@rig-c/parts 1.16.0 → 1.18.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/docs/MIGRATION.md CHANGED
@@ -210,3 +210,55 @@ no declared form changed.
210
210
  What to do: nothing for a config without `contour.bridges`. A part that declares it and
211
211
  holds a faint island no longer draws that island; if those pixels matter, keep the
212
212
  lattice for that part.
213
+
214
+ ## After 1.17.0: an artist's own file
215
+
216
+ Issue #359 makes an artist's layered PSD an input in its own right (AUTHORING §4,
217
+ *For artists* and *The correction loop*). Nothing a config already builds changes:
218
+ every new form was refused or a usage error before, so no byte any existing build
219
+ writes moves (the selftest's existing controls and the examples' `expected/` are
220
+ unchanged by it).
221
+
222
+ | change | before | after |
223
+ | --- | --- | --- |
224
+ | `assemble`, `--propose-plan` and `build` without `--head` | a usage error (exit 2) | one run: the full run must hold `face`, `eyewhite-r` and `eyewhite-l`, painted (`ASSEMBLE_SINGLE_RUN_FACE`); every row takes `"full"` (`ASSEMBLE_SINGLE_RUN_PLAN`); no `seethrough.head_box` (`ASSEMBLE_SINGLE_RUN_HEAD_BOX`) |
225
+ | `propose --full`/`--head` over runs with no depth on any part's layer (a PSD) | refused, `PROPOSE_TURN_DEPTH_PRESENT` on every part (exit 1) | no `turn`, one note `turn: SKIP — <runs> carry no depth_median …`, the proposal written (exit 0); a run where some parts' layers carry a depth and others do not is still refused part by part, and the detail now says so |
226
+ | a wrapper `layers.json` with `depth_median: null` | refused, `LAYERS_FIELD_PRESENT` | `null` on every drawn layer reads in the manifest's order; a mix is `LAYERS_DEPTH_ALL_OR_NONE` |
227
+ | a layer named `<layer>:hidden` | refused, `LAYERS_TAG_KNOWN` | a hidden-art layer, listed apart and never drawn; read as a cut's `under` and a limb segment's cap where the config names no file (`ASSEMBLE_HIDDEN_ONE_SOURCE` when it names one too) |
228
+ | `layers` on a PSD, or on a manifest with no depth | the table | the table and one `SKIP depth:` line naming the file |
229
+ | `parts.json`, a limb segment's `cap` | `image_px` with a cap file | `image_layer` after `image_px` when the image was a hidden-art layer |
230
+
231
+ What to do: nothing. A consumer that matched `PROPOSE_TURN_DEPTH_PRESENT` to detect a
232
+ PSD run reads the `turn: SKIP` note instead.
233
+
234
+ Issue #366 lets that one run be a file that is not square (AUTHORING §4, *For
235
+ artists*: the canvas). Two-run builds and a square file at `seethrough.resolution`
236
+ are read exactly as before — no `single_run_pad` block, no `padded:` line, the same
237
+ bytes (the selftest's existing single-run controls and the examples' `expected/` are
238
+ unchanged by it).
239
+
240
+ | change | before | after |
241
+ | --- | --- | --- |
242
+ | one run whose file is not the `resolution` square, no side above it | refused, `ASSEMBLE_RUN_CANVAS` | padded to the square, centred (the odd pixel right or bottom), and assembled in the file's pixels; `parts.json` ends with `single_run_pad` (`file_size`, `side`, `left`, `top`) and `assemble` prints a `padded:` line under `one run:` |
243
+ | one run whose file has a side above `resolution` | refused, `ASSEMBLE_RUN_CANVAS` | still refused by that code; the detail now says padding cannot shrink a file and names the resolution that would hold it |
244
+ | one run with a painting of another size than the file | read: the run mapped onto the painting at the painting's scale | refused, `ASSEMBLE_SINGLE_RUN_SOURCE` — §4 already required the same size |
245
+ | a `parts.json` with `single_run_pad` | refused, `PARTS_KEY_KNOWN` | read; a block that is not the centring, or disagrees with `rig_size`, is `PARTS_SINGLE_RUN_PAD` |
246
+
247
+ What to do: nothing, unless a single-run painting was not the file's own size — pass
248
+ the file flattened.
249
+
250
+ ### And a check before See-through (`painting`, issue #350)
251
+
252
+ A new command, `rig-parts painting --keypoints <k.json> [--person <id>]
253
+ <painting.png>`, reads a painting against its body-18 joints before See-through runs
254
+ and refuses what a rig cannot be cut from (arms against the body, hands together,
255
+ legs without a gap, a joint off the figure, a background that is not plain;
256
+ [PAINTING.md](PAINTING.md)). It reads the keypoint file `propose --keypoints` reads
257
+ and writes nothing; no other command changed, and no byte any build writes moves.
258
+
259
+ | change | before | after |
260
+ | --- | --- | --- |
261
+ | `rig-parts painting` | a usage error, `unknown command` (exit 2) | the check: exit 0 PASS, 1 with a `FAIL PAINTING_…` line per refusal |
262
+ | the README's input bullet for the painting | one sentence | the requirements, linked to `docs/PAINTING.md`, which ships in the package |
263
+
264
+ What to do: nothing. Run `painting` on a new painting before See-through.
@@ -0,0 +1,172 @@
1
+ # The painting: what makes one riggable
2
+
3
+ rig-parts starts from one painting of one character. Making that painting is
4
+ yours — on your own GPU, with any generator, or by hand — and this package runs
5
+ no model. But a painting the pipeline cannot rig fails late: a sleeve layer that
6
+ holds the torso, a leg chain that drags the other leg, a dance clip that tears.
7
+ This page lists what the painting must be, why the pipeline needs each thing, and
8
+ what breaks without it; gives one generation recipe as a starting point; says how
9
+ to paint alternate art for a limb; and describes `rig-parts painting`, the check
10
+ that reads the painting before See-through runs on it.
11
+
12
+ There are two ways in:
13
+
14
+ - **A generated painting**, decomposed by [See-through](https://github.com/shitagaki-lab/see-through)
15
+ into layers. Everything below is about this route.
16
+ - **An artist's own layered file** (a PSD, one layer per part): [AUTHORING §4,
17
+ *For artists*](AUTHORING.md#for-artists-your-own-layered-file-issue-359) and
18
+ *The correction loop*. The requirements below still hold for the figure — a
19
+ limb the artist draws against the body is as hard to move — but there is no
20
+ See-through step to fail, and an artist can paint what a joint hides as a
21
+ `<layer>:hidden` layer.
22
+
23
+ For the environment that makes a painting (an NVIDIA GPU, an Apple Silicon Mac, or
24
+ none), see [rig-c/getting-started](https://github.com/rig-c/getting-started).
25
+
26
+ ## The requirements
27
+
28
+ Each requirement says what the pipeline needs, what fails without it, and whether
29
+ `rig-parts painting` reads it (and under which rule) or only an eye can.
30
+
31
+ | requirement | why the pipeline needs it | what fails without it | read by |
32
+ | --- | --- | --- | --- |
33
+ | **Front view** | the proposer and the keypoint file read the subject's right on the image's left of a figure facing the viewer, and the eyes, the blink and the head turn are drafted from a face toward the viewer | a back view has no face part for `propose` to draft from (`PROPOSE_FACE_PRESENT`, or the face-less fallback its first note names) | an eye |
34
+ | **Full body, inside the frame** | the figure's height is the proposer's yardstick, and the feet carry the leg chain's last link | a cropped foot is a leg with no ankle; a figure touching the edge reads as background that is not plain | `PAINTING_BACKGROUND_PLAIN` |
35
+ | **Arms clear of the body** (an A-pose: arms down and out, a gap under each arm) | See-through separates what it can see; an arm with background round it becomes its own `handwear` and sleeve layers | an arm painted against the side is cut into a layer that holds part of the torso, and no rotation of its bone can swing it clear without dragging the torso's pixels | `PAINTING_ARM_CLEAR`: a gap on the line from each wrist to the hip of its side |
36
+ | **Hands apart and open** | each hand is a part on its own arm's chain; open fingers read as a hand at a thumbnail | clasped or touching hands are one `handwear` layer, split only by an `assemble.cuts` polygon drawn by hand; and the clasped hands the README showed until issue #227 did not read as hands above a thumbnail (`examples/demo/README.md`) | `PAINTING_HANDS_APART`: a gap on the line between the wrists. Hands that meet close a loop of arms round the torso, so both arms are refused with them |
37
+ | **Legs apart, with a visible gap** | the leg chain needs the legs painted apart (two legs that touch are one column See-through cannot split), and limbs are cut at their joints (#349, AUTHORING §3, *Limbs*), so each knee must be its own | legs that touch at the knee or the ankle come back as one `legwear` silhouette, a cut at the knee takes the other leg's pixels, and a step drags both | `PAINTING_LEGS_APART`: a gap on the line between the knees and on the line between the ankles |
38
+ | **Feet facing front** | a foot seen from the front stays inside its leg's column, below the ankle the leg chain ends at | not measured in this repository; read the leg parts on the `sheet` | an eye (body-18 has no foot points) |
39
+ | **A plain light background** | See-through and `assemble` read near-white as background (every channel above 235, the one test the assemble rim and the layer plausibility figures share) | scenery, a floor, a cast shadow, a gradient or a vignette is read as more figure — a layer of haze (`PLAN_LAYER_BACKGROUND`), or pixels that belong to no part | `PAINTING_BACKGROUND_PLAIN`: every border pixel near-white or unpainted |
40
+ | **Nothing held, no prop across a limb** | each part rides one bone; a prop belongs to no tag See-through knows | a held object joins the hands (`PAINTING_HANDS_APART`) or lands in a hand or garment layer and moves with the wrong bone | partly: a prop that joins the hands is `PAINTING_HANDS_APART`; anything else, an eye |
41
+ | **Clothing that leaves the joints unoccluded** | limbs are cut at the elbow and the knee (#349); each lower part carries a cap painted from what the joint hides | long sleeves and tights are fine; a cape over the elbows, a wide skirt over the knees or a forearm in front of the skirt's flare puts two parts' pixels on one joint. `assemble` names the missing cap pixels in its `limb cap:` lines | partly: a skirt over the knees is `PAINTING_LEGS_APART`, a forearm across a skirt is `PAINTING_ARM_CLEAR`; a cape over an elbow, an eye |
42
+ | **Resolution and aspect** | See-through runs on a square (`inputs` pads the painting white to a square of its longer side) at `seethrough.resolution` (1024 by default), and a second run on a crop round the head, because the eyes of a full-figure run are too small to separate. A standing figure is taller than wide; `comfy paint` writes twice its latent (832x1216 → 1664x2432) | a landscape painting is padded above and below and spends See-through's square on white; a small painting leaves the head crop too few pixels for the eyes | an eye; `inputs` refuses a translucent painting (`INPUTS_PAINTING_OPAQUE`) and a head box off it |
43
+
44
+ **One painting, one character.** The keypoint file may hold several people, and
45
+ `--person` names the one checked; the pipeline rigs one.
46
+
47
+ ## The check: `rig-parts painting`
48
+
49
+ ```
50
+ rig-parts painting --keypoints <keypoints.json> [--person <id>] <painting.png>
51
+ ```
52
+
53
+ It runs on the CPU, before See-through, on the painting and its body-18 joints:
54
+ the same keypoint file `propose --keypoints` reads (AUTHORING §3, *A posed
55
+ figure*), from any estimator or written by hand, measured on this painting (its
56
+ `width` and `height` are the painting's, `KEYPOINTS_IMAGE_SIZE`). It writes
57
+ nothing. It prints the figure, every joint and every gap with its count, then
58
+ `PASS` and exit 0, or a `FAIL` line per refusal and exit 1. Each `FAIL` line ends
59
+ with `(see rig-parts guide <RULE>)`, which prints the rule's row in
60
+ [AUTHORING §6](AUTHORING.md#6-refusals-the-rule-and-what-has-to-change).
61
+
62
+ What it reads, each a definition with no tuned number:
63
+
64
+ - **Ground** — a pixel the package already calls background: alpha 8 or less
65
+ (unpainted, the layer reader's cut), or every colour channel above 235
66
+ (near-white, the assemble stage's and the plausibility figures' test).
67
+ - **Background** — the ground that reaches the edge: ground 4-connected to ground
68
+ on the border. A white blouse inside its line art is ground but not background,
69
+ so it is figure.
70
+ - **Figure** — everything that is not background.
71
+ - **A gap** between two joints — at least one background pixel on the straight
72
+ line between them, sampled once per pixel the line crosses.
73
+
74
+ The rules: `PAINTING_BACKGROUND_PLAIN` (every border pixel is ground),
75
+ `PAINTING_JOINTS_STATED` (the wrists, hips, knees and ankles are `observed` with a
76
+ position), `PAINTING_JOINT_ON_FIGURE` (every observed joint's pixel is figure),
77
+ `PAINTING_ARM_CLEAR`, `PAINTING_HANDS_APART` and `PAINTING_LEGS_APART` (the gaps in
78
+ the table above).
79
+
80
+ What it does not read: a front view, the feet, a prop that does not join the
81
+ hands, a cape over an elbow, the hands' fingers, the face. A green `painting` says
82
+ the joints and the silhouette hold the requirements it reads, not that the
83
+ painting is good. A shadow or a floor enclosed by the background is figure to it;
84
+ the border rule sees it only where it reaches the edge.
85
+
86
+ ## A recipe that is one way, not the only way
87
+
88
+ Anyone with a different generator reads the requirements above, not this. This
89
+ is the `generation` block of the public `demo` example (`examples/demo/config.json`,
90
+ with its pose file `examples/demo/pose.json`), which `rig-parts comfy paint`
91
+ painted, with three changes: its character's words in `identity` and `costume`
92
+ are placeholders, and the words its idol costume needed in `negative_extra`
93
+ ("microphone, holding microphone, stage, stage lights") are left out; its full record — the candidates, the seed choice and a hand-detailer
94
+ pass `comfy paint` does not run — is in
95
+ [parts-examples](https://github.com/rig-c/parts-examples):
96
+
97
+ ```json
98
+ "generation": {
99
+ "checkpoint": "hassakuXLIllustrious_v13StyleA.safetensors",
100
+ "loras": [],
101
+ "trigger": "",
102
+ "identity": "1girl, solo, adult woman, <your character's hair, eyes, accessories>",
103
+ "sampler": { "steps": 30, "cfg": 6.0, "sampler": "euler_ancestral", "scheduler": "normal" },
104
+ "costume": "<the costume>, fully clothed, empty hands",
105
+ "negative_extra": "revealing clothes, bare shoulders, off shoulder, 2girls, multiple girls, holding, bag, weapon, clouds, cloud, sun, sky, sky background, grey background, blue background, gradient background, scenery, outdoors, from behind, back view, back of head, facing away, vignette, beige background, brown background, dark background, black background, spotlight, lighting gradient, flat color, cel shading, monochrome, lineart",
106
+ "pose": "full body, head to toe, entire body in frame, front view, facing viewer, looking at viewer, standing, arms away from body, hands apart away from skirt, open hands, relaxed fingers, relaxed pose, gentle smile, feet visible, shoes",
107
+ "style": "anime illustration, detailed, soft shading, (white background:1.3), simple background, plain background",
108
+ "negative_pose": "cropped, out of frame, cut off feet, close-up, portrait, upper body, from side, profile, sitting, kneeling, dynamic pose, arms raised, hand on face, contact shadow, cast shadow, floor, multiple views, reference sheet",
109
+ "latent": [832, 1216],
110
+ "seed": 71006,
111
+ "control": { "skeleton": "pose.json", "strength": 0.8, "end_percent": 0.7 }
112
+ }
113
+ ```
114
+
115
+ Put your character in the two placeholders, and negate what its costume invites.
116
+ What each part does:
117
+
118
+ - **The checkpoint** is public: [Hassaku XL (Illustrious)](https://civitai.com/models/140272)
119
+ v1.3 Style A, no LoRA. `scarf` and the two reference examples used
120
+ [Pony Diffusion V6 XL](https://civitai.com/models/257749) with the same sampler.
121
+ - **The control skeleton** is what holds the pose; a pose asked for in words
122
+ alone is one the sampler is free to ignore (`src/skeleton.ts`). `comfy paint`
123
+ draws it as OpenPose body-18 in the annotator's own style and applies it through
124
+ `controlnet-openpose-sdxl-1.0` at strength 0.8, ending at 0.7 of the steps. The
125
+ two built-ins are `stand_sides` (arms nearly straight down at the sides) and
126
+ `stand_clasp` (hands clasped at the waist), neither an A-pose; `pose.json` is a
127
+ pose file (issue #198) with the arms held out: the wrists at (206, 590) and
128
+ (626, 590) on the 832x1216 canvas, the shoulders at (340, 272) and (492, 272).
129
+ A pose file carries no words, so `generation.pose` is required beside it.
130
+ - **The pose words** repeat what the skeleton asks — arms away, hands apart and
131
+ open — and the **negatives** refuse what breaks a rig: a held object, a
132
+ background that is not plain, a back or side view, a crop, a cast shadow or a
133
+ floor.
134
+ - **The seed** is chosen by looking: the demo's was the best of sixteen candidates,
135
+ read at the hands; generate several and run `rig-parts painting` on each.
136
+
137
+ What this recipe did not hold, measured: on the demo painting itself, with joints
138
+ read by eye, `rig-parts painting` refuses both arms (the forearms cross the
139
+ skirt's flare) and the legs at the knees and the ankles (the pose file's knees
140
+ and ankles are the built-ins', close together, and the thighhighs touch). So
141
+ change the two things it did not ask for, and check the result: move the pose
142
+ file's knees and ankles apart and add leg words ("legs apart") to `pose`, and keep
143
+ a skirt short or narrow enough that the forearms hang clear of it. How far apart
144
+ holds a gap on a given checkpoint is not measured here; `painting` is the
145
+ instrument that says.
146
+
147
+ ## Alternate art for a limb
148
+
149
+ A rig plays its base art in every pose; where a limb turns somewhere the base art
150
+ cannot follow (behind the head, toward the camera), the mesh folds.
151
+ [rig-c/pose#6](https://github.com/rig-c/pose/issues/6) lets `rig-pose retarget`
152
+ switch to an alternate drawing of the limb for those spans, and its report's
153
+ `uncovered` list names every fold no alternate covers — that list is the answer
154
+ to *which* angles to paint.
155
+
156
+ To paint one without the character drifting, repaint only the limb:
157
+
158
+ 1. **Start from the base painting**, not from a new generation: the face, the
159
+ costume and the colours stay the base painting's pixels.
160
+ 2. **Inpaint with a mask along the old and the new limb**: the region the limb
161
+ leaves and the region it moves into, from the shoulder (or hip) down. Keep the
162
+ face out of the mask.
163
+ 3. **Use the key skeleton as the control**: the body-18 pose the alternate depicts,
164
+ in the painting's space — the same skeleton the pose map's `alternates` entry
165
+ records — drawn the way `comfy paint` draws a pose file.
166
+ 4. **Run See-through on the result and take the limb's layers** (the sleeve, the
167
+ hand); the rest of that run is discarded. The base rig's other parts stay the
168
+ base painting's.
169
+
170
+ `comfy paint` does not run an inpainting graph; the demo's hand-detailer pass is
171
+ the same idea at hand scale (a masked repaint on the same checkpoint, recorded
172
+ beside its painting in parts-examples).
package/docs/STABILITY.md CHANGED
@@ -46,21 +46,22 @@ defaults are the help's too, and none is guessed from the art.
46
46
  <!-- stable:commands -->
47
47
  | command | flags |
48
48
  | --- | --- |
49
- | `layers` | one positional path: a wrapper directory, a `layers.json` or a `.psd` |
49
+ | `layers` | one positional path: a wrapper directory, a `layers.json` or a `.psd`; with it, optional `--export` (a directory to write the wrapper form into, issue #359); or `--template` with `--canvas` and no path |
50
50
  | `sheet` | `--source`, `--layers` (repeatable), `--out`; optional `--cell`, `--cols` |
51
51
  | `inputs` | `--source`, `--config`, `--out` |
52
52
  | `comfy` | `paint`: `--config`, `--out`; optional `--seeds`, `--seed0`, `--host`, `--wait`, `--timeout`, `--poll` |
53
53
  | `comfy` | `seethrough`: `--image`, `--out`; optional `--resolution`, `--steps`, `--seed`, `--prefix`, `--offload`, `--lama`, `--nf4`, `--host`, `--wait`, `--timeout`, `--poll` |
54
- | `assemble` | `--propose-plan` with `--source`, `--full`, `--head`, `--config`; or `--source`, `--full`, `--head`, `--config`, `--out`, optional `--seam` (near-white, silhouette), `--project` (core, visible) |
54
+ | `assemble` | `--propose-plan` with `--source`, `--full`, `--config`, optional `--head`; or `--source`, `--full`, `--config`, `--out`, optional `--head` (without it, one run: issue #359), `--seam` (near-white, silhouette), `--project` (core, visible) |
55
55
  | `propose` | `--head-box` with `--full`, `--canvas` |
56
56
  | `propose` | `--parts`, `--source`, `--out`; optional `--compare` or `--from-config` (one of them), `--keypoints`, `--person` and `--wrist-snap` (each with `--keypoints`), `--full`, `--head` (the turn control's depths; not with `--from-config`), `--grid-rule` (`figure` or `part`, the drafted lattice's spacing; not with `--from-config`) |
57
57
  | `compare` | `--left`, `--right`; optional `--map` |
58
58
  | `rig` | `--config`, `--parts`, `--out`; optional `--idle-keys` (ctl, direct), `--page-edges` (pot, free), `--pack-shape` (rect, polygon) |
59
59
  | `check` | `--rig`, `--out`; optional `--parts`, `--source`, `--page-edges`, `--pack-shape`, `--requirements`, `--seam-pairs`, `--keep-stills` |
60
60
  | `loop` | `--frames`, `--out`; optional `--palette` |
61
- | `build` | `--config`, `--source`, `--full`, `--head`, `--out`; optional `--seam`, `--project`, `--page-edges`, `--pack-shape`, `--loop`, `--lead-in`, `--requirements`, `--idle-keys`, `--seam-pairs`, `--keep-stills` |
61
+ | `build` | `--config`, `--source`, `--full`, `--out`; optional `--head` (as for `assemble`), `--seam`, `--project`, `--page-edges`, `--pack-shape`, `--loop`, `--lead-in`, `--requirements`, `--idle-keys`, `--seam-pairs`, `--keep-stills` |
62
62
  | `compose` | `--scene`, `--out`; optional `--requirements`, `--accept` |
63
63
  | `mesh-draft` | `--config`, `--parts`, `--out`; optional `--requirements`, `--idle-keys` (ctl, direct), `--page-edges` (pot, free), `--pack-shape` (rect, polygon), `--more-triangles` |
64
+ | `painting` | one positional path, the painting; `--keypoints`; optional `--person` |
64
65
  | `guide` | one positional argument: a rule name, `§<n>`, `§<n>.<m>` or `§<n>.<m>.<k>` |
65
66
  | (none) | `--version`, `--help` |
66
67
  <!-- /stable:commands -->
@@ -111,7 +112,7 @@ The fields, object by object (a bold path is where the object sits; `<part>` is
111
112
  part name, `[i]` an entry of a list):
112
113
 
113
114
  <!-- stable:config -->
114
- - **config** — required by the full loader, in front of rig and build: `key`, `assemble`, `bones`, `meshes`, `regions`, `motion`; optional: `generation`, `seethrough`, `constraints`, `turn`, `scene`
115
+ - **config** — required by the full loader, in front of rig and build: `key`, `assemble`, `bones`, `meshes`, `regions`, `motion`; optional: `generation`, `seethrough`, `limbs`, `constraints`, `turn`, `scene`
115
116
  - **generation** — required: `checkpoint`, `loras`, `trigger`, `identity`, `sampler`, `costume`, `negative_extra`, `style`, `negative_pose`, `latent`, `seed`; optional: `pose`, `control`
116
117
  - **generation.loras[i]** — required: `name`, `strength`; optional: `strength_clip`
117
118
  - **generation.sampler** — required: `steps`, `cfg`, `sampler`, `scheduler`
@@ -124,7 +125,9 @@ part name, `[i]` an entry of a list):
124
125
  - **assemble.patches[i].draw**, when an object — required: `before`
125
126
  - **assemble.cuts[i]** — required: `from`, `into`, `polygon`, `draw`, `overlap`; optional: `under`
126
127
  - **assemble.cuts[i].draw**, when an object — required: `before`
127
- - **bones[i]**, a single bone — required: `name`, `parent`, `at`; optional: `tip`
128
+ - **limbs.&lt;limb&gt;** — required: `segments` (issue #349)
129
+ - **limbs.&lt;limb&gt;.segments[i]** — required: `part`, `from`, `bone`; required below a joint (i > 0): `joint`; optional below a joint: `range`, `cap`
130
+ - **bones[i]**, a single bone — required: `name`, `parent`, `at`; optional: `tip`, `inherit`
128
131
  - **bones[i]**, a chain — required: `chain`, `parent`, `points`, `tip`
129
132
  - **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`; optional with `grid` or `contour`: `influences` (issue #284; beside `auto` it is refused, CONFIG_INFLUENCES_MODE); optional with `grid`: `stray` (issue #303; beside `contour` or `auto` it is refused, CONFIG_STRAY_MODE)
130
133
  - **meshes.&lt;part&gt;.influences** — optional, at least one: `maxInfluences` (a whole number, 1 or more, or null for no cap), `floor` ("cut" or "continuous")
@@ -154,7 +157,7 @@ part name, `[i]` an entry of a list):
154
157
  - **turn** — required: `pivot`, `depths`
155
158
  - **turn.depths.&lt;part&gt;** — a See-through depth
156
159
  - **scene** — no field (`{}`; a record or an annotation only)
157
- - **proposal.json**, the file propose writes — `bones`, `meshes`, `regions`, `motion` under the rules above, `turn` with `--full`/`--head`, and `notes`
160
+ - **proposal.json**, the file propose writes — `bones`, `meshes`, `regions`, `limbs` under `--keypoints` where an arm or a leg is drafted from its joints (issue #349), `motion` under the rules above, `turn` with `--full`/`--head`, and `notes`
158
161
  <!-- /stable:config -->
159
162
 
160
163
  `TY14` holds the set of field names in backticks above to the set of names the
@@ -171,10 +174,12 @@ every number) are AUTHORING §3's tables, and the loader refuses any other by na
171
174
 
172
175
  | file | written by | what is stable |
173
176
  | --- | --- | --- |
174
- | `parts.json`, `parts/<name>.png` | `assemble`, `build` | one record per part: `from` (`<run>:<tag>` with a See-through v3 tag, `<run>:author:<label>` for a layer the author made — issue #256, read by no role rule — or `painting:<name>` for a patch), `cut_from` on a cut's piece only (the plan part it was cut from, issue #230), 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`, and `scene` (`figure_alpha_above`, `figure_px`, `figure_mask`) under `config.scene` only, with the figure's mask `figure_rig.png` beside the recomposite (issue #242) |
175
- | `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 |
177
+ | `parts.json`, `parts/<name>.png` | `assemble`, `build` | one record per part: `from` (`<run>:<tag>` with a See-through v3 tag, `<run>:author:<label>` for a layer the author made — issue #256, read by no role rule — or `painting:<name>` for a patch), `cut_from` on a cut's piece only (the plan part it was cut from, issue #230), `limb` on a limb segment's part only (issue #349: `name`, `segment`, `of`, `bone`, and below a joint `joint` and `cap` — `at`, `width`, `radius`, `box`, `layer_px`, `image_px` with a cap image, `image_layer` after it when that image was a hidden-art layer — issue #359, `<run>:<layer>:hidden` — `missing_px`), 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`, and `scene` (`figure_alpha_above`, `figure_px`, `figure_mask`) under `config.scene` only, with the figure's mask `figure_rig.png` beside the recomposite (issue #242); `single_run_pad` (`file_size`, `side`, `left`, `top`) last, only for one run whose file is not the `seethrough.resolution` square (issue #366) |
178
+ | `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; a bone carries `inherit` only where config.bones declares one, rig-c's mode name as written (issue #348) |
176
179
  | `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` (`params.maxEdge` and `contour.outlineCut` only when the mesh declares `contour.maxEdge`; `params.bridges` and `contour.bridges` — `islands`, `units`, `joins`, and `faint` only when an island was left out as faint — only when it declares `contour.bridges`); 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`); `influences`, as declared, when a lattice or contour mesh declares it (after `exponent`, or where `exponent` would be); `stray` and `stray_cleared` when a lattice mesh declares `stray` (after `influences`, or where `influences` would be); `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) |
177
- | `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_border` after the seam figures when `parts.json` declares a scene (issue #242), `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`), `ANIMATIONS_DO_NOT_FOLD` after them when `motion.json` holds an animation, the idle included — on every rig with an idle since issue #333 (issue #320: `status`, `animations`, `fps`, `physics_left_out`, `folding`, `folding_undeclared`, `declared_not_folding`, `bar`), `RECOMPOSITE_HOLES` (its first figure `declared_scene` when `parts.json` declares a scene), `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 |
180
+ | `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_border` after the seam figures when `parts.json` declares a scene (issue #242), `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`), `ANIMATIONS_DO_NOT_FOLD` after them when `motion.json` holds an animation, the idle included — on every rig with an idle since issue #333 (issue #320: `status`, `animations`, `fps`, `physics_left_out`, `folding`, `folding_undeclared`, `declared_not_folding`, `bar`), `FEET_STAY_LEVEL` after it when a `footwear` part rides a bone that hangs from another and `motion.json` holds an animation (issue #348: `status`, `reason` on a SKIP only, `animations`, `fps`, `physics_left_out`, `bar_degrees`, `bar`, `feet` — each `part`, `bone`, `hangs_from`, `status`, `frames_posed`, `worst`), `LIMB_ONE_BONE` after it (and after `STRESS_OFF_CHAIN` where that is written) when `parts.json` holds a limb segment's part (issue #349: `status`, `parts` — each `part`, `limb`, `bone`, `status`, `others`), `RECOMPOSITE_HOLES` (its first figure `declared_scene` when `parts.json` declares a scene), `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 |
181
+ | `layers.json`, `<index>_<name>.png` | `layers --export` | the wrapper form `layers` reads (issue #359): `width`, `height`, then `layers` — each `name`, `filename`, `left`, `top`, `right`, `bottom`, `depth_median` (the input's own; `null` for a PSD, the manifest's order then being the draw order) — drawn layers in draw order, then the hidden-art layers; a PNG's name is its index and its layer's name, and the manifest, not the file name, says which layer it is |
182
+ | the template `.psd` | `layers --template` | one empty layer per name `templateLayerNames` (`src/layers.ts`) holds, bottom first; the same canvas writes the same bytes |
178
183
  | `proposal.json`, `render/landmarks*.png` | `propose` | the config's four rig sections, `turn` with `--full`/`--head`, and `notes` |
179
184
  | `basis.json` | `propose` | spec `spine-parts-basis/1` |
180
185
  | `config.json`, `mesh_draft.json` | `mesh-draft` | `config.json` is the config read, byte for byte, but for each drafted part's `meshes` entry; `mesh_draft.json` is spec `rig-parts-mesh-draft/1`: `rules`, `lattice_check`, `draft_check`, `figure_overdraw`, and per lattice part `part`, `mode`, `lattice`, `candidate` (with `bridges` — `units`, `joins` of `span` and `area_px2`, `area_px2`, `overdraw`, and `faint` only when an island was left out as faint — only when the candidate is a bridged one, issue #326), `delta` (under `--more-triangles` only), `readings`, `gate` (each line's `reading`, `pass`, `text`, `margin`), `note`; and `not_compared` (issue #307), only when the config holds an `auto` or `contour` entry: per such entry, in config order, `part`, `mode` and `note` — the part was neither drafted nor compared, and a config of lattices alone writes no such key |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rig-c/parts",
3
- "version": "1.16.0",
3
+ "version": "1.18.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": {
@@ -43,6 +43,7 @@
43
43
  "workflows",
44
44
  "docs/AUTHORING.md",
45
45
  "docs/MIGRATION.md",
46
+ "docs/PAINTING.md",
46
47
  "docs/STABILITY.md",
47
48
  "skills",
48
49
  "NOTICE.md"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: rig-parts
3
- description: Turn one anime character painting and its See-through layer decomposition into a verified 2D character rig (Spine 4.3 skeleton data) — measured parts, weighted meshes, bone chains and a looping idle — with rig-parts, which gates everything through rig-c before it is written. Use for a request to rig or animate a single character painting, to run or read rig-parts layers, sheet, assemble, propose, rig, check, loop or build, or to write or fix a rig-parts config.json. Not for cutting art into parts by hand, for authoring a rig from loose PNGs (that is the rigc skill), for lip-sync or swapping a part's image, or for running See-through itself.
3
+ description: Turn one anime character painting and its See-through layer decomposition into a verified 2D character rig (Spine 4.3 skeleton data) — measured parts, weighted meshes, bone chains and a looping idle — with rig-parts, which gates everything through rig-c before it is written. Use for a request to rig or animate a single character painting, to check a painting before See-through (rig-parts painting), to run or read rig-parts layers, sheet, assemble, propose, rig, check, loop or build, or to write or fix a rig-parts config.json. Not for cutting art into parts by hand, for authoring a rig from loose PNGs (that is the rigc skill), for lip-sync or swapping a part's image, or for running See-through itself.
4
4
  license: MIT
5
5
  compatibility: Requires Bun 1.2 or later. The tool is the npm package @rig-c/parts (npm i -D @rig-c/parts, or bun add -d @rig-c/parts), whose command is rig-parts; rig-c is installed with it. See-through is run separately.
6
6
  ---
@@ -58,6 +58,15 @@ under that.
58
58
 
59
59
  ## The loop
60
60
 
61
+ 0. Before See-through, check the painting: `rig-parts painting --keypoints
62
+ <k.json> <painting.png>` with the figure's body-18 joints (the file
63
+ `propose --keypoints` reads, from an estimator or the painting — never a joint
64
+ you guessed). A `FAIL PAINTING_…` line names what a rig cannot be cut from —
65
+ an arm against the body, hands together, legs with no gap, a joint off the
66
+ figure, a background that is not plain — and the fix is a new painting, not a
67
+ config field. `docs/PAINTING.md` lists every requirement, the ones only an eye
68
+ reads (front view, feet, a cape over an elbow), and one generation recipe;
69
+ report those as not checked.
61
70
  1. `rig-parts inputs --source <painting> --config config.json --out <dir>` writes
62
71
  `st_input_full.png`, the painting on a white square. The config needs only `key`,
63
72
  `seethrough` and `assemble.rig_scale` at this point. Run See-through on it — any
@@ -93,7 +102,9 @@ under that.
93
102
  an arm raised, seated in a skirt that does not start at the hip: add
94
103
  `--keypoints <file>` (body-18 joints in painting px, each observed, occluded
95
104
  or missing; AUTHORING §3, *A posed figure*) so the neck, hip, chest and
96
- sleeves follow the pose and LINT reads the joints, not screen y. A clean
105
+ sleeves follow the pose and LINT reads the joints, not screen y. Each arm and
106
+ leg it places comes back as `limbs` (AUTHORING §3, *Limbs*): paste it, assemble
107
+ again, and read each `limb cap:` line for the pixels a cap is missing. A clean
97
108
  LINT does not show a seated hip is right; the overlay does. Never write a joint you did not get from an
98
109
  estimator or the painting: say `missing` and let the rule stand in.
99
110
  6. Correct against `render/landmarks.png` and `note:` lines; a
@@ -112,6 +123,7 @@ under that.
112
123
  (rigc refuses the pair the link's control splits, and the line names the flag
113
124
  on the command that ran; AUTHORING §3).
114
125
  7. `rig-parts build --config … --source … --full … --head … --out out --loop`
126
+ (no `--head` for an artist's own file, below)
115
127
  (add `--idle-keys direct` when step 6 said so).
116
128
  It stops at the first stage that refuses, printing that stage's lines under
117
129
  `[assemble]`, `[rig]` or `[check]`. Fix what the FAIL line names and build again.
@@ -125,6 +137,23 @@ under that.
125
137
  last: `check/build/skeleton.json`, `skeleton.atlas` and the packed page. Report
126
138
  them with the pack line and the check figures verbatim.
127
139
 
140
+ An artist's own layered PSD (issue #359; AUTHORING §4, *For artists*): one run,
141
+ no See-through, no `--head` and no `head_box` in the config. The file must hold
142
+ `face`, `eyewhite-r` and `eyewhite-l`, painted (`ASSEMBLE_SINGLE_RUN_FACE`
143
+ otherwise); its stacking is the draw order and it carries no depth, so `layers`
144
+ prints `SKIP depth:` and the turn draft says `turn: SKIP` — report those as
145
+ skipped, never as passed. `rig-parts layers --template art.psd --canvas <W>x<H>`
146
+ writes the empty layers an artist paints into. A layer named `<layer>:hidden` is
147
+ that layer's art where something covers it (the forearm under a sleeve): read as a
148
+ cut's `under` and a limb segment's cap, never drawn; a `hidden art:` line names
149
+ what read it. To correct a parse, `rig-parts layers --export work art.psd` writes
150
+ the same layers as `layers.json` and one PNG each; move pixels between the PNGs
151
+ (grow a PNG and its box in `layers.json` together), then pass `--full work` and
152
+ read `recomposite vs source` and the error map again (AUTHORING §4, *The
153
+ correction loop*). A patch in the wrong layer shows as error only where the
154
+ painting is near-white; elsewhere it shows as `drift=`/`seam=` on the part drawn
155
+ over it.
156
+
128
157
  Several characters in one rig: build each one green on its own, then
129
158
  `rig-parts compose --scene scene.json --out scene` (spec `spine-parts-scene/1`:
130
159
  the canvas, each character's `build` and `offset`, an optional plate with its