rig-parts 1.5.5 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -9
- package/cli.ts +19 -6
- package/docs/AUTHORING.md +110 -18
- package/docs/STABILITY.md +2 -2
- package/package.json +2 -2
- package/src/assemble.ts +329 -9
- package/src/build.ts +163 -11
- package/src/check.ts +224 -28
- package/src/instruments.ts +34 -10
- package/src/parts.ts +39 -2
- package/src/propose.ts +374 -45
- package/src/requirements.ts +58 -3
- package/src/rig.ts +214 -11
- package/src/scene.ts +14 -1
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ pose that holds the hands apart, then given one hand-detailer pass; its generati
|
|
|
29
29
|
record, See-through layers and licence are in
|
|
30
30
|
<a href="https://github.com/rig-c/parts-examples">parts-examples</a>.
|
|
31
31
|
See-through ran twice, once on the whole figure and once on a square head crop.
|
|
32
|
-
Then one command: <code>rig-parts build --loop</code>. The proposer's bones, meshes,
|
|
32
|
+
Then one command: <code>rig-parts build --loop --lead-in 3</code>. The proposer's bones, meshes,
|
|
33
33
|
regions and motion were used as proposed but for one correction, written in the
|
|
34
34
|
config beside the values it replaced: the two outer skirt chains were moved out to
|
|
35
35
|
0.8 of the skirt's half-width (the proposal's, within 90 px of the centre of a skirt
|
|
@@ -37,14 +37,17 @@ config beside the values it replaced: the two outer skirt chains were moved out
|
|
|
37
37
|
against 1.4725; moved, 2.425). One input-stage edit: <code>hair_back</code> is taken
|
|
38
38
|
from the full run, because the twin tails leave the head crop sideways (a plan edit).
|
|
39
39
|
<code>check</code> printed, verbatim:<br/>
|
|
40
|
-
<code>50 assertions:
|
|
40
|
+
<code>50 assertions: 25 measured (25 passed, 0 failed), 25 skipped, 0 not in profile "spine-html"</code><br/>
|
|
41
41
|
<code>loop: idle 49 frame(s) at 12 fps, f0000 vs f0048 (t = 4s): max |d| 0 (0 required)</code><br/>
|
|
42
42
|
<code>seam: setup pose at 654x1216, scale 0.9438: mean |d| 0.147 (<= 1.0), 0 px over 40, 0.00 rig px (the count / s²; <= 50), 0 px over 80 (reported)</code><br/>
|
|
43
43
|
<code>pack: skeleton.png 1051x972, 23 region(s), 96.9% covered, padding 2, page edges free, shape polygon</code><br/>
|
|
44
|
-
The loop is
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
The loop is that build's indexed APNG, 48 frames at 12 fps, 727,486 bytes, one
|
|
45
|
+
256-entry palette at a measured error of max 69, mean 0.630 per channel over every
|
|
46
|
+
frame (the lossless APNG beside it, the exactness record, is 5,148,992 bytes; the
|
|
47
|
+
GIF, at the same error, 781,526). The rig's hair, skirt, sleeves, bows and earrings
|
|
48
|
+
carry physics, which rigc's render starts from rest, so the idle is played three
|
|
49
|
+
periods ahead and the loop is the fourth: its last frame and the first differ by at
|
|
50
|
+
most 1 level (<code>--lead-in</code>). Frame 29 (2.417 s) is the
|
|
48
51
|
closed eye: the blink holds for 0.084 s, one 12 fps frame rounded up; the painting is
|
|
49
52
|
shown at half size, resampled and written by this package's PNG codec (nothing here
|
|
50
53
|
encodes JPEG). <code>rig-parts sheet</code> made the contact sheet. Its
|
|
@@ -274,7 +277,7 @@ agent skill.
|
|
|
274
277
|
| `comfy seethrough --image --out [--host]` | optional: run the ComfyUI See-through wrapper on one image and write the form `layers` reads |
|
|
275
278
|
| `layers <dir \| layers.json \| file.psd>` | print every layer of a decomposition: draw order, name, tag group, box, size, opaque pixels, depth, and its translucent, background and area figures; a `WARN` line for a layer `--propose-plan` will leave out |
|
|
276
279
|
| `sheet --source <png> --layers <path>… --out <png>` | a labelled contact sheet of the painting and every layer or part |
|
|
277
|
-
| `assemble --propose-plan …` | propose `assemble.plan` and `extend_below_crop` from the two runs, leaving out an implausible layer with a note naming the rule |
|
|
280
|
+
| `assemble --propose-plan …` | propose `assemble.plan` and `extend_below_crop` from the two runs, leaving out an implausible layer with a note naming the rule, and naming in a note any full-run body no planned part covers |
|
|
278
281
|
| `assemble --source --full --head --config --out [--seam] [--project]` | merge the two runs into rig-space parts, `parts.json`, the recomposite and its error map, and list the uncovered holes |
|
|
279
282
|
| `propose --head-box --full <run> --canvas WxH` | propose `seethrough.head_box` from the full run, held inside the painting |
|
|
280
283
|
| `propose --parts --source --out [--compare <config>]` | propose bones, meshes, regions and an idle; draw the overlay; print, per bone, which check read it or that none did and why (its role, its kind of segment), and write `basis.json` beside the proposal — what each bone rests on (a joint, a part's mask, a ratio, other bones) and, with `--compare`, whether the config's bone differs |
|
|
@@ -284,7 +287,7 @@ agent skill.
|
|
|
284
287
|
| `rig --config --parts --out [--idle-keys ctl\|direct]` | author `rig.json` + `motion.json`, written only after rig-c's gate is green; each mesh is in the mode its config entry names — `grid` (the lattice, what `propose` writes), `contour` (the traced outline with declared interior points) or `auto` (the contour mesh at alpha 1 and above, reduced and locally refined by rig-c's `reduceMesh` under the author's declared bounds, written only when its motion against the unreduced source on the idle passes the author's `motion` bounds through rig-c's `compareMeshesInMotion`; [AUTHORING §3](docs/AUTHORING.md)); every chain link is turned along its chain and carries its `length`, so a physics constraint added later has a lever, with every offset under it in the turned frame so nothing moves; `--idle-keys` says whether the idle's keys on mesh-driving bones go through `<bone>_ctl` parents (default) or stay on the bones with `invariants.idleDrivesMeshes` declared; the config's `constraints` go to rigc as written, and a two-bone ik over keyed links needs `--idle-keys direct` (on `rig` or `build`) |
|
|
285
288
|
| `check --rig --out [--parts] [--source] [--requirements]` | build packed, gated under `spine-html`, render the idle, measure seam, loop and the six judgement lines (mesh texture stretch among them, from the idle's `render --geometry`), and report the recomposite's holes from `parts.json`; on a rig spec with no `parts.json` or no `idle` (a merged rig, issue #77) the gate still runs and every line that needs the missing input says SKIP by name; `--source <painting.png>` adds `SETUP_POSE_VS_SOURCE`, the setup pose against the painting by assemble's recomposite figures; `--requirements <scene.json>` measures what a scene declares of the motion — a contact, a follow fraction, an aim, a joint range, a mesh's stretch, the seam between two parts over the motion — each against the author's own bar, from rig-c's posed frames, one line each, PASS, FAIL or NOT MEASURABLE (AUTHORING §7, *Declared requirements*) |
|
|
286
289
|
| `loop --frames <dir> --out <file.gif \| file.png> [--palette]` | encode a rendered idle as a looping GIF, lossless APNG, or indexed APNG (`--palette`) |
|
|
287
|
-
| `build --config --source --full --head --out [--seam] [--project] [--loop] [--requirements] [--idle-keys ctl\|direct]` | assemble, rig and check in one process, stopping at the first refusal; `--requirements` is forwarded to check, `--idle-keys` to rig |
|
|
290
|
+
| `build --config --source --full --head --out [--seam] [--project] [--loop] [--lead-in <periods>] [--requirements] [--idle-keys ctl\|direct]` | assemble, rig and check in one process, stopping at the first refusal; `--requirements` is forwarded to check, `--idle-keys` to rig; `--lead-in` (with `--loop`) encodes the loop from the last of n + 1 idle periods played back to back, for a rig whose physics does not end where the render starts it |
|
|
288
291
|
| `compose --scene <scene.json> --out [--requirements] [--accept]` | bind several characters' green builds into one rig (or, under `--accept`, builds failing only the bars named — for looking, not shipping): every name prefixed `<id>:` under one shared root, each character's offset added at its first-level bones, an optional background plate (its provenance recorded, judged by nothing) drawn first, and the draw order between the characters' slots as the scene file declares it — nothing inferred, nothing scaled; gated through rig-c as `rig` is, then checked ([AUTHORING §7](docs/AUTHORING.md), *Composing several characters*) |
|
|
289
292
|
|
|
290
293
|
`rig-parts --help` has every flag. Exit codes: 0 done, 1 input refused (every
|
|
@@ -333,7 +336,11 @@ These are limits of the approach, stated so nobody reads more into a green run:
|
|
|
333
336
|
### What can be built on top
|
|
334
337
|
|
|
335
338
|
This package makes no expression and no jiggle, but the rig it writes is the material for
|
|
336
|
-
both, and the config has a field for each
|
|
339
|
+
both, and the config has a field for each; `examples/demo` and `examples/scarf` carry a worked
|
|
340
|
+
set of each (issue #224: a hop, a head tilt, a wave or a bow, and physics on the hair, the
|
|
341
|
+
skirt, the sleeves and the scarf ends; also two head turns, a smile and a startle, which at
|
|
342
|
+
full-body size read as small moves of the head and face rather than as expressions —
|
|
343
|
+
one image per slot leaves the face only what its bones can do). [docs/AUTHORING.md](docs/AUTHORING.md) has a recipe
|
|
337
344
|
for each — a config fragment, the `check` lines it passes with, and its limit:
|
|
338
345
|
|
|
339
346
|
- [**Expressions and other named animations**](docs/AUTHORING.md#recipe-expressions-and-other-named-animations):
|
package/cli.ts
CHANGED
|
@@ -358,7 +358,11 @@ usage:
|
|
|
358
358
|
mean channel; error px: max channel > 40; uncovered: of those, where no
|
|
359
359
|
part has alpha above 128), then the uncovered holes (8-connected) and the
|
|
360
360
|
largest ${HOLES_LISTED}, each \`uncovered hole N: <px> px at x,y wxh (between
|
|
361
|
-
"<part>" <px> px, …)\` — the list parts.json holds under recomposite
|
|
361
|
+
"<part>" <px> px, …)\` — the list parts.json holds under recomposite —
|
|
362
|
+
and one \`uncovered:\` line per full-run layer the plan does not take from
|
|
363
|
+
the full run whose uncovered error holds a body (5x5-opened, 8-connected,
|
|
364
|
+
at least 150 full-run px in rig px), naming the layer, its pixels and the
|
|
365
|
+
rule that left it out.
|
|
362
366
|
Writes nothing unless every check passed.
|
|
363
367
|
--seam defaults to ${DEFAULT_SEAM_RULE}. --project says where a layer takes
|
|
364
368
|
the painting's pixel: core (the reference's) erodes every layer's top-most
|
|
@@ -371,7 +375,11 @@ usage:
|
|
|
371
375
|
Print {plan, extend_below_crop, notes} for config.assemble, from the two
|
|
372
376
|
runs. A layer \`layers\` WARNs about (PLAN_LAYER_TRANSLUCENT,
|
|
373
377
|
PLAN_LAYER_BACKGROUND, PLAN_LAYER_OVERSIZED) is not proposed, and a note
|
|
374
|
-
names it, its figures and the rule.
|
|
378
|
+
names it, its figures and the rule. A full-run layer holding a body no
|
|
379
|
+
planned part covers (a lock the head run's part does not reach and
|
|
380
|
+
extend_below_crop cannot continue) is named in a note with the body, the
|
|
381
|
+
rule that skipped it and the continuation; the plan itself is not
|
|
382
|
+
changed. Reads only config.seethrough.head_box,
|
|
375
383
|
config.seethrough.resolution and config.assemble.rig_scale — the rest of
|
|
376
384
|
the config need not exist yet.
|
|
377
385
|
|
|
@@ -409,7 +417,7 @@ usage:
|
|
|
409
417
|
--head <dir|psd> --out <dir> [--seam near-white|silhouette]
|
|
410
418
|
[--project core|visible] [--page-edges pot|free]
|
|
411
419
|
[--pack-shape rect|polygon] [--loop] [--requirements <file.json>]
|
|
412
|
-
[--idle-keys ctl|direct]
|
|
420
|
+
[--idle-keys ctl|direct] [--lead-in <periods>]
|
|
413
421
|
assemble, then rig, then check, in one process, each stage's own lines
|
|
414
422
|
printed under [assemble], [rig] and [check]; the first stage that refuses
|
|
415
423
|
stops the build with its own FAIL lines. The config must already carry
|
|
@@ -420,7 +428,9 @@ usage:
|
|
|
420
428
|
rig/ (rig), check/ (check, with the packed build in check/build/), and with
|
|
421
429
|
--loop idle.png (lossless APNG), idle-indexed.png (indexed APNG) and
|
|
422
430
|
idle.gif from check/idle_frames/, then one loop: line with the three sizes
|
|
423
|
-
and the two palette errors.
|
|
431
|
+
and the two palette errors. --lead-in <n> (with --loop) encodes them
|
|
432
|
+
instead from the last of n + 1 idle periods played back to back, for a
|
|
433
|
+
rig whose physics does not end where rigc's render starts it. The paths it writes are cleared first. A
|
|
424
434
|
green build ends with the pack line beside the spineboy yardstick and the
|
|
425
435
|
three artifact paths — skeleton .json, .atlas and the packed page: the
|
|
426
436
|
packed atlas is the result, the loose parts are the intermediate it was
|
|
@@ -566,7 +576,7 @@ const TAKES = {
|
|
|
566
576
|
'comfy seethrough': { valued: ['--image', '--out', '--resolution', '--steps', '--seed', '--prefix', '--host', '--wait', '--timeout', '--poll'], switches: ['--offload', '--lama', '--nf4'] },
|
|
567
577
|
'comfy paint': { valued: ['--config', '--out', '--seeds', '--seed0', '--host', '--wait', '--timeout', '--poll'], switches: [] },
|
|
568
578
|
inputs: { valued: ['--source', '--config', '--out'], switches: [] },
|
|
569
|
-
build: { valued: ['--config', '--source', '--full', '--head', '--out', '--seam', '--project', '--page-edges', '--pack-shape', '--requirements', '--idle-keys'], switches: ['--loop'] },
|
|
579
|
+
build: { valued: ['--config', '--source', '--full', '--head', '--out', '--seam', '--project', '--page-edges', '--pack-shape', '--requirements', '--idle-keys', '--lead-in'], switches: ['--loop'] },
|
|
570
580
|
compose: { valued: ['--scene', '--out', '--requirements', '--accept'], switches: [] },
|
|
571
581
|
} as const satisfies Record<string, { valued: readonly string[]; switches: readonly string[] }>;
|
|
572
582
|
|
|
@@ -1163,6 +1173,9 @@ function cmdBuild(args: string[]): number {
|
|
|
1163
1173
|
if (!isPackShape(shape)) return usage(shape);
|
|
1164
1174
|
const keys = idleKeysOf(flags.get('--idle-keys'));
|
|
1165
1175
|
if (!isIdleKeys(keys)) return usage(keys);
|
|
1176
|
+
const leadText = flags.get('--lead-in');
|
|
1177
|
+
if (leadText !== undefined && !/^[1-9][0-9]*$/.test(leadText)) return usage(`--lead-in ${leadText}; a whole number of idle periods, 1 or more, is required`);
|
|
1178
|
+
if (leadText !== undefined && !loop) return usage('--lead-in needs --loop; it says which frames the loop is encoded from');
|
|
1166
1179
|
const [config, source, full, head, out] = ['--config', '--source', '--full', '--head', '--out'].map((f) => flags.get(f) as string);
|
|
1167
1180
|
let bin: string;
|
|
1168
1181
|
try {
|
|
@@ -1173,7 +1186,7 @@ function cmdBuild(args: string[]): number {
|
|
|
1173
1186
|
const scratch = mkdtempSync(join(tmpdir(), 'rig-parts-build-'));
|
|
1174
1187
|
try {
|
|
1175
1188
|
const r = build(
|
|
1176
|
-
{ config, source, full, head, out, seam: seam as SeamRule, project: project as ProjectRule, loop, pageEdges: edges, packShape: shape, ...(flags.has('--requirements') ? { requirements: flags.get('--requirements') as string } : {}), idleKeys: keys },
|
|
1189
|
+
{ config, source, full, head, out, seam: seam as SeamRule, project: project as ProjectRule, loop, pageEdges: edges, packShape: shape, ...(flags.has('--requirements') ? { requirements: flags.get('--requirements') as string } : {}), idleKeys: keys, ...(leadText === undefined ? {} : { leadIn: Number(leadText) }) },
|
|
1177
1190
|
{ rig: rigcRunner(bin), check: rigcRunner(bin), checkBin: bin, scratch: join(scratch, 'rig-gate') },
|
|
1178
1191
|
console.log,
|
|
1179
1192
|
);
|
package/docs/AUTHORING.md
CHANGED
|
@@ -91,7 +91,7 @@ read by no CPU stage).
|
|
|
91
91
|
| `assemble.extend_below_crop` | assemble | **proposed** with the plan: `{part, run, tag}` — a head-run part that reaches the bottom of the head crop is continued from a full-run layer, whole connected components |
|
|
92
92
|
| `assemble.patches` | assemble; `meshes`/`regions` keys may name them too | **authored**, optional: `[{name, box, alpha, draw}]` — an extra part cut from the **painting** itself, for figure no See-through layer holds (a hem both runs dropped). `box` is `[x0, y0, x1, y1]` in **rig** pixels, `x1`/`y1` exclusive — the space of `parts.json` and `recomposite_rig.png`, where the hole is found; `alpha` is `"silhouette"` (the painting's figure silhouette inside the box, the one `--seam silhouette` uses) or `"box"` (the whole box); `draw` is `"back"`, `"front"` or `{"before": "<plan part>"}`. A patch is always a region: its bone is `regions.<name>`, in the one place every region's bone lives, and a `meshes` entry for it is refused. See §5 for how to place one |
|
|
93
93
|
| `assemble.cuts` | assemble; `meshes`/`regions` keys may name the new parts too, and must (each is a part like any other) | **authored**, optional (issue #170): `[{from, into, polygon, draw, overlap, under}]`, `under` optional — a plan part's layer cut by a polygon the author draws: the pixels of plan part `from` whose **centre** lies inside `polygon` (even-odd; a centre exactly on an edge is outside) leave `from` and make the new part `into`, colour and alpha, so every pixel of the layer ends in exactly one of the two. `polygon` is `[[x, y], …]`, at least three points, non-negative integer **rig** pixels — the space of `parts.json` and of the patches' boxes. The file that shows the layer in those coordinates is `assemble`'s own `rig/parts/<from>.png`, placed at its `parts.json` `x`, `y` (the PNG's pixel `(i, j)` is rig pixel `(x + i, y + j)`), or `render/recomposite_rig.png`, the whole rig 1:1; the contact sheets (`sheet`) are scaled and carry no coordinates. `draw` is `"back"`, `"front"` or `{"before": "<plan part>"}`, as for a patch (to keep the setup pose, draw the piece immediately in front of `from` — `{"before": "<the plan part after from>"}`, or `"front"` when `from` is the last plan part; `{"before": "<from>"}` draws it behind `from`, which `under` refuses as `ASSEMBLE_UNDER_DRAW` because the fill would hide it). `from` must be a plan part (`CONFIG_NAME_RESOLVES`; a patch or another cut's piece is refused), `into` a new name (`CONFIG_PART_UNIQUE`), the polygon three or more integer points (`CONFIG_FIELD_TYPE`). The piece's `parts.json` record carries `from`'s `<run>:<tag>` and its own counts, each split from the layer's by where the pixel lies; it is a mesh or a region under its own name, and the coverage rule holds it like a plan part. What the config cannot know the stage refuses: a polygon point past the rig (`ASSEMBLE_CUT_INSIDE`), two cuts of one part sharing a pixel (`ASSEMBLE_CUT_OVERLAP`), a cut that takes none of the layer's opaque pixels or leaves `from` none (`ASSEMBLE_CUT_PIXELS`). `overlap` is required, a non-negative integer of rig pixels with no default (`CONFIG_FIELD_TYPE`): the **band** — the polygon's pixels within `overlap` px of its edge by Chebyshev distance (the polygon's mask less its erosion by a `2 * overlap + 1` square) — stays in `from` as well as going to the piece, so the piece's resampled edge has art under it; the counts stay a strict partition and the band is the base's extra copy, printed on the `cut:` line. At `0` the two abut and `check`'s seam bar judges the edge between them (`CHECK_SEAM_WITHIN_BAR`, §5). A band only covers the edge at rest: a piece that swings well clear of where it was painted shows the hole it leaves, and a thin piece's band shows a ghost of the piece. `under` (issue #193), optional, is the author's image of what lies under the piece: a PNG path relative to the config's directory (`CONFIG_FIELD_TYPE` unless a non-empty string), in rig pixels over the polygon's **bounding box** — the least and greatest polygon x and y, so the image is `max x − min x` by `max y − min y` and its pixel `(i, j)` is rig pixel `(min x + i, min y + j)`. Where the cut removed pixels from `from` — the piece's pixels (alpha above 0) less the band — `from` takes the image's pixel, colour and alpha wherever the image's alpha is at least the alpha the cut removed there (**filled**); elsewhere `from` stays empty there (**left empty**): a transparent pixel is the author's statement that nothing lies under it (the background, or a part drawn behind), and a less opaque one is not half-filled. The image is read nowhere else, so its pixels over the band, over the box outside the polygon or where the layer had no art never change `from`. The `cut:` line then ends `; under <n> px filled, <m> px left empty` (`n + m` is every removed pixel), so an unintended hole is a number in the log, not a guess; the filled pixels count in `from`'s `opaque_px` and `occluded_px` (the piece is drawn over them), never as visible or projected. The stage refuses: a file that is not there (`ASSEMBLE_UNDER_PRESENT`) or not a PNG (`ASSEMBLE_UNDER_DECODES`), an image not exactly the box's size (`ASSEMBLE_UNDER_SIZE`, both sizes given), an image that fills none of the removed pixels — all transparent there, or another file (`ASSEMBLE_UNDER_EMPTY`; to leave the whole hole, drop `under`), and a piece drawn behind `from` (`ASSEMBLE_UNDER_DRAW`: the fill would hide it; draw it `"front"` or `{"before": "<the plan part after from>"}`). Producing the image is the author's, by whatever means; absent, `from` keeps only its band |
|
|
94
|
-
| `bones` | rig; `propose --from-config` | **proposed** by `propose`, then corrected. A single bone `{name, parent, at, tip?}` or a chain `{chain, parent, points, tip}` whose links are named `<chain>0 … <chain>n`. Parents come before children. In `rig.json` each link is **turned along its chain** — `rotation` is the direction from its origin to the next link's (the last link's to `tip`) and `length` that distance (issue #73), so a physics constraint added downstream finds a lever; under `--idle-keys ctl` the link's `<link>_ctl` carries the turn and the length and the link sits at local rotation 0 beneath it. A single bone is
|
|
94
|
+
| `bones` | rig; `propose --from-config` | **proposed** by `propose`, then corrected. A single bone `{name, parent, at, tip?}` or a chain `{chain, parent, points, tip}` whose links are named `<chain>0 … <chain>n`. Parents come before children. In `rig.json` each link is **turned along its chain** — `rotation` is the direction from its origin to the next link's (the last link's to `tip`) and `length` that distance (issue #73), so a physics constraint added downstream finds a lever; under `--idle-keys ctl` the link's `<link>_ctl` carries the turn and the length and the link sits at local rotation 0 beneath it. A single bone with a `tip` is turned the same way, towards its tip, with that distance as its length (issue #239); a tip on the bone's own origin is refused (`RIG_TIP_DISTINCT`). The five face bones `eye_r`, `eye_l`, `brow_r`, `brow_l` and `mouth` (by name, when one has no tip of its own) are turned to the eye line — the line through the origins of `eye_r` and `eye_l` as `bones` writes them, read image-left to image-right, drawn when parts.json holds both an `eyewhite-r` and an `eyewhite-l` part — so the blink's `scaley` squashes across the eye line on a tilted head; move an eye bone and the line moves with it. With one eyewhite or none, or an eye bone missing, the rig stage's `face axis:` line says so and they keep the page's axes. A bone under a face bone keeps the face's axis. With the line, `rig.json` also declares `invariants.axes` — one entry, `"face"`, through `eye_r` and `eye_l`, holding the turned face bones (and their controls) — so rig-c's gate holds the build to the line; the line is the one rigc draws through the same two bones, so the tolerance is only the float floor — the largest gap the emitted (float32) bones have to it, rounded up to 6 places plus one 6-place unit — and the `face axis:` line prints it. A failure is rig-c's `A51_BONES_LIE_ALONG_THEIR_DECLARED_AXIS` line, which names the bone and the fix (rig-c's `docs/AUTHORING.md` §3.7 and §5.2); with no line no entry is written and A51 reports SKIP. Every region on a turned bone is turned back, so the setup pose does not move. Any other single bone keeps world rotation 0; one whose parent is a link is turned back upright |
|
|
95
95
|
| `meshes.<part>` | rig | **proposed**, then corrected. Exactly one of `grid` (the lattice: cell size, px — what `propose` writes), `contour` (the outline mode, authored; the next row and "A contour mesh" below) or `auto` (the automatic mode, authored; "An automatic mesh" below) — two, or none, is `CONFIG_MESH_MODE`. In every mode: `r` (added to every distance before weighting: `w = 1/(d + r)²`), `segments` (a chain name, a bone name with a `tip`, or `[bone, [x0,y0], [x1,y1]]`), and, **authored**, optional, `exponent` (issue #161): a number above 0 that replaces the 2 in that rule, `w = 1/(d + r)^exponent` — a larger one hands each vertex more fully to its nearest bone; absent is 2 and changes no byte, a value that is not a number above 0 is `CONFIG_FIELD_TYPE` at `meshes.<part>.exponent`, and a declared one is echoed as `exponent` in the mesh's `mesh_report.json` row; the exponent is the distance rule's, so declared beside `rule: "heat"` it is refused (`CONFIG_FIELD_TYPE` at `meshes.<part>.exponent`). The segment list is the one authored decision about a layer: which bones may pull it. The slot's bone is the first segment's. Optional `rule` (issue #161): `"distance"` — the rule above, and what an absent `rule` means (every byte is the same) — or `"heat"`, bone heat over the part's own silhouette, in every mode: the lattice's art (alpha above 8) with holes filled, or for `contour` and `auto` the silhouette their outline is traced from (that mode's art — alpha above 8 for `contour`, alpha 1 and above for `auto` — less any island a declared `stray` left out, holes filled, grown by its `margin`); each bound bone's sources are the silhouette pixels whose centre lies within 0.75 px of its segment (a pixel two bones reach goes to the nearer, a tie to the first listed), held at 1 for that bone and 0 for the others; the field is solved by row-major Gauss–Seidel over-relaxation to a sweep change under 1e-7 within 20000 sweeps; a vertex reads the nearest silhouette pixel and takes the same cap and floor (and `regions`) as the distance rule; `r` is not read. The mesh's `mesh_report.json` row gains `heat` (the constants, each bone's sources and sweeps, the residual). Any other value is `CONFIG_FIELD_TYPE`; a bound bone with no source pixel is `RIG_HEAT_BONE_SOURCE`, an island no bone has a source in `RIG_HEAT_ISLAND_SOURCE`, a solve past its sweep bound `RIG_HEAT_CONVERGED` — none is weighted 0 |
|
|
96
96
|
| `meshes.<part>.contour` | rig | **authored**, optional (issue #84): `{tolerance, margin, spacing, budget?, stray?, regions?}`. `tolerance` — rig-c's Douglas–Peucker tolerance on the traced outline, px, 0 or more; `margin` — how far the silhouette grows before it is traced, px: 0, or 1 or more (a pixel joins when its centre lies within `margin` of an art pixel's centre; a value above 0 and below 1 adds nothing and is refused, `CONFIG_FIELD_TYPE`); `spacing` — the background interior spacing, px, above 0; `budget` — the most vertices the mesh may have (refused above it, nothing thinned); `stray` — the largest island, in art pixels, that may be left out of the mesh (absent: none is); `regions` — local deformation regions, each `{name, shape, bone, spacing, band}` with `shape` `"circle"` (`cx, cy, r`) or `"polygon"` (`points`, 3 or more): `bone` is the region's control bone (any bone `bones` declares), `spacing` the interior spacing inside the region and its band, `band` the width the bone's weight falls across. Every length and position is **rig px**, like every other in the config; the part image is the rig less `(x − 4, y − 4)` (its box less the pad), a translation, so a length is the same number in both. A region's `cx`, `cy`, `r`, `band` and `points` are multiples of 1/256 px (`CONFIG_FIELD_TYPE` otherwise); region names are unique per mesh (`CONFIG_REGION_NAME_UNIQUE`). The alpha threshold is not a field: art is alpha above 8, the lattice's and `check`'s |
|
|
97
97
|
| `meshes.<part>.ribs` | rig | **authored**, optional (issue #188), in the `contour` and `auto` modes: `{<chain>: {stations}, …}`, each key a chain this mesh's `segments` name. Each link of the chain gets a row of vertices across the part at its origin and at `stations` points evenly between its origin and its end (`stations`, a whole number, 0 or more, required; a chain of L links carries L × (stations + 1) ribs), each rib a row of vertices across the part, kept as a row of locked edges; the rule is "Ribs along a chain" under "A contour mesh". Absent places none and changes no byte. Refused: a lattice mesh with ribs (`CONFIG_RIBS_MODE` — its vertices are its grid's corners), a key that is not one of the mesh's chains (`CONFIG_NAME_RESOLVES`), an object naming no chain or a `stations` that is not a whole number from 0 (`CONFIG_FIELD_TYPE`); at the rig stage `CONTOUR_RIB_ART`, `CONTOUR_RIB_LINK`, `CONTOUR_RIB_CROSSING`, `CONTOUR_RIB_EDGE` (the contour refusals). The mesh's `mesh_report.json` row gains `ribs` — the declaration, the ribs placed and the vertices they hold — and its contour report (the source's, in `auto`) lists each rib's vertices |
|
|
@@ -200,6 +200,8 @@ What a joint with a position places, as given — no ratio is applied over it:
|
|
|
200
200
|
| `chest` | its rule, half way from neck to hip, taken along the line between the placed ends | the rule as before when neither end is a joint |
|
|
201
201
|
| `sleeve_<s>` | `<s>_shoulder` → `<s>_elbow` (two links), tip at `<s>_wrist`, with the two-blob rule's first two amplitudes and its chest stub laid along the upper arm — when every handwear part over 500 px holds one such wrist within 15 px of its art (the larger of the x and y gaps, the LINT's own tolerance), or is bound one by `--wrist-snap` (below) | the sleeve rule places every sleeve chain, and each arm joint's note says why: for a wrist on no part, `… lies on the art of no handwear part within 15 px, so it does not say which sleeve it ends; the nearest is <part>, <d> px from its art by the larger of the x and y gaps (--wrist-snap <d> would bind it)` — `(beyond --wrist-snap <px>)` when the flag was given and fell short, and `the nearest are <a> and <b>, each <d> px …, so no tolerance says which` when two parts tie |
|
|
202
202
|
| `eye_<s>`, `head`, the face box | not moved: they are measured off the parts | the note prints the eye joint's distance from the eye bone, with no bar |
|
|
203
|
+
| `leg_<s>` or `leg` (issue #241) | on a `legwear` part over 500 px: `<s>_hip` → `<s>_knee` (two links), tip at `<s>_ankle`, parent `hip`, the part meshed on the chain and a `hip` stub laid along the thigh — when every such part holds the ankle of a leg whose three joints are given, within 15 px of its art. A part holding both ankles gets a chain per leg only when its art breaks along the line from `r_knee` to `l_knee` and along the line from `r_ankle` to `l_ankle` (the legs painted apart); otherwise one chain, `leg`, through the midpoints of the two hips, the two knees and the two ankles. No idle track: the chain is drafted whatever the pose, and whether the legs move is the scene's. A note on the part says which and why | no leg with all three joints: no chain, and the part is the trunk rule's region with the note it always had, byte for byte. A complete leg whose ankle lies on no legwear part, or on two: no chain, and a note `<parts>: no leg chain — <why>; the trunk rule places it` |
|
|
204
|
+
| the trunk parts' segments (issue #243) | on the `neck` (head run), `topwear` and `bottomwear` meshes, each `[bone, from, to]` segment the rule drafts down the screen is laid along neck → hip, the line the chest is placed on — `neck` + 18 px along it to `chest`; a topwear part's `chest` segment from its art's nearest reach toward the neck end to 20 px short of `hip`, and its `hip` segment from there to 100 px past `hip`; a bottomwear part's `chest` segment from 30 px short of `chest` to 20 px short of `hip` — and the bottomwear waist segment runs across that line, 5 px past `hip`, over 0.09 to 0.91 of the art's width across it. The `head` segment on the neck mesh and the one-blob sleeve rule's chest segment are not moved. A note, `trunk segments (<parts>): laid along neck -> hip …`, gives the line's angle | neither end a joint: the vertical draft, byte for byte. Neck and hip on one point: no line, the vertical draft, and a note says so. An upright line over boxes tight on their art writes the vertical draft's bytes |
|
|
203
205
|
|
|
204
206
|
**`--wrist-snap <px>`** (issue #199), with `--keypoints` only, declares a tolerance
|
|
205
207
|
for a wrist that lies on no handwear part within the built-in 15 px — hands folded
|
|
@@ -229,8 +231,8 @@ silently:
|
|
|
229
231
|
The `assemble.cuts` entry (§3; §5, *Cutting a piece out of a layer*) splits the part; the
|
|
230
232
|
proposer does not.
|
|
231
233
|
|
|
232
|
-
Every other joint (`nose`,
|
|
233
|
-
with its state in one note: no bone is authored from it. Every joint the proposer
|
|
234
|
+
Every other joint (`nose`, ears, the knees and ankles no leg chain used; the eyes
|
|
235
|
+
with no eyewhite) is named with its state in one note: no bone is authored from it. Every joint the proposer
|
|
234
236
|
could use gets its own note — `used as given for bone X`, `used as the producer's
|
|
235
237
|
estimate for bone X`, or `missing: the rule "…" placed bone X instead` — after every
|
|
236
238
|
note the rules wrote. LINT then reads the torso by the relations the joints declare:
|
|
@@ -961,10 +963,35 @@ recipe below). With exactly this file beside `examples/reference-sample`'s confi
|
|
|
961
963
|
A bone the rig lacks is rigc's refusal at the rig stage, in rigc's words (`RIG_RIGC_GREEN`); a
|
|
962
964
|
fault in the file itself is the loader's (the row above names each one).
|
|
963
965
|
|
|
966
|
+
**Worked sets.** `examples/demo/animations.json` and `examples/scarf/animations.json`
|
|
967
|
+
(issue #224) carry `tilt`, `look_l`, `look_r`, `smile`, `startled`, a gesture (`wave` on
|
|
968
|
+
`demo`, `bow` on `scarf`) and `hop`, each a one-shot that keys only what it needs; the
|
|
969
|
+
examples' READMEs list what each keys and why. Two rules make a clip layer over the idle on
|
|
970
|
+
a player's second track rather than replace it:
|
|
971
|
+
|
|
972
|
+
- **Key the bones the idle leaves alone.** The idle turns and breathes the `*_ctl` bones
|
|
973
|
+
the rig stage writes (`head_ctl`, `chest_ctl`, a chain's `<chain><i>_ctl`) and `neck`; the
|
|
974
|
+
bone under each (`head`, `chest`, `<chain><i>`) is free. A `look_l` that keys `head` alone
|
|
975
|
+
leaves the idle's sway alive under it; one that keys `head_ctl` or `neck` stops it for as
|
|
976
|
+
long as the clip holds the key.
|
|
977
|
+
- **Key no constraint, draw order, deform or attachment.** A player mixing tracks refuses
|
|
978
|
+
those; bones are all a clip needs.
|
|
979
|
+
|
|
980
|
+
**Strands that trail.** A chain whose links lag the body is one `physics` constraint per
|
|
981
|
+
link in `constraints`, on the link bone (`hairback_r0`, not `hairback_r0_ctl`), driving
|
|
982
|
+
`rotate`; the examples soften it down the chain. A single bone with no `length` (a bow, an
|
|
983
|
+
earring, a bun) cannot take a `rotate` drive (rig-c's `A23`) and takes `x`/`y` instead. The
|
|
984
|
+
values that read on the examples, and the ones refused on the way there, are in their
|
|
985
|
+
READMEs.
|
|
986
|
+
|
|
964
987
|
**Limits.** Every slot holds one attachment, the part's own image, so an expression moves,
|
|
965
988
|
turns and scales the face's parts and never swaps one for another: there is no second mouth
|
|
966
|
-
shape to key, and no lip-sync. `check` measures the idle alone: an animation beside it
|
|
967
|
-
passed rigc's gate and nothing else — no seam, stretch or hole bar has read it.
|
|
989
|
+
or eye shape to key, and no lip-sync. `check` measures the idle alone: an animation beside it
|
|
990
|
+
has passed rigc's gate and nothing else — no seam, stretch or hole bar has read it. On the
|
|
991
|
+
examples each clip was read by `check`'s own `TEXTURE_STRETCH` reading applied to the clip's
|
|
992
|
+
`rigc render --geometry` (their READMEs give the figures); that is a measurement, not a
|
|
993
|
+
gate, and it is where an arm raised overhead was found to tear `demo`'s elbow (5.327
|
|
994
|
+
against 1.926544).
|
|
968
995
|
|
|
969
996
|
### Recipe: a soft region driven by physics
|
|
970
997
|
|
|
@@ -1122,8 +1149,14 @@ full loader before its assemble stage writes anything.
|
|
|
1122
1149
|
→ paste `plan` and `extend_below_crop` into `config.assemble`. Config: the
|
|
1123
1150
|
`layers` row, with `head_box`.
|
|
1124
1151
|
Read `notes`: a layer left out by a plausibility rule is named there with its
|
|
1125
|
-
figures and the rule (§6, *Plausibility*)
|
|
1126
|
-
|
|
1152
|
+
figures and the rule (§6, *Plausibility*), and a full-run layer holding a body
|
|
1153
|
+
no planned part covers — long hair that leaves the head crop sideways, or a
|
|
1154
|
+
head-run part that stops above the crop line so `extend_below_crop` continues
|
|
1155
|
+
nothing — is named with the body, the rule that skipped it and the two
|
|
1156
|
+
continuations (take the part from the full run, or add the full-run layer as a
|
|
1157
|
+
second part behind it). The plan is not changed; which continuation fits is
|
|
1158
|
+
yours.
|
|
1159
|
+
7. `rig-parts assemble … --out work` — read its `uncovered hole` and `uncovered:` lines and look at
|
|
1127
1160
|
`work/render/recomposite_error_rig.png` (§5): red is painting no part holds, which
|
|
1128
1161
|
no later stage can see — then
|
|
1129
1162
|
`rig-parts propose --parts work/rig --source inputs/painting.png --out work` →
|
|
@@ -1204,14 +1237,14 @@ proposal in as the steps above say (`RL01`); every step must exit 0.
|
|
|
1204
1237
|
| --- | --- | --- | --- |
|
|
1205
1238
|
| `layers` | the table, then the `WARN` lines | every tag the plan will need has opaque pixels; one `face` in the head run; `0 WARN line(s)` | a run whose layer PNG is not its box's size (`LAYERS_PNG_MATCHES_BBOX`); a `WARN PLAN_LAYER_…` line (§6, *Plausibility*) |
|
|
1206
1239
|
| `sheet` of both runs | the tile list (and the sheet, if you can see) | eyes, irises, lashes and brows as left/right pairs in the head run | a head box that cut off an ornament: move `head_box`, re-run the head crop |
|
|
1207
|
-
| `assemble` | one line per part, the `pixels:` totals (opaque = visible + occluded; taken; visible but not projected), then `recomposite vs source: mean \|d\|, within 8, error px > 40, uncovered error px`, then `uncovered holes (8-connected): N` and the largest five as `uncovered hole K: <px> px at x,y wxh (between "<part>" <px> px, …)
|
|
1240
|
+
| `assemble` | one line per part, the `pixels:` totals (opaque = visible + occluded; taken; visible but not projected), then `recomposite vs source: mean \|d\|, within 8, error px > 40, uncovered error px`, then `uncovered holes (8-connected): N` and the largest five as `uncovered hole K: <px> px at x,y wxh (between "<part>" <px> px, …)`, then one `uncovered: <n> of the <N> uncovered error px lie on the full run's "<tag>", in a body of <px> px at x,y wxh; <the rule that left it out>` line per full-run layer the plan does not take from the full run whose uncovered error holds a body (5x5-opened, 8-connected, at least 150 full-run px in rig px); and look at `render/recomposite_error_rig.png`. Between the part lines and the totals, one `cut: "<part>" opaque <n> = "<part>" <kept> + "<piece>" <taken> …` line per part an `assemble.cuts` entry cut (below; it ends `; under <n> px filled, <m> px left empty` when a cut of that part has `under`), then one `fringe pushed back: "<part>" <px> px, where the painting shows "<holder>" <px> px, …` line per part whose fringe was cleared (below) | on the examples: `reference-sample` 0.83 / 98.0 % / 4,359 / 1,185, 259 holes, the largest 94 px; `reference-demo` 2.34 / 95.8 % / 10,340 / 1,564, 453 holes, the largest 70 px (default rule) — many slivers along part edges, no hole a region could hide | one large hole: part of the figure is in no layer — a plan entry is missing, hair left the head crop sideways (reference-demo's `hair_back` is taken from the full run for that reason), or See-through split one garment into two and left the space between them in neither (a skirt as two trouser legs); the `between` parts say where. When neither run holds it at all, an `assemble.patches` entry cuts it from the painting (below) |
|
|
1208
1241
|
| `propose` | `note:` lines, `LINT` lines, the `coverage` lines, `landmarks.png`, `basis.json` | no LINT line: every chain link lies on its mesh's art, and the hip is below the chest and the figure's top quarter; the `coverage:` summary says how many bones that verdict covers — a `not checked` bone was read by no check (its line says why), and a `ratio` or `fallback` bone in `basis.json` is a guess | a link off the art (a bone on the background) — move it onto the layer; `LINT hip at [x, y] is not below chest at [x, y]: …` or `LINT hip at [x, y] is above 0.25 of the figure height (figure y T..B, so hip y must be at least L): a hip at the shoulders` — move `hip` down to the waist (and `chest` between it and the neck); a `hanging strand … -- no chain proposed` note — that strand hangs stiff until you add a chain down the x and rows it names (§3); a `no blink: …` or `blink without brows: …` note — the idle will not blink (or its brows will not drop), because no part came from an `eyewhite` (or `eyebrow`) layer; the note names the tags looked for; a `no eyewhite part for eye_<s> …` note — the iris and lash parts it names ride `head` and do not blink, because no `eyewhite-<s>` part made that side's eye bone: take the eyewhite from the other run, or keep them on `head`; a `no face part: face box derived from …` note (always the first) — `head`, `neck` and every face-height scale come from a box guessed off the hair and neck (§3): check `head` and `neck` on `landmarks_head.png` and move them; when it adds `the blink shuts the eyes over no face part`, read `BLINK_NO_HOLE` after `check` — an eye with no face under it can open a hole (the `reference-sample` with only its face removed: 587 px). Under `--keypoints`: the `lint rule set:` line first (joints, or screen and why), then the joint notes — `missing: the rule "…" placed bone X instead` is a bone still guessed; `not used — …` names why an arm's joints did not place its sleeve (for a wrist on no part, the nearest part and the `--wrist-snap` that would bind it); a `wrist snap: …` note is a wrist bound past 15 px by the flag — check that chain's tip on `landmarks.png`; a `one handwear part holds both wrists` note is two chains on one mesh — cut the part with `assemble.cuts` to separate them; `LINT chest at … is not between the neck joint …`, `LINT hip at … is not past chest …`, `LINT hip at … is nearer the neck joint …` and `LINT <chain><i> at … does not advance from <s>_shoulder toward <s>_wrist` are the joint-frame lines: move that bone between, past or along the joints they name |
|
|
1209
1242
|
| `compare` | one line per pair (origin, parent, tip, length, direction — or SKIP and why), then the per-row summary, the unmapped bones of each side, `required:`, each side's roles and the `controls:` line | proposal against the config you corrected: the rows you changed and no others. Config against the `rig.json` `build` writes for it: measured on both examples, every origin within 6.19e-7 px (the rig's offsets are written to 6 places) and every chain link's tip and length within 4.99e-4 px (`length` is written to 3), printed to three places as `0.000` (a signed figure as `+0.000` or `-0.000`); `parent … is the right's ancestor at depth 2, <bone>_ctl between` for every keyed mesh bone, no `DIFFERENT` and no `NOT MAPPED` | `parent DIFFERENT: left a, right b` — a bone hangs from another parent than the other side's; `frames not related` — a rig with no stage (`skeleton.width`/`height`), two configs at different `rig_scale`: the distance rows SKIP, so declare the frame in a `--map` file if the author knows it; `FAIL STRUCTURE_REQUIRED_PRESENT` — a bone the map requires is missing through its pairs |
|
|
1210
1243
|
| `rig` (inside `build`) | one line per mesh: vertices, triangles, bones, influences, `cover`; the `bones` line; the `idle keys` line; then rigc's gate lines (with A15's declared SKIP under `--idle-keys direct`); in `rig.json`, each chain link's (or its `_ctl`'s) `length` and `rotation` | `cover 1.00000` on every mesh, both gate summaries `0 failed` (the compile and the packed pages); every link's `length` the distance to the next link and `rotation` its direction (Spine degrees, counter-clockwise, y up, local to the parent), every offset under it — a child bone's `x, y`, a weight's bind `x, y`, a region's `x, y` — in that turned frame, and a region on a link carrying `rotation` that turns it back upright. Nothing moved: `flattenRig` (`src/rig.ts`) turns every offset back and gives the unturned numbers | `RIG_LATTICE_ONE_LOOP`: change that mesh's `grid` |
|
|
1211
1244
|
| `check` (inside `build`) | the gate lines verbatim, the pack line, `loop:` (and `loop physics:` when the rig declares a physics constraint, §7), `seam:`, the six judgement lines, `RECOMPOSITE_HOLES` and, under `--source`, `SETUP_POSE_VS_SOURCE` (§7), `check.json`; the last line says how many of the nine bars measured and names the ones that said SKIP | `check: PASS; 9 of 9 bar(s) measured, 0 skipped` on the examples, and a judgement line SKIP only where the character lacks what it reads; on a rig spec with no `parts.json` or no `idle` (a merged rig, §7 *Measuring a rig rig-parts did not assemble*), PASS with the skipped bars named | `CHECK_SEAM_WITHIN_BAR` or `CHECK_LOOP_CLOSES` (§6) |
|
|
1212
1245
|
| `check --requirements` (and `build --requirements`) | after the lines above, one line per declared requirement, `NAME: PASS`, `FAIL` or `NOT MEASURABLE — …` with its figures, the bar as declared and the worst frame; then `requirements: N declared — M measured (P PASS, F FAIL), K NOT MEASURABLE; not declared: <kinds>`; `check.json`'s `requirements` block; the renders under `requirements/` (§7, *Declared requirements*) | every line PASS and `0 NOT MEASURABLE`; a follow's `released_copy` says whether rigc's consumer-driven door was taken on the throwaway copy | `CHECK_REQUIREMENT_MET` (a figure past its bar; the line names the frame) or `CHECK_REQUIREMENT_MEASURABLE` (the quantity is undefined in the frames: a tip or an axis on a bone of length 0, an aim with no line, a follow no frame of which reaches its least drive); the last line then reads `check: FAIL — B bar(s) not met, R declared requirement(s) not PASS` |
|
|
1213
1246
|
| `compose` | the `[compose]` lines: one per character (its offset, its scale, its placed bounds, the shift and how many first-level bones, regions on `root` and weights bound to `root` it moved, its bone, slot, track and constraint counts, its `rig_scale` and idle), the declared order and the slot count it expands to, rigc's gate lines; then the `[check]` lines as for `check`, and `scene.json` | both gate summaries `0 failed`, `check: PASS` with the bars that measured and the ones that said SKIP named — on a composed rig `4 of 9`: the gate, the loop, `CHAIN_LAG` and `TEXTURE_STRETCH` (there is no `parts.json`; each character's own `build` measured all nine). `scene.json`'s `order.slots` is the order the compiled skeleton draws | a `SCENE_*` refusal (§6, *compose*) — the scene file, a build, or the order; `COMPOSE_RIGC_GREEN` — rigc's own line, quoted |
|
|
1214
|
-
| `loop` (inside `build --loop`, or `loop --frames … --out …`) | the dropped-duplicate line, each file's line, then `loop: idle.png N B (lossless); idle-indexed.png N B (max …, mean …); idle.gif N B (max …, mean …)` | `f0048.png equals f0000.png byte for byte, so it is dropped` | `LOOP_ENCODE` (§6) |
|
|
1247
|
+
| `loop` (inside `build --loop`, or `loop --frames … --out …`) | the dropped-duplicate line (under `build --lead-in`, the lead-in line in its place: the frames kept and the jump at the wrap), each file's line, then `loop: idle.png N B (lossless); idle-indexed.png N B (max …, mean …); idle.gif N B (max …, mean …)` | `f0048.png equals f0000.png byte for byte, so it is dropped` | `LOOP_ENCODE` (§6) |
|
|
1215
1248
|
|
|
1216
1249
|
`loop` writes three files from one frame set, and they are not interchangeable.
|
|
1217
1250
|
`idle.png` (`loop --out x.png`) is the lossless APNG: every frame decodes to the
|
|
@@ -1222,10 +1255,26 @@ entry, no dithering, filter None) — and is the small file to show. `idle.gif`
|
|
|
1222
1255
|
(`loop --out x.gif`) is the same median cut in a GIF. The indexed APNG and the GIF
|
|
1223
1256
|
print their palette error, per channel over R, G and B of every frame (and alpha's
|
|
1224
1257
|
max for the APNG); a figure is a measurement of the file, not a bar. On the demo
|
|
1225
|
-
(the README's animation since issue #
|
|
1226
|
-
5,
|
|
1227
|
-
max
|
|
1228
|
-
construction and the size is the difference.
|
|
1258
|
+
(the README's animation since issue #224's follow-up: `build --loop --lead-in 3`, rig-c
|
|
1259
|
+
2.33.0): 5,148,992 B lossless, 727,486 B indexed and 781,526 B GIF, both palette files
|
|
1260
|
+
at max 69, mean 0.630 — the two share one quantiser, so their error is the same by
|
|
1261
|
+
construction and the size is the difference. From issue #227 until then, `build --loop`
|
|
1262
|
+
with default flags, before the demo carried physics: 5,832,634, 827,857 and 889,063 B
|
|
1263
|
+
at max 65, mean 0.879.
|
|
1264
|
+
|
|
1265
|
+
**`build --loop --lead-in <n>`** is for a rig with physics. rigc's render resets every
|
|
1266
|
+
physics constraint at frame 0, so such an idle does not end where it starts: on the demo
|
|
1267
|
+
(issue #224's strands, the tails at inertia 0.8) frame 0 and frame 48 differ by max |d|
|
|
1268
|
+
132, 626 px over 40, and
|
|
1269
|
+
the plain loop keeps all 49 frames and jumps at the wrap. With `--lead-in n` the build
|
|
1270
|
+
renders the idle played n + 1 times back to back (`idle_lead_in`, the build's other
|
|
1271
|
+
animations kept so the viewport is fitted as for the idle frames), keeps the last
|
|
1272
|
+
period, drops its end frame (the next period's first) and prints how far that end frame
|
|
1273
|
+
is from the first kept one — the jump the loop will show. The settling is the rig's, not
|
|
1274
|
+
a constant: on the demo, `--lead-in 1` and `2` each still read max |d| 117, 305 px over 40, and `3` reads max 1, 0 px over 40. The idle
|
|
1275
|
+
must repeat without an invented value — every track keyed from 0 to the duration, ending
|
|
1276
|
+
where it starts — or the build refuses it (`LOOP_LEAD_IN_IDLE`). `check` and its bars
|
|
1277
|
+
read `check/idle_frames/` as before; only the loop files move. On reference-demo with `--seam silhouette`
|
|
1229
1278
|
(the README's animation until issue #227, rig-c 2.1.3, and 2.10.1 to the byte):
|
|
1230
1279
|
13,645,503 B lossless, 1,706,719 B indexed and 1,812,288 B GIF at max 57, mean 1.601;
|
|
1231
1280
|
with `--pack-shape rect` the same build writes 13,645,350, 1,706,520 and 1,812,238 B,
|
|
@@ -1474,14 +1523,25 @@ immediately behind `X`; `"front"` patches last, then `"front"` pieces). Its coun
|
|
|
1474
1523
|
A part's `from` is `<full|head>:<tag>` — the See-through run and tag, which every
|
|
1475
1524
|
role (`propose`) and every judgement-line region (`check`) is read from — or, for a
|
|
1476
1525
|
patch, `painting:<its own name>`; a cut's piece carries the `<run>:<tag>` of the part
|
|
1477
|
-
it was cut from, so two records may share one
|
|
1526
|
+
it was cut from, so two records may share one, and names that part in `cut_from` (issue
|
|
1527
|
+
#230; written on a piece only). The records are in draw order, so a piece drawn `"back"`
|
|
1528
|
+
or before its base comes first, and only `cut_from` says which of the two the cut made.
|
|
1529
|
+
The reader refuses a `cut_from` that names no part of the file, the piece itself, another
|
|
1530
|
+
piece, or a part on another layer (`PARTS_CUT_FROM_KNOWN`). A `parts.json` written before
|
|
1531
|
+
1.6.0 has no `cut_from` and still reads; `propose` alone refuses it when two of its parts
|
|
1532
|
+
share a layer (`PROPOSE_CUT_FROM_RECORDED`): re-run assemble. **A patch is 100 % source**: every pixel is the
|
|
1478
1533
|
painting's, so it is all visible and all taken — `visible_px`, `projected_core_px`
|
|
1479
1534
|
and `source_px_taken` equal `opaque_px`, and `occluded_px`,
|
|
1480
1535
|
`visible_not_projected_px`, `refused_drift_px` and `merged_px` are 0. The reader
|
|
1481
1536
|
refuses a `painting:` record that says anything else, or that names another part
|
|
1482
1537
|
(`PARTS_FROM_KNOWN`, `PARTS_COUNTS_ADD_UP`). No tag rule reads a patch: `propose`
|
|
1483
1538
|
puts it on the nearest trunk bone as a region with a note, and `check` counts it
|
|
1484
|
-
in no region.
|
|
1539
|
+
in no region. No tag rule reads a cut's piece either (issue #230): its base already took
|
|
1540
|
+
the tag's rule, and a rule that runs once per part of a tag would name the base's bones
|
|
1541
|
+
and chains a second time, so the piece rides the nearest trunk bone as a region with a
|
|
1542
|
+
note saying so — give it a mesh in `meshes` if it should bend. The one exception is the
|
|
1543
|
+
sleeve rule, which names its chains by side and takes a cut sleeve as a blob of its own
|
|
1544
|
+
(the `one handwear part holds both wrists` note, §3).
|
|
1485
1545
|
|
|
1486
1546
|
`visible_px + occluded_px = opaque_px`, and every projected pixel is visible; the stage
|
|
1487
1547
|
refuses (`ASSEMBLE_COUNTS_ADD_UP`) rather than write counts that break either, and the
|
|
@@ -1658,13 +1718,14 @@ See-through with another seed.
|
|
|
1658
1718
|
| `HEADBOX_FACE_PRESENT`, `HEADBOX_RUN_SQUARE`, `HEADBOX_CANVAS_SIZE`, `HEADBOX_FITS_CANVAS` | the full run has no face or is not square; `--canvas` is not a positive size; or the painting cannot hold the proposed box at its size — its shorter side is the bound (shrinking it would cut the head) | `--full`, `--canvas`, or the painting |
|
|
1659
1719
|
| `PROPOSE_SOURCE_PRESENT`, `PROPOSE_PNG_PRESENT`, `PROPOSE_PNG_MATCHES_BOX` | the painting or a part PNG is missing, or a PNG is not its box | `--source`, `--parts` (re-run assemble) |
|
|
1660
1720
|
| `PROPOSE_FACE_PRESENT` | no part comes from a `face` layer, and the face-less fallback cannot derive a face box either: it needs the head run's `neck` and at least one head-run `front hair`/`back hair` part whose top is above the neck's, and the message names the half that is missing. With both, `propose` does not refuse — it derives the box and says so in its first note (§5) | `assemble.plan`: take the face, or the head run's hair and neck |
|
|
1721
|
+
| `PROPOSE_CUT_FROM_RECORDED` | two parts share one layer and none of them records `cut_from`: a `parts.json` an `assemble` before 1.6.0 wrote with `assemble.cuts`. The records are in draw order, so which is the plan part and which the piece cannot be read off the file; the message names the parts and the layer. Every other reader still takes the file | `--parts`: re-run assemble (1.6.0+) to record `cut_from` |
|
|
1661
1722
|
| `PROPOSE_ACCESSORY_BODY` | an accessory has nothing above its pendant rows to hang its bone on | that part's plan entry, or author its bones by hand |
|
|
1662
1723
|
| `KEYPOINTS_FILE_PRESENT`, `KEYPOINTS_IS_JSON`, `KEYPOINTS_KEY_KNOWN`, `KEYPOINTS_FIELD_PRESENT`, `KEYPOINTS_FIELD_TYPE` | the `--keypoints` file is absent, not JSON, has a key this reader does not know, lacks one of `spec`, `space`, `width`, `height`, `source`, `people`, or holds a value of the wrong type (a size that is not a whole positive px count, an empty `source`, no people) | the keypoint file (§3, *A posed figure*) |
|
|
1663
1724
|
| `KEYPOINTS_SPEC_KNOWN`, `KEYPOINTS_SPACE_STATED` | the file is not `spine-parts-keypoints/1`, or states a space other than painting-px, origin top-left, y down | convert the file to that space; it is not read as if it were in it |
|
|
1664
1725
|
| `KEYPOINTS_JOINT_KNOWN`, `KEYPOINTS_JOINT_STATE`, `KEYPOINTS_POSITION_STATED`, `KEYPOINTS_POSITION_INSIDE` | a joint name outside body-18, a state outside observed / occluded / missing, an observed joint with no `at` or a missing one with one, or a position outside the `width`x`height` image | that joint |
|
|
1665
1726
|
| `KEYPOINTS_PERSON_UNIQUE`, `KEYPOINTS_PERSON_CHOSEN` | two people share an id; or the file holds more than one person and no `--person` names one, or `--person` names none of them (the message lists the ids) | `--person <id>` |
|
|
1666
1727
|
| `KEYPOINTS_IMAGE_SIZE` | the file's `width`x`height` is not the `--source` painting's | a file measured on this painting |
|
|
1667
|
-
| `PARTS_*` (`PARTS_FILE_PRESENT`, `PARTS_IS_JSON`, `PARTS_KEY_KNOWN`, `PARTS_FIELD_PRESENT`, `PARTS_FIELD_TYPE`, `PARTS_NAME_UNIQUE`, `PARTS_FROM_KNOWN`, `PARTS_BOX_INSIDE_RIG`, `PARTS_COUNTS_ADD_UP`, `PARTS_HOLES_LARGEST_FIRST`, `PARTS_HOLE_PART_KNOWN`) | the `parts.json` read is not assemble's contract (`PARTS_COUNTS_ADD_UP`: `visible_px + occluded_px` is not `opaque_px`, `visible_not_projected_px` is above `visible_px`, or the `recomposite` block's figures disagree — more uncovered than error pixels, a hole larger than its box, the wrong number of holes listed, listed areas that do not sum to `uncovered_error_px`; the last two codes are the block's order and its border names, §5) | re-run assemble; do not edit `parts.json` |
|
|
1728
|
+
| `PARTS_*` (`PARTS_FILE_PRESENT`, `PARTS_IS_JSON`, `PARTS_KEY_KNOWN`, `PARTS_FIELD_PRESENT`, `PARTS_FIELD_TYPE`, `PARTS_NAME_UNIQUE`, `PARTS_FROM_KNOWN`, `PARTS_CUT_FROM_KNOWN`, `PARTS_BOX_INSIDE_RIG`, `PARTS_COUNTS_ADD_UP`, `PARTS_HOLES_LARGEST_FIRST`, `PARTS_HOLE_PART_KNOWN`) | the `parts.json` read is not assemble's contract (`PARTS_COUNTS_ADD_UP`: `visible_px + occluded_px` is not `opaque_px`, `visible_not_projected_px` is above `visible_px`, or the `recomposite` block's figures disagree — more uncovered than error pixels, a hole larger than its box, the wrong number of holes listed, listed areas that do not sum to `uncovered_error_px`; the last two codes are the block's order and its border names, §5) | re-run assemble; do not edit `parts.json` |
|
|
1668
1729
|
|
|
1669
1730
|
### rig
|
|
1670
1731
|
|
|
@@ -1705,19 +1766,22 @@ See-through with another seed.
|
|
|
1705
1766
|
| `CHECK_TEXTURE_STRETCH` | a mesh triangle's edge, in some idle frame, is more than 1.926544 times its rest length or less than 1/1.926544 of it (the mesh, triangle, its three vertices, the edge and the frame are named); or a rest edge has length 0 | the chain tracks' `amps` on the bones that mesh is weighted to (the stretch grows with them), or the mesh's `segments` — a vertex blending two bones that swing against each other |
|
|
1706
1767
|
| `CHECK_SEAM_FRAME_SIZE`, `FRAMES_SIDECAR`, `CHECK_GEOMETRY_FILE` | rigc's render is not what its `frames.json` says, or its `geometry.json` is not a whole `rigc-geometry/1` export of the frames beside it (a frame count, a mesh whose vertex count differs from its rest entry; for the face half, another viewport than `frames.json`'s, other frame indices, the head bone or a feature's bone missing from a frame, a non-finite transform or time) | a rigc problem; report it |
|
|
1707
1768
|
| `LOOP_ENCODE` | the loop encoder refused a frame (translucent pixel in a GIF, a size change) | the frames; for a translucent frame write the lossless or the indexed APNG, which keep alpha |
|
|
1769
|
+
| `LOOP_LEAD_IN_IDLE` | `build --lead-in`: the idle cannot be repeated without inventing a value (a track not keyed from 0 to the duration, or ending where it does not start; a field besides `duration`, `loop`, `note`, `tracks`), the motion already has an `idle_lead_in`, or the render did not write whole periods | the refusal names the track or field; the demo's idle, as the rig stage writes it, repeats as written |
|
|
1708
1770
|
| `CHECK_PACK_LINE_READS` | rigc printed a `pack:` line that is not `pack: <page> <W>x<H>, <N> region(s), <P>% covered, padding <D>`, then `, page edges free` or nothing, then `, shape rect`, `, shape polygon` or nothing (rig-c 2.1 prints the shape; 1.5–2.0 printed none, read as `rect`); an unknown shape is this refusal; the line is quoted | a rigc this package does not know the output of; report it, with `rigc --version` |
|
|
1709
1771
|
| `CHECK_PACK_PAGE_EDGES` | the pack line disagrees with the `--page-edges` the build was run with — its `, page edges free` clause is there under `pot` or missing under `free`, or a `pot` page is not a power of two on both edges | a rigc problem; report it, with `rigc --version` |
|
|
1710
1772
|
| `CHECK_PACK_SHAPE` | the pack line disagrees with the `--pack-shape` the build was run with — it ends `, shape rect` under `polygon` or `, shape polygon` under `rect`, or it has no shape clause (the 1.5–2.0 form, read as `rect`) under `polygon` | a rigc older than 2.1.0 on `PATH`: rigc 2.0.3 takes `--pack-shape` without a word, packs by rectangles and prints the form with no shape clause, so this refusal is what catches it — `bun install` (this package depends on rig-c ^2.20.4); otherwise a rigc problem, report it with `rigc --version` |
|
|
1711
1773
|
| `BUILD_ARTIFACT_PRESENT` | the packed build lacks its `.json`, `.atlas` or page | a rigc problem; report it |
|
|
1712
1774
|
| `REQUIREMENTS_FILE` | `--requirements` names no file, or one that does not parse as a JSON object. Refused before anything is built (by `build`, before assemble) | the path of a `spine-parts-requirements/1` file |
|
|
1713
|
-
| `REQUIREMENTS_FIELD` | a field of the file is missing, of the wrong type, or not one the format reads: `spec`, `fps` (no default), `requirements`, each requirement's `name` (letters, digits, underscores; once each), `kind`, `animation` and its kind's fields — every bar among them (`within_px`, `fraction`, `tolerance`, `least_drive` above 0, `within_degrees` from 0 to 180, `lo_degrees` ≤ `hi_degrees`, `within_ratio` ≥ 1) — and each target's `bone`, `animation` and exactly one of `at` and `keys` (times strictly increasing). `note`, `*_note` (strings) and `x-…` (any value) are read by nothing, as in the config | write the field; the bar is yours |
|
|
1714
|
-
| `REQUIREMENTS_RESOLVES` | a bone, an `ik` or `transform` constraint (by name and `constraint_type`, as rig-c resolves it), a slot, a mesh attachment or an animation the file names is not in `rig.json` or `motion.json`, or a seam's part is not in `parts.json` — the detail lists the ones that are; or an animation whose name cannot be a directory. Refused before anything is built | the name as the rig spells it |
|
|
1775
|
+
| `REQUIREMENTS_FIELD` | a field of the file is missing, of the wrong type, or not one the format reads: `spec`, `fps` (no default), `requirements`, each requirement's `name` (letters, digits, underscores; once each), `kind`, `animation` and its kind's fields — every bar among them (`within_px`, `fraction`, `tolerance`, `least_drive` above 0, `within_degrees` from 0 to 180, `lo_degrees` ≤ `hi_degrees`, `within_ratio` ≥ 1) — and each target's `bone`, `animation` and exactly one of `at` and `keys` (times strictly increasing), and `not_planted`, `not_swinging` and `rises` when given (each a non-empty list of part names, each once; no part both in `not_swinging` and in `rises`). `note`, `*_note` (strings) and `x-…` (any value) are read by nothing, as in the config | write the field; the bar is yours |
|
|
1776
|
+
| `REQUIREMENTS_RESOLVES` | a bone, an `ik` or `transform` constraint (by name and `constraint_type`, as rig-c resolves it), a slot, a mesh attachment or an animation the file names is not in `rig.json` or `motion.json`, or a seam's part or a `not_planted`, `not_swinging` or `rises` name is not in `parts.json` — the detail lists the ones that are; or an animation whose name cannot be a directory. Refused before anything is built | the name as the rig spells it |
|
|
1715
1777
|
| `REQUIREMENTS_CONSTRAINT_DRIVES` | a `follow` names a bone its constraint does not constrain, or a property it does not drive: an `ik` drives `rotate` only; a `transform` drives `rotate` when a `to` names `rotate`, `translate` when one names `x` or `y` | the constraint's own bone and property |
|
|
1716
1778
|
| `REQUIREMENTS_TARGET_PARENT` | a scene target's bone is the root or is not parented to it, or the root is not at rest at the origin, or the animation keys the root — a stage point is a bone's position only under a root that stands still at the origin | a bone under the root for the scene to place |
|
|
1717
1779
|
| `REQUIREMENTS_TARGET` | a scene target places one bone twice for one animation, places it for an animation no requirement measures, has a key outside the animation's `[0, duration]`, or sits in a group the animation translates | one placement per bone and animation, inside it, for an animation a requirement reads |
|
|
1718
1780
|
| `CHECK_REQUIREMENTS_FRAMES` | a requirement render did not write every frame rigc sampled, or the as-declared, released and full renders of a follow sampled different frames | a rigc problem; report it |
|
|
1719
1781
|
| `CHECK_REQUIREMENT_MET` | a declared requirement measured outside its bar; the figure, its frame and the bar are quoted | the rig or its motion (§7, *Declared requirements*) — or the bar, if the scene asks less |
|
|
1720
1782
|
| `CHECK_REQUIREMENT_MEASURABLE` | a declared requirement is NOT MEASURABLE: what it asks is undefined in the frames, and the reason is quoted. Not a pass | the declaration (a bone with a length, a target off the bone's origin, a least drive the constraint reaches) or the rig |
|
|
1783
|
+
| `REQUIREMENTS_NOT_PLANTED` | a `not_planted` name is a part `check` does not read as a planted foot — it does not come from a See-through `footwear` layer — or there is no `parts.json` to choose the feet by (issue #231). Refused before anything is built | a `footwear` part's name |
|
|
1784
|
+
| `REQUIREMENTS_TIP_EXCEPTION` | a `not_swinging` or `rises` name is a part `TIP_OVER_ROOT` does not read — not from a See-through `handwear` or `bottomwear` layer — or there is no `parts.json` (refused before anything is built); or a `rises` part is not carried by a chain that rises: the chain's first link to its last, at the setup pose, runs other than up, the detail giving the direction measured (refused after the idle is rendered, before `check.json` is written) (issue #231) | a swinging part's name; for `rises`, a part whose chain does rise |
|
|
1721
1785
|
| `REQUIREMENTS_SEAM` | a `seam` cannot be read against the rig: there is no `parts.json` (a merged rig, §7 *Measuring a rig rig-parts did not assemble*), or the two parts' art does not meet at the setup pose (no 4-adjacent pair). Refused before anything is built | two parts whose art touches, on a rig with its `parts.json` |
|
|
1722
1786
|
|
|
1723
1787
|
### compose
|
|
@@ -2275,6 +2339,34 @@ unit (the stage box maps to the world by a translation and the y flip,
|
|
|
2275
2339
|
}
|
|
2276
2340
|
```
|
|
2277
2341
|
|
|
2342
|
+
**Feet that are not planted** (issue #231). The feet halves of `BREATH_VISIBLE` and
|
|
2343
|
+
`STILL_REGIONS_DARK` assume a figure that stands: every `footwear` part holds still.
|
|
2344
|
+
Whether the figure stands is the scene's knowledge, so a scene where it sits and its
|
|
2345
|
+
legs swing says so here, by part: `"not_planted": ["shoes"]`. Each name must be a
|
|
2346
|
+
`footwear` part in `parts.json` (`REQUIREMENTS_RESOLVES`, `REQUIREMENTS_NOT_PLANTED`).
|
|
2347
|
+
A declared part is left out of both feet halves, and the declaration is the first
|
|
2348
|
+
figure of each line it relaxes — `declared_not_planted` in `BREATH_VISIBLE`, and in
|
|
2349
|
+
`STILL_REGIONS_DARK`'s `feet` — in `check.json` and on the console, so a relaxed bar
|
|
2350
|
+
never reads as a passed one. With every foot declared, the torso is still measured
|
|
2351
|
+
(`feet_parts` `[]`, `feet_heat_max` null) and the feet half reads `unmeasured` with
|
|
2352
|
+
the reason. The field absent, nothing changes: every `footwear` part is a planted foot.
|
|
2353
|
+
|
|
2354
|
+
**Swinging parts that do not hang** (issue #231). `TIP_OVER_ROOT` reads every
|
|
2355
|
+
`handwear` and `bottomwear` part as hanging: the lower half of its box is the tip's.
|
|
2356
|
+
Two declarations, by part, say where that does not hold. `"not_swinging": ["under"]`
|
|
2357
|
+
— a piece cut off and left still — leaves the part out of the bar; its row reads
|
|
2358
|
+
`unmeasured` with the reason. `"rises": ["arm"]` — a forearm raised from the elbow —
|
|
2359
|
+
reads the part's **upper** half as the tip's (its row carries `tip_half: "upper"`),
|
|
2360
|
+
and only after checking the chain that carries it does rise: the part's bound bones
|
|
2361
|
+
walked up to a chain `CHAIN_LAG` reads, its first link's origin to its last at the
|
|
2362
|
+
setup pose, read along its longer axis, must run up, or the declaration is refused
|
|
2363
|
+
naming the direction measured. The line's first figures after `status` are
|
|
2364
|
+
`declared_not_swinging` and `declared_rises`. Each name must be a swinging part in
|
|
2365
|
+
`parts.json`, and no part may be in both lists.
|
|
2366
|
+
|
|
2367
|
+
`fps` and `requirements` are required as always; a file that declares only exceptions
|
|
2368
|
+
is `{ "spec": "spine-parts-requirements/1", "fps": 12, "requirements": [], "not_planted": ["shoes"], "not_swinging": ["under"], "rises": ["arm"] }`.
|
|
2369
|
+
|
|
2278
2370
|
**Four outcomes, never merged** (#87):
|
|
2279
2371
|
|
|
2280
2372
|
| outcome | when | what it does to the run |
|
package/docs/STABILITY.md
CHANGED
|
@@ -57,7 +57,7 @@ defaults are the help's too, and none is guessed from the art.
|
|
|
57
57
|
| `rig` | `--config`, `--parts`, `--out`; optional `--idle-keys` (ctl, direct), `--page-edges` (pot, free), `--pack-shape` (rect, polygon) |
|
|
58
58
|
| `check` | `--rig`, `--out`; optional `--parts`, `--source`, `--page-edges`, `--pack-shape`, `--requirements`, `--seam-pairs`, `--keep-stills` |
|
|
59
59
|
| `loop` | `--frames`, `--out`; optional `--palette` |
|
|
60
|
-
| `build` | `--config`, `--source`, `--full`, `--head`, `--out`; optional `--seam`, `--project`, `--page-edges`, `--pack-shape`, `--loop`, `--requirements`, `--idle-keys` |
|
|
60
|
+
| `build` | `--config`, `--source`, `--full`, `--head`, `--out`; optional `--seam`, `--project`, `--page-edges`, `--pack-shape`, `--loop`, `--lead-in`, `--requirements`, `--idle-keys` |
|
|
61
61
|
| `compose` | `--scene`, `--out`; optional `--requirements`, `--accept` |
|
|
62
62
|
| (none) | `--version`, `--help` |
|
|
63
63
|
<!-- /stable:commands -->
|
|
@@ -155,7 +155,7 @@ every number) are AUTHORING §3's tables, and the loader refuses any other by na
|
|
|
155
155
|
|
|
156
156
|
| file | written by | what is stable |
|
|
157
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` |
|
|
158
|
+
| `parts.json`, `parts/<name>.png` | `assemble`, `build` | one record per part: `from`, `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` |
|
|
159
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
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
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 |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rig-parts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.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": {
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"ag-psd": "^31.0.2",
|
|
63
|
-
"rig-c": "^2.
|
|
63
|
+
"rig-c": "^2.40.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@esotericsoftware/spine-core": "4.3.13",
|