@rig-c/parts 1.15.0 → 1.17.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 +4 -0
- package/cli.ts +62 -12
- package/docs/AUTHORING.md +454 -200
- package/docs/STABILITY.md +12 -8
- package/package.json +1 -1
- package/skills/rig-parts/SKILL.md +11 -2
- package/src/assemble.ts +325 -23
- package/src/autoamplitude.ts +23 -3
- package/src/autoenvelope.ts +17 -5
- package/src/build.ts +81 -8
- package/src/check.ts +632 -11
- package/src/config.ts +185 -8
- package/src/errors.ts +16 -0
- package/src/guide.ts +255 -0
- package/src/limbs.ts +188 -0
- package/src/parts.ts +89 -4
- package/src/propose.ts +137 -107
- package/src/rig.ts +43 -8
- package/src/scene.ts +2 -2
package/docs/AUTHORING.md
CHANGED
|
@@ -4,7 +4,12 @@ This is the guide an agent authors from. It assumes you cannot see the painting,
|
|
|
4
4
|
the layers or the rig: what you have is this page, the tool's printed lines, and
|
|
5
5
|
the files it writes. Every refusal the tool prints names a rule, an object, the
|
|
6
6
|
value found and the value required — §6 maps each rule to the field or input that
|
|
7
|
-
has to change
|
|
7
|
+
has to change — and ends with `(see rig-parts guide RULE)`. That command prints the
|
|
8
|
+
rule's one row of this page, read from the installed file when it runs; nothing is
|
|
9
|
+
kept apart from this file. `rig-parts guide §<n>` prints a section, `§<n>.<m>`
|
|
10
|
+
the m-th `###` under it and `§<n>.<m>.<k>` the k-th `####` under that, counted as
|
|
11
|
+
the file stands. Each row's first cell starts with an anchor named for its
|
|
12
|
+
rule, so `AUTHORING.md#RULE` on github.com lands on the row.
|
|
8
13
|
|
|
9
14
|
The worked example throughout is [`examples/reference-sample`](https://github.com/rig-c/parts/tree/main/examples/reference-sample): its
|
|
10
15
|
`config.json` is a complete, loading config, `proposal.json` is what the proposer
|
|
@@ -91,12 +96,13 @@ read by no CPU stage).
|
|
|
91
96
|
| `seethrough.resolution` | assemble — each run's canvas must be `resolution` square (`ASSEMBLE_RUN_CANVAS`) | recorded from the See-through runs; 1024 in both examples |
|
|
92
97
|
| `seethrough.steps`, `.seed`, `.offload` | no CPU stage | recorded from the runs |
|
|
93
98
|
| `seethrough.head_box` | inputs (cuts the head image there; optional at the first call); assemble — where the head run sits on the painting | **proposed** by `propose --head-box` from the full run, square, source pixels, shifted inside the painting when needed; the head run must then be fed exactly that crop |
|
|
94
|
-
| `assemble.rig_scale` | assemble | authored; rig pixels per source pixel. 0.5 in both examples (a 1664x2432 painting makes an 832x1216 rig) |
|
|
99
|
+
| `assemble.rig_scale` | assemble — the rig is `trunc(w × rig_scale)` x `trunc(h × rig_scale)`, and every rig-px value after it (`bones`, `meshes`, `motion`, `patches`, `cuts`) is in that rig's pixels; `check --source` (`CHECK_SOURCE_SIZE`) and `compose` (`SCENE_RIG_SCALE_AGREES`) read it back off `parts.json` | authored; rig pixels per source pixel. 0.5 in both examples (a 1664x2432 painting makes an 832x1216 rig). **Keep the figure about 1,100 to 1,200 rig px tall** — the `H` of `propose`'s `mesh spacing:` note, the height of the parts' boxes together — so for another painting, about 1,150 over the figure's height in painting px: that is the size the proposer's spacing divisor was calibrated at (H 1106–1185, the `mesh spacing` note says so) and the size of the two examples `check`'s bars are derived from, and the proposer and `check` also hold fixed rig-px values that do not scale with it (the fringe's 10 px step, the trunk segments' 18, 20, 30 and 100 px, the 15 px wrist tolerance, the 10-row pendant floor, the seam bar's 50 rig px over 40). What else it trades, measured on `demo` with the README loop from a fresh config at 0.25, 0.5 and 1 (issue #345, rig-c 2.47.1): the same plan and the same ten chains; every bar but the one the uncorrected `demo` always fails (`bottomwear` `TIP_OVER_ROOT`, the README loop's `RL01`) passing at all three; the atlas page 418x606, 832x1205 and 1825x2047; the figure's mesh spacing 16, 32 and 64, so 830, 868 and 932 triangles; the breath 2.5 % of a torso that scales with it; and the proposed bones, scaled to 0.5, off the 0.5 proposal's by up to 38 px at 0.25 and 22.5 px at 1 (the hairpin's origin; the skirt roots 20 and 10.5) — the fixed-px values above. Changing it after the rig sections are written is not refused: `demo`'s tracked config built at 0.25 gated green and `check` failed only `TIP_OVER_ROOT` on both sleeves; `propose --from-config` names it (54 `LINT` lines, links off the art) — propose again at the new scale. Absent: `CONFIG_FIELD_PRESENT`; 0, negative or not a number: `CONFIG_FIELD_TYPE`; a rig under 1x1: `ASSEMBLE_RIG_SIZE` |
|
|
95
100
|
| `assemble.plan` | assemble; also the list every `meshes`/`regions` key must come from | **proposed** by `assemble --propose-plan`. `[part name, "full" \| "head", See-through tag]`, in draw order back to front. Names are free; roles come from the tag. A layer the author made and added to a run takes `author:<label>` in the tag's place, and has no role (§5, *A layer the author made*) |
|
|
96
101
|
| `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 |
|
|
97
102
|
| `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 |
|
|
98
103
|
| `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 |
|
|
99
|
-
| `
|
|
104
|
+
| `limbs` | assemble (the cut and the caps), rig (through `regions`), check (`LIMB_ONE_BONE`) | **proposed** by `propose --keypoints` (issue #349), then checked: `{<limb>: {segments: [{part, from, bone}, {part, from, bone, joint, range?, cap?}, …]}}`, the upper segment first. The rule is *Limbs: cut at their joints* below the table. `part` is a new part (`CONFIG_PART_NAME`, `CONFIG_PART_UNIQUE` against the plan, patches, cuts and every other limb part); `from` a plan part or a cut's piece (`CONFIG_NAME_RESOLVES`) — the layer the segment's pixels come from, which is cut into the limb parts and is not itself made: a `meshes` or `regions` entry for it is `CONFIG_NAME_RESOLVES`, and the segments of one limb that take one part are consecutive (`CONFIG_LIMB_FROM_RUN`); `bone` a declared bone, each segment's the child of the one before (`CONFIG_LIMB_BONES_CHAIN`); the upper segment names no `joint`, `range` or `cap` (`CONFIG_KEY_KNOWN`), every other names its `joint` (`CONFIG_FIELD_PRESENT`) — the joint is its bone's origin; `range` is `[min, max]` degrees from rest with `min <= 0 <= max` (`CONFIG_LIMB_RANGE`), metadata no stage here reads (the stress readers pose each joint at its ends; rig-c needs no rotation limit); `cap` a PNG path relative to the config's directory (`CONFIG_FIELD_TYPE`). Each limb part is attached like any part — `regions.<part>`, which must be the segment's `bone` (`CONFIG_LIMB_BONE`), or a mesh, which `check` holds to that bone alone (`LIMB_ONE_BONE`). With `limbs`, `assemble` reads `bones` too (`CONFIG_FIELD_PRESENT` without it). Absent, nothing is cut at a joint and no byte of any output moves |
|
|
105
|
+
| `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. With the line the rig stage also adds `head_up` (issue #250): a slotless bone under `head`, at head's origin, turned to the eye line + 90 degrees and as long as the eye midpoint lies from head's origin along that axis — the head's frame, which a rule that needs it reads; `head` keeps its own frame, so no key on it or under it changes meaning, and a config bone of that name is refused (`RIG_HEAD_UP_NAME_FREE`). A face bone with its own `tip` is held too (issue #258), in a second entry, `"face_tips"`, when its tip lies along the line within whole-pixel rounding — a tip written in whole pixels sits at most sqrt(2)/2 px off the point of the line it stands for, so its direction may sit up to asin((sqrt(2)/2) / length) degrees off — with its tolerance measured the same way; a tip further off is the bone's own axis, and the `face axis:` line names it with its gap and that bound. 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. A single bone may declare `inherit` (issue #348): what it takes from its parent's transform, one of rig-c's own mode names exactly as rig-c's table spells them — `normal`, `onlyTranslation`, `noRotationOrReflection`, `noScale`, `noScaleOrReflection` (rig-c's `RigBone.inherit`) — written to that bone in `rig.json` as declared; any other spelling, `"NoScale"` included (the runtime would fold its first letter; nothing here folds or maps), is refused (`CONFIG_BONE_INHERIT`), and a chain takes no `inherit` (`CONFIG_KEY_KNOWN`). Its setup rotation is the turn from where rig-c's own poser puts the bone with no rotation of its own under that mode, so it still stands upright (or along its tip) at the setup pose. Where the idle gives the bone a `<bone>_ctl`, the mode goes on the control: the control is the bone the parent's rotation reaches, and the bone under it inherits normally, so the idle's keys moved onto the control still turn it. A foot that does not take its shin's rotation (`noRotationOrReflection` or `onlyTranslation`) keeps its shoe level while the leg is posed (`FEET_STAY_LEVEL`, §7); which mode is the author's. An automatic mesh weighted through a bone with a mode other than `normal` gets no derived amplitude (its row names the bone) and no residual envelope (rig-c's `SKINNING_RANGE_UNSUPPORTED`). Absent, `rig.json` carries no `inherit` and no byte moves |
|
|
100
106
|
| `meshes.<part>` | rig | **proposed**, then corrected. Exactly one of `grid` (the lattice: cell size, px — what `propose` writes: by default one spacing for the figure, round(H / 37) rig px with H the height of every part's box together, a part whose tenth of its short side is already coarser keeping that, and under `propose --grid-rule part` the reference's tenth of the part's short side clamped to 5..36, issue #265), `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, less any island a declared `stray` left out) 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. The rule is chosen per mesh, so `RIG_HEAT_BONE_SOURCE` names three remedies: move the segment onto the art, take the bone out of `segments`, or keep this part on the distance rule — the one to take when the bone anchors the part from outside its art (a torso bone under a neck), since the first moves a bone another part placed and the second drops the anchor (issue #303). On a lattice, `RIG_HEAT_ISLAND_SOURCE` on an island that is dust — at most 4 px and at most 0.1 % of the part's art px, `mesh-draft`'s line — names `meshes.<part>.stray` and the figure that leaves it out, with the value declared; an island above that line keeps the segment remedy, a real piece being a real authoring question |
|
|
101
107
|
| `meshes.<part>.contour` | rig | **authored**, optional (issue #84): `{tolerance, margin, spacing, maxEdge?, budget?, stray?, bridges?, 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; `maxEdge` (issue #265) — the longest outline edge, px, above 0: every simplified edge longer than it is cut into `ceil(length / maxEdge)` equal pieces, each cut point on the 1/256 px grid, before any region or rib touches the outline (absent: nothing is cut, and no byte moves; under 2/256 px the rig stage refuses it, `CONTOUR_PARAMETER`, because two cut points could snap together); the row echoes it in `params` and counts the points it added in `contour.outlineCut`, both only when declared; `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); `bridges` (issue #326) — `true`, its one value: islands are read in this order — **dust first** (those `stray` leaves out), **then faint islands** (every pixel's alpha under 64, a quarter of full opacity: left out the same way, their pixels kept in the image but not meshed, so not drawn, and named in the row's `contour.bridges.faint` with their px, brightest alpha and box), **then every visible island is meshed and bridged, whatever the bridge costs** — overdraw is reported, never a reason to drop art; the largest island, or a tie for it, is never left out, faint or not: dropping it would draft the part without its art, and a part whose main body is faint is a question about the layer, which the plan and the author own, not one for the mesh — and the pieces are joined into the one outline rig-c takes by bridges — the kept islands, holes filled, grow together by `margin`, so islands closer than about twice the margin are one grown silhouette, traced as one; each silhouette is traced, simplified, capped, refined and triangulated as a one-island mesh is; then, starting from the silhouette with the most art, the nearest pair of a vertex on the joined outline and one on a silhouette still apart whose quad holds (wound as the mesh, crossing no outline, holding no other vertex, one closed outline after) is joined by that quad, two triangles over no art, until none is apart. Coverage and overshoot read the silhouettes' triangles; a bridge's area is in `meshArea` and in the row's `contour.bridges` (`islands`, `units`, and per join `unit`, `span` — its two crossing edges, px — `area`, `vertices`, `pair`; and `faint`, only when an island was left out as faint), and the row's `params` echoes `bridges`, both only when declared; `art_coverage` counts a faint island's pixels as art not covered. Absent, a second island is refused as below and no byte moves; on one island it writes the mesh the undeclared entry writes. Any other value is `CONFIG_FIELD_TYPE`; beside `ribs` it is `CONTOUR_PARAMETER` (a rib runs across one outline); a join no pair makes is `CONTOUR_BRIDGE`. A bridge stretches with whatever pulls its two ends apart, so it belongs on a part whose pieces ride one bone — the only case `mesh-draft` drafts; `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 |
|
|
102
108
|
| `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 |
|
|
@@ -277,9 +283,9 @@ What a joint with a position places, as given — no ratio is applied over it:
|
|
|
277
283
|
| `neck` | `neck` | the rule: half way from the chin to the neck part's bottom (or 0.12 face heights below the chin), on the eye axis |
|
|
278
284
|
| `hip` | the midpoint of `r_hip` and `l_hip` — a point between two joints, said as that | the hip rule (bottomwear top, the waist, or 0.32 of the figure); one hip alone is said to be unused |
|
|
279
285
|
| `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 |
|
|
280
|
-
| `sleeve_<s>` | `<s>_shoulder` → `<s>_elbow` (two links), tip at `<s>_wrist`, with the two-blob rule's first two amplitudes
|
|
286
|
+
| `sleeve_<s>` | `<s>_shoulder` → `<s>_elbow` (two links), tip at `<s>_wrist`, with the two-blob rule's first two amplitudes; the arm is a limb (issue #349), `arm_<s>`: its handwear part is cut at the elbow into `upperarm_<s>` on link 0 and `forearm_<s>` on link 1, each a region — no mesh, no chest stub — 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 |
|
|
281
287
|
| `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 |
|
|
282
|
-
| `leg_<s>`
|
|
288
|
+
| `leg_<s>` (issue #241), `foot_<s>` | on a `legwear` part over 500 px: `<s>_hip` → `<s>_knee` (two links), tip at `<s>_ankle`, parent `hip` — 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. The leg is a limb (issue #349), `leg_<s>`: the part is cut at the knee into `thigh_<s>` on link 0 and `shin_<s>` on link 1, each a region — no mesh, no `hip` stub (until #349 the thigh was meshed with one, which pinned it to the hip as the chest stub pinned a sleeve); two legs on one part are split between the two limbs by the cut. When every leg's ankle lies within 15 px of the art of exactly one `footwear` part over 500 px, each leg gets `foot_<s>`, a single bone at the ankle under `leg_<s>1` with `inherit` `"noRotationOrReflection"`, and the footwear part is cut between the feet as `foot_<s>`, the limb's third segment; otherwise no foot is drafted and the note gives each ankle's distance to the nearest footwear art. No idle track: the chain is drafted whatever the pose, and whether the legs move is the scene's. A note per limb says what was cut 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` |
|
|
283
289
|
| 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, when it has one (issue #262: only when its art reaches above `chest`), 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 |
|
|
284
290
|
|
|
285
291
|
**`--wrist-snap <px>`** (issue #199), with `--keypoints` only, declares a tolerance
|
|
@@ -301,14 +307,12 @@ changes, byte for byte. Choosing the tolerance automatically is not done: the no
|
|
|
301
307
|
for an unbound wrist prints the distance that would have bound it.
|
|
302
308
|
|
|
303
309
|
**One handwear part holding both wrists** — two sleeves and the hands decomposed as
|
|
304
|
-
one piece, not clasped at the midline — gets both
|
|
305
|
-
before, and a note says so rather than leaving two chains to share the part
|
|
306
|
-
silently:
|
|
310
|
+
one piece, not clasped at the midline — gets both arms' limbs on its one part, and a note says so:
|
|
307
311
|
|
|
308
|
-
one handwear part holds both wrists: r_wrist and l_wrist both end on <part>, so
|
|
312
|
+
one handwear part holds both wrists: r_wrist and l_wrist both end on <part>, so limbs arm_r and arm_l both take it, and the cut gives each pixel to the arm whose bones pass nearest it; where the arms touch or cross in its art that split is a line no painting draws — to draw it yourself, cut one sleeve out of <part> with an assemble.cuts entry (a polygon round it) and name the piece as that arm's from
|
|
309
313
|
|
|
310
|
-
|
|
311
|
-
proposer does not.
|
|
314
|
+
An `assemble.cuts` entry (§3; §5, *Cutting a piece out of a layer*) draws the split by hand;
|
|
315
|
+
the proposer does not.
|
|
312
316
|
|
|
313
317
|
Every other joint (`nose`, ears, the knees and ankles no leg chain used; the eyes
|
|
314
318
|
with no eyewhite) is named with its state in one note: no bone is authored from it. Every joint the proposer
|
|
@@ -429,8 +433,73 @@ top edge instead would close the eye upward onto the upper lid and still move wh
|
|
|
429
433
|
above it by (1 − squash) × its height above the pivot, so the cut, not the pivot, is what
|
|
430
434
|
holds the crease.
|
|
431
435
|
|
|
436
|
+
### Limbs: cut at their joints (`limbs`, issue #349)
|
|
437
|
+
|
|
438
|
+
**A limb is separate parts, cut at its joints, each rigid on its own bone.** The upper arm,
|
|
439
|
+
the forearm with the hand, the thigh, the shin and the foot are each a part on one bone with
|
|
440
|
+
weight 1, and a bend is a rotation at the joint, never a deformed mesh. A limb mesh blended
|
|
441
|
+
along a chain and bent hard is what every "grotesque" verdict on a posed rig came from (the
|
|
442
|
+
exam's walk, rig-c/pose's demo); a part on one bone cannot do that, and `check`'s
|
|
443
|
+
`LIMB_ONE_BONE` refuses a limb part bound to a second bone by name. Everything below this
|
|
444
|
+
section about fitting a mesh to motion — the weight cut, the contour and automatic modes, ribs,
|
|
445
|
+
the physics recipe — is for the parts that have no joints: the skirt, the clothing, the hair,
|
|
446
|
+
the torso.
|
|
447
|
+
|
|
448
|
+
`propose --keypoints` drafts the block from the body-18 joints (§3, *A posed figure*): an arm
|
|
449
|
+
whose shoulder, elbow and wrist are given is `arm_<s>`, `upperarm_<s>` on `sleeve_<s>0` and
|
|
450
|
+
`forearm_<s>` on `sleeve_<s>1`, cut at `elbow`; a leg whose hip, knee and ankle are given is
|
|
451
|
+
`leg_<s>`, `thigh_<s>` on `leg_<s>0` and `shin_<s>` on `leg_<s>1`, cut at `knee`, and — when
|
|
452
|
+
every leg's ankle lies on one footwear part — `foot_<s>` on a bone of its own at the ankle under
|
|
453
|
+
the shin, `inherit` `"noRotationOrReflection"`, so the shoe keeps its setup angle while the leg
|
|
454
|
+
turns (`FEET_STAY_LEVEL`, §7). Nothing else is a limb: hair chains and physics sleeves are not,
|
|
455
|
+
and a config without `limbs` builds as it always did. Then `assemble` with the block cuts the
|
|
456
|
+
layers, as follows; every step is arithmetic on the declared bones and the layer's pixels
|
|
457
|
+
(`src/limbs.ts`):
|
|
458
|
+
|
|
459
|
+
- **Which limb.** A part a limb takes (`from`) goes wholly to the limbs that take it. With two —
|
|
460
|
+
See-through's one `legwear` holding both legs — each pixel goes to the limb whose polyline (its
|
|
461
|
+
bones' origins in order, then the last bone's end) passes nearest the pixel's centre, a tie to
|
|
462
|
+
the limb declared first. No polygon is drawn, and each leg's lower part carries its own cap.
|
|
463
|
+
- **The joint line.** Between two segments the joint is the lower bone's origin, and the line
|
|
464
|
+
runs through it perpendicular to the limb's axis there — the sum of the upper bone's and the
|
|
465
|
+
lower bone's unit directions, so on a bent limb the bisector. A pixel whose centre is past the
|
|
466
|
+
line (its dot product with the axis, from the joint, above 0) goes to the lower segment.
|
|
467
|
+
Segments from different parts (the shin's legwear, the foot's footwear) are not cut at all:
|
|
468
|
+
each takes its limb's share of its own part.
|
|
469
|
+
- **The cap.** Each lower segment carries an overlap past its joint: the pixels within half the
|
|
470
|
+
limb's width of the joint, on the upper side of the line — a disc about the limb's width across,
|
|
471
|
+
so a bend shows no gap. The width is read along the joint line: the limb's art (alpha above 8,
|
|
472
|
+
both segments' parts) within half a pixel of the line, the run through the joint (its nearest
|
|
473
|
+
pixel within 1 px of it, neighbours at most 1.5 px apart), first to last plus one pixel, to 3
|
|
474
|
+
places. The tool invents no pixel of it: each is the `cap` image's where that image is not
|
|
475
|
+
transparent, else the layer's where the limb has art there, else **missing**. The line
|
|
476
|
+
`assemble` prints for each joint counts all three and gives the cap's box, `[x, y, w, h]` in
|
|
477
|
+
rig px:
|
|
478
|
+
|
|
479
|
+
limb cap: "arm_r" joint "elbow" at [332, 424], on "forearm_r": a disc of radius 19.9165 px (the limb 39.833 px across the joint line), box [312, 404, 40, 40] — on the upper side of the line 621 px from the layer, 7 px missing — …
|
|
480
|
+
|
|
481
|
+
The missing pixels are where the painting hides the limb or where the disc passes its outline.
|
|
482
|
+
Paint them — and, if the layer's own pixels carry the limb's outline across the cap, the whole
|
|
483
|
+
cap — into a `w`x`h` image whose pixel `(i, j)` is rig pixel `(x + i, y + j)`, and name it in
|
|
484
|
+
the segment's `cap`; its transparent pixels keep the layer's. The record is `parts.json`'s
|
|
485
|
+
`limb.cap` on the lower part. A cap image of another size is `ASSEMBLE_LIMB_CAP_SIZE`, one
|
|
486
|
+
transparent over every cap pixel `ASSEMBLE_LIMB_CAP_EMPTY`.
|
|
487
|
+
- **Draw order.** A limb stands where its upper segment's part stood in the plan, its parts
|
|
488
|
+
lowest first, so the upper is drawn over the lower at every joint: upper arm over forearm,
|
|
489
|
+
thigh over shin, shin over foot. The parts it took leave the order.
|
|
490
|
+
- **What `check` reads.** `LIMB_ONE_BONE` (§7) holds every limb part to its one bone in
|
|
491
|
+
`rig.json`. `TIP_OVER_ROOT` does not read a limb part (it turns at its joint; it does not
|
|
492
|
+
hang), and its row says so.
|
|
493
|
+
|
|
494
|
+
The first character built this way (the exam-01 test rig, issue #349) read, per joint, 5 to 10
|
|
495
|
+
missing cap pixels at the elbows and knees and 468 and 562 at the ankles, where the shoe starts
|
|
496
|
+
below the ankle line.
|
|
497
|
+
|
|
432
498
|
### The weight cut (`meshes.<part>.influences`, issue #284)
|
|
433
499
|
|
|
500
|
+
This section and the mesh sections after it are for parts with no joints; a limb is cut at
|
|
501
|
+
its joints instead (*Limbs: cut at their joints*, above).
|
|
502
|
+
|
|
434
503
|
The distance rule (and bone heat) shares a vertex among the bones its mesh's segments name,
|
|
435
504
|
then cuts the list: the 4 largest kept, any share under 0.03 dropped. Both numbers are the
|
|
436
505
|
reference implementation's (`[:4]` and `>= 0.03`), carried over as port constants. Neither
|
|
@@ -598,21 +667,21 @@ contour refusal in a run is listed together; nothing falls back to the lattice:
|
|
|
598
667
|
|
|
599
668
|
| rule | means | change |
|
|
600
669
|
| --- | --- | --- |
|
|
601
|
-
|
|
|
602
|
-
|
|
|
603
|
-
|
|
|
604
|
-
|
|
|
605
|
-
|
|
|
606
|
-
|
|
|
607
|
-
|
|
|
608
|
-
|
|
|
609
|
-
|
|
|
610
|
-
|
|
|
611
|
-
|
|
|
612
|
-
|
|
|
613
|
-
|
|
|
614
|
-
|
|
|
615
|
-
|
|
|
670
|
+
| <a id="CONTOUR_COVERAGE"></a>`CONTOUR_COVERAGE` | an art pixel lies outside the mesh after the margin and simplification | raise `margin` or lower `tolerance` |
|
|
671
|
+
| <a id="CONTOUR_OVERSHOOT"></a>`CONTOUR_OVERSHOOT` | the mesh reaches further than `margin + tolerance + 1` px past the art | lower `margin` or `tolerance`; a grown pixel is within `margin` of art by definition, so what passes the bound is simplification, or a transparent pocket the grown silhouette closed (counted in `grownHolePixels`) |
|
|
672
|
+
| <a id="CONTOUR_BUDGET"></a>`CONTOUR_BUDGET` | more vertices than `budget` | coarser `spacing` or region `spacing`, or a larger `budget` |
|
|
673
|
+
| <a id="CONTOUR_ONE_ISLAND"></a>`CONTOUR_ONE_ISLAND` | the art is more than one 4-connected island (every island's pixel count named); with `stray` declared, an island other than the largest above it, or a tie for the largest | `stray`, if the extra islands are stray pixels you accept not drawing; `bridges: true`, if the pieces ride one bone (issue #326); otherwise a part that is two pieces stays a lattice part, or is split |
|
|
674
|
+
| <a id="CONTOUR_BRIDGE"></a>`CONTOUR_BRIDGE` | under `bridges`, a grown silhouette no bridge can join: of every pair of a vertex on the joined outline and one on a silhouette still apart, none gives a quad wound as the mesh that crosses no outline, holds no other vertex and leaves one closed outline (the silhouettes joined and apart named by art px). The case selftest `CT107` plants: a tolerance that simplifies one outline straight across its notch and through the piece standing in it | lower `tolerance`, or keep the lattice for this part |
|
|
675
|
+
| <a id="CONTOUR_TRACE"></a>`CONTOUR_TRACE` | rigc's tracer refuses a diagonal pinch (two pixels meeting at one corner) in the silhouette before it grows, in its words. A pinch through a hole is not one (the hole is filled first), and no island with its holes filled has one (selftest `CE08`, over every island of every 4x4 mask), so this is a guard; a pinch the growth makes is filled, not refused | the lattice, or the art |
|
|
676
|
+
| <a id="CONTOUR_SELF_INTERSECTION"></a>`CONTOUR_SELF_INTERSECTION` | the simplified outline crosses itself, or too few vertices are left | lower `tolerance` |
|
|
677
|
+
| <a id="CONTOUR_INDEX"></a><a id="CONTOUR_GRID"></a><a id="CONTOUR_COINCIDENT_VERTICES"></a><a id="CONTOUR_ZERO_AREA_TRIANGLE"></a><a id="CONTOUR_ONE_LOOP"></a><a id="CONTOUR_TILING"></a>`CONTOUR_INDEX`, `CONTOUR_GRID`, `CONTOUR_COINCIDENT_VERTICES`, `CONTOUR_ZERO_AREA_TRIANGLE`, `CONTOUR_ONE_LOOP`, `CONTOUR_TILING` | the built mesh fails a topology check (a bug, not an authoring error) | report it |
|
|
678
|
+
| <a id="CONTOUR_PART_HAS_ART"></a>`CONTOUR_PART_HAS_ART` | no pixel above alpha 8 | re-run assemble |
|
|
679
|
+
| <a id="CONTOUR_PARAMETER"></a>`CONTOUR_PARAMETER` | a parameter `src/contour.ts` cannot run at: a margin above 0 and below 1 px (it would add no pixel), a spacing whose keep radius (half of it) snaps to 0, a polygon whose band folds it, a part over 32768 px | the named field |
|
|
680
|
+
| <a id="RIG_CONTOUR_REGIONS_OVERLAP"></a>`RIG_CONTOUR_REGIONS_OVERLAP` | a vertex two regions both reach (`g > 0`); the detail names the vertex and both regions | move the regions apart or narrow a band |
|
|
681
|
+
| <a id="CONTOUR_RIB_ART"></a>`CONTOUR_RIB_ART` | a rib's point (a link origin or a station) is not on the part's art (its pixel at or below the threshold) or not inside the outline, or a point between its ends falls within 1/256 px of the outline — a rib that leaves the art | move the chain onto the part, or leave the chain out of `ribs` |
|
|
682
|
+
| <a id="CONTOUR_RIB_LINK"></a>`CONTOUR_RIB_LINK` | a chain link shorter than the outline's `tolerance` (or of no length), or a joint where the chain turns straight back on itself; the detail names the chain, the link and the tolerance field | fewer, longer links, or a lower `tolerance` |
|
|
683
|
+
| <a id="CONTOUR_RIB_CROSSING"></a>`CONTOUR_RIB_CROSSING` | two ribs cross, touch or share an end (both named, with their ends) | fewer `stations`, or a chain that bends less sharply inside a wide part |
|
|
684
|
+
| <a id="CONTOUR_RIB_EDGE"></a>`CONTOUR_RIB_EDGE` | a rib's consecutive vertices could not be joined by an edge (no edge across them could be flipped) — a guard: the rule keeps every other point off a rib | report it |
|
|
616
685
|
|
|
617
686
|
**Ribs along a chain** (`meshes.<part>.ribs`, issue #188). A rib is a row of vertices across
|
|
618
687
|
the part at a joint of a chain the mesh is bound to, or at a station along one of its links;
|
|
@@ -1103,23 +1172,26 @@ passing steps: step <n>, <v> vertices (best among tested candidates)`. Weights a
|
|
|
1103
1172
|
dropped, the heaviest entry closes): the 0.03 floor that makes the lattice's last-entry close
|
|
1104
1173
|
safe is the author's to choose here.
|
|
1105
1174
|
|
|
1106
|
-
**Refusals** — every one names the part and the rule; nothing falls back
|
|
1175
|
+
**Refusals** — every one names the part and the rule; nothing falls back. The config's own
|
|
1176
|
+
rules hold here as everywhere — a missing or out-of-range number, a Stage B opt-in that is not
|
|
1177
|
+
exactly a value rig-c accepts, a field the mode does not have (`CONFIG_FIELD_PRESENT`,
|
|
1178
|
+
`CONFIG_FIELD_TYPE`, `CONFIG_KEY_KNOWN`), an unknown bone or region name
|
|
1179
|
+
(`CONFIG_NAME_RESOLVES`) — and their rows are §6's, *The config*:
|
|
1107
1180
|
|
|
1108
1181
|
| rule | means |
|
|
1109
1182
|
| --- | --- |
|
|
1110
|
-
|
|
|
1111
|
-
|
|
|
1112
|
-
|
|
|
1113
|
-
| `CONFIG_KEY_KNOWN` | a field the mode does not have — a bound on one of the five allocation rows, or an authored `motionAmplitude` (it is derived, never written) |
|
|
1183
|
+
| <a id="CONFIG_MESH_MODE"></a>`CONFIG_MESH_MODE` | `auto` beside `grid` or `contour`, or no mode at all |
|
|
1184
|
+
| <a id="CONFIG_REGION_NAME_UNIQUE"></a>`CONFIG_REGION_NAME_UNIQUE` | a region named twice in one mesh's `regions` — every one named in one run |
|
|
1185
|
+
| <a id="CONFIG_REGION_BAND_NEEDS_BONE"></a><a id="CONFIG_REGION_BONE_NEEDS_BAND"></a>`CONFIG_REGION_BAND_NEEDS_BONE`, `CONFIG_REGION_BONE_NEEDS_BAND` | a region with a `band` and no `bone`, or a `bone` and no `band`: write both for a region that weights its bone, neither for a density-only region (issue #155) |
|
|
1114
1186
|
| `CONTOUR_*` | the source is refused by the contour mode's own checks at alpha 1 and above — most often `CONTOUR_ONE_ISLAND`: faint pixels the alpha-above-8 modes never saw are islands here |
|
|
1115
|
-
|
|
|
1116
|
-
|
|
|
1117
|
-
|
|
|
1118
|
-
|
|
|
1119
|
-
|
|
|
1120
|
-
|
|
|
1121
|
-
|
|
|
1122
|
-
|
|
|
1187
|
+
| <a id="AUTO_MESH_INPUT"></a>`AUTO_MESH_INPUT` | rig-c refused the call's input by throwing (a protected vertex the source does not have), in its words and code |
|
|
1188
|
+
| <a id="AUTO_MESH_TERMINATION"></a>`AUTO_MESH_TERMINATION` | rig-c returned no mesh: `invalid-input` (the source fails its own `sourceBounds`, a region it refuses, protected influences over the cap), `unsupported-topology`, or `budget-exhausted` with `none-met-the-targets`; or, in the acceptance loop, a replay that does not end as rig-c's contract promises (`replayed-to-accepted-step` at the step asked, `candidatesTried` the full run's `acceptedAt[n − 1].step`, its `acceptedAt` the full run's first n operations, each the same `step`, `kind`, `count` and `sourceVertices`) |
|
|
1189
|
+
| <a id="AUTO_MESH_ACCEPTED"></a>`AUTO_MESH_ACCEPTED` | rig-c returned a mesh that is not accepted; the detail names every declared row not passing and the constraint that stopped it |
|
|
1190
|
+
| <a id="AUTO_MESH_NO_STIMULUS"></a>`AUTO_MESH_NO_STIMULUS` | neither the idle nor a declared `stimulus` moves some of the part's bound bones against the others, so no frame deforms it — the detail names the bones with no motion against each other and the field to declare; missing stimulus is not a pass; declare `meshes.<part>.auto.stimulus`, put the part in `contour` or `grid` mode, or key a bone it binds |
|
|
1191
|
+
| <a id="AUTO_MESH_MOTION"></a>`AUTO_MESH_MOTION` | the reduced mesh against its source on the idle is not accepted and the acceptance loop wrote no step in its place: "no reduction passes the motion bound" (the full result's failing rows and every probe named; under `motion.selection`, "… among the tested candidates", with `maxProbes` and the termination), or the chosen step passes on the grid frames and not on the whole idle (its selection and held-out values and worst frames named); when the source itself is not accepted against itself, one sentence first (issue #280): "the unreduced source itself fails <where> (<row> <value> against <bound>), so no replayed step can pass — change the source (its spacing or its outline) or lower the stimulus", `<where>` a declared stimulus by its animation's name (`at stimulus hem +150`), `at idle frame <id>`, or `in its geometry` for a geometry row, the stimulus remedy only when it was read at one; then the full result's rows, for the record. No search runs, and the stage's `replay "<part>"` line names the same place |
|
|
1192
|
+
| <a id="AUTO_MESH_SELECTION_BUDGET"></a>`AUTO_MESH_SELECTION_BUDGET` | `motion.selection.maxProbes` is below ⌈log₂(N − I)⌉, the bisection the multi-interval search runs whole first; N, I and the number required named; nothing replayed |
|
|
1193
|
+
| <a id="AUTO_MESH_SELECTION_ROLES"></a>`AUTO_MESH_SELECTION_ROLES` | a multi-interval choice whose probes read a frame the final comparison holds out, or one it does not declare `selection`; the frames named, the held-out claim withdrawn |
|
|
1194
|
+
| <a id="AUTO_MESH_MOTION_INPUT"></a>`AUTO_MESH_MOTION_INPUT` | the comparison could not be made: rig-c refused its input (its code carried — `COMPARE_REFERENCE_FAILS` when the source fails its own `sourceBounds`, `COMPARE_INPUTS_DIFFER`, …), the reference build is red at rigc's gate, or a gate build wrote no `skeleton.model.json`; in the acceptance loop, a replayed step's build that rigc's gate refuses |
|
|
1123
1195
|
|
|
1124
1196
|
**What rig-c cannot refine.** Refinement inserts only inside a region and its band (the
|
|
1125
1197
|
contract's P16). rig-c 2.19.0 stopped by name when an edge's far end lay further beyond the
|
|
@@ -1163,6 +1235,69 @@ right, at +30 moved its hand bone `sleeve_l2` 43.9 px right and 27.6 px up, at
|
|
|
1163
1235
|
51.9 px right, toward the body — so `demo`'s `wave` raises the image's right arm with
|
|
1164
1236
|
`sleeve_l0` at +48 (selftest `RG99` holds the sign on the rig fixture).
|
|
1165
1237
|
|
|
1238
|
+
`demo`'s `wave` in full, as [`examples/demo/animations.json`](https://github.com/rig-c/parts/blob/main/examples/demo/animations.json)
|
|
1239
|
+
holds it (`curve` is rig-c's escape from a named easing, its AUTHORING R6): the arm out to the
|
|
1240
|
+
side and held, a bend further down the arm, the hand rocked ±10°, back down.
|
|
1241
|
+
|
|
1242
|
+
```jsonc
|
|
1243
|
+
"wave": {
|
|
1244
|
+
"duration": 2.21,
|
|
1245
|
+
"loop": false,
|
|
1246
|
+
"tracks": [
|
|
1247
|
+
{
|
|
1248
|
+
"bone": "sleeve_l0",
|
|
1249
|
+
"property": "rotate",
|
|
1250
|
+
"keys": [
|
|
1251
|
+
{"t": 0, "v": [0], "curve": [0.0875, 0, 0.2625, 48]},
|
|
1252
|
+
{"t": 0.35, "v": [48], "curve": [0.69, 48, 1.37, 48]},
|
|
1253
|
+
{"t": 1.71, "v": [48], "curve": [1.835, 48, 2.085, 0]},
|
|
1254
|
+
{"t": 2.21, "v": [0]}
|
|
1255
|
+
]
|
|
1256
|
+
},
|
|
1257
|
+
{
|
|
1258
|
+
"bone": "sleeve_l1",
|
|
1259
|
+
"property": "rotate",
|
|
1260
|
+
"keys": [
|
|
1261
|
+
{"t": 0, "v": [0], "curve": [0.0875, 0, 0.2625, 20]},
|
|
1262
|
+
{"t": 0.35, "v": [20], "curve": [0.69, 20, 1.37, 20]},
|
|
1263
|
+
{"t": 1.71, "v": [20], "curve": [1.835, 20, 2.085, 0]},
|
|
1264
|
+
{"t": 2.21, "v": [0]}
|
|
1265
|
+
]
|
|
1266
|
+
},
|
|
1267
|
+
{
|
|
1268
|
+
"bone": "sleeve_l2",
|
|
1269
|
+
"property": "rotate",
|
|
1270
|
+
"keys": [
|
|
1271
|
+
{"t": 0, "v": [0], "curve": [0.0875, 0, 0.2625, 0]},
|
|
1272
|
+
{"t": 0.35, "v": [0], "curve": [0.3925, 0, 0.4775, 10]},
|
|
1273
|
+
{"t": 0.52, "v": [10], "curve": [0.605, 10, 0.775, -10]},
|
|
1274
|
+
{"t": 0.86, "v": [-10], "curve": [0.945, -10, 1.115, 10]},
|
|
1275
|
+
{"t": 1.2, "v": [10], "curve": [1.285, 10, 1.455, 0]},
|
|
1276
|
+
{"t": 1.54, "v": [0], "curve": [1.7075, 0, 2.0425, 0]},
|
|
1277
|
+
{"t": 2.21, "v": [0]}
|
|
1278
|
+
]
|
|
1279
|
+
}
|
|
1280
|
+
]
|
|
1281
|
+
}
|
|
1282
|
+
```
|
|
1283
|
+
|
|
1284
|
+
**Which link bends where.** A sleeve chain the proposer drafts without `--keypoints` (the
|
|
1285
|
+
two-blob rule, `src/propose.ts`) divides the `handwear` part's height in three, not the arm
|
|
1286
|
+
at its joints: its links stand at 0, 1/3 and 2/3 of the way from 15 px below the part's top
|
|
1287
|
+
row to 6 px above its bottom row, and its tip 3 px above the bottom row. On `demo`, `sleeve_l`'s
|
|
1288
|
+
links stand at y 260, 381 and 502, tip 626 (rig px), and on `scarf` at 277, 413 and 550, tip
|
|
1289
|
+
689; on both paintings the elbow lies between links 1 and 2 and the wrist between link 2 and
|
|
1290
|
+
the tip [observed: the chain drawn over the painting and read by eye, issue #345]. So
|
|
1291
|
+
`sleeve_l1` turns the arm part way down the upper arm, and `sleeve_l2` part way down the
|
|
1292
|
+
forearm, hand included: `wave`'s +20 on `sleeve_l1` is that bend, not an elbow's. Place the
|
|
1293
|
+
links on the joints (`bones`, the chain's `points`) before keying a bend that must read as
|
|
1294
|
+
an elbow. Under `--keypoints` the chain is `<s>_shoulder` → `<s>_elbow`, tip at `<s>_wrist`
|
|
1295
|
+
(§3, *A posed figure*): two links, the second the forearm from the elbow, and no `sleeve_l2`,
|
|
1296
|
+
so a clip keying `sleeve_l2` names a bone that rig lacks. `propose --keypoints` on `demo`'s
|
|
1297
|
+
parts, fed its generation control pose doubled to painting px (what was asked of the model,
|
|
1298
|
+
not where the joints ended — read for the chain's shape only), wrote `sleeve_l`
|
|
1299
|
+
`[[492, 272], [550, 440]]`, tip `[626, 590]`, amplitudes `[-0.2, -0.6]`.
|
|
1300
|
+
|
|
1166
1301
|
`build` writes `surprised` into `rig/motion.json` after `idle`, gates it with the rig, and
|
|
1167
1302
|
`check` names it on a line of its own and reads it for folds (`ANIMATIONS_DO_NOT_FOLD`, §7,
|
|
1168
1303
|
issue #320). [`examples/reference-sample`](https://github.com/rig-c/parts/tree/main/examples/reference-sample), in the repository, carries one such file,
|
|
@@ -1173,7 +1308,8 @@ issue #320). [`examples/reference-sample`](https://github.com/rig-c/parts/tree/m
|
|
|
1173
1308
|
[rig] animations beside the idle, from …/animations.json as written: hop
|
|
1174
1309
|
[check] beside the idle: 1 animation(s), hop — built and gated by rigc with the rig; ANIMATIONS_DO_NOT_FOLD reads each for folds, every other bar here reads the idle
|
|
1175
1310
|
[check] ANIMATIONS_DO_NOT_FOLD: PASS — 2 animation(s) read by rigc render --folds at 12 fps, its 2 physics constraint(s) left out (idle, hop): 0 folding mesh(es), 0 not declared in may_fold (<= 0)
|
|
1176
|
-
[check]
|
|
1311
|
+
[check] STRESS_OFF_CHAIN: SKIP — "sleeves": its weights ride 2 chains ("sleeve_r0_ctl", "sleeve_l0_ctl"): turning one stretches the part toward the other by construction; a part riding one chain is read until a limbs block names each limb
|
|
1312
|
+
[check] check: PASS; 10 of 11 bar(s) measured, 1 skipped (STRESS_OFF_CHAIN)
|
|
1177
1313
|
```
|
|
1178
1314
|
|
|
1179
1315
|
A bone the rig lacks is rigc's refusal at the rig stage, in rigc's words (`RIG_RIGC_GREEN`); a
|
|
@@ -1223,6 +1359,19 @@ way there, are in their READMEs, in the repository:
|
|
|
1223
1359
|
[`examples/demo/README.md`](https://github.com/rig-c/parts/blob/main/examples/demo/README.md) and
|
|
1224
1360
|
[`examples/scarf/README.md`](https://github.com/rig-c/parts/blob/main/examples/scarf/README.md).
|
|
1225
1361
|
|
|
1362
|
+
**Under the idle alone** a strand trails by what its constraint's values make of a slow
|
|
1363
|
+
swing, and the soft-region recipe's *Limits* (below) is the same finding for a jiggle: a slow
|
|
1364
|
+
idle barely moves a stiff spring, and faster keys — a hop, a turn, in a named animation — are
|
|
1365
|
+
what it answers. Measured on `demo` (issue #345, rig-c 2.47.1: the idle rendered at 30 fps
|
|
1366
|
+
with `--geometry`, the build against the same build with `constraints` removed, each link's
|
|
1367
|
+
world angle compared frame by frame): the twin tails' last links (`hairback_r2` and
|
|
1368
|
+
`hairback_l2`, inertia 0.8, strength 58.5, the values above) trail their keyed angle by at
|
|
1369
|
+
most 2.753° and 1.720° — `hairback_r2`'s tip 9.96 rig px, where the idle swings that link's
|
|
1370
|
+
world angle through 9.276°, and 2.612° in the idle's second half, so not the physics reset's
|
|
1371
|
+
transient; the bangs' last links (inertia 0.2, strength 130) by at most 0.127°, the skirt's
|
|
1372
|
+
0.073°, the sleeves' 0.054°. A strand that reads stiff under the idle is not broken: key it
|
|
1373
|
+
in a clip, or soften it as the tails are softened.
|
|
1374
|
+
|
|
1226
1375
|
**Limits.** Every slot holds one attachment, the part's own image, so an expression moves,
|
|
1227
1376
|
turns and scales the face's parts and never swaps one for another: there is no second mouth
|
|
1228
1377
|
or eye shape to key, and no lip-sync. `check` reads an animation beside the idle for folds
|
|
@@ -1233,6 +1382,16 @@ examples each clip was read by `check`'s own `TEXTURE_STRETCH` reading applied t
|
|
|
1233
1382
|
gate, and it is where an arm raised overhead was found to tear `demo`'s elbow (5.327
|
|
1234
1383
|
against 1.926544).
|
|
1235
1384
|
|
|
1385
|
+
**A raised arm moves its `handwear` part only.** The proposer meshes each `handwear` part on
|
|
1386
|
+
its sleeve chain and the `topwear` part on `chest` and `hip` alone (§3, *the trunk parts'
|
|
1387
|
+
segments* and the sleeve rule), so arm art See-through left inside `topwear` — a puff
|
|
1388
|
+
sleeve, a shoulder cap — stays with the torso while the arm leaves it. On `demo`, whose puff
|
|
1389
|
+
sleeves are in `handwear`, `wave` (rendered at 30 fps with `--geometry`, physics left out,
|
|
1390
|
+
issue #345) moves `handwear_l`'s vertices up to 443.2 rig px and every other slot's by 0.
|
|
1391
|
+
To make such art follow the arm, cut it out of `topwear` with an `assemble.cuts` entry and
|
|
1392
|
+
give the piece a mesh on the `sleeve_<s>` chain (§5, *Cutting a piece out of a layer*, the move
|
|
1393
|
+
`scarf`'s `robe_r` measured); that cut has not been measured on a sleeve.
|
|
1394
|
+
|
|
1236
1395
|
### Recipe: a soft region driven by physics
|
|
1237
1396
|
|
|
1238
1397
|
A jiggle (a bust, the hips) is a patch of one part that lags behind the body. The package
|
|
@@ -1267,7 +1426,7 @@ fragment below, cut to the bust:
|
|
|
1267
1426
|
`build` on `reference-sample` as tracked (PR #187; the values above are the ones tuned for its `hop`, issue #183):
|
|
1268
1427
|
|
|
1269
1428
|
```
|
|
1270
|
-
check: PASS; 10 of
|
|
1429
|
+
check: PASS; 10 of 11 bar(s) measured, 1 skipped (STRESS_OFF_CHAIN)
|
|
1271
1430
|
loop physics: 2 physics constraint(s) left out of the loop's frames, reported, not judged — "bust_phys" on bone "chest_jiggle" (rig.json), "hip_phys" on bone "hip_jiggle" (rig.json)
|
|
1272
1431
|
loop: idle 49 frame(s) at 12 fps, f0000 vs f0048 (t = 4s) with the rig's 2 physics constraint(s) left out (named on the `loop physics:` line; rendered with them, the ends need not meet — `build --loop --lead-in <n>`): max |d| 0 (0 required)
|
|
1273
1432
|
```
|
|
@@ -1571,11 +1730,11 @@ proposal in as the steps above say (`RL01`); every step must exit 0.
|
|
|
1571
1730
|
| --- | --- | --- | --- |
|
|
1572
1731
|
| `layers` | the table, then one `author-made: layer "author:<label>" — …` line per layer the author made (group `author` in the table; §5, *A layer the author made*), 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*) |
|
|
1573
1732
|
| `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 |
|
|
1574
|
-
| `assemble` | one line per part — its counts (`op=` opaque, `vis=` visible, `src=` taken / candidates, `unproj=` visible but not projected, `drift=<n> (<p>% of core)`, `merged=`, `seam=`; *parts.json*, below). `drift=` is `refused_drift_px` in rig px and its share of the part's candidates, `projected_core_px`, which it is a subset of (issue #314); no bar reads either. On the four public examples the share runs to 94.5 % (`scarf` `hair_back`, 479 of 507) and the count to 26,472 (`scarf` `topwear`, 22.3 %), and the seam override repaints refused top-most pixels afterwards, so a large count says where See-through's colour was not taken, not that the part is unlike the painting: the `drift:` line below is the one that names a body of them another part holds. Then 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), then one `drift: "<part>" refuses <n> px of <run>:<tag> (its colour more than 90 off the painting, max channel), in a body of <px> px at x,y wxh (…); by the plan's draw order "<holder>" holds <px> px of it (…), "<holder>" drawn in front of "<part>"` line per part whose drift refusals hold a body (the same opening and bar) that another part holds in the draw order — that layer is not what the painting shows there (none on the five public paintings); and look at `render/recomposite_error_rig.png`. Between the part lines and the totals, one `author-made: part "<part>" (<run>:author:<label>) — …` line per part from a layer the author made (below, *A layer the author made*), then 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) |
|
|
1733
|
+
| `assemble` | one line per part — its counts (`op=` opaque, `vis=` visible, `src=` taken / candidates, `unproj=` visible but not projected, `drift=<n> (<p>% of core)`, `merged=`, `seam=`; *parts.json*, below). `drift=` is `refused_drift_px` in rig px and its share of the part's candidates, `projected_core_px`, which it is a subset of (issue #314); no bar reads either. On the four public examples the share runs to 94.5 % (`scarf` `hair_back`, 479 of 507) and the count to 26,472 (`scarf` `topwear`, 22.3 %), and the seam override repaints refused top-most pixels afterwards, so a large count says where See-through's colour was not taken, not that the part is unlike the painting: the `drift:` line below is the one that names a body of them another part holds. Then 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), then one `drift: "<part>" refuses <n> px of <run>:<tag> (its colour more than 90 off the painting, max channel), in a body of <px> px at x,y wxh (…); by the plan's draw order "<holder>" holds <px> px of it (…), "<holder>" drawn in front of "<part>"` line per part whose drift refusals hold a body (the same opening and bar) that another part holds in the draw order — that layer is not what the painting shows there (none on the five public paintings); and look at `render/recomposite_error_rig.png`. Between the part lines and the totals, one `author-made: part "<part>" (<run>:author:<label>) — …` line per part from a layer the author made (below, *A layer the author made*), then 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 — with `config.limbs` (issue #349) — one `limb cut: "<part>" opaque <n> = "<segment part>" <px> + …` line per part a limb takes and one `limb cap:` line per joint, its cap's pixels from the cap image, from the layer and missing, and its box (§3, *Limbs: cut at their joints*), 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) |
|
|
1575
1734
|
| `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 <link> at … runs to … N degrees off the head's down axis …` — a fringe link that does not lean with the head (§3, the fringe in the head's frame): move it along the lock it drives; `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 |
|
|
1576
1735
|
| `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 |
|
|
1577
1736
|
| `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` |
|
|
1578
|
-
| `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, then — when `motion.json` holds an animation, the idle included — `ANIMATIONS_DO_NOT_FOLD` and one `folds` line per folding mesh, rigc's own (issues #320, #333), `RECOMPOSITE_HOLES` and, under `--source`, `SETUP_POSE_VS_SOURCE` (§7), `check.json`; the last line says how many of the bars measured — nine, ten with the fold bar — and names the ones that said SKIP | `check: PASS;
|
|
1737
|
+
| `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, then — when `motion.json` holds an animation, the idle included — `ANIMATIONS_DO_NOT_FOLD` and one `folds` line per folding mesh, rigc's own (issues #320, #333), then — where a `footwear` part rides a bone that hangs from another — `FEET_STAY_LEVEL` and one `foot` line per such part (issue #348), then — when `parts.json` names a `handwear` part and there is an idle — `STRESS_OFF_CHAIN` (issue #347), then — where `parts.json` holds a limb segment's part — `LIMB_ONE_BONE` and one `limb` line per such part (issue #349), `RECOMPOSITE_HOLES` and, under `--source`, `SETUP_POSE_VS_SOURCE` (§7), `check.json`; the last line says how many of the bars measured — nine, ten with the fold bar, one more each with the feet-level bar, the stress bar and the limb bar — and names the ones that said SKIP | `check: PASS; 11 of 11 bar(s) measured, 0 skipped` on `demo` and `scarf`, whose sleeves each ride one chain; `check: PASS; 10 of 11 bar(s) measured, 1 skipped (STRESS_OFF_CHAIN)` on `reference-demo` and `reference-sample`, whose one `sleeves` mesh rides both sleeve chains (issue #347) — no example writes `FEET_STAY_LEVEL`, every shoe riding `root`; 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); `CHECK_ANIMATIONS_DO_NOT_FOLD` — a clip turns a mesh over (§6); `CHECK_STRESS_OFF_CHAIN` — a sleeve weighted off its chain (§6); `CHECK_LIMB_ONE_BONE` — a limb part on a second bone (§6) |
|
|
1579
1738
|
| `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; a `stretch` line's `held_by` (issue #321), right after `worst`, names the bones the worst edge's two vertices hang on and their idle chains, in `CHECK_TEXTURE_STRETCH`'s words (§6) and by the same function, on a PASS as on a FAIL | `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` |
|
|
1580
1739
|
| `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 |
|
|
1581
1740
|
| `loop` (inside `build --loop`, or `loop --frames … --out …`) | the dropped-duplicate line, or, when the end frame is not frame 0, the jump line: its max \|d\| and px over 40, then why — under `build`, `the rig holds N physics constraint(s), and rigc's render starts every one at rest at frame 0` with the remedy `build --loop --lead-in <n>`, or `the rig holds no physics constraint, so the idle itself does not close` (`CHECK_LOOP_CLOSES`); under `loop --frames`, which reads frames alone, both causes (issue #325); 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) |
|
|
@@ -1960,20 +2119,24 @@ colour. Opaque, and the same bytes on every run.
|
|
|
1960
2119
|
|
|
1961
2120
|
## 6. Refusals: the rule, and what has to change
|
|
1962
2121
|
|
|
1963
|
-
Every refusal is `FAIL RULE: object — detail
|
|
1964
|
-
|
|
2122
|
+
Every refusal is `FAIL RULE: object — detail (see rig-parts guide RULE)`, and the
|
|
2123
|
+
command at the end prints the rule's row below. Inside `build` it is printed under the
|
|
2124
|
+
stage's prefix (`[assemble] FAIL …`), and the build stops there. A line that quotes a
|
|
2125
|
+
rigc failure (`RIG_RIGC_GREEN`, `CHECK_RIGC_GREEN`) keeps rigc's own pointer inside the
|
|
2126
|
+
quote, and this package's goes after it. Every rule the source can print has exactly one
|
|
2127
|
+
row in this page's `rule` and `line` tables; the selftest holds that (`TY16`).
|
|
1965
2128
|
|
|
1966
2129
|
### Reading the inputs
|
|
1967
2130
|
|
|
1968
2131
|
| rule | means | change |
|
|
1969
2132
|
| --- | --- | --- |
|
|
1970
|
-
|
|
|
1971
|
-
|
|
|
1972
|
-
|
|
|
1973
|
-
|
|
|
1974
|
-
|
|
|
1975
|
-
|
|
|
1976
|
-
|
|
|
2133
|
+
| <a id="LAYERS_INPUT_KIND"></a>`LAYERS_INPUT_KIND` | the path is neither a directory with `layers.json`, a `layers.json`, nor a `.psd` | the `--full`/`--head` path |
|
|
2134
|
+
| <a id="LAYERS_MANIFEST_PRESENT"></a><a id="LAYERS_MANIFEST_IS_JSON"></a><a id="LAYERS_FIELD_PRESENT"></a><a id="LAYERS_KEY_KNOWN"></a>`LAYERS_MANIFEST_PRESENT`, `LAYERS_MANIFEST_IS_JSON`, `LAYERS_FIELD_PRESENT`, `LAYERS_KEY_KNOWN` | the wrapper's `layers.json` is missing, unparsable, or not the wrapper's shape | the run's output directory; re-export it |
|
|
2135
|
+
| <a id="LAYERS_PNG_PRESENT"></a><a id="LAYERS_PNG_UNAMBIGUOUS"></a><a id="LAYERS_PNG_DECODES"></a><a id="LAYERS_PNG_MATCHES_BBOX"></a>`LAYERS_PNG_PRESENT`, `LAYERS_PNG_UNAMBIGUOUS`, `LAYERS_PNG_DECODES`, `LAYERS_PNG_MATCHES_BBOX` | a layer's PNG is missing, found in two places, not a PNG, or not its box's size | the run's files |
|
|
2136
|
+
| <a id="LAYERS_TAG_KNOWN"></a><a id="LAYERS_NAME_UNIQUE"></a><a id="LAYERS_BBOX_INSIDE_CANVAS"></a>`LAYERS_TAG_KNOWN`, `LAYERS_NAME_UNIQUE`, `LAYERS_BBOX_INSIDE_CANVAS` | a layer name that is neither a See-through v3 tag nor `author:<label>` (or is `author:` with a label that is empty, starts with `.` or whitespace, ends with whitespace, or holds a slash, backslash or colon — the detail says which), a repeated name, a box off the canvas | the run (these are See-through's own outputs); a layer you added by hand is named `author:<label>` (§5, *A layer the author made*) |
|
|
2137
|
+
| <a id="PSD_FILE_PRESENT"></a><a id="PSD_PARSES"></a><a id="PSD_IS_RGB8"></a><a id="PSD_HAS_LAYERS"></a><a id="PSD_LAYER_PLAIN"></a><a id="PSD_LAYER_HAS_PIXELS"></a>`PSD_FILE_PRESENT`, `PSD_PARSES`, `PSD_IS_RGB8`, `PSD_HAS_LAYERS`, `PSD_LAYER_PLAIN`, `PSD_LAYER_HAS_PIXELS` | the `.psd` is missing, unreadable, not 8-bit RGB, has no layer, or has a layer that is hidden, not at full opacity, or without pixels | the `.psd` |
|
|
2138
|
+
| <a id="ASSEMBLE_SOURCE_PRESENT"></a><a id="ASSEMBLE_SOURCE_DECODES"></a>`ASSEMBLE_SOURCE_PRESENT`, `ASSEMBLE_SOURCE_DECODES` | the painting is missing or not a PNG | `--source` |
|
|
2139
|
+
| <a id="SHEET_SOURCE_PRESENT"></a><a id="SHEET_PNG_PRESENT"></a>`SHEET_SOURCE_PRESENT`, `SHEET_PNG_PRESENT` | `sheet`'s painting, or a part PNG a `parts.json` lists, is missing | `--source`, `--layers` |
|
|
1977
2140
|
|
|
1978
2141
|
### Plausibility (`WARN` in `layers`, a note in `assemble --propose-plan`)
|
|
1979
2142
|
|
|
@@ -2000,9 +2163,9 @@ over the whole union: a layer is part of it, so it could never be more than 1x.
|
|
|
2000
2163
|
|
|
2001
2164
|
| rule | crossed when | [observed] on the two examples' 116 layers (four runs) |
|
|
2002
2165
|
| --- | --- | --- |
|
|
2003
|
-
|
|
|
2004
|
-
|
|
|
2005
|
-
|
|
|
2166
|
+
| <a id="PLAN_LAYER_TRANSLUCENT"></a>`PLAN_LAYER_TRANSLUCENT` | judged, and `translucent` above 50 % | the most translucent judged layer is 17.8 % (reference-sample, full run, `front hair`) |
|
|
2167
|
+
| <a id="PLAN_LAYER_BACKGROUND"></a>`PLAN_LAYER_BACKGROUND` | judged, `background` above 50 %, and `translucent` above 25 % | the most background-coloured judged layer is 21.9 % (reference-demo, head run, `topwear`, a white dress); of judged layers above 10 % background, the most translucent is 5.6 % (reference-demo, full run, `handwear-r`) |
|
|
2168
|
+
| <a id="PLAN_LAYER_OVERSIZED"></a>`PLAN_LAYER_OVERSIZED` | `area` above 4x | the largest is 1.681x (reference-demo, head run, `back hair`, which fills the crop) |
|
|
2006
2169
|
|
|
2007
2170
|
**Judged** means `area` at least 0.05x (or `-`). The two colour rules skip smaller
|
|
2008
2171
|
layers on purpose: **[observed]** all 27 example layers of 150 px or more that are above
|
|
@@ -2031,162 +2194,214 @@ See-through with another seed.
|
|
|
2031
2194
|
|
|
2032
2195
|
| rule | means | change |
|
|
2033
2196
|
| --- | --- | --- |
|
|
2034
|
-
|
|
|
2035
|
-
|
|
|
2036
|
-
| `
|
|
2037
|
-
|
|
|
2038
|
-
| `
|
|
2039
|
-
| `
|
|
2040
|
-
| `
|
|
2041
|
-
| `
|
|
2042
|
-
| `
|
|
2043
|
-
| `
|
|
2044
|
-
| `
|
|
2045
|
-
| `
|
|
2046
|
-
| `
|
|
2047
|
-
| `
|
|
2048
|
-
| `
|
|
2049
|
-
|
|
|
2050
|
-
| `
|
|
2051
|
-
| `
|
|
2052
|
-
| `
|
|
2053
|
-
| `
|
|
2054
|
-
| `
|
|
2055
|
-
| `
|
|
2056
|
-
| `
|
|
2197
|
+
| <a id="CONFIG_FILE_PRESENT"></a><a id="CONFIG_IS_JSON"></a>`CONFIG_FILE_PRESENT`, `CONFIG_IS_JSON` | no such file, or not JSON | `--config` |
|
|
2198
|
+
| <a id="CONFIG_KEY_KNOWN"></a><a id="CONFIG_KEY_RETIRED"></a><a id="CONFIG_FIELD_PRESENT"></a><a id="CONFIG_FIELD_TYPE"></a>`CONFIG_KEY_KNOWN`, `CONFIG_KEY_RETIRED`, `CONFIG_FIELD_PRESENT`, `CONFIG_FIELD_TYPE` | an unknown key (a retired one says what replaces it), a missing one, a wrong type; a project's own record under a plain key, or an annotation (`note`, `<name>_note`) holding something other than a string; in `meshes.<part>.auto` (§3, *An automatic mesh*), a missing or out-of-range number, a Stage B opt-in that is not exactly a value rig-c accepts, or a field the mode does not have — a bound on one of the five allocation rows, or an authored `motionAmplitude` (it is derived, never written); under `comfy paint`, `CONFIG_FIELD_PRESENT` on `config.generation`: a config with no `generation` block (the line names the fields it holds) | the named field; a record goes under a key beginning `x-` (any JSON, read by nothing), a remark under `note` or `<name>_note` (a string) — §3; under `comfy paint`, `config.generation` |
|
|
2199
|
+
| <a id="CONFIG_KEY_UNIQUE"></a>`CONFIG_KEY_UNIQUE` | a key written twice in one object of a file the config names — the pose file `generation.control.skeleton` names, or the `motion.animations_from` file; JSON keeps only the last value, so every other would be dropped without a word | that file: each key once |
|
|
2200
|
+
| <a id="CONFIG_ANIMATION_NAME_FREE"></a>`CONFIG_ANIMATION_NAME_FREE` | the `motion.animations_from` file holds an animation named `idle`, the animation `config.motion` writes | rename that animation |
|
|
2201
|
+
| <a id="CONFIG_HEAD_BOX_SQUARE"></a>`CONFIG_HEAD_BOX_SQUARE` | `seethrough.head_box` is not a non-empty square | `head_box` — take `propose --head-box`'s |
|
|
2202
|
+
| <a id="CONFIG_TAG_KNOWN"></a><a id="CONFIG_PART_NAME"></a><a id="CONFIG_PART_UNIQUE"></a>`CONFIG_TAG_KNOWN`, `CONFIG_PART_NAME`, `CONFIG_PART_UNIQUE` | a plan or extend entry names neither a v3 tag nor `author:<label>` (an `author:` tag with a malformed label says what the label must be), a part name that is not a file name, or a part or layer twice — a patch named like a plan part or another patch, and a cut's `into` named like a plan part, a patch or another cut's, included | `assemble.plan`, `assemble.patches`, `assemble.cuts` |
|
|
2203
|
+
| <a id="CONFIG_NAME_RESOLVES"></a>`CONFIG_NAME_RESOLVES` | a parent, segment, region, track, blink member, blink still part or bone, extend part, patch or cut `draw.before`, or cut `from` names nothing declared above it (a cut's `from` must be a plan part); or a constraint's `bones`, `target`, `source` or `bone` names a bone `bones` does not declare (the detail names the constraint and lists the bones that exist); in `meshes.<part>.auto`, a bone or region name nothing declares | the named reference, or the declaration it needs |
|
|
2204
|
+
| <a id="CONFIG_BONE_UNIQUE"></a>`CONFIG_BONE_UNIQUE` | a bone or chain declared twice, or `root` declared | `bones` |
|
|
2205
|
+
| <a id="CONFIG_BONE_INHERIT"></a>`CONFIG_BONE_INHERIT` | a single bone's `inherit` is a string that is not one of rig-c's five mode names as its table spells them (issue #348); the line lists all five. `"NoScale"` is refused too: the runtime would fold the first letter, and this loader folds and maps nothing | `bones[i].inherit` — `normal`, `onlyTranslation`, `noRotationOrReflection`, `noScale` or `noScaleOrReflection` (§3, `bones`) |
|
|
2206
|
+
| <a id="CONFIG_LIMB_BONE"></a><a id="CONFIG_LIMB_BONES_CHAIN"></a><a id="CONFIG_LIMB_FROM_RUN"></a><a id="CONFIG_LIMB_RANGE"></a>`CONFIG_LIMB_BONE`, `CONFIG_LIMB_BONES_CHAIN`, `CONFIG_LIMB_FROM_RUN`, `CONFIG_LIMB_RANGE` | `config.limbs` (issue #349): a limb part's `regions` entry names a bone other than its segment's; a segment's bone is not the child of the segment above's (the lower segment turns about the joint on a bone that hangs from the upper's); two segments of one limb take one part with another part between them; a `range` without `min <= 0 <= max` | `regions.<part>` the segment's `bone`; `bones` (parent the lower bone under the upper) or the segment's `bone`; the segments' order or `from`; the `range` (degrees from rest, rest in it) |
|
|
2207
|
+
| <a id="CONFIG_PART_ATTACHED"></a>`CONFIG_PART_ATTACHED` | a plan part or a cut's piece with neither or both of a mesh and a region; a patch with a mesh, or with no region | `meshes` / `regions` |
|
|
2208
|
+
| <a id="CONFIG_RIBS_MODE"></a>`CONFIG_RIBS_MODE` | `meshes.<part>.ribs` on a lattice (`grid`) mesh: its vertices are its grid's corners, which no row can move (issue #188) | put the part in `contour` or `auto`, or remove `ribs` |
|
|
2209
|
+
| <a id="CONFIG_INFLUENCES_MODE"></a>`CONFIG_INFLUENCES_MODE` | `meshes.<part>.influences` on an automatic (`auto`) mesh: that mode's cap and floor are `auto.influences`, which rig-c's reduction is handed (issue #284) | declare them in `auto.influences`, or remove `influences` |
|
|
2210
|
+
| <a id="CONFIG_STRAY_MODE"></a>`CONFIG_STRAY_MODE` | `meshes.<part>.stray` on a contour (`contour`) or automatic (`auto`) mesh: those modes state the largest island they may leave out in `contour.stray` and `auto.source.stray`, which their trace reads (issue #303) | declare it there, or remove `stray` |
|
|
2211
|
+
| <a id="CONFIG_PATCH_BOX"></a>`CONFIG_PATCH_BOX` | an `assemble.patches` box with `x1 <= x0` or `y1 <= y0` | that patch's `box` (`x1`, `y1` are exclusive) |
|
|
2212
|
+
| <a id="CONFIG_AMPS_MATCH_CHAIN"></a>`CONFIG_AMPS_MATCH_CHAIN` | a chain track's `amps` is not one per link | that track's `amps` |
|
|
2213
|
+
| <a id="CONFIG_PERIOD_DIVIDES_DURATION"></a>`CONFIG_PERIOD_DIVIDES_DURATION` | a period that is not a whole fraction of the idle — the loop could not close | that track's `period`, or `motion.duration` |
|
|
2214
|
+
| <a id="CONFIG_BLINK_GROUP_MEMBERS"></a>`CONFIG_BLINK_GROUP_MEMBERS` | `motion.blink.eyes` or `motion.blink.brows` is `[]`: a group with no members, which rigc refuses at the gate | a figure with no eyewhite part has nothing to blink: leave `motion.blink` out; one with no eyebrow part: leave `brows` and `brow_drop` out |
|
|
2215
|
+
| <a id="CONFIG_BLINK_GROUP_UNIQUE"></a>`CONFIG_BLINK_GROUP_UNIQUE` | `motion.blink.eyes` or `motion.blink.brows` names one bone more than once; the detail gives the bone and every index it sits at. rigc refuses it at the gate (`group "eyes" names member "eye" twice`) | name each bone once: the group keys every member it names |
|
|
2216
|
+
| <a id="CONFIG_BONE_PROPERTY_KEYED_ONCE"></a>`CONFIG_BONE_PROPERTY_KEYED_ONCE` | two tracks key one bone property: two single tracks, a single track on a chain link's `rotate`, or a single track on a blink member's `scaley` (`eyes`) or `translatey` (`brows`); the detail names the property and every track by its config path. rigc refuses it at the gate (`animation "idle" has two tracks on eye.scaley; merge them into one track`) | merge them into one track, or key another property or bone |
|
|
2217
|
+
| <a id="CONFIG_BLINK_BROWS_PAIRED"></a>`CONFIG_BLINK_BROWS_PAIRED` | `motion.blink.brows` without `brow_drop`, or `brow_drop` without `brows` | state both or neither |
|
|
2218
|
+
| <a id="CONFIG_STILL_OFF_THE_BLINK"></a>`CONFIG_STILL_OFF_THE_BLINK` | a `motion.blink.still` entry names a region on a bone the blink's `eyes` does not name (nothing to hold still), or its `bone` is one the blink's `eyes` names (the still piece would blink) | that entry's part, or its `bone` — the eye bone's parent, `head` as proposed |
|
|
2219
|
+
| <a id="CONFIG_CONSTRAINT_TYPE_KNOWN"></a>`CONFIG_CONSTRAINT_TYPE_KNOWN` | a `constraints` entry's `type` is not one of rig-c's five: `ik`, `transform`, `path`, `physics`, `slider` (spelled as rigc spells them; `IK` is not `ik`) | that entry's `type` |
|
|
2220
|
+
| <a id="CONFIG_CONSTRAINT_NAME_UNIQUE"></a>`CONFIG_CONSTRAINT_NAME_UNIQUE` | two `constraints` entries of one kind share a `name`; rigc finds a constraint by its kind and its name, so an ik and a transform may share one | rename one |
|
|
2221
|
+
| <a id="CONFIG_CONSTRAINT_TARGET_DETACHED"></a>`CONFIG_CONSTRAINT_TARGET_DETACHED` | the bone an ik follows (`target`) or a transform reads (`source`) is one of the bones that constraint drives, or sits under one (the detail gives the line of parents) — driving them would move what they follow. This package's refusal: rig-c 2.15.0 gates such a rig green when nothing declares the parentage (measured on the selftest's rig fixture, issue #103) | a bone beside the chain; a scene target is a single bone parented to `root` (§3) |
|
|
2222
|
+
| <a id="CONFIG_TURN_PIVOT_BEHIND_NEAREST"></a>`CONFIG_TURN_PIVOT_BEHIND_NEAREST` | `turn.pivot` is at or in front of the nearest part's depth: the law `(pivot − depth) / (pivot − nearest)` has no value there, and in front of it every part travels against the dial | a pivot above the smallest depth in `turn.depths` |
|
|
2223
|
+
| <a id="CONFIG_TURN_BONE_FREE"></a>`CONFIG_TURN_BONE_FREE` | the config has `turn` and `bones` declares a bone named `turn`, the control the rig stage adds | rename that bone |
|
|
2057
2224
|
|
|
2058
2225
|
### inputs
|
|
2059
2226
|
|
|
2060
2227
|
| rule | means | change |
|
|
2061
2228
|
| --- | --- | --- |
|
|
2062
|
-
|
|
|
2063
|
-
|
|
|
2064
|
-
|
|
|
2229
|
+
| <a id="INPUTS_SOURCE_PRESENT"></a>`INPUTS_SOURCE_PRESENT` | no such painting | `--source` |
|
|
2230
|
+
| <a id="INPUTS_PAINTING_OPAQUE"></a>`INPUTS_PAINTING_OPAQUE` | the painting has a pixel below alpha 255 | the painting |
|
|
2231
|
+
| <a id="INPUTS_HEAD_BOX_INSIDE"></a>`INPUTS_HEAD_BOX_INSIDE` | `seethrough.head_box` leaves the painting (the crop is not padded) | `head_box` — take `propose --head-box`'s |
|
|
2065
2232
|
|
|
2066
2233
|
### The optional ComfyUI adapter (`comfy paint`, `comfy seethrough`)
|
|
2067
2234
|
|
|
2068
2235
|
| rule | means | change |
|
|
2069
2236
|
| --- | --- | --- |
|
|
2070
|
-
|
|
|
2071
|
-
|
|
|
2072
|
-
|
|
|
2073
|
-
|
|
|
2074
|
-
|
|
|
2075
|
-
|
|
|
2076
|
-
|
|
|
2237
|
+
| <a id="COMFY_HOST_GIVEN"></a><a id="COMFY_REACHABLE"></a><a id="COMFY_REQUEST_OK"></a>`COMFY_HOST_GIVEN`, `COMFY_REACHABLE`, `COMFY_REQUEST_OK` | no `--host`/`COMFY_HOST`, nothing answering there, or a non-200 answer | the host, or the box |
|
|
2238
|
+
| <a id="COMFY_NODE_PRESENT"></a><a id="COMFY_INPUT_KNOWN"></a><a id="COMFY_INPUT_SET"></a><a id="COMFY_CHOICE_PRESENT"></a>`COMFY_NODE_PRESENT`, `COMFY_INPUT_KNOWN`, `COMFY_INPUT_SET`, `COMFY_CHOICE_PRESENT` | the box's `/object_info` lacks a node class the graph uses, an input it sets, an input it must set, or a model file it names | install the node or model on the box, or the config value naming it |
|
|
2239
|
+
| <a id="COMFY_QUEUE_EMPTY"></a><a id="COMFY_PROMPT_ACCEPTED"></a><a id="COMFY_HISTORY_WITHIN"></a><a id="COMFY_RUN_OK"></a>`COMFY_QUEUE_EMPTY`, `COMFY_PROMPT_ACCEPTED`, `COMFY_HISTORY_WITHIN`, `COMFY_RUN_OK` | someone else's job kept the queue busy past `--wait`, the box rejected the graph, the job did not finish within `--timeout`, or it ended in error (quoted) | `--wait`/`--timeout`, or what the quoted error names |
|
|
2240
|
+
| <a id="COMFY_HISTORY_OUTPUTS"></a><a id="COMFY_VIEW_PRESENT"></a><a id="COMFY_MANIFEST_NAMED"></a><a id="COMFY_MANIFEST_IS_THIS_RUN"></a><a id="COMFY_LAYER_NAME"></a>`COMFY_HISTORY_OUTPUTS`, `COMFY_VIEW_PRESENT`, `COMFY_MANIFEST_NAMED`, `COMFY_MANIFEST_IS_THIS_RUN`, `COMFY_LAYER_NAME` | the job's outputs are missing, unreadable, belong to another run, or name a layer that is not a plain file name | the wrapper's version on the box; report it |
|
|
2241
|
+
| <a id="COMFY_IMAGE_PRESENT"></a><a id="COMFY_OUT_EMPTY"></a><a id="COMFY_OUT_FREE"></a>`COMFY_IMAGE_PRESENT`, `COMFY_OUT_EMPTY`, `COMFY_OUT_FREE` | no `--image`, an `--out` that already holds files, or a seed whose painting is already on disk | `--image`, `--out`, `--seed0` |
|
|
2242
|
+
| <a id="COMFY_PAINTING_SIZE"></a>`COMFY_PAINTING_SIZE` | the painting `comfy paint` got back is not twice the latent (a config with no `generation` block is `CONFIG_FIELD_PRESENT`, §6 *The config*) | `config.generation` |
|
|
2243
|
+
| <a id="CONFIG_POSE_CANVAS"></a><a id="CONFIG_POSE_KEYPOINTS"></a><a id="CONFIG_POSE_IN_CANVAS"></a>`CONFIG_POSE_CANVAS`, `CONFIG_POSE_KEYPOINTS`, `CONFIG_POSE_IN_CANVAS` | the pose file `generation.control.skeleton` names states another canvas than `generation.latent`, holds other than the 18 body-18 keypoints, or puts one off its canvas | the pose file (§3, the `generation.control.skeleton` row) |
|
|
2077
2244
|
|
|
2078
2245
|
### assemble
|
|
2079
2246
|
|
|
2080
2247
|
| rule | means | change |
|
|
2081
2248
|
| --- | --- | --- |
|
|
2082
|
-
|
|
|
2083
|
-
|
|
|
2084
|
-
|
|
|
2085
|
-
|
|
|
2086
|
-
|
|
|
2087
|
-
|
|
|
2088
|
-
|
|
|
2089
|
-
|
|
|
2090
|
-
|
|
|
2091
|
-
|
|
|
2092
|
-
|
|
|
2093
|
-
|
|
|
2094
|
-
|
|
|
2095
|
-
|
|
|
2096
|
-
|
|
|
2097
|
-
| `
|
|
2249
|
+
| <a id="ASSEMBLE_FIELD_PRESENT"></a>`ASSEMBLE_FIELD_PRESENT` | `seethrough.head_box` is missing | `propose --head-box` proposes it (§3) |
|
|
2250
|
+
| <a id="ASSEMBLE_RIG_SIZE"></a>`ASSEMBLE_RIG_SIZE` | `rig_scale` makes an empty rig | `assemble.rig_scale` |
|
|
2251
|
+
| <a id="ASSEMBLE_HEAD_BOX_INSIDE"></a>`ASSEMBLE_HEAD_BOX_INSIDE` | the head box is outside the painting | `head_box` — `propose --head-box` holds it inside |
|
|
2252
|
+
| <a id="ASSEMBLE_RUN_CANVAS"></a>`ASSEMBLE_RUN_CANVAS` | a run's canvas is not `resolution` square | `seethrough.resolution`, or the run |
|
|
2253
|
+
| <a id="ASSEMBLE_PLAN_TAG_IN_RUN"></a><a id="ASSEMBLE_EXTEND_TAG_IN_RUN"></a>`ASSEMBLE_PLAN_TAG_IN_RUN`, `ASSEMBLE_EXTEND_TAG_IN_RUN` | an entry takes a tag its run does not hold (the detail lists what it does hold) | that entry's run or tag |
|
|
2254
|
+
| <a id="ASSEMBLE_PART_OPAQUE"></a>`ASSEMBLE_PART_OPAQUE` | a part ended with no opaque pixel | drop the entry, or take the tag from the other run |
|
|
2255
|
+
| <a id="ASSEMBLE_PATCH_BOX_INSIDE"></a>`ASSEMBLE_PATCH_BOX_INSIDE` | a patch's box reaches past the rig (the painting times `rig_scale`; the detail gives the size) | that patch's `box` — it is in rig pixels, not painting pixels |
|
|
2256
|
+
| <a id="ASSEMBLE_PATCH_OPAQUE"></a>`ASSEMBLE_PATCH_OPAQUE` | a patch takes no pixel: a `"silhouette"` patch whose box holds none of the figure | move the box onto the figure, or `"alpha": "box"` |
|
|
2257
|
+
| <a id="ASSEMBLE_CUT_INSIDE"></a>`ASSEMBLE_CUT_INSIDE` | a cut's polygon has a point past the rig (the detail gives the points and the size) | that cut's `polygon` — it is in rig pixels, not painting pixels |
|
|
2258
|
+
| <a id="ASSEMBLE_CUT_OVERLAP"></a>`ASSEMBLE_CUT_OVERLAP` | two cuts of one part share a rig pixel (the detail gives the count and the first, `x,y`) | one of the two polygons: a pixel goes to one part |
|
|
2259
|
+
| <a id="ASSEMBLE_CUT_PIXELS"></a>`ASSEMBLE_CUT_PIXELS` | a cut takes none of its part's opaque pixels (alpha above 8), or a part's cuts leave it none | draw the polygon over the art; to move the whole layer, rename the plan part instead |
|
|
2260
|
+
| <a id="ASSEMBLE_UNDER_PRESENT"></a><a id="ASSEMBLE_UNDER_DECODES"></a>`ASSEMBLE_UNDER_PRESENT`, `ASSEMBLE_UNDER_DECODES` | a cut's `under` names no file (relative to the config's directory), or a file that is not a PNG; every cut's is named in one refusal | that cut's `under` |
|
|
2261
|
+
| <a id="ASSEMBLE_UNDER_SIZE"></a>`ASSEMBLE_UNDER_SIZE` | a cut's `under` image is not the size of its polygon's bounding box (the detail gives both, and the box's corner) | the image: `max x − min x` by `max y − min y` of the polygon, in rig pixels |
|
|
2262
|
+
| <a id="ASSEMBLE_UNDER_EMPTY"></a>`ASSEMBLE_UNDER_EMPTY` | a cut's `under` image fills none of the pixels the cut removed: its alpha is below the alpha removed at every one (all transparent there, or another file) | the image or its path; to leave the whole hole, drop `under` |
|
|
2263
|
+
| <a id="ASSEMBLE_UNDER_DRAW"></a>`ASSEMBLE_UNDER_DRAW` | a cut with `under` draws its piece behind its part, which the fill would hide it under | that cut's `draw`: `"front"`, or `{"before": …}` the plan part after its `from` |
|
|
2264
|
+
| <a id="ASSEMBLE_LIMB_TAKES"></a><a id="ASSEMBLE_LIMB_PIXELS"></a>`ASSEMBLE_LIMB_TAKES`, `ASSEMBLE_LIMB_PIXELS` | a part a limb takes has no opaque pixel, or a limb segment gets none of it — the joint lines through the bones' origins put none of the limb's pixels on it, or another limb's polyline is nearer every one (issue #349) | the bones: their origins on the limb's art, each joint where the limb bends |
|
|
2265
|
+
| <a id="ASSEMBLE_LIMB_JOINT"></a><a id="ASSEMBLE_LIMB_JOINT_ON_ART"></a>`ASSEMBLE_LIMB_JOINT`, `ASSEMBLE_LIMB_JOINT_ON_ART` | a joint has no line — the upper bone has no length, or the limb folds straight back on itself — or its bone's origin lies on none of the limb's art within 1 px along the line, so the limb has no width there to size the cap by (issue #349) | the joint's bone: on the limb's art, at the joint |
|
|
2266
|
+
| <a id="ASSEMBLE_LIMB_CAP_PRESENT"></a><a id="ASSEMBLE_LIMB_CAP_DECODES"></a><a id="ASSEMBLE_LIMB_CAP_SIZE"></a><a id="ASSEMBLE_LIMB_CAP_EMPTY"></a>`ASSEMBLE_LIMB_CAP_PRESENT`, `ASSEMBLE_LIMB_CAP_DECODES`, `ASSEMBLE_LIMB_CAP_SIZE`, `ASSEMBLE_LIMB_CAP_EMPTY` | a segment's `cap` names no file (relative to the config's directory) or one that is not a PNG; an image not the size of the cap's box (the detail gives both, and the box's corner); or one transparent over every cap pixel (issue #349) | the image: the box the `limb cap:` line prints, `w`x`h`, its pixel `(i, j)` rig pixel `(x + i, y + j)`; to keep the layer's cap, drop `cap` |
|
|
2267
|
+
| <a id="ASSEMBLE_COUNTS_ADD_UP"></a>`ASSEMBLE_COUNTS_ADD_UP` | a part's visible and occluded counts do not add up to its opaque pixels, or a projected pixel is not visible, or a cut part's pieces do not add up to it — an assembler bug, not an input problem | report it with the part named; nothing was written |
|
|
2098
2268
|
|
|
2099
2269
|
### propose
|
|
2100
2270
|
|
|
2101
2271
|
| rule | means | change |
|
|
2102
2272
|
| --- | --- | --- |
|
|
2103
|
-
|
|
|
2104
|
-
|
|
|
2105
|
-
|
|
|
2106
|
-
|
|
|
2107
|
-
| `
|
|
2108
|
-
|
|
|
2109
|
-
|
|
|
2110
|
-
| `
|
|
2111
|
-
| `
|
|
2112
|
-
|
|
|
2113
|
-
|
|
|
2114
|
-
|
|
|
2273
|
+
| <a id="HEADBOX_FACE_PRESENT"></a><a id="HEADBOX_RUN_SQUARE"></a><a id="HEADBOX_CANVAS_SIZE"></a><a id="HEADBOX_FITS_CANVAS"></a>`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 |
|
|
2274
|
+
| <a id="PROPOSE_SOURCE_PRESENT"></a><a id="PROPOSE_PNG_PRESENT"></a><a id="PROPOSE_PNG_MATCHES_BOX"></a>`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) |
|
|
2275
|
+
| <a id="PROPOSE_FACE_PRESENT"></a>`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 |
|
|
2276
|
+
| <a id="PROPOSE_CUT_FROM_RECORDED"></a>`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` |
|
|
2277
|
+
| <a id="PROPOSE_LIMB_PARTS"></a>`PROPOSE_LIMB_PARTS` | `parts.json` holds parts `config.limbs` cut at their joints (issue #349); the limbs are drafted from the parts before the cut, which the rules read by layer | `--parts` a build assembled with the config's `limbs` left out; keep the block the config holds (its caps and ranges are the author's). `propose --from-config` reads the config's bones on either build |
|
|
2278
|
+
| <a id="PROPOSE_ACCESSORY_BODY"></a>`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 |
|
|
2279
|
+
| <a id="PROPOSE_TURN_RUN_GIVEN"></a><a id="PROPOSE_TURN_LAYER_PRESENT"></a><a id="PROPOSE_TURN_DEPTH_PRESENT"></a>`PROPOSE_TURN_RUN_GIVEN`, `PROPOSE_TURN_LAYER_PRESENT`, `PROPOSE_TURN_DEPTH_PRESENT` | with `--full`/`--head` (issue #251): a part came from a run whose layers were not given, the run given holds no layer of the part's tag, or its layer carries no `depth_median` (a PSD carries none) | give the run the parts were assembled from, as the wrapper's `layers.json` |
|
|
2280
|
+
| <a id="BASIS_RECORDS_EVERY_BONE"></a><a id="BASIS_NAMES_RESOLVE"></a><a id="BASIS_KIND_KNOWN"></a><a id="BASIS_KIND_HOLDS"></a>`BASIS_RECORDS_EVERY_BONE`, `BASIS_NAMES_RESOLVE`, `BASIS_KIND_KNOWN`, `BASIS_KIND_HOLDS` | `propose --keypoints`'s record of how it placed each bone, `basis.json`, does not hold to the proposal it was written with: a proposed bone with no record, one recorded twice or out of the proposal's order; a part, bone or frame quantity it names that is not there; a placement kind outside the known ones; or a placement that does not hold what its kind says (a joint placement with no joint, a non-joint one with a joint, a derived one with no bone, a constant that is not finite). Nothing is written | a proposer bug, not an input problem: report it with the line |
|
|
2281
|
+
| <a id="KEYPOINTS_FILE_PRESENT"></a><a id="KEYPOINTS_IS_JSON"></a><a id="KEYPOINTS_KEY_KNOWN"></a><a id="KEYPOINTS_FIELD_PRESENT"></a><a id="KEYPOINTS_FIELD_TYPE"></a>`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*) |
|
|
2282
|
+
| <a id="KEYPOINTS_SPEC_KNOWN"></a><a id="KEYPOINTS_SPACE_STATED"></a>`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 |
|
|
2283
|
+
| <a id="KEYPOINTS_JOINT_KNOWN"></a><a id="KEYPOINTS_JOINT_STATE"></a><a id="KEYPOINTS_POSITION_STATED"></a><a id="KEYPOINTS_POSITION_INSIDE"></a>`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 |
|
|
2284
|
+
| <a id="KEYPOINTS_PERSON_UNIQUE"></a><a id="KEYPOINTS_PERSON_CHOSEN"></a>`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>` |
|
|
2285
|
+
| <a id="KEYPOINTS_IMAGE_SIZE"></a>`KEYPOINTS_IMAGE_SIZE` | the file's `width`x`height` is not the `--source` painting's | a file measured on this painting |
|
|
2286
|
+
| <a id="PARTS_FILE_PRESENT"></a><a id="PARTS_IS_JSON"></a><a id="PARTS_KEY_KNOWN"></a><a id="PARTS_FIELD_PRESENT"></a><a id="PARTS_FIELD_TYPE"></a><a id="PARTS_NAME_UNIQUE"></a><a id="PARTS_FROM_KNOWN"></a><a id="PARTS_CUT_FROM_KNOWN"></a><a id="PARTS_BOX_INSIDE_RIG"></a><a id="PARTS_COUNTS_ADD_UP"></a><a id="PARTS_HOLES_LARGEST_FIRST"></a><a id="PARTS_HOLE_PART_KNOWN"></a>`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` |
|
|
2287
|
+
|
|
2288
|
+
### compare
|
|
2289
|
+
|
|
2290
|
+
| rule | means | change |
|
|
2291
|
+
| --- | --- | --- |
|
|
2292
|
+
| <a id="STRUCTURE_FILE_PRESENT"></a><a id="STRUCTURE_FILE_IS_JSON"></a><a id="STRUCTURE_FORM"></a>`STRUCTURE_FILE_PRESENT`, `STRUCTURE_FILE_IS_JSON`, `STRUCTURE_FORM` | a `--left` or `--right` path is missing, not JSON, or not one of the three sides `compare` reads: a file that states a `spec` other than rig-c's rig spec, or none of `spec` (a rig.json), `key` (a config) or `bones` (a proposal) | the path |
|
|
2293
|
+
| <a id="STRUCTURE_RIG_SPEC"></a><a id="STRUCTURE_NAME_RESOLVES"></a>`STRUCTURE_RIG_SPEC`, `STRUCTURE_NAME_RESOLVES` | rig-c's rig spec reader refuses a rig.json side (its words quoted), or a rig.json side's weight, constraint or skin names a bone or slot its own bones or slots do not declare | that side's file |
|
|
2294
|
+
| <a id="STRUCTURE_MAP_FIELD"></a><a id="STRUCTURE_MAP_KEY_KNOWN"></a>`STRUCTURE_MAP_FIELD`, `STRUCTURE_MAP_KEY_KNOWN` | the `--map` file is not a JSON object stating `"spec": "spine-parts-bonemap/1"`, a field is of the wrong shape (`pairs` a list of [left name, right name]; `required` a list of left bone names, each once; `frame` `{"scale": <number above 0>, "offset": [x, y]}`, neither assumed; `note` a string), or it holds a key the reader does not read | the map |
|
|
2295
|
+
| <a id="STRUCTURE_MAP_RESOLVES"></a><a id="STRUCTURE_MAP_ONE_TO_ONE"></a>`STRUCTURE_MAP_RESOLVES`, `STRUCTURE_MAP_ONE_TO_ONE` | a pair names a bone its side does not have (the detail says when it is a bone of the other side: a pair is [left, right]), or pairs one bone twice | that pair |
|
|
2296
|
+
| <a id="STRUCTURE_REQUIRED_PRESENT"></a>`STRUCTURE_REQUIRED_PRESENT` | a bone the map's `required` names is absent on either side through the pairing; this is the comparison's own FAIL, printed after its lines, exit 1 | the side that lacks it, or the pairing |
|
|
2115
2297
|
|
|
2116
2298
|
### rig
|
|
2117
2299
|
|
|
2118
2300
|
| rule | means | change |
|
|
2119
2301
|
| --- | --- | --- |
|
|
2120
|
-
|
|
|
2121
|
-
|
|
|
2122
|
-
|
|
|
2123
|
-
|
|
|
2124
|
-
|
|
|
2125
|
-
|
|
|
2126
|
-
| `
|
|
2127
|
-
| `
|
|
2128
|
-
| `
|
|
2129
|
-
| `
|
|
2130
|
-
|
|
|
2131
|
-
|
|
|
2302
|
+
| <a id="RIG_PART_PRESENT"></a><a id="RIG_PART_ATTACHED"></a>`RIG_PART_PRESENT`, `RIG_PART_ATTACHED` | a `meshes`/`regions` key that is not in `parts.json`, a part with neither, or a `painting:` part with a mesh | the config and the plan must name the same parts; a patch is a region |
|
|
2303
|
+
| <a id="RIG_PNG_PRESENT"></a><a id="RIG_PNG_MATCHES_BOX"></a><a id="RIG_PART_HAS_ART"></a>`RIG_PNG_PRESENT`, `RIG_PNG_MATCHES_BOX`, `RIG_PART_HAS_ART` | a part's PNG is missing, the wrong size, or has no art pixel | re-run assemble |
|
|
2304
|
+
| <a id="RIG_NAME_RESOLVES"></a><a id="RIG_SEGMENT_DEFINED"></a><a id="RIG_CHAIN_POINTS"></a>`RIG_NAME_RESOLVES`, `RIG_SEGMENT_DEFINED`, `RIG_CHAIN_POINTS` | a segment names an undeclared bone, a bone with no `tip` and no next link, or a chain too short to make a link | that bone's `tip`, or write the segment out as `[bone, [x0,y0], [x1,y1]]` |
|
|
2305
|
+
| <a id="RIG_INFLUENCES_KEPT"></a>`RIG_INFLUENCES_KEPT` | a mesh's declared `influences` leaves a vertex with no bone: every capped share is under 0.03 (at or under it, for the continuous floor). The largest of k shares is at least 1/k, so this needs 34 or more kept bones; the default cap of 4 never reaches it (issue #284). The detail names the first vertex, how many more, and its largest share | declare `maxInfluences` 33 or less, or name fewer bones in `segments` |
|
|
2306
|
+
| <a id="RIG_LATTICE_ONE_LOOP"></a>`RIG_LATTICE_ONE_LOOP` | the lattice over a part does not close into one outline even after the repair passes | that mesh's `grid` |
|
|
2307
|
+
| <a id="RIG_CONTROL_NAME_FREE"></a>`RIG_CONTROL_NAME_FREE` | a keyed, mesh-weighted bone needs `<bone>_ctl` and that name is taken | rename the declared bone |
|
|
2308
|
+
| <a id="RIG_HEAD_UP_NAME_FREE"></a>`RIG_HEAD_UP_NAME_FREE` | `config.bones` declares `head_up`, the bone the rig stage adds under `head` to carry the face's up axis (issue #250) | rename that bone |
|
|
2309
|
+
| <a id="RIG_TIP_DISTINCT"></a>`RIG_TIP_DISTINCT` | a single bone's `tip` is its own `at`: a bone turns from its origin towards its tip (issue #239), and a tip on the origin has no direction | another `tip`, or leave the tip out |
|
|
2310
|
+
| <a id="RIG_HEAT_BONE_SOURCE"></a>`RIG_HEAT_BONE_SOURCE` | under `meshes.<part>.rule` `"heat"`, a bone the mesh's `segments` bind holds no source pixel: no silhouette pixel centre within 0.75 px of its segment is nearer it than another bound bone's (the segment is quoted in rig px). A bone with no source is not weighted 0 | move its segment onto the art, take the bone out of `segments`, or keep this part on the distance rule (`rule` `"distance"`, or none: the rule is per mesh) |
|
|
2311
|
+
| <a id="RIG_HEAT_ISLAND_SOURCE"></a>`RIG_HEAT_ISLAND_SOURCE` | under rule `"heat"`, a 4-connected island of the part's silhouette holds no bound bone's source pixel, so the heat equation has no answer there; nothing is borrowed from the nearest island. The detail gives the island's size and corner, and, for an island at mesh-draft's dust line, the `stray` that would leave it out | a segment within 0.75 px of the island, the `stray` the detail names, or the distance rule |
|
|
2312
|
+
| <a id="RIG_HEAT_CONVERGED"></a>`RIG_HEAT_CONVERGED` | under rule `"heat"`, a bone's field still changes by more than the tolerance after the most sweeps the solve takes (the figures quoted); nothing half-solved is written | a smaller part, or the distance rule |
|
|
2313
|
+
| <a id="FLATTEN_REGION_UPRIGHT"></a>`FLATTEN_REGION_UPRIGHT` | `flattenRig` (`src/rig.ts`), the reference's unturned form of a built rig — which only the repository's `scripts/rig_oracle.ts` calls, no command — met a region whose `rotation` does not cancel its bone's turn, so its flat form would be drawn turned | a repository tool's input, not an author's: report it with the line |
|
|
2314
|
+
| <a id="RIG_TURN_NAME_FREE"></a>`RIG_TURN_NAME_FREE` | with `turn`: a twin (`turn_<part>_<bone>`), the control `turn` or a transform constraint `turn_<part>` the turn writes is a name the rig already holds | rename the declared bone or constraint |
|
|
2315
|
+
| <a id="RIG_KEY_FRAME_UNTURNED"></a>`RIG_KEY_FRAME_UNTURNED` | a `translate` key on a bone whose parent is a chain link turned along its chain, or a `scale`/`shear` key (a track, or the blink's `eyes`/`brows` group) on a turned link: the key would act along the link's axis, not the picture's; the detail names the track, the bone and the turn | key the chain's own parent, or key `rotate`; a link whose turn is 0 (a level chain) keeps every key |
|
|
2316
|
+
| <a id="RIG_BLINK_INSIDE_IDLE"></a>`RIG_BLINK_INSIDE_IDLE` | the blink runs outside the idle | `motion.blink.t` |
|
|
2317
|
+
| <a id="RIG_BLINK_HOLD_SPANS_A_FRAME"></a>`RIG_BLINK_HOLD_SPANS_A_FRAME` | the tree's `BLINK.hold` is shorter than one frame at `IDLE_FPS`, so for some `motion.blink.t` no idle frame — and no frame of the loop — shows the closed eye; the detail counts the phases that miss and names the first | nothing in the config: `BLINK.hold` in `src/motion.ts`, at least `1/IDLE_FPS` s (§3) |
|
|
2318
|
+
| <a id="RIG_STILL_ROW_INSIDE_PART"></a><a id="RIG_STILL_ROW_CLEAR"></a><a id="RIG_STILL_PIECES_HAVE_ART"></a><a id="RIG_STILL_NAME_FREE"></a>`RIG_STILL_ROW_INSIDE_PART`, `RIG_STILL_ROW_CLEAR`, `RIG_STILL_PIECES_HAVE_ART`, `RIG_STILL_NAME_FREE` | a `motion.blink.still` row that is not strictly inside the part, that crosses art (a cut through art changes the render even at rest), that leaves one piece with no art, or whose `<part>_still` slot name another part already has | that entry's `row` — a row with no art between the crease and the lash line — or rename the other part |
|
|
2319
|
+
| <a id="RIG_RIGC_GREEN"></a>`RIG_RIGC_GREEN` | rig-c refused the rig; its own FAIL or compile-error line is quoted, and nothing was written. A `constraints` field rigc does not read, or a value it refuses, is this line in rigc's words (`constraint "aim" (ik) has a key this compiler does not read: "mixx" (did you mean "mix"?)`), as is `A25_DETACHED_BONE_PARENTAGE` on a declared scene target. So is an ik whose `bones` are more than two, or two of which the second is not the first's child: from rig-c 2.15.0 its rig-spec parser refuses both by name (`ik constraint "reach" names 3 bones …`, `ik constraint "reach": "hem1" is not a child of "body" ("hem0" stands between) …`; firejune/rigc#1205), and this package no longer refuses them itself (issue #103; it did from #92 while rigc's gate passed them). Under `--idle-keys ctl` a two-bone ik over a chain link and its child link is that second refusal too, because the child's `<link>_ctl` stands between them; rigc's remedy names the control, which a config cannot, so when rigc's line says that control alone stands between, the rig stage adds a sentence naming `--idle-keys direct` on the command that ran | the field rigc's line names; for the split pair, `rig --idle-keys direct` or `build --idle-keys direct`, as the line says, which keys the link in place — rig-c's own AUTHORING §5 maps each of its assertions (`node_modules/rig-c/docs/AUTHORING.md`) |
|
|
2132
2320
|
|
|
2133
2321
|
### mesh-draft
|
|
2134
2322
|
|
|
2135
2323
|
| rule | means | change |
|
|
2136
2324
|
| --- | --- | --- |
|
|
2137
|
-
|
|
|
2138
|
-
|
|
|
2139
|
-
|
|
|
2140
|
-
|
|
|
2141
|
-
|
|
|
2325
|
+
| <a id="MESH_DRAFT_FIGURE"></a>`MESH_DRAFT_FIGURE` | parts.json holds no part, or the figure is so short that `round(H / 37)` is 0: nothing raises the spacing | nothing to draft on this figure; author a `contour` entry by hand |
|
|
2326
|
+
| <a id="MESH_DRAFT_LATTICE_GREEN"></a>`MESH_DRAFT_LATTICE_GREEN` | the config as written does not build or does not check PASS; each of its problems is quoted. The gate holds every candidate to the lattice it would replace, so that lattice must be green first | make `build` green, then run `mesh-draft` |
|
|
2327
|
+
| <a id="MESH_DRAFT_BEND_NAMES"></a>`MESH_DRAFT_BEND_NAMES` | `motion.json` (with `animations_from`) already holds an animation named `mesh-draft <part> +15` or `-15`, the names the bend set is walked as | rename that animation |
|
|
2328
|
+
| <a id="MESH_DRAFT_COMPARE_BUILD"></a>`MESH_DRAFT_COMPARE_BUILD` | rigc's gate refused one of the three comparison builds (the drafted rig with every candidate as its lattice, its candidate or its dense reference); rigc's lines are quoted | read rigc's line; nothing was written |
|
|
2329
|
+
| <a id="MESH_DRAFT_COMPARE"></a>`MESH_DRAFT_COMPARE` | rig-c's `compareMeshesInMotion` refused the comparison's input, with rig-c's code | read rig-c's code; nothing was written |
|
|
2142
2330
|
|
|
2143
2331
|
A part that fails a reading is not a refusal: it keeps its lattice, the command
|
|
2144
2332
|
exits 0, and `mesh_draft.json` and the console name the reading and the amount.
|
|
2145
2333
|
|
|
2334
|
+
### rig-c's mesh refusals, quoted in a line
|
|
2335
|
+
|
|
2336
|
+
rig-c's mesh library refuses a malformed input by throwing with a code of its own. This
|
|
2337
|
+
package does not print those as lines of their own: it quotes the code inside its own
|
|
2338
|
+
line — `AUTO_MESH_INPUT` and `AUTO_MESH_MOTION_INPUT` (§3, *An automatic mesh*),
|
|
2339
|
+
`MESH_DRAFT_COMPARE`, and the `residual not measurable: <bone> <CODE>` clause of an
|
|
2340
|
+
automatic mesh's row — and the row is here, not in rig-c's guide (rig-c's mesh
|
|
2341
|
+
documents do not ship). Each is an input this package built; none is an author's field.
|
|
2342
|
+
|
|
2343
|
+
| rule | means | change |
|
|
2344
|
+
| --- | --- | --- |
|
|
2345
|
+
| <a id="REDUCE_INPUT_MISSING"></a>`REDUCE_INPUT_MISSING` | a field of the input this package handed rig-c's `reduceMesh`, `measureMeshQuality` or `skinningEnvelopeBone` is missing or not of its shape (rig-c gives no field a default); the field and what it requires are quoted | an input this package built, not an author's: report it with the line |
|
|
2346
|
+
| <a id="REDUCE_INPUT_LINE"></a>`REDUCE_INPUT_LINE` | the input names a line source without the lines it indexes, or a line source that is not `{ id, mesh }` | an input this package built, not an author's: report it with the line |
|
|
2347
|
+
| <a id="REDUCE_MASK_SIZE"></a>`REDUCE_MASK_SIZE` | the art mask handed with a part is not a whole, non-empty size, or holds a byte count other than width × height | an input this package built, not an author's: report it with the line |
|
|
2348
|
+
| <a id="REDUCE_ART_RASTERS_MISMATCH"></a>`REDUCE_ART_RASTERS_MISMATCH` | the art rasters passed beside an input were taken for another input (another mask size, threshold or frame), or the step rasters were made over another rasters object | an input this package built, not an author's: report it with the line |
|
|
2349
|
+
| <a id="REDUCE_UV_RANGE"></a>`REDUCE_UV_RANGE` | a source vertex's UV is outside 0..1 beyond rig-c's slack (its A22) | an input this package built, not an author's: report it with the line |
|
|
2350
|
+
| <a id="REDUCE_THRESHOLD_RANGE"></a>`REDUCE_THRESHOLD_RANGE` | the art threshold is not a whole number in 1..255 | an input this package built, not an author's: report it with the line |
|
|
2351
|
+
| <a id="COMPARE_INPUT_MISSING"></a>`COMPARE_INPUT_MISSING` | a field of the input this package handed rig-c's `compareMeshesInMotion` is missing or malformed, two builds share an id, or one attachment is listed twice | an input this package built, not an author's: report it with the line |
|
|
2352
|
+
| <a id="COMPARE_INPUTS_DIFFER"></a>`COMPARE_INPUTS_DIFFER` | a candidate build differs from the reference outside what the comparison may vary (the compared mesh's vertices, UVs, triangles, hull, edges and weights); the path and both values are quoted | an input this package built, not an author's: report it with the line |
|
|
2353
|
+
| <a id="COMPARE_REFERENCE_FAILS"></a>`COMPARE_REFERENCE_FAILS` | the reference — the unreduced source — fails its own art fit at the setup pose (coverage, overshoot or undercut against `sourceBounds`); a deviation from a reference that does not carry its own art is not evidence | the source, which is the author's: `meshes.<part>.auto.sourceBounds`, or the source's `spacing` or outline (`auto.source`) |
|
|
2354
|
+
| <a id="COMPARE_UV_CARRIER_NOT_UNIQUE"></a>`COMPARE_UV_CARRIER_NOT_UNIQUE` | a sample lies in two UV triangles that do not meet there at a shared vertex or edge: the mesh's UVs overlap or fold, so no one triangle carries it | an input this package built, not an author's: report it with the line |
|
|
2355
|
+
| <a id="COMPARE_WARMUP_UNSUPPORTED"></a>`COMPARE_WARMUP_UNSUPPORTED` | a physics warm-up other than 0 was asked of the comparison; physics resets at time 0 and steps from there | an input this package built, not an author's: report it with the line |
|
|
2356
|
+
| <a id="SKINNING_RANGE_UNSUPPORTED"></a>`SKINNING_RANGE_UNSUPPORTED` | `skinningEnvelopeBone` was handed a bone range not declared by the bone's own keys (a physics swing, a range read off a posed schedule), or a bone whose setup scale is not uniform; the bound is not proven, so it is refused | nothing to change for the build: inside the residual clause it means the residual veto was not applied to that bone, and the motion comparison decides |
|
|
2357
|
+
|
|
2146
2358
|
### check and build
|
|
2147
2359
|
|
|
2148
2360
|
| rule | means | change |
|
|
2149
2361
|
| --- | --- | --- |
|
|
2150
|
-
|
|
|
2151
|
-
|
|
|
2152
|
-
|
|
|
2153
|
-
|
|
|
2154
|
-
|
|
|
2155
|
-
|
|
|
2156
|
-
|
|
|
2157
|
-
|
|
|
2158
|
-
|
|
|
2159
|
-
|
|
|
2160
|
-
|
|
|
2161
|
-
|
|
|
2162
|
-
|
|
|
2163
|
-
|
|
|
2164
|
-
|
|
|
2165
|
-
|
|
|
2166
|
-
|
|
|
2167
|
-
|
|
|
2168
|
-
|
|
|
2169
|
-
| `
|
|
2170
|
-
|
|
|
2171
|
-
| `
|
|
2172
|
-
| `
|
|
2173
|
-
|
|
|
2174
|
-
| `
|
|
2175
|
-
| `
|
|
2176
|
-
| `
|
|
2177
|
-
| `
|
|
2178
|
-
| `
|
|
2179
|
-
|
|
|
2180
|
-
| `
|
|
2181
|
-
| `
|
|
2182
|
-
| `
|
|
2183
|
-
| `
|
|
2184
|
-
| `
|
|
2185
|
-
| `
|
|
2186
|
-
|
|
|
2187
|
-
|
|
|
2188
|
-
|
|
|
2189
|
-
| `
|
|
2362
|
+
| <a id="CHECK_RIGC_PRESENT"></a>`CHECK_RIGC_PRESENT` | no `rigc` binary found (every place looked is listed) | `bun install` |
|
|
2363
|
+
| <a id="CHECK_RIGC_PACKAGE"></a>`CHECK_RIGC_PACKAGE` | `node_modules/.bin/rigc` is missing under the package root named: this lookup (the selftest's, issue #337) takes this package's own rigc and no other — no directory above, no `PATH` | `bun install` in that root |
|
|
2364
|
+
| <a id="CHECK_INPUT_PRESENT"></a><a id="CHECK_INPUT_IS_JSON"></a><a id="CHECK_PART_PNG_PRESENT"></a><a id="CHECK_PART_PNG_MATCHES_BOX"></a><a id="CHECK_PART_SLOT_PRESENT"></a><a id="CHECK_RIG_STAGE_PRESENT"></a><a id="CHECK_RIG_STAGE_IS_THE_CANVAS"></a><a id="CHECK_RIG_ROOT_BONE"></a><a id="CHECK_IDLE_PRESENT"></a>`CHECK_INPUT_PRESENT`, `CHECK_INPUT_IS_JSON`, `CHECK_PART_PNG_PRESENT`, `CHECK_PART_PNG_MATCHES_BOX`, `CHECK_PART_SLOT_PRESENT`, `CHECK_RIG_STAGE_PRESENT`, `CHECK_RIG_STAGE_IS_THE_CANVAS`, `CHECK_RIG_ROOT_BONE`, `CHECK_IDLE_PRESENT` | the rig directory is incomplete or disagrees with `parts.json` (`CHECK_PART_SLOT_PRESENT`: a part with no slot of its own name, which the judgement lines render it by). `motion.json` is required even with no animation in it, because `rigc build` takes `--motion` (a spec with `"animations": {}` builds green); `CHECK_IDLE_PRESENT` is an `idle` that is there with no positive `duration` — an absent `idle` is measured around (§7). `CHECK_INPUT_PRESENT` on `…/parts.json`: `--parts` named a directory without `parts.json` — most often `parts/` itself — or, without `--parts`, the rig directory has none while the directory above it does (build's layout, `<out>/rig` under `<out>/parts.json`). The detail says it: "--parts names the directory holding parts.json and parts/, not parts/ itself (after build, that is build's --out, whose rig is <out>/rig); without --parts it is --rig", and names the parent when the parent holds `parts.json`. With neither (no `--parts`, and no `parts.json` beside `rig.json` or above it), the rig is measured without parts and nothing is refused (§7) | re-run rig (`build` does both); for `…/parts.json`, `--parts` — the directory above `parts/` |
|
|
2365
|
+
| <a id="CHECK_SOURCE_SIZE"></a>`CHECK_SOURCE_SIZE` | the painting `--source` names is not this rig's: no single `rig_scale` takes its width and height to the stage's (assemble makes the canvas `trunc(w × rig_scale)` x `trunc(h × rig_scale)`), or, with `parts.json` read, its `scale_rig_per_source` does not; or the stage is not whole pixels. Refused before anything is built | the painting the rig was made from — the stage's own size, or the painting `assemble` was given |
|
|
2366
|
+
| <a id="CHECK_SOURCE_PNG"></a>`CHECK_SOURCE_PNG` | `--source` names a file that does not read as a PNG | a PNG |
|
|
2367
|
+
| <a id="CHECK_SOURCE_GRID"></a>`CHECK_SOURCE_GRID` | the setup-pose still and its black-tinted twin (the coverage `SETUP_POSE_VS_SOURCE` reads) did not come back on one grid over one opaque background | a rigc problem; report it |
|
|
2368
|
+
| <a id="CHECK_RIGC_VERSION"></a>`CHECK_RIGC_VERSION` | `rigc --version` is below 1.4.0, or prints no version: its `render` has no `--geometry`, which `TEXTURE_STRETCH` reads. Refused before anything is built | `bun install` (this package depends on rig-c ^2.20.4), or put a newer `rigc` first on `PATH` |
|
|
2369
|
+
| <a id="CHECK_RIGC_ENTRY"></a><a id="CHECK_RIGC_ENTRY_READS"></a>`CHECK_RIGC_ENTRY`, `CHECK_RIGC_ENTRY_READS` | `rigc --version` names no entry (a rigc below 2.0.0), or names one in neither launcher form (`entry: cli.ts — @esotericsoftware/spine-core <v> present`, `entry: cli_core.ts — @esotericsoftware/spine-core absent — …`); `check.json`'s `rigc_entry` records the one that gated the build | `bun install` |
|
|
2370
|
+
| <a id="CHECK_RIGC_GREEN"></a>`CHECK_RIGC_GREEN` | a rigc step failed; its line is quoted | as `RIG_RIGC_GREEN` |
|
|
2371
|
+
| <a id="CHECK_LOOP_LAST_FRAME_AT_DURATION"></a>`CHECK_LOOP_LAST_FRAME_AT_DURATION` | the idle's last frame does not sit at `duration` | `motion.duration` — a whole number of 1/12 s |
|
|
2372
|
+
| <a id="CHECK_LOOP_CLOSES"></a>`CHECK_LOOP_CLOSES` | frame 0 and the frame at `duration` differ (max and first pixel quoted); with a physics constraint, the frames of the rig with every physics constraint left out, and the object says so (§7, *loop*) | a track whose last key is not its first |
|
|
2373
|
+
| <a id="CHECK_SEAM_WITHIN_BAR"></a>`CHECK_SEAM_WITHIN_BAR` | the setup pose does not reproduce the flat stack of parts | read the `seam pair` lines and `check/seam/` pictures (§7; magenta = a counted pixel, cyan = the box round them): the pair, its boxes and the pixels counted. Usually a region or mesh placed off its part; compare with `recomposite_rig.png`. A pair of one layer cut in two with `differing_copies_px` is the cut line: move the polygon's edge, not `overlap` |
|
|
2374
|
+
| <a id="CHECK_BREATH_VISIBLE"></a>`CHECK_BREATH_VISIBLE` | the torso (`topwear`), rendered alone, barely moves over the idle — or the feet (`footwear`), rendered alone, move at all | the chest's breath tracks (`motion.tracks` on `chest`), or the torso mesh's `segments`; for the feet, the bone their region rides (`regions.<part>`, `root` in both examples) |
|
|
2375
|
+
| <a id="CHECK_BLINK_NO_HOLE"></a>`CHECK_BLINK_NO_HOLE` | with the blink held shut, the eyewhite box shows the page where the open eye had art | the layer under the eye: the `face` part has no art there. Take the face from the other run, or add a part under the eye; `motion.blink.squash` only hides the hole less |
|
|
2376
|
+
| <a id="CHECK_CHAIN_LAG"></a>`CHECK_CHAIN_LAG` | a rotate track leads (or does not lag) the keyed bone above it, or a chain link swings less than the link above — or, in a chain that carries a part the scene file declares `rests`, more than the link above (issue #245; the object names the part and the file) | that chain track's `phase`/`lag` (a positive `lag`, a child `phase` above its parent's) or its `amps` (non-decreasing toward the tip; non-increasing on a chain declared resting) |
|
|
2377
|
+
| <a id="CHECK_TIP_OVER_ROOT"></a>`CHECK_TIP_OVER_ROOT` | a `handwear`/`bottomwear` part's art in the lower half of its box travels less than 1.4725 times as far as in the upper half, measured from the idle's posed geometry (rig px quoted) | the chain track's `amps` (grow toward the tip), or the mesh's `segments` (the chain must be among them), or its mode: on `scarf`'s short skirt the proposal's lattice read 1.207 and the same part in `contour` mode 1.738 with the same segments and idle (issue #118) — both carried the `chest` segment #262 removed, after which the lattice reads 3.487. When the detail says `the root travels with the breath (x px of y px): it is carried by \`<bone>\`` (issue #262) the chain is not the cause: a bone an idle `translate` track moves (the breath) moves the root more than the tip, and with that translate held still (the part posed again without it, in proportion to each vertex's weight on the bone and those under it) the ratio passes — the row adds `carried_by`, `breath_rig_px`, `root_without_breath_rig_px` and `tip_without_breath_rig_px`; take that bone's segment off the mesh, or bind the root to the bone the part hangs from. A part the scene file declares `rests` (issue #245) is held the other way, its tip half's travel at most its root half's (ratio ≤ 1); the detail then reads `the scene file's rests declares its tip at rest, so a ratio <= 1 is required`, and for it the fix is the chain's `amps` (shrinking toward the tip) or the mesh's tip weighted to a bone the idle does not swing |
|
|
2378
|
+
| <a id="CHECK_STILL_REGIONS_DARK"></a>`CHECK_STILL_REGIONS_DARK` | a slot of the face's still set (the `face` slots and every slot drawn over the face that the head bone alone carries) moves relative to the bone the face's slot rides, or a `footwear` slot moves on the screen, by more than the arithmetic's own rounding — measured from the idle's posed geometry (the slot, its largest displacement in rig px, the idle frame and the tolerance quoted) | on the face: a face mesh with a weight on a bone other than the head (`segments`), or one deformed by another bone; on the feet: a mesh weighted to a swinging bone, or a region on the wrong bone. A bang swinging over the face is not this line's failure: its depth is reported (`crossing`), with no bar |
|
|
2379
|
+
| <a id="CHECK_TEXTURE_STRETCH"></a>`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, and — issue #314 — the bones the edge's two vertices hang on: each vertex's two largest weights from `rig.json`, `vertex <i> is weighted to "<bone>" <w>, …`, then `on the idle's chains, the chain from "<first link>" carries "<bone>", …` — each chain `CHAIN_LAG` reads named once, by its first link — with a bone on no chain said, or `none of these bones hangs on a chain of the idle`); 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. Two chains named, with opposed amplitudes: give both one sign, or drop one — `propose --from-config` measures the pair before a build (§3, *Two chains on one lattice*). An edge whose two ends disagree on whether a bone's small share survives the 0.03 cut (one vertex keeps the bone at a few hundredths, the next drops it — read the two vertices' weights the line quotes): declare `influences: {floor: "continuous"}` on that mesh first, `rule: "heat"` second; the weight `exponent` moves the figure without removing the cut (issue #115, `reference-demo` `hair_back` as contour at tolerance 1, rig-c 2.47.1: 2.535 as drafted; continuous floor 1.422, heat 1.816, both PASS; exponent 1.5 / 3 / 4 / 6 read 2.564 / 1.902 / 2.119 / 4.816, the one pass on the same cut at another edge) |
|
|
2380
|
+
| <a id="CHECK_ANIMATIONS_DO_NOT_FOLD"></a>`CHECK_ANIMATIONS_DO_NOT_FOLD` | an animation, the idle included, turns a mesh triangle over against the setup pose on some frame, read by `rigc render --folds` over the build with its physics constraints left out (issues #320, #333); the object names the animation and the mesh, the detail quotes rigc's line — the frames, the worst frame, which triangles, their world box and setup-pose area. Or a `may_fold` entry of the `--requirements` file names a slot and animation that does not fold: an exception that excepts nothing | the clip's keys on the bones that mesh is weighted to (a bend past what the weights carry, a translate that carries one row of vertices past the next), or the mesh's `segments`; to look, `rigc inspect --candidate <out>/check/build --show art,folds,mesh --animation <name> --at <the worst frame's time> --zoom folds`. A fold the art means (a sleeve behind the body) is declared, `"may_fold": [{ "slot": …, "animation": …, "why": … }]` (§7, *Declared requirements*); a stale entry is taken out |
|
|
2381
|
+
| <a id="CHECK_FEET_STAY_LEVEL"></a>`CHECK_FEET_STAY_LEVEL` | a `footwear` part riding a bone that hangs from another turns more than ±10 degrees from its setup pose on a frame where a bone above that bone is turned (issue #348) — the bar is HQ's line (rig-c/parts#347 ruling 4), not a figure measured here; the object names the part, its bone and the bone it hangs from, the detail the animation, frame and time, the turned bone and its turn, the drawing's turn, and every bone the turn came through with its `inherit` | config.bones' `inherit` on the foot's bone (§3, `bones`): a mode that does not take the parent's rotation (`noRotationOrReflection`, `onlyTranslation`) keeps the drawing at its setup angle; which mode is the author's. Or the clip's keys on the foot's own bone, which turn the shoe whatever its mode |
|
|
2382
|
+
| <a id="CHECK_STRESS_OFF_CHAIN"></a>`CHECK_STRESS_OFF_CHAIN` | a mesh from a See-through `handwear` layer that rides one chain of the idle does not turn rigidly with it: with the chain's first link turned 90°, −90° or 180° on a throwaway copy (physics left out, posed by rigc, issue #347), its worst edge reads above 1.0000 as max(ratio, 1/ratio) against the setup pose. The object names the mesh, the link and the turn; the detail quotes the edge and names each bone the mesh is weighted to off the chain, with how many vertices carry it and the largest weight. Or the turned render shows no mesh on the slot: not read is not a pass | the mesh's `segments`: drop the segment on the bone the line names (a 16 px `chest` stub at the shoulder, as `propose` drafted until issue #347), so the sleeve rides its chain alone. Measured (rigc 2.47.1): `demo`'s sleeves read 2.46 to 254.7 with the stub and 1.0000 without it, and the setup-pose seam does not move (mean 0.147, 0 px over 40, both ways) |
|
|
2383
|
+
| <a id="CHECK_LIMB_ONE_BONE"></a>`CHECK_LIMB_ONE_BONE` | a part a `config.limbs` segment made is bound in `rig.json` to a bone besides its segment's — a mesh weighted to a second bone, or a slot on another bone — or to none (issue #349); the object names the part, its limb and its bone, the detail every other bone | `regions.<part>` the segment's bone, or a mesh whose `segments` name that bone alone: a bend is a rotation at the joint |
|
|
2384
|
+
| <a id="CHECK_FOLDS_READ"></a>`CHECK_FOLDS_READ` | the fold render's `frames.json` names no set for an animation, a `folds.json` is missing, not `rigc-folds/1`, another animation's or another rate's, or a folding mesh has no line rigc printed for it | a rigc problem; report it, with `rigc --version` |
|
|
2385
|
+
| <a id="CHECK_SEAM_FRAME_SIZE"></a><a id="FRAMES_SIDECAR"></a><a id="CHECK_GEOMETRY_FILE"></a>`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 |
|
|
2386
|
+
| <a id="LOOP_ENCODE"></a>`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 |
|
|
2387
|
+
| <a id="LOOP_LEAD_IN_IDLE"></a>`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 |
|
|
2388
|
+
| <a id="CHECK_PACK_LINE_READS"></a>`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` |
|
|
2389
|
+
| <a id="CHECK_PACK_PAGE_EDGES"></a>`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` |
|
|
2390
|
+
| <a id="CHECK_PACK_SHAPE"></a>`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` |
|
|
2391
|
+
| <a id="BUILD_ARTIFACT_PRESENT"></a>`BUILD_ARTIFACT_PRESENT` | the packed build lacks its `.json`, `.atlas` or page | a rigc problem; report it |
|
|
2392
|
+
| <a id="REQUIREMENTS_FILE"></a>`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 |
|
|
2393
|
+
| <a id="REQUIREMENTS_FIELD"></a>`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`, `rises` and `rests` when given (each a non-empty list of part names, each once; no part both in `not_swinging` and in `rises` or `rests`), and `may_fold` when given (a non-empty list of `{ "slot", "animation", "why" }`, every one a non-blank string, each pair once; issue #320). `note`, `*_note` (strings) and `x-…` (any value) are read by nothing, as in the config | write the field; the bar is yours |
|
|
2394
|
+
| <a id="REQUIREMENTS_RESOLVES"></a>`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`, `rises` or `rests` 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 |
|
|
2395
|
+
| <a id="REQUIREMENTS_CONSTRAINT_DRIVES"></a>`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 |
|
|
2396
|
+
| <a id="REQUIREMENTS_TARGET_PARENT"></a>`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 |
|
|
2397
|
+
| <a id="REQUIREMENTS_TARGET"></a>`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 |
|
|
2398
|
+
| <a id="CHECK_REQUIREMENTS_FRAMES"></a>`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 |
|
|
2399
|
+
| <a id="CHECK_REQUIREMENT_MET"></a>`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 |
|
|
2400
|
+
| <a id="CHECK_REQUIREMENT_MEASURABLE"></a>`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 |
|
|
2401
|
+
| <a id="REQUIREMENTS_MAY_FOLD"></a>`REQUIREMENTS_MAY_FOLD` | a `may_fold` entry names a slot with no mesh attachment — a region is one quad and cannot fold (issue #320). Refused before anything is built. Before issue #333 an entry naming the idle was refused here too; the bar reads the idle now, and `idle` is an animation name like any other | a mesh slot |
|
|
2402
|
+
| <a id="REQUIREMENTS_NOT_PLANTED"></a>`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 |
|
|
2403
|
+
| <a id="REQUIREMENTS_TIP_EXCEPTION"></a>`REQUIREMENTS_TIP_EXCEPTION` | a `not_swinging`, `rises` or `rests` 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 **last link**, at the setup pose, runs other than up — from its origin along its `length` (the extent the rig stage turns a link to), or, a last link with no length, from the link before's origin to its own — the detail giving the link read and the direction measured (refused after the idle is rendered, before `check.json` is written) (issues #231, #322; until #322 it read the chain's first link's origin to its last's, which refused a folded arm — a link that hangs, then a forearm raised) | a swinging part's name; for `rises`, a part whose chain does rise |
|
|
2404
|
+
| <a id="REQUIREMENTS_SEAM"></a>`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` |
|
|
2190
2405
|
|
|
2191
2406
|
### compose
|
|
2192
2407
|
|
|
@@ -2196,26 +2411,36 @@ and stay absent).
|
|
|
2196
2411
|
|
|
2197
2412
|
| rule | means | change |
|
|
2198
2413
|
| --- | --- | --- |
|
|
2199
|
-
|
|
|
2200
|
-
|
|
|
2201
|
-
|
|
|
2202
|
-
|
|
|
2203
|
-
|
|
|
2204
|
-
|
|
|
2205
|
-
|
|
|
2206
|
-
|
|
|
2207
|
-
|
|
|
2208
|
-
|
|
|
2209
|
-
|
|
|
2210
|
-
|
|
|
2211
|
-
|
|
|
2212
|
-
|
|
|
2213
|
-
|
|
|
2214
|
-
|
|
|
2215
|
-
|
|
|
2216
|
-
|
|
|
2414
|
+
| <a id="SCENE_FILE"></a><a id="SCENE_SPEC"></a><a id="SCENE_FIELD_PRESENT"></a><a id="SCENE_FIELD_TYPE"></a><a id="SCENE_KEY_KNOWN"></a>`SCENE_FILE`, `SCENE_SPEC`, `SCENE_FIELD_PRESENT`, `SCENE_FIELD_TYPE`, `SCENE_KEY_KNOWN` | the scene file is missing, not a JSON object, not `spine-parts-scene/1`, or a field is missing, of the wrong type or not one the format reads (`canvas` two positive integers; `characters` at least one, each `id`, `build`, `offset` — an offset is never assumed (0, 0) — and an optional `scale`, a positive finite number: 0, a negative number or a non-number is refused at `characters[i].scale`; `order` a list of strings). `note`, `*_note` (strings) and `x-…` (any value) are read by nothing | the field |
|
|
2415
|
+
| <a id="SCENE_ID_UNIQUE"></a><a id="SCENE_ID_FORM"></a>`SCENE_ID_UNIQUE`, `SCENE_ID_FORM` | an `id` repeated, empty, or holding `:` — the separator of a prefixed name — or `/`, `\` or a leading `.`, because an id begins every image file of its character | another id |
|
|
2416
|
+
| <a id="SCENE_PLATE_PROVENANCE"></a><a id="SCENE_PLATE_PRESENT"></a><a id="SCENE_PLATE_SIZE"></a>`SCENE_PLATE_PROVENANCE`, `SCENE_PLATE_PRESENT`, `SCENE_PLATE_SIZE` | the plate's `provenance` is not `observed`, `generated` or `unknown`; its image is missing or not a PNG; it is not the canvas's size (it is drawn at canvas (0, 0) and never scaled) | the plate |
|
|
2417
|
+
| <a id="SCENE_BUILD_PRESENT"></a>`SCENE_BUILD_PRESENT` | a build directory, or a file `build` writes in it (`parts.json`, `rig/rig.json`, `rig/motion.json` with an `idle`, an image its skin names, `check/check.json`), is missing | run `build` for that character |
|
|
2418
|
+
| <a id="SCENE_BUILD_GREEN"></a>`SCENE_BUILD_GREEN` | the build's own `check/check.json` does not say `PASS` and `gate_spine_html_green`; under an accept list (`--accept`, `characters[].accept`), it failed a bar the list does not name, its gate is red, a declared requirement is not PASS, or it names no failing bar — the bars not met and the ones accepted are listed | finish that character first: compose binds finished characters. To look at the scene meanwhile, name the failing bars (§7, *Composing several characters*) |
|
|
2419
|
+
| <a id="SCENE_ACCEPT_KNOWN"></a>`SCENE_ACCEPT_KNOWN` | an `--accept` name, or one in a character's `accept`, is not a bar `check` holds a build to: a problem code (`CHECK_LOOP_CLOSES`) where the bar's name (`loop`) belongs, a misspelling, or `gate`, which is rig-c's and never accepted | one of the names the message lists |
|
|
2420
|
+
| <a id="SCENE_BUILD_FIELD_KNOWN"></a>`SCENE_BUILD_FIELD_KNOWN` | a build's `rig.json` or `motion.json` carries a key compose does not know how to prefix or place, or a root with a transform of its own | a rig `build` wrote; a rig written by something else is `check`'s to measure (§7, *Measuring a rig rig-parts did not assemble*), not compose's to merge |
|
|
2421
|
+
| <a id="SCENE_RIG_SCALE_AGREES"></a>`SCENE_RIG_SCALE_AGREES` | the characters' `parts.json` `scale_rig_per_source` differ (each named) | one `assemble.rig_scale` for every character; `characters[].scale` sizes a placed character, it does not make two `rig_scale`s one |
|
|
2422
|
+
| <a id="SCENE_SCALE_EXACT"></a>`SCENE_SCALE_EXACT` | a character at a `scale` other than 1 carries something no per-character value can scale: a physics constraint with a nonzero `wind` or `gravity` (Spine applies both through the skeleton's `referenceScale`, which the composed skeleton holds once for every character), a track whose `property` compose does not know to be a length or not, or a translate key whose `v` is neither a list of numbers nor a map of them | `scale` 1 for that character, or rebuild it at another `assemble.rig_scale` |
|
|
2423
|
+
| <a id="SCENE_DURATION_AGREES"></a>`SCENE_DURATION_AGREES` | the characters' idles are of different durations (each named) | one `motion.duration` |
|
|
2424
|
+
| <a id="SCENE_CHARACTER_INSIDE_CANVAS"></a>`SCENE_CHARACTER_INSIDE_CANVAS` | a character's part boxes, placed at its offset, leave the canvas (the boxes and the canvas px quoted) | the offset, or the canvas |
|
|
2425
|
+
| <a id="SCENE_ORDER_RESOLVES"></a>`SCENE_ORDER_RESOLVES` | an order entry names no character, or `<id>:<slot>` names a slot that character does not have (its slots listed) | the entry |
|
|
2426
|
+
| <a id="SCENE_ORDER_ONCE"></a><a id="SCENE_ORDER_COMPLETE"></a>`SCENE_ORDER_ONCE`, `SCENE_ORDER_COMPLETE` | a slot is drawn twice (a slot entry repeated, or an id listed twice), or never (the character's id is absent and some of its slots are named nowhere — they are listed) | name each slot once, or the id for the slots not named elsewhere |
|
|
2427
|
+
| <a id="SCENE_NAME_PREFIXED"></a><a id="SCENE_NAME_RESOLVES"></a>`SCENE_NAME_PREFIXED`, `SCENE_NAME_RESOLVES` | a build's constraint or `invariants.detached` names a bone its own character does not declare — one another character does (`…_PREFIXED`, naming the prefixed names it could have meant) or none does (`…_RESOLVES`); or a `--requirements` name (bone, target bone, constraint, slot, attachment, seam part) is a bare name some character holds, which the composed rig holds only prefixed | a bone of the same character; in a requirements file, `<id>:<name>` |
|
|
2428
|
+
| <a id="SCENE_ROOT_SHARED"></a>`SCENE_ROOT_SHARED` | a character's idle keys `root` (a track, or a group holding it), or one of its constraints names `root`: the root is every character's, so either would move or reach them all | key or constrain a bone of the character's own |
|
|
2429
|
+
| <a id="SCENE_INVARIANT_AGREES"></a>`SCENE_INVARIANT_AGREES` | two characters declare `invariants.idleDrivesMeshes` with different `why`s | rebuild with this package's `--idle-keys direct`, whose `why` is one sentence |
|
|
2430
|
+
| <a id="SCENE_IMAGE_NAME_FREE"></a>`SCENE_IMAGE_NAME_FREE` | two images compose to one file name (`<id>.<file>`: an id `x` with an image `y.cloth.png`, and an id `x.y` with `cloth.png`) | another id |
|
|
2431
|
+
| <a id="COMPOSE_RIGC_GREEN"></a>`COMPOSE_RIGC_GREEN` | rig-c refused the composed rig; its line is quoted. A field compose carries as written (a constraint's `mix`, a slot's setup attachment) is rigc's to judge | the build whose field it names |
|
|
2217
2432
|
| `REQUIREMENTS_*` | the `--requirements` file, as for `check` | as for `check` |
|
|
2218
2433
|
|
|
2434
|
+
### The command line
|
|
2435
|
+
|
|
2436
|
+
| rule | means | change |
|
|
2437
|
+
| --- | --- | --- |
|
|
2438
|
+
| <a id="USAGE"></a>`USAGE` | the call is malformed: an unknown command or flag, a flag given twice or without its value, a required flag missing, or two flags that exclude each other; the line says which. Exit 2, and nothing runs | the call — `rig-parts --help` lists the commands, and a command's refusal of a flag it does not take lists the flags it does |
|
|
2439
|
+
| <a id="NOT_IMPLEMENTED"></a>`NOT_IMPLEMENTED` | the command is registered for a later version and does nothing in this one; exit 2. No command is today (`LATER` in `cli.ts` is empty) | a version that implements it |
|
|
2440
|
+
| <a id="GUIDE_FILE_PRESENT"></a>`GUIDE_FILE_PRESENT` | `rig-parts guide` found no `docs/AUTHORING.md` beside the `cli.ts` it runs from | reinstall the package: the file is in its `files` |
|
|
2441
|
+
| <a id="GUIDE_RULE_KNOWN"></a>`GUIDE_RULE_KNOWN` | `rig-parts guide <RULE>`: no row of this guide names the rule. The line, on stderr, lists the three nearest names the guide does hold; nothing is printed in their place | one of the names listed, spelled as the line printed it |
|
|
2442
|
+
| <a id="GUIDE_SECTION_KNOWN"></a>`GUIDE_SECTION_KNOWN` | `rig-parts guide §<n>`, `§<n>.<m>` or `§<n>.<m>.<k>`: there is no such section, or no such subsection under the one it names; the line, on stderr, names the deepest section that exists and lists its sections | a number the detail lists |
|
|
2443
|
+
|
|
2219
2444
|
## 7. The bars `check` enforces, and what only an eye answers today
|
|
2220
2445
|
|
|
2221
2446
|
`check.json`'s `PASS` is true exactly when all of these hold (the reference
|
|
@@ -2319,13 +2544,17 @@ the two examples [observed]:
|
|
|
2319
2544
|
|
|
2320
2545
|
| line | measures | bar | `reference-demo` | `reference-sample` | SKIP when |
|
|
2321
2546
|
| --- | --- | --- | --- | --- | --- |
|
|
2322
|
-
|
|
|
2323
|
-
|
|
|
2547
|
+
| <a id="BREATH_VISIBLE"></a>`BREATH_VISIBLE` | `topwear` parts rendered alone (`rigc render --slot`): heat mean over their box; `footwear` parts alone: heat max over theirs | torso mean ≥ 3.809; feet max ≤ 0 | 15.251; 0 | 7.617; 0 | no `topwear` and no `footwear` part. One of the two absent (issue #323): the other half is measured and decides the line, which then carries `halves_measured` `"1 of 2"` first, then each half's own status — `torso_status`, `feet_status` — the absent half's `SKIP` with its `torso_reason` or `feet_reason`; a run that measured both halves writes the keys it always wrote |
|
|
2548
|
+
| <a id="BLINK_NO_HOLE"></a>`BLINK_NO_HOLE` | the setup pose with every `scaley` track on the eyewhite slots' bones held at its closed value, against the setup pose, at full size: pixels in the eyewhite box that show the page where the open eye had art | 0 px | 0 | 0 | no `eyewhite` part, or no `scaley` track on its bones goes below its first key |
|
|
2324
2549
|
| ″ (reported) | the same box: each closed-eye pixel's max-channel distance to the nearest colour the open eye's box holds — max, and pixels over 40 | none | 15; 0 | 11; 0 | as above |
|
|
2325
|
-
|
|
|
2326
|
-
|
|
|
2327
|
-
|
|
|
2328
|
-
|
|
|
2550
|
+
| <a id="CHAIN_LAG"></a>`CHAIN_LAG` | `motion.json`'s rotate tracks read as sines (DFT of the keys: period, amplitude, phase) and arranged by the bone tree — a keyed bone's parent is its nearest keyed ancestor | every lag ≥ 0.001 cycle; amplitude non-decreasing down each unbranched chain — non-increasing down a chain that carries a part declared `rests` (issue #245) | lags 0.040 (neck to head) to 0.120; 12 chains | lags 0.040 to 0.100; 9 chains | no rotate track under another of the same period |
|
|
2551
|
+
| <a id="TIP_OVER_ROOT"></a>`TIP_OVER_ROOT` | each `handwear`/`bottomwear` part: how far the centroid of its art travels in the lower half of its box against the upper half — the art's AREA centroid inside each fixed half (cut at h/2), every art pixel (alpha above 8) carried through its attachment's posed triangles from the idle's `geometry.json` and clipped to the half exactly, rig px; `instrument: "geometry"` in the line (issue #118) | ratio ≥ 1.4725; a part declared `rests`, ratio ≤ 1 (issue #245) | `bottomwear` 3.222, `sleeves` 4.721 | `bottomwear` 4.956, `sleeves` 11.830 | no such part |
|
|
2552
|
+
| <a id="STILL_REGIONS_DARK"></a>`STILL_REGIONS_DARK` | from the idle's posed geometry (`geometry.json`), `instrument: "geometry"` in each half (issue #123). **Face:** the still set — the `face` slots, and every slot drawn after the first of them whose art overlaps a face part's at the setup pose, that the head bone alone carries (a region on it, or a mesh whose every weight is it) and that the idle does not key by slot (`deform`, `sequence`, a slot track: `driven_slots`). The head bone is the bone the `face` parts' slot rides in `rig.json`. Each still slot's art (alpha above 8), carried through its posed attachment and back through the head bone's setup-to-frame map on every idle frame, against its setup position: `max_rig_px` (and where, `at`, when it is a motion), `rms_rig_px`, per slot in `still_slots`. **Feet:** the `footwear` slots the same way in screen space — they ride the root, which the idle does not key, so the screen is their own frame. **Reported, no bar:** `crossing` — per slot drawn after the still set's first slot and not in it, how deep its art reaches into the region (`face` on top at the setup pose, clear of where `eyewhite`, `irides`, `eyelash`, `eyebrow` and `mouth` go in the head's frame; for the feet, `footwear` on top), `depth_rig_px`, and the most of it covered on one frame, `area_rig_px2` | each half's `max_rig_px` ≤ its `tolerance_rig_px`: nothing moves, up to the arithmetic's rounding, √2 × 2 × 35 × M² × ulp(C) (below) | face 4.202e-13 ≤ 2.286e-11; `hair_front` crossing 2.816 rig px deep, 89.395 rig px² (frame 47); feet 0 ≤ 2.814e-12 | face 4.418e-13 ≤ 2.286e-11 (`face`, `ear_l`, `ear_r`); `hair_front` 2.194 deep, 50.605 rig px² (frame 23); feet 0 ≤ 2.814e-12 | no `face` and no `footwear` part (one of the two absent leaves that half unmeasured; so do face parts on two slot bones, or idle frames with no `geometry.json`) |
|
|
2553
|
+
| <a id="TEXTURE_STRETCH"></a>`TEXTURE_STRETCH` | every mesh triangle's three edges in every idle frame, read from the `geometry.json` the idle render writes (`rigc render --geometry`, rig-c 1.4.0 or later): skinned length over rest length, the rest being the setup pose's bones with no deform. The figure is the rig's worst max(ratio, 1/ratio); each mesh's largest and smallest ratio, with triangle, vertices, edge and frame, is the detail | max(ratio, 1/ratio) ≤ 1.926544 | 1.388: `hair_back` triangle 449, edge 42-43 at 0.720 in frame 26 (largest stretch 1.291, frame 2) | 1.227: `sleeves` triangle 169, edge 126-51 at 0.815 in frame 28 (largest stretch 1.196, frame 5) | the rig draws no mesh, or the render wrote no `geometry.json` |
|
|
2554
|
+
| <a id="ANIMATIONS_DO_NOT_FOLD"></a>`ANIMATIONS_DO_NOT_FOLD` | every animation, the idle included, through one `rigc render --folds` at 12 fps over the build with its physics constraints left out: the meshes with a triangle turned over against the setup pose on some frame, less those the requirements file's `may_fold` declares (below) | 0 undeclared folding meshes, and no `may_fold` entry that matches no fold | 0, over `idle` | 0, over `idle` and `hop`, 2 physics constraints left out | never SKIP: written whenever `motion.json` holds an animation |
|
|
2555
|
+
| <a id="FEET_STAY_LEVEL"></a>`FEET_STAY_LEVEL` | issue #348. Each `footwear` part whose slot's bone hangs from another bone (rig.json's `parent`; a part on `root` hangs from nothing and is not read), over every animation, the idle included, from the same `rigc render --folds` run, which then also writes `--geometry`: on each frame where a bone above the part's bone — its parent or any bone over that — has a world rotation other than its setup pose's (no threshold; the nearest is named), the drawing's turn: the least-squares rotation carrying the attachment's setup-pose vertices onto the frame's, both centred (a region's four corners turn exactly with its bone). **This is the reading of "the sole's angle"**: no rig data marks a sole, so level is the drawing's setup angle, the painting's own; a declared sole line would replace it if one ever exists | every read foot within ±10 degrees — HQ's line (rig-c/parts#347 ruling 4), not a figure measured here | not written: the shoes ride `root` | not written: the shoes ride `root` | SKIP when no frame turns a bone above any read foot (not counted as measured); not written at all when no `footwear` part hangs from a bone, or `motion.json` holds no animation, so the examples' `check.json` keep their keys |
|
|
2556
|
+
| <a id="STRESS_OFF_CHAIN"></a>`STRESS_OFF_CHAIN` | each mesh from a See-through `handwear` layer whose weights ride exactly one chain the idle keys: the chain's first link turned 90°, −90° and 180° from its setup rotation (interim, issue #347: until a config block declares each limb and its joint's range), one `rigc build --profile spine` and one `rigc render --geometry` of a copy with its physics constraints left out; per turn, the part's worst edge as max(ratio, 1/ratio) against the setup pose, at four places, and the bones it is weighted to off the chain. A part riding two chains, or none, or not a weighted mesh, is listed under `not_read` with the reason, and so is a part a `config.limbs` segment made (issue #349): `LIMB_ONE_BONE` holds it to its one bone, so it turns rigidly by construction | 1.0000 — the part turning rigidly with its chain; float32 noise on rigid sleeves measured at most 1.0000090 | SKIP: `sleeves` rides 2 chains | SKIP: `sleeves` rides 2 chains | no part comes from a `handwear` layer or the motion has no idle (the line is not written); every `handwear` part not read (SKIP, each reason) |
|
|
2557
|
+
| <a id="LIMB_ONE_BONE"></a>`LIMB_ONE_BONE` | issue #349. Each part `parts.json` records as a limb segment's (`limb`), read off `rig.json` alone, nothing rendered: the bones its attachments are bound to — a mesh's weights, or its slot's bone for a region — against its segment's bone (under `config.turn`, that bone's leaf twin counts as the bone) | every limb part bound to its one bone alone, weight 1 | not written: no limbs | not written: no limbs | never: written only when `parts.json` holds a limb part, so the examples' `check.json` keep their keys |
|
|
2329
2558
|
|
|
2330
2559
|
**`TIP_OVER_ROOT` is measured from geometry, not pixels (issue #118).** Until #118 the
|
|
2331
2560
|
line rendered each part alone at `--max 640` and took, per half of its frame box, the
|
|
@@ -2455,6 +2684,30 @@ The selftest's planted cases (by hand):
|
|
|
2455
2684
|
| a foot whose root moves `fround(0.05)` rig px | PASS, heat 0.779–0.785 | FAIL, 0.05 rig px |
|
|
2456
2685
|
| a face mesh weighted to a bone sliding `fround(0.05)` under a rolling head | PASS, 0.851–0.855 against 0.936–0.948 | FAIL, 0.05 rig px |
|
|
2457
2686
|
|
|
2687
|
+
**`STRESS_OFF_CHAIN`: a sleeve turned far (issue #347).** The idle moves a sleeve a few
|
|
2688
|
+
degrees, so a sleeve that only looks right at rest passes every idle bar and is first seen
|
|
2689
|
+
broken by whoever poses it. This bar poses it first. For each part from a See-through
|
|
2690
|
+
`handwear` layer whose weights ride exactly one chain the idle keys, the chain's first link
|
|
2691
|
+
(the bone the idle keys) is turned 90°, −90° and 180° from its setup rotation — the card's
|
|
2692
|
+
arm raised, arm across and arm behind the head — on a throwaway copy with its physics
|
|
2693
|
+
constraints left out: one `rigc build --profile spine`, one `rigc render --geometry` at
|
|
2694
|
+
rigc's smallest `--max` (the reading is world units), and the part's worst edge as
|
|
2695
|
+
max(ratio, 1/ratio) against the setup pose, the quantity `TEXTURE_STRETCH` reads. A part
|
|
2696
|
+
weighted to its chain alone turns with the link as one piece, so it reads exactly 1; the bar
|
|
2697
|
+
is that reading at four places, **1.0000** — not a margin: the rigid sleeves of `demo` and of
|
|
2698
|
+
a test rig read 1.0000038 to 1.0000090 (float32 bone arithmetic), and the same sleeves with a
|
|
2699
|
+
16 px `chest` segment at the shoulder read 2.41 to 1,498 (rigc 2.47.1). A vertex weighted to a
|
|
2700
|
+
bone the turn does not move is pulled between the two, and the line names that bone, how many
|
|
2701
|
+
vertices carry it and the largest weight: the segment on it in `meshes.<part>.segments` is
|
|
2702
|
+
the one to drop. `propose` drafted that stub on every sleeve until issue #347; `demo` and
|
|
2703
|
+
`scarf` carried it, and dropping it moved neither the setup-pose seam nor any bar's status.
|
|
2704
|
+
Two limits, both stated rather than guessed. **The turns are interim:** a config block that
|
|
2705
|
+
names each limb and its joint's declared range is the next card, and the bar then poses each
|
|
2706
|
+
limb at its range's ends. **The scope is the `handwear` tag:** a part riding two chains (one
|
|
2707
|
+
mesh for both sleeves, as `reference-demo` and `reference-sample` have) stretches between them
|
|
2708
|
+
by construction and is listed under `not_read` with that reason, and a one-chain pendant on
|
|
2709
|
+
another tag is not read — `reference-demo`'s `hairpin`, its tassel turned 180°, reads 23.7.
|
|
2710
|
+
|
|
2458
2711
|
**`ANIMATIONS_DO_NOT_FOLD`: every animation, the idle included (issues #320, #333).** The one
|
|
2459
2712
|
bar that reads an animation other than the idle, and it reads the idle with them, written — as
|
|
2460
2713
|
a key of `check.json` after `TEXTURE_STRETCH`, and a console line after the judgement lines —
|
|
@@ -2508,7 +2761,7 @@ After them, one **reported line** with no bar:
|
|
|
2508
2761
|
|
|
2509
2762
|
| line | reports | bar | `reference-demo` | `reference-sample` | SKIP when |
|
|
2510
2763
|
| --- | --- | --- | --- | --- | --- |
|
|
2511
|
-
|
|
|
2764
|
+
| <a id="RECOMPOSITE_HOLES"></a>`RECOMPOSITE_HOLES` | `parts.json`'s `recomposite` block (§5), read rather than measured — under `config.scene` (issue #242) it was measured inside the figure, and the line's first figure, `declared_scene`, says so: `error_px`, `uncovered_error_px`, `hole_count`, and the largest hole's `px`, `box` (`x,y wxh`) and `borders` (`<part> <px> px`) | none — status `REPORTED`, never FAIL, and `PASS` does not read it | 1,564 px in 453 holes; largest 70 px at 351,155 6x22, `hair_back` 53 px, `hair_front` 12 px | 1,185 px in 259 holes; largest 94 px at 479,412 7x34, `sleeves` 42 px, `topwear` 40 px, `bottomwear` 6 px | `parts.json` has no `recomposite` block (the reference's files) |
|
|
2512
2765
|
|
|
2513
2766
|
It exists because no gate can see what it reports. The seam compares the setup pose
|
|
2514
2767
|
with the flat stack **of the parts**, so a pixel of the painting that no part holds is
|
|
@@ -2526,7 +2779,7 @@ Under `--source <painting.png>`, a second reported line, also never a FAIL
|
|
|
2526
2779
|
|
|
2527
2780
|
| line | reports | bar | `reference-demo` | `reference-sample` | SKIP when |
|
|
2528
2781
|
| --- | --- | --- | --- | --- | --- |
|
|
2529
|
-
|
|
|
2782
|
+
| <a id="SETUP_POSE_VS_SOURCE"></a>`SETUP_POSE_VS_SOURCE` | the setup pose against the painting, by `assemble`'s own `measureRecomposite` over the stage's pixels — `mean_abs` and `within_share` (mean channel, within 8), `error_px` (max channel over 40), `uncovered_error_px` (of those, where the pose has alpha 128 or less), `hole_count` and the largest hole's box — with `painting_px`, `stage_px`, `render_px` and `render_scale` beside them. The painting is resampled onto the stage as assemble resamples it (lanczos3, alpha dropped). rigc renders onto an opaque grey, so the pose over white and its alpha are read off a second still of the same pose with every slot tinted black; both are carried onto the stage with the seam's map turned round (bilinear) | none — status `REPORTED`; assemble applies no bar to the figures it measures, so none is derived here | 3.146 / 93.43 % / 12,399 / 1,732, 518 holes, the largest 61 px at 351,157 6x20 (assemble's recomposite: 2.391 / 95.81 % / 11,050 / 1,564, 453) | 1.095 / 97.30 % / 5,348 / 1,239, 313 holes, the largest 88 px at 479,416 6x29 (assemble's: 0.835 / 97.95 % / 4,512 / 1,185, 259) | not written without `--source` |
|
|
2530
2783
|
|
|
2531
2784
|
The figures are assemble's by construction, not a second definition beside them;
|
|
2532
2785
|
what differs is what they are taken of — the pose rigc draws, not the flat stack —
|
|
@@ -2639,6 +2892,7 @@ it reads is there, and says SKIP with the reason when it is not:
|
|
|
2639
2892
|
| `BREATH_VISIBLE`, `BLINK_NO_HOLE`, `TIP_OVER_ROOT`, `STILL_REGIONS_DARK` | `parts.json`'s tags and the idle | either missing, or as in the table above |
|
|
2640
2893
|
| `CHAIN_LAG`, `TEXTURE_STRETCH` | the idle (and `rig.json`) | no `idle`, or as in the table above |
|
|
2641
2894
|
| `ANIMATIONS_DO_NOT_FOLD` | every animation, the idle included, through `rigc render --folds` | never SKIP: written when `motion.json` holds an animation, the idle alone included (issue #333), absent when it holds none (with or without a `parts.json`) |
|
|
2895
|
+
| `STRESS_OFF_CHAIN` | `parts.json`'s tags, the idle's chains, `rig.json`'s weights, and a turned copy rigc poses | written only when `parts.json` names a `handwear` part and there is an idle (absent on a rig with no `parts.json`); SKIP when no such part rides exactly one chain, each part's reason |
|
|
2642
2896
|
| `RECOMPOSITE_HOLES` | `parts.json`'s `recomposite` block | no `parts.json`, or no block |
|
|
2643
2897
|
| `SETUP_POSE_VS_SOURCE` | the rig spec and the painting | no `--source` |
|
|
2644
2898
|
|
|
@@ -2674,7 +2928,7 @@ single-character path (§4, steps 0–9) on its own, already isolated input to a
|
|
|
2674
2928
|
| `characters[].build` | a `build --out` directory (relative to the scene file) whose own `check/check.json` is green |
|
|
2675
2929
|
| `characters[].offset` | `[x, y]`, a translation from the build's rig px to canvas px. Every character is built at one `assemble.rig_scale`, so its rig px are canvas px at scale 1 |
|
|
2676
2930
|
| `characters[].scale` | optional, a positive number; absent is 1, and 1 composes to the bytes a scene without the key writes. The character's size on the canvas, about its stage's top-left corner: a rig px `p` lands at canvas px `scale * p + offset` (issue #197). A character scaled up past its art is drawn soft — the art is not resampled; rebuild it at a higher `assemble.rig_scale` if that matters |
|
|
2677
|
-
| `characters[].accept` | optional, a list of bar names: the bars this character's own check may have failed and still be composed (issue #203). `compose --accept <bar>[,<bar>…]` is the same list for every character; the two are joined, so the command line applies to every character and a character's list adds to it. Each name is one of the bars `check`'s summary names, less the gate — `loop`, `seam`, `BREATH_VISIBLE`, `BLINK_NO_HOLE`, `CHAIN_LAG`, `TIP_OVER_ROOT`, `STILL_REGIONS_DARK`, `TEXTURE_STRETCH`, `ANIMATIONS_DO_NOT_FOLD` (issue #320); anything else is `SCENE_ACCEPT_KNOWN`. A build is taken when every bar its `check.json` failed is named; its gate red, a declared requirement not PASS, or a bar not named is `SCENE_BUILD_GREEN` as before. **It is for looking, not for shipping:** the `[compose]` line says which failing bars were accepted, `scene.json` records them as the character's `accepted`, the composed rig's own check measures them again and reports them as it finds them, and the run exits 1 even when that check is PASS (a composed rig has no `parts.json`, so the seam and four judgement lines say SKIP there). A list that accepts nothing — every build green — composes to the bytes a scene without one writes |
|
|
2931
|
+
| `characters[].accept` | optional, a list of bar names: the bars this character's own check may have failed and still be composed (issue #203). `compose --accept <bar>[,<bar>…]` is the same list for every character; the two are joined, so the command line applies to every character and a character's list adds to it. Each name is one of the bars `check`'s summary names, less the gate — `loop`, `seam`, `BREATH_VISIBLE`, `BLINK_NO_HOLE`, `CHAIN_LAG`, `TIP_OVER_ROOT`, `STILL_REGIONS_DARK`, `TEXTURE_STRETCH`, `ANIMATIONS_DO_NOT_FOLD` (issue #320), `STRESS_OFF_CHAIN` (issue #347); anything else is `SCENE_ACCEPT_KNOWN`. A build is taken when every bar its `check.json` failed is named; its gate red, a declared requirement not PASS, or a bar not named is `SCENE_BUILD_GREEN` as before. **It is for looking, not for shipping:** the `[compose]` line says which failing bars were accepted, `scene.json` records them as the character's `accepted`, the composed rig's own check measures them again and reports them as it finds them, and the run exits 1 even when that check is PASS (a composed rig has no `parts.json`, so the seam and four judgement lines say SKIP there). A list that accepts nothing — every build green — composes to the bytes a scene without one writes |
|
|
2678
2932
|
| `order` | the draw order, back to front: a character id (its slots not named elsewhere, in its own order) or one `<id>:<slot>`. Every slot of every character is drawn exactly once. Interleaving is written by naming slots: `["a", "b:arm_l", "b"]` draws `b`'s left arm between `a` and the rest of `b` |
|
|
2679
2933
|
|
|
2680
2934
|
What is composed:
|