Community编程与开发github.com

ishmum123/kinetic-promo-video

Agent skill: promo videos from a deterministic HTML timeline - kinetic typography, animated UI mockups, frame-rendered with a headless browser and ffmpeg. Install: npx skills add ishmum123/kinetic-promo-video

kinetic-promo-video 是什么?

kinetic-promo-video is a Claude Code agent skill that agent skill: promo videos from a deterministic HTML timeline - kinetic typography, animated UI mockups, frame-rendered with a headless browser and ffmpeg. Install: npx skills add ishmum123/kinetic-promo-video.

兼容平台Claude Code~Codex CLI~Cursor
npx skills add ishmum123/kinetic-promo-video

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Kinetic Promo Video

Build a broadcast-looking vertical promo video from nothing but a description of the business. The video is authored as a single HTML page driven by a paused master clock, then rendered frame by frame and encoded. No editor, no stock footage, no timeline app — and every frame is reproducible from a timestamp.

Inputs

  • $brief — what the thing is, who it's for, what makes it different. Required. Pull it from the conversation, the repo's README, or ask.
  • $reference — optional. A video URL or local file whose look should be matched.
  • $brand — optional. Name, tagline, URL, colors, logo. If absent, use a clearly flagged placeholder (never silently invent a brand and present it as final).
  • $duration — optional. Default 30–35 s silent, 45–60 s narrated (the voice sets the length — see references/audio.md). Keep under 60 s for Shorts/Reels/TikTok.
  • $audiodefault: narrated, no music. Write a voice-over and build the timeline around it unless the user asks for a silent piece. Music is the one thing that stays off unless explicitly requested.

Goal

promo.mp4 — 1080×1920, 30 fps, H.264, playable and correct on first watch — plus the scene.html that generated it, a render.py that reproduces it, a voice.srt caption file for narrated pieces, and a README with the beat sheet and the constants to rebrand it. Success is not "a file exists": it is frames you have looked at that read cleanly, with no overlapping text, no elements visible before their cue, and no dead air.

Steps

1. Check the toolchain

which ffmpeg ffprobe yt-dlp python3
python3 -m venv .venv && .venv/bin/pip install -q playwright && .venv/bin/playwright install chromium

ffmpeg and a Chromium for Playwright are hard requirements. yt-dlp is needed only for reference teardown. Prefer a venv — the user's system Python may be externally managed.

Success criteria: ffmpeg -version works and .venv/bin/python -c "from playwright.sync_api import sync_playwright; sync_playwright().start().chromium.executable_path" prints a path.

2. Establish the visual target

Two paths — pick by whether $reference exists.

2a. Reference given → tear it down

Read references/teardown.md and follow it. In short: download it, probe it, extract 1 fps contact sheets, actually read the sheet images, and write down dimensions, duration, palette, type treatment, beat structure, and motion vocabulary before writing any code.

Never describe a reference you have not looked at frame by frame. A page's title or description tells you nothing about its motion design.

2b. No reference → derive the subject's own language first

Do not open default-style.md yet. Spend two minutes answering four questions about the actual subject:

  1. What are the objects? Books, jars, invoices, faces, a dashboard. These are what should move.
  2. What light do they live in? Reading lamp, showroom, moonlight, screen glow, daylight through a window.
  3. How do they physically move? Things with mass settle. Paper turns and creases. Liquids spread. Data snaps.
  4. What is the spine? The one recurring element carrying the argument — a countdown, a clock crossing a night, a receipt growing, a route filling in. Ideally it is the claim, not decoration.

If those four answers give you a coherent look, build that. A skincare promo about overnight repair gets night palette, serif type, slow settling motion and a dial running 10pm→7am — not glowing rings.

Fall back to the house style when the subject genuinely suggests nothing specific (most B2B software, abstract services). Then read references/default-style.md and use it as-is: it is a complete, validated spec (dark navy + blue glow, geometric sans, blur-in kinetic type, glowing horizon, ring outro). Tell the user which style you're using in one line and that they can swap it by naming a reference video — then keep going. Do not stall for approval.

Honesty check before you build. If your beat timings land within ~0.5 s of the template's and the signature shots survived — the echoed word stack, the ring bloom, the horizon-plus-slab card, blur-in as the only text move — you reskinned the template rather than designing for the subject. That is fine when you chose the fallback deliberately, and a defect when you didn't.

Success criteria: a short written spec — canvas size, fps, duration, palette hexes, font, and the motion moves you will use — that you can point back to while building. If you derived a subject-native language, it also names the spine and the moves you are deliberately not using.

3. Write the beat sheet

Read references/audio.md and write the voice track first — it is on by default. The voice owns the timeline: generate the lines, measure them, and derive beat times from the measurements rather than fitting speech into round numbers. Keep the measured per-line timings — they become voice.srt at delivery. Only skip this when the user asked for a silent piece.

Read references/beats.md for the structure and copy rules, then map the user's actual differentiators onto beats. The middle third is where the product is sold: it must contain the specific reasons this thing is better, not adjectives. Assume muted playback — most Shorts/Reels viewers never hear the voice — so every claim in the voice-over must also land as on-screen text, not only as narration.

Write the beat sheet out as a table (t-range → beat) before writing code. Getting the pacing wrong is far more expensive to fix after the scenes are built.

Artifacts: beat table with explicit second ranges summing to $duration.

Success criteria: every beat traces to something real about the product, and the ranges are contiguous with no gaps > 0.3 s.

4. Scaffold from the templates

$SKILL below is this skill's own directory — the one holding this SKILL.md. Resolve it from your skills listing rather than guessing a path; it is often mounted read-only, which is fine because everything gets copied out.

mkdir -p video && cp "$SKILL/templates/render.py" video/
cp "$SKILL/templates/scene-starter.html" video/scene.html
bash "$SKILL/templates/fetch-fonts.sh" video/fonts     # Poppins subsets, ~40 KB

scene-starter.html already contains the animation harness (seek, win, io, pop, swap, draw, seeded RNG, atmosphere) and seven example beats covering every pattern worth copying. Do not rewrite the harness — it encodes the bugs listed under Rules. Replace the example beats; keep everything above them.

Success criteria: python render.py --contact produces contact.png from the untouched starter.

5. Build the scenes

One IIFE per beat, each creating its own layer() gated by win(layer, tIn, tOut). Inside, every animated element gets exactly one io() / pop() / swap() call.

Build UI mockups (dashboards, phones, laptops, cards, chips) as plain DOM + CSS and animate them in — they carry the "real product" feel that pure type cannot. Charts are divs and inline SVG; no chart library, no images, no external requests.

A hard cut is a legitimate move: two win() layers sharing an exact time boundary, entered with steps(1,end), give a deliberate single-frame cut — the right tool for a tonal snap such as story-world → flat brand color. Everything else eases; the cut lands because it is the only one.

Real multicolour logos are often illegible on both dark scenes and flat brand grounds — put the asset on a small white plate rather than recoloring it.

Rules: see the Rules section. They are not style preferences — each one is a specific failure this skill has already hit.

Success criteria: python render.py --contact renders without errors.

6. Preview loop — look at every frame

python render.py --contact          # 24-frame overview, ~20 s
python render.py --at 6.2 12.0 19.5 # specific moments, full resolution

Read the resulting PNGs with your image-reading tool — whatever the harness calls it — and inspect them. Then fix and repeat. Iterate here until the sheet is clean — a full render is 10× slower, so never use it as your feedback loop.

The two views answer different questions. The contact sheet is for structure: timing, overlaps, dead frames, beat order. It is 270×480 per frame and it systematically under-reads dark or low-contrast work — a piece that looks muddy and broken on the sheet is often clean at full size. Judge contrast, palette and legibility only from --at frames, and pull at least one per beat whenever the palette is dark, plus one per pictogram or illustration — recognizability cannot be judged at tile size (see Rule 12). Do not raise brightness to fix something the sheet exaggerated.

What to hunt for on every pass:

  • two pieces of text legible at once mid-transition
  • anything visible before its cue (the classic fill: 'both' bug — see Rules)
  • background elements that read as recognizable shapes instead of atmosphere
  • stacked translucent blobs — overlapping alpha layers composite into visible intersection arcs and read as discs; use one element with a rim that dissolves inside its own box, sized larger than the frame
  • dead frames — any moment with nothing on screen
  • text or mockups crowded against the frame edges, or too small for a phone screen

Human checkpoint: none required, but if the user is present, show them the contact sheet before the full render — pacing and copy notes are cheapest now.

Success criteria: you have viewed a contact sheet in which every frame reads cleanly and no defect above is present.

7. Render and verify

Smoke-test the encoder first. Render a ~2 s slice — via a range flag if your render.py copy has one, otherwise by temporarily shrinking the duration constants — and ffprobe the result. Encoder and mux problems surface in seconds here instead of after a multi-minute full render.

python render.py                    # -> promo.mp4, ~1 screenshot per frame
# narrated pieces: mux only after the encoder process has EXITED
ffmpeg -y -i promo.mp4 -i vo/voice.wav -c:v copy -c:a aac -b:a 192k promo_av.mp4
ffprobe -v error -show_entries format=duration \
        -show_entries stream=codec_type,codec_name,width,height,nb_frames \
        -of default=noprint_wrappers=1 promo_av.mp4
ffmpeg -y -v error -i promo_av.mp4 -vf "fps=1/1.2,scale=180:320,tile=10x3" -frames:v 1 verify.png

Run the full render in the background. It is ~1 screenshot per frame — a 50 s video is ~1500 frames and comfortably exceeds a 600 s command timeout. Poll for the render process to exit, not for the mp4 to appear: the file exists on disk long before it is finished, and muxing early gives moov atom not found.

For narrated pieces, write voice.srt from the per-line timings measured in step 3 — the numbers already exist; this is a formatting pass, not new work.

Read verify.png — verifying the encoded output, not the browser, is the point. Then delete the scratch sheets

相关技能