npm.io
0.2.1 • Published yesterdayCLI

@html-docs/html-video

Licence
MIT
Version
0.2.1
Deps
7
Size
75 kB
Vulns
0
Weekly
0

HTML Video

@html-docs/html-video is the deterministic rendering core behind HTML Docs' generated-video feature. A language model authors ordinary HTML, CSS, and a small seek-driven JavaScript function. This package validates that source, opens it in an isolated Chromium page, seeks to every frame, and pipes PNG frames into FFmpeg.

The model is the author, not the renderer. The renderer is fully local and open source: Puppeteer/Chromium produces pixels and FFmpeg encodes MP4, WebM, or GIF. A hosted service is optional operational infrastructure, not part of the composition format.

Modular explainer projects

For narrated or multi-scene work, author a project directory instead of one large JSON string:

video-project/
  video.project.json
  global.css
  audio/voiceover.wav
  audio/words.json
  assets/
  scenes/01-hook.html
  scenes/01-hook.css
  scenes/01-hook.js

The compiler concatenates scene modules into the stable version-1 composition format, embeds declared local assets as data URLs, measures the real voiceover, and derives scene boundaries from narration cues. Every cue owns exact text, one scene, and one or more unique target IDs. Builds fail when cue text does not cover the narration exactly, timed words are unassigned, cues overlap or cross scene boundaries, or targets are missing.

html-docs-video build ./video-project
html-docs-video check ./video-project
html-docs-video audit ./video-project
html-docs-video render ./video-project --output ./video-project/final.mp4

audit samples the opening, development, and resolve of every scene plus cue midpoints. It writes a quality report, individual PNGs, and a contact sheet; it scores narration ownership, framing diversity, explanatory structure, visible development, and deterministic seeking. publish enforces the same gate.

Composition contract

Every composition is a versioned JSON object with dimensions, frame rate, duration, HTML, CSS, script, scenes, assets, and user-overridable variables. Its script registers one API:

window.__HTML_VIDEO__ = {
  renderFrame({ root, timeMs, progress, variables }) {
    root.querySelector('.title').style.opacity = String(Math.min(1, timeMs / 500))
  },
}

Calling renderFrame at the same timestamp must always produce the same pixels. Wall clocks, unseeded randomness, timers, network calls, self-playing CSS animations, storage access, and runtime imports are rejected. The app also captures the same timestamp twice and compares the PNG bytes before it starts a full render.

Local-agent pipeline

  1. The owner copies a video brief from the document editor into a local Codex or Claude Code session with the HTML Docs skill.
  2. That existing agent session reads the document and authors the composition JSON. HTML Docs does not call a separate hosted model.
  3. Static and browser validation run on the user's computer.
  4. Local Chromium captures each frame and local FFmpeg encodes the MP4.
  5. The CLI registers the composition and receives one-use Supabase upload tokens from HTML Docs.
  6. The MP4 and poster upload directly from the user's computer to Supabase Storage; they never pass through Vercel.
  7. A lightweight completion call verifies the objects, inserts an atomic <video> block, and links the composition/render records.

Local requirements

  • Set HTML_VIDEO_CHROMIUM_PATH or HTML_VIDEO_FFMPEG_PATH only when automatic binary discovery is unsuitable.
  • Set HTMLDOCS_API_KEY to an account API key created in HTML Docs settings (or pass --api-key).
  • The document must be owned by the API-key account.

Run the database migration in scripts/sql/html_video.sql. The app lazily creates the public doc-videos storage bucket for rendered media; source compositions remain behind server-side access.

CLI development loop

pnpm --filter @html-docs/html-video cli check fixtures/hello.json
pnpm --filter @html-docs/html-video cli snapshot fixtures/hello.json --at 0,1500,2999
pnpm --filter @html-docs/html-video cli render fixtures/hello.json --output /tmp/hello.mp4
pnpm --filter @html-docs/html-video cli publish fixtures/hello.json \
  --document <document-id> \
  --prompt "Animate the key ideas" \
  --provider codex \
  --voiceover /path/to/narration.aiff \
  --output /tmp/hello.mp4

After the package is published, agents can use the equivalent portable command:

npx @html-docs/html-video publish composition.json \
  --document <document-id> \
  --prompt "Animate the key ideas" \
  --provider claude

--voiceover accepts a local audio file and muxes it into MP4 output. Use --replace-region <region-key> to update an existing generated-video block instead of inserting another one. Compositions must run for at least 3 seconds. There is no framework-imposed upper duration limit; narration and media generation remain local, and long renders are bounded only by the user's machine, storage, and upload capacity.

The package API exposes the same loadVideoInput, compileVideoProject, validateCompositionStatic, auditComposition, captureSnapshots, and renderComposition functions used by the CLI, so rendering can move to a queue or dedicated worker later without changing stored compositions or document embeds.