Getting started

CLI reference

Spec reference

Concepts

Install

From npm:

npm install lazy-frames
npx lazy doctor

Install for an AI agent

Agents need the Lazy Frames CLI on your machine and the raw skill instructions. Install the package first:

npm install lazy-frames
npx lazy doctor

Then use your agent's skill-from-URL option, or ask it to read and follow this raw Markdown skill:

https://lazy-frames.cosmicstack.ai/skill.md

Open the raw skill · View the human-readable version

Example agent request:

Read and follow the Lazy Frames skill at
https://lazy-frames.cosmicstack.ai/skill.md

Then make a promo video for https://example.com.

From source (for development):

git clone https://github.com/cosmicstack-labs/lazy-frames.git
cd lazy-frames
npm install && npm run build
npx lazy doctor

Prerequisites

DependencyRequired forCheck
Node.js ≥ 20CLI + enginenode --version
ffmpeg + ffprobeencoding + audioffmpeg -version
Google Chromeheadless renderinglazy doctor
Python 3audio sidecarpython3 --version
macOS sayTTS narrationsay -v '?'

Run npx lazy doctor to verify all providers.

First video

Website promo:

npx lazy capture https://example.com projects/acme
npx lazy snapshot projects/acme --update
npx lazy check projects/acme
npx lazy preview projects/acme   # review in browser
npx lazy render projects/acme     # after approval

Cinematic clip:

npx lazy gen image -p projects/cine --seed 21 --style ridge --name r01
# write spec.json referencing assets/gen/r01.png + r01.depth.png
npx lazy render projects/cine

capture

Captures a website: screenshots @2x, palette, copy, fonts, logo. Writes a starter spec.

lazy capture <url> [project] [--json]

gen

Generates media with local providers.

lazy gen image -p <project> --seed 21 --style ridge --name r01
lazy gen music -p <project> --mood calm --bpm 90 --bars 12 --seed 21
lazy gen tts -p <project> --text "Hello world" --voice Samantha --rate 165

Image styles: ridge, dune, nebula. Generates <name>.png + <name>.depth.png.

script

Drafts an editable narration script from on-screen scene content. With --apply, it writes narration.md and scene-linked narration beats into spec.json.

lazy script <project> [--provider say] [--voice Samantha]
lazy script projects/cine --provider elevenlabs --voice VOICE_ID --apply

Each beat uses sceneId and offsetMs. Lazy Frames measures the synthesized audio and rejects narration that would overrun its scene or the final timeline.

plugin

Plugins are reviewed, capability-scoped adapters. Install records the exact version and manifest fingerprint in lazy-plugins.json, plus a separate user-local approval for that project. A committed lockfile cannot grant itself permission. Arbitrary package URLs and install scripts are not accepted.

lazy plugin search [tts|script|storytelling]
lazy plugin install elevenlabs -p projects/cine
lazy plugin list -p projects/cine
lazy plugin remove elevenlabs -p projects/cine

ElevenLabs setup:

export ELEVENLABS_API_KEY="your-key"
lazy gen tts -p projects/cine --provider elevenlabs --voice VOICE_ID \
  --text "Every frame follows the story." --name narration-01

The credential stays in the environment and is never stored in the spec or lockfile. See the plugin store and its machine-readable registry.

check

Validates: environment, spec schema, semantic checks, and two blocking gates (snapshot regression + seek determinism).

lazy check <project> [--json] [--skip-gates]

snapshot

Creates or updates the snapshot regression baseline.

lazy snapshot <project> [--update]

Run --update once in a new project or after intentional spec changes.

render

Renders the composition to MP4. Generates audio (if in spec), muxes, probe-verifies, prints SHA-256.

lazy render <project> [-o <path>] [--fps N] [--parallel N] [--fast] [--json]

preview

Serves a scrubbable timeline at localhost:4173.

lazy preview <project> [-p <port>]

doctor

Reports Node/Python versions, memory, hardware tier, and provider availability.

lazy doctor [--json]

Spec structure

{
  "specVersion": 1,
  "meta": { "id": "my-video", "width": 1920, "height": 1080, "fps": 24 },
  "style": {
    "tokens": {
      "palette": ["#0B0F19", "#C49A5C", "#E2E0DC"],
      "fontDisplay": "Space Grotesk",
      "fontBody": "Inter"
    },
    "grade": "none"
  },
  "scenes": [ ... ],
  "audio": { ... },
  "outputs": [{ "format": "mp4", "path": "out/video.mp4", "codec": "h264" }]
}

Palette convention: index 0 = background, 1 = accent, 2 = foreground.

Width/height must be even (h264 yuv420p requirement).

Scene types

TypeWhat it does
typographyText reveals: titles, quotes, lockups (4 reveal styles)
stat-hitCount-up numbers, labels, bars
browser-frameScreenshot in a browser chrome mockup with cursor
ui-calloutScreenshot with dimmed mask, hotspot spotlight, label
atmosphereDrifting gradient blobs — ambient backdrops
parallax2.5D camera move over a still (flat or depth-map mode)
video-layerFootage playback with trim, speed, grade
three-sceneDeterministic 3D: cube/ico/grid/particles (canvas 2D)

Transitions

TypeEffect
cutInstant
fade / dissolve / dip-to-blackOpacity in/out
whip-panHorizontal slide with quick ease
light-leakHold + fade (flash-like)
luma-wipeVertical slide wipe

All transitions: { "type": "...", "ms": N }. Must be shorter than scene duration.

Audio

All audio is declarative — generated at render time, cached by content hash.

"audio": {
  "narration": [{ "text": "...", "startMs": 3600, "voice": "Samantha", "rate": 165 }],
  "music": { "mood": "calm", "bpm": 90, "bars": 12, "seed": 21, "gainDb": -14 },
  "sfx": [{ "kind": "whoosh", "atMs": 2400, "seed": 1, "gainDb": -6 }]
}

SFX kinds: whoosh, hit, rise, boom.

LUT & grade

Stage grade (style.grade): CSS filter on the composition root. Presets: none, contrast, vivid, muted, monochrome.

Output LUT (outputs[0].lut): 3D LUT .cube file applied via ffmpeg lut3d. Bundled: teal-orange, noir-film, faded-vintage.

Determinism

Same spec + same machine = byte-identical MP4. Enforced by:

Gates

Snapshot regression: renders keyframes, hashes pixels, compares against snapshots/baseline.json. Drift = error with scene + timestamp.

Seek determinism: renders 5 timestamps twice in one session, compares hashes. Catches in-session nondeterminism.