Skip to content

Commit 9e26d9e

Browse files
committed
Improve Scene 3: realistic drawer buttons + AI Usage popup
Replace generic drawer buttons with real config labels (AI Usage, Critique, Git, Yazi, gh-dash, Tailscale etc). Add TmuxPopup component showing Claude/Codex API usage percentages — the demo's key moment. Extend scene from 5s to 7s for the full interaction: tap ☰ More → drawer opens → tap AI Usage → popup fades in over terminal.
1 parent e339253 commit 9e26d9e

4 files changed

Lines changed: 140 additions & 37 deletions

File tree

‎demo/src/DemoVideo.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@ export const FPS = 30
1313
export const TRANSITION_FRAMES = 15
1414

1515
/** Scene durations in frames — order matches TransitionSeries below */
16-
export const SCENE_DURATION_FRAMES = [75, 120, 150, 60] as const
16+
export const SCENE_DURATION_FRAMES = [75, 120, 210, 60] as const
1717

1818
/** Total frames accounting for overlapping transitions */
1919
export const TOTAL_FRAMES =
2020
SCENE_DURATION_FRAMES.reduce((sum, f) => sum + f, 0) -
2121
(SCENE_DURATION_FRAMES.length - 1) * TRANSITION_FRAMES
2222

2323
/**
24-
* Main composition (~13.5s): 4 scenes, organic spring transitions.
24+
* Main composition (~14s): 4 scenes, organic spring transitions.
2525
*
2626
* | Scene | Duration | Transition out |
2727
* |-------------|------------- |--------------------|
2828
* | Phone Intro | 2.5s (75f) | fade |
2929
* | Swipe Demo | 4s (120f) | wipe from-bottom |
30-
* | AI Tools | 5s (150f) | fade |
30+
* | AI Tools | 7s (210f) | fade |
3131
* | Tagline | 2s (60f) | — |
3232
*/
3333
export const DemoVideo: React.FC = () => {

‎demo/src/components/DrawerOverlay.tsx‎

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,23 @@ import { Easing, interpolate, useCurrentFrame } from 'remotion'
33
import { FONT_FAMILY } from '../fonts'
44
import { colours } from '../theme'
55

6-
/** Button labels from src/config.ts defaultDrawerButtons — authentic subset */
6+
/** Button labels from user's real webmux config */
77
const DRAWER_BUTTONS = [
8-
'+ Win',
9-
'Split |',
10-
'Split —',
11-
'Zoom',
12-
'Sessions',
13-
'Windows',
8+
'AI Usage',
9+
'Critique',
1410
'Git',
15-
'Files',
11+
'Yazi',
1612
'Links',
17-
'PgUp',
18-
'PgDn',
19-
'Copy',
20-
'Help',
21-
'Kill',
22-
'Combo',
13+
'Scratch',
14+
'Neovim',
15+
'Detach',
16+
'Thumbs',
17+
'Diff',
18+
'gh-dash',
19+
'Ports',
20+
'Layouts',
21+
'Tailscale',
22+
'+ Win',
2323
] as const
2424

2525
/**
@@ -31,8 +31,18 @@ export const DrawerOverlay: React.FC<{
3131
showFrame: number
3232
/** Frame when drawer starts closing */
3333
hideFrame: number
34-
}> = ({ showFrame, hideFrame }) => {
34+
/** Button label to highlight (tap feedback) */
35+
highlightButton?: string
36+
/** Frame when highlight starts */
37+
highlightAt?: number
38+
}> = ({ showFrame, hideFrame, highlightButton, highlightAt = 0 }) => {
3539
const frame = useCurrentFrame()
40+
41+
const isHighlighted = (label: string) => {
42+
if (label !== highlightButton) return false
43+
const elapsed = frame - highlightAt
44+
return elapsed >= 0 && elapsed < 4
45+
}
3646
const SLIDE_DURATION = 8
3747

3848
// Slide up: showFrame → showFrame + SLIDE_DURATION
@@ -114,7 +124,7 @@ export const DrawerOverlay: React.FC<{
114124
<div
115125
key={label}
116126
style={{
117-
background: colours.surface1,
127+
background: isHighlighted(label) ? colours.surface2 : colours.surface1,
118128
color: colours.fg,
119129
borderRadius: 8,
120130
padding: '10px 6px',

‎demo/src/components/TmuxPopup.tsx‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import type React from 'react'
2+
import { interpolate, useCurrentFrame } from 'remotion'
3+
import { FONT_FAMILY } from '../fonts'
4+
import { colours } from '../theme'
5+
6+
/** Tmux-style floating popup with box-drawing border */
7+
export const TmuxPopup: React.FC<{
8+
/** Frame when popup appears */
9+
showFrame: number
10+
}> = ({ showFrame }) => {
11+
const frame = useCurrentFrame()
12+
13+
if (frame < showFrame) return null
14+
15+
const age = frame - showFrame
16+
const opacity = interpolate(age, [0, 6], [0, 1], { extrapolateRight: 'clamp' })
17+
const scale = interpolate(age, [0, 6], [0.95, 1], { extrapolateRight: 'clamp' })
18+
19+
return (
20+
<div
21+
style={{
22+
position: 'absolute',
23+
inset: 0,
24+
zIndex: 10001,
25+
display: 'flex',
26+
alignItems: 'center',
27+
justifyContent: 'center',
28+
pointerEvents: 'none',
29+
}}
30+
>
31+
<div
32+
style={{
33+
width: '70%',
34+
background: '#181825',
35+
border: `2px solid ${colours.blue}`,
36+
borderRadius: 8,
37+
padding: '16px 20px',
38+
fontFamily: `"${FONT_FAMILY}", monospace`,
39+
fontSize: 12,
40+
lineHeight: 1.8,
41+
color: colours.fg,
42+
opacity,
43+
transform: `scale(${scale})`,
44+
whiteSpace: 'pre',
45+
}}
46+
>
47+
{/* Claude section */}
48+
<div style={{ color: colours.blue, fontWeight: 700 }}>── Claude ──</div>
49+
<div>
50+
<span style={{ color: colours.fg }}>5-hour: </span>
51+
<span style={{ color: colours.yellow, fontWeight: 700 }}>42%</span>
52+
<span style={{ color: colours.fg, opacity: 0.6 }}>{' resets in 2h 14m'}</span>
53+
</div>
54+
<div>
55+
<span style={{ color: colours.fg }}>7-day: </span>
56+
<span style={{ color: colours.green, fontWeight: 700 }}>12%</span>
57+
<span style={{ color: colours.fg, opacity: 0.6 }}>{' resets in 4d 2h'}</span>
58+
</div>
59+
<div style={{ height: 8 }} />
60+
{/* Codex section */}
61+
<div style={{ color: colours.green, fontWeight: 700 }}>── Codex ───</div>
62+
<div>
63+
<span style={{ color: colours.fg }}>5-hour: </span>
64+
<span style={{ color: colours.green, fontWeight: 700 }}>{' 8%'}</span>
65+
<span style={{ color: colours.fg, opacity: 0.6 }}>{' resets in 3h 41m'}</span>
66+
</div>
67+
<div>
68+
<span style={{ color: colours.fg }}>7-day: </span>
69+
<span style={{ color: colours.green, fontWeight: 700 }}>{' 3%'}</span>
70+
<span style={{ color: colours.fg, opacity: 0.6 }}>{' resets in 5d 18h'}</span>
71+
</div>
72+
<div style={{ height: 12 }} />
73+
<div style={{ color: colours.overlay, fontSize: 11 }}>press any key</div>
74+
</div>
75+
</div>
76+
)
77+
}

‎demo/src/scenes/AITools.tsx‎

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,38 @@ import { Caption } from '../components/Caption'
44
import { DrawerOverlay } from '../components/DrawerOverlay'
55
import { PhoneMockup } from '../components/PhoneMockup'
66
import { Terminal } from '../components/Terminal'
7+
import { TmuxPopup } from '../components/TmuxPopup'
78
import { TmuxStatusBar } from '../components/TmuxStatusBar'
89
import { TapFinger } from '../components/TouchFinger'
910
import { WebmuxToolbar } from '../components/WebmuxToolbar'
1011
import { claudeCodeDenseScreen, claudeCodeDenseStatus } from '../screens'
1112
import { colours } from '../theme'
1213

1314
/**
14-
* Scene 3: Dense Claude Code output — tests pass, drawer interaction (5s / 150 frames)
15+
* Scene 3: Dense output → drawer → AI Usage popup (7s / 210 frames)
1516
*
1617
* Timeline:
17-
* 0-28: Completed edits visible, Bash test block staggers in
18-
* 28-55: Hold — viewer reads test results
19-
* 59-61: Finger taps ☰ More
20-
* 61-81: Drawer slides up, holds open
21-
* 81: Drawer closes
22-
* 85-87: Finger taps Esc
23-
* 87-150: Hold + transition
18+
* 0-28: Bash test block staggers in
19+
* 28-45: Hold — viewer reads results
20+
* 45: Finger taps ☰ More (toolbar highlight)
21+
* 49: Drawer slides up
22+
* 49-68: Drawer open, viewer reads buttons
23+
* 68: Finger taps "AI Usage" (drawer button highlight)
24+
* 76: Drawer slides down
25+
* 84: AI Usage popup fades in over terminal
26+
* 84-180: Popup visible (~3.2s — viewer reads usage data)
27+
* 180-210: Hold + transition out
2428
*/
2529
export const AITools: React.FC = () => {
2630
const frame = useCurrentFrame()
2731

28-
// Toolbar button highlight: ☰ More tap at 59, Esc tap at 85
29-
const highlightButton =
30-
frame >= 59 && frame < 63 ? '\u2630 More' : frame >= 85 && frame < 89 ? 'Esc' : undefined
31-
const highlightAt = frame >= 59 && frame < 63 ? 59 : frame >= 85 && frame < 89 ? 85 : 0
32+
// Toolbar highlight: ☰ More tap at 45
33+
const toolbarHighlight = frame >= 45 && frame < 49 ? '\u2630 More' : undefined
34+
const toolbarHighlightAt = frame >= 45 && frame < 49 ? 45 : 0
35+
36+
// Drawer button highlight: AI Usage tap at 68
37+
const drawerHighlight = frame >= 68 && frame < 72 ? 'AI Usage' : undefined
38+
const drawerHighlightAt = frame >= 68 && frame < 72 ? 68 : 0
3239

3340
return (
3441
<AbsoluteFill
@@ -45,15 +52,24 @@ export const AITools: React.FC = () => {
4552
<div style={{ position: 'relative', flex: 1, display: 'flex', flexDirection: 'column' }}>
4653
<Terminal screen={claudeCodeDenseScreen} />
4754
<TmuxStatusBar {...claudeCodeDenseStatus} />
48-
<WebmuxToolbar highlightButton={highlightButton} highlightAt={highlightAt} />
55+
<WebmuxToolbar highlightButton={toolbarHighlight} highlightAt={toolbarHighlightAt} />
4956

5057
{/* Finger taps ☰ More to open drawer */}
51-
<TapFinger tapFrame={59} position={[175, 775]} />
52-
{/* Finger taps Esc */}
53-
<TapFinger tapFrame={85} position={[25, 735]} />
58+
<TapFinger tapFrame={45} position={[175, 775]} />
59+
60+
{/* Finger taps AI Usage in drawer */}
61+
<TapFinger tapFrame={68} position={[68, 660]} />
62+
63+
{/* Command drawer */}
64+
<DrawerOverlay
65+
showFrame={49}
66+
hideFrame={76}
67+
highlightButton={drawerHighlight}
68+
highlightAt={drawerHighlightAt}
69+
/>
5470

55-
{/* Command drawer overlay */}
56-
<DrawerOverlay showFrame={61} hideFrame={81} />
71+
{/* AI Usage popup appears after drawer closes */}
72+
<TmuxPopup showFrame={84} />
5773
</div>
5874
</PhoneMockup>
5975
<Caption text="One tap away." />

0 commit comments

Comments
 (0)