@rig-c/parts 1.18.0 → 1.20.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/PAINTING.md CHANGED
@@ -5,7 +5,7 @@ yours — on your own GPU, with any generator, or by hand — and this package r
5
5
  no model. But a painting the pipeline cannot rig fails late: a sleeve layer that
6
6
  holds the torso, a leg chain that drags the other leg, a dance clip that tears.
7
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
8
+ what breaks without it; gives one generation recipe that passes the check, and what it measured; says how
9
9
  to paint alternate art for a limb; and describes `rig-parts painting`, the check
10
10
  that reads the painting before See-through runs on it.
11
11
 
@@ -31,14 +31,14 @@ Each requirement says what the pipeline needs, what fails without it, and whethe
31
31
  | requirement | why the pipeline needs it | what fails without it | read by |
32
32
  | --- | --- | --- | --- |
33
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` |
34
+ | **Full body, inside the frame** — hair and ribbons too | 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. Long hair and trailing ribbons are figure: where they reach the edge they fail the border, and where they curl round the figure into a ring they close off the background between the arms and the body (*What the recipe measured*, below) | `PAINTING_BACKGROUND_PLAIN`; a ring, `PAINTING_ARM_CLEAR` and `PAINTING_HANDS_APART` |
35
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
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
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
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
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
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 |
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`; anything on an elbow — a cape, a sleeve's frill, a bow — an eye (no rule reads the elbow; *What the recipe measured*) |
42
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
43
 
44
44
  **One painting, one character.** The keypoint file may hold several people, and
@@ -72,47 +72,150 @@ What it reads, each a definition with no tuned number:
72
72
  line between them, sampled once per pixel the line crosses.
73
73
 
74
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).
75
+ `PAINTING_JOINTS_STATED` (the wrists, knees and ankles are `observed` with a
76
+ position; a hip is `observed` or `occluded` with a position),
77
+ `PAINTING_JOINT_ON_FIGURE` (every observed joint's pixel, and every occluded hip's,
78
+ is figure), `PAINTING_ARM_CLEAR`, `PAINTING_HANDS_APART` and `PAINTING_LEGS_APART`
79
+ (the gaps in the table above).
80
+
81
+ **An occluded hip** (issue #372). A skirt hides the hips on most clothed figures —
82
+ on every one of the 24 paintings behind the recipe below — and `occluded` with a
83
+ position is how the keypoint file says so: the joint is where its producer
84
+ estimated it, and the painting does not show it. The check reads an occluded hip
85
+ when the arm's gap read from it is **well defined**, which it decides from what it
86
+ reads:
87
+
88
+ - the hip **carries a position**. The keypoint reader already holds every position
89
+ inside the image (`KEYPOINTS_POSITION_INSIDE`), so every sample of the line from
90
+ the wrist to the hip is a pixel of the painting;
91
+ - that position's pixel **is figure** (`PAINTING_JOINT_ON_FIGURE`, which reads an
92
+ occluded hip as it reads an observed joint). An estimate placed on the background
93
+ would put a background pixel at the end of the arm's own line, and the arm would
94
+ pass on the estimate rather than on the painting.
95
+
96
+ A hip with no position is still refused (`PAINTING_JOINTS_STATED`): it gives the arm
97
+ rule no line to read. Only the hips: an occluded wrist is a hand the painting does
98
+ not show, and an occluded knee or ankle is a leg whose gap cannot be read. The
99
+ joints line counts occluded hips apart (`joints: 16 observed, 2 occluded with a
100
+ position (r_hip, l_hip), 18 on the figure`), and an arm's gap line says when it was
101
+ read from one.
79
102
 
80
103
  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
104
+ hands, anything on an elbow (a cape, a sleeve's frill, a bow), the hands' fingers,
105
+ the face. A green `painting` says
82
106
  the joints and the silhouette hold the requirements it reads, not that the
83
107
  painting is good. A shadow or a floor enclosed by the background is figure to it;
84
108
  the border rule sees it only where it reaches the edge.
85
109
 
86
110
  ## A recipe that is one way, not the only way
87
111
 
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):
112
+ Anyone with a different generator reads the requirements above, not this. This is
113
+ one way that passes `painting`: the `generation` block and the pose file of seed
114
+ 372108, painted by `rig-parts comfy paint` for issue #372 as one of 24 candidates,
115
+ and chosen to be the next public example — a character for a wind demo, where hair
116
+ and cloth move by physics under a side gust. Its painting and See-through layers are
117
+ not yet published; when they are, its record joins the others in
118
+ [parts-examples](https://github.com/rig-c/parts-examples). The block:
96
119
 
97
120
  ```json
98
121
  "generation": {
99
122
  "checkpoint": "hassakuXLIllustrious_v13StyleA.safetensors",
100
123
  "loras": [],
101
124
  "trigger": "",
102
- "identity": "1girl, solo, adult woman, <your character's hair, eyes, accessories>",
125
+ "identity": "1girl, solo, adult woman, very long twin tails reaching the knees, deep blue hair, amber eyes, large red hair ribbons with long trailing ends",
103
126
  "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",
127
+ "costume": "white blouse with long fitted sleeves, red ribbon bow at the collar with long trailing ribbon ends, very wide flared tiered skirt, three ruffled layers, petticoat, skirt above the knees, knees visible, white thighhighs, red ankle boots, fully clothed, empty hands",
128
+ "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, long skirt, knee-length skirt, cape, legs together, knees together, crossed legs, hands on skirt, holding skirt, wide sleeves",
129
+ "pose": "full body, head to toe, entire body in frame, front view, facing viewer, looking at viewer, standing, legs apart, arms spread away from body, arms out to the sides, hands apart away from skirt, open hands, spread fingers, relaxed pose, gentle smile, feet visible, feet facing forward, shoes",
107
130
  "style": "anime illustration, detailed, soft shading, (white background:1.3), simple background, plain background",
108
131
  "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
132
  "latent": [832, 1216],
110
- "seed": 71006,
133
+ "seed": 372108,
111
134
  "control": { "skeleton": "pose.json", "strength": 0.8, "end_percent": 0.7 }
112
135
  }
113
136
  ```
114
137
 
115
- Put your character in the two placeholders, and negate what its costume invites.
138
+ and the pose file it names, `pose.json` (OpenPose body-18 points on the 832x1216
139
+ latent canvas, x right, y down):
140
+
141
+ ```json
142
+ {
143
+ "width": 832,
144
+ "height": 1216,
145
+ "points": {
146
+ "nose": [416, 176],
147
+ "neck": [416, 252],
148
+ "r_shoulder": [340, 272],
149
+ "r_elbow": [258, 418],
150
+ "r_wrist": [168, 540],
151
+ "l_shoulder": [492, 272],
152
+ "l_elbow": [574, 418],
153
+ "l_wrist": [664, 540],
154
+ "r_hip": [374, 612],
155
+ "r_knee": [352, 862],
156
+ "r_ankle": [326, 1100],
157
+ "l_hip": [458, 612],
158
+ "l_knee": [480, 862],
159
+ "l_ankle": [506, 1100],
160
+ "r_eye": [398, 160],
161
+ "l_eye": [434, 160],
162
+ "r_ear": [378, 170],
163
+ "l_ear": [454, 170]
164
+ }
165
+ }
166
+ ```
167
+
168
+ **What `comfy paint` adds.** The prompt the sampler reads is not only the block's
169
+ words. `comfy paint` puts a fixed head in front of each side (`POSITIVE_HEAD` and
170
+ `NEGATIVE_HEAD` in `src/graphs.ts`, the reference implementation's, verbatim) — on
171
+ this Illustrious checkpoint as on the Pony one, where its `score_*` words come
172
+ from. A reader copying this recipe to another generator copies these too, or
173
+ knows they are left out:
174
+
175
+ - positive head: `score_9, score_8_up, score_7_up, source_anime, masterpiece, best quality, highly detailed`
176
+ - negative head: `score_4, score_3, score_2, score_1, worst quality, low quality, lowres, blurry, jpeg artifacts, nsfw, nude, naked, cleavage, underwear, sexual, suggestive, child, loli, shota, kid, toddler, text, watermark, signature, logo, bad anatomy, bad hands, extra fingers, deformed, mutated`
177
+
178
+ The positive is then the head, `trigger`, `identity`, `costume`, `pose` and
179
+ `style`, joined with `, `; the negative is the head, `negative_extra` and
180
+ `negative_pose`. The two strings seed 372108 was sampled with, as `comfy paint`
181
+ recorded them beside the painting:
182
+
183
+ ```
184
+ positive: score_9, score_8_up, score_7_up, source_anime, masterpiece, best quality, highly detailed, 1girl, solo, adult woman, very long twin tails reaching the knees, deep blue hair, amber eyes, large red hair ribbons with long trailing ends, white blouse with long fitted sleeves, red ribbon bow at the collar with long trailing ribbon ends, very wide flared tiered skirt, three ruffled layers, petticoat, skirt above the knees, knees visible, white thighhighs, red ankle boots, fully clothed, empty hands, full body, head to toe, entire body in frame, front view, facing viewer, looking at viewer, standing, legs apart, arms spread away from body, arms out to the sides, hands apart away from skirt, open hands, spread fingers, relaxed pose, gentle smile, feet visible, feet facing forward, shoes, anime illustration, detailed, soft shading, (white background:1.3), simple background, plain background
185
+ negative: score_4, score_3, score_2, score_1, worst quality, low quality, lowres, blurry, jpeg artifacts, nsfw, nude, naked, cleavage, underwear, sexual, suggestive, child, loli, shota, kid, toddler, text, watermark, signature, logo, bad anatomy, bad hands, extra fingers, deformed, mutated, 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, long skirt, knee-length skirt, cape, legs together, knees together, crossed legs, hands on skirt, holding skirt, wide sleeves, 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
186
+ ```
187
+
188
+ **What `painting` read on it**, with the wrists, knees and ankles read by eye on the
189
+ painting at full size (on a 50 px grid) and the hips — under the skirt — at the pose
190
+ file's hips x2. Written `observed`, as the check required until this change (the
191
+ two paths shortened):
192
+
193
+ ```
194
+ rig-parts painting: painting_372108.png, joints from kp/eye_372108.json person "a" (source: read by eye from the painting at full resolution on a 50 px grid (wrists, knees, ankles); hips under the skirt taken from the pose file x2; head and shoulders from the pose file x2 (not read by the check))
195
+ painting 1664x2432: background 2558081 px, figure 1488767 px; border 8188 px, 0 not background-coloured
196
+ joints: 18 observed, 18 on the figure
197
+ gap right arm (r_wrist to r_hip): 60 of 429 sampled pixels are background
198
+ gap left arm (l_wrist to l_hip): 76 of 415 sampled pixels are background
199
+ gap hands (r_wrist to l_wrist): 157 of 1011 sampled pixels are background
200
+ gap knees (r_knee to l_knee): 137 of 261 sampled pixels are background
201
+ gap ankles (r_ankle to l_ankle): 248 of 351 sampled pixels are background
202
+ PASS the painting holds every requirement this check reads (docs/PAINTING.md); what only an eye reads is listed there
203
+ ```
204
+
205
+ The same file with the two hips `occluded` (their honest state, read since this
206
+ change; *An occluded hip*, above) reads the same five gaps:
207
+
208
+ ```
209
+ painting 1664x2432: background 2558081 px, figure 1488767 px; border 8188 px, 0 not background-coloured
210
+ joints: 16 observed, 2 occluded with a position (r_hip, l_hip), 18 on the figure
211
+ gap right arm (r_wrist to r_hip): 60 of 429 sampled pixels are background (r_hip occluded, read at its position)
212
+ gap left arm (l_wrist to l_hip): 76 of 415 sampled pixels are background (l_hip occluded, read at its position)
213
+ gap hands (r_wrist to l_wrist): 157 of 1011 sampled pixels are background
214
+ gap knees (r_knee to l_knee): 137 of 261 sampled pixels are background
215
+ gap ankles (r_ankle to l_ankle): 248 of 351 sampled pixels are background
216
+ PASS the painting holds every requirement this check reads (docs/PAINTING.md); what only an eye reads is listed there
217
+ ```
218
+
116
219
  What each part does:
117
220
 
118
221
  - **The checkpoint** is public: [Hassaku XL (Illustrious)](https://civitai.com/models/140272)
@@ -120,29 +223,81 @@ What each part does:
120
223
  [Pony Diffusion V6 XL](https://civitai.com/models/257749) with the same sampler.
121
224
  - **The control skeleton** is what holds the pose; a pose asked for in words
122
225
  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.
226
+ draws the pose file as OpenPose body-18 in the annotator's own style and applies
227
+ it through `controlnet-openpose-sdxl-1.0` at strength 0.8, ending at 0.7 of the
228
+ steps. A pose file carries no words, so `generation.pose` is required beside it.
229
+ This one is the public `demo`'s pose file (`examples/demo/pose.json`) with the
230
+ head, neck and shoulders unchanged and the limbs moved, latent px:
231
+
232
+ | joint | `demo` | this recipe |
233
+ | --- | --- | --- |
234
+ | wrists | (206, 590), (626, 590) | (168, 540), (664, 540) — 72 px above the hips' line, 206 px out from each hip |
235
+ | elbows | (282, 440), (550, 440) | (258, 418), (574, 418) |
236
+ | hips | (378, 612), (454, 612) | (374, 612), (458, 612) |
237
+ | knees | (384, 862), (448, 862) — 64 px apart | (352, 862), (480, 862) — 128 px apart |
238
+ | ankles | (388, 1100), (444, 1100) — 56 px apart | (326, 1100), (506, 1100) — 180 px apart |
239
+
240
+ The paintings followed it: on the seven candidates whose joints were read by
241
+ eye, every wrist, knee and ankle lies within 38 painting px (in x or in y) of the
242
+ pose file's x2. On this one the eye read the wrists at (320, 1080) and
243
+ (1330, 1080), the knees at (700, 1720) and (960, 1720), and the ankles at
244
+ (655, 2190) and (1005, 2190).
245
+ - **The pose words** repeat what the skeleton asks — legs apart, arms out, hands
246
+ apart and open, feet forward — and the **negatives** refuse what breaks a rig: a
247
+ held object, a background that is not plain, a back or side view, a crop, a cast
248
+ shadow or a floor, and what closes the legs or covers them (`long skirt`,
249
+ `knee-length skirt`, `cape`, `legs together`, `knees together`, `crossed legs`).
250
+ - **The seed** is chosen by looking and by `painting`: generate several, run the
251
+ check on each, then read what it cannot (below). This one was chosen over the
252
+ others that passed because its ribbons wrap the twin tails (free ribbon arcs
253
+ become the rest shape a physics constraint swings from), its hair hangs at rest
254
+ (a candidate painted with its tails already swept out was a blown rest shape),
255
+ it has the widest two-layer skirt (the largest wind surface), and its tails
256
+ hang behind the figure, so they come out under a side gust. Two other passing
257
+ candidates were set aside because they read as a well-known existing character.
258
+
259
+ ## What the recipe measured
260
+
261
+ 24 paintings, seeds 372001-372008, 372101-372108 and 372201-372208, on the pose
262
+ file above under three wordings of the hair and the skirt (the block above is the
263
+ second; the first asked for twin tails "reaching the thighs" and a "wide flared
264
+ layered ruffled miniskirt", the third added "layered skirt"). Screened with
265
+ `painting` on the pose file's joints x2 — a screen, not a reading: a pose-file
266
+ joint can land off the limb, which three did (`PAINTING_JOINT_ON_FIGURE`, on a
267
+ wrist or an ankle), and the seven best were then read by eye. On that screen:
268
+
269
+ - **Spreading the knees and the ankles in the pose file holds a gap.** The knee
270
+ gap held in 23 of 24 paintings and the ankle gap in 24 of 24, on Hassaku XL
271
+ v1.3 Style A. The one knee miss painted an overskirt down to the shins, which
272
+ joins the legs whatever the skeleton says. On the `demo` painting, painted from
273
+ knees 64 and ankles 56 latent px apart, `painting` refuses both.
274
+ - **What clears `PAINTING_ARM_CLEAR` is the wrists' height above the skirt's
275
+ flare, not a narrow skirt.** With the wrists 72 latent px above the hips' line
276
+ (the `demo`'s are 22), both arm gaps held in 23 of 24 paintings, the widest
277
+ skirts among them: this recipe's two-layer skirt, at 60 and 76 background px on
278
+ the eye-read arm lines, and a three-tier ruffled skirt at 59 and 74. The one miss
279
+ is the hair ring below. On the `demo` painting the forearms hang across the
280
+ flare and both arms are refused.
281
+ - **Long hair and ribbons that reach the frame fail the border.** 6 of the 9
282
+ refusals were `PAINTING_BACKGROUND_PLAIN`: twin tails or a ribbon's trailing
283
+ end painted out to the edge: 1 of 8 under the first wording (tails "reaching the
284
+ thighs"), 5 of 16 under the other two (tails "reaching the knees", "large red
285
+ hair ribbons with long trailing ends") — counts, not a rate any other prompt will
286
+ repeat. One of the six
287
+ also curled its hair round the figure into a ring: the white between the arms
288
+ and the body was no longer connected to the edge, so it was not background, and
289
+ both arms and the hands were refused with the border (`PAINTING_ARM_CLEAR` x2,
290
+ `PAINTING_HANDS_APART`). The remedy, **untested here**: leave a margin round
291
+ where the hair falls — the pose file decides where the figure sits, and this
292
+ one puts the wrists 168 latent px from each side — and ask for hair no longer
293
+ than the frame holds; `painting` says whether a seed kept it inside.
294
+ - **`painting` cannot see the elbow.** Body-18 has an elbow point, but no rule reads
295
+ it, and 3 of the 7 best candidates passed with something on it: two with short
296
+ puff sleeves whose frilled cuff ends on the elbow, one with ribbons tied in
297
+ bows at the elbows. The costume's "long fitted sleeves" did not prevent either.
298
+ It is an eye check: look at each elbow at full size before See-through runs.
299
+ Prompt advice, **untested here**: add `puffy sleeves, short sleeves, puff
300
+ sleeves, elbow ribbon, ribbon on arm` to `negative_extra`.
146
301
 
147
302
  ## Alternate art for a limb
148
303
 
package/docs/STABILITY.md CHANGED
@@ -53,7 +53,7 @@ defaults are the help's too, and none is guessed from the art.
53
53
  | `comfy` | `seethrough`: `--image`, `--out`; optional `--resolution`, `--steps`, `--seed`, `--prefix`, `--offload`, `--lama`, `--nf4`, `--host`, `--wait`, `--timeout`, `--poll` |
54
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
- | `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`) |
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`), `--cloth` (a config whose `cloth` block is the recipe, issue #364; 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` |
@@ -112,7 +112,7 @@ The fields, object by object (a bold path is where the object sits; `<part>` is
112
112
  part name, `[i]` an entry of a list):
113
113
 
114
114
  <!-- stable:config -->
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
+ - **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`, `cloth`
116
116
  - **generation** — required: `checkpoint`, `loras`, `trigger`, `identity`, `sampler`, `costume`, `negative_extra`, `style`, `negative_pose`, `latent`, `seed`; optional: `pose`, `control`
117
117
  - **generation.loras[i]** — required: `name`, `strength`; optional: `strength_clip`
118
118
  - **generation.sampler** — required: `steps`, `cfg`, `sampler`, `scheduler`
@@ -147,6 +147,10 @@ part name, `[i]` an entry of a list):
147
147
  - **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)
148
148
  - **meshes.&lt;part&gt;.auto.boundaryRuns** — required: `maxVertices`
149
149
  - **meshes.&lt;part&gt;.auto.stimulus**, or each entry of it when a list — required: `chain`, `degrees`
150
+ - **cloth.&lt;tag&gt;**, the tag bottomwear, back hair or front hair (issue #364; read by propose --cloth only) — required: `chains`, `links`, `wind`, `gravity`; optional: `split`, `length_ratio`, `strength`, `damping`, `alternate_damping`, `translate`, `swing` (on bottomwear only)
151
+ - **cloth.&lt;tag&gt;.split** — required: `at`, `into`
152
+ - **cloth.&lt;tag&gt;.strength** — required: `trunk`, `branch`, `edge`
153
+ - **cloth.&lt;tag&gt;.swing** — required: `scales`
150
154
  - **regions.&lt;part&gt;** — a bone name
151
155
  - **motion** — required: `duration`, `tracks`; optional: `blink`, `animations_from`
152
156
  - **motion.tracks[i]**, a single track — required: `bone`, `prop`, `amp`, `period`, `phase`; optional: `base`
@@ -180,7 +184,7 @@ every number) are AUTHORING §3's tables, and the loader refuses any other by na
180
184
  | `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
185
  | `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
186
  | the template `.psd` | `layers --template` | one empty layer per name `templateLayerNames` (`src/layers.ts`) holds, bottom first; the same canvas writes the same bytes |
183
- | `proposal.json`, `render/landmarks*.png` | `propose` | the config's four rig sections, `turn` with `--full`/`--head`, and `notes` |
187
+ | `proposal.json`, `render/landmarks*.png` | `propose` | the config's four rig sections, `constraints` with `--cloth` (issue #364: a physics constraint per tree link named `<bone>_physics`, a dangling end's `<bone>_translate`, and a skirt swing's transforms `<swing>_<tree>`), `turn` with `--full`/`--head`, and `notes` |
184
188
  | `basis.json` | `propose` | spec `spine-parts-basis/1` |
185
189
  | `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 |
186
190
  | the scene report | `compose` | spec `spine-parts-scene-report/1` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rig-c/parts",
3
- "version": "1.18.0",
3
+ "version": "1.20.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": {
@@ -61,7 +61,7 @@
61
61
  },
62
62
  "dependencies": {
63
63
  "ag-psd": "^31.0.2",
64
- "rig-c": "^2.47.1"
64
+ "rig-c": "^2.54.0"
65
65
  },
66
66
  "devDependencies": {
67
67
  "@esotericsoftware/spine-core": "4.3.13",
@@ -65,8 +65,9 @@ under that.
65
65
  an arm against the body, hands together, legs with no gap, a joint off the
66
66
  figure, a background that is not plain — and the fix is a new painting, not a
67
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.
68
+ reads (front view, feet, anything on an elbow: a cape, a sleeve's frill, a
69
+ bow), and one generation recipe; report those as not checked. A hip a skirt
70
+ hides is written `occluded` with its estimated position, not `observed`.
70
71
  1. `rig-parts inputs --source <painting> --config config.json --out <dir>` writes
71
72
  `st_input_full.png`, the painting on a white square. The config needs only `key`,
72
73
  `seethrough` and `assemble.rig_scale` at this point. Run See-through on it — any
@@ -83,9 +84,11 @@ under that.
83
84
  `work/render/recomposite_error_rig.png`; a large red hole between two parts is a
84
85
  gap See-through left (a skirt split into two legs), fixed in the plan or the layers,
85
86
  not in the rig. Then `rig-parts propose --parts work/rig
86
- --source <painting> --out work` → copy `bones`, `meshes`, `regions`, `motion`
87
- from `proposal.json` into the config. `assemble` needs the plan and none of
88
- those four; do not stub them to get past it (AUTHORING §4 says what each step
87
+ --source <painting> --out work` → copy `bones`, `meshes`, `regions`, `limbs`,
88
+ `motion`, `constraints`, `turn` from `proposal.json` into the config, each it
89
+ wrote (`limbs` only with `--keypoints`, `constraints` only with `--cloth`, `turn`
90
+ only with `--full`/`--head`; a `limbs` block left out is refused at the next step). `assemble` needs the plan and none of
91
+ those sections; do not stub them to get past it (AUTHORING §4 says what each step
89
92
  requires). If an `uncovered hole` stays large with the plan right — a piece
90
93
  of the figure neither run holds, red in `recomposite_error_rig.png` — add an
91
94
  `assemble.patches` entry (a rig-pixel box, `alpha: "silhouette"`, drawn
@@ -107,6 +110,18 @@ under that.
107
110
  again, and read each `limb cap:` line for the pixels a cap is missing. A clean
108
111
  LINT does not show a seated hip is right; the overlay does. Never write a joint you did not get from an
109
112
  estimator or the painting: say `missing` and let the rule stand in.
113
+ A skirt or hair that must answer the scene (wind, the body moving) rather than
114
+ loop a keyed swing: add a `cloth` block to the config — one recipe per tag,
115
+ `bottomwear`, `back hair`, `front hair`: `chains`, `links`, `wind` and `gravity`
116
+ as `[root, tip]` (multipliers of the consumer's environment, tip >= root), and
117
+ optionally `split`, `strength`, `damping`/`alternate_damping`, `translate`,
118
+ and on the skirt `swing.scales` (AUTHORING §3, *Recipe: cloth and hair*) —
119
+ and propose with `--cloth config.json`; copy its `constraints` too. Every
120
+ number is yours but `length_ratio` and `strength`, whose defaults the note
121
+ names. Weights across neighbouring trees are not drafted (issue #378). No
122
+ stop at the legs is drafted: on the recipe's fixture the environment alone
123
+ pushed no hem through a thigh, but the consumer's hip motion can
124
+ (rig-c/core#1413).
110
125
  6. Correct against `render/landmarks.png` and `note:` lines; a
111
126
  `coverage … not checked` line is a bone no check read (the line says why),
112
127
  and `basis.json` beside the proposal says what each bone rests on — check
package/src/build.ts CHANGED
@@ -70,7 +70,7 @@ import {
70
70
  splitSchedule,
71
71
  untestedIntervals,
72
72
  } from './autoreplay.ts';
73
- import { besideIdleLine, FOLD_LINE, type FoldsLine, LEVEL_LINE, type LevelLine, LIMB_LINE, type LimbLine, STRESS_LINE, buildGateLines, causeLines, IDLE_FPS, IDLE_MAX_PX, maxRgbDiff, REQUIREMENTS_DIR, type CheckReport, type PackLine, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, JUDGEMENT_LINES, type JudgementLine, packedBuildArgs, packedBuildLabel, type PackMode, type PackShape, type PageEdges, readFrameSet, rigcFailed, rigcIdentity, rigcRanClause, REPORTED_LINES, type ReportedLine, type RigcRunner, runCheck, SEAM_DIR, SEAM_MEAN_BAR, seamPairText, seamRigPxText, SOURCE_LINE, SEAM_PX_BAR, SEAM_PX_LEVEL, SEAM_PX_LEVEL_HIGH, SPINEBOY_YARDSTICK, STILL_DIR } from './check.ts';
73
+ import { besideIdleLine, FOLD_LINE, type FoldsLine, LEVEL_LINE, type LevelLine, LIMB_LINE, type LimbLine, STRESS_LINE, buildGateLines, causeLines, IDLE_FPS, IDLE_MAX_PX, maxRgbDiff, REQUIREMENTS_DIR, type CheckReport, type PackLine, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, GATE_PROFILE, JUDGEMENT_LINES, type JudgementLine, packedBuildArgs, packedBuildLabel, type PackMode, type PackShape, type PageEdges, readFrameSet, rigcFailed, rigcIdentity, rigcRanClause, REPORTED_LINES, type ReportedLine, type RigcRunner, runCheck, SEAM_DIR, SEAM_MEAN_BAR, seamPairText, seamRigPxText, SOURCE_LINE, SEAM_PX_BAR, SEAM_PX_LEVEL, SEAM_PX_LEVEL_HIGH, SPINEBOY_YARDSTICK, STILL_DIR } from './check.ts';
74
74
  import { type Cut, type Limb, loadConfig, loadConfigAndAnimations, loadEarlyConfig } from './config.ts';
75
75
  import { failLine, PartsError, type Problem, refuseIfAny } from './errors.ts';
76
76
  import type { MeshQualityReport, MotionSchedule } from 'rig-c/mesh';
@@ -365,7 +365,7 @@ function gateRun(label: string, rigc: RigcRunner, args: string[]): GateRun {
365
365
  * written anywhere, so packing them was work nobody read. No render is asked
366
366
  * of rigc by either build.
367
367
  */
368
- export const REFERENCE_BUILD_ARGS: readonly string[] = ['--profile', 'spine-html'];
368
+ export const REFERENCE_BUILD_ARGS: readonly string[] = ['--profile', GATE_PROFILE];
369
369
 
370
370
  /** The reference build's label, as the rig stage prints it. */
371
371
  export const REFERENCE_BUILD_LABEL = `build ${REFERENCE_BUILD_ARGS.join(' ')}`;
package/src/check.ts CHANGED
@@ -30,7 +30,7 @@
30
30
  *
31
31
  * | output | what |
32
32
  * | --- | --- |
33
- * | `build/` | `rigc build --profile spine-html --pack --page-edges free --pack-shape polygon` (or `pot`, `rect`, when the caller names them; {@link PAGE_EDGES}, {@link PACK_SHAPES}) — the packed atlas is the final artifact |
33
+ * | `build/` | `rigc build --profile rig-play --pack --page-edges free --pack-shape polygon` (or `pot`, `rect`, when the caller names them; {@link PAGE_EDGES}, {@link PACK_SHAPES}) — the packed atlas is the final artifact |
34
34
  * | `gate_spine-html.txt` | that build's gate lines, verbatim — the one gate: rigc's `build` runs it once over the compile and once over the packed pages on disk, and `spine-html` holds every rule `spine` measures (selftest `CH09`) |
35
35
  * | `idle_frames/` | `rigc render --animation idle --fps 12 --max 640 --geometry`: `frames.json` + `idle/f*.png` + `idle/geometry.json` (each mesh's skinned vertices, which `TEXTURE_STRETCH` reads, every attachment's posed triangles, which `TIP_OVER_ROOT` and both halves of `STILL_REGIONS_DARK` read since issues #118 and #123, and every bone's world transform, which the face half reads its head bone from) |
36
36
  * | `contact.png` | rigc's own contact sheet of that render, copied out |
@@ -304,9 +304,17 @@ export interface PackMode {
304
304
  /** Both defaults, {@link DEFAULT_PAGE_EDGES} and {@link DEFAULT_PACK_SHAPE}. */
305
305
  export const DEFAULT_PACK_MODE: PackMode = { pageEdges: DEFAULT_PAGE_EDGES, packShape: DEFAULT_PACK_SHAPE };
306
306
 
307
+ /**
308
+ * The profile every rigc build this package runs is gated under. rig-c 2.50.0
309
+ * renamed `spine-html` to `rig-play` and runs the same rules under it; the old
310
+ * name is accepted only until a later minor release and prints a deprecation
311
+ * line on stderr (selftest `CK20` holds every stage's build to the new name).
312
+ */
313
+ export const GATE_PROFILE = 'rig-play';
314
+
307
315
  /** The packed build's rigc arguments after `--out <dir>`, as every stage that packs passes them. */
308
316
  export function packedBuildArgs(mode: PackMode): string[] {
309
- return ['--profile', 'spine-html', '--pack', '--page-edges', mode.pageEdges, '--pack-shape', mode.packShape];
317
+ return ['--profile', GATE_PROFILE, '--pack', '--page-edges', mode.pageEdges, '--pack-shape', mode.packShape];
310
318
  }
311
319
 
312
320
  /** The packed build as a label: the rigc command line that was run, after `rigc`. */