A film that looks like the product made it: its colors, type, components, logo and voice, cut to music. Built in Remotion inside (or beside) the product's codebase, so it reuses real components and stays editable.
Non-negotiables
- Their design wins. Every rule comes from the product: its tokens, components, rules files, landing page and copy. Never carry another product's taste in, including anything in this skill that their design contradicts.
- Ask, don't assume. What the film shows and how it is made are the user's call. Interview them before writing the story (reference/interview.md). Offer options drawn from what you found in their code, never generic ones.
- Every frame is a pure function of time. No CSS transitions or keyframes, no timers, no
Date.now(), no state carried between frames. A component that runs its own clock gets a frame-driven twin. - Measure, never guess. Beats come from the audio, positions from the DOM (debug overlay), colors from decoded pixels of the final files.
- Honest claims. Show only what the product really does. Find its claims rules and approved lines before writing a word.
- Ask first before committing, pushing or publishing. Keep every rendered version (
out/<film>/v1,v2, ...).
Workflow
- Quick discovery. Just enough to ask good questions: rules files, tokens, components, the logo (and any mascot or animated mark), the landing page, the main features. See reference/discovery.md.
- Interview. Two rounds of AskUserQuestion: the brief, then the ingredients. A third round only if needed. See reference/interview.md.
- Brand kit →
videos/BRAND.md. Finish discovery on what they chose and fill templates/BRAND.md. - Story →
videos/<film>-prompt.md. Read reference/story.md and reference/ingredients.md, then fill templates/film-prompt.md. Checkpoint with the user: beat sheet and 3 style frames. - Music. Skip if the film is silent. See reference/music.md:
scripts/beats.py, the per-bar stem map,scripts/audio-edit.py, SFX on measured peaks. - Engine and scenes. Read reference/engine.md.
- Copy templates/kit/ into
videos/src/kit/. - One folder per film:
cues.ts(the beat sheet as data),layout.ts,acts/, the composition.
- Copy templates/kit/ into
- Review loop. See reference/review.md.
- Stills at every handoff (
scripts/stills.ts,--debugto measure). - Contact and handoff sheets, then a half-res draft.
- Fix, repeat, and show the user frames as you go.
- Stills at every handoff (
- Final render, verify, deliver. See reference/render.md:
scripts/render.ts, thenscripts/verify.py, then send the files.
Quality floor (always, whatever the ingredients)
- Only the product's own surfaces, colors, borders and shades. Never invent card backgrounds, outlines or tints it does not use.
- Readable at the delivery size. Fewer words beat smaller words. Cut labels that restate the picture.
- Text is never covered by a cursor, a chip or a texture. It never crosses other text in a move. A line never re-centers while it builds: keep every word's slot.
- Loading states keep their width. Use the product's own loading pattern.
- Something happens on every beat. A bar where nothing moves reads as slow.
- Scene boundaries land on bars. A loop's last frame equals its first. A landing loop must read muted.
- No effects the product's language does not use: glows, particles, click rings, bouncy easing, shaders.
Traps that cost real time
- Remotion stills do not forward console logs. Print measurements into the frame (
templates/kit/debug.tsx). npx remotion stillre-bundles on every call. Usescripts/stills.ts: bundle once, render many frames.- Remotion's bundled ffmpeg has no
tmix,selectortile. Use a full ffmpeg (uv run --with imageio-ffmpeg). - Color range: the Remotion master is limited range, BT.601, untagged. Blending it as full range lifts
#0a0a0ato#171717, a gray box on a dark page. Decode frame 0 of every deliverable and check the numbers. interpolateColorscannot parsecolor-mix(). Any color that animates is a hex token.- Async image components (Radix or base-ui avatars) can render empty in a frame. Twin them with Remotion
<Img>. - Springs that retarget: sum one closed-form step per key, with keys sorted by time.
- CSS dashed borders crawl while a box resizes. Draw dashes as SVG strokes at a fixed pitch.
- WebGL or shader effects on their own clock paint a different picture each run. Prefer textures painted per frame.
- In a monorepo:
- pin every
remotionand@remotion/*to one exact version - never let the video workspace re-resolve the app's Tailwind
- alias the app's path imports in the webpack override
- pin every
- Stop only the processes you started; other sessions may be waiting on the machine.