Communitygithub.com

josueh04/product-video-skills

Compose a narrated product demo in HyperFrames: the stage (the product UI rebuilt at its real viewport and scaled to 1080p, camera, rack focus with veil, chapter titles, cursor and clicks, typing, streaming text, pop-ups, toasts, scrolls, end screen and lockup) and the build.py that anchors every beat to a word of the narration. Use it whenever you write or edit a video's video/build.py, src/template.tpl or src/app.css, place a beat on a word, add a chapter, a click, a pop-up or a push-in, frame a screen, build the end screen or lockup, snapshot setup beats, or render a draft or delivery MP4 of a product video in this workbench. Also use it when someone says "the cursor is off", "too zoomed in", "too fast", "it feels chaotic", "the title flashes", "sync the UI to the voice", or asks for a walkthrough, demo or pitch video of a UI.

¿Qué es product-video-skills?

product-video-skills is a Claude Code agent skill that compose a narrated product demo in HyperFrames: the stage (the product UI rebuilt at its real viewport and scaled to 1080p, camera, rack focus with veil, chapter titles, cursor and clicks, typing, streaming text, pop-ups, toasts, scrolls, end screen and lockup) and the build.py that anchors every beat to a word of the narration. Use it whenever you write or edit a video's video/build.py, src/template.tpl or src/app.css, place a beat on a word, add a chapter, a click, a pop-up or a push-in, frame a screen, build the end screen or lockup, snapshot setup beats, or render a draft or delivery MP4 of a product video in this workbench. Also use it when someone says "the cursor is off", "too zoomed in", "too fast", "it feels chaotic", "the title flashes", "sync the UI to the voice", or asks for a walkthrough, demo or pitch video of a UI.

Compatible con✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/josueh04/product-video-skills/tree/HEAD/skills/ui-demo-composer

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

UI demo composer

A product video here is one HyperFrames composition built from three files you write per video and a kit shared by every video:

FileWhat it isWho edits it
video/build.pyThe beat table T: every time derived from word timingsYou
video/src/template.tplThe rebuilt UI, the screen layers and the GSAP timelineYou
video/src/app.cssThe product UI CSS, literal values from specs/You
kit/stage.css, kit/titles.css, kit/stage.jsStage layers and seek-safe helpersThis skill
products/<slug>/kit/tokens.css, fonts/, icons/, ui/The product's tokens, fonts, icons and shared UI piecesproduct-kit
video/index.htmlGenerated by build.py. Never edit it by handNobody

scripts/buildlib.py does the generic part of every build (timings, the signature gate, audio tags, inlining, placeholders, icons, the camera clamp) so build.py stays a short list of beats.

The stage model

#root > #stage > #camera > #blurWrap > #app      the product, in app pixels
               > #veil, .pvs-ttl, #endS, #lock, #fade      screen space, 1920x1080
  • The UI is rebuilt at its real viewport and scaled once. #app is product.yaml app_canvas.logical CSS pixels (for example 1440x810), scaled to 1920x1080 by one transform. Production CSS keeps its literal pixels, so a spec value pastes in unchanged and every measurement compares 1:1 against the code. Pick a desktop width above the app's breakpoint, in 16:9; if there is a screen recording, use its logical size. A canvas that is not 16:9 is letterboxed (buildlib warns).
  • Positions are measured, never typed. S.box(sel) sums offsets up to #app after fonts load. If the CSS changes, the cursor still lands on the button.
  • The cursor and the click ripple are the last children of #app, so they scale and blur with the product. Pop-ups (.pvs-modal) and toasts (.pvs-toast-slot) live in #app too.
  • Only #camera moves and only #blurWrap blurs. Never tween #app or #stage.

Framing: 1x full page by default

Default every product beat to 1x, full page, with pop-ups at their natural size and centred the way the app shows them. Push-ins are gentle (up to video.max_zoom, 1.35 by default), keep the whole section in frame and never put a frame edge through a label. One framing per chapter: make the move behind the chapter title while the product is out of focus, or as one slow signature move.

Why: in the production these skills come from, a settings video was rejected twice for zoom. A 1.67x punch-in cut labels in half ("I can't tell what is happening"), and later framings of about 2x per column felt cramped even with nothing cut. The video the reviewer held up as the model ran at 1x the whole time. A far-out canvas (shown at 50 %) or a narrow chat column tolerates more: raise max_zoom in product.yaml for that product, not per beat. b.cam() and S.cam() clamp above max_zoom and warn. Details and numbers: references/framing-and-pacing.md.

Pacing: chapters are pauses

  • Open on context, never mid-UI: logo, product name and one line on what it is, over the product out of focus.
  • Each chapter opens with a two-tone title over the product racked out of focus (blur plus a veil), holds at least about 1.4 s, and focus returns just before the word that names the first action. Screen changes happen behind the title, so there are no hard cuts.
  • One idea per chapter, one change at a time, 0.6 to 1 s apart, a hold of about 0.8 s at the end of each chapter. Real waits of the product compress to 1 or 2 s.
  • The end screen shows breadth (what else the product does, with real UI pieces), then the lockup.

Why: a dense one-take cut with a micro-action every 0.5 s read as polish to its maker and as noise to the reviewer ("too fast, too much at once, overwhelming"); zooming in and out in the results made them impossible to follow. The calm chaptered version was approved.

Every beat is anchored to a word

b = buildlib.Build(__file__)
T, w, end = b.T, b.w, b.end
T["N2"] = T["ch1"] + 0.3                                  # placing a clip id places that clip
T["rack1"] = T["N2"] + w("N2", "after") - 0.25            # focus returns just before "after"
T["send1"] = max(T["type1"] + T["type1Dur"] + 0.4, end("N3") + 0.15)
  • w(clip, prefix, nth=1) is the start of the first word beginning with prefix, relative to the clip. It raises when the word is missing (no silent fallback: a fallback that quietly lands a beat at a default time is how motion drifts away from the voice unnoticed).
  • A UI event leads the word that names it by 0.05 to 0.45 s. max() keeps both the narration order and "the UI has finished"; end(k) is T[k] plus the clip duration (or b.dur(k, d)).
  • Typing speed is characters per second (about 17 to 21), or fixed to fit a beat.
  • Clicks, typing and pops get their sound on the same T (b.click(t), b.typing(text, t, dur), b.pop(t)), so a retimed beat moves its sound too.
  • Regenerating one line of voice re-times the whole video. That is the point.

Why: timing has one source of truth. When a line is regenerated, everything anchored to it moves together; hand-typed seconds go stale at the first retake.

Workflow

  1. Read BRIEF.md (chapters, framing), COVERAGE.md (what each chapter must explain on screen), specs/*.md and TRUTH.md. Do not invent UI: a screen or behaviour without a source in SOURCES.md or specs/ stays out.
  2. Rebuild the screens in src/template.tpl and src/app.css from the specs, with fictional data from product.yaml cast. Reuse product pieces from kit/ui/ with {{UI:name}} instead of copying them from another video (references/ui-component-library.md).
  3. Write the beats in build.py and the timeline in the template with the kit helpers (references/stage-kit.md for the API, references/beat-recipes.md for each beat, references/end-screen-and-lockup.md). Follow the seek-safe-motion skill for every tween.
  4. Build a draft and read the beat table it prints:
    PVS_HOME="$(cd "$(cd "${CLAUDE_SKILL_DIR}" && pwd -P)/../.." && pwd)"
    "$PVS_HOME/bin/pvs-py" <video_dir>/video/build.py --draft
    
    Before any voice exists, --draft --fake-timings invents word timings from lines.tsv so you can lay out screens.
  5. Lint and check, from <video_dir>/video/:
    "$PVS_HOME/bin/pvs-py" "$PVS_HOME/skills/seek-safe-motion/scripts/lint_motion.py" .
    npx --yes [email protected] check
    
    Expect 0 errors and 0 runtime warnings. One lint warning is expected for the monolithic stage: composition_file_too_large (the kit is inlined). Then run the second check the build prints, check --at <setup beat times>: the default samples often land only on racked moments, where the kit hides product text from the contrast pass (it is blurred on purpose), so contrast ... checked 0 there audited nothing a viewer reads. check alone is not enough: it passed on a video where moving items were invisible for most of their path. Look at frames.
  6. Snapshot every setup beat and look at each image yourself. Mark them with b.snap(t, label) in build.py; the build prints the exact command:
    npx --yes [email protected] snapshot . --at 3.2,4.7,9.98 --no-end --describe false -o snapshots/setup
    
    --no-end captures only those times; --describe false keeps frames from being sent to an external vision API. Check the framing (nothing cut at an edge), the cursor on its target, pop-ups centred at natural size, titles whole. --zoom "#toast" --zoom-scale 2 crops one element. To test a suspicious tween, --at <start>,<later> must match --at <later>.
  7. Render. A draft for review, then delivery once BRIEF.md is signed (build.py prints this line):
    npx --yes [email protected] render . -o renders/<video>-v<k>.mp4 --fps 30 --quality draft
    npx --yes [email protected] render . -o renders/<video>-v<k>.mp4 --fps 30 --quality delivery
    
    Then run render-qa on the MP4. Keep every version's MP4.

The signature gate

build.py refuses to build until coverage_signed_by and claims_signed_by are set in BRIEF.md (exit 2). --draft builds anyway and stamps <meta name="pvs-draft" content="1"> into index.html; QA marks its report as a draft and delivery refuses it. Do not sign on the reviewer's behalf, and do not strip the meta: a draft is for looking, never for shipping.

Why: in the production these skills come from, 9 of 26 versions happened because a video did not explain a feature the reviewer cared about, and nobody had written those features down before building. The gate makes the agreement come first.

Rules that come from incidents

  • Fix production glitches, keep the look. Keep layout, tokens and behaviour 1:1, but fix visible defects of the live app (missing padding, overflowing or cut text, grey native controls, a focus ring left after a click). List every fix in BRIEF.md notes.
  • Show what is configurable when the product is configurable: the settings a buyer would ask about belong on screen, not only in narration.
  • Close a menu one frame before opening a modal over it. An open dropdown under a new dialog left ghost text in one render.
  • Fade only the end screen content into the lockup, keep its background until the lockup is up. Fading both showed a frame of sharp UI between them (S.lockup does this).
  • Hover before the click (hov class about 0.12 s before), cursor in after the first rack and out before the end screen.
  • No vendor or banned names in UI, data or narration (product.yaml banned_terms, names). If a real screen shows one, keep that piece out of frame, and never leave it visibly empty.
  • Do not render to show progress early. Iterate with snapshots; render when the setup beats look right.

Files

PathRead it when
references/stage-kit.mdYou need a helper's signature, a placeholder, a CSS variable or the buildlib API
references/beat-recipes.mdYou build a specific beat: opening, chapter, click, typing, streaming, pop-up, dropdown, toast, scroll, push-in
references/framing-and-pacing.mdYou choose a framing or a rhythm, or the reviewer says "zoomed", "fast", "chaotic"
references/end-screen-and-lockup.mdYou build the ending
references/ui-component-library.mdA UI piece will appear in more than one video, or you are about to copy markup from another video
scripts/buildlib.pyYou need behaviour the API reference does not cover
kit/stage.jsSame, for the timeline helpers
PVS_HOME/_template/video/video/The example build.py, template.tpl and app.css every new video starts from

Individual skills in this repo

This repo contains 14 individual skills — each has its own dedicated page.

josueh04/product-video-skills

Extract, once per product, everything every video of it reuses and write it to kit/ and product.yaml (design tokens, font subsets as woff2, icon subsets as SVG from the product's own icon packages, logos in light, dark and app-tile variants from the repo, a fictional cast proposed once for veto and then frozen, the canonical-names map, pronunciations, banned terms and the read-only tool list). Use it when a product is set up or its kit is missing or incomplete, when a video needs an icon, font or logo that is not in kit/ yet, when someone asks for demo names, fake customers, phone numbers or emails, when a brand word is mispronounced or an old product name shows up, and when checking that demo data is fictional.

josueh04/product-video-skills

Interview the user about a product, then create products/<slug>/ with its own git history, a filled product.yaml and linked skills, fetch its sources and build its kit. Run only when the user types /product-new.

josueh04/product-video-skills

Back every sentence of a video's narration (audio/lines.tsv) and every screen it shows with a citation into the pinned source code (role/path:line@sha) or a docs URL, mark what is visible in the UI versus backend-only, flag restricted or unreleased features, and cut or rewrite anything unbacked; writes the video's TRUTH.md and checks it with truth_check.py. Use it whenever a script or narration is drafted or edited, before voice is generated, before a build, when someone asks "can we say this?", "is this true?", "does the product really do X?", when a reviewer asks for a feature or a claim the product may not support, and when a source document (pitch deck, PRD, marketing page) makes claims the video wants to repeat.

josueh04/product-video-skills

Check a rendered product video before anyone else sees it: worker-pattern flicker, black frames, loudness and true peak, clipping, clicks at clip edges, overlapping narration, speech to text against the script, banned terms and legacy names, camera zoom, contact sheets, frame strips at transitions and parity against the approved version; then write qa/REPORT.json, the only thing deliver.py accepts. Use it after every HyperFrames render, whenever someone asks "is the render clean", "QA this", "check the video", "check the audio", "why does it flicker", "there is a click", "compare v3 with v2", "did the approved part change", or before showing, sending, uploading or delivering any MP4, even when the request does not say QA. Also use it to triage a defect a reviewer reported in a render.

josueh04/product-video-skills

Write a product video's narration and turn it into voice clips with word timings, pronunciation fixes, sound effects and even loudness. The script becomes a table of moments and then audio/lines.tsv (one clip per sentence, with role and speed columns); tts.py voices it with ElevenLabs or the free macOS say voice, maps brand respellings back to the on-screen spelling, normalizes every clip and writes audio/timings.json for the composer; make_sfx.py builds typing tracks from real keystrokes and places recorded click and pop sounds. Use it whenever a video needs a script, narration, voice-over, lines.tsv, timings.json, TTS, a new take, a voice or casting choice, a pronunciation fix ("it says the name wrong"), a changed sentence, a tone note ("too hype", "sounds cut off"), audio levels, a click at the end of a clip, typing or click sounds, or when the build stage asks for the voice. Also use it for silent loops, which still need a moment table and SFX.

josueh04/product-video-skills

The animation rules that keep HyperFrames' parallel render workers from dropping, flashing or flickering elements, plus a static lint (lint_motion.py) that finds the violations in a video's template before it costs a render. Use it whenever you write or edit GSAP tweens, timelines, cursors, camera moves, typing, scrolls or pop-ups in a HyperFrames composition or a video's src/template.tpl, whenever a render shows flicker, stutter, an element that vanishes on some frames, a title that flashes, or a "WORKER PATTERN" line from scan_render.py or qa.py, and whenever the preview looks right but the MP4 does not. Also use it to review someone else's timeline code before rendering.

josueh04/product-video-skills

Pin a product's source code (read-only exports in sources/ plus sources.lock), confirm that the pinned commit is what runs in production, and map every screen of a video brief to its route, components, i18n strings and state, written to the video's SOURCES.md. Use it whenever a video needs to know where a screen lives in the code, when sources/ is missing or stale, before ui-spec-from-code or product-truth start on a video, after the product's frontend changed ("what changed", "which videos are affected", "refresh the sources", "is this checkout current", "which commit is in prod"), and when there is no code and you need an inventory of the no-code references (recordings, recovered captures, docs) a screen can be rebuilt from.

josueh04/product-video-skills

Gather pixel references for UI that the code cannot show, or to check a rebuild against the real thing, using frames and timed OCR text from screen recordings, captures recovered from past Claude Code session transcripts, a local instance of the app built like production, and web research for third-party apps, plus side-by-side parity images and contact sheets. Use it whenever someone hands over a screen recording (.mov or .mp4) of the product, when a screen has no usable source code (a stale checkout, another company's UI such as a sign-in page, calendar or CRM, runtime output from a backend not in the repos), when asked "what does it really look like", "match the recording", "how long does that animation take in the app", "compare our render to the real app", or when screenshots from an earlier session might already exist. Never uses the reviewer's personal browser.

josueh04/product-video-skills

Turn a product's real frontend code into 1:1 rebuild specs for a video, one read-only subagent per screen, each returning static HTML, CSS with every variable resolved to its literal value and cited (role/path:line@sha), every state, transitions with exact durations and easings, icons from the code's own icon sets, and the exact i18n strings; plus resolve_tokens.py to write the product's design tokens to kit/tokens.css. Use it whenever a screen of the product has to appear in a video, when writing or fixing video/src/app.css or the template markup, when someone asks for exact sizes, colors, fonts, paddings, animations or icons of a screen, when a rebuilt screen "looks off" next to the real app, and when the design tokens or theme of a product need extracting. Framework adapters cover Angular with PrimeNG (proven), React, Vue, Tailwind and plain HTML (unproven).

josueh04/product-video-skills

Say where this session stands in the Product Video Skills workbench (setup state, which product and video the current folder belongs to, the stage of every video) and the exact next command to type. Also answers "how do I..." questions about the workbench from its docs.

josueh04/product-video-skills

Coordinate the build of one or more signed videos of the current product with subagents (source recon, product truth, UI specs, voice, one builder per video), re-run QA itself, then deliver. A light coordinator that never builds itself. Run only when the user types /video-build.

josueh04/product-video-skills

Start a new video of the current product - create videos/<video>/, write BRIEF.md, the feature coverage matrix (COVERAGE.md) and the claims sheet (CLAIMS.md), propose chapters, then stop for the reviewer's sign-off. Never builds. Run only when the user types /video-new.

josueh04/product-video-skills

Turn a batch of reviewer feedback on the product's videos into one table per video, fix every video that got notes in parallel (one subagent each) while keeping approved parts, re-run QA and parity, bump versions and deliver. Run only when the user types /video-review.

josueh04/product-video-skills

Check this machine and install the pinned video toolchain of the Product Video Skills workbench (HyperFrames CLI, its rendering Chrome and its agent skills from the same release, the Python environment, the speech model for QA), then run the self-check. Safe to run again. `/video-setup check` only reports.

Skills relacionados