product-video — Create Product Introduction Videos with Code
Rebuild the product's UI in HTML, write motion so that "time alone determines everything," capture each frame in a headless browser, and synthesize music and sound effects in the browser. All you need is Node.js, ffmpeg, and Chromium.
This skill includes a ready-to-run template (assets/template/). It comes with tools for rendering, audio, and quality inspection, plus a 30-second sample video. Instead of building the mechanism from scratch, duplicate the template and swap out the content.
Important Assumption: You Can't See or Hear It Yourself
You cannot play the video to check it. Therefore, the quality of this work depends on the number of times you export still images and inspect them with your own eyes, and on numerically measured quality checks. If you just write code and assume "it must be done," you'll inevitably end up with cut-off text, overlaps, and momentary glitches. Check each scene visually side-by-side before moving to the next, fix issues immediately, then proceed. You cannot hear the audio, so present measured numeric values and ask a human to verify the audible quality.
Rules to Follow (With Reasons)
- Appearance must be determined only by time. Stack motion with
tl.*for "at what second" or calculate it directly from t usingonFrame((t) => …). Do not use CSS animation/transition,setTimeout,Math.random(), or current time. Because the same frame always appears for a given time, you can render in parallel and re-render only specific parts. - Inspect after writing. After writing each scene, use
--sheetto arrange frames side-by-side and open the image to inspect. Check scene transitions in 0.1–0.2 second increments. Do not proceed to the next scene without inspecting. - Do not animate text-heavy components slowly. The browser aligns text to pixel boundaries, so moving text slightly over several seconds causes it to vibrate/flicker. Move containers and headings swiftly (within about 1 second), then animate content inside the static container. Only background light can move slowly.
- Use
tl.infor entrance,tl.out/tl.hidefor removal.tl.fromTokeeps the original value until the start time, so if used for entrance, it may briefly appear before the intended moment. - Write CSS for the product's UI under the root scene class (e.g.,
.ui-chat .row). Using short names like.row.titlebare will conflict with template components or other scenes, causing hard-to-notice visual breaks. - Ensure readable sizes. The video will be viewed on mobile phones. Headings must be 68px or larger; body text within containers must be 18px or larger on screen (font size × scale). For small screens, either enlarge the entire container or zoom in to the area of interest.
- Do not bend the truth. Do not include anything that cannot be verified in source materials. Do not show something that cannot be done as "possible." Do not include unverified numbers, comparisons with other companies, or endorsements. Do not draw other companies' logos; write their names as text. On the final card, insert a small note (via
brand.fine) stating that the UI is a reconstruction. - Place scene boundaries and major motions on the beat. The moment a logo snaps into place, scene transitions, and the final card should be at the same time as a hit point in the music (
hit: true). This makes the whole piece feel tight. - Do not change volume or timbre. The values in
kit/audio.jsare balanced through measurement. Changing them without being able to hear will cause imbalance. Only modify the music sections (plan.js) and the sound effect cues. - Do not write "confirmed" for what you haven't measured. Always state in your report that you have not listened to the audio.
Procedure
There is a confirmation at the end of each stage. Do not skip confirmations (fixing later is much more expensive).
This is a lengthy task. If the context gets compressed mid-task and you forget details, reread this file and the references/ for that stage. Leave the decided structure (scene table) as comments at the top of src/js/plan.js so you can resume even after interruption.
0. Preparation
node "${CLAUDE_SKILL_DIR}/scripts/new.mjs" video # Duplicates the template into video/ (adjust location as needed)
cd video && npm install --ignore-scripts
node render.mjs --sheet 0:29:2 # If the sample video's contact sheet appears at out/sheet.png, preparation is complete
${CLAUDE_SKILL_DIR} is the folder containing this SKILL.md. When the literal string appears, replace it with the absolute path of this file's folder.
If the browser is missing, run npx playwright install chromium. If that environment is impossible, use the installed Chrome or Edge (execute with environment variable CHROME_CHANNEL=chrome or CHROME_CHANNEL=msedge). If ffmpeg is missing, install it.
First, look at the sample src/js/scenes.js and the exported out/sheet.png. Examples are faster to understand component usage than explanations.
1. Research
Every fact shown in the video must have a source. Read the README, documentation, design guidelines (colors, typography, spacing), and actual UI text, then write down:
- Who has what problem, and how the product solves it (in one sentence)
- Features to highlight and the evidence (which part of which document)
- Actual UI text that appears on screen (button names, status messages, notification text). Fake text will be immediately spotted by someone familiar with the real product
- Actual visual appearance of the UI. If screenshots or UI mockups are available, open them and copy the layout, colors, spacing, and font sizes. If not, extract from UI code (components, styles, design tokens)
- Supported environments, constraints, and assumptions (to avoid overpromising)
If not specified in the request, decide the following yourself and proceed, then include them in the report: length (60–90 seconds; shorter requests can be 30 seconds), language (product UI and document language), and whether to use bright or dark scenes. Only ask the requestor about brand colors, logo, and fonts if the documents don't contain them.
2. Decide the Structure
Create a scene table before building. The structure template, heading style, and timing guidelines are in references/direction.md. Read it before proceeding.
- Communicate one idea per scene. Keep the scene heading to one idea. Do not make it a list of features
- Start with the "problem," not the product
- Place scene boundaries on beats (at 120 BPM, every 2 seconds)
- Write the
T(scene start times) andmusic(music sections) insrc/js/plan.jsaccording to this table
Briefly show the decided structure to the requestor. You may start building without waiting for approval (if the direction is wrong, you'll find out earlier).
3. Prepare Brand and UI
src/js/brand.js: Name, tagline, colors, fonts, logo. Values must come from the actual productsrc/css/app.cssand the HTML inscenes.js: Reconstruction of the product's UI. Match colors, dimensions, and text to the real thing- Before adding motion, render a still with
--shotand compare it to the real UI. If they don't match when static, they won't match in motion
Do not paste screenshots; rebuild the UI in HTML. This allows you to animate individual components, zoom in without pixelation, and switch colors per scene.
4. Build Scene by Scene
Write a function for each scene in scenes.js. Components and writing style are in references/kit.md. Read it before you start writing.
For each scene, repeat the following:
node render.mjs --sheet 14:26:1 # Arrange frames of that scene at 1-second intervals → open out/sheet.png to inspect
node render.mjs --shot 16.6,22.5 # View specific frames at 1x → out/shots/
node render.mjs --sheet 13.4:14.6:0.1 --cols 7 --w 420 # View scene transitions at 0.1–0.2 second increments
node render.mjs --lint # Automatically detect cut-off text, overlaps, and too-small fonts
Points to check: Is text cut off? Are elements overlapping? Are fonts readable? Is spacing balanced? Is it immediately clear what to look at? Are there leftover components from the previous scene?
As a rule of thumb, inspect each scene at least 3 times (right after writing, after fixing, and the transition before/after). For details too small to see in the contact sheet, use --shot at 1x.
5. Add Audio
Music is automatically composed from the sequence of sections in plan.js. Sound effects are triggered by cue("type", time) calls accumulated while building scenes. See references/audio.md for details.
node render.mjs --audio # out/audio-master.wav. Volume and peak levels are displayed
6. Full Review and Quality Check
node render.mjs # 1x full render (a few minutes for a 30-second video). out/video.mp4
node tools/qa.mjs # Checks format, volume, 1-frame glitches, dropped frames, black frames, silence
node render.mjs --sheet 0:90:1.5 --cols 6 # View the entire video (adjust duration to match video length)
Fix all ✗ issues. Read references/qa.md for how to interpret the QA output and how to fix common issues.
Now comes the finishing step. The first passing version is usually "not broken, but lacks impact." Look at the full contact sheet, list at least 5 things to improve, then fix them. Look for:
- Periods lasting more than 2 seconds with no action
- Large empty spaces, off-center compositions, empty areas inside containers (e.g., the bottom half of a phone screen is white)
- Moments where the cause-and-effect is unclear (button press → UI change not visually connected)
- Text, colors, or layout that differ from the real product
If you can't find 5 issues, your inspection interval is too coarse. Re-inspect at 1-second intervals, and 0.25-second intervals for critical scenes.
7. Export the Final Version
node render.mjs --scale 2 --keep-frames # Render at 2x scale, then downscale (3–4x slower than 1x). Run in the background.
node tools/qa.mjs
node tools/extras.mjs web # Create a lightweight version under 10 MB (for chat or GitHub sharing)
node tools/extras.mjs poster 15.9 # Generate a static poster frame (at the time that best tells the story)
Rendering at 2x scale produces smoother edges and reduces text vibration by half. If it stops midway, add --resume --reuse-audio to continue from where it left off. To re-render only a fixed section, delete the corresponding frame files (from out/frames/) and use --resume.
8. Report
Write the following briefly and honestly (template at the end of references/qa.md):
- What was produced (file location, duration, resolution) and a summary of the structure
- What was verified (QA results) and what was not verified. Since you haven't listened to the audio, always state: "Numerically within spec. Please confirm audible quality."
- What you decided yourself (duration, language, color usage, etc.) and what you could not verify from source materials
- That the UI is a reconstruction. How to request revisions
When Asked to Revise
When revising a video created with this template, do not start from scratch.
- Read
references/kit.mdand the relevant code. Headings and UI text are inscenes.js, final card text inbrand.js, timing and music inplan.js, UI appearance inapp.css - Make the changes
- Inspect the changed scenes and their transitions using
--shot/--sheet. Also run--lint - If scene length or music sections changed, also verify that
node render.mjs --audioproduces no warnings - If a new video file is requested, export it using steps 6–7. If not, report what you inspected and ask whether to export
Running node render.mjs without options starts a full render (taking several minutes or more). For inspection only, always use --shot, --sheet, or --lint. Usage: node render.mjs --help.
Quality Standards
Before delivering, verify yourself:
- Even with the sound off, the story is understandable from the headings alone
- The first 3 seconds present a problem that makes the viewer think "this is about me"
- In every scene, the focus is on a single element (not animating two things simultaneously)
- Someone familiar with the product would not feel any mismatch in the UI or text
- There are no
✗results in--lintortools/qa.mjs - All scene transitions have been inspected at 0.1–0.2 second increments
Reference Materials
| File | Contents | When to Read |
|---|---|---|
references/direction.md | Structure templates, timing, heading style, layout and animation guidelines | Before deciding the structure (required) |
references/kit.md | Role of each template file, engine and component usage | Before writing scenes (required) |
references/audio.md | Music sections, sound effect cue list, measurement methods | When adding audio |
references/qa.md | QA output interpretation, common issues and fixes, report template | During review and final export |
assets/template/src/js/scenes.js | Sample video; real examples of component usage | First step |