π₯οΈ 16:9 video for YouTube
The YouTube standard format is 1920 Γ 1080 px. With HyperFrames, you write scenes in HTML + GSAP and render a high-quality MP4βwithout opening a video editor.
The generator build-index.mjs writes a index.html with a fixed viewport at 1920 Γ 1080. HyperFrames uses headless Chrome to capture each frame, and FFmpeg assembles the MP4. Without a flag, the output is always 16:9.
- β Use
--quality highin the final render - β Keep the narration to β 100 seconds of speech (β 1:50 video)
- β Include a high-contrast thumbnail in scene 1
- β Generate MP4 with H.264 codec, smooth 60fps
- β Publish render
--quality draft(low resolution) - β Exceed 15 min without chapters (retention drop)
- β Use a font smaller than 32px (illegible on mobile)
- β Omit the CTA scene (lost conversions)
sceneN() returns static HTML; anim() receives the GSAP timeline and animates the elements.π± Shorts/Reels/TikTok in 9:16
The same HTML project becomes a video 1080 Γ 1920 px with the flag --vertical. HyperFrames rebuilds the layout and renders the tall frameβwithout duplicating code.
node build-index.mjs (without a flag)node build-index.mjs --verticalIn --vertical, HyperFrames injects the class .vertical no <body>. Use selectors .vertical .sua-classe in the scene CSS to reposition elements β column instead of row, larger text, smaller margins.
- β Use fonts β₯ 48px in vertical mode (smaller safe zone)
- β Keep the CTA and caption in the lower half of the screen
- β Validate the layout with
npx hyperframes inspect --samples 16 - β Limit to β€ 60 s for Shorts/Reels (β€ 180 s for TikTok)
- β Reuse the 16:9 layout without adjustments
.vertical - β Put important text in the top band (covered by the app UI)
- β Skip linting before rendering β layout errors appear magnified
- β Publish without captions (most people watch without sound)
β±οΈ Why ~110s keeps viewers engaged
100 seconds of speech equals ~1:50 of video. That's long enough to teach a complete concept and short enough to hold attention β the sweet spot for Shorts and YouTube tutorials.
Each scene in SCRIPT.md has β 15β18 s of narration (measured with ffprobe). With 6β7 scenes, you get exactly ~100 s of speech. Voice: pf_dora --speed 0.98 in Kokoro. Store the durations in the array AUDIO[] of the build-index.mjs.
ffprobe assets/audio/sN.wav β HyperFrames synchronizes animation and audio.π¬ Always-on subtitles/captions
85% of videos in feeds are watched on mute. Burned-in captions in the frame ensure accessibility and readability even without sound β and reinforce the dark premium visual identity.
The array CAPTIONS[] in build-index.mjs defines text synchronized with the audio. The template injects a <div class="caption"> fixed at the bottom of each scene. The default CSS uses Inter 600, 36px, rgba(0,0,0,0.55) background, 12px padding β readable against any background.
The HyperFrames caption is burned-in β itβs part of the video frame. This is intentional: it ensures it appears on any platform, even when the player is muted and doesnβt support SRT/VTT. For SEO, also add a separate caption file when uploading to YouTube.
In --vertical, use .vertical .caption { font-size: 52px; bottom: 160px; } β 1080Γ1920 resolution is much larger, so the caption needs to scale.
π CTA at the end
The last scene is the CTA β Call to Action. In the INEMA.CLUB standard, it displays "CONTINUES AT" + a prominently featured domain + a readable URL. It's already included in the HyperFrames template as scene9().
The final scene shows "CONTINUED IN" + INEMA.CLUB with an amber glow, URL π inema.club and short narration: "This is INEMA dot CLUB content. Visit: inema dot club.". It is the scene9() in the template β don't remove it.
- β Keep the CTA scene in ALL videos
- β Readable URL and URL spoken in the narration
- β Adapt it to your brand (replace INEMA.CLUB with your domain)
- β Keep the amber glow β consistent visual identity
- β Remove the final scene (loses conversion and identity)
- β Add a long CTA (> 8 s) β viewer leaves
- β Unreadable URL or background that competes with the text
- β Forget to say the URL in the narration
β»οΈ One script, two formats
A single SCRIPT.md + a single build-index.mjs produce both MP4s. This is the complete HyperFrames publishing workflow β no duplicated code.
Write the script once. Adapt the scene CSS with selectors .vertical. Run the generator twice. The result is two MP4s ready to publish on YouTube (16:9) and on YouTube Shorts / Instagram Reels / TikTok (9:16).
Use --quality draft to check timing and layout before spending time on the final render. Extract frames with npx hyperframes inspect --samples 16 and review the 16 screenshots before running --quality high.
- β Render 16:9 first, validate, then 9:16
- β Store both MP4s in
renders/with distinct names - β Test
--quality draftin both modes before high - β Add selectors
.verticalin the scene CSS for long text
- β Keep two separate build-index files (violates DRY)
- β Publish without linting β layout bugs show up in the player
- β Overwrite renders/ without versioning
- β Ignore the safe zone in vertical mode
π Module 4.1 summary
--vertical.