Skip to content
Video & Audio
Skill

/make-video

Make videos drawn with code: motion graphics, launch and explainer videos, animated shorts, animated charts and data, logo reveals, social clips, music visualizers, UI demos and GIF loops. Write one HTML page that draws any frame from its time t, render it frame-exact to MP4

From plugin
helios
13035 skills1 MCP

Claude Code

$ npx -y skills add BintzGavin/helios --skill make-video --agent claude-code

SKILL.md

make-video.SKILL.md
name: make-video
description: "Make videos drawn with code: motion graphics, launch and explainer videos, animated shorts, animated charts and data, logo reveals, social clips, music visualizers, UI demos and GIF loops. Write one HTML page that draws any frame from its time t, render it frame-exact to MP4 with Helios, check stills and contact sheets, and add a soundtrack. Use when the user asks for one of these as an MP4, GIF or animation file. Not for live-action or AI-generated realistic footage or editing camera video."

Make a video with Helios

A Helios video is one HTML page with one function, `window.renderAt(t)`. It draws the frame at `t` seconds. The Helios renderer loads the page in headless Chrome, calls `renderAt(t)` once per frame, captures each frame and encodes the MP4. There is no bundler, no framework and no capture script to write.

Choose an original direction

When the request leaves the look open, don't fall back on a stock look or copy another page's design. Draw a random seed (use an **apply-randomness** skill if one is installed, otherwise run `LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 256; echo`). Write three genuinely different directions for this subject, then let verifiable patterns in the seed (a digit run, a repeated fragment, a cluster of capitals) pick one and settle its palette, type and motion. When the user gives a brand, a style or a reference, follow it instead.

Helios also has opt-in libraries: named visual styles (`motion-styles`) and genre recipes (`video-recipes`). Use them only when the user names a style or genre from them or asks for options. Otherwise you may offer them once, in one line, but don't load them: a menu of ready-made looks pulls every video toward the same few.

1. Write the page

Every frame must be a **pure function of `t`**. The renderer may ask for frames in any order, and it renders the same frame identically every time.

  • **Derive everything from `t`:** positions, opacity, which scene is showing. Never use counters, `x += speed`, physics stepped frame by frame, or `setTimeout`/`setInterval`.
  • **Randomness must be seeded.** Use `rand(seed)` below, not a bare `Math.random()` inside `renderAt`.
  • **Load assets before the first frame.** Keep a `ready` promise for fonts and images, and make `renderAt` async and `await ready`. The renderer waits for any promise that `renderAt` returns.
  • **Size the page to the video.** A canvas the size of the video, with `html,body{margin:0;overflow:hidden}`.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>html,body{margin:0;background:#0b0b10;overflow:hidden}</style>
</head>
<body>
<canvas id="c" width="1920" height="1080"></canvas>
<script>
const W = 1920, H = 1080;
const ctx = document.getElementById('c').getContext('2d');

const clamp = (x, a = 0, b = 1) => Math.min(b, Math.max(a, x));
const ease = (x) => 1 - Math.pow(1 - clamp(x), 3);              // easeOutCubic
const span = (t, start, dur) => clamp((t - start) / dur);         // 0→1 over [start, start+dur]
const rand = (seed) => { const x = Math.sin(seed * 12.9898) * 43758.5453; return x - Math.floor(x); };

const ready = document.fonts.ready;                               // plus any images you load

window.renderAt = async (t) => {
  await ready;
  ctx.fillStyle = '#0b0b10';
  ctx.fillRect(0, 0, W, H);

  // Scene 1 (0–3s): title rises in.
  const p = ease(span(t, 0.2, 1.2));
  ctx.globalAlpha = p;
  ctx.fillStyle = '#f5b700';
  ctx.font = '800 140px system-ui, sans-serif';
  ctx.textAlign = 'center';
  ctx.fillText('Hello, video', W / 2, H / 2 + 60 * (1 - p));
  ctx.globalAlpha = 1;

  // Particles: a seeded position per particle, animated by t.
  for (let i = 0; i < 80; i++) {
    const x = (rand(i) * W + t * 60 * (0.5 + rand(i + 99))) % W;
    const y = rand(i + 7) * H;
    ctx.fillStyle = `rgba(255,255,255,${0.15 + 0.35 * rand(i + 3)})`;
    ctx.fillRect(x, y, 3, 3);
  }
};
</script>
</body>
</html>

DOM, CSS, SVG and WebGL pages work too. Set styles from `t` inside `renderAt`, or let CSS animations and GSAP/motion timelines run. The renderer seeks those to each frame's time. See [references/pages.md](references/pages.md).

2. Render it

npx -y @helios-project/cli@latest render video.html -o video.mp4 --duration 12

| Flag | Use | |---|---| | `--duration <s>` | Length in seconds. Fractions are fine. Required for a `renderAt` page. | | `--width 1080 --height 1920` | Frame size; the default is 1920×1080. Match your canvas. Vertical 9:16 is `1080x1920`. | | `--fps <n>` | Frame rate; the default is 30. | | `--audio song.mp3` | Soundtrack, trimmed to the video. | | `--mode canvas` | Faster for a page that is only one full-frame `<canvas>`. The default, `dom`, captures the page as it looks. | | `--preset medium` | For the final file. It's several times smaller at the same quality and takes longer to encode. The default, `ultrafast`, is quick for drafts. |

Rendering is frame-exact. Frame *n* is exactly `renderAt(n / fps)`, with no dropped or duplicated frames and no dependence on machine speed.

For a GIF, render the MP4 and then convert it. See [references/pages.md](references/pages.md#gif).

3. Look at the frames before you say it's done

Don't hand over a video you haven't looked at. Render stills and contact sheets from the page itself; they're fast and need no encode:

npx -y @helios-project/cli@latest still video.html --at 0.5,3,7.25            # full-size PNGs
npx -y @helios-project/cli@latest sheet video.html --every 1 --duration 12   # one labelled grid
npx -y @helios-project/cli@latest sheet video.html --strip 2:3 --fps 30      # every frame in 2–3s
npx -y @helios-project/cli@latest sheet video.html --at 4 --crop 600,300,720,480  # zoom into a region

Before a long render, check that the page really is a function of `t`:

npx -y @helios-project/cli@latest verify video.html --duration 12   # exits 1 and names the frames that depend on hist
Read more
@bintzgavin
Ships withhelios

Programmatic video creation with web technologies you already know. CSS animations just work.

13035 skills1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
130
Star history of BintzGavin/helios on GitHub, a chart by star-history.com

Other skills on helios.

core

core

Core API for Helios video engine. Use when creating compositions, managing timeline state, controlling playback, or subscribing…

@bintzgavin@bintzgavinInstall Skill
animated-video-philosophy

animated-video-philoso…

Story-first motion design philosophy for animated video: motion must earn its place; arc (establish, complicate, resolve); show…

@bintzgavin@bintzgavinInstall Skill
motion-styles

motion-styles

Opt-in library of established visual styles for code-drawn Helios videos: style cards (colour rules, type, motion grammar, a…

@bintzgavin@bintzgavinInstall Skill
canvas

canvas

Patterns for using Helios with Vanilla Canvas API. Use when building high-performance 2D/3D animations without frameworks.

@bintzgavin@bintzgavinInstall Skill
chartjs

chartjs

Chart.js integration patterns for Helios. Use when creating animated data visualizations with Chart.js.

@bintzgavin@bintzgavinInstall Skill

More skills from other plugins.

captions-overlay

captions-overlay

Overlay doctrine for captions in HyperFrames videos — the caption MODEL (drop / rail / embed) and the rule that captions are an…

@heygen-com@heygen-comInstall Skill
acestep

acestep

AI music generation with ACE-Step 1.5 — background music, vocal tracks, covers, stem extraction for video production. Use when…

@calesthio@calesthioInstall Skill
seedance-antislop

seedance-antislop

This skill should be used when a Seedance 2.0 prompt contains generic AI filler, hollow superlatives, vague cinematic language,…

@emily2040@emily2040Install Skill

Questions about make-video.

Which coding agents can use make-video?
make-video installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.