When no template fits, the video can be written as one HTML document, a Hyperframes composition. Layout, type, colour, and motion are all yours. In Claude, the connector teaches this through get_composition_guide and a library of motion-design guides, so you can simply describe the video you want.
The shape of a composition
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link href="https://fonts.googleapis.com/css2?family=Anton&display=swap" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
html, body { width: 1080px; height: 1920px; margin: 0; overflow: hidden; background: #0c152a; }
#root { position: relative; width: 100%; height: 100%; overflow: hidden; color: #fff; }
#title { position: absolute; left: 80px; right: 80px; top: 600px; font: 220px/1 "Anton", sans-serif; }
</style>
</head>
<body>
<div id="root" data-composition-id="main" data-start="0" data-duration="10"
data-width="1080" data-height="1920" data-fps="30">
<div id="title">Weekend sale</div>
</div>
<script>
const tl = gsap.timeline({ paused: true });
tl.from("#title", { yPercent: 40, opacity: 0, duration: 0.8, ease: "power3.out" }, 0.2);
window.__timelines = window.__timelines || {};
window.__timelines["main"] = tl;
</script>
</body>
</html>The rules that matter:
- One root with
data-composition-id,data-width,data-height, anddata-duration(seconds, up to 60). The duration is what you pay in credits. - One paused GSAP timeline, registered as
window.__timelines["main"]. The renderer steps through it frame by frame. - No clocks or randomness.
setTimeout,requestAnimationFrame, CSS animations,Date.now(), and unseededMath.random()do not follow the timeline, so the video would differ from the preview. - No network at render time. See the next section for what you can load.
What you can load
| Asset | How |
|---|---|
| GSAP 3.14 | Any jsdelivr, cdnjs, or unpkg URL, or vendor/gsap.min.js. Mosio uses its own copy. |
| GSAP plugins | CustomEase, CustomBounce, CustomWiggle, DrawSVG, EasePack, Flip, MorphSVG, MotionPath, Physics2D, PhysicsProps, ScrambleText, SplitText, Text: from a CDN URL or vendor/<Name>.min.js. |
| Google Fonts | A normal fonts.googleapis.com link or @import. Mosio downloads the Latin subsets when it checks the page. |
| Built-in fonts | Bebas Neue, Archivo Black, Poppins, Playfair Display, Space Grotesk, Caveat, Noto Sans, from vendor/. |
| Images | Inline SVG, CSS, or small data: images. |
| Registry components | data-composition-src="compositions/components/<name>.html"; see below. |
Anything else (other URLs, video, audio, iframes) is refused before rendering.
Registry components
Mosio carries the 237 components of the Hyperframes registry: text effects, transitions, overlays, UI cards, charts, captions. In Claude, the search_registry and get_registry_item tools find them. Load one as a sub-composition and Mosio supplies the file:
<div data-composition-id="scramble-reveal"
data-composition-src="compositions/components/scramble-reveal.html"
data-variable-values='{"text":"KOPI SENJA","accent":"violet"}'
data-start="3" data-duration="3" data-width="1459" data-height="432"></div>Checking and fixing
Mosio checks every composition before it renders or spends credits: assets, the root element, and the Hyperframes lint rules. A failed check returns invalid_composition with a list of problems, each with a code and usually a hint:
{
"error": "invalid_composition",
"details": {
"problems": [
{ "code": "non_deterministic_code", "message": "Math.random() ...", "hint": "Use a seeded PRNG ..." }
]
}
}In Claude this loop is automatic: Claude reads the problems, fixes the HTML, and checks again.
Rendering
- In Claude:
preview_compositionshows a free moving preview; Buat video in the card renders it. - From code:
POST /v1/compositionswith the HTML. See Render a composition.