06 · Foundations
HyperFrames
The brand, rendered in HTML-native video. HyperFrames is an agent-first alternative to Remotion — compositions are plain HTML with data-* timing attributes, animated with GSAP, rendered to MP4. This page is the practical guide for rendering Shibin motion in it.
When to reach for it
Motion covers the brand's motion canon regardless of tool. HyperFrames and Remotion are both canonical — they solve different shapes of problem.
HyperFrames
HTML-first, agent-first
- Prompting a video end-to-end with an agent
- Reskinning an existing website's look into motion
- Short promos, About videos, narrative launch films
- When Inter + CSS + GSAP is the whole story
Remotion
React-native, programmatic
- Complex data-driven compositions (charts, lists)
- Props-driven templates rendered at scale
- Fine frame-level control with
interpolate/spring - Tight integration with a React codebase
Same brand rules apply to both — every non-negotiable in Motion (cream canvas, indigo accent, Inter, sentence case, 30 fps, no gradients) is mandatory here too.
Install & scaffold
Node 22 and FFmpeg 8 are prerequisites. No global install — everything runs through npx.
-
1
Scaffold a project. Skills install automatically — agents will pick them up on the next session.
# inside your workspace root npx hyperframes init <slug> cd <slug> -
2
Preview in the browser with live reload.
npx hyperframes preview
-
3
Lint before render. Run this after every change.
npx hyperframes lint
-
4
Render to MP4.
npx hyperframes render -o renders/out.mp4
Composition anatomy
A composition is an HTML file. The root #stage carries composition-level attributes; every timed element carries its own timing attributes and must include class="clip" or it renders invisible. Timelines are paused GSAP instances registered on window.__timelines — the engine seeks them deterministically.
Required on stage
data-composition-id · data-width · data-height · data-start
Required on clips
data-start · data-duration · data-track-index · class="clip"
Determinism
No Date.now · no Math.random · no network fetch at render
<div id="stage" data-composition-id="shibin-about" data-start="0" data-width="1920" data-height="1080"> <h1 id="title" class="clip hero" data-start="0" data-duration="4" data-track-index="1"> I help Shopify brands grow with AI<span class="cursor"></span> </h1> </div> <script> window.__timelines = window.__timelines || {}; window.__timelines["shibin-about"] = gsap.timeline({ paused: true }); window.__timelines["shibin-about"] .from("#title", { opacity: 0, y: 12, duration: 0.4, ease: "power2.out" }, 0); </script>
Brand tokens in CSS
Paste this block at the top of every composition. Never hardcode hex values in an index.html — always reference the token. If a composition needs a color the tokens don't provide, the system needs an update, not the composition.
:root { --background: #F8F7F2; --foreground: #1A1A1A; --text-secondary: #4A4A4A; --text-muted: #6B6B6B; --text-faint: #9B9B9B; --accent: #1C1856; --divider: #E0DED8; --ease-out: cubic-bezier(0.33, 1, 0.68, 1); /* power2.out */ --dur-entrance: 0.4s; --dur-transition: 0.4s; } body { background: var(--background); color: var(--foreground); font-family: 'Inter', system-ui, sans-serif; margin: 0; }
Load Inter via Google Fonts in <head> — the render pipeline handles it. Use weights 400 / 500 / 600 only. Never include Caveat in video.
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap">
Default entrance
Every element enters the same way: opacity 0→1 + translateY(12px → 0) over 400 ms with power2.out. Exits are symmetric, 8 px up. This is the only entrance primitive the brand uses — resist the urge to invent more.
Duration
400ms (≈12f @ 30fps)
Easing
power2.out (enter) · power2.in (exit)
Enter
opacity 0→1 · translateY 12→0
Exit
opacity 1→0 · translateY 0→-8
// default entrance tl.from("#title", { opacity: 0, y: 12, duration: 0.4, ease: "power2.out" }, 0); // default exit tl.to("#title", { opacity: 0, y: -8, duration: 0.4, ease: "power2.in" }, "+=3.6");
The accent line
120 × 9 px at 1080p. Draws left→right over 400 ms under every hero title. This is the brand gesture in motion — an off-brand HyperFrames composition is usually one that skipped the accent line.
.accent-line { width: 120px; height: 9px; background: var(--accent); border-radius: 999px; transform-origin: left center; transform: scaleX(0); } // GSAP tl.to(".accent-line", { scaleX: 1, duration: 0.4, ease: "power2.out" }, 0.2);
Pill CTA
Same silhouette as the web pill — 1.5 px border, rounded-full, Inter 500. For video, skip the hover state: stroke in from transparent to filled-indigo on appear, or just hold outlined.
.pill { display: inline-flex; align-items: center; gap: 8px; padding: 14px 24px; border: 1.5px solid var(--foreground); border-radius: 999px; font-weight: 500; font-size: 20px; color: var(--foreground); background: transparent; } .pill.filled { background: var(--accent); color: var(--background); border-color: var(--accent); }
Blinking cursor
Same rule as web: the indigo cursor appears only after the word "AI" in any restatement of the tagline. Nowhere else. 9 px wide × 1.1em tall, step-end timing, flips every 500 ms.
.cursor { display: inline-block; width: 9px; height: 1.1em; background: var(--accent); border-radius: 1px; animation: cursor-blink 1s step-end infinite; vertical-align: text-top; } @keyframes cursor-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
Using the catalog
HyperFrames ships 50+ blocks via npx hyperframes add — shader transitions, social overlays, data charts. Most are off-brand by default (loud colors, gradients, Manrope-ish type). Before using one:
- Retint every baked-in color to
var(--accent)/var(--background). - Strip gradients, glows, and drop shadows — even subtle ones.
- Swap the typeface to Inter.
- If the block still doesn't feel quiet, build the pattern from scratch with the tokens above.
flash-through-white is the most brand-compatible shader transition once retinted to flash through cream. Avoid anything labelled glitch, chromatic, or destruction — they fight the brand's calm.
Rendering defaults
Container · codec
H.264 MP4, CRF 18, Rec.709
Framerate
30 fps · 60 fps only for UI capture
Formats
1920×1080 · 1080×1080 · 1080×1920
Safe area
6% of shorter edge (≈64 px on 1080)
Don't
- × Hardcode hex in HTML — always reference the token.
- × Skip
class="clip"on timed elements. - × Call
Date.now()orMath.random()at render time. - × Use a catalog block without retinting first.
- × Mix framerates within a composition.
- × Use Caveat in video — Inter only.
- × Let captured footage bleed edge-to-edge — wrap in a 48 px cream frame.