GitHub Repo Promo Video
Depends on: website-to-hyperframes — load it before starting. Its 6-step workflow (capture → brand → brief → storyboard → build → validate) and all reference files apply here. This skill specializes that workflow for GitHub repository promos.
Core Decisions
| Decision | Value | Why |
|---|---|---|
| Dimensions | 1080x1920 (Instagram Reels) | Instagram Reels is the primary distribution format. Landscape is secondary. |
| Phone mockup viewport | Full-screen of available viewport | The phone mockup fills the entire 1080x1920 canvas — no letterboxing, no sidebars. The scrolling screenshot occupies every pixel. |
| Narration priority | Narration drives timing | Beat durations are computed FROM the narration audio, not the other way around. The narrator always knows the scroll state. |
| Output folder | github-promos/<repo-name>/ | All promo projects live under a parent github-promos/ directory for organization. |
| Follow CTA | @githubprojects (or user-specified) | Final beat shows "Follow @githubprojects for more trending repos" — not just "star on GitHub". |
Directory Structure
Every promo project lives under a single parent folder:
github-promos/ <repo-name>/ index.html ← main composition (mandatory) package.json ← Node project config (from hyperframes init) hyperframes.config.json ← HyperFrames config DESIGN.md ← brand cheat sheet (Step 1 output) STORYBOARD.md ← beat plan (Step 3 output) SCRIPT.md ← narration script (Step 3 output) assets/ repo-page.png ← Full-page GitHub screenshot (dark mode) narration.mp3 ← ElevenLabs voiceover renders/ ← generated videos
Sibling repos coexist under github-promos/:
github-promos/ mercury-agent-skills/ nextjs/ three.js/ react/
Workflow
This skill follows the website-to-hyperframes 6-step process, specialized for GitHub repos. Steps marked 💬 require user confirmation before proceeding.
Step 0: Capture Repo Info
Use web-search or fetch_url to collect from the GitHub API and repo page:
- Stars, forks, watchers, open issues
- Primary language, top languages breakdown
- Description, topics/tags, about section
- Latest release, license, recent activity
- README summary (what the project does, who it's for)
Then use the screenshot skill to capture a full-page screenshot of the repo in dark mode:
use_skill("screenshot") // URL: https://github.com/{owner}/{repo} // Full page, dark mode, viewport 1080x1920 // Save as: github-promos/{repo}/assets/repo-page.png
Get the screenshot dimensions — you need the pixel height for scroll calculations:
bashsips -g pixelHeight github-promos/{repo}/assets/repo-page.png sips -g pixelWidth github-promos/{repo}/assets/repo-page.png
Step 1: Brand Identity
Write DESIGN.md — GitHub dark theme defaults:
| Token | Value |
|---|---|
| Background | #0d1117 |
| Text | #e6edf3 |
| Muted | #8b949e |
| Border | #30363d |
| Blue | #58a6ff |
| Green | #3fb950 / CTA #238636 |
| Gold | #f9c513 |
| Purple | #bc8cff |
| Orange | #f0883e |
| Glass BG | rgba(22,27,34,0.8) + backdrop-filter |
Font: Inter (400–900).
Step 2: Strategy & Brief 💬
Align with the user on:
- Which repo and what aspect to highlight
- Tone (professional, hype, educational)
- Audience (developers, founders, general tech)
- The ONE message this video must communicate
Step 3: Storyboard + Script 💬
Write STORYBOARD.md and SCRIPT.md together. Critical: narration writes itself around the scroll timing.
7-Beat Structure (MANDATORY)
| Beat | Timing | Visual | Narration focus |
|---|---|---|---|
| 1. Hero | 0–~4s | Repo name, tagline, badges (stars/forks/lang) | "This is {repo}. {one-liner}." |
| 2. Scroll | ~4–~15s | Fullscreen phone mockup scrolls through the repo page | Narration describes what's scrolling into view, synced to scroll position |
| 3. Stats | ~15–~19s | 2x2 stat cards (stars, forks, issues, language) | "The numbers. {X} stars. {Y} forks." |
| 4. What You Build | ~19–~23s | 8–10 feature/use-case chips | "What can you build? {feature list}." |
| 5. Stars | ~23–~27s | Large star icon, big star count, label | "And {X} developers agree." |
| 6. CTA | ~27–~31s | "Star on GitHub" button with glow | "Star it today. {repo URL}." |
| 7. Follow | ~31–~33s | "Follow @{handle} for more trending repos" pill | "Follow @{handle} for more." |
The narration script MUST reference the scroll state. Example:
"Mercury Skills — a curated library of 130 agent capabilities." (Beat 1) "Let's scroll through what's inside — here's the full registry, categories from AI to DevOps." (Beat 2 — scroll starts) "Zooming into the README — see how easy it is to search and install." (Beat 2 — scroll at 60%) "The numbers: 20 thousand stars, 3 thousand forks." (Beat 3)
The narrator never says "scrolling through" in a vacuum — they always describe what is currently on screen.
Timing from narration
- Write the script first.
- Generate audio (Step 4).
- Measure actual audio duration per beat.
- Set
data-startanddata-durationon each beat<div>from the measured timings. - If Beat 2 audio is 11 seconds, the scroll animation spans those 11 seconds — not a fixed 10.
Step 4: Voiceover Generation 💬
Ask the user which TTS provider:
| Provider | When | API |
|---|---|---|
| ElevenLabs (default) | Best quality, most voices | POST https://api.elevenlabs.io/v1/text-to-speech/{voice_id} |
| HeyGen TTS | If already in HeyGen ecosystem | Built-in to HyperFrames Studio |
| Kokoro | Free, good quality | Local inference |
Default ElevenLabs config:
bashcurl -s -X POST "https://api.elevenlabs.io/v1/text-to-speech/AZnzlk1XvdvUeBnXmlld" \ -H "xi-api-key: $ELEVENLABS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "SCRIPT_HERE", "model_id": "eleven_multilingual_v2", "voice_settings": { "stability": 0.35, "similarity_boost": 0.8, "style": 0.25, "use_speaker_boost": true } }' \ --output github-promos/{repo}/assets/narration.mp3
Verify: ls -la github-promos/{repo}/assets/narration.mp3 — file must exist and be > 0 bytes.
After generating audio, transcribe it with timestamps (ElevenLabs returns these, or use ffmpeg + whisper). Map each timestamp to a beat. Update the storyboard timings from real audio durations.
Step 5: Build Compositions
Follow the website-to-hyperframes build step, with these repo-specific requirements:
Mandatory architecture
html<div id="root" data-composition-id="{repo}-promo" data-width="1080" data-height="1920" data-start="0" data-duration="{total_seconds}"> <audio id="narration-audio" src="assets/narration.mp3" data-start="0" data-duration="{total_seconds}" preload="auto"></audio> <!-- Background layers --> <div id="bg"></div> <div id="bg-grid"></div> <div class="glow-orb g1"></div> <div class="glow-orb g2"></div> <div id="scanlines"></div> <!-- 7 beats, each .beat.clip with data-start/data-duration --> ... </div>
Fullscreen phone mockup (Beat 2)
The phone fills the entire 1080x1920 canvas — not a centered phone with dead space.
css.phone-frame { position: absolute; inset: 0; /* fills entire canvas */ width: 1080px; height: 1920px; border-radius: 0px; /* no rounded corners on fullscreen */ overflow: hidden; background: #0d1117; } .phone-screen { position: absolute; inset: 0; overflow: hidden; } .phone-scroll-content { position: absolute; top: 0; left: 0; width: 100%; height: {IMG_H}px; /* actual screenshot height */ } .phone-scroll-thumb { position: absolute; right: 8px; width: 5px; border-radius: 3px; background: linear-gradient(180deg, #58a6ff, #3fb950); height: {THUMB_H}px; /* computed: TRACK_H * (1920 / IMG_H) */ top: 0; }
Scroll variables:
javascriptvar IMG_H = /* actual screenshot pixel height */; var PHONE_H = 1920; var MAX_SCROLL = IMG_H - PHONE_H; // Three scroll stops at ~30%, ~60%, ~88% var SCROLL_1 = -Math.round(MAX_SCROLL * 0.3); var SCROLL_2 = -Math.round(MAX_SCROLL * 0.6); var SCROLL_3 = -Math.round(MAX_SCROLL * 0.88); // Scroll thumb var TRACK_H = 1920; var THUMB_H = Math.round(TRACK_H * (PHONE_H / IMG_H)); var THUMB_TRAVEL = TRACK_H - THUMB_H; function thumbY(scrollPx) { return (Math.abs(scrollPx) / MAX_SCROLL) * THUMB_TRAVEL; }
GSAP timeline
javascriptwindow.__timelines = window.__timelines || {}; var tl = gsap.timeline({paused: true}); // Beat 1: Hero — fade in elements, stagger badges // Beat 2: Phone scroll — three scroll segments with different easing // gsap.to('.phone-scroll-content', { y: SCROLL_1, duration: beat2Duration * 0.33, ease: 'power3.out' }) // gsap.to('.phone-scroll-content', { y: SCROLL_2, duration: beat2Duration * 0.33, ease: 'power2.out' }) // gsap.to('.phone-scroll-content', { y: SCROLL_3, duration: beat2Duration * 0.34, ease: 'power1.out' }) // gsap.to('.phone-scroll-thumb', { top: thumbY(SCROLL_1), ... }) // ... repeat for SCROLL_2, SCROLL_3 // Beat 3: Stats — stagger-in cards // Beat 4: Chips — stagger-in feature tags // Beat 5: Stars — scale-in with elastic rotation // Beat 6: CTA — fade-in button with glow pulse // Beat 7: Follow — quick fade-in pill window.__timelines["{repo}-promo"] = tl;
Important: Scroll durations come from the narration audio. If Beat 2's audio segment is 11 seconds, the scroll animations fill those 11 seconds proportionally — not a fixed speed.
Step 6: Validate & Deliver
bashcd github-promos/{repo} npx hyperframes lint npx hyperframes validate npx hyperframes snapshot
Fix all errors. Then render at draft quality first:
bashnpx hyperframes render --quality draft
Verify output in renders/. If clean, render final:
bashnpx hyperframes render --quality standard
Deliver the MP4 to the user. Ask: "Would you like me to post this, or render at high quality first?"
Seven Beats — Detailed Specifications
Beat 1: Hero (0s → ~4s)
- Category pill: e.g.
FRONTENDorAI / ML— repo's primary category - Repo name: Large text, gradient blue→green (
linear-gradient(135deg, #58a6ff, #3fb950)) - Tagline: One-liner from repo description,
#8b949ecolor - 3 badges: Stars count, forks count, primary language — pill-shaped, border
#30363d, icons from Lucide
Beat 2: Fullscreen Scrollable Phone (~4s → ~15s)
The phone fills the ENTIRE 1080x1920 canvas. No frame bezels, no rounded corners on the outer viewport. The GitHub screenshot scrolls behind a status bar overlay and a scroll thumb indicator.
- Status bar at top: time, repo name, signal icons (semi-transparent overlay)
- Content: full-page GitHub screenshot scrolls from top to bottom
- Scroll thumb on the right edge: 5px wide, gradient blue→green, tracks scroll position
- Three scroll stops matching the narration's description of what's on screen
- Each scroll segment: different easing (
power3.out→power2.out→power1.out)
Beat 3: Stats (~15s → ~19s)
Title: "By the Numbers" in #e6edf3.
2×2 grid of glass-morphism stat cards:
| Position | Icon | Value | Label |
|---|---|---|---|
| Top-left | Star | {stars}k | Stars |
| Top-right | GitFork | {forks} | Forks |
| Bottom-left | AlertCircle | {issues} | Open Issues |
| Bottom-right | Code | {language} | Language |
Each card: rgba(22,27,34,0.8) background, backdrop-filter: blur(12px), border #30363d, value text with gradient matching the icon category.
Beat 4: What You Can Build (~19s → ~23s)
Title: "What Can You Build?" in #e6edf3.
8–10 chips in a wrapping grid. Each chip:
- Rounded pill,
px-3 py-1.5 - Left border color matches category (blue for dev, green for infra, purple for AI, etc.)
#e6edf3text onrgba(22,27,34,0.6)background
Beat 5: Stars Highlight (~23s → ~27s)
- Large star icon (Lucide
Star, 120px) withscale: 0 → 1.2 → 1elastic animation + slight rotation - Star count in large gradient gold text:
linear-gradient(135deg, #f9c513, #f0883e) - Label underneath: "developers trust this repo" in
#8b949e
Beat 6: CTA (~27s → ~31s)
- Title: "Star on GitHub Today" in
#e6edf3 - Subtitle: repo description or tagline in
#8b949e - Green CTA button:
#238636background,#e6edf3text, border-radius 999px - Subtle glow pulse animation:
box-shadow: 0 0 20px rgba(35,134,54,0.4)pulsing
Beat 7: Follow (~31s → ~33s)
- Text: "Follow for more trending GitHub repositories" in
#e6edf3 - Pill with
@githubprojects(or user-specified handle): rounded, border#30363d, backgroundrgba(22,27,34,0.8) - Quick 0.5s fade-in
Narration-Aware Scroll Sync
This is the key architectural rule: the narration script is aware of what's on screen during the scroll.
How to write narration-aware scripts
-
Know the scroll stops. Before writing the script, you know the 3 scroll positions (30%, 60%, 88%) and what content appears at each position (from the screenshot).
-
Call out what you see. The narrator describes the content at each scroll position:
- Start: "Here's the repo — README front and center."
- 30% scroll: "Scrolling down through the installation instructions..."
- 60% scroll: "And here's the full feature list, categories from AI to DevOps."
- 88% scroll: "Down to the contributor section at the bottom."
-
Time narration to scroll duration. If Beat 2 audio is 11 seconds total, the three scroll segments each get approximately 3.7 seconds. Write ~12 words per segment so the narrator isn't rushing.
-
Never narrate in a vacuum. If the scroll is paused at 60% showing the feature list, the narration should reference specific features visible at that position — not generic filler.
Example: narration-aware script
[Beat 1 — 4s] "Mercury Skills — 130 curated agent capabilities, one command away." [Beat 2 — 11s, scroll across full page] 0s–3.7s "Let's walk through it. Here's the full registry on GitHub —" 3.7s–7.3s "scrolling into the installation section — one CLI command and you're in." 7.3s–11s "Here's the feature grid — AI, DevOps, mobile, finance, 23 categories deep." [Beat 3 — 4s] "The numbers: 20 thousand stars, 3 thousand forks, and zero friction to start." [Beat 4 — 4s] "What can you build? PDF generation, Amazon shopping, screenshots, Twitter automation, and counting." [Beat 5 — 4s] "And 20,000 developers agree — this is the agent skills library that ships." [Beat 6 — 4s] "Star it today. github.com/cosmicstack-labs/mercury-agent-skills." [Beat 7 — 2s] "Follow @githubprojects for more trending repos."
Prerequisites
ELEVENLABS_API_KEYenvironment variable (for ElevenLabs voiceover)- Node.js >= 22 with HyperFrames installed globally
ffmpegavailable in PATH (for audio duration measurement if not using ElevenLabs timestamps)
Troubleshooting
| Issue | Fix |
|---|---|
| Screenshot too tall | Use actual pixel height for IMG_H; MAX_SCROLL = IMG_H - 1920 |
| Audio not playing | Verify assets/narration.mp3 exists and src path is relative to project root |
| ElevenLabs API error | Check ELEVENLABS_API_KEY env var, verify credits |
| HyperFrames not found | npm install -g hyperframes then npx hyperframes init |
| Render fails | Run npx hyperframes init --example blank in the project dir first |
| Scroll speed too fast | Increase data-duration on Beat 2, or add more scroll words to narration |
| Phone not fullscreen | Set .phone-frame { inset: 0; border-radius: 0; } — no bezels |
| Narration desync | Re-transcribe audio, map timestamps to beats, update data-start/data-duration |
| Beat overlap | Ensure each beat's data-start + data-duration doesn't exceed the next beat's data-start |
Skill Dependency
Required dependency: website-to-hyperframes
Load it before starting. Its 6-step workflow (capture → brand → brief → storyboard → build → validate) and all reference files (step-0-capture.md through step-6-validate.md, capabilities.md, techniques.md) apply to this skill as the general framework. This skill specializes that workflow for GitHub repository promos with narration-aware scroll sync and the 7-beat structure.


