@rig-c/parts 0.0.0-stage → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +134 -0
  3. package/README.md +433 -2
  4. package/bin/rig-parts.cjs +43 -0
  5. package/cli.ts +1240 -0
  6. package/docs/AUTHORING.md +2387 -0
  7. package/docs/MIGRATION.md +150 -0
  8. package/docs/STABILITY.md +262 -0
  9. package/package.json +70 -4
  10. package/skills/rig-parts/SKILL.md +167 -0
  11. package/src/apng.ts +381 -0
  12. package/src/assemble.ts +2259 -0
  13. package/src/autoamplitude.ts +194 -0
  14. package/src/autoenvelope.ts +404 -0
  15. package/src/automesh.ts +585 -0
  16. package/src/automotion.ts +447 -0
  17. package/src/autoreplay.ts +516 -0
  18. package/src/build.ts +1240 -0
  19. package/src/check.ts +2942 -0
  20. package/src/comfy/client.ts +245 -0
  21. package/src/comfy/index.ts +19 -0
  22. package/src/comfy/painting.ts +136 -0
  23. package/src/comfy/seethrough.ts +171 -0
  24. package/src/config.ts +2283 -0
  25. package/src/contour.ts +1901 -0
  26. package/src/coords.ts +26 -0
  27. package/src/diagnostics.ts +198 -0
  28. package/src/errors.ts +39 -0
  29. package/src/gif.ts +213 -0
  30. package/src/graphs.ts +302 -0
  31. package/src/headbox.ts +173 -0
  32. package/src/heat.ts +313 -0
  33. package/src/inputs.ts +100 -0
  34. package/src/instruments.ts +1145 -0
  35. package/src/keypoints.ts +296 -0
  36. package/src/layers.ts +598 -0
  37. package/src/localweights.ts +217 -0
  38. package/src/mesh.ts +362 -0
  39. package/src/motion.ts +311 -0
  40. package/src/palette.ts +208 -0
  41. package/src/parts.ts +410 -0
  42. package/src/propose.ts +2540 -0
  43. package/src/pyfmt.ts +135 -0
  44. package/src/raster/blur.ts +80 -0
  45. package/src/raster/components.ts +165 -0
  46. package/src/raster/composite.ts +81 -0
  47. package/src/raster/index.ts +9 -0
  48. package/src/raster/morph.ts +116 -0
  49. package/src/raster/png.ts +82 -0
  50. package/src/raster/poly.ts +166 -0
  51. package/src/raster/resize.ts +301 -0
  52. package/src/raster/types.ts +89 -0
  53. package/src/raster/warp.ts +121 -0
  54. package/src/requirements.ts +1240 -0
  55. package/src/rig.ts +1440 -0
  56. package/src/round.ts +62 -0
  57. package/src/scene.ts +1414 -0
  58. package/src/sheet.ts +128 -0
  59. package/src/skeleton.ts +400 -0
  60. package/src/structure.ts +858 -0
  61. package/src/tags.ts +121 -0
  62. package/src/weights.ts +124 -0
  63. package/workflows/seethrough.json +68 -0
@@ -0,0 +1,150 @@
1
+ # Migrating from 0.16.0
2
+
3
+ 0.16.0 was the last version published under the package's former name. This page is
4
+ what changed between it and 1.0.0 for a user of the command, an author of a config
5
+ and a reader of the files a build writes; what 1.0.0 holds stable is
6
+ [STABILITY.md](STABILITY.md). It comes in two parts: 0.16.0 to the release candidate
7
+ 1.0.0-rc.1, then what landed between the candidate and 1.0.0. Every figure is quoted
8
+ from the pull request that measured it.
9
+
10
+ ## In one paragraph
11
+
12
+ Install `@rig-c/parts` (the package's name after 1.5.3; *After 1.5.3* below). A
13
+ config that built on 0.16.0 loads and builds unchanged: every config change since is
14
+ a new, opt-in field inside a new mesh mode. The bytes a config without that mode
15
+ builds moved once, by a declared exception (every mesh triangle's vertex order,
16
+ #133); apart from it, each change since 0.16.0 that touched the code was measured
17
+ against the tree before it on the three public examples' builds, and moved no byte
18
+ of them. Inside the automatic mode, one change after the candidate moves declared
19
+ bytes, named in *Since 1.0.0-rc.1*: the skinning envelope's reference (#169).
20
+
21
+ ## From 0.16.0 to 1.0.0-rc.1
22
+
23
+ ### The package name
24
+
25
+ | | 0.16.0 | 1.0.0-rc.1 and 1.0.0 |
26
+ | --- | --- | --- |
27
+ | npm package | the former name | `rig-parts`; the alias `spine-parts` is published beside it at every version, the same files with only the `name` in `package.json` changed |
28
+ | command | the former name | `rig-parts`; the install also keeps the alias `spine-parts` as a second command on the same launcher, for the transition |
29
+ | repository | the former repository name (GitHub redirects it) | `firejune/rig-parts` |
30
+ | selftest variables | the `SPINE_PARTS_` names | `RIG_PARTS_CORPUS`, `RIG_PARTS_SELFTEST_JOBS`, each read first, with the former `SPINE_PARTS_` name read when it is not set |
31
+ | spec ids of the files authors write and this package writes | `spine-parts-requirements/1`, `spine-parts-scene/1`, `spine-parts-keypoints/1`, `spine-parts-bonemap/1`, `spine-parts-basis/1`, `spine-parts-scene-report/1` | unchanged: they name a file format, not the tool, so a file written before the rename still reads |
32
+ | public examples repository | `spine-parts-examples` | unchanged (it keeps the name it was published under) |
33
+
34
+ What to do: install with `npm install -g @rig-c/parts` and write `rig-parts` in scripts.
35
+ A script or a dependant that names the alias `spine-parts` keeps working and keeps
36
+ receiving every release; how long the alias stays is RELEASING.md's *The alias stays
37
+ until its retirement questions have written answers*. No build output carries the
38
+ package name: a grep of all 330 files the three example builds write found neither
39
+ spelling (#142). The console does: the lines that name the tool (5 per build: the
40
+ `build`, `assemble`, `rig` twice and `check` lines) now say `rig-parts`. Where a
41
+ config uses a constraint or `--idle-keys direct`, the `why` prose this package writes
42
+ into `rig.json`'s invariants names `rig-parts` too; that prefix is the one known
43
+ output change of the rename (#142).
44
+
45
+ ### rig-c, as this package sees it
46
+
47
+ The dependency is `rig-c` `^2.33.0` at 1.0.0 (`^2.31.0` at 1.0.0-rc.1; the moves
48
+ between the two are in *Since 1.0.0-rc.1*), where 0.16.0 took the same upstream
49
+ package under its former npm name at `^2.15.0`; that name is spelled only in `CHANGELOG.md`.
50
+ The upstream package was renamed on npm at 2.20.4 with the same `exports` map
51
+ (#138), and every import, probe and sentence here names `rig-c`. A project that
52
+ installed the former upstream name beside this package installs nothing more:
53
+ `rig-c` comes as a dependency. No Spine runtime is a dependency, as in 0.16.0.
54
+
55
+ ### The config
56
+
57
+ **A config that built on 0.16.0 loads unchanged.** The loader's only change between
58
+ the two is one more optional key, `auto`, on `meshes.<part>`, and the objects under it;
59
+ no key was removed, renamed or made required outside it, and no CLI flag was added or
60
+ removed (`git diff v0.16.0` of `src/config.ts` and `cli.ts`). `grid` and `contour`
61
+ meshes read exactly as before, and `propose` still writes `grid`.
62
+
63
+ What an author who adopts the new mode meets (AUTHORING §3, *An automatic mesh*):
64
+
65
+ - **`meshes.<part>.auto`**, the third mesh mode (#131): the contour mesh at alpha 1
66
+ and above, reduced and locally refined by rig-c's `reduceMesh` under declared
67
+ bounds. Exactly one of `grid`, `contour` and `auto` per mesh.
68
+ - **`motion` is required in it** (#134): at least `maxLocalDeformation`, the bound
69
+ the reduced mesh's motion against its unreduced source on the idle must meet
70
+ before the part is written. A part the idle cannot deform is refused, never
71
+ passed.
72
+ - **`maxOvershoot` and `maxUndercut` take `null`** (#139), in `sourceBounds` and in
73
+ `targets.artFit`: measured and reported, not bounded. Leaving the field out is
74
+ still refused by name.
75
+ - **The acceptance loop** (#141) replays a less-reduced step when the motion gate
76
+ refuses the full reduction; it needs no field. **`motion.selection`** (#151,
77
+ opt-in) replaces its bisection with a budgeted multi-interval search.
78
+ - **The Stage B opt-ins** (#147): `boundaryRuns`, `retriangulate`, `removalOrder`.
79
+ - **`motion.gradation`** (#150, opt-in): the author's G for rig-c's allocation
80
+ contrast row.
81
+ - **`motion.residual`** (#152, opt-in): the skinning residual as a per-step veto.
82
+
83
+ Without any of these the mode's output is what it was before each was added: every
84
+ pull request that added one compared the opt-out run against the tree before it,
85
+ byte for byte.
86
+
87
+ ### The bytes a build writes
88
+
89
+ | change | what moved | measured |
90
+ | --- | --- | --- |
91
+ | #131, the automatic mode | nothing for a config without `auto` | 330 of 330 files of the three example builds identical, main at rig-c 2.15.0 against the change at 2.19.0 |
92
+ | #133, the winding | **the declared exception**: every mesh `triangles` triple `[a, b, c]` is written `[a, c, b]` (counter-clockwise in Spine world), in `rig.json`, the compiled `skeleton.json`, `skeleton.model.json` and the render's `geometry.json`; the `TEXTURE_STRETCH` entries in `check.json` that print a triangle's vertices and edge print them in that order; `spine.sha256` follows the skeleton bytes | every rendered PNG byte-identical before and after; the triangle index, the unordered edge, the frame, the ratio and the severity unchanged |
93
+ | #134, #137 to #142, #146, #147, #150, #152 | nothing | 330 of 330 at each, against the tree before it; the console differs in the one `rigc <version>` line per build where rig-c moved |
94
+ | #172 unit 1b, one mask under `stray` | nothing for a part without `auto.source.stray`; a part that declares it now builds where its extra islands at or under the figure refused it (`REDUCE_SOURCE_FAILS_ITS_ART_BOUNDS`): the islands are cleared from the art every reader of the mesh takes, and its row gains `stray_cleared` (islands, pixels, art pixels) and its mesh line a `stray cleared` clause; the written image is the part as assembled | the selftest's `SY01`–`SY06` on a synthetic crumb part; a part without `stray` reads the very mask object it read before (`SY03`) |
95
+ | #151, the multi-interval selection | nothing without `motion.selection` | measured on the selftest's fixture configs, not the example builds: rig.json, motion.json, mesh_report.json and the printed log identical in all six configurations; #152 then measured the example builds against the tree #151 left, 330 of 330 |
96
+
97
+ What to do: a consumer that compares a build with one 0.16.0 wrote, byte for byte,
98
+ expects the #133 exception and nothing else; one that reads the meshes (a renderer,
99
+ a culling pass, rig-c's own orientation rows) now reads every triangle
100
+ counter-clockwise in Spine world, as rig-c writes its own. Spine does not cull, so
101
+ nothing draws differently.
102
+
103
+ ## Since 1.0.0-rc.1
104
+
105
+ Every change below is additive to the interface: a field that was refused is now
106
+ accepted, or a build that was refused now builds; nothing a 1.0.0-rc.1 config could
107
+ say is removed or reads differently, outside the declared byte move below. No CLI
108
+ flag was added or removed.
109
+
110
+ - **Density-only regions** (#156, opt-in): an `auto.regions` entry may leave out both
111
+ `bone` and `band` to ask rig-c for density without touching any weight. One without
112
+ the other is refused by name (`CONFIG_REGION_BAND_NEEDS_BONE`,
113
+ `CONFIG_REGION_BONE_NEEDS_BAND`; at 1.0.0-rc.1 the same input was refused
114
+ `CONFIG_FIELD_PRESENT`, naming the missing field), and a region with both reads as
115
+ before. A config without such a region builds as before.
116
+ - **The skinning envelope's reference** (#169), **the declared byte move**: under
117
+ `motion.residual`, the envelope rig-c's reducer is sent is derived against the
118
+ lowest common ancestor of the slot's bone and every bone the part's weights bind,
119
+ where 1.0.0-rc.1 derived it against the slot's bone and, when a bound bone did not
120
+ hang below it, sent no target, so the residual veto did not apply. Such a part's
121
+ reduction, written mesh and `mesh_report.json` row move; a part whose bound bones
122
+ all hang below the slot's bone makes the same call as before. The
123
+ `skinning_residual` row keeps its shape: its `reference` names the bone the envelope
124
+ was derived against, and a part whose reference is not the slot's bone carries a
125
+ second `rule` sentence naming the rule. `ENVELOPE_BONE_NOT_BELOW_REFERENCE` keeps
126
+ its name and its check.
127
+ - **rig-c `^2.33.0`** (#163, #166, #173, from `^2.31.0`): 2.32.1 refuses, by name, a
128
+ refinement insertion whose triangle would read as degenerate (`MQ_DEGENERATE`)
129
+ instead of writing it (rigc#1311); 2.32.2 no longer misrefuses a motion sample on an
130
+ edge two triangles share (`COMPARE_UV_CARRIER_NOT_UNIQUE`, rigc#1323); 2.33.0 adds
131
+ named interior lines, which this package does not send. The three example builds
132
+ are byte-identical across the move (#173).
133
+
134
+ What to do: nothing for a config without `auto`. A config under `auto` that declares
135
+ `motion.residual` may write a different mesh than 1.0.0-rc.1 did, as above; a
136
+ consumer that compares builds byte for byte with 1.0.0-rc.1 expects that move and
137
+ nothing else.
138
+
139
+ ## After 1.5.3: the scoped name
140
+
141
+ | | 1.0.0 to 1.5.3 | after 1.5.3 |
142
+ | --- | --- | --- |
143
+ | npm package | `rig-parts` | `@rig-c/parts`; `rig-parts` and the alias `spine-parts` are published beside it at every version as aliases, the same files with only the `name` in `package.json` changed |
144
+ | command | `rig-parts`, and the alias `spine-parts` on the same launcher | unchanged |
145
+ | repository | `firejune/rig-parts` (GitHub redirects it) | `rig-c/parts`, beside `rig-c/core` (npm `rig-c`) and `rig-c/play` |
146
+ | spec ids, the config, the bytes a build writes | | unchanged |
147
+
148
+ What to do: install with `npm i -D @rig-c/parts` (or `npm install -g @rig-c/parts`);
149
+ command lines do not change. A dependant that names `rig-parts` keeps receiving
150
+ every release under it (#222).
@@ -0,0 +1,262 @@
1
+ # Interface stability
2
+
3
+ This page states what **1.0.0 holds stable**, and what it does not. Every item is
4
+ read off the tree: the command and flag lists below are held to
5
+ `cli.ts`, and the config field list to the loader in `src/config.ts`, by the
6
+ selftest's `TY13` and `TY14` (the `tree` suite), so neither list can drift from the
7
+ code without a red run. What changed for an author coming from 0.16.0 is
8
+ [MIGRATION.md](MIGRATION.md).
9
+
10
+ ## What "stable" means here
11
+
12
+ From 1.0.0 the package follows semantic versioning over the items on this page. A
13
+ stable item is not removed, renamed, or given another meaning inside a major
14
+ version; a new command, flag, optional config field, report key or refusal may
15
+ arrive in a minor version, because a reader written against the old surface still
16
+ reads it. A refusal may be retired in a minor version when what it refused becomes
17
+ accepted (0.13.0 retired two ik refusals that way, when rig-c's parser took them
18
+ over).
19
+
20
+ The list was frozen for review at the release candidate 1.0.0-rc.1, and 1.0.0 was
21
+ promoted from it after the owner's acceptance of the production evidence (issue #126,
22
+ item 7; `docs/evidence/production-trial.md` in the repository). Every interface
23
+ change between the two is additive, and [MIGRATION.md](MIGRATION.md)'s *Since
24
+ 1.0.0-rc.1* names each one, with the build bytes that moved.
25
+
26
+ Bytes are a separate promise, and a narrower one: **one version of this package
27
+ with one installed rig-c writes the same bytes for the same inputs** (*Determinism*
28
+ below). A build's bytes are not promised across versions. A later version may move
29
+ them, and when it does, the change that moves them declares which bytes and why (the
30
+ winding change of #133 is the example: [MIGRATION.md](MIGRATION.md)).
31
+
32
+ ## Commands and flags
33
+
34
+ Exit codes are part of the interface: **0** the command did what it says, **1** it
35
+ refused its input (every reason a `FAIL` line), **2** a usage error or a command
36
+ this version does not implement. No command is unimplemented at 1.0.0 (`LATER`
37
+ in `cli.ts` is empty). A refusal line has the shape
38
+ ` FAIL <RULE>: <object> — <value found>; <value required>`: the rule name is a
39
+ stable identifier, and the detail after it is prose that may be reworded. A command
40
+ also answers to the alias `spine-parts` as long as the install keeps it
41
+ ([MIGRATION.md](MIGRATION.md)). `-h`, `help` and `-v` are the short forms of
42
+ `--help` and `--version`. The flags' meanings are `rig-parts --help`'s; their
43
+ defaults are the help's too, and none is guessed from the art.
44
+
45
+ <!-- stable:commands -->
46
+ | command | flags |
47
+ | --- | --- |
48
+ | `layers` | one positional path: a wrapper directory, a `layers.json` or a `.psd` |
49
+ | `sheet` | `--source`, `--layers` (repeatable), `--out`; optional `--cell`, `--cols` |
50
+ | `inputs` | `--source`, `--config`, `--out` |
51
+ | `comfy` | `paint`: `--config`, `--out`; optional `--seeds`, `--seed0`, `--host`, `--wait`, `--timeout`, `--poll` |
52
+ | `comfy` | `seethrough`: `--image`, `--out`; optional `--resolution`, `--steps`, `--seed`, `--prefix`, `--offload`, `--lama`, `--nf4`, `--host`, `--wait`, `--timeout`, `--poll` |
53
+ | `assemble` | `--propose-plan` with `--source`, `--full`, `--head`, `--config`; or `--source`, `--full`, `--head`, `--config`, `--out`, optional `--seam` (near-white, silhouette), `--project` (core, visible) |
54
+ | `propose` | `--head-box` with `--full`, `--canvas` |
55
+ | `propose` | `--parts`, `--source`, `--out`; optional `--compare` or `--from-config` (one of them), `--keypoints`, `--person` and `--wrist-snap` (each with `--keypoints`) |
56
+ | `compare` | `--left`, `--right`; optional `--map` |
57
+ | `rig` | `--config`, `--parts`, `--out`; optional `--idle-keys` (ctl, direct), `--page-edges` (pot, free), `--pack-shape` (rect, polygon) |
58
+ | `check` | `--rig`, `--out`; optional `--parts`, `--source`, `--page-edges`, `--pack-shape`, `--requirements`, `--seam-pairs`, `--keep-stills` |
59
+ | `loop` | `--frames`, `--out`; optional `--palette` |
60
+ | `build` | `--config`, `--source`, `--full`, `--head`, `--out`; optional `--seam`, `--project`, `--page-edges`, `--pack-shape`, `--loop`, `--requirements`, `--idle-keys` |
61
+ | `compose` | `--scene`, `--out`; optional `--requirements`, `--accept` |
62
+ | (none) | `--version`, `--help` |
63
+ <!-- /stable:commands -->
64
+
65
+ `TY13` holds the first column to the commands `cli.ts` dispatches and the set of
66
+ flags named anywhere in the table to the set of flags `cli.ts` spells. It holds the
67
+ names, not which command takes which flag: that pairing is the CLI's, and the `cli`
68
+ suite's controls read it from the help.
69
+
70
+ ## The config contract
71
+
72
+ `src/config.ts` is the schema and the loader, and
73
+ [AUTHORING §3](AUTHORING.md#3-configjson-field-by-field) explains every field. The
74
+ rules that make the contract:
75
+
76
+ - **Every key is known or refused** (`CONFIG_KEY_KNOWN`), a required key that is
77
+ missing is refused by name (`CONFIG_FIELD_PRESENT`), and nothing is defaulted
78
+ from the art. A field absent where absence means "none" (a contour's `stray`, an
79
+ automatic mesh's `minAngle`) is written as that in the report, never filled in.
80
+ - **Two open doors, and nothing reads behind them**: `note` and any key ending in
81
+ `_note` hold a string anywhere an object is; any key beginning `x-` with a name
82
+ after it holds any JSON value in the same places. They are not open in `meshes`,
83
+ `regions` or `motion.blink.still`, whose keys are part names.
84
+ - **Coordinates** in `bones`, `meshes` and `motion` are rig pixels, y down, origin
85
+ top-left.
86
+ - **A mesh is one of three modes**: `grid` (the lattice, what `propose` writes),
87
+ `contour` (the traced outline with declared interior points) or `auto` (the
88
+ automatic mode: the contour mesh at alpha 1 and above reduced by rig-c's
89
+ `reduceMesh` under declared bounds, written only when its motion against the
90
+ unreduced source passes the author's bounds). Two, or none, is
91
+ `CONFIG_MESH_MODE`. The top-level default does not change: `propose` writes
92
+ `grid`, and a config that names no `auto` builds as it did before the mode
93
+ existed.
94
+ - **`constraints`** are rig-c's own rig-spec constraints (`RigConstraint` in
95
+ rig-c's `src/rig.ts`), handed to rigc as written; this loader checks their
96
+ `type`, their `name` and that every bone they name resolves.
97
+
98
+ The fields, object by object (a bold path is where the object sits; `<part>` is a
99
+ part name, `[i]` an entry of a list):
100
+
101
+ <!-- stable:config -->
102
+ - **config** — required by the full loader, in front of rig and build: `key`, `assemble`, `bones`, `meshes`, `regions`, `motion`; optional: `generation`, `seethrough`, `constraints`
103
+ - **generation** — required: `checkpoint`, `loras`, `trigger`, `identity`, `sampler`, `costume`, `negative_extra`, `style`, `negative_pose`, `latent`, `seed`; optional: `pose`, `control`
104
+ - **generation.loras[i]** — required: `name`, `strength`; optional: `strength_clip`
105
+ - **generation.sampler** — required: `steps`, `cfg`, `sampler`, `scheduler`
106
+ - **generation.control** — required: `skeleton`, `strength`, `end_percent`; optional: `model`
107
+ - **generation.control.skeleton**, the pose file it names when it is no built-in — required: `width`, `height`, `points`
108
+ - **seethrough** — required: `resolution`, `steps`, `seed`, `offload`; optional: `head_box`
109
+ - **assemble** — required: `rig_scale`, `plan` (from plain `assemble` on); optional: `extend_below_crop`, `patches`, `cuts`
110
+ - **assemble.extend_below_crop[i]** — required: `part`, `run`, `tag`
111
+ - **assemble.patches[i]** — required: `name`, `box`, `alpha`, `draw`
112
+ - **assemble.patches[i].draw**, when an object — required: `before`
113
+ - **assemble.cuts[i]** — required: `from`, `into`, `polygon`, `draw`, `overlap`; optional: `under`
114
+ - **assemble.cuts[i].draw**, when an object — required: `before`
115
+ - **bones[i]**, a single bone — required: `name`, `parent`, `at`; optional: `tip`
116
+ - **bones[i]**, a chain — required: `chain`, `parent`, `points`, `tip`
117
+ - **meshes.&lt;part&gt;** — exactly one of `grid`, `contour`, `auto`; required in every mode: `r`, `segments`; optional in every mode: `exponent`, `rule`; optional with `contour` or `auto`: `ribs`
118
+ - **meshes.&lt;part&gt;.ribs.&lt;chain&gt;** — required: `stations`
119
+ - **meshes.&lt;part&gt;.contour** — required: `tolerance`, `margin`, `spacing`; optional: `budget`, `stray`, `regions`
120
+ - **meshes.&lt;part&gt;.contour.regions[i]** — required: `name`, `shape`, `bone`, `spacing`, `band`, and `cx`, `cy`, `r` for a circle or `points` for a polygon
121
+ - **meshes.&lt;part&gt;.auto** — required: `source`, `sourceBounds`, `targets`, `influences`, `budget`, `minArtSamples`, `motion`; optional: `protect`, `regions`, the three Stage B opt-ins `boundaryRuns`, `retriangulate`, `removalOrder`, and `stimulus`
122
+ - **meshes.&lt;part&gt;.auto.source** — required: `tolerance`, `margin`, `spacing`; optional: `stray`
123
+ - **meshes.&lt;part&gt;.auto.sourceBounds** and **meshes.&lt;part&gt;.auto.targets.artFit** — required: `minCoverage`, `maxOvershoot`, `maxUndercut` (each of the last two a number or null, the bound declared absent)
124
+ - **meshes.&lt;part&gt;.auto.targets** — required: `artFit`, `maxBoundaryDeviation`; optional: `minAngle`
125
+ - **meshes.&lt;part&gt;.auto.influences** — required: `maxInfluences`, `minWeight`
126
+ - **meshes.&lt;part&gt;.auto.budget** — required: `maxCandidates`
127
+ - **meshes.&lt;part&gt;.auto.motion** — required: `maxLocalDeformation`; optional: `maxStretch`, `minStretch`, `deformMayFold`, `gradation`, `selection`, `residual`
128
+ - **meshes.&lt;part&gt;.auto.motion.selection** — required: `policy`, `maxProbes`
129
+ - **meshes.&lt;part&gt;.auto.motion.residual** — required: `maxResidual`
130
+ - **meshes.&lt;part&gt;.auto.protect** — optional: `hull`, `vertices`, `edges`, `regionBoundaries`, `weightJump`, `influences`
131
+ - **meshes.&lt;part&gt;.auto.regions[i]** — required: `name`, `shape`, `maxEdgeLength`, `transition`, `grade`, `minArtSamples`, and `cx`, `cy`, `r` for a circle or `points` for a polygon; optional: `bone`, `band` (both or neither; with neither the region is density only)
132
+ - **meshes.&lt;part&gt;.auto.boundaryRuns** — required: `maxVertices`
133
+ - **meshes.&lt;part&gt;.auto.stimulus**, or each entry of it when a list — required: `chain`, `degrees`
134
+ - **regions.&lt;part&gt;** — a bone name
135
+ - **motion** — required: `duration`, `tracks`; optional: `blink`, `animations_from`
136
+ - **motion.tracks[i]**, a single track — required: `bone`, `prop`, `amp`, `period`, `phase`; optional: `base`
137
+ - **motion.tracks[i]**, a chain track — required: `chain`, `amps`, `period`, `phase`, `lag`
138
+ - **motion.blink** — required: `t`, `eyes`, `squash`; optional: `brows`, `brow_drop`, `still`
139
+ - **motion.blink.still.&lt;part&gt;** — required: `row`, `bone`
140
+ - **motion.animations_from**, the file it names — required: `spec`, `animations`
141
+ - **proposal.json**, the file propose writes — `bones`, `meshes`, `regions`, `motion` under the rules above, and `notes`
142
+ <!-- /stable:config -->
143
+
144
+ `TY14` holds the set of field names in backticks above to the set of names the
145
+ loader's object checks spell (every `c.object(…)` in `src/config.ts`, with the lists
146
+ they name), in both directions, and refuses an object check whose key list it cannot
147
+ read. It holds the names, not their nesting or which are required: the `config`
148
+ suite's controls hold those, refusal by refusal.
149
+
150
+ The values a field takes (`retriangulate` is "delaunay", `removalOrder`
151
+ "deformation-load", `selection.policy` "multi-interval"; the units and ranges of
152
+ every number) are AUTHORING §3's tables, and the loader refuses any other by name.
153
+
154
+ ## Files this package writes
155
+
156
+ | file | written by | what is stable |
157
+ | --- | --- | --- |
158
+ | `parts.json`, `parts/<name>.png` | `assemble`, `build` | one record per part: `from`, the box `x`, `y`, `w`, `h` (rig px), the pixel counts `src/parts.ts` documents (`opaque_px`, `visible_px`, `occluded_px`, `projected_core_px`, `source_px_taken`, `visible_not_projected_px`, `refused_drift_px`, `merged_px`, `seam_override_px`, and `fringe_pushed_back` when not empty); `rig_size`, `scale_rig_per_source`, `ghost_px`, `recomposite` |
159
+ | `rig/rig.json`, `rig/motion.json`, `rig/images/` | `rig`, `build`, `compose` | rig-c's rig spec and motion spec, `spec` `rigc-rig/1` and `rigc-motion/1`: the format is rig-c's, and this package writes only what rig-c's parser accepts |
160
+ | `rig/mesh_report.json` | `rig`, `build` | one row per mesh: `part`, `vertices`, `triangles`, `hull`, `bones`, `max_influences`, `mean_influences`, `art_coverage`, then `grid` (a lattice); `mode` "contour" with `params`, `contour`, `regions`; or `mode` "auto" with `settings`, `source`, `result`, `residuals`, `worst_residual`, `worst_region`, `motion_amplitude`, `termination`, `weights`, `regions`, `deformation`, `quality_report` (rig-c's `mesh-quality-report/1` document whole), `motion_report`, and, only when they apply, `stray_cleared` (after `source`, when `source.stray` is declared), `skinning_residual` and `replay` (`AutoMeshReport` in `src/rig.ts`); in every mode, `exponent` when the mesh declares one (after `grid`, or after `mode`); `ribs` when a contour or auto mesh declares them (after `exponent`, or after `mode`), and then `contour.ribs` (`source.contour.ribs` in the automatic mode) |
161
+ | `check/check.json` and the rest of `check/` | `check`, `build`, `compose` | the reference's fields in its order (`gate_spine_html_green`, `rigc_entry`, `pack_mode`, `loop_max_diff`, the seam figures — `seam_mean`, `seam_px_over_40`, `seam_px_over_80` and, from issue #216, `seam_frame_scale`, the frame scale the bar divides the count by), `loop_physics` after `loop_max_diff` when the rig declares a physics constraint, `seam_pairs` after the seam figures when the seam bar fails or `--seam-pairs` asks (each row's picture under `check/seam/`; `--keep-stills` leaves the setup-pose still and its `frames.json` under `check/setup_still/`), then the judgement lines (`BREATH_VISIBLE`, `BLINK_NO_HOLE`, `CHAIN_LAG`, `TIP_OVER_ROOT`, `STILL_REGIONS_DARK`, `TEXTURE_STRETCH`), `RECOMPOSITE_HOLES`, `SETUP_POSE_VS_SOURCE`, `skipped`, a `requirements` block under `--requirements`, and `PASS`; `check/build/skeleton.json`, `.atlas` and `.png` are the packed artifact rig-c writes |
162
+ | `proposal.json`, `render/landmarks*.png` | `propose` | the config's four rig sections and `notes` |
163
+ | `basis.json` | `propose` | spec `spine-parts-basis/1` |
164
+ | the scene report | `compose` | spec `spine-parts-scene-report/1` |
165
+ | `idle.png`, `idle-indexed.png`, `idle.gif` | `loop`, `build --loop` | APNG and GIF encodings of the rendered idle |
166
+
167
+ Files authors write for this package, each with a spec id the reader holds:
168
+ `spine-parts-requirements/1` (`check --requirements`), `spine-parts-scene/1`
169
+ (`compose --scene`), `spine-parts-keypoints/1` (`propose --keypoints`),
170
+ `spine-parts-bonemap/1` (`compare --map`). The spec ids keep the package's former
171
+ name on purpose: they name a file format, not the tool, and a file written before
172
+ the rename still reads. They do not change at 1.0.
173
+
174
+ ## Environment
175
+
176
+ The installed package reads two environment variables and no other: `PATH`, where
177
+ the launcher finds Bun and the CLI finds the `rigc` its own `node_modules` holds,
178
+ and `COMFY_HOST`, which `comfy paint` and `comfy seethrough` read when `--host` is
179
+ not given (it has no default). `RIG_PARTS_CORPUS` and `RIG_PARTS_SELFTEST_JOBS`,
180
+ with their former `SPINE_PARTS_` names read when they are not set, are the
181
+ selftest's, a development interface of this repository: the selftest does not ship
182
+ in the package.
183
+
184
+ ## rig-c
185
+
186
+ `dependencies` takes `rig-c` `^2.33.0`: 2.33.0 or any later 2.x. Bun 1.2 or later
187
+ runs the package (`engines`). What this package relies on in rig-c, every import
188
+ read off `src/` and `cli.ts`:
189
+
190
+ - the named entries `rig-c/mesh` (the outline functions, `measureAuthoredMeshFit`,
191
+ `reduceMesh`, `skinningEnvelopeBone`, `writeMeshQualityReport` and their types)
192
+ and `rig-c/meshcompare` (`compareMeshesInMotion`);
193
+ - the deep paths its `exports` map carries: `rig-c/src/rig.ts` (`parseRigSpec`,
194
+ `RIG_SPEC_VERSION`, the constraint keys), `rig-c/src/errors.ts`,
195
+ `rig-c/src/png.ts`, `rig-c/src/transform.ts` (the y flip, through
196
+ `src/coords.ts` only), `rig-c/tools/plate.ts` (the PNG codec) and
197
+ `rig-c/tools/font5x7.ts`;
198
+ - the `rigc` command: `build` and `render`, and `--version`, whose `entry:` line
199
+ says which validator gated a build (`check.json`'s `rigc_entry`).
200
+
201
+ A rig-c release that moves any of these breaks this package by name, and the
202
+ install smoke is where that shows first. No Spine runtime is a dependency: an
203
+ install is gated by rigc's own validator, and `@esotericsoftware/spine-core` is a
204
+ development dependency of this repository only.
205
+
206
+ ## What is not stable
207
+
208
+ - **The evidence documents** under `docs/evidence/`: their layout, columns and
209
+ figures are a measurement record of one tree on one rig-c, regenerated when the
210
+ tools or rig-c move.
211
+ - **The tools** under `tools/` (the matrix, the surveys, the comparisons) and their
212
+ command lines, and the scripts under `scripts/`.
213
+ - **The selftest**: its control names, counts and line wording.
214
+ - **Console prose** beyond the shapes above: the detail after a rule name, the
215
+ wording of a note, the order of informational lines.
216
+ - **The examples' `expected/` outputs**: they are this repository's regression
217
+ record and move with any change that declares a byte move.
218
+ - **Bytes across versions**, as stated at the top.
219
+
220
+ ## Bounded time, and what the checks cost
221
+
222
+ The automatic mode's search is bounded by counts the author declares or the call
223
+ derives, never by a clock (`src/` reads none): rig-c's `reduceMesh` tries at most
224
+ `budget.maxCandidates` steps, the acceptance loop replays at most ⌈log₂(N − I)⌉
225
+ removal steps (N the call's accepted operations, I the refinement's), and the
226
+ multi-interval selection at most `motion.selection.maxProbes`, each replay one
227
+ unpacked gated build and one motion comparison. Wall time is therefore a property of
228
+ the input and the machine. Measured: the evidence tools run every cell under a
229
+ 600 s cap and a whole matrix under 2,700 s (`docs/evidence/auto-mesh-matrix.md`,
230
+ *re-running*); one `reduceMesh` call on the public parts took 0.7 s to 10.7 s at
231
+ rig-c 2.23.0 (the same document's quiet timing table, a remote WSL runner, pool,
232
+ load under 2); at rig-c 2.31.0 the whole rig stage of one automatic part, motion
233
+ gate and acceptance loop included, took 1.1 s to 61.6 s on the eight parts the
234
+ surveys switch, demo `bottomwear` the slowest at 12 gated builds, with a run-to-run
235
+ spread of ±15 % on that part (pull request #152's paired exclusive timing, remote
236
+ 20-core runner; the surveys print wall time to standard error, not into the
237
+ documents). On CI (`ubuntu-latest`), the last two green runs on `main` took 4 min
238
+ 54 s and 8 min 28 s for the full selftest (842 controls over 45 suites at
239
+ `22b2c5a`, with the public examples fetched; the job's limit is 20 minutes) and
240
+ 42 s and 41 s for the install smoke (6 cases; limit 10 minutes), at `8be4cd1` and
241
+ `22b2c5a` respectively. None of these figures is a promise: they are what the named
242
+ runs measured.
243
+
244
+ ## Determinism
245
+
246
+ The same inputs, with the same version of this package and the same installed
247
+ rig-c, write the same bytes: fixed key order in every JSON written, stable sorts, no
248
+ clock, no randomness and no locale-sensitive formatting. `src/` is pure outside
249
+ `src/comfy/` (`TY06` refuses a clock, randomness or network call anywhere else under
250
+ `src/`). The selftest holds it by running the same thing twice and comparing the bytes:
251
+ `PN01` (the PNG codec), `PT01` (`parts.json` round trip), `AS07` (`assemble`
252
+ from the CLI), `SK04` (the skeleton), `RG03` (two lattice builds), `CW20` and
253
+ `CT20` (a contour rig and a contour mesh), `AM24` (an automatic mesh), `MO11`,
254
+ `MO27`, `MO44`, `MO50`, `MO63` and `MO74` (the motion gate, the acceptance
255
+ loop's replay, every Stage B opt-in, a gradation, the multi-interval selection's
256
+ policy path and the residual veto), `CK02`, `CK33` and `CK79` (`check`, its
257
+ stretch geometry, and `check --requirements`), `DG13` (`basis.json`), `LP08`
258
+ (the indexed APNG) and `ST26` (the `compare` printout). With the public examples
259
+ fetched, the `chain` suite builds each of them and holds `parts.json`
260
+ (`CH02`), `rig.json`, `motion.json` and `mesh_report.json` (`CH03`),
261
+ `check.json` (`CH04`) and the gate file (`CH05`) to its tracked `expected/`,
262
+ field by field, with the tolerances `CH07` plants against.
package/package.json CHANGED
@@ -1,6 +1,72 @@
1
1
  {
2
2
  "name": "@rig-c/parts",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.5.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
+ "type": "module",
6
+ "bin": {
7
+ "rig-parts": "./bin/rig-parts.cjs",
8
+ "spine-parts": "./bin/rig-parts.cjs"
9
+ },
10
+ "engines": {
11
+ "bun": ">=1.2.0"
12
+ },
13
+ "license": "MIT",
14
+ "author": "firejune",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/rig-c/parts.git"
18
+ },
19
+ "homepage": "https://github.com/rig-c/parts#readme",
20
+ "bugs": "https://github.com/rig-c/parts/issues",
21
+ "keywords": [
22
+ "spine",
23
+ "spine2d",
24
+ "spine-2d",
25
+ "ai",
26
+ "ai-agents",
27
+ "rigging",
28
+ "character-rigging",
29
+ "character-parts",
30
+ "layer-decomposition",
31
+ "see-through",
32
+ "anime",
33
+ "live2d-alternative",
34
+ "weighted-mesh",
35
+ "skeletal-animation",
36
+ "psd",
37
+ "cli"
38
+ ],
39
+ "files": [
40
+ "bin/rig-parts.cjs",
41
+ "cli.ts",
42
+ "src",
43
+ "workflows",
44
+ "docs/AUTHORING.md",
45
+ "docs/MIGRATION.md",
46
+ "docs/STABILITY.md",
47
+ "skills",
48
+ "NOTICE.md"
49
+ ],
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "scripts": {
54
+ "fetch-examples": "bash scripts/fetch-examples.sh",
55
+ "selftest": "bun selftest.ts",
56
+ "smoke": "bun scripts/install_smoke.ts",
57
+ "typecheck": "bunx tsc --noEmit",
58
+ "lint": "bunx eslint .",
59
+ "prepublishOnly": "bun run typecheck && bun run lint && bun run selftest"
60
+ },
61
+ "dependencies": {
62
+ "ag-psd": "^31.0.2",
63
+ "rig-c": "^2.33.0"
64
+ },
65
+ "devDependencies": {
66
+ "@esotericsoftware/spine-core": "4.3.13",
67
+ "@types/bun": "^1.4.2",
68
+ "eslint": "^10.11.0",
69
+ "typescript": "^5.9.3",
70
+ "typescript-eslint": "^8.70.1"
71
+ }
72
+ }