Agent skill · product-film

Product film: silent, looping, your product as its own components.

A skill for coding agents to make a short silent product film – website hero, landing section, social cut – as a deterministic HTML timeline rendered with Playwright and cut with ffmpeg. The numbers come from sixteen cuts of a shipped SaaS hero film; they work for any product with a UI.

What it builds

Silent, looping films of 20–60 s with full-frame cuts, the product shown as its own real components on a 3D plate with a camera that never stops. One engine, two routes.

Route A

With footage

Licensed live-action cuts of people alternate with product beats. Each product beat follows the human action that motivates it: someone at a laptop, then the prompt; a meeting, then the share dialog.

Route B

Pure product

Product beats only, joined by the plate, with captions or end cards if the surface needs words. Faster to make and needs no licence.

Keep the rig in one place. Put the camera code and the numbers below in references/camera-rig.md next to the skill and read it before writing any beat. Tune from there; do not re-derive.

When to use

Use it for

  • A new hero, section or launch film, or a recut, new beat or new ending of an existing one.
  • Showing the product at fidelity, in motion, without screen-recording the real app.

Not for

  • Feature walkthroughs captured from the live app with test data.
  • Films with music or a voice track – use an editor timeline for those.
  • Deploying the finished MP4 to your site.

Inputs to settle before rendering

Ask only for what cannot be inferred; state assumptions otherwise.

InputWhat to settle
ReferenceA film the user points at. Fetch it, find the video URL, probe it with ffprobe: resolution, fps, length, bitrate, audio track, poster, preload. The spec becomes the target; the structure becomes the grammar.
Story and screenOne line: what the user does in the product, who reacts, how the result reaches them. Which screens appear (dashboard, editor, dialog, notification) and their exact copy.
RouteA if people footage is wanted and licensable; B if the film is product-only or footage is out of scope.
Surface and lengthHome hero loop (30 s, silent, poster, preload="none") · landing section (20–25 s) · social (45–60 s, captions; 9:16 reflow is a separate pass).
BrandThe product's design tokens, fonts and any third-party brands shown in the UI.

The engine

Every product beat is an HTML page that exposes window.seek(t) and draws frame t deterministically. A renderer opens it headless at 1920×1080 with device scale factor 2, calls seek(i/25) for each frame and screenshots to JPEG; ffmpeg encodes the beat with grain and a vignette. An assembly script cuts footage segments (Route A) and concatenates everything into a master, a 1080p web file, a 720p review file and a poster.

beats.htmlseek(t) draws each frame
→
render.jsPlaywright frames → seg/<beat>.mp4
→
assemble.shcut list → master, 1080p, 720p, poster
→
review-vNN.htmlone review page, many versions
LayerFileRole
Beatsbeats.htmlOne <div class="beat"> per beat, real product markup and CSS inside, 3D world and camera, particles on a canvas, seek(t)
Rendererrender.jsPlaywright frames → seg/<beat>.mp4; an ONLY=b4,b6 env var renders a subset
Assemblyassemble.shCut list → segments → concat → master → 1080p, 720p, poster
Reviewreview-vNN.html720p and poster embedded as base64, "What changed since" on top, republished as new versions of one shared page

Build these four once as templates in the skill's templates/ folder and copy them for each film; do not start from a blank file.

Product fidelity

The UI on screen must be the product's own components, not a mock-up.

When a component isn't available as code, rebuild it from the shipped UI and your tokens, and say so on the review page.

The numbers

These held across sixteen cuts of a production hero film. Start here; change one at a time and re-render only the beat you changed.

1.5 smedian footage cut (0.75–1.8 s)
2.5–3.8 sproduct beat, Route A; 2.5–5 s in Route B
5 / 10 scuts per ten seconds, always short–short–long
≥ 0.5 send-state hold on every product beat

Pacing

Camera

A perspective world at perspective:1500px; the camera translates on z – a dolly, never a 2D scale.

magnification = 1500 / (1500 − z_cam − z_obj)
RuleValue
MoveOne per beat, cubic ease-in-out over the whole beat: z from about −80 to +180…+500
Driftx += 6·sin(0.9t), y += 4·sin(1.25t) under the move, so a hold never freezes
RotationHand-held objects only (popovers, dialogs, phones): settle from 7° / −9° to 1.5° / −2°, plus ±0.6–1.2° sine. Never on screen-fixed objects (input bar, main card) – tilt there reads as a bug.
Subject vs groundSubject to z 260–280, scale 1.45–1.7×. Ground scales 0.98, dims to 0.86, blurs ≤ 1.6 px as the focus plane follows the subject. The ground is never removed.
Depth of fieldblur = clamp((|z − focus| − 90) / 110, 0, 3.5) px; opacity × (1 − 0.1·blur/3.5)

Entrances

Plate and texture

Footage (Route A)

Procedure

  1. Working folder outside the repo and outside any temporary scratch space, e.g. ~/films/<film>/. Agent scratch directories get pruned and take the session's work with them.
  2. Reference and concept. Probe the reference. Write a one-page concept: what the film is not, who the protagonist is, the beat sheet, the register of the humans (Route A). Share it for review.
  3. Storyboard. Route A: search a stock-footage library through a headed, persistent browser profile (bot protection blocks headless), sample frames, build the storyboard from real frames – all shots from one shoot, every shot 0.5–2 s. Route B: the beat list with the copy per beat. Iterate as versions of one page.
  4. Sources. Route A: the user buys the licence and downloads the files; they go in footage/. Route B: nothing to fetch.
  5. Beats. Copy templates/beats.html, paste the product stylesheet, build one beat at a time; check each with a contact sheet (ffmpeg -vf "fps=2.5,scale=480:-1,tile=4x2") before rendering the next.
  6. Render with render.js from a directory where require('playwright') resolves.
  7. Assemble with assemble.sh: cut list with in-points, durations and per-cut comments; build; make a whole-film contact sheet at 1 fps and look at it.
  8. Review page. Embed the 720p and the poster, write "What changed since cut vN", publish it as a new version of the same review page. Send the MP4 to the user as a file. Post frames, not prose, when asking for a decision.
  9. Loop on feedback. Collect open comments, act on each, reply with what changed, close the thread.
  10. Ship the 1080p file and poster to your site, with the poster at the same frame the film uses.

Review discipline

Gotchas already paid for

SymptomFix
Children go softA CSS filter on a parent blurs its children; sharp objects must be siblings of blurred panels.
Slow push jitterszoompan at 1080p jitters; compute it on a 7680-wide upscale.
Concat can't find filesThe concat list's paths resolve relative to the list file.
Script breaks on varszsh mangles $var:flags; write assembly scripts in bash.
Phone UI in 16:9A floating device on the plate with the camera pushing into its screen.
Email after a phone shotShow the mobile mail app, not the desktop one.

What this skill does not do