Skip to content

Repository files navigation

kino — /ˈkiːnoʊ/ n. German: cinema, from Greek kīnēma: motion

Agent-driven short-form video production

License: MIT Node ≥20 TypeScript 9:16 MP4 output Voiceover by ElevenLabs


kino turns an agent-authored JSON spec into a finished vertical video. The agent writes the spec, kino renders it: ElevenLabs voiceover, an optional AI avatar (HeyGen / Hedra / Replicate) or a faceless background, composited to a 9:16 / 3:4 MP4 by an in-house headless-Chrome render engine.

Showcase

kino writing its own advert.json spec, live The Descent — motion graphics from a long-form kino build Lunara — quiet mood piece
The self-demo
kino types its own advert.json and builds the ad you're watching
▶ watch with sound
The Descent
real footage into the motion-graphics finale of a 66s build
▶ watch full video with sound
Lunara
stock b-roll and a quiet voiceover
▶ watch with sound

Fictional sample brands. Each is a real, deterministic kino build — faceless, 9:16, ElevenLabs voiceover. Previews are silent trimmed clips; click any preview (or the ▶ links) to play the full MP4 with sound in your browser.

Pipeline at a glance

spec.json ─▶ validate ─▶ voiceover (ElevenLabs) ─▶ avatar plan + trim
          ─▶ avatar (HeyGen/Hedra/Replicate) or faceless background / motion graphics
          ─▶ native render (headless Chrome) ─▶ ffmpeg ─▶ out/<title>/…mp4

No LLM inside the CLI: every step is deterministic, so the same spec renders the same video.

Install

git clone https://github.com/sdkv2/kino.git ~/kino     # clone the toolchain once
cd <your-project> && bash ~/kino/setup.sh              # install `kino` + write a project .env

On Windows (or anywhere without bash): node ~/kino/setup.mjs — same installer, pure Node. setup.sh/setup.mjs is a guided installer: prerequisite checks (Node 20+, ffmpeg, ImageMagick — offers to install what's missing via brew/apt/winget), npm install / build / link, then an API-key walkthrough (written to a chmod 600, git-ignored .env; re-runs keep existing keys). Manual install:

cd ~/kino && npm install && npm run build && npm link

Requires Node 20+, ffmpeg/ffprobe (+ ImageMagick for storyboards). Real VO needs an ElevenLabs key (referral link — supports the project). Faceless builds need only that. Avatar builds also need the avatar provider's key, plus ElevenLabs whenever kino drives the voice (most setups).

Quickstart

cd <project> && npx @sdkv2/kino init acme            # scaffold .env, brand.md, dirs + a sample spec
npx @sdkv2/kino doctor                               # preflight: API keys, ffmpeg/ffprobe, heygen CLI
npx @sdkv2/kino build projects/acme/specs/sample.json --mock  # free structural preview (no API spend)
npx @sdkv2/kino build projects/acme/specs/sample.json         # real render → projects/acme/out/sample/

kino init writes a ready-to-build faceless sample (provider none, $0), so the first kino build works with no editing. Swap in your own spec once the preview looks right.

npx pulls Node deps fresh each first run — Puppeteer's Chromium is bundled. ffmpeg/ffprobe use your system install if on PATH, otherwise fall back to a bundled binary automatically. For frequent use, npm i -g @sdkv2/kino avoids the npx resolve overhead.

Agent skills

Agent playbooks (video-production, ad-voice, adversarial-critique, …) are in skills/ — the only copy in the repo.

From any project (Cursor / Claude Code / Codex / …):

npx skills add sdkv2/kino
# or one skill:  npx skills add sdkv2/kino@ad-voice

Inside a kino workspace (after clone / npm link):

kino skills --install                 # local symlinks → .agents .cursor .claude .codex (gitignored; also run by kino init)
kino skills --install --agents cursor,claude

Agent fan-out dirs stay off git so they do not clutter the tree. Details: skills/README.md.

Features

  • Avatar enginesnone (faceless, $0), heygen (Avatar-IV), hedra (Character-3), replicate (open-source lip-sync). Avatars are trimmed to on-camera segments to cut spend; VO + avatar are content-hash cached.
  • Faceless backgroundsglow, image, mesh, aurora, particles, grid, custom — frame-deterministic Canvas2D, auto-coloured from the brand.
  • Captionsphrase (editorial block) or words (revealed word-by-word, synced to real VO timestamps, with active-word highlight + per-segment emphasis).
  • Fonts — pick a name from kino fonts (fetched on demand from Google Fonts into ~/.kino/fonts/), or use any raw CSS family.
  • Stock mediakino pexels (video) and kino photos (stills) search Pexels (portrait-first) into project assets; same PEXELS_API_KEY. .mp4 / .jpg work in app cut-ins.
  • Animated backgrounds & overlays — backgrounds, logo, captions, and kickers are all tweenable on one keyframe layer (backgroundKeyframes/logoKeyframes/…), with timed backgroundTriggers.
  • Motion graphics — author a self-contained HTML/CSS file in assets/motion/; kino drives it per-frame via CSS variables, with scrubbed @keyframes and a .kino-cliptext helper, sanitized and determinism-linted. See docs/motion-graphics.md.
  • Branding & compliance — logo mark + a per-mode AI disclosure; brand bannedPhrases fail the build (no guaranteed-outcome copy).
  • Inspect & iterateinspect (plan as JSON), still/storyboard (fast mock previews), frames (extract from a render). Built for tight agent loops.
  • Brands & projectsbrands/<name>/brand.md (markdown frontmatter + guidelines) is shared; every build runs inside a projects/<name>/ (its own specs/assets/out + a project.json that assigns a brand). kino init <brand> scaffolds the first one; kino projects --new adds more.

How kino drives motion graphics

There is no running timeline: kino seeks headless Chrome to frame N, sets CSS custom properties on the graphic, and screenshots — every frame. The JSON spec owns the clock; the graphic is a stateless canvas that reads the variables and paints that one frame, so the same spec always renders the same pixels.

Each frame the graphic receives:

  • --progress (0 → 1 across the beat) plus eased curves — --kino-out, --kino-inout, --kino-overshoot, --kino-spring, and seam-safe --kino-edge
  • --pulse — a fast-attack, decaying envelope fired by spec triggers (punches timed to VO words)
  • --<param> — every key in the spec's params, tweened by keyframes
  • brand palette + fonts (--kino-mint, --kino-font, …) and per-word voiceover timings (--kino-words-shown / env.words), so typed UIs land characters in sync with the speech
{ "kind": "motion", "source": "motion/stat.html", "text": "Eighty-six percent match.",
  "params": { "pct": 0 },
  "keyframes": [{ "at": 0.2, "params": { "pct": 86 }, "ease": "overshoot" }],
  "triggers":  [{ "at": 0.2, "action": "pulse" }] }

Real CSS @keyframes work too: kino force-pauses all animations and scrubs .kino-anim elements across the beat via a --progress-driven negative animation-delay. Three tiers by file extension:

Source Model
.html declarative CSS reading the variable contract
.js pure render(env) → HTML, re-evaluated per frame (loops, computed geometry)
.json Lottie, frame-seeked with goToAndStop — stretched, looped, or word-fired by triggers

Every graphic is lint-checked for determinism (no transition, timers, Date.now, Math.random, network) and sanitized into a Shadow DOM before render. Full contract: docs/motion-graphics.md.

Documentation

Longer guides are in docs/:

Development

npm run build     # tsc → dist/
npm test          # vitest (run once);  npm run test:watch to watch
npm run dev -- <args>   # run the CLI from source via tsx

Work on a feature branch (feat/…, fix/…, chore/…), bump version in package.json for releases, and open a PR to main. Version history lives in CHANGELOG.md. Full guidelines: CONTRIBUTING.md.

License

MIT © sdkv2

About

Agent-driven short-form video production — a CLI that turns an agent-authored JSON spec into a finished vertical video (ElevenLabs VO, optional AI avatar, deterministic in-house headless-Chrome renderer)

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages