Create and revise code-driven videos with Canvas, SVG, HTML/CSS, Three.js, Remotion, Manim, or p5.js, including sound, deterministic frame capture, visual review, and MP4 verification. Use for rendered explainers, procedural animations, motion graphics, promos, and music-synchronized films; not for general web apps, scroll-driven HTML stories, or footage generation with video models.
91%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
A code video is a program frame(t) → image, sampled at t = i / fps and encoded. Almost every failure in this kind of work is one of four things: the film is never finished, the picture depends on wall-clock time, nobody looked at the frames, or the file does not match the brief. This skill prevents those four.
Use a separate project folder for the video source, SPEC.md, build files, and outputs. Resolve SKILL_DIR to the absolute directory containing this SKILL.md, whether installed in the agent's skills directory or used from this repository. Run project commands from the video project folder; invoke bundled scripts through "$SKILL_DIR/scripts/..." so they do not depend on the current working directory. Set SKILL_DIR again in each shell session if needed.
Requirements: Node.js 18+ for browser capture, Python 3, FFmpeg/ffprobe with libx264 and AAC, and fonts covering the requested language. Install Playwright (with Chromium) or Puppeteer in the video project; the capture helper resolves its packages there first. Python audio dependencies are listed in requirements.txt; edge-tts needs network access, and faster-whisper needs downloaded model weights for transcription checks. Install only the tools required by the chosen renderer and audio workflow. Setup and invocation examples: English guide / 中文指南 in the source repository; these repository guides are not required when the skill folder is installed on its own.
Deliver the playable MP4, source code and reproduction commands, SPEC.md, VERIFY.md, and a contact sheet. Audio stems and timing data belong in the project when sound is used.
Reference paths are relative to this skill folder; output and input paths in commands are relative to the video project. Besides this file it holds craft guides in references/ and helper scripts in scripts/ (audio packages in requirements.txt). Read every guide that matches the request before writing SPEC.md; most videos need two or three.
| Guide | Read when the request has… |
|---|---|
references/explainer-diagrams.md | anything to teach or explain: math, science, history, processes, data |
references/stylized-looks.md | a named style, medium or artist (ink wash, pixel art, cut paper, vaporwave, watercolour, …) |
references/simulations-and-generative.md | particles, flocks, cellular automata, physics, fields, shaders, generative patterns |
references/character-and-creature-motion.md | people, animals or creatures that move or act |
references/threejs-scenes-and-cameras.md | a 3D scene, product or camera move |
references/motion-graphics-and-promos.md | kinetic type, UI, logos, product or brand promos |
references/sound-design-and-narration.md | any audio: narration, music, effects, ambience |
references/music-and-beat-sync.md | music-led films, beat-cut picture, supplied tracks or lyrics |
A request that names a style always needs references/stylized-looks.md, and a film with any audio always needs references/sound-design-and-narration.md.
SPEC.md. Ask the user only about the few open choices that would change the whole film (for example language, aspect ratio, length, or whether there is a voice), and only when you can ask; otherwise choose a sensible default and say which.Before writing code, write SPEC.md in the project folder:
Choose the stack for the content, not out of habit:
| Content | Good default |
|---|---|
| 2D diagrams, math, particles, pixel art, painterly textures | Canvas 2D (browser or @napi-rs/canvas in Node) |
| Crisp vector shapes, UI, kinetic type, logos | SVG / HTML+CSS driven by a paused timeline, or Remotion |
| LaTeX-heavy math | Manim (or KaTeX/MathJax rendered to SVG) |
| 3D scenes, products, cameras | Three.js (see references/threejs-scenes-and-cameras.md) |
| Shaders, aurora, fields, post effects | WebGL / GLSL fragment shaders |
t, for example window.seek = async (t) => {...} plus window.READY = true once fonts and images are loaded. Frame i is rendered at t = i / fps.t must always give the same image, in any order, in a fresh page. Forbidden: Date.now(), performance.now(), requestAnimationFrame loops that advance state, CSS transitions/animations left running, a playing GSAP timeline, unseeded Math.random(), state carried over from the previous frame.paused: true timeline and call tl.seek(t). CSS animations: set animation-play-state: paused and a negative animation-delay, or compute styles from t yourself. Remotion: derive everything from useCurrentFrame().function mulberry32(a){return function(){a|=0;a=a+0x6D2B79F5|0;let t=Math.imul(a^a>>>15,1|a);t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296}}t (interpolate between stored steps). Never integrate inside the render call.t (smoothstep, cubic in/out, closed-form damped springs). A value that changes target several times is a sum of eased segments, still a pure function of t.scripts/capture.mjs serves the project folder, opens the page in headless Chromium (Playwright or Puppeteer, resolved from the project's node_modules first), calls seek(t) for each frame and pipes screenshots into ffmpeg:
node "$SKILL_DIR/scripts/capture.mjs" <project_dir> --page index.html --fps 30 --dur 12 --size 1920x1080 --out out/video.mp4
Test it on 2–3 frames (--frames 3) before anything else. If Chromium cannot start (for example missing system libraries) and you cannot fix that quickly, switch early to a path that needs no browser: Canvas 2D in Node with @napi-rs/canvas, or Manim. Do not spend your time fighting the browser.@napi-rs/canvas and write raw RGBA to ffmpeg's stdin (-f rawvideo -pix_fmt rgba -s WxH -r FPS -i -).-c:v libx264 -pix_fmt yuv420p -crf 18 -preset medium -movflags +faststart. A film without sound has no audio stream (-an), not a silent track. Sound is muxed in a separate step (section 10). Width and height must be even.np.roll); crop to the visible window and precompute static layers once.--start and --frames (each chunk to its own file, all from the same seek(t) code), then join them losslessly: list the chunks in chunks.txt (file 'part_000.mp4' …) and run ffmpeg -f concat -safe 0 -i chunks.txt -c copy video.mp4. Check the joined frame count.flush=True to a log. Before you inspect a result, confirm it came from the run you just started (timestamp, a config line in the log), not from an older file.echo $! > build/sim.pid) and stop it with kill $(cat build/sim.pid). pkill -f <pattern> can match your own shell command and kill it.Pixels are the only evidence. Repeat this loop at least twice.
You know what the code is meant to draw, so you will tend to see it in the frame even when it is not there. Read every still in two steps:
sh "$SKILL_DIR/scripts/contact_sheet.sh" out/video.mp4 out/sheet.jpg 1 (one frame per second; use 2 s steps and 8 columns for films over a minute) and read it end to end: composition, readability, continuity, empty or broken frames, and for long films whether sections look alike.Readability rule of thumb: after a text finishes animating in, hold it about letters / 15 + 1.5 s (English) or characters / 4.5 + 1.5 s (Chinese); a title card at least 2 s in a short film. Never shrink text below about 28 px at 1080p to make it fit.
Run sh "$SKILL_DIR/scripts/check_video.sh" out/final.mp4 1920 1080 30 10 15 (add 1 or 0 at the end to require or forbid an audio stream). It reports resolution, fps, duration, frame count, codec, pixel format, audio streams and their length, black segments and frozen segments, and fails on mismatches. Then go through SPEC.md line by line against the actual frames and write VERIFY.md: each must-have, pass/fail, and the timestamp or still that shows it. Do not write "checked" for anything you did not look at.
Evidence in VERIFY.md is what the pixels show, not what the code does. "Pavilion mid-slope, drawn by draw_pavilion()" is not evidence. "t=38 s still: a small roofed pavilion is visible at about (820, 410), about 60 px tall" is. If the pixels do not show a must-have clearly, mark it FAIL and fix it, or list it as a known gap.
| Symptom | Cause | Fix |
|---|---|---|
| Video plays too fast or jitters | Animation driven by wall clock or rAF during capture | Drive everything from t |
| First frames blank or fonts wrong | Captured before fonts/images loaded | Set READY after document.fonts.ready and image decode |
| Particles or textures shimmer | Randomness re-drawn every frame | Seed once, store per-object values |
| Subject too small or pushed to an edge | Never checked stills at final size | Subject ≥ 1/3 frame height at key moments |
| Subject not recognizable (a koi that reads as a leaf, a mountain that is a triangle) | Shape built from primitives and judged against intent | Cold read (section 5); design the silhouette first and check it at thumbnail size |
| Hero effect weak (tiny, dim fireworks; reflections brighter than the bursts) | Background details compete with the subject | Make the subject the highest-contrast element; dim the rest |
| Hours lost reconstructing a pattern or constant | Recalled from memory and debugged by trial | Timebox (section 1); use reference data in the craft guides |
| Text overlaps or leaves the frame | Positions estimated, not measured | Measure text boxes with the real font; keep a 5% safe margin |
| Duration or fps off by a few frames | Rounding or a CSS/GSAP duration mismatch | Frame count = round(dur × fps); check with check_video.sh |
| Invented claims on screen | Copy written from memory | Only the strings in SPEC.md |
STRUCTURE.md: the sections or movements in order, what each one shows and changes, roughly how long each takes, and how each hands over to the next. Total the estimates against the target length.When the brief asks for a loop, make every animated quantity periodic with a period that divides the loop length (rotations, oscillations, noise offsets, camera paths, overlay grain). Frame N would equal frame 0; render frames 0 … N-1. Check by playing the end into the start and by comparing the last and first frames: they must be consecutive states, not duplicates. Simulations that must loop are designed on the loop period from the start (see references/simulations-and-generative.md).
SPEC.md. When it asks for sound, plan and build it with references/sound-design-and-narration.md; for music-led films also references/music-and-beat-sync.md. When it says no audio, deliver no audio stream.scripts/audio_check.sh and scripts/sync_check.py.fc-list. Use fonts from the environment or from the project's assets/ (install others only if you may, and respect their licences); check that every glyph renders (no tofu boxes, especially for Chinese).When the brief supplies video clips to show inside the film (in a card, a screen, a wall of tiles):
ffprobe each clip for size, fps, duration and audio. Write in SPEC.md which window of which clip appears where (clip in/out time, film start time, speed, size on screen).<video> elements during capture. Seeking a video in headless Chromium is asynchronous, slow and may show the wrong or a blank frame. Extract each window to an image sequence first, at the film's fps and the size it is shown at:
ffmpeg -ss IN -t DUR -i assets/clip.mp4 -vf "fps=30,scale=1280:720" -q:v 3 build/clips/clip/%04d.jpg
Preload the images before READY. In seek(t), draw frame floor((t - start) * fps), clamped to the window, so frame i of the film always shows the same clip frame. Several tiles of the same clip can reuse one sequence with different offsets.fps= in the extraction resample it; never change the speed by dropping or repeating frames by hand.-ss IN -t DUR -vn) and mix it as its own stem, aligned to the film start time.OpenSenseNova/SenseNova-Skills
95db9cf
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.