Communitygithub.com

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.

product-video-skills란 무엇인가요?

product-video-skills is a Claude Code agent skill that 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.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/josueh04/product-video-skills/tree/HEAD/skills/render-qa

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Render QA

A render is not done when the renderer exits. It is done when the evidence says it is clean: the automatic report, every contact sheet looked at, strips at every transition looked at, and the narration edges listened to. In the production these skills come from, subagents reported renders as clean that had a 0.3 s UI flash before the lockup, a clipped modal and a title that vanished on every third frame. The scripts and the strips found all three.

The scripts live next to this file. Resolve the workbench once:

PVS_HOME="$(cd "$(cd "${CLAUDE_SKILL_DIR}" && pwd -P)/../.." && pwd)"
PY="$PVS_HOME/bin/pvs-py"
S="$PVS_HOME/skills/render-qa/scripts"

Keep the interpreter and the script folder in separate variables and quote both ("$PY" "$S/qa.py"): one variable holding a command plus a path is not split by zsh and breaks in bash as soon as a path has a space.

<video_dir> is products/<slug>/videos/<video>/ (it holds BRIEF.md, audio/, video/).

The gate, in order

  1. Before rendering. Run the motion lint (seek-safe-motion skill), hyperframes check, and snapshots of every setup beat. check alone is not enough: it once passed a video in which moving elements were invisible for three of their four stretches. The pre-render steps are in references/checklist.md.
  2. Right after the render, the fast scan (a few seconds): "$PY" "$S/scan_render.py" <mp4>. A WORKER PATTERN line means a seek-safety bug: stop and fix the timeline (see seek-safe-motion), do not run the rest yet.
  3. The full report: "$PY" "$S/qa.py" <video_dir> <mp4>. It runs every automatic check, writes qa/REPORT.json and qa/REPORT.md, contact sheets in qa/sheets/, strips in qa/strips/ (each outlier run and the last 5 s), and the transcript in qa/asr.txt. About 15 s for a 2 to 3 minute 60 fps video on a recent Mac, speech to text included. Read REPORT.md top to bottom, including the warnings and every ASR diff.
  4. The pass by eye. The report ends with what the scripts cannot see. Do all of it:
    • Look at every contact sheet, not a sample.
    • Make strips at 5 to 6 fps around every modal open and close, scroll, camera move, chapter change, beat that changed in this version, and the end screen to lockup handoff: "$PY" "$S/strips.py" <mp4> <video_dir>/qa/strips modal:21.0:23.4:8 lockup:57:60. A 1 fps sheet samples one frame per second; a 0.3 s flash fits between two samples.
    • Run "$PY" "$S/edges.py" <mp4> <video_dir> and listen to every edge it marks.
    • If this version edits an approved one, prove the rest did not move: "$PY" "$S/parity.py" <approved.mp4> <new.mp4> --skip 41.0:48.5. How to read sheets, strips and parity output: references/reading-sheets-and-strips.md.
  5. Triage every failure and warning with references/triage.md: it lists the real defects these checks found and the false positives, with how each was told apart. Fix the cause in the source (template, build, lines.tsv, audio), rebuild, re-render, and run the gate again from step 2. Never edit index.html by hand: the build regenerates it.
  6. Delivery is not this skill's call. deliver.py runs only when the user, or a user-invoked skill the user started (/video-build, /video-review), asks to deliver. It refuses unless the report passed, is not a draft and matches the MP4 byte for byte.

What the checks measure

CheckFails whenWhy this threshold
size, fpssize differs from video.size; fps only warnsA wrong size is a broken render; a different fps can be intended (30 vs 60)
worker_patterna run of 4 or more outlier frames all on one frame index mod 3HyperFrames renders with 3 interleaved workers; one losing state hits every third frame
outliersnever (warning)Scrolls at full speed, blur racks and camera returns make isolated outliers too; look at each strip
black_framesmean luma under 3 outside the first 1 s and last 2 sFades from and to black are intended; black mid-video is a bug
voice_overlaptwo voice clips' spoken words overlap by more than 20 msMeasured on word timings, not clip bounds: silent tails overlapping is fine
loudnessintegrated loudness more than 1 LU from voice.mix_lufsDelivered finals measured -16.8 to -15.3 LUFS for a -16 target
true_peakabove -1.0 dBFSHeadroom for the lossy encoders of upload platforms
clippingany sample at 0.995 or more on a real channelMeasured per channel, not on a downmix, so one clipped side is not hidden
clicks_outside_clipsan impulsive click outside every audio clipInside an SFX is expected; inside voice it is almost always a consonant
abrupt_edgesnever (warning)A sound ending in 5 ms outside an SFX is usually a badly trimmed clip; listen
asrword match under 0.93, or skippedFinals measured 0.953 to 0.988; script compared in playback order, not file order
banned_terms_*a banned term, never-say phrase or legacy name heard, visible in index.html, or in lines.tsvFrom product.yaml; the live UI may still show an old name, the video must not
camera_zoomnever (warning) above video.max_zoomFull-page screens at about 2x were rejected twice as "super zoomed in"; a zoomed-out canvas tolerates more
motion_lintthe seek-safe-motion lint reports an errorCatches the timeline bugs before they cost a render

--no-asr makes the report fail on purpose: a narration that drifted from the script is exactly what a reviewer hears first. Speech to text uses whisper small.en for English and the multilingual small model for any other lang (it downloads once if missing).

The report contract

qa/REPORT.json follows docs/contracts.md: mp4 (relative to the video folder), sha256, created, draft, checks (name, passed, detail, and level: warn for warnings), passed. It also carries draft_reason, probe, artifacts and the ASR diffs. draft is true when either signature in BRIEF.md is empty or video/index.html carries <meta name="pvs-draft" content="1"> (written by build.py --draft). A draft can pass every check and still never be delivered: unsigned coverage is how a video ends up missing the feature the reviewer cared about.

Delivering (only when asked)

"$PY" "$S/deliver.py" <video_dir> <mp4> [--archive-previous] [--dry-run]

It copies to <product_dir>/deliveries/ as review.naming (default {product} {video} v{version}.mp4, version from BRIEF.md) with an APFS clone where possible, verifies the copy byte for byte, and writes <same name>.BRIEF.md beside it. It never overwrites: the same bytes again is a no-op, different bytes under a delivered name bump the version in the file name (then bump BRIEF.md to match). --archive-previous moves older versions of the video into deliveries/previous/ so the reviewer's folder holds only the latest. After delivering, tell the reviewer in one table: video, version, duration, what changed, and at most three open decisions, each with a recommended default. Any copy already uploaded somewhere is now stale: say so.

Rules that come from incidents

  • Re-run the evidence yourself. When a subagent says a render is clean, read its REPORT.md, open the sheets and strips, and check the sha256 matches the file you will deliver. "Clean" from an agent is a claim, the report is evidence.
  • Every version gets its own file name in renders/; never delete an older one. Overwrite only a version the reviewer has not seen yet, inside a fix cycle.
  • Never kill processes you did not start (Chrome, ffmpeg, node): other agents render on the same machine.
  • Snapshots without the vision API: pass --describe false to hyperframes snapshot, so no frame of an unreleased product leaves the machine.
  • Spelling-only ASR diffs are fine (a brand word heard as two words, a time written in words). Read each diff before deciding; a diff of several words is a cut or garbled line.

Scripts

ScriptUse
qa.py <video_dir> <mp4> [--out DIR] [--no-asr] [--strip name:t0:t1[:fps]]The full report; exit 1 when not passed
scan_render.py <mp4> [--json]Fast flicker, black and loudness scan; exit 1 on worker pattern or mid-video black
qa_full.py <video_dir> <mp4> [--out DIR] [--no-asr]The measurements alone, as REPORT.txt
sheets.py <mp4> <outdir> [--fps 1]1 fps contact sheets, 4x4
strips.py <mp4> <outdir> name:t0:t1[:fps] ...Labelled strips around transitions (default 6 fps)
edges.py <mp4> <video_dir or index.html>Level before and after every narration clip
parity.py <old> <new> [--end T] [--skip A:B] [--threshold 1.0] [--audio]Frame parity; exit 1 above the threshold
banned_terms.py [--product DIR] [--text T] [FILE or DIR ...]Banned terms, never-say phrases and legacy names; exit 1 on hits
deliver.py <video_dir> <mp4> [--archive-previous] [--dry-run]The delivery gate

banned_terms.find_banned(text, product) returns [(term, kind)] for other skills to reuse.

References

  • references/checklist.md: the whole gate as boxes to tick, from build to the reviewer message. Read it before the first render of a video and before any delivery.
  • references/reading-sheets-and-strips.md: what to look for in sheets, strips, crops, parity and the numeric checks (bright-pixel counts, diff boxes). Read it when doing step 4.
  • references/triage.md: every failure this QA produced, real or false, and how it was told apart and fixed. Read it as soon as any check fails or warns.

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

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

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.

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.

관련 스킬