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.
- northnoir-1.0.0/MANIFEST.in +8 -0
- northnoir-1.0.0/PKG-INFO +215 -0
- northnoir-1.0.0/README.md +192 -0
- northnoir-1.0.0/bin/northnoir +10 -0
- northnoir-1.0.0/bin/northnoir.js +19 -0
- northnoir-1.0.0/northnoir.egg-info/PKG-INFO +215 -0
- northnoir-1.0.0/northnoir.egg-info/SOURCES.txt +40 -0
- northnoir-1.0.0/northnoir.egg-info/dependency_links.txt +1 -0
- northnoir-1.0.0/northnoir.egg-info/entry_points.txt +2 -0
- northnoir-1.0.0/northnoir.egg-info/requires.txt +12 -0
- northnoir-1.0.0/northnoir.egg-info/top_level.txt +1 -0
- northnoir-1.0.0/northnoir_cli/__init__.py +3 -0
- northnoir-1.0.0/northnoir_cli/__main__.py +4 -0
- northnoir-1.0.0/northnoir_cli/cli.py +962 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/__init__.py +0 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/__main__.py +8 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/audio.py +95 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/check_script.js +840 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/config.py +101 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/encode.py +96 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/imaging.py +186 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/init_script.js +298 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/quality.py +218 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/quality_script.js +157 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/renderer.py +556 -0
- northnoir-1.0.0/northnoir_cli/runtime/app/resources.py +48 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/LICENSE.anidoodle.txt +204 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/LICENSE.p5.txt +458 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/LICENSE.roughjs.txt +21 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/LICENSE.simplex-noise.txt +43 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/SHA256SUMS +7 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/anidoodle-draw.js +1 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/anidoodle-kit.js +4 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/p5.min.js +2 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/rough.min.js +1 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/ruvil-marks.js +444 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/ruvil-sim.js +165 -0
- northnoir-1.0.0/northnoir_cli/runtime/libs/simplex-noise.js +473 -0
- northnoir-1.0.0/northnoir_cli/skill/SKILL.md +376 -0
- northnoir-1.0.0/package.json +23 -0
- northnoir-1.0.0/pyproject.toml +54 -0
- northnoir-1.0.0/setup.cfg +4 -0
northnoir-1.0.0/PKG-INFO
ADDED
|
@@ -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`.
|