PTENES
MODULE 4.1

πŸ“Ί YouTube & Shorts

Publish an explainer video on YouTube (16:9) and a Short/Reel (9:16) from the same HyperFrames project β€” without filming yourself or using nonlinear editing.

6
Topics
25
Minutes
Practical
Level
Application
Type
build-index.mjs node . 16:9 1920Γ—1080 YouTube 9:16 1080Γ— 1920 Shorts --vertical πŸ“„ SCRIPT.md A script. Two renders. node build-index.mjs node build-index.mjs --vertical
1

πŸ–₯️ 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.

Main concept

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.

βœ“ DO in YouTube videos
  • βœ“ Use --quality high in 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
βœ— DO NOT in YouTube videos
  • βœ— 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)
Render 16:9 β€” exact command
# Generates index.html 1920Γ—1080, then renders it
node build-index.mjs &&
npx hyperframes render --quality high \
--output renders/meu-tutorial-16x9.mp4
Key concepts
Fixed viewport
The index.html has width/height hard-coded to 1920Γ—1080β€”Chrome captures exactly that.
H.264 + FFmpeg
HyperFrames calls FFmpeg internally. The generated MP4 is accepted by YouTube uploads without re-encoding.
GSAP scenes
Each sceneN() returns static HTML; anim() receives the GSAP timeline and animates the elements.
2

πŸ“± 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.

πŸ“Š Dimensions and destinations
16:9 β€” Horizontal
Resolution: 1920 Γ— 1080 px
Destination: YouTube, Vimeo, LinkedIn
Flag: node build-index.mjs (without a flag)
9:16 β€” Vertical
Resolution: 1080 Γ— 1920 px
Destination: YouTube Shorts, Instagram Reels, TikTok
Flag: node build-index.mjs --vertical
πŸ’‘
Adaptive CSS layout

In --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.

βœ“ DO in Shorts/Reels
  • βœ“ 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)
βœ— DO NOT in Shorts/Reels
  • βœ— 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)
Key concepts
Flag --vertical
Injects a class and rewrites the viewport to 1080Γ—1920 without changing the scene functions.
Safe zone
Reserve ~15% at the top and bottom for app UI β€” content only in the center band.
Reels vs Shorts
The same 9:16 MP4 works for Instagram Reels and YouTube Shorts β€” upload it to both.
60 s limit
Shorts must be ≀ 60 s to appear in the dedicated tab. Longer videos become regular videos.
3

⏱️ 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.

Typical retention timeline
0 – 5 s
Hook β€” don't wrap it up
5 – 30 s
Fast context
30 – 90 s
Core content
90 – 110 s
CTA β€” conversion
> 180 s
Sharp decline
⚑
The narration is the metronome

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.

πŸ“Š Duration Γ— retention equation
~100s
of speech (TTS pf_dora)
β‰ˆ 1:50
of rendered video
> 65%
expected average retention
Key concepts
Hook in the first 5s
Scene 1 determines whether the viewer stays. Start with the promise or the problemβ€”never with a brand intro.
Real AUDIO[]
Fill in with the exact durations of ffprobe assets/audio/sN.wav β€” HyperFrames synchronizes animation and audio.
speed 0.98
A speed slightly below 1.0 makes speech sound more natural in PT-BR with the pf_dora voice.
4

πŸ’¬ 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.

How it works in HyperFrames

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.

Caption style (house style)
/* caption burned into the frame */
.caption {
position: absolute;
bottom: 72px; /* above the safe zone */
left: 50%; transform: translateX(-50%);
font-family: 'Inter', sans-serif;
font-weight: 600;
font-size: 36px;
color: #F0EBD8;
background: rgba(0,0,0,0.55);
border-radius: 8px;
padding: 10px 20px;
max-width: 80%; text-align: center;
}
⚠️
A caption is not a subtitle file

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.

πŸ’‘
Vertical: adjust the font-size

In --vertical, use .vertical .caption { font-size: 52px; bottom: 160px; } β€” 1080Γ—1920 resolution is much larger, so the caption needs to scale.

Key concepts
CAPTIONS[]
Array of strings in build-index.mjsβ€”each item corresponds to a scene and is injected into the frame.
Accessibility
Burned-in captions serve deaf users and people in places without audio (bus, work).
translucent rgba
A semi-transparent background preserves the frame's appearance while ensuring minimum WCAG 2.1 AA contrast.
5

🏁 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().

Standard INEMA.CLUB CTA scene

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.

Example prompt β€” activating the video-explicativo skill
# Paste into Claude Code (video-explicativo skill installed)
Create an explainer video about "how Kokoro TTS works".
Generate 16:9 and 9:16. CTA for INEMA.CLUB.
pf_dora voice, speed 0.98, PT-BR.
Premium dark palette, amber accent #FFC300.
The skill follows this workflow: SCRIPT.md β†’ init β†’ fetch-fonts β†’ narration WAV β†’ build-index.mjs β†’ lint β†’ render Γ—2.
Where the CTA fits into the video structure
Scenes 1–7: content
Script, examples, animations β€” the real value of the video.
Scene 8: summary
Quick recap (3–5 s) of the key points β€” anchors the memory.
Scene 9: INEMA.CLUB CTA ← required
INEMA.CLUB with glow + URL + short narration. Already included in the template.
βœ“ DO in the CTA
  • βœ“ 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
βœ— DO NOT in the CTA
  • βœ— 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
Key concepts
scene9()
Prebuilt function in the template β€” don't rewrite it from scratch; just adjust the domain and glow.
Amber glow
an amber drop-shadow #FFC300 pulses on the brand mark β€” signaling "click here" without needing a button.
Dual channel
Visual URL + spoken URL = bimodal reinforcement. People who watched with sound and those who watched on mute both catch the destination.
6

♻️ 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.

DRY Principle Applied to Video

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).

Complete render sequence (both formats)
# 1. Render 16:9 β€” YouTube (1920Γ—1080)
node build-index.mjs && \
npx hyperframes render --quality high \
--output renders/kokoro-tts-16x9.mp4

# 2. Render 9:16 β€” Shorts/Reels (1080Γ—1920)
node build-index.mjs --vertical && \
npx hyperframes render --quality high \
--output renders/kokoro-tts-9x16.mp4

# 3. Validate before publishing
npx hyperframes lint # 0 errors
npx hyperframes inspect --samples 16 # 0 layout issues
πŸ’‘
Always render the draft first

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.

Condensed pipeline
πŸ“„
SCRIPT.md
6–9 scenes, ~100s spoken
β†’
πŸ”§
build-index.mjs
sceneN() + anim()
β†’
🎬
16x9.mp4
9x16.mp4
ready for upload
βœ“ DO in the dual workflow
  • βœ“ Render 16:9 first, validate, then 9:16
  • βœ“ Store both MP4s in renders/ with distinct names
  • βœ“ Test --quality draft in both modes before high
  • βœ“ Add selectors .vertical in the scene CSS for long text
βœ— DO NOT in the dual workflow
  • βœ— 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
Key concepts
DRY
Don't Repeat Yourselfβ€”a single source, two outputs. No duplicate maintenance.
renders/
Default output folder. Always use the -16x9 and -9x16 suffixes in the names to avoid confusion.
lint + inspect
Two quality passes: lint checks the HTML/JS; inspect extracts frames and shows visual overflow.
draft β†’ high
Draft rendering is fast (~20s). High can take minutes. Always validate in draft first.

πŸ“‹ Module 4.1 summary

βœ“ 16:9 (1920Γ—1080) = YouTube. No flag in build-index.mjs.
βœ“ 9:16 (1080Γ—1920) = Shorts/Reels/TikTok. Flag --vertical.
βœ“ ~100s of speech (β‰ˆ 1:50) maximizes retention. Voice pf_dora speed 0.98.
βœ“ Burned-in captions: Inter 600, 36px, rgba(0,0,0,0.55). Always on.
βœ“ Required final CTA (scene9) β€” INEMA.CLUB or your brand.
βœ“ One SCRIPT.md β†’ two MP4s. Lint + inspect before publishing.
Next module:
4.2 πŸš€ Onboarding, lessons & launches
Apply HyperFrames to course welcome videos, recorded lessons, and product launchesβ€”with CTA variations for each context.