Skip to main content

northnoir — the local CLI for AI-drawn video

Make AI-drawn videos from your terminal, with your own AI coding agent as the model and your own machine as the compute. The northnoir CLI checks and renders a North Noir scene.html (the window.SCENE contract) entirely locally — headless Chromium paints every frame, ffmpeg encodes H.264 — with no API keys, no North Noir account, and no cloud tokens.

Your agent (Claude Code, OpenCode, Codex, Gemini CLI, Cursor) writes the drawing code, runs the checks, looks at its own frames, fixes what is wrong, and renders the final MP4. That loop is the product.

Install

Preview status: the northnoir package is not on PyPI or npm yet — registry publication is pending maintainer registry access. The tested install today is from source (below). Do not trust any third-party package using this name until this page says otherwise.

From source (isolated, puts northnoir on your PATH):

git clone https://github.com/syver777/NorthNoir.git
pipx install ./NorthNoir/packages/northnoir-cli
northnoir doctor --install   # installs Chromium via Playwright, then verifies
northnoir doctor             # Chromium, ffmpeg, pinned libraries (SHA256)

Alternative: pip install ./NorthNoir/packages/northnoir-cli into a Python virtual environment you manage yourself.

The npm package is not published. bin/northnoir.js in this repository is a thin Node shim over the Python package: it needs Python 3.10+ with playwright, Pillow and numpy already installed, so it is not a stand-alone npx installer and is not advertised as one.

Your host coding agent and your machine do the work: the agent's own usage/subscription terms apply to its model use, and rendering uses your local CPU and disk. NorthNoir provides no model inference through this CLI and charges nothing for local work.

Requirements: Python 3.10+, ffmpeg on PATH (brew install ffmpeg on macOS, sudo apt install ffmpeg on Debian/Ubuntu). Chromium is installed for you by northnoir doctor --install (Playwright). Docker is an optional transparent fallback when a local ruvil-js-renderer:local image exists.

Quickstart

northnoir init my-film --title "My Film"     # scaffold scene.html
northnoir check my-film/scene.html --still   # gate 1: frame 0 + report
northnoir check my-film/scene.html           # gate 2: sampled frames + quality
northnoir render my-film/scene.html -o my-film/my-film.mp4

Or hand the whole job to your agent: install the bundled skill (below), then ask for a video. The skill teaches the agent the contract and the loop.

The 4-step agent loop

  1. Author — write scene.html: one self-contained page whose JavaScript paints every frame of a 1920×1080 canvas. Frame 0 already shows the finished scene.
  2. Still check — northnoir check scene.html --still, then view frame-0000.png. Fix composition, scale and contrast before animating.
  3. Motion check — northnoir check scene.html, view contact-sheet.png, read the readability/collision/composition flags, fix, re-check (up to 3 improvement rounds; keep the best version).
  4. Render — northnoir render scene.html -o out.mp4, view the poster, verify with ffprobe (1920×1080, H.264, declared duration, stereo audio).

Commands

Command What it does
northnoir doctor [--install] [--json] Verify Chromium/Playwright, ffmpeg/ffprobe, and the pinned scene libraries (SHA256). --install runs the guided setup (Playwright Chromium) first.
northnoir init <dir> [--title "..."] [--duration 5] [--fps 24] [--style <id>] [--force] [--json] Scaffold <dir>/scene.html (working window.SCENE starter) + <dir>/.northnoir/.
northnoir check <scene.html> [--still] [--frames 0,12,24,...] [--out <dir>] [--json] Deterministic observer + quality + audio check. Writes full-res frame-NNNN.png files, contact-sheet.png, report.json (and audio.wav when the scene has audio) to <scene_dir>/.northnoir/check/ by default. Always prints JSON.
northnoir render <scene.html> [-o <output.mp4>] [--fps 24] [--duration <sec>] [--no-audio] [--json] Render every frame at 1920×1080, render SCENE.audio offline (48 kHz stereo), mux H.264 + AAC. Writes <output>.poster.png and <output>.sheet.png. Always prints JSON.
northnoir styles [--json] List the 31 AnidoodleDraw style ids and the RuvilMarks helpers.
northnoir skill [install] [--install] [--json] Print the bundled northnoir-draw skill path; install copies it into the agent skill folders.
northnoir --version Print the CLI version.

Exit codes: 0 only when the report is ok, 1 on scene/encode failure, 2 on usage errors.

check JSON: ok, still_only, errors, quality (readability / collision / composition + flags), cues, cue_errors, audio_ok, metrics (deterministic, canvas size, blank/frozen frames), frame_paths, contact_sheet_path, report_path. Quality flags are review evidence — they do not by themselves flip ok.

render JSON: ok, output_mp4, poster_png, contact_sheet_png, frames_rendered, duration_s, fps, has_audio, size_bytes, elapsed_s.

The window.SCENE contract (cheat-sheet)

  • Canvas is 1920×1080. Declare SCENE.fps, SCENE.frames (or SCENE.duration), SCENE.width/height, and SCENE.canvas.
  • SCENE.renderFrame(n) is a pure function of n: no unseeded randomness, no wall-clock reads for drawing decisions (the renderer re-seeds per frame, so renders are deterministic and re-renders are byte-identical).
  • SCENE.init() bakes textures once and registers subjects/blockers: window.__ruvilSubjects.register(id, role, boxFn) / window.__ruvilBlockers.register(...), keeping the declarative SCENE.subjects / SCENE.blockers mirrors in sync. Draw the main subject inside window.__ruvilSubjects.draw('hero', () => { ... }) so the checker can measure it.
  • SCENE.cues: [{ t, prompt, seconds }] — timed sound beats, validated against the scene duration.
  • SCENE.audio(ctx, info): procedural audio scheduled on the OfflineAudioContext you are given (48 kHz stereo out). Keep peaks ≤ 0.7, seed every noise source, sync hits to your cues.
  • Only five pinned library URLs may be loaded — every other network request is blocked by the renderer: https://libs.ruvil/p5.min.js, rough.min.js, simplex-noise.js, ruvil-marks.js, anidoodle-draw.js (served offline from the package, SHA256-verified by doctor).

Kit reference

  • RuvilMarks (ruvil-marks.js): paper(ctx, o) (bake the paper ground once in init()), wash, stipple (blue-noise dots; density = tone), hatch (spacing = tone), rng(seed) (mulberry32), hash(a, b) (boil outlines 1–3 px via hash(boilIndex, strokeId)).
  • AnidoodleDraw (anidoodle-draw.js): AnidoodleDraw.draw('<id>', ctx, frame, W, H) plates one of 31 finished style scenes under your scene; AnidoodleDraw.styles lists the ids at runtime. Run northnoir styles.

The agent skill

northnoir skill install

copies the bundled northnoir-draw skill into .claude/skills/, .agents/skills/, ~/.config/opencode/skills/ and ~/.claude/skills/, so Claude Code, OpenCode, Codex, Gemini CLI and Cursor agents learn the contract, the 4-step loop, the quality-flag fix table and the craft rules before they draw. northnoir skill prints the bundled path.

CLI vs Studio vs MCP

CLI (this package) Web Studio MCP server
Where it runs Your machine North Noir cloud Your chat app
The model Your AI coding agent The model you pick in Studio The model you pick
Cost Free, local North Noir tokens (free plan: your own API key) North Noir tokens
Best for One drawn scene, agent-driven Timelines, voice/music, multi-section films at scale Drawing from Claude/Cursor chats

Troubleshooting

  • doctor says Chromium will not launch — run northnoir doctor --install. On Linux you may also need Playwright's system libraries: python3 -m playwright install-deps chromium (asks for sudo; the CLI never runs sudo itself).
  • ffmpeg missing — install it with your OS package manager (above); doctor prints the exact hint for your platform.
  • The Node shim cannot start Python / deps missing — the npm package is not published; bin/northnoir.js is a repo-only thin shim. Use the source install above (recommended), or install the pinned deps into the Python the shim finds and set NORTHNOIR_PYTHON to choose the interpreter.
  • A library SHA256 fails — the vendored runtime is corrupted or hand-edited. Reinstall the package; maintainers refresh it with tools/sync_runtime.py (single source of truth: cloudrun/ruvil-js-renderer/ in the repo).
  • Slow renders — rendering is deterministic software rendering; heavy full-canvas grain costs time per frame. Check avg_ms_per_frame in the check report before rendering long scenes.

Development

python3 tools/sync_runtime.py   # refresh northnoir_cli/runtime from cloudrun/
python3 -m pytest tests/ -q     # end-to-end suite (doctor/styles/init/check/render)
python3 northnoir_cli/cli.py doctor   # or: ./bin/northnoir doctor

Packaging choice: a Python package (the engine is Python + Playwright; Chromium and ffmpeg are external tools doctor verifies). An unpublished thin Node shim (bin/northnoir.js, private: true in package.json) is kept for repo use only. A compiled single binary was rejected: it would have to bundle a Python interpreter plus Playwright plus a browser download, which is larger, more fragile across platforms, and harder to debug than pipx.

Licenses

The CLI code is proprietary North Noir software (see pyproject.toml). The bundled scene libraries keep their own licenses, shipped beside them in northnoir_cli/runtime/libs/: LICENSE.p5.txt (p5.js), LICENSE.roughjs.txt (rough.js), LICENSE.simplex-noise.txt (simplex-noise), LICENSE.anidoodle.txt (AnidoodleDraw / RuvilMarks). Their pinned SHA256 digests are in northnoir_cli/runtime/libs/SHA256SUMS and verified by northnoir doctor.

Metadata

Release files for northnoir 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for northnoir 1.0.0
File Size Uploaded
northnoir-1.0.0.tar.gz 625.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for northnoir 1.0.0
File Interpreter ABI Platform
northnoir-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / northnoir-1.0.0.tar.gz

Download URL northnoir-1.0.0.tar.gz
Size 625.7 kB
Tags Source
SHA-256 checksum
How to use checksums
b17065f902f25fedc377ca5064aa04438488782481f0e30439d9779041c05226
BLAKE2b-256 checksum
How to use checksums
8a2f421fef45f037963877257c7e7ce1a2ed97762fc93c44e2d1f5e76289f3c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / northnoir-1.0.0-py3-none-any.whl

Download URL northnoir-1.0.0-py3-none-any.whl
Size 635.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cb896c83c8d1437c278d528dc9f3fcf221b6be52da76040ed1c2c978e8fc9c8d
BLAKE2b-256 checksum
How to use checksums
29551fdf096a5e790c49f012bee6e3d79b7d5ed6304685e4fd18f560991c0bce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

1.0.1

2 release files

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page