Metadata-Version: 2.4
Name: northnoir
Version: 1.0.0
Summary: Local CLI for making AI-drawn videos with your own AI coding agent — check and render scene.html with headless Chromium and ffmpeg. No API keys, no account.
Author: North Noir
License: Proprietary
Project-URL: Homepage, https://northnoir.com/cli
Project-URL: Documentation, https://northnoir.com/cli
Project-URL: Source, https://github.com/syver777/NorthNoir/tree/main/packages/northnoir-cli
Keywords: ai-drawn-video,animation,cli,playwright,ffmpeg
Classifier: Environment :: Console
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Multimedia :: Video
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: playwright==1.63.0
Requires-Dist: Pillow==12.3.0
Requires-Dist: numpy==2.5.3; python_version >= "3.12"
Requires-Dist: numpy==2.2.6; python_version < "3.12"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"

# 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):

```sh
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

```sh
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

```sh
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

```sh
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`.
