northnoir 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. northnoir-1.0.0/MANIFEST.in +8 -0
  2. northnoir-1.0.0/PKG-INFO +215 -0
  3. northnoir-1.0.0/README.md +192 -0
  4. northnoir-1.0.0/bin/northnoir +10 -0
  5. northnoir-1.0.0/bin/northnoir.js +19 -0
  6. northnoir-1.0.0/northnoir.egg-info/PKG-INFO +215 -0
  7. northnoir-1.0.0/northnoir.egg-info/SOURCES.txt +40 -0
  8. northnoir-1.0.0/northnoir.egg-info/dependency_links.txt +1 -0
  9. northnoir-1.0.0/northnoir.egg-info/entry_points.txt +2 -0
  10. northnoir-1.0.0/northnoir.egg-info/requires.txt +12 -0
  11. northnoir-1.0.0/northnoir.egg-info/top_level.txt +1 -0
  12. northnoir-1.0.0/northnoir_cli/__init__.py +3 -0
  13. northnoir-1.0.0/northnoir_cli/__main__.py +4 -0
  14. northnoir-1.0.0/northnoir_cli/cli.py +962 -0
  15. northnoir-1.0.0/northnoir_cli/runtime/app/__init__.py +0 -0
  16. northnoir-1.0.0/northnoir_cli/runtime/app/__main__.py +8 -0
  17. northnoir-1.0.0/northnoir_cli/runtime/app/audio.py +95 -0
  18. northnoir-1.0.0/northnoir_cli/runtime/app/check_script.js +840 -0
  19. northnoir-1.0.0/northnoir_cli/runtime/app/config.py +101 -0
  20. northnoir-1.0.0/northnoir_cli/runtime/app/encode.py +96 -0
  21. northnoir-1.0.0/northnoir_cli/runtime/app/imaging.py +186 -0
  22. northnoir-1.0.0/northnoir_cli/runtime/app/init_script.js +298 -0
  23. northnoir-1.0.0/northnoir_cli/runtime/app/quality.py +218 -0
  24. northnoir-1.0.0/northnoir_cli/runtime/app/quality_script.js +157 -0
  25. northnoir-1.0.0/northnoir_cli/runtime/app/renderer.py +556 -0
  26. northnoir-1.0.0/northnoir_cli/runtime/app/resources.py +48 -0
  27. northnoir-1.0.0/northnoir_cli/runtime/libs/LICENSE.anidoodle.txt +204 -0
  28. northnoir-1.0.0/northnoir_cli/runtime/libs/LICENSE.p5.txt +458 -0
  29. northnoir-1.0.0/northnoir_cli/runtime/libs/LICENSE.roughjs.txt +21 -0
  30. northnoir-1.0.0/northnoir_cli/runtime/libs/LICENSE.simplex-noise.txt +43 -0
  31. northnoir-1.0.0/northnoir_cli/runtime/libs/SHA256SUMS +7 -0
  32. northnoir-1.0.0/northnoir_cli/runtime/libs/anidoodle-draw.js +1 -0
  33. northnoir-1.0.0/northnoir_cli/runtime/libs/anidoodle-kit.js +4 -0
  34. northnoir-1.0.0/northnoir_cli/runtime/libs/p5.min.js +2 -0
  35. northnoir-1.0.0/northnoir_cli/runtime/libs/rough.min.js +1 -0
  36. northnoir-1.0.0/northnoir_cli/runtime/libs/ruvil-marks.js +444 -0
  37. northnoir-1.0.0/northnoir_cli/runtime/libs/ruvil-sim.js +165 -0
  38. northnoir-1.0.0/northnoir_cli/runtime/libs/simplex-noise.js +473 -0
  39. northnoir-1.0.0/northnoir_cli/skill/SKILL.md +376 -0
  40. northnoir-1.0.0/package.json +23 -0
  41. northnoir-1.0.0/pyproject.toml +54 -0
  42. northnoir-1.0.0/setup.cfg +4 -0
@@ -0,0 +1,8 @@
1
+ include README.md pyproject.toml package.json
2
+ include bin/northnoir bin/northnoir.js
3
+ global-exclude *.pyc
4
+ global-exclude __pycache__
5
+ prune examples
6
+ prune tests
7
+ prune tools
8
+ exclude .gitignore
@@ -0,0 +1,215 @@
1
+ Metadata-Version: 2.4
2
+ Name: northnoir
3
+ Version: 1.0.0
4
+ 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.
5
+ Author: North Noir
6
+ License: Proprietary
7
+ Project-URL: Homepage, https://northnoir.com/cli
8
+ Project-URL: Documentation, https://northnoir.com/cli
9
+ Project-URL: Source, https://github.com/syver777/NorthNoir/tree/main/packages/northnoir-cli
10
+ Keywords: ai-drawn-video,animation,cli,playwright,ffmpeg
11
+ Classifier: Environment :: Console
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Multimedia :: Video
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: playwright==1.63.0
17
+ Requires-Dist: Pillow==12.3.0
18
+ Requires-Dist: numpy==2.5.3; python_version >= "3.12"
19
+ Requires-Dist: numpy==2.2.6; python_version < "3.12"
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest>=8; extra == "dev"
22
+ Requires-Dist: build>=1.2; extra == "dev"
23
+
24
+ # northnoir — the local CLI for AI-drawn video
25
+
26
+ Make AI-drawn videos from your terminal, with **your own AI coding agent as the
27
+ model and your own machine as the compute**. The `northnoir` CLI checks and
28
+ renders a North Noir `scene.html` (the `window.SCENE` contract) entirely
29
+ locally — headless Chromium paints every frame, `ffmpeg` encodes H.264 — with
30
+ **no API keys, no North Noir account, and no cloud tokens**.
31
+
32
+ Your agent (Claude Code, OpenCode, Codex, Gemini CLI, Cursor) writes the
33
+ drawing code, runs the checks, *looks at its own frames*, fixes what is wrong,
34
+ and renders the final MP4. That loop is the product.
35
+
36
+ ## Install
37
+
38
+ > **Preview status:** the `northnoir` package is not on PyPI or npm yet —
39
+ > registry publication is pending maintainer registry access. The tested
40
+ > install today is from source (below). Do not trust any third-party package
41
+ > using this name until this page says otherwise.
42
+
43
+ From source (isolated, puts `northnoir` on your PATH):
44
+
45
+ ```sh
46
+ git clone https://github.com/syver777/NorthNoir.git
47
+ pipx install ./NorthNoir/packages/northnoir-cli
48
+ northnoir doctor --install # installs Chromium via Playwright, then verifies
49
+ northnoir doctor # Chromium, ffmpeg, pinned libraries (SHA256)
50
+ ```
51
+
52
+ Alternative: `pip install ./NorthNoir/packages/northnoir-cli` into a Python
53
+ virtual environment you manage yourself.
54
+
55
+ The npm package is **not published**. `bin/northnoir.js` in this repository is
56
+ a thin Node shim over the Python package: it needs Python 3.10+ with
57
+ `playwright`, `Pillow` and `numpy` already installed, so it is not a
58
+ stand-alone `npx` installer and is not advertised as one.
59
+
60
+ Your host coding agent and your machine do the work: the agent's own
61
+ usage/subscription terms apply to its model use, and rendering uses your local
62
+ CPU and disk. NorthNoir provides no model inference through this CLI and
63
+ charges nothing for local work.
64
+
65
+ Requirements: Python 3.10+, `ffmpeg` on PATH (`brew install ffmpeg` on macOS,
66
+ `sudo apt install ffmpeg` on Debian/Ubuntu). Chromium is installed for you by
67
+ `northnoir doctor --install` (Playwright). Docker is an optional transparent
68
+ fallback when a local `ruvil-js-renderer:local` image exists.
69
+
70
+ ## Quickstart
71
+
72
+ ```sh
73
+ northnoir init my-film --title "My Film" # scaffold scene.html
74
+ northnoir check my-film/scene.html --still # gate 1: frame 0 + report
75
+ northnoir check my-film/scene.html # gate 2: sampled frames + quality
76
+ northnoir render my-film/scene.html -o my-film/my-film.mp4
77
+ ```
78
+
79
+ Or hand the whole job to your agent: install the bundled skill (below), then
80
+ ask for a video. The skill teaches the agent the contract and the loop.
81
+
82
+ ## The 4-step agent loop
83
+
84
+ 1. **Author** — write `scene.html`: one self-contained page whose JavaScript
85
+ paints every frame of a 1920×1080 canvas. Frame 0 already shows the
86
+ finished scene.
87
+ 2. **Still check** — `northnoir check scene.html --still`, then *view*
88
+ `frame-0000.png`. Fix composition, scale and contrast before animating.
89
+ 3. **Motion check** — `northnoir check scene.html`, view `contact-sheet.png`,
90
+ read the readability/collision/composition flags, fix, re-check (up to 3
91
+ improvement rounds; keep the best version).
92
+ 4. **Render** — `northnoir render scene.html -o out.mp4`, view the poster,
93
+ verify with `ffprobe` (1920×1080, H.264, declared duration, stereo audio).
94
+
95
+ ## Commands
96
+
97
+ | Command | What it does |
98
+ |---|---|
99
+ | `northnoir doctor [--install] [--json]` | Verify Chromium/Playwright, `ffmpeg`/`ffprobe`, and the pinned scene libraries (SHA256). `--install` runs the guided setup (Playwright Chromium) first. |
100
+ | `northnoir init <dir> [--title "..."] [--duration 5] [--fps 24] [--style <id>] [--force] [--json]` | Scaffold `<dir>/scene.html` (working `window.SCENE` starter) + `<dir>/.northnoir/`. |
101
+ | `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. |
102
+ | `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. |
103
+ | `northnoir styles [--json]` | List the 31 AnidoodleDraw style ids and the RuvilMarks helpers. |
104
+ | `northnoir skill [install] [--install] [--json]` | Print the bundled `northnoir-draw` skill path; `install` copies it into the agent skill folders. |
105
+ | `northnoir --version` | Print the CLI version. |
106
+
107
+ Exit codes: `0` only when the report is `ok`, `1` on scene/encode failure,
108
+ `2` on usage errors.
109
+
110
+ `check` JSON: `ok`, `still_only`, `errors`, `quality` (readability / collision /
111
+ composition + `flags`), `cues`, `cue_errors`, `audio_ok`, `metrics`
112
+ (deterministic, canvas size, blank/frozen frames), `frame_paths`,
113
+ `contact_sheet_path`, `report_path`. Quality flags are review evidence — they
114
+ do not by themselves flip `ok`.
115
+
116
+ `render` JSON: `ok`, `output_mp4`, `poster_png`, `contact_sheet_png`,
117
+ `frames_rendered`, `duration_s`, `fps`, `has_audio`, `size_bytes`, `elapsed_s`.
118
+
119
+ ## The `window.SCENE` contract (cheat-sheet)
120
+
121
+ - Canvas is **1920×1080**. Declare `SCENE.fps`, `SCENE.frames` (or
122
+ `SCENE.duration`), `SCENE.width/height`, and `SCENE.canvas`.
123
+ - `SCENE.renderFrame(n)` is a **pure function of `n`**: no unseeded randomness,
124
+ no wall-clock reads for drawing decisions (the renderer re-seeds per frame,
125
+ so renders are deterministic and re-renders are byte-identical).
126
+ - `SCENE.init()` bakes textures once and registers subjects/blockers:
127
+ `window.__ruvilSubjects.register(id, role, boxFn)` /
128
+ `window.__ruvilBlockers.register(...)`, keeping the declarative
129
+ `SCENE.subjects` / `SCENE.blockers` mirrors in sync. Draw the main subject
130
+ inside `window.__ruvilSubjects.draw('hero', () => { ... })` so the checker
131
+ can measure it.
132
+ - `SCENE.cues`: `[{ t, prompt, seconds }]` — timed sound beats, validated
133
+ against the scene duration.
134
+ - `SCENE.audio(ctx, info)`: procedural audio scheduled on the
135
+ `OfflineAudioContext` you are given (48 kHz stereo out). Keep peaks ≤ 0.7,
136
+ seed every noise source, sync hits to your cues.
137
+ - Only five pinned library URLs may be loaded — every other network request is
138
+ blocked by the renderer:
139
+ `https://libs.ruvil/p5.min.js`, `rough.min.js`, `simplex-noise.js`,
140
+ `ruvil-marks.js`, `anidoodle-draw.js` (served offline from the package,
141
+ SHA256-verified by `doctor`).
142
+
143
+ ## Kit reference
144
+
145
+ - **RuvilMarks** (`ruvil-marks.js`): `paper(ctx, o)` (bake the paper ground
146
+ once in `init()`), `wash`, `stipple` (blue-noise dots; density = tone),
147
+ `hatch` (spacing = tone), `rng(seed)` (mulberry32), `hash(a, b)` (boil
148
+ outlines 1–3 px via `hash(boilIndex, strokeId)`).
149
+ - **AnidoodleDraw** (`anidoodle-draw.js`): `AnidoodleDraw.draw('<id>', ctx,
150
+ frame, W, H)` plates one of 31 finished style scenes under your scene;
151
+ `AnidoodleDraw.styles` lists the ids at runtime. Run `northnoir styles`.
152
+
153
+ ## The agent skill
154
+
155
+ ```sh
156
+ northnoir skill install
157
+ ```
158
+
159
+ copies the bundled `northnoir-draw` skill into `.claude/skills/`,
160
+ `.agents/skills/`, `~/.config/opencode/skills/` and `~/.claude/skills/`, so
161
+ Claude Code, OpenCode, Codex, Gemini CLI and Cursor agents learn the contract,
162
+ the 4-step loop, the quality-flag fix table and the craft rules before they
163
+ draw. `northnoir skill` prints the bundled path.
164
+
165
+ ## CLI vs Studio vs MCP
166
+
167
+ | | CLI (this package) | Web Studio | MCP server |
168
+ |---|---|---|---|
169
+ | Where it runs | Your machine | North Noir cloud | Your chat app |
170
+ | The model | Your AI coding agent | The model you pick in Studio | The model you pick |
171
+ | Cost | Free, local | North Noir tokens (free plan: your own API key) | North Noir tokens |
172
+ | Best for | One drawn scene, agent-driven | Timelines, voice/music, multi-section films at scale | Drawing from Claude/Cursor chats |
173
+
174
+ ## Troubleshooting
175
+
176
+ - **`doctor` says Chromium will not launch** — run `northnoir doctor
177
+ --install`. On Linux you may also need Playwright's system libraries:
178
+ `python3 -m playwright install-deps chromium` (asks for sudo; the CLI never
179
+ runs sudo itself).
180
+ - **`ffmpeg` missing** — install it with your OS package manager (above);
181
+ `doctor` prints the exact hint for your platform.
182
+ - **The Node shim cannot start Python / deps missing** — the npm package is
183
+ not published; `bin/northnoir.js` is a repo-only thin shim. Use the source
184
+ install above (recommended), or install the pinned deps into the Python the
185
+ shim finds and set `NORTHNOIR_PYTHON` to choose the interpreter.
186
+ - **A library SHA256 fails** — the vendored runtime is corrupted or hand-edited.
187
+ Reinstall the package; maintainers refresh it with `tools/sync_runtime.py`
188
+ (single source of truth: `cloudrun/ruvil-js-renderer/` in the repo).
189
+ - **Slow renders** — rendering is deterministic software rendering; heavy
190
+ full-canvas grain costs time per frame. Check `avg_ms_per_frame` in the
191
+ check report before rendering long scenes.
192
+
193
+ ## Development
194
+
195
+ ```sh
196
+ python3 tools/sync_runtime.py # refresh northnoir_cli/runtime from cloudrun/
197
+ python3 -m pytest tests/ -q # end-to-end suite (doctor/styles/init/check/render)
198
+ python3 northnoir_cli/cli.py doctor # or: ./bin/northnoir doctor
199
+ ```
200
+
201
+ Packaging choice: a **Python package** (the engine is Python + Playwright;
202
+ Chromium and ffmpeg are external tools `doctor` verifies). An unpublished
203
+ thin Node shim (`bin/northnoir.js`, `private: true` in `package.json`) is kept
204
+ for repo use only. A compiled single binary was rejected: it would have
205
+ to bundle a Python interpreter plus Playwright plus a browser download, which
206
+ is larger, more fragile across platforms, and harder to debug than `pipx`.
207
+
208
+ ## Licenses
209
+
210
+ The CLI code is proprietary North Noir software (see `pyproject.toml`). The
211
+ bundled scene libraries keep their own licenses, shipped beside them in
212
+ `northnoir_cli/runtime/libs/`: `LICENSE.p5.txt` (p5.js), `LICENSE.roughjs.txt`
213
+ (rough.js), `LICENSE.simplex-noise.txt` (simplex-noise), `LICENSE.anidoodle.txt`
214
+ (AnidoodleDraw / RuvilMarks). Their pinned SHA256 digests are in
215
+ `northnoir_cli/runtime/libs/SHA256SUMS` and verified by `northnoir doctor`.
@@ -0,0 +1,192 @@
1
+ # northnoir — the local CLI for AI-drawn video
2
+
3
+ Make AI-drawn videos from your terminal, with **your own AI coding agent as the
4
+ model and your own machine as the compute**. The `northnoir` CLI checks and
5
+ renders a North Noir `scene.html` (the `window.SCENE` contract) entirely
6
+ locally — headless Chromium paints every frame, `ffmpeg` encodes H.264 — with
7
+ **no API keys, no North Noir account, and no cloud tokens**.
8
+
9
+ Your agent (Claude Code, OpenCode, Codex, Gemini CLI, Cursor) writes the
10
+ drawing code, runs the checks, *looks at its own frames*, fixes what is wrong,
11
+ and renders the final MP4. That loop is the product.
12
+
13
+ ## Install
14
+
15
+ > **Preview status:** the `northnoir` package is not on PyPI or npm yet —
16
+ > registry publication is pending maintainer registry access. The tested
17
+ > install today is from source (below). Do not trust any third-party package
18
+ > using this name until this page says otherwise.
19
+
20
+ From source (isolated, puts `northnoir` on your PATH):
21
+
22
+ ```sh
23
+ git clone https://github.com/syver777/NorthNoir.git
24
+ pipx install ./NorthNoir/packages/northnoir-cli
25
+ northnoir doctor --install # installs Chromium via Playwright, then verifies
26
+ northnoir doctor # Chromium, ffmpeg, pinned libraries (SHA256)
27
+ ```
28
+
29
+ Alternative: `pip install ./NorthNoir/packages/northnoir-cli` into a Python
30
+ virtual environment you manage yourself.
31
+
32
+ The npm package is **not published**. `bin/northnoir.js` in this repository is
33
+ a thin Node shim over the Python package: it needs Python 3.10+ with
34
+ `playwright`, `Pillow` and `numpy` already installed, so it is not a
35
+ stand-alone `npx` installer and is not advertised as one.
36
+
37
+ Your host coding agent and your machine do the work: the agent's own
38
+ usage/subscription terms apply to its model use, and rendering uses your local
39
+ CPU and disk. NorthNoir provides no model inference through this CLI and
40
+ charges nothing for local work.
41
+
42
+ Requirements: Python 3.10+, `ffmpeg` on PATH (`brew install ffmpeg` on macOS,
43
+ `sudo apt install ffmpeg` on Debian/Ubuntu). Chromium is installed for you by
44
+ `northnoir doctor --install` (Playwright). Docker is an optional transparent
45
+ fallback when a local `ruvil-js-renderer:local` image exists.
46
+
47
+ ## Quickstart
48
+
49
+ ```sh
50
+ northnoir init my-film --title "My Film" # scaffold scene.html
51
+ northnoir check my-film/scene.html --still # gate 1: frame 0 + report
52
+ northnoir check my-film/scene.html # gate 2: sampled frames + quality
53
+ northnoir render my-film/scene.html -o my-film/my-film.mp4
54
+ ```
55
+
56
+ Or hand the whole job to your agent: install the bundled skill (below), then
57
+ ask for a video. The skill teaches the agent the contract and the loop.
58
+
59
+ ## The 4-step agent loop
60
+
61
+ 1. **Author** — write `scene.html`: one self-contained page whose JavaScript
62
+ paints every frame of a 1920×1080 canvas. Frame 0 already shows the
63
+ finished scene.
64
+ 2. **Still check** — `northnoir check scene.html --still`, then *view*
65
+ `frame-0000.png`. Fix composition, scale and contrast before animating.
66
+ 3. **Motion check** — `northnoir check scene.html`, view `contact-sheet.png`,
67
+ read the readability/collision/composition flags, fix, re-check (up to 3
68
+ improvement rounds; keep the best version).
69
+ 4. **Render** — `northnoir render scene.html -o out.mp4`, view the poster,
70
+ verify with `ffprobe` (1920×1080, H.264, declared duration, stereo audio).
71
+
72
+ ## Commands
73
+
74
+ | Command | What it does |
75
+ |---|---|
76
+ | `northnoir doctor [--install] [--json]` | Verify Chromium/Playwright, `ffmpeg`/`ffprobe`, and the pinned scene libraries (SHA256). `--install` runs the guided setup (Playwright Chromium) first. |
77
+ | `northnoir init <dir> [--title "..."] [--duration 5] [--fps 24] [--style <id>] [--force] [--json]` | Scaffold `<dir>/scene.html` (working `window.SCENE` starter) + `<dir>/.northnoir/`. |
78
+ | `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. |
79
+ | `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. |
80
+ | `northnoir styles [--json]` | List the 31 AnidoodleDraw style ids and the RuvilMarks helpers. |
81
+ | `northnoir skill [install] [--install] [--json]` | Print the bundled `northnoir-draw` skill path; `install` copies it into the agent skill folders. |
82
+ | `northnoir --version` | Print the CLI version. |
83
+
84
+ Exit codes: `0` only when the report is `ok`, `1` on scene/encode failure,
85
+ `2` on usage errors.
86
+
87
+ `check` JSON: `ok`, `still_only`, `errors`, `quality` (readability / collision /
88
+ composition + `flags`), `cues`, `cue_errors`, `audio_ok`, `metrics`
89
+ (deterministic, canvas size, blank/frozen frames), `frame_paths`,
90
+ `contact_sheet_path`, `report_path`. Quality flags are review evidence — they
91
+ do not by themselves flip `ok`.
92
+
93
+ `render` JSON: `ok`, `output_mp4`, `poster_png`, `contact_sheet_png`,
94
+ `frames_rendered`, `duration_s`, `fps`, `has_audio`, `size_bytes`, `elapsed_s`.
95
+
96
+ ## The `window.SCENE` contract (cheat-sheet)
97
+
98
+ - Canvas is **1920×1080**. Declare `SCENE.fps`, `SCENE.frames` (or
99
+ `SCENE.duration`), `SCENE.width/height`, and `SCENE.canvas`.
100
+ - `SCENE.renderFrame(n)` is a **pure function of `n`**: no unseeded randomness,
101
+ no wall-clock reads for drawing decisions (the renderer re-seeds per frame,
102
+ so renders are deterministic and re-renders are byte-identical).
103
+ - `SCENE.init()` bakes textures once and registers subjects/blockers:
104
+ `window.__ruvilSubjects.register(id, role, boxFn)` /
105
+ `window.__ruvilBlockers.register(...)`, keeping the declarative
106
+ `SCENE.subjects` / `SCENE.blockers` mirrors in sync. Draw the main subject
107
+ inside `window.__ruvilSubjects.draw('hero', () => { ... })` so the checker
108
+ can measure it.
109
+ - `SCENE.cues`: `[{ t, prompt, seconds }]` — timed sound beats, validated
110
+ against the scene duration.
111
+ - `SCENE.audio(ctx, info)`: procedural audio scheduled on the
112
+ `OfflineAudioContext` you are given (48 kHz stereo out). Keep peaks ≤ 0.7,
113
+ seed every noise source, sync hits to your cues.
114
+ - Only five pinned library URLs may be loaded — every other network request is
115
+ blocked by the renderer:
116
+ `https://libs.ruvil/p5.min.js`, `rough.min.js`, `simplex-noise.js`,
117
+ `ruvil-marks.js`, `anidoodle-draw.js` (served offline from the package,
118
+ SHA256-verified by `doctor`).
119
+
120
+ ## Kit reference
121
+
122
+ - **RuvilMarks** (`ruvil-marks.js`): `paper(ctx, o)` (bake the paper ground
123
+ once in `init()`), `wash`, `stipple` (blue-noise dots; density = tone),
124
+ `hatch` (spacing = tone), `rng(seed)` (mulberry32), `hash(a, b)` (boil
125
+ outlines 1–3 px via `hash(boilIndex, strokeId)`).
126
+ - **AnidoodleDraw** (`anidoodle-draw.js`): `AnidoodleDraw.draw('<id>', ctx,
127
+ frame, W, H)` plates one of 31 finished style scenes under your scene;
128
+ `AnidoodleDraw.styles` lists the ids at runtime. Run `northnoir styles`.
129
+
130
+ ## The agent skill
131
+
132
+ ```sh
133
+ northnoir skill install
134
+ ```
135
+
136
+ copies the bundled `northnoir-draw` skill into `.claude/skills/`,
137
+ `.agents/skills/`, `~/.config/opencode/skills/` and `~/.claude/skills/`, so
138
+ Claude Code, OpenCode, Codex, Gemini CLI and Cursor agents learn the contract,
139
+ the 4-step loop, the quality-flag fix table and the craft rules before they
140
+ draw. `northnoir skill` prints the bundled path.
141
+
142
+ ## CLI vs Studio vs MCP
143
+
144
+ | | CLI (this package) | Web Studio | MCP server |
145
+ |---|---|---|---|
146
+ | Where it runs | Your machine | North Noir cloud | Your chat app |
147
+ | The model | Your AI coding agent | The model you pick in Studio | The model you pick |
148
+ | Cost | Free, local | North Noir tokens (free plan: your own API key) | North Noir tokens |
149
+ | Best for | One drawn scene, agent-driven | Timelines, voice/music, multi-section films at scale | Drawing from Claude/Cursor chats |
150
+
151
+ ## Troubleshooting
152
+
153
+ - **`doctor` says Chromium will not launch** — run `northnoir doctor
154
+ --install`. On Linux you may also need Playwright's system libraries:
155
+ `python3 -m playwright install-deps chromium` (asks for sudo; the CLI never
156
+ runs sudo itself).
157
+ - **`ffmpeg` missing** — install it with your OS package manager (above);
158
+ `doctor` prints the exact hint for your platform.
159
+ - **The Node shim cannot start Python / deps missing** — the npm package is
160
+ not published; `bin/northnoir.js` is a repo-only thin shim. Use the source
161
+ install above (recommended), or install the pinned deps into the Python the
162
+ shim finds and set `NORTHNOIR_PYTHON` to choose the interpreter.
163
+ - **A library SHA256 fails** — the vendored runtime is corrupted or hand-edited.
164
+ Reinstall the package; maintainers refresh it with `tools/sync_runtime.py`
165
+ (single source of truth: `cloudrun/ruvil-js-renderer/` in the repo).
166
+ - **Slow renders** — rendering is deterministic software rendering; heavy
167
+ full-canvas grain costs time per frame. Check `avg_ms_per_frame` in the
168
+ check report before rendering long scenes.
169
+
170
+ ## Development
171
+
172
+ ```sh
173
+ python3 tools/sync_runtime.py # refresh northnoir_cli/runtime from cloudrun/
174
+ python3 -m pytest tests/ -q # end-to-end suite (doctor/styles/init/check/render)
175
+ python3 northnoir_cli/cli.py doctor # or: ./bin/northnoir doctor
176
+ ```
177
+
178
+ Packaging choice: a **Python package** (the engine is Python + Playwright;
179
+ Chromium and ffmpeg are external tools `doctor` verifies). An unpublished
180
+ thin Node shim (`bin/northnoir.js`, `private: true` in `package.json`) is kept
181
+ for repo use only. A compiled single binary was rejected: it would have
182
+ to bundle a Python interpreter plus Playwright plus a browser download, which
183
+ is larger, more fragile across platforms, and harder to debug than `pipx`.
184
+
185
+ ## Licenses
186
+
187
+ The CLI code is proprietary North Noir software (see `pyproject.toml`). The
188
+ bundled scene libraries keep their own licenses, shipped beside them in
189
+ `northnoir_cli/runtime/libs/`: `LICENSE.p5.txt` (p5.js), `LICENSE.roughjs.txt`
190
+ (rough.js), `LICENSE.simplex-noise.txt` (simplex-noise), `LICENSE.anidoodle.txt`
191
+ (AnidoodleDraw / RuvilMarks). Their pinned SHA256 digests are in
192
+ `northnoir_cli/runtime/libs/SHA256SUMS` and verified by `northnoir doctor`.
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env python3
2
+ """Repo/npm shim: run the bundled northnoir_cli package without installing it."""
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
7
+ from northnoir_cli.cli import main
8
+
9
+ if __name__ == "__main__":
10
+ raise SystemExit(main())
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ // Thin npx wrapper: delegates to the bundled Python package.
3
+ // Requires Python 3.10+ with playwright, Pillow and numpy available
4
+ // (the pipx/pip install provides them; `northnoir doctor` diagnoses gaps).
5
+ const { spawnSync } = require('node:child_process');
6
+ const path = require('node:path');
7
+
8
+ const root = path.join(__dirname, '..');
9
+ const python = process.env.NORTHNOIR_PYTHON || (process.platform === 'win32' ? 'python' : 'python3');
10
+ const result = spawnSync(python, [path.join(root, 'bin', 'northnoir'), ...process.argv.slice(2)], {
11
+ stdio: 'inherit',
12
+ env: { ...process.env, PYTHONPATH: root + (process.env.PYTHONPATH ? path.delimiter + process.env.PYTHONPATH : '') },
13
+ });
14
+ if (result.error) {
15
+ console.error(`northnoir: could not start ${python} (${result.error.message})`);
16
+ console.error('Install the Python package instead: pipx install northnoir');
17
+ process.exit(1);
18
+ }
19
+ process.exit(result.status === null ? 1 : result.status);
@@ -0,0 +1,215 @@
1
+ Metadata-Version: 2.4
2
+ Name: northnoir
3
+ Version: 1.0.0
4
+ 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.
5
+ Author: North Noir
6
+ License: Proprietary
7
+ Project-URL: Homepage, https://northnoir.com/cli
8
+ Project-URL: Documentation, https://northnoir.com/cli
9
+ Project-URL: Source, https://github.com/syver777/NorthNoir/tree/main/packages/northnoir-cli
10
+ Keywords: ai-drawn-video,animation,cli,playwright,ffmpeg
11
+ Classifier: Environment :: Console
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Multimedia :: Video
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: playwright==1.63.0
17
+ Requires-Dist: Pillow==12.3.0
18
+ Requires-Dist: numpy==2.5.3; python_version >= "3.12"
19
+ Requires-Dist: numpy==2.2.6; python_version < "3.12"
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest>=8; extra == "dev"
22
+ Requires-Dist: build>=1.2; extra == "dev"
23
+
24
+ # northnoir — the local CLI for AI-drawn video
25
+
26
+ Make AI-drawn videos from your terminal, with **your own AI coding agent as the
27
+ model and your own machine as the compute**. The `northnoir` CLI checks and
28
+ renders a North Noir `scene.html` (the `window.SCENE` contract) entirely
29
+ locally — headless Chromium paints every frame, `ffmpeg` encodes H.264 — with
30
+ **no API keys, no North Noir account, and no cloud tokens**.
31
+
32
+ Your agent (Claude Code, OpenCode, Codex, Gemini CLI, Cursor) writes the
33
+ drawing code, runs the checks, *looks at its own frames*, fixes what is wrong,
34
+ and renders the final MP4. That loop is the product.
35
+
36
+ ## Install
37
+
38
+ > **Preview status:** the `northnoir` package is not on PyPI or npm yet —
39
+ > registry publication is pending maintainer registry access. The tested
40
+ > install today is from source (below). Do not trust any third-party package
41
+ > using this name until this page says otherwise.
42
+
43
+ From source (isolated, puts `northnoir` on your PATH):
44
+
45
+ ```sh
46
+ git clone https://github.com/syver777/NorthNoir.git
47
+ pipx install ./NorthNoir/packages/northnoir-cli
48
+ northnoir doctor --install # installs Chromium via Playwright, then verifies
49
+ northnoir doctor # Chromium, ffmpeg, pinned libraries (SHA256)
50
+ ```
51
+
52
+ Alternative: `pip install ./NorthNoir/packages/northnoir-cli` into a Python
53
+ virtual environment you manage yourself.
54
+
55
+ The npm package is **not published**. `bin/northnoir.js` in this repository is
56
+ a thin Node shim over the Python package: it needs Python 3.10+ with
57
+ `playwright`, `Pillow` and `numpy` already installed, so it is not a
58
+ stand-alone `npx` installer and is not advertised as one.
59
+
60
+ Your host coding agent and your machine do the work: the agent's own
61
+ usage/subscription terms apply to its model use, and rendering uses your local
62
+ CPU and disk. NorthNoir provides no model inference through this CLI and
63
+ charges nothing for local work.
64
+
65
+ Requirements: Python 3.10+, `ffmpeg` on PATH (`brew install ffmpeg` on macOS,
66
+ `sudo apt install ffmpeg` on Debian/Ubuntu). Chromium is installed for you by
67
+ `northnoir doctor --install` (Playwright). Docker is an optional transparent
68
+ fallback when a local `ruvil-js-renderer:local` image exists.
69
+
70
+ ## Quickstart
71
+
72
+ ```sh
73
+ northnoir init my-film --title "My Film" # scaffold scene.html
74
+ northnoir check my-film/scene.html --still # gate 1: frame 0 + report
75
+ northnoir check my-film/scene.html # gate 2: sampled frames + quality
76
+ northnoir render my-film/scene.html -o my-film/my-film.mp4
77
+ ```
78
+
79
+ Or hand the whole job to your agent: install the bundled skill (below), then
80
+ ask for a video. The skill teaches the agent the contract and the loop.
81
+
82
+ ## The 4-step agent loop
83
+
84
+ 1. **Author** — write `scene.html`: one self-contained page whose JavaScript
85
+ paints every frame of a 1920×1080 canvas. Frame 0 already shows the
86
+ finished scene.
87
+ 2. **Still check** — `northnoir check scene.html --still`, then *view*
88
+ `frame-0000.png`. Fix composition, scale and contrast before animating.
89
+ 3. **Motion check** — `northnoir check scene.html`, view `contact-sheet.png`,
90
+ read the readability/collision/composition flags, fix, re-check (up to 3
91
+ improvement rounds; keep the best version).
92
+ 4. **Render** — `northnoir render scene.html -o out.mp4`, view the poster,
93
+ verify with `ffprobe` (1920×1080, H.264, declared duration, stereo audio).
94
+
95
+ ## Commands
96
+
97
+ | Command | What it does |
98
+ |---|---|
99
+ | `northnoir doctor [--install] [--json]` | Verify Chromium/Playwright, `ffmpeg`/`ffprobe`, and the pinned scene libraries (SHA256). `--install` runs the guided setup (Playwright Chromium) first. |
100
+ | `northnoir init <dir> [--title "..."] [--duration 5] [--fps 24] [--style <id>] [--force] [--json]` | Scaffold `<dir>/scene.html` (working `window.SCENE` starter) + `<dir>/.northnoir/`. |
101
+ | `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. |
102
+ | `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. |
103
+ | `northnoir styles [--json]` | List the 31 AnidoodleDraw style ids and the RuvilMarks helpers. |
104
+ | `northnoir skill [install] [--install] [--json]` | Print the bundled `northnoir-draw` skill path; `install` copies it into the agent skill folders. |
105
+ | `northnoir --version` | Print the CLI version. |
106
+
107
+ Exit codes: `0` only when the report is `ok`, `1` on scene/encode failure,
108
+ `2` on usage errors.
109
+
110
+ `check` JSON: `ok`, `still_only`, `errors`, `quality` (readability / collision /
111
+ composition + `flags`), `cues`, `cue_errors`, `audio_ok`, `metrics`
112
+ (deterministic, canvas size, blank/frozen frames), `frame_paths`,
113
+ `contact_sheet_path`, `report_path`. Quality flags are review evidence — they
114
+ do not by themselves flip `ok`.
115
+
116
+ `render` JSON: `ok`, `output_mp4`, `poster_png`, `contact_sheet_png`,
117
+ `frames_rendered`, `duration_s`, `fps`, `has_audio`, `size_bytes`, `elapsed_s`.
118
+
119
+ ## The `window.SCENE` contract (cheat-sheet)
120
+
121
+ - Canvas is **1920×1080**. Declare `SCENE.fps`, `SCENE.frames` (or
122
+ `SCENE.duration`), `SCENE.width/height`, and `SCENE.canvas`.
123
+ - `SCENE.renderFrame(n)` is a **pure function of `n`**: no unseeded randomness,
124
+ no wall-clock reads for drawing decisions (the renderer re-seeds per frame,
125
+ so renders are deterministic and re-renders are byte-identical).
126
+ - `SCENE.init()` bakes textures once and registers subjects/blockers:
127
+ `window.__ruvilSubjects.register(id, role, boxFn)` /
128
+ `window.__ruvilBlockers.register(...)`, keeping the declarative
129
+ `SCENE.subjects` / `SCENE.blockers` mirrors in sync. Draw the main subject
130
+ inside `window.__ruvilSubjects.draw('hero', () => { ... })` so the checker
131
+ can measure it.
132
+ - `SCENE.cues`: `[{ t, prompt, seconds }]` — timed sound beats, validated
133
+ against the scene duration.
134
+ - `SCENE.audio(ctx, info)`: procedural audio scheduled on the
135
+ `OfflineAudioContext` you are given (48 kHz stereo out). Keep peaks ≤ 0.7,
136
+ seed every noise source, sync hits to your cues.
137
+ - Only five pinned library URLs may be loaded — every other network request is
138
+ blocked by the renderer:
139
+ `https://libs.ruvil/p5.min.js`, `rough.min.js`, `simplex-noise.js`,
140
+ `ruvil-marks.js`, `anidoodle-draw.js` (served offline from the package,
141
+ SHA256-verified by `doctor`).
142
+
143
+ ## Kit reference
144
+
145
+ - **RuvilMarks** (`ruvil-marks.js`): `paper(ctx, o)` (bake the paper ground
146
+ once in `init()`), `wash`, `stipple` (blue-noise dots; density = tone),
147
+ `hatch` (spacing = tone), `rng(seed)` (mulberry32), `hash(a, b)` (boil
148
+ outlines 1–3 px via `hash(boilIndex, strokeId)`).
149
+ - **AnidoodleDraw** (`anidoodle-draw.js`): `AnidoodleDraw.draw('<id>', ctx,
150
+ frame, W, H)` plates one of 31 finished style scenes under your scene;
151
+ `AnidoodleDraw.styles` lists the ids at runtime. Run `northnoir styles`.
152
+
153
+ ## The agent skill
154
+
155
+ ```sh
156
+ northnoir skill install
157
+ ```
158
+
159
+ copies the bundled `northnoir-draw` skill into `.claude/skills/`,
160
+ `.agents/skills/`, `~/.config/opencode/skills/` and `~/.claude/skills/`, so
161
+ Claude Code, OpenCode, Codex, Gemini CLI and Cursor agents learn the contract,
162
+ the 4-step loop, the quality-flag fix table and the craft rules before they
163
+ draw. `northnoir skill` prints the bundled path.
164
+
165
+ ## CLI vs Studio vs MCP
166
+
167
+ | | CLI (this package) | Web Studio | MCP server |
168
+ |---|---|---|---|
169
+ | Where it runs | Your machine | North Noir cloud | Your chat app |
170
+ | The model | Your AI coding agent | The model you pick in Studio | The model you pick |
171
+ | Cost | Free, local | North Noir tokens (free plan: your own API key) | North Noir tokens |
172
+ | Best for | One drawn scene, agent-driven | Timelines, voice/music, multi-section films at scale | Drawing from Claude/Cursor chats |
173
+
174
+ ## Troubleshooting
175
+
176
+ - **`doctor` says Chromium will not launch** — run `northnoir doctor
177
+ --install`. On Linux you may also need Playwright's system libraries:
178
+ `python3 -m playwright install-deps chromium` (asks for sudo; the CLI never
179
+ runs sudo itself).
180
+ - **`ffmpeg` missing** — install it with your OS package manager (above);
181
+ `doctor` prints the exact hint for your platform.
182
+ - **The Node shim cannot start Python / deps missing** — the npm package is
183
+ not published; `bin/northnoir.js` is a repo-only thin shim. Use the source
184
+ install above (recommended), or install the pinned deps into the Python the
185
+ shim finds and set `NORTHNOIR_PYTHON` to choose the interpreter.
186
+ - **A library SHA256 fails** — the vendored runtime is corrupted or hand-edited.
187
+ Reinstall the package; maintainers refresh it with `tools/sync_runtime.py`
188
+ (single source of truth: `cloudrun/ruvil-js-renderer/` in the repo).
189
+ - **Slow renders** — rendering is deterministic software rendering; heavy
190
+ full-canvas grain costs time per frame. Check `avg_ms_per_frame` in the
191
+ check report before rendering long scenes.
192
+
193
+ ## Development
194
+
195
+ ```sh
196
+ python3 tools/sync_runtime.py # refresh northnoir_cli/runtime from cloudrun/
197
+ python3 -m pytest tests/ -q # end-to-end suite (doctor/styles/init/check/render)
198
+ python3 northnoir_cli/cli.py doctor # or: ./bin/northnoir doctor
199
+ ```
200
+
201
+ Packaging choice: a **Python package** (the engine is Python + Playwright;
202
+ Chromium and ffmpeg are external tools `doctor` verifies). An unpublished
203
+ thin Node shim (`bin/northnoir.js`, `private: true` in `package.json`) is kept
204
+ for repo use only. A compiled single binary was rejected: it would have
205
+ to bundle a Python interpreter plus Playwright plus a browser download, which
206
+ is larger, more fragile across platforms, and harder to debug than `pipx`.
207
+
208
+ ## Licenses
209
+
210
+ The CLI code is proprietary North Noir software (see `pyproject.toml`). The
211
+ bundled scene libraries keep their own licenses, shipped beside them in
212
+ `northnoir_cli/runtime/libs/`: `LICENSE.p5.txt` (p5.js), `LICENSE.roughjs.txt`
213
+ (rough.js), `LICENSE.simplex-noise.txt` (simplex-noise), `LICENSE.anidoodle.txt`
214
+ (AnidoodleDraw / RuvilMarks). Their pinned SHA256 digests are in
215
+ `northnoir_cli/runtime/libs/SHA256SUMS` and verified by `northnoir doctor`.