Skip to content

Commit 41337ef

Browse files
committed
Wire up 5-scene composition β€” new story arc
5 scenes (75 + 90 + 135 + 90 + 90 frames), 4 transitions. Story: Hook β†’ Swipe β†’ Intervene β†’ Drawer β†’ Tagline. Transitions: fade, fade, wipe-from-bottom, fade. TOTAL_FRAMES recalculates automatically.
1 parent dba2a44 commit 41337ef

2 files changed

Lines changed: 45 additions & 28 deletions

File tree

β€Ždemo/src/DemoVideo.tsxβ€Ž

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { fade } from '@remotion/transitions/fade'
33
import { wipe } from '@remotion/transitions/wipe'
44
import type React from 'react'
55
import { AITools } from './scenes/AITools'
6+
import { Intervene } from './scenes/Intervene'
67
import { PhoneIntro } from './scenes/PhoneIntro'
78
import { SwipeDemo } from './scenes/SwipeDemo'
89
import { Tagline } from './scenes/Tagline'
@@ -13,27 +14,32 @@ export const FPS = 30
1314
export const TRANSITION_FRAMES = 15
1415

1516
/** Scene durations in frames β€” order matches TransitionSeries below */
16-
export const SCENE_DURATION_FRAMES = [75, 120, 210, 60] as const
17+
export const SCENE_DURATION_FRAMES = [75, 90, 135, 90, 90] as const
1718

1819
/** Total frames accounting for overlapping transitions */
1920
export const TOTAL_FRAMES =
2021
SCENE_DURATION_FRAMES.reduce((sum, f) => sum + f, 0) -
2122
(SCENE_DURATION_FRAMES.length - 1) * TRANSITION_FRAMES
2223

2324
/**
24-
* Main composition (~14s): 4 scenes, organic spring transitions.
25+
* Main composition (~16s): 5 scenes, organic spring transitions.
2526
*
26-
* | Scene | Duration | Transition out |
27-
* |-------------|------------- |--------------------|
28-
* | Phone Intro | 2.5s (75f) | fade |
29-
* | Swipe Demo | 4s (120f) | wipe from-bottom |
30-
* | AI Tools | 7s (210f) | fade |
31-
* | Tagline | 2s (60f) | β€” |
27+
* Story arc: Problem β†’ Solution β†’ Proof β†’ Action
28+
* Pacing: slow β†’ fast β†’ slow β†’ fast β†’ slow
29+
*
30+
* | Scene | Duration | Transition out |
31+
* |-------------|-------------- |--------------------|
32+
* | Hook | 2.5s (75f) | fade |
33+
* | Swipe | 3s (90f) | fade |
34+
* | Intervene | 4.5s (135f) | wipe from-bottom |
35+
* | Drawer | 3s (90f) | fade |
36+
* | Tagline | 3s (90f) | β€” |
3237
*/
3338
export const DemoVideo: React.FC = () => {
3439
return (
3540
<TransitionSeries>
36-
{/* Scene 1: The Hook β€” phone arrives, Claude Code mid-session */}
41+
{/* Scene 1: THE HOOK β€” phone arrives, Claude Code mid-session.
42+
Establishes tension: "3 agents. 0 keyboards." */}
3743
<TransitionSeries.Sequence durationInFrames={SCENE_DURATION_FRAMES[0]}>
3844
<PhoneIntro />
3945
</TransitionSeries.Sequence>
@@ -43,18 +49,33 @@ export const DemoVideo: React.FC = () => {
4349
timing={springTiming({ config: SMOOTH, durationInFrames: TRANSITION_FRAMES })}
4450
/>
4551

46-
{/* Scene 2: The Swipe β€” Claude Code β†’ OpenCode */}
52+
{/* Scene 2: THE SWIPE β€” single confident swipe Claude β†’ OpenCode.
53+
Hero moment: spatial metaphor for agent switching. */}
4754
<TransitionSeries.Sequence durationInFrames={SCENE_DURATION_FRAMES[1]}>
4855
<SwipeDemo />
4956
</TransitionSeries.Sequence>
5057

5158
<TransitionSeries.Transition
52-
presentation={wipe({ direction: 'from-bottom' })}
59+
presentation={fade()}
5360
timing={springTiming({ config: SMOOTH, durationInFrames: TRANSITION_FRAMES })}
5461
/>
5562

56-
{/* Scene 3: The Power β€” dense output, drawer interaction */}
63+
{/* Scene 3: THE INTERVENTION β€” scroll through Claude's plan, tap to approve.
64+
Emotional peak: proves you can control, not just monitor.
65+
"Not just monitoring. Controlling." */}
5766
<TransitionSeries.Sequence durationInFrames={SCENE_DURATION_FRAMES[2]}>
67+
<Intervene />
68+
</TransitionSeries.Sequence>
69+
70+
<TransitionSeries.Transition
71+
presentation={wipe({ direction: 'from-bottom' })}
72+
timing={springTiming({ config: SMOOTH, durationInFrames: TRANSITION_FRAMES })}
73+
/>
74+
75+
{/* Scene 4: THE DRAWER β€” compressed power flash.
76+
Tap β†’ drawer opens β†’ viewer sees grid β†’ done.
77+
"Everything. One tap away." */}
78+
<TransitionSeries.Sequence durationInFrames={SCENE_DURATION_FRAMES[3]}>
5879
<AITools />
5980
</TransitionSeries.Sequence>
6081

@@ -63,8 +84,9 @@ export const DemoVideo: React.FC = () => {
6384
timing={springTiming({ config: SMOOTH, durationInFrames: TRANSITION_FRAMES })}
6485
/>
6586

66-
{/* Scene 4: The Close β€” logo, tagline, hold */}
67-
<TransitionSeries.Sequence durationInFrames={SCENE_DURATION_FRAMES[3]}>
87+
{/* Scene 5: THE TAGLINE β€” "Your agents. In your pocket."
88+
Agent-forward positioning. npx webmux CTA. */}
89+
<TransitionSeries.Sequence durationInFrames={SCENE_DURATION_FRAMES[4]}>
6890
<Tagline />
6991
</TransitionSeries.Sequence>
7092
</TransitionSeries>

β€Ždemo/src/scenes/Intervene.tsxβ€Ž

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type React from 'react'
2-
import { interpolate, useCurrentFrame } from 'remotion'
2+
import { Sequence, interpolate, useCurrentFrame } from 'remotion'
33
import { AgentHeader } from '../components/AgentHeader'
44
import { SceneLayout } from '../components/SceneLayout'
55
import { Terminal } from '../components/Terminal'
@@ -37,19 +37,19 @@ export const Intervene: React.FC = () => {
3737
extrapolateRight: 'clamp',
3838
})
3939

40-
// Switch to accepted screen at frame 70
41-
const showAccepted = frame >= 70
42-
const screen = showAccepted ? claudeCodeAcceptedScreen : claudeCodePlanScreen
43-
// Accepted screen has its own appearAt stagger β€” offset by frame 70
44-
const acceptedOffset = showAccepted ? frame - 70 : frame
40+
// Switch to accepted screen at frame 70 β€” use Sequence to reset
41+
// useCurrentFrame() so the accepted screen's appearAt staggers work
42+
const ACCEPT_FRAME = 70
4543

4644
return (
4745
<SceneLayout caption="Not just monitoring. Controlling." captionAppearAt={15}>
4846
<AgentHeader agent="claude" />
49-
{showAccepted ? (
50-
<AcceptedTerminal frame={acceptedOffset} />
47+
{frame < ACCEPT_FRAME ? (
48+
<Terminal screen={claudeCodePlanScreen} scrollOffset={scrollOffset} />
5149
) : (
52-
<Terminal screen={screen} scrollOffset={scrollOffset} />
50+
<Sequence from={ACCEPT_FRAME} layout="none">
51+
<Terminal screen={claudeCodeAcceptedScreen} />
52+
</Sequence>
5353
)}
5454
<TmuxStatusBar {...claudeCodePlanStatus} />
5555
<WebmuxToolbar />
@@ -68,8 +68,3 @@ export const Intervene: React.FC = () => {
6868
</SceneLayout>
6969
)
7070
}
71-
72-
/** Wrapper that resets useCurrentFrame context for accepted screen stagger */
73-
const AcceptedTerminal: React.FC<{ frame: number }> = () => {
74-
return <Terminal screen={claudeCodeAcceptedScreen} />
75-
}

0 commit comments

Comments
Β (0)