rig-parts 1.5.4 → 1.6.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/NOTICE.md CHANGED
@@ -96,16 +96,29 @@ ships none and downloads none, and the terms that govern an image they produce
96
96
  are the terms of those models. A painting from any other source works the same
97
97
  way.
98
98
 
99
- The images this repository ships — `assets/demo-*` and `assets/sample-parts.png`
100
- — and the public examples' paintings were generated with
101
- `ponyDiffusionV6XL_v6StartWithThisOne.safetensors`,
102
- [Pony Diffusion V6 XL](https://civitai.com/models/257749), with no LoRA. The
103
- checkpoint itself is not redistributed. **[observed 2026-09-27]** CivitAI's model
104
- API reported for it `allowCommercialUse: ["Image", "RentCivit"]`,
105
- `allowNoCredit: false`, `allowDerivatives: true` and
106
- `allowDifferentLicense: false`: generated images may be used commercially and
107
- the model must be credited, which this line and the
108
- [spine-parts-examples](https://github.com/firejune/spine-parts-examples) README do.
99
+ The images this repository ships, and the public examples' paintings, were
100
+ generated with one of two checkpoints, with no LoRA; neither checkpoint is
101
+ redistributed.
102
+
103
+ - `assets/demo-*` and the `demo` example's painting (since issue #227):
104
+ `hassakuXLIllustrious_v13StyleA.safetensors`,
105
+ [Hassaku XL (Illustrious)](https://civitai.com/models/140272) v1.3 Style A, by
106
+ Ikena. Credit, as sharing it requires: *Painted with Hassaku XL (Illustrious)
107
+ v1.3 Style A by Ikena (https://civitai.com/models/140272), Fair AI Public
108
+ License 1.0-SD.* **[observed 2026-10-11]** The model page's version and licence
109
+ section reads "All Models using the Fair AI Public License 1.0-SD license", and
110
+ CivitAI's model API reported `allowCommercialUse: ["RentCivit", "Rent", "Image"]`,
111
+ `allowNoCredit: false`, `allowDerivatives: true` and `allowDifferentLicense: false`.
112
+ - `assets/sample-parts.png` and the `scarf`, `reference-sample` and `reference-demo`
113
+ paintings: `ponyDiffusionV6XL_v6StartWithThisOne.safetensors`,
114
+ [Pony Diffusion V6 XL](https://civitai.com/models/257749). **[observed
115
+ 2026-09-27]** CivitAI's model API reported for it `allowCommercialUse: ["Image",
116
+ "RentCivit"]`, `allowNoCredit: false`, `allowDerivatives: true` and
117
+ `allowDifferentLicense: false`: generated images may be used commercially and
118
+ the model must be credited, which this line does.
119
+
120
+ The [parts-examples](https://github.com/rig-c/parts-examples) README records
121
+ both, beside each character's generation record.
109
122
 
110
123
  ## 4. Behaviour reimplemented, not code copied
111
124
 
package/README.md CHANGED
@@ -14,57 +14,45 @@ input is silent.
14
14
  ## What you get
15
15
 
16
16
  <p align="center">
17
- <img src="https://raw.githubusercontent.com/rig-c/parts/main/assets/demo-source.png" alt="The demo painting: a generated full-body character in a white and pink frilled dress with long pink twin tails, standing with her hands clasped" height="420" />
17
+ <img src="https://raw.githubusercontent.com/rig-c/parts/main/assets/demo-source.png" alt="The demo painting: a generated full-body character in a white and pink idol dress with a layered skirt and long pink twin tails, standing with her arms held away from her body and her hands open" height="420" />
18
18
  <img src="https://raw.githubusercontent.com/rig-c/parts/main/assets/demo-idle.png" alt="The same character rigged, breathing, blinking once and swaying her hair, sleeves and skirt in a four-second loop" height="420" />
19
19
  </p>
20
20
 
21
21
  <p align="center">
22
- <img src="https://raw.githubusercontent.com/rig-c/parts/main/assets/demo-parts.png" alt="Contact sheet of the painting and the 22 assembled parts it was split into: hair, dress, sleeves, shoes, face, eyes, brows, mouth and ornaments" width="100%" />
22
+ <img src="https://raw.githubusercontent.com/rig-c/parts/main/assets/demo-parts.png" alt="Contact sheet of the painting and the 23 assembled parts it was split into: hair, sleeves, legs, boots, neck, skirt, bodice, earrings, hair ornaments, ears, face, brows, mouth and eyes" width="100%" />
23
23
  </p>
24
24
 
25
25
  <p align="center"><em>
26
- The painting was generated for this repository with a public checkpoint (Pony
27
- Diffusion V6 XL) and no LoRA; its generation record, See-through layers and licence
28
- are in <a href="https://github.com/firejune/spine-parts-examples">spine-parts-examples</a>
29
- (that repository keeps the name it was published under before this package's rename).
26
+ The painting was generated for this repository with a public checkpoint (Hassaku XL
27
+ (Illustrious) v1.3 Style A, by Ikena, Fair AI Public License 1.0-SD) and no LoRA, on a
28
+ pose that holds the hands apart, then given one hand-detailer pass; its generation
29
+ record, See-through layers and licence are in
30
+ <a href="https://github.com/rig-c/parts-examples">parts-examples</a>.
30
31
  See-through ran twice, once on the whole figure and once on a square head crop.
31
- Then one command: <code>rig-parts build --seam silhouette --loop</code>. The
32
- proposer's bones, meshes, regions and motion were used <b>unedited</b>. Two input-stage
33
- edits were made by hand for the reference run this example reproduces: the head box
34
- was shifted down into the canvas (its proposal ran 118 px above the top edge;
35
- <code>propose --head-box</code> now makes that shift itself), and <code>hair_back</code>
36
- is taken from the full run, because the twin tails leave the head crop sideways
37
- (a plan edit). <code>check</code> printed, verbatim:<br/>
38
- <code>50 assertions: 24 measured (24 passed, 0 failed), 26 skipped, 0 not in profile "spine-html"</code><br/>
32
+ Then one command: <code>rig-parts build --loop</code>. The proposer's bones, meshes,
33
+ regions and motion were used as proposed but for one correction, written in the
34
+ config beside the values it replaced: the two outer skirt chains were moved out to
35
+ 0.8 of the skirt's half-width (the proposal's, within 90 px of the centre of a skirt
36
+ 449 px wide, swung it about its middle and failed <code>TIP_OVER_ROOT</code>, 0.442
37
+ against 1.4725; moved, 2.425). One input-stage edit: <code>hair_back</code> is taken
38
+ from the full run, because the twin tails leave the head crop sideways (a plan edit).
39
+ <code>check</code> printed, verbatim:<br/>
40
+ <code>50 assertions: 25 measured (25 passed, 0 failed), 25 skipped, 0 not in profile "spine-html"</code><br/>
39
41
  <code>loop: idle 49 frame(s) at 12 fps, f0000 vs f0048 (t = 4s): max |d| 0 (0 required)</code><br/>
40
- <code>seam: setup pose at 714x1216, scale 0.9422: mean |d| 0.234 (&lt;= 1.0), 2 px over 40, 2.25 rig px (the count / s²; &lt;= 50), 0 px over 80 (reported)</code><br/>
41
- <code>pack: skeleton.png 922x1348, 22 region(s), 94.9% covered, padding 2, page edges free, shape polygon</code><br/>
42
- <code>--seam silhouette</code> repaired the navy blobs the default rule leaves on the white
43
- blouse (recomposite error pixels 10,340 → 8,644); the default stays
44
- <code>near-white</code>, the reference implementation's rule, so the examples stay
45
- comparable with it. The loop is <code>rig-parts loop --palette</code>'s indexed APNG, 48 frames at
46
- 12 fps, 1,706,719 bytes, one 256-entry palette at a measured error of max 57, mean 1.601
42
+ <code>seam: setup pose at 654x1216, scale 0.9438: mean |d| 0.147 (&lt;= 1.0), 0 px over 40, 0.00 rig px (the count / s²; &lt;= 50), 0 px over 80 (reported)</code><br/>
43
+ <code>pack: skeleton.png 1051x972, 23 region(s), 96.9% covered, padding 2, page edges free, shape polygon</code><br/>
44
+ The loop is <code>rig-parts loop --palette</code>'s indexed APNG, 48 frames at
45
+ 12 fps, 827,857 bytes, one 256-entry palette at a measured error of max 65, mean 0.879
47
46
  per channel over every frame (the lossless APNG beside it, the exactness record, is
48
- 13,645,503 bytes; the GIF, at the same error, 1,812,288). Frame 29 (2.417 s) is the
49
- closed eye: the blink holds for 0.084 s, one 12 fps frame rounded up, where the
50
- reference implementation held 0.04 s and no frame of its loop showed the eyes shut
51
- (issue #32); the painting is shown at half size, resampled and written
52
- by this package's PNG codec (nothing here encodes JPEG). <code>rig-parts sheet</code>
53
- made the contact sheet.
47
+ 5,832,634 bytes; the GIF, at the same error, 889,063). Frame 29 (2.417 s) is the
48
+ closed eye: the blink holds for 0.084 s, one 12 fps frame rounded up; the painting is
49
+ shown at half size, resampled and written by this package's PNG codec (nothing here
50
+ encodes JPEG). <code>rig-parts sheet</code> made the contact sheet. Its
51
+ <code>expected/</code> is this port's own build (<a href="examples/demo/README.md">examples/demo</a>).
54
52
  </em></p>
55
53
 
56
- <p align="center">
57
- <img src="https://raw.githubusercontent.com/rig-c/parts/main/assets/sample-parts.png" alt="Contact sheet of the sample character's painting and its 20 parts" width="560" />
58
- </p>
59
-
60
54
  <p align="center"><em>
61
- The plain fixture, <code>examples/sample</code>: same checkpoint, no LoRA, and a rig
62
- built from its own proposal with no hand edit at all —
63
- <code>seam: setup pose at 379x1216, scale 1.0116: mean |d| 0.204 (&lt;= 1.0), 2 px over 40, 1.95 rig px (the count / s²; &lt;= 50), 0 px over 80 (reported)</code>, loop max |d| 0.
64
- </em></p>
65
-
66
- <p align="center"><em>
67
- The hanging element, <code>examples/scarf</code>: same checkpoint, no LoRA, a very long
55
+ The hanging element, <code>examples/scarf</code>: Pony Diffusion V6 XL, no LoRA, a very long
68
56
  red scarf whose ends hang free, and the first character run through this pipeline
69
57
  with its proposal used unedited — the only hand corrections are four
70
58
  <code>assemble.patches</code>, each answering an <code>uncovered hole</code> line.
@@ -73,6 +61,15 @@ switched to the contour mode. It has no reference output: its <code>expected/</c
73
61
  is this port's own build (<a href="examples/scarf/README.md">examples/scarf</a>).
74
62
  </em></p>
75
63
 
64
+ <p align="center"><em>
65
+ Two more characters are tracked as fixtures and not shown:
66
+ <code>examples/reference-demo</code> and <code>examples/reference-sample</code>, the two
67
+ the reference implementation ran (published as <code>demo</code> and <code>sample</code>
68
+ until issue #227, which took the clasped-hands painting off display). Their
69
+ <code>expected/</code> is that implementation's own output, which the selftest holds
70
+ this port to.
71
+ </em></p>
72
+
76
73
  ## What it takes in
77
74
 
78
75
  - **One painting** — a PNG of one character, front-facing, full body, taller than
@@ -102,7 +99,7 @@ page** (issue #2):
102
99
 
103
100
  | path under `--out` | what |
104
101
  | --- | --- |
105
- | `check/build/skeleton.json`, `skeleton.atlas`, `skeleton.png` | **the artifact** — Spine 4.3 skeleton data and one packed page, written by `rigc build --pack --page-edges free --pack-shape polygon` and gated under `spine-html`, which holds every rule `spine` measures (on the demo, rigc 2.1.3 and 2.10.1: the 14 rules `validate --profile spine` measures are among the build's 24; 16 are not in `spine`) |
102
+ | `check/build/skeleton.json`, `skeleton.atlas`, `skeleton.png` | **the artifact** — Spine 4.3 skeleton data and one packed page, written by `rigc build --pack --page-edges free --pack-shape polygon` and gated under `spine-html`, which holds every rule `spine` measures (on reference-demo, rigc 2.1.3 and 2.10.1: the 14 rules `validate --profile spine` measures are among the build's 24; 16 are not in `spine`) |
106
103
  | `parts/*.png`, `parts.json`, `recomposite_rig.png`, `recomposite_error_rig.png` | the loose parts, each cropped to its alpha box; the record of where every part came from, how many of its pixels were re-taken from the painting, and the recomposite's uncovered holes with their boxes; the flat stack of parts; its error map — red where no part covers a pixel the painting has, blue where a part covers it in the wrong colour |
107
104
  | `rig/` | `rig.json` and `motion.json` in rig-c's spec, `mesh_report.json`, the padded `images/` |
108
105
  | `check/` | both gate files verbatim, the idle's frames and their `geometry.json` (skinned vertices per frame), `contact.png`, `motion_heat.png`, `check.json` (with `pack_mode`, the `--page-edges` and `--pack-shape` the page was packed under) |
@@ -110,7 +107,7 @@ page** (issue #2):
110
107
 
111
108
  The last lines of a green build are the pack line, printed beside the Spine example
112
109
  export's `spineboy.png` as a yardstick (a reference, not a bar), and the three
113
- artifact paths — here for `examples/sample`:
110
+ artifact paths — here for `examples/reference-sample`:
114
111
 
115
112
  ```
116
113
  build: PASS — the packed atlas is the artifact; parts/ and rig/ are the intermediates it was made from
@@ -121,7 +118,7 @@ build: PASS — the packed atlas is the artifact; parts/ and rig/ are the interm
121
118
  ```
122
119
 
123
120
  The page's edges are free by default: rigc picks the least-area page the parts need,
124
- not the next power of two. On the two examples, packed by rectangles, that is 967x1338
121
+ not the next power of two. On the two reference examples, packed by rectangles, that is 967x1338
125
122
  and 479x1166, where a power-of-two page is 1024x2048 and 512x2048, and covered goes from 56.3 % to 91.2 % and
126
123
  from 49.7 % to 93.4 %. The cost is the one rigc's help states: *"region attachments
127
124
  sampling within 1 LSB of the loose build rather than exactly"*. Measured on both
@@ -192,8 +189,8 @@ head run on `st_input_head.png` is what gives the eyes more pixels
192
189
  **See-through is required; ComfyUI is not.** The wrapper is one route among
193
190
  four, and `rig-parts comfy` is only a convenience for that route: every
194
191
  stage after See-through reads files, whichever route wrote them. On the two
195
- public examples each run took 171–199 s through the wrapper (each run's
196
- `meta.json`, in [spine-parts-examples](https://github.com/firejune/spine-parts-examples)).
192
+ reference examples each run took 171–199 s through the wrapper, and on the demo 179 s (each run's
193
+ `meta.json`, in [parts-examples](https://github.com/rig-c/parts-examples)).
197
194
 
198
195
  ### The two images See-through is fed: `inputs`
199
196
 
@@ -277,7 +274,7 @@ agent skill.
277
274
  | `comfy seethrough --image --out [--host]` | optional: run the ComfyUI See-through wrapper on one image and write the form `layers` reads |
278
275
  | `layers <dir \| layers.json \| file.psd>` | print every layer of a decomposition: draw order, name, tag group, box, size, opaque pixels, depth, and its translucent, background and area figures; a `WARN` line for a layer `--propose-plan` will leave out |
279
276
  | `sheet --source <png> --layers <path>… --out <png>` | a labelled contact sheet of the painting and every layer or part |
280
- | `assemble --propose-plan …` | propose `assemble.plan` and `extend_below_crop` from the two runs, leaving out an implausible layer with a note naming the rule |
277
+ | `assemble --propose-plan …` | propose `assemble.plan` and `extend_below_crop` from the two runs, leaving out an implausible layer with a note naming the rule, and naming in a note any full-run body no planned part covers |
281
278
  | `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 |
282
279
  | `propose --head-box --full <run> --canvas WxH` | propose `seethrough.head_box` from the full run, held inside the painting |
283
280
  | `propose --parts --source --out [--compare <config>]` | 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 |
@@ -336,7 +333,9 @@ These are limits of the approach, stated so nobody reads more into a green run:
336
333
  ### What can be built on top
337
334
 
338
335
  This package makes no expression and no jiggle, but the rig it writes is the material for
339
- both, and the config has a field for each. [docs/AUTHORING.md](docs/AUTHORING.md) has a recipe
336
+ both, and the config has a field for each; `examples/demo` and `examples/scarf` carry a worked
337
+ set of each (issue #224: a tilt, two looks, a smile, a startle, a wave or a bow and a hop,
338
+ with physics on the hair, the skirt, the sleeves and the scarf ends). [docs/AUTHORING.md](docs/AUTHORING.md) has a recipe
340
339
  for each — a config fragment, the `check` lines it passes with, and its limit:
341
340
 
342
341
  - [**Expressions and other named animations**](docs/AUTHORING.md#recipe-expressions-and-other-named-animations):
@@ -346,9 +345,9 @@ for each — a config fragment, the `check` lines it passes with, and its limit:
346
345
  image; `check` measures the idle alone.
347
346
  - [**A soft region driven by physics**](docs/AUTHORING.md#recipe-a-soft-region-driven-by-physics)
348
347
  (a bust, the hips): a bone the config authors, a contour-mode region that hands it the patch,
349
- and a `physics` constraint on it; `examples/sample` carries one. Under the sample's slow
348
+ and a `physics` constraint on it; `examples/reference-sample` carries one. Under its slow
350
349
  4 s idle the bust moves at most 0.066 rig px and the hips not at all: the spring answers
351
- faster keys on the body. The sample's `hop`, a named animation keying only `hip`, moves the
350
+ faster keys on the body. Its `hop`, a named animation keying only `hip`, moves the
352
351
  bust up to 6.583 and the hips up to 4.432 rig px; the region's `band` caps how far a patch may
353
352
  go before the texture-stretch ceiling, and `check` measures the idle alone.
354
353
 
@@ -357,15 +356,16 @@ for each — a config fragment, the `check` lines it passes with, and its limit:
357
356
  `parts.json` splits each part's opaque pixels (`opaque_px`) into `visible_px` — no
358
357
  later layer of its See-through run is opaque in front of them — and `occluded_px`,
359
358
  and counts the visible ones whose colour was not taken from the painting
360
- (`visible_not_projected_px`). On the three public examples, from the totals of their
359
+ (`visible_not_projected_px`). On the four examples, from the totals of their
361
360
  `expected/parts.json` (the default `--project core`; `scarf`'s painting patches are
362
361
  whole painting pixels, so they count as taken):
363
362
 
364
363
  | | opaque px | occluded | visible, not projected | taken from the painting |
365
364
  | --- | --- | --- | --- | --- |
366
- | `sample` | 298,363 | 79,122 (26.5 %) | 35,979 (12.1 %) | 183,262 (61.4 %) |
367
- | `demo` | 765,924 | 202,343 (26.4 %) | 75,626 (9.9 %) | 487,955 (63.7 %) |
365
+ | `demo` | 362,441 | 69,098 (19.1 %) | 67,164 (18.5 %) | 226,179 (62.4 %) |
368
366
  | `scarf` | 283,813 | 78,503 (27.7 %) | 56,699 (20.0 %) | 148,611 (52.4 %) |
367
+ | `reference-sample` | 298,363 | 79,122 (26.5 %) | 35,979 (12.1 %) | 183,262 (61.4 %) |
368
+ | `reference-demo` | 765,924 | 202,343 (26.4 %) | 75,626 (9.9 %) | 487,955 (63.7 %) |
369
369
 
370
370
  The occluded share is art the painting does not show — a back-hair layer, a neck, the
371
371
  parts of an ear under the hair — and is See-through's synthesis by necessity; it is
@@ -373,18 +373,19 @@ what the decomposition is for. The visible-but-not-projected share is synthesis
373
373
  the painting was there to be taken: a part too thin for the reference rule's 5x5
374
374
  eroded core, an anti-aliased fringe below alpha 250, a rim beside a layer in front, a
375
375
  pixel refused for drift. `--project visible` keeps the erosion only along a rim with a
376
- layer in front, which takes that share to 22,476 (7.5 %) on `sample` and 49,672 (6.5 %)
377
- on `demo` (from the `parts.json` of a `--project visible` build). On the eleven thin
376
+ layer in front, which takes that share to 22,476 (7.5 %) on `reference-sample` and 49,672 (6.5 %)
377
+ on `reference-demo` (from the `parts.json` of a `--project visible` build). On the eleven thin
378
378
  head parts — brows, lashes, irises, eye whites, ears, mouth — it takes 296 of
379
- `sample`'s 1,289 visible pixels where `core` takes 110, and 824 of `demo`'s 2,162
379
+ `reference-sample`'s 1,289 visible pixels where `core` takes 110, and 824 of `reference-demo`'s 2,162
380
380
  where `core` takes 343. What neither rule takes is the fringe: a per-pixel
381
381
  classification of those parts under `visible`, recorded with the change that added
382
- the flag, puts 813 of `sample`'s 993 still-unprojected pixels and 879 of `demo`'s
382
+ the flag, puts 813 of `reference-sample`'s 993 still-unprojected pixels and 879 of `reference-demo`'s
383
383
  1,338 below alpha 250. Where such a fringe keeps the stack off the painting and a part
384
384
  beneath holds the pixel in the painting's colour, `assemble` clears it instead, and
385
385
  the assemble line and `parts.json` say how many pixels, of which part, over which
386
386
  (AUTHORING §5, *The fringe push-back*; the figures in this section were measured
387
- before it, at v0.14.0).
387
+ before it, at v0.14.0, but for the `demo` row, which is its `expected/parts.json`
388
+ as this port wrote it in issue #227).
388
389
 
389
390
  ## Requirements
390
391
 
package/cli.ts CHANGED
@@ -358,7 +358,11 @@ usage:
358
358
  mean channel; error px: max channel > 40; uncovered: of those, where no
359
359
  part has alpha above 128), then the uncovered holes (8-connected) and the
360
360
  largest ${HOLES_LISTED}, each \`uncovered hole N: <px> px at x,y wxh (between
361
- "<part>" <px> px, …)\` — the list parts.json holds under recomposite.
361
+ "<part>" <px> px, …)\` — the list parts.json holds under recomposite —
362
+ and one \`uncovered:\` line per full-run layer the plan does not take from
363
+ the full run whose uncovered error holds a body (5x5-opened, 8-connected,
364
+ at least 150 full-run px in rig px), naming the layer, its pixels and the
365
+ rule that left it out.
362
366
  Writes nothing unless every check passed.
363
367
  --seam defaults to ${DEFAULT_SEAM_RULE}. --project says where a layer takes
364
368
  the painting's pixel: core (the reference's) erodes every layer's top-most
@@ -371,7 +375,11 @@ usage:
371
375
  Print {plan, extend_below_crop, notes} for config.assemble, from the two
372
376
  runs. A layer \`layers\` WARNs about (PLAN_LAYER_TRANSLUCENT,
373
377
  PLAN_LAYER_BACKGROUND, PLAN_LAYER_OVERSIZED) is not proposed, and a note
374
- names it, its figures and the rule. Reads only config.seethrough.head_box,
378
+ names it, its figures and the rule. A full-run layer holding a body no
379
+ planned part covers (a lock the head run's part does not reach and
380
+ extend_below_crop cannot continue) is named in a note with the body, the
381
+ rule that skipped it and the continuation; the plan itself is not
382
+ changed. Reads only config.seethrough.head_box,
375
383
  config.seethrough.resolution and config.assemble.rig_scale — the rest of
376
384
  the config need not exist yet.
377
385