From ffbf1b1f32df528cb7d18ccbd36c41655ff2ede7 Mon Sep 17 00:00:00 2001 From: HolgerHatGarKeineNode Date: Sat, 24 Jan 2026 12:42:01 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=AC=20Add=20PortalPresentation=20skele?= =?UTF-8?q?ton=20composition:=20implement=20main=20composition=20structure?= =?UTF-8?q?=20with=209=20scene=20sequences=20for=20the=2090-second=20cinem?= =?UTF-8?q?atic=20Portal=20presentation=20video.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.5 --- videos/src/PortalPresentation.tsx | 224 ++++++++++++++++++++++++++++++ videos/src/Root.tsx | 9 ++ 2 files changed, 233 insertions(+) create mode 100644 videos/src/PortalPresentation.tsx diff --git a/videos/src/PortalPresentation.tsx b/videos/src/PortalPresentation.tsx new file mode 100644 index 0000000..39763cf --- /dev/null +++ b/videos/src/PortalPresentation.tsx @@ -0,0 +1,224 @@ +import { AbsoluteFill, Sequence, useVideoConfig, Img, staticFile } from "remotion"; +import { inconsolataFont } from "./fonts/inconsolata"; + +/** + * PortalPresentation - Main composition for the Einundzwanzig Portal presentation video + * + * Scene Structure (90 seconds total @ 30fps = 2700 frames): + * 1. Logo Reveal (6s) - Frames 0-180 + * 2. Portal Title (4s) - Frames 180-300 + * 3. Dashboard Overview (12s) - Frames 300-660 + * 4. Meine Meetups (12s) - Frames 660-1020 + * 5. Top Länder (12s) - Frames 1020-1380 + * 6. Top Meetups (10s) - Frames 1380-1680 + * 7. Activity Feed (10s) - Frames 1680-1980 + * 8. Call to Action (12s) - Frames 1980-2340 + * 9. Outro (12s) - Frames 2340-2700 + */ +export const PortalPresentation: React.FC = () => { + const { fps } = useVideoConfig(); + + // Scene durations in seconds + const SCENE_DURATIONS = { + logoReveal: 6, + portalTitle: 4, + dashboardOverview: 12, + meineMeetups: 12, + topLaender: 12, + topMeetups: 10, + activityFeed: 10, + callToAction: 12, + outro: 12, + }; + + // Calculate frame positions for each scene + const sceneFrames = { + logoReveal: { from: 0, duration: SCENE_DURATIONS.logoReveal * fps }, + portalTitle: { + from: SCENE_DURATIONS.logoReveal * fps, + duration: SCENE_DURATIONS.portalTitle * fps, + }, + dashboardOverview: { + from: (SCENE_DURATIONS.logoReveal + SCENE_DURATIONS.portalTitle) * fps, + duration: SCENE_DURATIONS.dashboardOverview * fps, + }, + meineMeetups: { + from: + (SCENE_DURATIONS.logoReveal + + SCENE_DURATIONS.portalTitle + + SCENE_DURATIONS.dashboardOverview) * + fps, + duration: SCENE_DURATIONS.meineMeetups * fps, + }, + topLaender: { + from: + (SCENE_DURATIONS.logoReveal + + SCENE_DURATIONS.portalTitle + + SCENE_DURATIONS.dashboardOverview + + SCENE_DURATIONS.meineMeetups) * + fps, + duration: SCENE_DURATIONS.topLaender * fps, + }, + topMeetups: { + from: + (SCENE_DURATIONS.logoReveal + + SCENE_DURATIONS.portalTitle + + SCENE_DURATIONS.dashboardOverview + + SCENE_DURATIONS.meineMeetups + + SCENE_DURATIONS.topLaender) * + fps, + duration: SCENE_DURATIONS.topMeetups * fps, + }, + activityFeed: { + from: + (SCENE_DURATIONS.logoReveal + + SCENE_DURATIONS.portalTitle + + SCENE_DURATIONS.dashboardOverview + + SCENE_DURATIONS.meineMeetups + + SCENE_DURATIONS.topLaender + + SCENE_DURATIONS.topMeetups) * + fps, + duration: SCENE_DURATIONS.activityFeed * fps, + }, + callToAction: { + from: + (SCENE_DURATIONS.logoReveal + + SCENE_DURATIONS.portalTitle + + SCENE_DURATIONS.dashboardOverview + + SCENE_DURATIONS.meineMeetups + + SCENE_DURATIONS.topLaender + + SCENE_DURATIONS.topMeetups + + SCENE_DURATIONS.activityFeed) * + fps, + duration: SCENE_DURATIONS.callToAction * fps, + }, + outro: { + from: + (SCENE_DURATIONS.logoReveal + + SCENE_DURATIONS.portalTitle + + SCENE_DURATIONS.dashboardOverview + + SCENE_DURATIONS.meineMeetups + + SCENE_DURATIONS.topLaender + + SCENE_DURATIONS.topMeetups + + SCENE_DURATIONS.activityFeed + + SCENE_DURATIONS.callToAction) * + fps, + duration: SCENE_DURATIONS.outro * fps, + }, + }; + + return ( + + {/* Wallpaper Background */} + + + {/* Scene 1: Logo Reveal (6s) */} + + + + + {/* Scene 2: Portal Title (4s) */} + + + + + {/* Scene 3: Dashboard Overview (12s) */} + + + + + {/* Scene 4: Meine Meetups (12s) */} + + + + + {/* Scene 5: Top Länder (12s) */} + + + + + {/* Scene 6: Top Meetups (10s) */} + + + + + {/* Scene 7: Activity Feed (10s) */} + + + + + {/* Scene 8: Call to Action (12s) */} + + + + + {/* Scene 9: Outro (12s) */} + + + + + ); +}; + +/** + * Placeholder component for scenes that haven't been implemented yet. + * Displays a centered scene name with visual indicators. + */ +const PlaceholderScene: React.FC<{ name: string; sceneNumber: number }> = ({ + name, + sceneNumber, +}) => { + return ( + +
+
+ {sceneNumber} +
+

{name}

+

Scene placeholder

+
+
+ ); +}; diff --git a/videos/src/Root.tsx b/videos/src/Root.tsx index 6115979..147396a 100644 --- a/videos/src/Root.tsx +++ b/videos/src/Root.tsx @@ -3,6 +3,7 @@ import { Composition } from "remotion"; import { MyComposition } from "./Composition"; import { Nip05Tutorial } from "./Nip05Tutorial"; import { Nip05TutorialMobile } from "./Nip05TutorialMobile"; +import { PortalPresentation } from "./PortalPresentation"; export const RemotionRoot: React.FC = () => { return ( @@ -31,6 +32,14 @@ export const RemotionRoot: React.FC = () => { width={1080} height={1920} /> + ); };