rig-parts 1.83.1 → 1.84.0

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.
package/README.md CHANGED
@@ -184,26 +184,7 @@ pads a non-square upload before resizing; the centre-crop reported in
184
184
  `st_input_full.png` supplies the explicit white padding that rig-parts maps back
185
185
  to the original painting. This is a source inspection, not a new demo run.
186
186
 
187
- **The head run is needed on every route that was read.** See-through's model
188
- already separates the head in a second stage of its own: it crops the head the
189
- first stage found, runs the face tags on that crop at the same `resolution`, and
190
- pastes the result back **resized to the full image's scale**. So the face comes
191
- back at the full run's pixel density whichever route ran it, and the separate
192
- head run on `st_input_head.png` is what gives the eyes more pixels
193
- (read on 2026-09-28 at see-through `a25a549` and wrapper 0.5.0 `98d754b`):
194
-
195
- - *Hugging Face Space* — the same two-stage code, with `resolution` capped at
196
- 1280 (768 by default): the head run is still needed.
197
- - *ModelScope demo* — its code was not read, so what the head run adds on that
198
- route has not been measured.
199
- - *Upstream CLI* — the `.psd` frame is the `resolution`-sided square the first
200
- stage ran on (1280 by default), and the head stage is pasted into it at that
201
- scale: the head run is still needed.
202
- - *ComfyUI wrapper* — `SeeThrough_GenerateLayers` runs both stages with no input
203
- to change the second, at most `resolution` 2048, which on the examples' 2432 px
204
- square is 1.19 source px per layer px against 0.77 and 0.47 for their head
205
- crops; at the 1024 the examples ran, the full run's right eye white is 22×13 px
206
- and the head run's 60×38: the head run is still needed.
187
+ The [head-run source reading](docs/AUTHORING.md#see-through-head-run-source-reading) explains why a separate head crop is needed.
207
188
 
208
189
  **See-through is required; ComfyUI is not.** The wrapper is one route among
209
190
  four, and `rig-parts comfy` is only a convenience for that route: every
@@ -329,86 +310,29 @@ agent skill.
329
310
 
330
311
  ## Commands
331
312
 
313
+ Command details and config saving are in the [command reference](docs/AUTHORING.md#command-reference) and [stable interface](docs/STABILITY.md#commands-and-flags).
314
+
332
315
  | command | does |
333
316
  | --- | --- |
334
- | `inputs --source <png> --config <json> --out <dir>` | the two images See-through is fed: the painting on a white square, and the head box's crop once the config has one |
335
- | `comfy paint --config --out [--host]` | optional: generate the painting on a ComfyUI box from the config's `generation` block |
336
- | `comfy seethrough --image --out [--host]` | optional: run the ComfyUI See-through wrapper on one image and write the form `layers` reads |
337
- | `layers <dir \| layers.json \| file.psd>` | keep the existing columns (`opaque_px` still means alpha >8) and append source-alpha boxes `drawn(a>8)` / `opaque(a>=250)` with exclusive right/bottom; name absent boxes, report the existing body-group union height at **CORE_ALPHA (>=250)** in **input-canvas px**, and show its >8 union separately; no anatomical height, ownership/erosion or painting registration is inferred ([units and rig-scale guidance](docs/AUTHORING.md#4-the-command-order)) |
338
- | `sheet --source <png> --layers <path>… --out <png>` | a labelled contact sheet of the painting and every layer or part |
339
- | `assemble --propose-plan … [--write-config <config>]` | propose `assemble.plan` and `extend_below_crop` from the two runs, leaving out an implausible layer with a note naming the rule, naming in a note any full-run body no planned part covers, and naming every layer no row takes with why (empty, taken from the other run only, a plausibility rule; `nose`, never planned, with the row that lets `propose` read the head's pitch) |
340
- | `assemble --source --full --head --config --out [--seam] [--project]` | merge the two runs into rig-space parts, `parts.json`, the recomposite and its error map, and list the uncovered holes |
341
- | `propose --head-box --full <run> --canvas WxH [--no-back-hair] [--write-config <config>]` | propose `seethrough.head_box` from the full run, held inside the painting; `--no-back-hair` leaves the back-hair layer out of that proposal |
342
- | `propose --parts --source --out [--compare <config>] [--write-config <config> [--only-missing]]` | propose bones, meshes, regions and an idle; draw the overlay; print, per bone, which check read it or that none did and why (its role, its kind of segment), and write `basis.json` beside the proposal — what each bone rests on (a joint, a part's mask, a ratio, other bones) and, with `--compare`, whether the config's bone differs |
343
- | `propose … --keypoints <file> [--person <id>]` | read a posed figure's joints from one explicit file (space, image size, people, each joint observed, occluded or missing, its source): a joint with a position places the neck, hip, chest or a sleeve chain as given, a note says how every joint was used or which rule stood in, and LINT reads the torso and sleeves along the joints instead of by screen y ([AUTHORING §3](docs/AUTHORING.md)) |
344
- | `propose … --full <run> --head <run> --write-config <config>` | [draft an independent neck](docs/AUTHORING.md#a-neck-that-moves-on-its-own) in an existing sampled body turn and reassemble its full-run source under `<out>/rig` |
345
- | `propose … --grid-rule figure\|part` | how each drafted lattice's spacing is chosen: `figure` (the default) one spacing for the figure, round(H / 37) rig px, a part already coarser keeping its own, with a note on its calibration and cost; `part` the reference's rule, a tenth of the part's short side (the oracle examples are proposed under it) |
346
- | `propose --parts --source --out --from-config <config> [--keypoints <file> [--person <id>]]` | draw and LINT the config's current bones (by the joints too, given `--keypoints`); proposes nothing, so takes only these flags (not `--full`, `--head`, `--cloth`, `--write-config`, `--wrist-snap`, `--grid-rule`, `--only-missing` or `--compare`) |
347
- | `compare --left <file> --right <file> [--map <bonemap.json>]` | compare two skeletons — a config, a proposal or a `rig.json` — bone by bone: origin, parent, tip, length and direction per pair, the bones neither side pairs, the required ones missing, and each side's roles read off the spec; no frame is guessed, and nothing pairs by resemblance (`propose --compare` reads origins only) |
348
- | `rig --config --parts --out [--idle-keys ctl\|direct]` | author `rig.json` + `motion.json`, written only after rig-c's gate is green; each mesh is in the mode its config entry names — `grid` (the lattice, what `propose` writes), `contour` (the traced outline with declared interior points) or `auto` (the contour mesh at alpha 1 and above, reduced and locally refined by rig-c's `reduceMesh` under the author's declared bounds, written only when its motion against the unreduced source on the idle passes the author's `motion` bounds through rig-c's `compareMeshesInMotion`; [AUTHORING §3](docs/AUTHORING.md)); every chain link is turned along its chain and carries its `length`, so a physics constraint added later has a lever, with every offset under it in the turned frame so nothing moves; `--idle-keys` says whether the idle's keys on mesh-driving bones go through `<bone>_ctl` parents (default) or stay on the bones with `invariants.idleDrivesMeshes` declared; the config's `constraints` go to rigc as written, and a two-bone ik over keyed links needs `--idle-keys direct` (on `rig` or `build`) |
349
- | `check --rig --out [--parts] [--source] [--requirements]` | build packed, gated under `rig-play`, render the idle, measure seam, loop and the six judgement lines (mesh texture stretch among them, from the idle's `render --geometry`), and report the recomposite's holes from `parts.json`; on a rig spec with no `parts.json` or no `idle` (a merged rig, issue #77) the gate still runs and every line that needs the missing input says SKIP by name; `--source <painting.png>` adds `SETUP_POSE_VS_SOURCE`, the setup pose against the painting by assemble's recomposite figures; `--requirements <scene.json>` measures what a scene declares of the motion — a contact, a follow fraction, an aim, a joint range, a mesh's stretch, the seam between two parts over the motion — each against the author's own bar, from rig-c's posed frames, one line each, PASS, FAIL or NOT MEASURABLE (AUTHORING §7, *Declared requirements*) |
350
- | `loop --frames <dir> --out <file.gif \| file.png> [--palette]` | encode a rendered idle as a looping GIF, lossless APNG, or indexed APNG (`--palette`) |
351
- | `build --config --source --full --head --out [--seam] [--project] [--loop] [--lead-in <periods>] [--requirements] [--seam-pairs] [--keep-stills] [--idle-keys ctl\|direct]` | assemble, rig and check in one process, stopping at the first refusal; `--requirements`, `--seam-pairs` and `--keep-stills` are forwarded to check, `--idle-keys` to rig; `--lead-in` (with `--loop`) encodes the loop from the last of n + 1 idle periods played back to back, for a rig whose physics does not end where the render starts it |
352
- | `compose --scene <scene.json> --out [--requirements] [--accept]` | bind several characters' green builds into one rig (or, under `--accept`, builds failing only the bars named — for looking, not shipping): every name prefixed `<id>:` under one shared root, each character's offset added at its first-level bones, an optional background plate (its provenance recorded, judged by nothing) drawn first, and the draw order between the characters' slots as the scene file declares it — nothing inferred, nothing scaled; gated through rig-c as `rig` is, then checked ([AUTHORING §7](docs/AUTHORING.md), *Composing several characters*) |
353
- | `mesh-draft --config <json> --parts <dir> --out <dir>` | draft contour meshes for configured lattices, keeping each only where it holds against its lattice through rig-c; write the revised config and measurement report |
354
- | `mesh-stats --config <json> --parts <dir>` | print each configured mesh's vertex and triangle counts and their total through the rig stage's construction; write nothing |
355
- | `painting --keypoints <json> [--person <id>] <png>` | before See-through, read the painting against its declared joints and refuse named background, joint or limb-gap problems; write nothing |
356
- | `remesh --rig <dir> --config <json> --parts <dir> --part <name> --out <dir>` | with exactly one of `--mesh <entry.json>` or `--delta <mesh-edit.json>`, re-fit one part of a gated rig into a fresh revision, preserving the input |
357
- | `retune --rig <dir> --config <json> --parts <dir> --out <dir>` | splice the config's constraints and idle onto a gated rig in a fresh revision, carrying its attachments over as bytes |
358
- | `guide <RULE \| §<n> \| §<n>.<m> \| §<n>.<m>.<k>>` | print the one row of [docs/AUTHORING.md](docs/AUTHORING.md) that names a rule (a refusal and the bar it enforces, `CHECK_<LINE>` and `<LINE>`, print together), or one section, `###` subsection or `####` under it, read from the installed file when it runs |
359
-
360
- `rig-parts --help` has every flag. Exit codes: 0 done, 1 input refused (every
361
- reason is a FAIL line), 2 a usage error or a command this version does not implement.
362
- Every FAIL line ends with `(see rig-parts guide <RULE>)`, the command that prints the
363
- guide's row for that rule, and each row is anchored on the web as
364
- `docs/AUTHORING.md#<RULE>`.
365
-
366
- What 1.0.0 holds stable — these commands and their flags, the config
367
- fields, the files a build writes and their spec ids, the environment, and what this
368
- package relies on in rig-c — and what is not, is [docs/STABILITY.md](docs/STABILITY.md).
369
- Coming from 0.16.0: [docs/MIGRATION.md](docs/MIGRATION.md).
370
-
371
- `--write-config <config.json>` saves the proposals above into an existing
372
- regular config file: `seethrough.head_box`, `assemble.plan` plus
373
- `assemble.extend_below_crop`, or the present config sections of an ordinary
374
- proposal. The [neck draft](docs/AUTHORING.md#a-neck-that-moves-on-its-own)
375
- (`propose … --full --head --write-config`) is another writer: for an existing
376
- `turn.body` config with one neck plan row, it selects the full-run neck, drafts a
377
- rigid unit and its depth, and reassembles parts under `<out>/rig`.
378
- For `assemble --propose-plan`, the destination must name `--config`
379
- itself; a different destination is a usage error. Other fields and absent optional
380
- sections remain; proposal notes are not copied. Changed whole values are spliced
381
- into the original text, preserving untouched bytes. Stage loaders validate the candidate, including `proposed_rig_scale`,
382
- before atomic replacement. Relative paths keep the config's directory as their
383
- base. Changes are listed on stderr; the head-box and plan JSON on stdout remain.
384
- An identical update leaves bytes and mtime untouched. Without the flag no config
385
- is changed. This commits the config file, not a transaction across the proposal
386
- artifacts.
387
-
388
- With `--cloth <config.json>`, the flag requires a **new** destination and applies
389
- the recipe's entry ownership: recipe-owned entries are spliced into the cloth
390
- config while hand entries and unrelated text survive; conflicts are refused.
391
- The destination must also be separate from all four artifacts under `--out`:
392
- `proposal.json`, `basis.json`, `render/landmarks.png`, `render/landmarks_head.png`.
393
- Aliases, including directory symlinks and hardlinks, count as collisions too.
394
- Fresh output is published without overwriting a file created while the command
395
- runs. Its already-checked splice text may be a partial config; it is not passed
396
- through the full-config loader. If removing the staged temporary fails after
397
- publication, the error may accompany an already-published complete config.
398
- `--from <previous.json>` retains the previous-recipe comparison.
399
- With `--only-missing` (issue #671), an ordinary proposal's `--write-config` adds
400
- only `meshes.<part>` or `regions.<part>` for each proposed part the config
401
- attaches by neither, entry by entry, and, for a part the 1.37.0 arm split makes
402
- (`full:drape-<s>`, `full:hand-<s>`) that `assemble.plan` does not name, its plan
403
- row beside the arm's row; every existing row and entry and every other byte
404
- stays as read, and nothing else of the proposal is written. The candidate passes
405
- the full loader first, so an entry on a bone the config does not declare is
406
- refused naming the part and the bone; nothing missing leaves bytes and mtime
407
- untouched. It is the upgrade path for a config proposed before the 1.37.0 arm
408
- split ([MIGRATION](docs/MIGRATION.md#after-1370-merged-arm-layers-are-split-issue-490)),
409
- and a usage error with `--head-box`, `--cloth` or `--from-config`.
410
- `--from-config` proposes nothing and cannot be combined with `--write-config`.
411
- [AUTHORING §4](docs/AUTHORING.md#4-the-command-order) describes all four modes.
317
+ | `inputs` | [Prepare the two See-through input images](docs/AUTHORING.md#command-reference) |
318
+ | `comfy` | [Drive an optional ComfyUI painting or layer job](docs/AUTHORING.md#command-reference) |
319
+ | `layers` | [Inspect wrapper layers or a PSD](docs/AUTHORING.md#command-reference) |
320
+ | `sheet` | [Make a contact sheet](docs/AUTHORING.md#command-reference) |
321
+ | `assemble` | [Merge layers into measured parts](docs/AUTHORING.md#command-reference) |
322
+ | `propose` | [Draft or inspect a character config](docs/AUTHORING.md#command-reference) |
323
+ | `compare` | [Compare two skeletons by name](docs/AUTHORING.md#command-reference) |
324
+ | `rig` | [Author gated rig and motion specs](docs/AUTHORING.md#command-reference) |
325
+ | `check` | [Build, render and measure a rig](docs/AUTHORING.md#command-reference) |
326
+ | `loop` | [Encode rendered frames as GIF or APNG](docs/AUTHORING.md#command-reference) |
327
+ | `build` | [Assemble, rig and check in one process](docs/AUTHORING.md#command-reference) |
328
+ | `compose` | [Combine character builds into a scene](docs/AUTHORING.md#command-reference) |
329
+ | `mesh-draft` | [Draft and compare contour meshes](docs/AUTHORING.md#command-reference) |
330
+ | `mesh-stats` | [Count mesh vertices and triangles](docs/AUTHORING.md#command-reference) |
331
+ | `painting` | [Check a painting against declared joints](docs/AUTHORING.md#command-reference) |
332
+ | `remesh` | [Revise one mesh in a gated rig](docs/AUTHORING.md#command-reference) |
333
+ | `retune` | [Revise constraints and idle in a gated rig](docs/AUTHORING.md#command-reference) |
334
+ | `guide` | [Read the installed authoring reference](docs/AUTHORING.md#command-reference) |
335
+
412
336
 
413
337
  ## What it does not do
414
338
 
@@ -539,15 +463,7 @@ selftest and CI do; `check.json`'s `rigc_entry` records which one gated a build.
539
463
 
540
464
  ## Licence posture
541
465
 
542
- rig-parts is MIT. It writes rig-c's input, and rig-c writes Spine skeleton data. If a
543
- product integrates a Spine Runtime to play that data, the integration is under Esoteric
544
- Software's Spine Runtimes License: permitted under Section 2 of the Spine Editor License
545
- Agreement, or otherwise on the condition that each user of the product obtains their own
546
- Spine Editor license. What those terms turn on is the integration, as rig-c's
547
- [NOTICE.md](https://github.com/rig-c/core/blob/main/NOTICE.md) states it, not the data as
548
- a file. Neither package installs `spine-core`; this repository uses it in development,
549
- for the round trip in its selftest and CI. [NOTICE.md](NOTICE.md) records that chain and every other
550
- third-party term this package touches, See-through's included.
466
+ MIT; see [NOTICE.md](NOTICE.md) for third-party terms and the Spine runtime licence posture.
551
467
 
552
468
  ## Development
553
469
 
@@ -579,43 +495,14 @@ records the generated default-cap case and its preservation controls.
579
495
  practice, [RELEASING.md](RELEASING.md) the cut, [docs/STABILITY.md](docs/STABILITY.md)
580
496
  the interface it holds.
581
497
 
582
- ## Licence
583
-
584
- MIT — see [LICENSE](LICENSE). Third-party terms: [NOTICE.md](NOTICE.md).
498
+ ## Depth-driven rigging
585
499
 
500
+ See the [depth-driven rigging reference](docs/AUTHORING.md#depth-driven-rigging) for sampled head and body turns and unit-depth precedence.
586
501
 
587
502
  ### Per-layer depth input
588
503
 
589
- `config.depth` explicitly enables scalar input. Without it, `depth_filename`
590
- is a legacy hint: no depth-file I/O, validation, fetch, reference or output is
591
- activated, even when files or in-memory sheets exist. Active See-through sheets
592
- are read as opaque grayscale source data. Declare positive finite `depth.zScale`;
593
- eight bits do not supply world units. See-through far-high encoding is explicitly `near: "black"`. User
594
- per-layer/run-canvas fallbacks declare image, near and zScale themselves; a
595
- missing declared file is an error, not a fallback. The ordering median remains
596
- separate, and its agreement reading cannot certify an image's polarity.
597
-
598
- Assembly emits registered part sheets and references; rig emits PAD4 sheets and
599
- `depth_sheets.json`. Since 1.68.0 (#777), [config.turn.roles](docs/AUTHORING.md#3-configjson-field-by-field)
600
- uses depth sheets for 2.5D head turns with grid or authored weighted surfaces and `yaw_dial`/`pitch_dial`
601
- controls; see [`CONFIG_TURN_ROLE_UNKNOWN`](docs/AUTHORING.md#CONFIG_TURN_ROLE_UNKNOWN)
602
- and [`CONFIG_TURN_SURFACE_REQUIRED`](docs/AUTHORING.md#CONFIG_TURN_SURFACE_REQUIRED).
603
- `turn.body.roles` adds independent body yaw. A weighted mesh declared as
604
- `"surface"` in either group and blending head and torso bones receives both
605
- fields in proportion to its skin weights. Inside the existing setup alpha
606
- overlap with a single-group neighbour, a blended attachment's vertex takes
607
- that neighbour's existing emitted triangle field at its setup position (#804), without changing skin weights,
608
- setup or idle. A `motion.blink.still` unit neighbour supplies both emitted
609
- pieces, each on its own bone and resolved depth; transparent padding does not
610
- let either piece lend its field to the other's art (#807). Missing emitted
611
- split support is refused by name. Conflicting neighbour groups are refused by name. Each sibling island takes only its
612
- own group; parts without a blended attachment keep their existing role behavior
613
- and output bytes. Unlisted meshes do not consume turn depth sheets. See the
614
- [blended surface contract](docs/AUTHORING.md#per-layer-depth-sheets-773).
615
- This copies the field at vertices; different triangle partitions can still
616
- differ between vertices. The [corrected #804 acceptance](https://github.com/rig-c/parts/issues/804#issuecomment-6478778123)
617
- checks vertex correspondence and reports those residuals per fixture; the
618
- contract records the measured grid residual and preserves its seam readings.
619
- No-image builds keep the legacy output bytes. `comfy seethrough --config <file> --depth-run <full|head>`
620
- uses the same opt-in; its default captures art only. Standalone authored part
621
- references remain active declarations. See [the input contract and refusals](docs/AUTHORING.md#per-layer-depth-sheets-773).
504
+ See the [per-layer depth input contract](docs/AUTHORING.md#per-layer-depth-input) for opt-in sheets, calibration and their consumers.
505
+
506
+ ## Licence
507
+
508
+ MIT — see [LICENSE](LICENSE). Third-party terms: [NOTICE.md](NOTICE.md).
package/docs/AUTHORING.md CHANGED
@@ -70,6 +70,29 @@ model stack. The wrapper README and the adapter graph use different node names
70
70
  and depth-model identifiers; [the adapter notes](../README.md#the-optional-comfyui-adapter)
71
71
  name the graph actually sent.
72
72
 
73
+ ### See-through head-run source reading
74
+
75
+ **The head run is needed on every route that was read.** See-through's model
76
+ already separates the head in a second stage of its own: it crops the head the
77
+ first stage found, runs the face tags on that crop at the same `resolution`, and
78
+ pastes the result back **resized to the full image's scale**. So the face comes
79
+ back at the full run's pixel density whichever route ran it, and the separate
80
+ head run on `st_input_head.png` is what gives the eyes more pixels
81
+ (read on 2026-09-28 at see-through `a25a549` and wrapper 0.5.0 `98d754b`):
82
+
83
+ - *Hugging Face Space* — the same two-stage code, with `resolution` capped at
84
+ 1280 (768 by default): the head run is still needed.
85
+ - *ModelScope demo* — its code was not read, so what the head run adds on that
86
+ route has not been measured.
87
+ - *Upstream CLI* — the `.psd` frame is the `resolution`-sided square the first
88
+ stage ran on (1280 by default), and the head stage is pasted into it at that
89
+ scale: the head run is still needed.
90
+ - *ComfyUI wrapper* — `SeeThrough_GenerateLayers` runs both stages with no input
91
+ to change the second, at most `resolution` 2048, which on the examples' 2432 px
92
+ square is 1.19 source px per layer px against 0.77 and 0.47 for their head
93
+ crops; at the 1024 the examples ran, the full run's right eye white is 22×13 px
94
+ and the head run's 60×38: the head run is still needed.
95
+
73
96
  ## 2. The folder
74
97
 
75
98
  Nothing in rig-parts requires a layout; every command takes paths. The one the
@@ -3608,6 +3631,90 @@ artifacts under `--out`: `proposal.json`, `basis.json`, `render/landmarks.png` a
3608
3631
  existing hardlinks are refused before artifact output; the ordinary mode names
3609
3632
  `CONFIG_WRITE_TARGET`, and the cloth mode `PROPOSE_WRITE_CONFIG_FRESH`.
3610
3633
 
3634
+ ### Command reference
3635
+
3636
+ | command | does |
3637
+ | --- | --- |
3638
+ | `inputs --source <png> --config <json> --out <dir>` | the two images See-through is fed: the painting on a white square, and the head box's crop once the config has one |
3639
+ | `comfy paint --config --out [--host]` | optional: generate the painting on a ComfyUI box from the config's `generation` block |
3640
+ | `comfy seethrough --image --out [--host]` | optional: run the ComfyUI See-through wrapper on one image and write the form `layers` reads |
3641
+ | `layers <dir \| layers.json \| file.psd>` | keep the existing columns (`opaque_px` still means alpha >8) and append source-alpha boxes `drawn(a>8)` / `opaque(a>=250)` with exclusive right/bottom; name absent boxes, report the existing body-group union height at **CORE_ALPHA (>=250)** in **input-canvas px**, and show its >8 union separately; no anatomical height, ownership/erosion or painting registration is inferred ([units and rig-scale guidance](AUTHORING.md#4-the-command-order)) |
3642
+ | `sheet --source <png> --layers <path>… --out <png>` | a labelled contact sheet of the painting and every layer or part |
3643
+ | `assemble --propose-plan … [--write-config <config>]` | propose `assemble.plan` and `extend_below_crop` from the two runs, leaving out an implausible layer with a note naming the rule, naming in a note any full-run body no planned part covers, and naming every layer no row takes with why (empty, taken from the other run only, a plausibility rule; `nose`, never planned, with the row that lets `propose` read the head's pitch) |
3644
+ | `assemble --source --full --head --config --out [--seam] [--project]` | merge the two runs into rig-space parts, `parts.json`, the recomposite and its error map, and list the uncovered holes |
3645
+ | `propose --head-box --full <run> --canvas WxH [--no-back-hair] [--write-config <config>]` | propose `seethrough.head_box` from the full run, held inside the painting; `--no-back-hair` leaves the back-hair layer out of that proposal |
3646
+ | `propose --parts --source --out [--compare <config>] [--write-config <config> [--only-missing]]` | propose bones, meshes, regions and an idle; draw the overlay; print, per bone, which check read it or that none did and why (its role, its kind of segment), and write `basis.json` beside the proposal — what each bone rests on (a joint, a part's mask, a ratio, other bones) and, with `--compare`, whether the config's bone differs |
3647
+ | `propose … --keypoints <file> [--person <id>]` | read a posed figure's joints from one explicit file (space, image size, people, each joint observed, occluded or missing, its source): a joint with a position places the neck, hip, chest or a sleeve chain as given, a note says how every joint was used or which rule stood in, and LINT reads the torso and sleeves along the joints instead of by screen y ([AUTHORING §3](AUTHORING.md)) |
3648
+ | `propose … --full <run> --head <run> --write-config <config>` | [draft an independent neck](AUTHORING.md#a-neck-that-moves-on-its-own) in an existing sampled body turn and reassemble its full-run source under `<out>/rig` |
3649
+ | `propose … --grid-rule figure\|part` | how each drafted lattice's spacing is chosen: `figure` (the default) one spacing for the figure, round(H / 37) rig px, a part already coarser keeping its own, with a note on its calibration and cost; `part` the reference's rule, a tenth of the part's short side (the oracle examples are proposed under it) |
3650
+ | `propose --parts --source --out --from-config <config> [--keypoints <file> [--person <id>]]` | draw and LINT the config's current bones (by the joints too, given `--keypoints`); proposes nothing, so takes only these flags (not `--full`, `--head`, `--cloth`, `--write-config`, `--wrist-snap`, `--grid-rule`, `--only-missing` or `--compare`) |
3651
+ | `compare --left <file> --right <file> [--map <bonemap.json>]` | compare two skeletons — a config, a proposal or a `rig.json` — bone by bone: origin, parent, tip, length and direction per pair, the bones neither side pairs, the required ones missing, and each side's roles read off the spec; no frame is guessed, and nothing pairs by resemblance (`propose --compare` reads origins only) |
3652
+ | `rig --config --parts --out [--idle-keys ctl\|direct]` | author `rig.json` + `motion.json`, written only after rig-c's gate is green; each mesh is in the mode its config entry names — `grid` (the lattice, what `propose` writes), `contour` (the traced outline with declared interior points) or `auto` (the contour mesh at alpha 1 and above, reduced and locally refined by rig-c's `reduceMesh` under the author's declared bounds, written only when its motion against the unreduced source on the idle passes the author's `motion` bounds through rig-c's `compareMeshesInMotion`; [AUTHORING §3](AUTHORING.md)); every chain link is turned along its chain and carries its `length`, so a physics constraint added later has a lever, with every offset under it in the turned frame so nothing moves; `--idle-keys` says whether the idle's keys on mesh-driving bones go through `<bone>_ctl` parents (default) or stay on the bones with `invariants.idleDrivesMeshes` declared; the config's `constraints` go to rigc as written, and a two-bone ik over keyed links needs `--idle-keys direct` (on `rig` or `build`) |
3653
+ | `check --rig --out [--parts] [--source] [--requirements]` | build packed, gated under `rig-play`, render the idle, measure seam, loop and the six judgement lines (mesh texture stretch among them, from the idle's `render --geometry`), and report the recomposite's holes from `parts.json`; on a rig spec with no `parts.json` or no `idle` (a merged rig, issue #77) the gate still runs and every line that needs the missing input says SKIP by name; `--source <painting.png>` adds `SETUP_POSE_VS_SOURCE`, the setup pose against the painting by assemble's recomposite figures; `--requirements <scene.json>` measures what a scene declares of the motion — a contact, a follow fraction, an aim, a joint range, a mesh's stretch, the seam between two parts over the motion — each against the author's own bar, from rig-c's posed frames, one line each, PASS, FAIL or NOT MEASURABLE (AUTHORING §7, *Declared requirements*) |
3654
+ | `loop --frames <dir> --out <file.gif \| file.png> [--palette]` | encode a rendered idle as a looping GIF, lossless APNG, or indexed APNG (`--palette`) |
3655
+ | `build --config --source --full --head --out [--seam] [--project] [--loop] [--lead-in <periods>] [--requirements] [--seam-pairs] [--keep-stills] [--idle-keys ctl\|direct]` | assemble, rig and check in one process, stopping at the first refusal; `--requirements`, `--seam-pairs` and `--keep-stills` are forwarded to check, `--idle-keys` to rig; `--lead-in` (with `--loop`) encodes the loop from the last of n + 1 idle periods played back to back, for a rig whose physics does not end where the render starts it |
3656
+ | `compose --scene <scene.json> --out [--requirements] [--accept]` | bind several characters' green builds into one rig (or, under `--accept`, builds failing only the bars named — for looking, not shipping): every name prefixed `<id>:` under one shared root, each character's offset added at its first-level bones, an optional background plate (its provenance recorded, judged by nothing) drawn first, and the draw order between the characters' slots as the scene file declares it — nothing inferred, nothing scaled; gated through rig-c as `rig` is, then checked ([AUTHORING §7](AUTHORING.md), *Composing several characters*) |
3657
+ | `mesh-draft --config <json> --parts <dir> --out <dir>` | draft contour meshes for configured lattices, keeping each only where it holds against its lattice through rig-c; write the revised config and measurement report |
3658
+ | `mesh-stats --config <json> --parts <dir>` | print each configured mesh's vertex and triangle counts and their total through the rig stage's construction; write nothing |
3659
+ | `painting --keypoints <json> [--person <id>] <png>` | before See-through, read the painting against its declared joints and refuse named background, joint or limb-gap problems; write nothing |
3660
+ | `remesh --rig <dir> --config <json> --parts <dir> --part <name> --out <dir>` | with exactly one of `--mesh <entry.json>` or `--delta <mesh-edit.json>`, re-fit one part of a gated rig into a fresh revision, preserving the input |
3661
+ | `retune --rig <dir> --config <json> --parts <dir> --out <dir>` | splice the config's constraints and idle onto a gated rig in a fresh revision, carrying its attachments over as bytes |
3662
+ | `guide <RULE \| §<n> \| §<n>.<m> \| §<n>.<m>.<k>>` | print the one row of [docs/AUTHORING.md](AUTHORING.md) that names a rule (a refusal and the bar it enforces, `CHECK_<LINE>` and `<LINE>`, print together), or one section, `###` subsection or `####` under it, read from the installed file when it runs |
3663
+
3664
+ `rig-parts --help` has every flag. Exit codes: 0 done, 1 input refused (every
3665
+ reason is a FAIL line), 2 a usage error or a command this version does not implement.
3666
+ Every FAIL line ends with `(see rig-parts guide <RULE>)`, the command that prints the
3667
+ guide's row for that rule, and each row is anchored on the web as
3668
+ `docs/AUTHORING.md#<RULE>`.
3669
+
3670
+ What 1.0.0 holds stable — these commands and their flags, the config
3671
+ fields, the files a build writes and their spec ids, the environment, and what this
3672
+ package relies on in rig-c — and what is not, is [docs/STABILITY.md](STABILITY.md).
3673
+ Coming from 0.16.0: [docs/MIGRATION.md](MIGRATION.md).
3674
+
3675
+ ### Writing proposed config fields
3676
+
3677
+ `--write-config <config.json>` saves the proposals above into an existing
3678
+ regular config file: `seethrough.head_box`, `assemble.plan` plus
3679
+ `assemble.extend_below_crop`, or the present config sections of an ordinary
3680
+ proposal. The [neck draft](AUTHORING.md#a-neck-that-moves-on-its-own)
3681
+ (`propose … --full --head --write-config`) is another writer: for an existing
3682
+ `turn.body` config with one neck plan row, it selects the full-run neck, drafts a
3683
+ rigid unit and its depth, and reassembles parts under `<out>/rig`.
3684
+ For `assemble --propose-plan`, the destination must name `--config`
3685
+ itself; a different destination is a usage error. Other fields and absent optional
3686
+ sections remain; proposal notes are not copied. Changed whole values are spliced
3687
+ into the original text, preserving untouched bytes. Stage loaders validate the candidate, including `proposed_rig_scale`,
3688
+ before atomic replacement. Relative paths keep the config's directory as their
3689
+ base. Changes are listed on stderr; the head-box and plan JSON on stdout remain.
3690
+ An identical update leaves bytes and mtime untouched. Without the flag no config
3691
+ is changed. This commits the config file, not a transaction across the proposal
3692
+ artifacts.
3693
+
3694
+ With `--cloth <config.json>`, the flag requires a **new** destination and applies
3695
+ the recipe's entry ownership: recipe-owned entries are spliced into the cloth
3696
+ config while hand entries and unrelated text survive; conflicts are refused.
3697
+ The destination must also be separate from all four artifacts under `--out`:
3698
+ `proposal.json`, `basis.json`, `render/landmarks.png`, `render/landmarks_head.png`.
3699
+ Aliases, including directory symlinks and hardlinks, count as collisions too.
3700
+ Fresh output is published without overwriting a file created while the command
3701
+ runs. Its already-checked splice text may be a partial config; it is not passed
3702
+ through the full-config loader. If removing the staged temporary fails after
3703
+ publication, the error may accompany an already-published complete config.
3704
+ `--from <previous.json>` retains the previous-recipe comparison.
3705
+ With `--only-missing` (issue #671), an ordinary proposal's `--write-config` adds
3706
+ only `meshes.<part>` or `regions.<part>` for each proposed part the config
3707
+ attaches by neither, entry by entry, and, for a part the 1.37.0 arm split makes
3708
+ (`full:drape-<s>`, `full:hand-<s>`) that `assemble.plan` does not name, its plan
3709
+ row beside the arm's row; every existing row and entry and every other byte
3710
+ stays as read, and nothing else of the proposal is written. The candidate passes
3711
+ the full loader first, so an entry on a bone the config does not declare is
3712
+ refused naming the part and the bone; nothing missing leaves bytes and mtime
3713
+ untouched. It is the upgrade path for a config proposed before the 1.37.0 arm
3714
+ split ([MIGRATION](MIGRATION.md#after-1370-merged-arm-layers-are-split-issue-490)),
3715
+ and a usage error with `--head-box`, `--cloth` or `--from-config`.
3716
+ `--from-config` proposes nothing and cannot be combined with `--write-config`.
3717
+ [AUTHORING §4](AUTHORING.md#4-the-command-order) describes all four modes.
3611
3718
  ## 5. After each stage: what to read
3612
3719
 
3613
3720
  | stage | read | green looks like | a common red |
@@ -4994,7 +5101,7 @@ and stay absent).
4994
5101
  | <a id="DEPTH_SOURCE_AMBIGUOUS"></a>`DEPTH_SOURCE_AMBIGUOUS` | writer/user or layer/canvas declarations overlap | select one authoritative route explicitly |
4995
5102
  | <a id="DEPTH_SOURCE_RESOLVES"></a>`DEPTH_SOURCE_RESOLVES` | user key names no source layer | use the exact source tag in the selected run |
4996
5103
  | <a id="DEPTH_SOURCE_BASE"></a>`DEPTH_SOURCE_BASE` | a direct assembler caller supplied user paths without config base | pass the actual config-directory base |
4997
- | <a id="DEPTH_PART_SUPPORT"></a>`DEPTH_PART_SUPPORT` | exact copied/generated material lacks source depth or compatible units | provide a declared scalar source/registration; do not infer or fill depth |
5104
+ | <a id="DEPTH_PART_SUPPORT"></a>`DEPTH_PART_SUPPORT` | exact copied/generated material lacks source depth or compatible units | provide a declared scalar source/registration; do not infer or fill depth; declare the part `unit` with an explicit authored `unitDepths` value when its material includes authored under-art |
4998
5105
  | <a id="PARTS_DEPTH_REFERENCE"></a>`PARTS_DEPTH_REFERENCE` | persisted fields/provenance violate the reference shape | restore image, near, positive zScale and exact source records |
4999
5106
  | <a id="DEPTH_SILHOUETTE_SIZE_MISMATCH"></a>`DEPTH_SILHOUETTE_SIZE_MISMATCH` | `extendDepthSilhouette` or `padTurnDepthSheet` received a source depth sheet and artwork raster of different dimensions | supply the part's matching unpadded depth sheet and artwork raster |
5000
5107
  | <a id="CONFIG_TURN_COUNTER_RANGE"></a>`CONFIG_TURN_COUNTER_RANGE` | `config.turn.counter` (or `config.turn.body.counter`) is outside `[0, 1]` | supply a non-negative rear counter-translation fraction in `[0, 1]` |
@@ -5011,6 +5118,7 @@ and stay absent).
5011
5118
  | <a id="RIG_TURN_SURFACE_OVERLAP_DEPTH"></a>`RIG_TURN_SURFACE_OVERLAP_DEPTH` | same-group overlap neighbours demand incompatible emitted offsets at one target setup point | separate the conflicting support or provide coincident neighbour fields; the refusal names the fields and target vertex |
5012
5119
  | <a id="RIG_TURN_SURFACE_MESH_BINDINGS"></a>`RIG_TURN_SURFACE_MESH_BINDINGS` | an authored surface mesh has unresolved/nonclosing weights or shares a frame moved by a unit/rear turn carrier; declared stop draw aliases resolve to their links for setup sampling | provide weighted bindings closing at 1 in the authored frame; `<link>_d` resolves only for links declared in `config.stops`; use independent chains for parts with different roles |
5013
5120
  | <a id="RIG_TURN_SURFACE_MESH_ATTACHMENT"></a>`RIG_TURN_SURFACE_MESH_ATTACHMENT` | a surface mesh has an alternate drawing without its own registered depth sampling frame | use the base attachment; explicit islands retain their own slot, attachment and bindings |
5121
+ | <a id="RIG_TURN_BODY_UNCOVERED"></a>`RIG_TURN_BODY_UNCOVERED` | **Warning:** a shown part without a body role overlaps a moved `turn.body` surface at setup alpha >= 128 and has different emitted endpoint displacement | declare the intended body role and inspect both endpoints; no role or depth is inferred |
5014
5122
  | <a id="RIG_TURN_SURFACE_DEPTH_REQUIRED"></a>`RIG_TURN_SURFACE_DEPTH_REQUIRED` | a part with role `"surface"` in `config.turn.roles` or `config.turn.body.roles` carries no depth sheet in `parts.json` | run `assemble` with `config.depth` or provide `<part>_depth.png` in `parts.json` |
5015
5123
  | <a id="RIG_TURN_GRID_BUDGET"></a>`RIG_TURN_GRID_BUDGET` | a `"surface"` grid exceeds 2,400 triangles on one slot or 4,000 triangles across all `"surface"` slots | lower `config.turn.grid` / `config.turn.body.grid` `[cols, rows]` within the per-slot and total budgets |
5016
5124
  | <a id="RIG_TURN_HEAD_BONE"></a>`RIG_TURN_HEAD_BONE` | `buildRig` found no `"head"` (or body turn root) bone when emitting 2.5D turn carriers | declare `"head"` (or the body turn root bone) in `config.bones` |
@@ -5913,6 +6021,71 @@ on a bone of length 0 are NOT MEASURABLE and the run is not PASS (`CK68`–`CK79
5913
6021
  frame the slide peaks; a seam on a rig with no `parts.json` is refused before anything
5914
6022
  is built (`CK83`–`CK85`, `RQ30`–`RQ35`).
5915
6023
 
6024
+ ### Art joints on a fixed skeleton
6025
+
6026
+ When art is fitted to a skeleton whose setup must stay fixed, declare
6027
+ `fixed_skeleton` in the existing `--requirements` file (issue #880):
6028
+
6029
+ ```json
6030
+ {
6031
+ "spec": "spine-parts-requirements/1",
6032
+ "fps": 12,
6033
+ "requirements": [],
6034
+ "fixed_skeleton": {
6035
+ "source": "independent joint measurements on the fitted art",
6036
+ "within_px": 4,
6037
+ "joints": [
6038
+ { "name": "shoulder", "bone": "upper_arm", "at": [26, 57] }
6039
+ ]
6040
+ }
6041
+ }
6042
+ ```
6043
+
6044
+ The block explicitly identifies this as a fixed-skeleton comparison; a generation
6045
+ control pose does not. `source` is required nonempty provenance text, recorded
6046
+ without interpretation. Each `at` is an independently measured point on the art
6047
+ **as placed on the rig's stage**, in stage pixels from its top-left, x right and y
6048
+ down, the same space as a requirement's `target.stage`. Convert painting/source
6049
+ coordinates through the actual placement before declaring them: raw source pixels,
6050
+ bone-local offsets and normalized coordinates are not stage pixels. Each nonempty
6051
+ `name` is unique and each `bone` explicitly names its matching bone origin in
6052
+ `rig.json`. No anatomical names, hidden joints, correspondences or positions are
6053
+ inferred; only the listed measurements are covered. An unmeasured joint must not
6054
+ be supplied as the bone's own position.
6055
+
6056
+ `check` uses the existing setup-still renderer, requesting `--geometry`, and reads
6057
+ `geometry.json`'s `setup.bones` through its existing geometry reader. It converts
6058
+ the renderer's setup-world origin to stage pixels through the coordinate door;
6059
+ it never substitutes an animation's first frame or a bone's parent-local `x,y`.
6060
+ This also works for an external `rig.json` with no `parts.json` or idle. The
6061
+ Euclidean distance, art point and setup origin are printed **for every declared
6062
+ joint** and written to `check.json`'s `ART_JOINT_DISTANCE`, along with `source`,
6063
+ `instrument` and `within_px`. This is a setup-placement check, not a motion check
6064
+ or automatic detection of joints in an image.
6065
+
6066
+ `within_px` is optional and, when present, must be finite and nonnegative. The
6067
+ example's `4` is an authored demonstration, not a calibrated or default tolerance.
6068
+ Distance **greater than** the declared limit fails; equality passes. Without a
6069
+ limit, the block and every joint are **SKIP**, with the measured distances and
6070
+ `within_px: null`; this line is excluded from measured bars and contributes no
6071
+ PASS. Other independent checks may still pass. With no `fixed_skeleton` block,
6072
+ this measurement adds no output or render call. `fps` and `requirements` remain
6073
+ required by the enclosing file; they do not change this setup measurement.
6074
+
6075
+ | rule | change |
6076
+ | --- | --- |
6077
+ | <a id="CHECK_ART_JOINT_DISTANCE"></a>`CHECK_ART_JOINT_DISTANCE` | The named joint is farther from its setup bone origin than `fixed_skeleton.within_px`; the message gives distance and limit. Correct a wrong art measurement or bone correspondence, or supply art aligned to the fixed skeleton. Choose any changed limit explicitly from the consumer's requirement; bones and art are never moved by this check. |
6078
+ | <a id="CHECK_ART_JOINT_MEASURED"></a>`CHECK_ART_JOINT_MEASURED` | Supply a finite renderer setup origin and a finite measurable distance; missing geometry is never taken as zero. The existing `CHECK_GEOMETRY_FILE` refusal names missing/malformed geometry. |
6079
+
6080
+ `REQUIREMENTS_FIELD` and `REQUIREMENTS_RESOLVES` cover malformed declarations:
6081
+ supply nonempty provenance and a nonempty joint list, unique joint names, finite
6082
+ `[x, y]` points, known bone names and an explicit valid limit or omit the limit.
6083
+ Unknown fields are refused.
6084
+
6085
+ | line | measures | bar | SKIP |
6086
+ | --- | --- | --- | --- |
6087
+ | <a id="ART_JOINT_DISTANCE"></a>`ART_JOINT_DISTANCE` | Each independently measured art joint versus its explicitly named bone's renderer setup origin, in stage pixels; printed and recorded per joint | distance <= the declared `fixed_skeleton.within_px`, with no rounding slack | no limit declared: every row and the block retain their distances as SKIP, never a pass; no declaration: no line |
6088
+
5916
6089
  ## 8. What one character costs
5917
6090
 
5918
6091
  | step | reference-sample | reference-demo | source |
@@ -6216,6 +6389,62 @@ art. An authored `parts.json` depth reference remains an active standalone
6216
6389
  `rig` declaration even without config opt-in: its file/size/color/opacity
6217
6390
  guards still apply. With binding inactive there is no added reference, file or
6218
6391
  legacy-byte change. #773 adds no image generation, geometry or motion model.
6392
+
6393
+ ### Missing body-turn coverage
6394
+
6395
+ `RIG_TURN_BODY_UNCOVERED` warns when a shown part without a
6396
+ `turn.body.roles` entry overlaps a moved body surface. It names both parts,
6397
+ both endpoint times, their actual emitted displacement vectors and the maximum
6398
+ relative displacement at a setup painting-pixel centre. Both drawings require
6399
+ alpha >= 128 and actual covering setup triangles; bounding boxes and transparent
6400
+ pixels alone do not count. Excluded alpha does not count. The diagnostic reads
6401
+ positive bindings in the declared torso subtree, excluding head/neck subtrees.
6402
+ Explicit body roles and bindings wholly inheriting an emitted body-turn carrier
6403
+ count as declared coverage; identical inherited motion needs no second role. Differences no larger than the producer's six-place
6404
+ encoding unit (0.000001 rig px) are ignored. This is a warning about a missing
6405
+ declaration, not an automatic seam verdict or a rule for limb crossings.
6406
+
6407
+ Warnings belong to the stage report only. They add no rig, motion or PNG field
6408
+ and never assign a role, depth, binding or draw order. A part already bound to
6409
+ `chest` does not inherit a weighted topwear surface's per-vertex deform. Declare
6410
+ its actual intended role, then inspect setup, both turn endpoints and their diff;
6411
+ an explicit role alone does not establish that two drawings remain coincident.
6412
+
6413
+ ### Unit depth precedence
6414
+
6415
+ For `"unit"` roles, a transported part's sheet is recorded and validated but is not
6416
+ necessarily the depth used to move its bone. `turn.unitDepths` (and the body
6417
+ map `turn.body.unitDepths`, which inherits the head map when omitted) uses
6418
+ calibrated world depths. An explicit `0` is a value, not a request to sample.
6419
+ With active depth binding, assembly skips scalar transport only when every declared turn group makes the part `unit` with explicit part or carried-bone `unitDepths` covering every still piece, records the resolved values in `provenance.depth` as `{kind: "authored-unit", values: [...]}`, and retains input-sheet validation and every implicit-unit or sampled-surface refusal.
6420
+ For each carried unit bone, the existing producer resolves depth in this order:
6421
+
6422
+ 1. `unitDepths.<part>`; when both names are present, the part entry wins.
6423
+ 2. `unitDepths.<bone>`, using the carried bone's name.
6424
+ 3. The primary surface's extended sheet at the unit's setup landmark. The
6425
+ head group prefers the `face` surface, otherwise the first declared surface;
6426
+ the body group uses its first declared surface. This depth is relative to
6427
+ that surface's reference and the group's pivot. A unit mesh uses its child
6428
+ landmarks, or its part centre when those landmarks are absent.
6429
+ 4. Only if still unresolved, the unit's own sheet's opaque-art median. This
6430
+ lower-level fallback is not an authoring switch: the documented config
6431
+ reader requires a surface in each active group and supplies declared region
6432
+ landmarks or a mesh sampling position. No documented configuration is
6433
+ provided here to bypass primary sampling and select the own sheet instead.
6434
+
6435
+ Outside or nonopaque primary support produces
6436
+ [`RIG_TURN_UNIT_DEPTH_SUPPORT`](#RIG_TURN_UNIT_DEPTH_SUPPORT), retains the
6437
+ extended primary sample, and does not select the own sheet. Removing all
6438
+ surfaces is refused by
6439
+ [`CONFIG_TURN_SURFACE_REQUIRED`](#CONFIG_TURN_SURFACE_REQUIRED).
6440
+ Consequently, removing `unitDepths` alone does not make an own-sheet change
6441
+ move a unit: primary-surface sampling can still mask it. In that case the own
6442
+ sheet remains in `depth_sheets.json` and its padded PNG, but is not consumed
6443
+ for that unit's turn geometry. Author an explicit calibrated `unitDepths`
6444
+ entry to control its rigid depth; change the primary surface only when that
6445
+ shared sampled field is what should change. A `"surface"` part's own sampled
6446
+ geometry is a separate consumer described above.
6447
+
6219
6448
  ### Explicit source-derived waist pivot stage
6220
6449
 
6221
6450
  `withWaistPivot` is a pure, explicit candidate-stage operation over an already
@@ -6335,3 +6564,51 @@ they do not certify a new toolchain, input or packaging build. No tuning to meet
6335
6564
  | <a id="CONFIG_WAIST_NAME_FREE"></a>`CONFIG_WAIST_NAME_FREE` | The generated bone name already exists; declare an unused name | declare an unused name |
6336
6565
  | <a id="RIG_WAIST_DECLARATION"></a>`RIG_WAIST_DECLARATION` | Actual provenance, pair bindings or drawing ownership do not match the bounded declaration; supply the declared base two-bone mesh/rigid-region pair | supply the declared base pair |
6337
6566
  | <a id="RIG_WAIST_MOTION"></a>`RIG_WAIST_MOTION` | Imported tracks drive the generated waist frame; retain their original authored targets | retain the original authored targets |
6567
+
6568
+ ### Depth-driven rigging
6569
+
6570
+ Registered per-part depth sheets drive sampled head yaw/pitch through
6571
+ `turn.roles` and independent body yaw through `turn.body.roles`. Region
6572
+ surfaces use depth-bearing grids; authored weighted surfaces keep their
6573
+ skinning and receive per-influence deform offsets sampled at setup positions.
6574
+ These controls are exercised on public synthetic fixtures. Unit parts use the
6575
+ [documented depth precedence](AUTHORING.md#unit-depth-precedence), so a
6576
+ recorded unit sheet does not by itself promise different turn geometry.
6577
+ See the [authoring contract](AUTHORING.md#per-layer-depth-sheets-773)
6578
+ and the [getting-started guide](https://github.com/rig-c/getting-started).
6579
+
6580
+ ### Per-layer depth input
6581
+
6582
+ `config.depth` explicitly enables scalar input. Without it, `depth_filename`
6583
+ is a legacy hint: no depth-file I/O, validation, fetch, reference or output is
6584
+ activated, even when files or in-memory sheets exist. Active See-through sheets
6585
+ are read as opaque grayscale source data. Declare positive finite `depth.zScale`;
6586
+ eight bits do not supply world units. See-through far-high encoding is explicitly `near: "black"`. User
6587
+ per-layer/run-canvas fallbacks declare image, near and zScale themselves; a
6588
+ missing declared file is an error, not a fallback. The ordering median remains
6589
+ separate, and its agreement reading cannot certify an image's polarity.
6590
+
6591
+ Assembly emits registered part sheets and references; rig emits PAD4 sheets and
6592
+ `depth_sheets.json`. Since 1.68.0 (#777), [config.turn.roles](AUTHORING.md#3-configjson-field-by-field)
6593
+ uses depth sheets for 2.5D head turns with grid or authored weighted surfaces and `yaw_dial`/`pitch_dial`
6594
+ controls; see [`CONFIG_TURN_ROLE_UNKNOWN`](AUTHORING.md#CONFIG_TURN_ROLE_UNKNOWN)
6595
+ and [`CONFIG_TURN_SURFACE_REQUIRED`](AUTHORING.md#CONFIG_TURN_SURFACE_REQUIRED).
6596
+ `turn.body.roles` adds independent body yaw. A weighted mesh declared as
6597
+ `"surface"` in either group and blending head and torso bones receives both
6598
+ fields in proportion to its skin weights. Inside the existing setup alpha
6599
+ overlap with a single-group neighbour, a blended attachment's vertex takes
6600
+ that neighbour's existing emitted triangle field at its setup position (#804), without changing skin weights,
6601
+ setup or idle. A `motion.blink.still` unit neighbour supplies both emitted
6602
+ pieces, each on its own bone and resolved depth; transparent padding does not
6603
+ let either piece lend its field to the other's art (#807). Missing emitted
6604
+ split support is refused by name. Conflicting neighbour groups are refused by name. Each sibling island takes only its
6605
+ own group; parts without a blended attachment keep their existing role behavior
6606
+ and output bytes. Unlisted meshes do not consume turn depth sheets. See the
6607
+ [blended surface contract](AUTHORING.md#per-layer-depth-sheets-773).
6608
+ This copies the field at vertices; different triangle partitions can still
6609
+ differ between vertices. The [corrected #804 acceptance](https://github.com/rig-c/parts/issues/804#issuecomment-6478778123)
6610
+ checks vertex correspondence and reports those residuals per fixture; the
6611
+ contract records the measured grid residual and preserves its seam readings.
6612
+ No-image builds keep the legacy output bytes. `comfy seethrough --config <file> --depth-run <full|head>`
6613
+ uses the same opt-in; its default captures art only. Standalone authored part
6614
+ references remain active declarations. See [the input contract and refusals](AUTHORING.md#per-layer-depth-sheets-773).
package/docs/STABILITY.md CHANGED
@@ -80,6 +80,10 @@ command's flag union; `comfy paint` and `comfy seethrough` are checked separatel
80
80
  Required combinations within a mode remain the CLI's; the `cli` suite's controls
81
81
  read them from the help.
82
82
 
83
+ The [command reference](AUTHORING.md#command-reference) describes each mode;
84
+ [writing proposed config fields](AUTHORING.md#writing-proposed-config-fields)
85
+ records the existing-file and fresh-file destinations and byte-preservation rules.
86
+
83
87
  ## The config contract
84
88
 
85
89
  `src/config.ts` is the schema and the loader, and
@@ -478,6 +482,22 @@ Assembly's optional part `depth` reference holds `image`, `near`, `zScale` and
478
482
  active binding. Persisted authored part references remain active for standalone
479
483
  rig reading regardless of config opt-in. `rig` adds padded measurement PNGs and the `rig-parts-depth-sheets/1`
480
484
  `depth_sheets.json` companion only with references (each output `part`, actual
481
- padded `size`, and `depth`; a still split names both slices). Current weighted meshes do
482
- not acquire a Core field or change geometry; #763 owns the generator consumer.
485
+ padded `size`, and `depth`; a still split names both slices). Passive references
486
+ add these companions without changing weighted geometry. Active `"surface"`
487
+ roles in `turn.roles` and `turn.body.roles` consume registered sheets:
488
+ region surfaces emit Core grid generators with `generator.depth`; authored
489
+ weighted surfaces keep their topology and bindings and emit sampled per-influence
490
+ inverse-bind deform offsets in motion, without adding a Core attachment depth
491
+ field. Head yaw/pitch and independent body yaw use their existing turn groups.
492
+ Blended surfaces retain the documented per-group masks and setup-overlap
493
+ neighbour field rules in [AUTHORING](AUTHORING.md#per-layer-depth-sheets-773).
494
+ `RIG_TURN_BODY_UNCOVERED` is a report-only warning for a shown torso part
495
+ without a body role that has opaque setup-triangle overlap with a moved body
496
+ surface and different emitted endpoint displacement. It names the part, surface,
497
+ times, vectors and relative travel. Head/neck bindings, transparent/excluded
498
+ alpha, explicit/inherited body roles and identical inherited motion are excluded as
499
+ described in [AUTHORING](AUTHORING.md#missing-body-turn-coverage). It assigns
500
+ no role or depth and changes no emitted file bytes.
501
+ The unit-depth precedence and its primary-surface sampling are documented in
502
+ [AUTHORING](AUTHORING.md#unit-depth-precedence).
483
503
  The separate ordering scalar is unchanged. No-image outputs retain legacy bytes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rig-parts",
3
- "version": "1.83.1",
3
+ "version": "1.84.0",
4
4
  "description": "AI-authored 2D character parts from one anime painting and its See-through layer decomposition: measured parts, weighted-mesh rig specs, verified through rig-c before anything is written. A CLI for agents that cannot see the image.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,6 +58,7 @@
58
58
  "scripts": {
59
59
  "fetch-examples": "bash scripts/fetch-examples.sh",
60
60
  "selftest": "bun selftest.ts",
61
+ "check:readme": "bun scripts/readme_policy.ts",
61
62
  "selftest:pre": "bun selftest.ts --pre",
62
63
  "smoke": "bun scripts/install_smoke.ts",
63
64
  "typecheck": "bunx tsc --noEmit",