Skip to content

feat(app): mascot reel page and a recorder for videos - #146

Merged
httpsphl merged 3 commits into
mainfrom
feat/mascot-reel
Oct 4, 2026
Merged

httpsphl merged 3 commits into
mainfrom
feat/mascot-reel

Conversation

@httpsphl

@httpsphl httpsphl commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Stacked on #145 (the mascot cheer): its two commits show here until it merges.

What

  • ?reel (dev only, src/dev/Reel.tsx): a row of bots in eight colors passing by, as in a carousel. Every 3 s the row slides one place; the bot that comes to the middle grows in, lands squashed, works for a moment (embers) and cheers when it finishes. The others idle, blinking and glancing each in its own time. &beat=2600 changes the pace.
  • pnpm reel (scripts/reel.mjs + scripts/reelClock.js): records that page to an MP4 at 60 fps with a headless Edge or Chrome and ffmpeg. Options: --seconds, --size 1080x1920, --beat, --blur, --url, --out; default output .dev/reel/reel.mp4 (git-ignored).

How the recorder works

The page's clock stands still (timers, requestAnimationFrame, Date.now, performance.now, and every CSS animation and transition held paused). The recorder moves it 1/60 s at a time and takes a screenshot of each frame, so the video is frame-exact on any computer (12 s takes about a minute here). --blur blends each frame with its neighbors in ffmpeg.

Dropped along the way:

  • the browser's frame stream (Page.startScreencast): its time stamps came out of order and drifted from the page's clock, and it stopped sending frames after 3 to 9 s;
  • the browser's virtual time: the page never loaded.

Windows treats the headless window as covered and slows its painting, so the recorder turns off occlusion and emulates focus; a screenshot that gets no answer in 5 s is retried after a fresh paint.

Tests

  • src/dev/reel.test.tsx: the middle bot goes idle → working → idle with the cheer, and the row moves on.
  • Recorded 3 s, 7 s and 12 s videos and checked their frames.

Nothing here runs in the app build: the page only loads under pnpm dev.

When a bot goes from working to idle, its mascot crouches, jumps up
stretched, lands squashed and smiles with its eyes bent into two arcs,
then opens them again with a blink (1.2 s). A mascot that shows up
idle does not cheer. The motion lives in its own file,
mascot-cheer.css, and every frame ends at rest, so less motion shows
nothing.
The open eyes sit on a line that rises to the right (about 14 degrees),
but the arcs of the shut and smiling eyes were drawn level, so they
looked crooked next to it. Both arcs now turn by the angle of that line,
in a group of their own so the smile's CSS transform keeps the turn.
A dev-only page (?reel) shows a row of bots in many colors passing by:
every beat the row slides one place, and the bot that comes to the
middle lands, works for a moment and cheers when it finishes, with the
same moods as in the app.

`pnpm reel` records it to a 60 fps video. It stops the page's clock
(timers, animation frames, Date and performance.now, CSS animations),
moves it a sixtieth of a second at a time and takes a picture of each
frame, so the video comes out the same on any computer. --blur blends
each frame with its neighbors. The browser's own frame stream was
tried first and dropped: its time stamps run out of order and it
stopped sending frames after a few seconds.
@httpsphl
httpsphl merged commit 2002e03 into main Oct 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant