🧹 npx hyperframes lint
The first quality gate: the linter analyzes your index.html generated and reports structural issues before you spend time rendering. Goal: 0 errors.
The linter reads the index.html generated (not the build-index.mjs) and validates the composition structure. Errors stop the render—warnings are informational.
Always run after node build-index.mjs e before for any render. Lint is fast (<2 s) and doesn't launch Chrome.
overlapping_clipsTwo scene clips have overlapping time intervals. Fix this by adjusting the array AUDIO[] no build-index.mjs — the sum of the durations must be strictly sequential.
multiple_root_compositionsMore than one element with data-composition at the document root. HyperFrames accepts only one composition per file index.html.
google_fonts_importThe lint detects a @import url('fonts.googleapis.com/...') in the CSS. External fonts are prohibited because headless Chrome has no internet access during rendering. Use node fetch-fonts.mjs to download the .woff2 and serve locally via assets/fonts/fonts.css.
During composition, run node build-index.mjs && npx hyperframes lint with each relevant modification to the build-index.mjs. Cost: less than 2 seconds. Prevents surprises at render time.
🔍 npx hyperframes inspect --samples 16
The inspector launches headless Chrome, captures 16 frames distributed throughout the video, and audits each one: layout, text overflow, elements outside the canvas. Goal: 0 issues.
- ✓ Add
data-layout-ignorein off-canvas decorative elements (giant background words, glows,.bg-layer) - ✓ Prefer
left/rightinstead ofwidthfor highlight markers - ✓ Test long code in
overflow-x: autowith an explicitly sized container - ✓ Use
z-index:-1in the glows so they don't overflow the bounding box
- ✗ Code-line text overflowing the container — shorten it or break it into lines
- ✗ SVG without
viewBoxnot defined — the auditor can't calculate bounds - ✗
position: absolutewithoutoverflow: hiddenin the parent - ✗ Decorative elements without
data-layout-ignore— marked as false-positive overflow
The inspector detects bounding-box overflow, not readability or contrast issues. After 0 problemas in inspect, you still need to review frames from the draft render visually — especially in scenes with text over a gradient.
🎬 Draft render — iterate quickly
The mode --quality draft generates a low-resolution MP4 in seconds. Extract one frame per scene with ffmpeg -nostdin and check it visually before spending time on the final render.
Use the scene start time as <t>. For a scene that starts at 12.5 s, use -ss 12.5. The flag -nostdin is required on Windows/git-bash to prevent ffmpeg from consuming stdin and exiting without generating the file.
Claude can view PNG images directly. Extract one frame per scene and check text alignment, overflow, animations in the right position, and readability against the background. Repeat for all scenes.
Edit the build-index.mjs, run node build-index.mjs && npx hyperframes render --quality draft again. The draft loop is cheap—iterate freely before the final render.
| Aspect | Draft | High |
|---|---|---|
| Objective | Visual review | Final delivery |
| Speed | Fast (<30 s) | 3–4 min / 110s of video |
| Quality | Reduced | Maximum (30 fps) |
| Usage | Iteration loop | Once, at the end |
1 frame per scene works well. For an 8-scene video, that’s 8 ffmpeg calls. Focus on transitions and titles—they’re the parts most likely to overflow.
👂 Validate the narration with the user
Claude can't hear audio. The user is responsible for validating the narration — and should do so before from the high render to avoid wasting 3–4 minutes of processing.
The image analysis tool (Read) works for PNGs and frames, but WAV audio isn’t supported. All narration validation must be done by the user listening to the files assets/audio/sN.wav directly.
Before rendering at high quality, confirm with the user: correct pronunciation of technical terms, speed (pf_dora --speed 0.98 is the default), natural pauses between scenes, and a duration that fits each scene’s visuals.
- ✓ Listen to each
assets/audio/sN.wavbefore the final render - ✓ Confirm that acronyms were expanded correctly (e.g., "GSAP" → "jee-sap" sounds natural?)
- ✓ Make sure the WAV duration is consistent with the visual scene
- ✓ Check via
ffprobewhether the measured duration matches theAUDIO[]
- ✗ Don't run a high-quality render without listening to the WAVs—costly rework
- ✗ Don't rely only on the measured duration—the speech may be cut off
- ✗ Don't use a speed above 1.05—the voice sounds metallic and artificial
- ✗ Don't ignore incorrect pronunciations of English terms in the PT-BR text
Beyond pf_dora (female, recommended default with --speed 0.98), there are pm_alex e pm_santa for male voice variations. If a term is pronounced incorrectly, rewrite it phonetically in the assets/txt/sN.txt and regenerate the WAV.
🚀 Render high — delivery quality
After clean lint, inspect with no overflow, a reviewed draft, and approved narration, it’s time for the final render: --quality high --fps 30. An ~110s video is about ~3,500 frames and takes 3–4 minutes on a typical machine with 22 cores.
HyperFrames launches headless Chrome at full resolution (1920×1080 or 1080×1920), captures each frame as a PNG, passes them all to FFmpeg, and encodes H.264 with the WAV audio embedded. At 30 fps, 110 seconds = 3,300 frames.
Render time varies with the number of available colors. With 22 colors, expect ~3–4 minutes for a 110s video.
- ✓
npx hyperframes lint— 0 confirmed errors - ✓
npx hyperframes inspect --samples 16— 0 layout issues - ✓ Draft visually checked (1 frame/scene)
- ✓ Voice-over approved by the user
- ✗ Lint still reports errors — it will fail midway through rendering
- ✗ Didn't see any frames from the draft—risk of rework
- ✗ The user hasn't listened to the WAVs — they may need to render again
- ✗ O
index.htmlwas not regenerated after the last edit
📐 Generate both formats — 16:9 and 9:16
From the same project, generate the 16:9 (YouTube) and 9:16 (Shorts/Reels) versions in sequence. The critical rule: render immediately after generating each format — never leave two index.html simultaneous at the root.
O build-index.mjs always overwrites the same one index.html. If you run both modes before rendering, the second overwrites the first and you lose the composition. The correct sequence is: generate → render → generate another version → render.
node build-index.mjs (without a flag)renders/nome-16x9.mp4node build-index.mjs --verticalrenders/nome-9x16.mp4To automate both formats at once, chain with &&:
O && ensures the 9:16 render starts only after the 16:9 render finishes successfully.
- ✓
node build-index.mjs→ render 16:9 →node build-index.mjs --vertical→ render 9:16 - ✓ Always confirm which one
index.htmlis active before rendering - ✓ Name the outputs with the suffix
-16x9e-9x16from the start
- ✗ Run
build-index.mjsebuild-index.mjs --verticalwithout rendering between the two - ✗ Render without
--outputexplicit — may overwrite a previous render - ✗ Use the same output name for both formats
📋 Module 2.5 Summary
- ✓
npx hyperframes lint: the 3 fatal errors and how to fix each one - ✓
npx hyperframes inspect --samples 16: overflow,data-layout-ignoreand false positives - ✓ Draft render + frame extraction with
ffmpeg -nostdin -y -ss <t> -vframes 1 -update 1 - ✓ Claude can't hear audio — the user is responsible for validating the narration
- ✓ High-quality render:
--quality high --fps 30· ~110s ≈ 3,500 frames ≈ 3–4 min - ✓ 16:9 → 9:16 sequence: generate and render each format before generating the next