| name | render-qc |
| description | Quality-check rendered video outputs, Hyperframes atoms, Remotion previews, and composer artifacts for this project. Use after creating or changing any atom, generated clip, render plan, timeline, caption layout, presenter framing, or final MP4. |
Render QC
Overview
Verify that a render is watchable and consistent before calling the pipeline done.
Checks
- Run the repo's programmatic checks after code or plan changes.
- Run
npm run qc:layout after editing Hyperframes atom layout or any Remotion plan that layers presenter, captions, widgets, transitions, or content.
- Use
ffprobe for final media metadata.
- Generate contact sheets for atoms and final renders.
- Inspect for black frames, frozen frames, unreadable text, bad crops, and presenter/content/caption collisions.
- Inspect targeted full-resolution frames for every visual state with text, cards, pointers, presenter docks, or captions. Contact sheets are not enough for overlap-sensitive review.
- Confirm that transitions connect the intended outgoing and incoming visuals.
- For every creator effect contract, verify the declared owner, cue window, safe zones, audio/caption budget, fallback, and QC targets against the rendered frames or artifact outputs.
- Reject empty transition atoms. A transition frame must carry a visible continuity object or incoming-preview state and must have its own
layout-qc checkpoint when it contains DOM-rendered text or shapes.
- Reject transition atoms that make the handoff worse than a simple cut: flashing layers, unrelated preview imagery, abrupt image swaps, or motion that does not preserve a continuity object.
- Confirm that all clips obey the global style spec.
- Reject any layout where a component detail crosses text or another component: accent bars over words, leader lines through boxes, endpoints detached from lines, labels clipped by card edges, or panels squeezed to unreadable sizes.
- Reject forced layouts. If side-by-side panels cause crowding, clipping, or overlapping indicator components, the shot must switch to top-down, single-focus, or sequential build.
- Reject renders where faded outgoing panels still sit under incoming result text, titles, captions, or widgets.
- Reject black-background overlay frames caused by missing alpha in WebM/MOV assets; verify overlay codec pixel format or inspect targeted frames.
- Reject caption plans that behave like transcript subtitles. Burned-in captions should be sparse emphasis; full accessibility captions belong in a separate caption track.
- Reject widgets or React/Hyperframes motion that lack a visible reason tied to the spoken idea.
- For presenter-aware gesture renders, verify both modes. With
debugging: true, tracker boxes and fingertip labels must be visible. With debugging: false, those diagnostics must be hidden while the detected gesture still drives the polished effect.
- Reject reaction widgets that are only time-synced. Also reject widgets that jitter by following raw boxes every frame. The detected hand box, palm box, or fingertip should drive event, direction, reveal progress, or focus point, then the UI should stabilize into a readable composition.
- Inspect at least one frame immediately before, during, and after every custom transition. Contact sheets are not enough for transition quality.
- Scrub cue phrases such as "look at this part" and "compare these two"; visual changes should land within about 0.5s of the spoken cue or be flagged.
- LOCKED — for any VOICED render, visual-only QC is INSUFFICIENT: a fully-desynced cut once shipped because it looked correct frame-by-frame in the stills. The render is NOT pass until the audio↔visual sync gate
pipeline/qc-voice-sync.mjs exits 0 (it runs automatically as render-promo-voiced.sh step 4b and aborts on a nonzero exit; run it standalone against a pre-existing master). The gate reads the render-emitted timeline sidecar + ASR + silences and fails on any cue outside its window (±0.5s), an unvoiced tail >0.9s, a head-trim into speech, comp/voice length divergence, or a budget-stretched window. The continuous voiced timeline is VOICE-GUIDED — a scene's on-screen span = its spoken cue span; visualBudgetSeconds is inert and a budget meant to outlast the VO is the banned budget-stretch (pacing is a script change, never a decoupled budget). Verify the gate itself with npm run qc:voice-sync-selftest (fixed cut → EXIT 0; forced budget-stretch → EXIT 1).
- If cue times are not ASR/manual, verify the render plan records the fallback timing method, such as
ffmpeg silencedetect pause alignment; do not accept unqualified duration-scaled script timing for recorded video.
- During content-dominant recorded sections, verify the presenter dock remains visible, moving, and outside all reserved content rectangles.
- In docked-presenter layouts, flag frames where the main visual is pushed into the lower half and the top stage is mostly empty, unless that empty space is an intentional beat lasting under one second.
- Prefer browser-derived geometry for layout checks. Static
layout-qc rectangles are only acceptable when they are generated from actual rendered boxes or manually updated after every visual edit.
Commands
Use these as applicable:
npm run check
npm run qc:layout
npx hyperframes lint
ffprobe output/lesson-001.mp4
ffmpeg -y -i output/lesson-001.mp4 -vf "fps=1/5,scale=384:216,tile=3x3" /tmp/lesson-contact.jpg
npm run qc:voice-sync-selftest
Output
Report:
- commands run
- media metadata
- visual findings
- pass/fail
- exact remaining risks
Read references/qc-checklist.md for the review checklist.