The reference is the launch video of producthub.lat (October 2026), refined over fourteen rounds of
feedback. The code that made it is next to this file in reference/ and is the starting point of every new
video: adapt it, never start from a blank page.
What you need
| Tool | For |
|---|---|
Node 18+ and npx hyperframes (HyperFrames CLI by HeyGen) |
Lint, snapshot and render the HTML composition to MP4 |
ffmpeg |
Read frames of the rendered MP4, mux the soundtrack |
Python 3 with numpy, scipy, soundfile, librosa (a venv is fine) |
Measure the music's beats and build the soundtrack |
potrace and ImageMagick (optional) |
Turn a small PNG wordmark into a vector |
| A music generator (the reference used Gemini) | The music track, from reference/music-prompt.md |
Where things live
| What | Where |
|---|---|
| The video's project | videos/<slug>/ in the current workspace |
| Composition source | videos/<slug>/v2/index.template.html (from reference/index.template.html), built into videos/<slug>/index.html by reference/build.py |
| Brand assets | videos/<slug>/assets/ — fonts, wordmark-vector.svg, site screenshots, logos/*.png for the logo ring |
| Soundtrack builder | videos/<slug>/v2/audio/mix.py (from reference/mix.py) |
| Renders | videos/<slug>/renders/vN.mp4 — number every version; never overwrite one the user already saw |
The reference template points at Product Hub's assets (site screenshots, partner logos, fonts). They are not shipped here: each video brings its own.
The style — rules for any brand
Each rule is stated first; why it exists follows. These carry over to every video. What was decided only for the Product Hub brand lives in its own section below and does not carry over.
- One continuous composition, one timeline, built by one agent. Never one sub-agent per scene. Eight agents building eight scenes produced eight slides that did not know each other. Continuity (exit tied to entrance, fixed elements) needs one author and one GSAP timeline.
- The brand comes from the live site's CSS, not from design tokens and not from a reference video. A video shared "as a reference" is for the kind of motion only — never its colors. Read the site's global CSS: it often overrides the design system's tokens.
- Every scene has a slow, continuous camera zoom (3–6 %, in or out,
sine.inOut). It is what makes the video feel shot by a real camera. Stills are allowed only inside it. - A "camera turn" is a fast camera move (whip pan), never a rotation of the frame. Use horizontal or vertical whips with blur; do not rotate screens or objects (except a logo ring that orbits by design).
- Tie the exit of a scene to the entrance of the next. If the outgoing object leaves upward, the incoming one is born from below on the same motion; if the camera dives in, the next scene arrives on the same forward move.
- Three text entrances, alternated (
textInin the reference):push: each word glides in and nudges the previous ones; the line re-centers with a small overshoot. Only on a few key lines. The overshoot grows with the distance the line travels, so a long last word needs a softer bounce per step ([0.6, [0, 1.0, 0.35]]in the reference).rise: each word fades up out of a blur, no overshoot.mask: each word slides up from behind its own baseline. Bouncing every line reads as a beginner's video. Never a typewriter for text entrances; typing is only for a UI field (a URL bar).
- Fixed elements stay fixed across transitions and recolor with the transition edge. An anchor line above a run of slides never moves; it changes color exactly where the circle / wipe / whip passes, by stacking one copy per color clipped with the same clip-path, ease and timing as the incoming slide. Same for a floor light shared by two dark scenes: one layer under both, only the content moves.
- Backgrounds tint directly between scenes (white → blue), never through black.
- Vary the transition per cut: circle reveal, wipe up, whip pan, zoom-through, camera pull-back (zoom-out reveal). A small set, never the same one twice in a row.
- The logo is always an image or a vector, never live text. When the largest file the brand has is a
small PNG, rebuild it as a vector: redraw a geometric mark by hand as SVG paths (so its pieces can be
animated) and trace the wordmark with potrace (8× upscale, threshold,
--alphamax 0.85). Compare the trace against the original before using it. How the logo sits on dark grounds follows the brand's own rule for that case — ask if the brand has none. - One signature transition per video, taken from something only this brand has, placed at the video's turning point (the music's explosion lands there). It is decided per brand — from its mark, its product UI, its shapes — and proposed to the user before building. Product Hub's was the dive into its P (below); it is an example of the idea, not a move to reuse on another mark.
- No decorative light rays, no grids of dots, no colors borrowed from a reference. Glows and accents only in the brand's own color family.
Product Hub video — decisions for that brand only
Recorded so the reference code makes sense; for another brand each one is a question, not a default.
- The P as a portal, both ways. Mid-video the camera dives into the star in the negative space of the P and the programs scene is discovered there; the closing does the inverse — the P comes back from huge with the logos scene inside its star, which goes dark fast while the P shrinks to the center, then the wordmark completes the lockup.
- The star is never animated (no flash, no glow on it): it does not fit the brand.
- On dark grounds the logo is white and transparent, never on a white plate.
- Closing lockup at ~800 px wide, slogan smaller underneath, URL below.
- Glass course cards on white: translucent white gradient, hairline, backdrop blur, a soft brand-blue glow behind the grid.
- Type: everything Geist 400, as the live site (no bold).
Workflow
- Brief, one round. Ask with options: destination (→ aspect), length, the opening scene, which story. Default: 16:9, ~40 s, no voice-over, opening on the product's own UI (the reference opens on a search bar typing the new URL).
- Brand capture from the live site (or a local dev server when it is not published yet): colors and fonts from its CSS, screenshots of the sections the video shows, logos (rule 10).
- Write the scene map — scene, seconds, move in, move out — in the project. The reference map below is the template.
- Adapt
reference/index.template.html: replace copy, assets and colors, and rebuild the signature transition for the new brand (the Product Hub portal code —ISO,O, the star path — is only an example of how one was built). Build withpython3 v2/build.pyfrom the project root. - Check before showing:
npx hyperframes lint, thennpx hyperframes snapshot --at <times>and read the contact sheets at every cut; for anything that must align (a handoff, a mask), seek the timeline in a browser and compare bounding boxes numerically. Read frames of the rendered MP4 too (ffmpeg -vf fps=…,tile=…): the renderer differs from the browser. - Render with
npx hyperframes render --quality high --output renders/vN.mp4and give the user the path. - Soundtrack (below), muxed onto the last approved picture.
Soundtrack
- Music: the user generates it from
reference/music-prompt.md, adapted to the new scene times. - Re-cut it onto the picture with
mix.py: measure the tempo and the hits (librosa), find the exact transients with a 40–120 Hz band RMS at 20 ms resolution, and cut only on the same beat position of the bar, with 50 ms equal-power crossfades. Do not trust the generator's seconds or BPM. - The reference arrangement:
- quiet ambient intro;
- the beat lands on the first big visual moment;
- from the moment the brand's logo is complete on screen, a progressive fade (slow start, about −48 dB in 2.4 s) feeding a tempo ping-pong echo, so the silence before the turning point breathes;
- a DJ rewind (the groove reversed, speeding up, anti-aliased) leading into the signature transition;
- the song explodes on the signature transition and runs uncut to the end, the loud part settling 3.5 dB lower with softened highs after the first hit;
- a fade to zero starting with the closing slogan.
- Sound effects: only UI sounds — one synthesized mechanical key per typed character, the mouse click (press + release) with a soft pop. Whooshes, impacts, chimes and shimmers were tried and removed.
- Master: gain first, then
alimiter(limit 0.84), −14 LUFS integrated, true peak ≤ −1 dB. Neverloudnormin dynamic mode: it squashes the quiet intro. Mux with-c:v copy.
Engine pitfalls (each one cost a round)
clip-path: url(#svgClipPath)and SVGfilter: url()do not work in the render; use CSSmask-imagewith an SVG data URI, or plaincircle()/inset()clip-paths.- Tweening
mask-position/mask-sizeas strings misinterpolates (it landed at a tenth of the size); drive them through numeric CSS variables (--mx,--my,--mw,--mh) andcalc(var(--mx) * 1px). fromTorenders its from-state at build time: an element that must stay hidden until its moment needstl.set(el, { opacity: 0 }, 0)plusimmediateRender: false(a click ripple showed from frame 0).- Zero-duration tweens render wrong under seek; use ≥ 0.05 s.
- An ease with overshoot on
filter: blur()goes negative and is ignored (text stayed blurred): split position (with overshoot) and opacity/blur (no overshoot) into two tweens. opacity < 1orfilteron an ancestor flattenspreserve-3d: build rings as a 2D rotation inside ascaleYwrapper with counter-rotated children.- A camera zoom below 1 shows the page background at the edges: give the layer its own ground.
- Standalone tests need
window.__timelines = window.__timelines || {}before registering.
The reference video's scene map (Product Hub, 41.9 s) — an example of rhythm, not a script
| Seconds | Scene | In → out |
|---|---|---|
| 0 – 6.4 | Search bar types the new URL, click, the bar opens into the site's header | pill rises; window grows from the pill; scroll exits upward |
| 6.1 – 9.9 | "Es tiempo de construir" | born from below on the scroll's motion; shrinks into the fixed anchor |
| 9.65 – 16.5 | Four dynamic lines, alternating grounds | circle · wipe up · whip pan · circle; anchor fixed, recolored by the edge |
| 16.25 – 21 | "La IA reescribe los roles de / Producto. UX. Tecnología." | zoom-through in; scale-up blur out |
| 20.7 – 25.8 | Logo lockup + tagline, then the camera dives into the star of the P | portal; the next scene appears when the star fills the frame |
| 24.45 – 31.4 | Programs on white, glass cards in a diagonal wave | forward move continues; white tints to blue on exit |
| 30.95 – 36 | "Equipos de las siguientes empresas confían en nosotros", logo ring | camera pull-back while the ring keeps turning |
| 35.9 – 41.9 | Inverse portal: the P returns from huge with the logos inside, goes dark, settles; lockup, slogan, URL | fade to black |
What this skill never does
- Hand scenes to parallel sub-agents.
- Take colors, fonts or layout from a reference video.
- Rotate the frame.
- Carry a Product Hub-only decision to another brand without asking.
- Bounce every line.
- Add sound effects beyond typing and clicks.