---
title: "Design your own video"
description: "Render an HTML composition you or Claude wrote, with fonts, GSAP, and registry components."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.mosio.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Design your own video

When no template fits, the video can be written as one HTML document, a [Hyperframes](https://hyperframes.heygen.com) 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

```html
<!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`, and `data-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 unseeded `Math.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](https://github.com/heygen-com/hyperframes/tree/main/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:

```html
<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:

```json
{
  "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_composition` shows a free moving preview; **Buat video** in the card renders it.
- From code: `POST /v1/compositions` with the HTML. See [Render a composition](/api).

Source: https://docs.mosio.me/guides/design-your-own/index.mdx
