06 · Foundations
HyperFrames
The restrained brand, rendered in HTML-native video. HyperFrames compositions are plain HTML with data-* timing attributes, animated with GSAP, and rendered to MP4. This page applies the white, graphite, and monochrome system to that workflow.
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 General Sans + 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
The same rules apply to both: white canvas, neutral palette, General Sans, Manrope only for metadata, monochrome imagery, sentence case, 30 fps, and no decorative effects. See Motion for the shared canon.
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. </h1> </div> <script> window.__timelines = window.__timelines || {}; window.__timelines["shibin-about"] = gsap.timeline({ paused: true }); window.__timelines["shibin-about"] .from("#title", { opacity: 0, y: 4, duration: 0.3, 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: #FFFFFF; --foreground: #27272A; --text-secondary: #626366; --text-muted: #71717A; --text-faint: #8E8F92; --accent: #18181B; --divider: #E4E4E7; --font-sans: 'Shibin General Sans', 'General Sans', system-ui, sans-serif; --font-meta: 'Manrope', system-ui, sans-serif; --ease-out: cubic-bezier(0.22, 1, 0.36, 1); --dur-entrance: 0.3s; --dur-transition: 0.3s; } body { background: var(--background); color: var(--foreground); font-family: var(--font-sans); margin: 0; }
Load the exact variable-normal General Sans face used on shibin.co. Use weights 400 / 500 / 600. Load Manrope separately and apply it only to dates, timestamps, breadcrumbs, and other small metadata.
@font-face { font-family: 'Shibin General Sans'; src: url('https://cdn.fontshare.com/wf/LHQJ5KSAL7VGAEIDSTEXCCOIUKFLT2I6/GW57XUEG4ZBVMLZZTQZTGYPROITRRQ5W/JA3IZUEMJ2J6WWT2OQVJOAWDXO3YL4YG.woff2') format('woff2'); font-style: normal; font-weight: 200 700; font-display: swap; } <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500&display=swap">
Default entrance
Start with opacity alone. When spatial movement improves comprehension, add no more than translateY(4px → 0) over 300 ms with power2.out. Exits fade in place. Stagger only elements whose reading order matters.
Duration
300ms (≈9f @ 30fps)
Easing
power2.out (enter) · power2.in (exit)
Enter
opacity 0→1 · optional translateY 4→0
Exit
opacity 1→0
// default entrance tl.from("#title", { opacity: 0, y: 4, duration: 0.3, ease: "power2.out" }, 0); // default exit tl.to("#title", { opacity: 0, duration: 0.3, ease: "power2.in" }, "+=3.7");
The graphite rule
At 1080p, the web’s 40 × 3 rule can scale to 120 × 3. Reveal it over 200 ms and use it once in an opening or section divider. Do not repeat it under every heading.
.graphite-rule { width: 120px; height: 3px; background: var(--accent); border-radius: 2px; transform-origin: left center; transform: scaleX(0); } // GSAP tl.to(".graphite-rule", { scaleX: 1, duration: 0.2, ease: "power2.out" }, 0.2);
Text action
Actions remain quiet underlined text with an up-right arrow. Fade the action in as one unit. The arrow can nudge two pixels after the text settles; no fill or enclosing pill is needed.
.text-action {
display: inline-flex; align-items: center; gap: 8px;
padding-bottom: 4px;
border-bottom: 1px solid var(--foreground);
font-weight: 500; font-size: 20px;
color: var(--foreground);
background: transparent;
}
Using the catalog
HyperFrames ships 50+ blocks via npx hyperframes add. Many arrive with loud colors, effects, or decorative layouts. Before using one:
- Map every baked-in color to the neutral tokens above.
- Strip gradients, glows, and drop shadows — even subtle ones.
- Swap primary type to General Sans and keep Manrope to metadata.
- Convert pill CTAs into underlined text actions.
- Remove decorative grids, patterned backgrounds, and color treatments from imagery.
- If the block still doesn't feel quiet, build the pattern from scratch with the tokens above.
Prefer a plain cross-fade through white to a shader transition. Avoid anything labelled glitch, chromatic, or destruction; those effects compete with the content.
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 simplifying it first.
- × Mix framerates within a composition.
- × Use fonts beyond General Sans and metadata-only Manrope.
- × Use color imagery, decorative grids, gradients, or heavy shadows.