@rig-c/parts 1.11.0 → 1.13.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 +15 -11
- package/cli.ts +13 -4
- package/docs/AUTHORING.md +188 -32
- package/docs/STABILITY.md +3 -3
- package/package.json +2 -2
- package/skills/rig-parts/SKILL.md +8 -5
- package/src/assemble.ts +85 -2
- package/src/build.ts +16 -2
- package/src/check.ts +65 -4
- package/src/config.ts +22 -1
- package/src/heat.ts +42 -6
- package/src/mesh.ts +61 -0
- package/src/meshdraft.ts +43 -9
- package/src/propose.ts +55 -2
- package/src/rig.ts +19 -5
- package/src/squeeze.ts +274 -0
package/README.md
CHANGED
|
@@ -41,13 +41,13 @@ from the full run, because the twin tails leave the head crop sideways (a plan e
|
|
|
41
41
|
<code>loop: idle 41 frame(s) at 12 fps, f0000 vs f0040 (t = 3.333333333333333s): max |d| 0 (0 required)</code><br/>
|
|
42
42
|
<code>seam: setup pose at 654x1216, scale 0.9438: mean |d| 0.147 (<= 1.0), 0 px over 40, 0.00 rig px (the count / s²; <= 50), 0 px over 80 (reported)</code><br/>
|
|
43
43
|
<code>pack: skeleton.png 1051x972, 23 region(s), 96.9% covered, padding 2, page edges free, shape polygon</code><br/>
|
|
44
|
-
The loop is that build's indexed APNG, 40 frames at 12 fps,
|
|
45
|
-
256-entry palette at a measured error of max
|
|
46
|
-
frame (the lossless APNG beside it, the exactness record, is 4,
|
|
47
|
-
GIF, at the same error, 760,
|
|
44
|
+
The loop is that build's indexed APNG, 40 frames at 12 fps, 703,909 bytes, one
|
|
45
|
+
256-entry palette at a measured error of max 71, mean 0.636 per channel over every
|
|
46
|
+
frame (the lossless APNG beside it, the exactness record, is 4,449,233 bytes; the
|
|
47
|
+
GIF, at the same error, 760,058). The rig's hair, skirt, sleeves, bows and earrings
|
|
48
48
|
carry physics, which rigc's render starts from rest, so the idle is played three
|
|
49
49
|
periods ahead and the loop is the fourth: the frame one period after its first differs
|
|
50
|
-
from it by max
|
|
50
|
+
from it by max 1 level, 0 px over 40 (<code>--lead-in</code>). Frame 29 (2.417 s) is the
|
|
51
51
|
closed eye: the blink holds for 0.084 s, one 12 fps frame rounded up; the painting is
|
|
52
52
|
shown at half size, resampled and written by this package's PNG codec (nothing here
|
|
53
53
|
encodes JPEG). <code>rig-parts sheet</code> made the contact sheet. Its
|
|
@@ -228,7 +228,7 @@ than queueing behind someone else's job.
|
|
|
228
228
|
## The loop, for an agent
|
|
229
229
|
|
|
230
230
|
```sh
|
|
231
|
-
rig-parts inputs --source painting.png --config config.json --out inputs # st_input_full.png
|
|
231
|
+
rig-parts inputs --source painting.png --config config.json --out inputs # st_input_full.png; the config needs assemble.rig_scale
|
|
232
232
|
# See-through on st_input_full.png (external, or `rig-parts comfy seethrough`) -> layers/full
|
|
233
233
|
rig-parts layers layers/full # every layer: box, opaque px, depth, plausibility figures; WARN lines
|
|
234
234
|
rig-parts propose --head-box --full layers/full --canvas 1664x2432
|
|
@@ -278,7 +278,7 @@ agent skill.
|
|
|
278
278
|
| `comfy seethrough --image --out [--host]` | optional: run the ComfyUI See-through wrapper on one image and write the form `layers` reads |
|
|
279
279
|
| `layers <dir \| layers.json \| file.psd>` | print every layer of a decomposition: draw order, name, tag group, box, size, opaque pixels, depth, and its translucent, background and area figures; a `WARN` line for a layer `--propose-plan` will leave out |
|
|
280
280
|
| `sheet --source <png> --layers <path>… --out <png>` | a labelled contact sheet of the painting and every layer or part |
|
|
281
|
-
| `assemble --propose-plan …` | propose `assemble.plan` and `extend_below_crop` from the two runs, leaving out an implausible layer with a note naming the rule,
|
|
281
|
+
| `assemble --propose-plan …` | propose `assemble.plan` and `extend_below_crop` from the two runs, leaving out an implausible layer with a note naming the rule, naming in a note any full-run body no planned part covers, and naming every layer no row takes with why (empty, taken from the other run only, a plausibility rule; `nose`, never planned, with the row that lets `propose` read the head's pitch) |
|
|
282
282
|
| `assemble --source --full --head --config --out [--seam] [--project]` | merge the two runs into rig-space parts, `parts.json`, the recomposite and its error map, and list the uncovered holes |
|
|
283
283
|
| `propose --head-box --full <run> --canvas WxH` | propose `seethrough.head_box` from the full run, held inside the painting |
|
|
284
284
|
| `propose --parts --source --out [--compare <config>]` | propose bones, meshes, regions and an idle; draw the overlay; print, per bone, which check read it or that none did and why (its role, its kind of segment), and write `basis.json` beside the proposal — what each bone rests on (a joint, a part's mask, a ratio, other bones) and, with `--compare`, whether the config's bone differs |
|
|
@@ -323,9 +323,13 @@ These are limits of the approach, stated so nobody reads more into a green run:
|
|
|
323
323
|
existence proof, not a rate.
|
|
324
324
|
- **`loop` writes GIF and APNG (lossless and indexed), not WebP**: an animated WebP needs a VP8/VP8L
|
|
325
325
|
encoder, which this package does not carry.
|
|
326
|
-
- **The proposer
|
|
327
|
-
put the hip below
|
|
328
|
-
|
|
326
|
+
- **The proposer reads the torso by screen y unless it is told the pose.** Its ratios
|
|
327
|
+
put the hip below `bottomwear`'s top edge and the chest above it, and hang the sleeves
|
|
328
|
+
from the shoulders. A figure whose joints are not there — reclining, an arm raised, or
|
|
329
|
+
seated in a skirt that does not start at the hip — needs `propose --keypoints`; sitting
|
|
330
|
+
alone does not, but a clean LINT does not show the hip is right (it asks only that the
|
|
331
|
+
hip be below the chest and the shoulders), so read the overlay ([AUTHORING §3](docs/AUTHORING.md)). The
|
|
332
|
+
file of joints comes from any pose
|
|
329
333
|
estimator or a hand; this package does not estimate a pose itself, and its
|
|
330
334
|
keypoint support has been measured on generated figures and on files read off the
|
|
331
335
|
examples' own configs, never on an estimator's output.
|
|
@@ -355,7 +359,7 @@ for each — a config fragment, the `check` lines it passes with, and its limit:
|
|
|
355
359
|
and a `physics` constraint on it; `examples/reference-sample` carries one. Under its slow
|
|
356
360
|
4 s idle the bust moves at most 0.066 rig px and the hips not at all: the spring answers
|
|
357
361
|
faster keys on the body. Its `hop`, a named animation keying only `hip`, moves the
|
|
358
|
-
bust up to 6.
|
|
362
|
+
bust up to 6.702 and the hips up to 4.609 rig px; the region's `band` caps how far a patch may
|
|
359
363
|
go before the texture-stretch ceiling, and `check` measures the idle alone.
|
|
360
364
|
|
|
361
365
|
### How much of a rig the model painted
|
package/cli.ts
CHANGED
|
@@ -96,8 +96,13 @@ usage:
|
|
|
96
96
|
link of a fringe chain (hung from head on a head-run front hair mesh, its tip
|
|
97
97
|
no lower than the chin) that drifts more than ${FRINGE_STEP_PX} px plus a pixel's
|
|
98
98
|
rounding across the head's down axis (the eye line's perpendicular), for a
|
|
99
|
-
hip that is not below the chest,
|
|
100
|
-
height (the shoulders)
|
|
99
|
+
hip that is not below the chest, for a hip above ${HIP_MIN_FRACTION} of the figure's
|
|
100
|
+
height (the shoulders), and for two keyed chains on one lattice mesh whose
|
|
101
|
+
own swing, every other bone held, takes an edge of the rig stage's lattice
|
|
102
|
+
past check's TEXTURE_STRETCH bar (with each chain alone, the tips'
|
|
103
|
+
distance, and each remedy's own figure: one sign for opposed amplitudes,
|
|
104
|
+
dropping a chain; a contour or automatic mesh, or rule "heat", is said in
|
|
105
|
+
a "squeeze not read" note); the fringe's three chains stand in the head's frame,
|
|
101
106
|
rooted on the part's art, and a note says they are a template, not its
|
|
102
107
|
locks; a headwear/earwear layer with hanging strands
|
|
103
108
|
gets one pendulum chain per strand and a note with each strand's x, rows
|
|
@@ -273,8 +278,11 @@ usage:
|
|
|
273
278
|
than its lattice, and the report records each part's triangle and
|
|
274
279
|
overdraw difference. A part that passes is drafted, its note saying
|
|
275
280
|
what it was measured against; one that fails keeps its entry, and the
|
|
276
|
-
report names each failed reading and by how much.
|
|
277
|
-
drafted
|
|
281
|
+
report names each failed reading and by how much. An auto or contour
|
|
282
|
+
entry is neither drafted nor compared with anything: a NOT COMPARED line
|
|
283
|
+
and the report's not_compared name each, so build it once on a lattice
|
|
284
|
+
and compare the rig stage's mesh lines (AUTHORING §3, issue #307).
|
|
285
|
+
Written only when the drafted config's check is PASS. --requirements, --idle-keys,
|
|
278
286
|
--page-edges and --pack-shape are as for rig and check.
|
|
279
287
|
|
|
280
288
|
rig-parts check --rig <dir> --out <dir> [--parts <dir>] [--source <painting.png>]
|
|
@@ -880,6 +888,7 @@ function printLint(P: PartSet, spec: { bones: CharacterConfig['bones']; meshes:
|
|
|
880
888
|
for (const f of res.findings) console.log(lintLine(f));
|
|
881
889
|
for (const m of res.unknownMeshes) console.log(`note: mesh ${JSON.stringify(m)} names no part in parts.json, so it was not linted`);
|
|
882
890
|
for (const w of res.lockUnread) console.log(`note: off-lock not read: ${w}`);
|
|
891
|
+
for (const w of res.squeezeUnread) console.log(`note: squeeze not read: ${w}`);
|
|
883
892
|
for (const b of res.missingTorsoBones) {
|
|
884
893
|
console.log(
|
|
885
894
|
res.basis?.torso.read === true
|
package/docs/AUTHORING.md
CHANGED
|
@@ -6,12 +6,17 @@ 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
7
|
has to change.
|
|
8
8
|
|
|
9
|
-
The worked example throughout is [`examples/reference-sample`](
|
|
9
|
+
The worked example throughout is [`examples/reference-sample`](https://github.com/rig-c/parts/tree/main/examples/reference-sample): its
|
|
10
10
|
`config.json` is a complete, loading config, `proposal.json` is what the proposer
|
|
11
11
|
wrote for it, and `expected/` is what the reference implementation produced from
|
|
12
12
|
the same inputs — except `check.json`, which this port's `build` regenerates since
|
|
13
13
|
the reference has no judgement lines (§7). `bun run fetch-examples` puts its painting and See-through layers
|
|
14
|
-
into `examples/reference-sample/inputs
|
|
14
|
+
into `examples/reference-sample/inputs/` in a clone of the repository.
|
|
15
|
+
|
|
16
|
+
A path this page names that the installed package does not hold — anything under
|
|
17
|
+
`examples/`, `docs/evidence/`, `tools/`, `fixtures/` or `scripts/`, and the scripts
|
|
18
|
+
`bun run` names — is in the repository, https://github.com/rig-c/parts; the package holds the files
|
|
19
|
+
`package.json` lists under `files` (`npm pack --dry-run` prints them).
|
|
15
20
|
|
|
16
21
|
The examples' names: `reference-sample` and `reference-demo` are the two characters
|
|
17
22
|
the reference implementation ran (published as `sample` and `demo` until issue #227),
|
|
@@ -92,10 +97,11 @@ read by no CPU stage).
|
|
|
92
97
|
| `assemble.patches` | assemble; `meshes`/`regions` keys may name them too | **authored**, optional: `[{name, box, alpha, draw}]` — an extra part cut from the **painting** itself, for figure no See-through layer holds (a hem both runs dropped). `box` is `[x0, y0, x1, y1]` in **rig** pixels, `x1`/`y1` exclusive — the space of `parts.json` and `recomposite_rig.png`, where the hole is found; `alpha` is `"silhouette"` (the painting's figure silhouette inside the box, the one `--seam silhouette` uses) or `"box"` (the whole box); `draw` is `"back"`, `"front"` or `{"before": "<plan part>"}`. A patch is always a region: its bone is `regions.<name>`, in the one place every region's bone lives, and a `meshes` entry for it is refused. See §5 for how to place one |
|
|
93
98
|
| `assemble.cuts` | assemble; `meshes`/`regions` keys may name the new parts too, and must (each is a part like any other) | **authored**, optional (issue #170): `[{from, into, polygon, draw, overlap, under}]`, `under` optional — a plan part's layer cut by a polygon the author draws: the pixels of plan part `from` whose **centre** lies inside `polygon` (even-odd; a centre exactly on an edge is outside) leave `from` and make the new part `into`, colour and alpha, so every pixel of the layer ends in exactly one of the two. `polygon` is `[[x, y], …]`, at least three points, non-negative integer **rig** pixels — the space of `parts.json` and of the patches' boxes. The file that shows the layer in those coordinates is `assemble`'s own `rig/parts/<from>.png`, placed at its `parts.json` `x`, `y` (the PNG's pixel `(i, j)` is rig pixel `(x + i, y + j)`), or `render/recomposite_rig.png`, the whole rig 1:1; the contact sheets (`sheet`) are scaled and carry no coordinates. `draw` is `"back"`, `"front"` or `{"before": "<plan part>"}`, as for a patch (to keep the setup pose, draw the piece immediately in front of `from` — `{"before": "<the plan part after from>"}`, or `"front"` when `from` is the last plan part; `{"before": "<from>"}` draws it behind `from`, which `under` refuses as `ASSEMBLE_UNDER_DRAW` because the fill would hide it). `from` must be a plan part (`CONFIG_NAME_RESOLVES`; a patch or another cut's piece is refused), `into` a new name (`CONFIG_PART_UNIQUE`), the polygon three or more integer points (`CONFIG_FIELD_TYPE`). The piece's `parts.json` record carries `from`'s `<run>:<tag>` and its own counts, each split from the layer's by where the pixel lies; it is a mesh or a region under its own name, and the coverage rule holds it like a plan part. What the config cannot know the stage refuses: a polygon point past the rig (`ASSEMBLE_CUT_INSIDE`), two cuts of one part sharing a pixel (`ASSEMBLE_CUT_OVERLAP`), a cut that takes none of the layer's opaque pixels or leaves `from` none (`ASSEMBLE_CUT_PIXELS`). `overlap` is required, a non-negative integer of rig pixels with no default (`CONFIG_FIELD_TYPE`): the **band** — the polygon's pixels within `overlap` px of its edge by Chebyshev distance (the polygon's mask less its erosion by a `2 * overlap + 1` square) — stays in `from` as well as going to the piece, so the piece's resampled edge has art under it; the counts stay a strict partition and the band is the base's extra copy, printed on the `cut:` line. At `0` the two abut and `check`'s seam bar judges the edge between them (`CHECK_SEAM_WITHIN_BAR`, §5). A band only covers the edge at rest: a piece that swings well clear of where it was painted shows the hole it leaves, and a thin piece's band shows a ghost of the piece. `under` (issue #193), optional, is the author's image of what lies under the piece: a PNG path relative to the config's directory (`CONFIG_FIELD_TYPE` unless a non-empty string), in rig pixels over the polygon's **bounding box** — the least and greatest polygon x and y, so the image is `max x − min x` by `max y − min y` and its pixel `(i, j)` is rig pixel `(min x + i, min y + j)`. Where the cut removed pixels from `from` — the piece's pixels (alpha above 0) less the band — `from` takes the image's pixel, colour and alpha wherever the image's alpha is at least the alpha the cut removed there (**filled**); elsewhere `from` stays empty there (**left empty**): a transparent pixel is the author's statement that nothing lies under it (the background, or a part drawn behind), and a less opaque one is not half-filled. The image is read nowhere else, so its pixels over the band, over the box outside the polygon or where the layer had no art never change `from`. The `cut:` line then ends `; under <n> px filled, <m> px left empty` (`n + m` is every removed pixel), so an unintended hole is a number in the log, not a guess; the filled pixels count in `from`'s `opaque_px` and `occluded_px` (the piece is drawn over them), never as visible or projected. The stage refuses: a file that is not there (`ASSEMBLE_UNDER_PRESENT`) or not a PNG (`ASSEMBLE_UNDER_DECODES`), an image not exactly the box's size (`ASSEMBLE_UNDER_SIZE`, both sizes given), an image that fills none of the removed pixels — all transparent there, or another file (`ASSEMBLE_UNDER_EMPTY`; to leave the whole hole, drop `under`), and a piece drawn behind `from` (`ASSEMBLE_UNDER_DRAW`: the fill would hide it; draw it `"front"` or `{"before": "<the plan part after from>"}`). Producing the image is the author's, by whatever means; absent, `from` keeps only its band |
|
|
94
99
|
| `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 |
|
|
95
|
-
| `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) 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 |
|
|
100
|
+
| `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 |
|
|
96
101
|
| `meshes.<part>.contour` | rig | **authored**, optional (issue #84): `{tolerance, margin, spacing, maxEdge?, budget?, stray?, regions?}`. `tolerance` — rig-c's Douglas–Peucker tolerance on the traced outline, px, 0 or more; `margin` — how far the silhouette grows before it is traced, px: 0, or 1 or more (a pixel joins when its centre lies within `margin` of an art pixel's centre; a value above 0 and below 1 adds nothing and is refused, `CONFIG_FIELD_TYPE`); `spacing` — the background interior spacing, px, above 0; `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); `regions` — local deformation regions, each `{name, shape, bone, spacing, band}` with `shape` `"circle"` (`cx, cy, r`) or `"polygon"` (`points`, 3 or more): `bone` is the region's control bone (any bone `bones` declares), `spacing` the interior spacing inside the region and its band, `band` the width the bone's weight falls across. Every length and position is **rig px**, like every other in the config; the part image is the rig less `(x − 4, y − 4)` (its box less the pad), a translation, so a length is the same number in both. A region's `cx`, `cy`, `r`, `band` and `points` are multiples of 1/256 px (`CONFIG_FIELD_TYPE` otherwise); region names are unique per mesh (`CONFIG_REGION_NAME_UNIQUE`). The alpha threshold is not a field: art is alpha above 8, the lattice's and `check`'s |
|
|
97
102
|
| `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 |
|
|
98
103
|
| `meshes.<part>.influences` | rig | **authored**, optional (issue #284), in the `grid` and `contour` modes: `{maxInfluences?, floor?}`, at least one. `maxInfluences` — the most bones that pull one vertex, a whole number 1 or more, or `null`, no cap (every bone the mesh's `segments` name; `null` is the config's spelling of a bound declared absent, as in `maxOvershoot` and `weightJump`); absent is 4. `floor` — `"cut"` (the capped shares normalised, any under 0.03 dropped, the rest normalised again; what an absent `floor` means) or `"continuous"` (0.03 subtracted from every capped share, those at or below 0 dropped, the rest normalised again, so a bone fades out of a vertex instead of leaving it in one step). Absent, the mesh is weighted at 4 and the cut and every byte is the one written before the field existed; declared, it applies under either `rule`, and is echoed as `influences` in the mesh's `mesh_report.json` row. `propose` never writes it, and `mesh-draft` carries a lattice's declaration to the contour candidate it drafts. A cap that is not a whole number 1 or more or `null` (the string `"none"` included), another `floor`, or an object naming neither is `CONFIG_FIELD_TYPE`; a vertex the declared cut leaves with no bone is `RIG_INFLUENCES_KEPT`; beside `auto` it is `CONFIG_INFLUENCES_MODE` (that mode's cap and floor are `auto.influences`). What each setting trades is "The weight cut" below |
|
|
104
|
+
| `meshes.<part>.stray` | rig | **authored**, optional (issue #303), in the `grid` mode: the largest island, in art pixels, that may be left out of the lattice — the contour mode's `contour.stray`, with the same meaning, over the same islands (the 4-connected islands of the art, alpha above 8): every island of `stray` art px or fewer is cleared from the art the lattice and, under `rule: "heat"`, its silhouette are built over, except an island as large as the largest, which is never left out (two equal largest pieces both stay). Unlike the contour mode an island above the figure is not refused — the lattice bridges every island it keeps, as it always has. An island that sits in a cell the lattice keeps for other art leaves the lattice unchanged: there `stray` changes only the silhouette `rule: "heat"` reads, and gives back no triangle (demo `bottomwear`'s 2 px island, in the cell kept for the hem's tip, is that case). Absent, nothing is left out and every byte is the one written before the field existed; a figure that leaves nothing out changes no byte of `rig.json` or `motion.json`. The part's image is not touched: a pixel left out stays in it, and is drawn only where a cell kept for other art happens to cover it; `art_coverage` is over all the art, the islands left out included. Declared, the mesh's `mesh_report.json` row echoes `stray` and adds `stray_cleared` (`islands`, `pixels`, `art_pixels`, after `influences`), and the rig stage's mesh line ends `stray <n> left out <i> island(s), <p> of <a> art px`. A value that is not a whole number from 0 is `CONFIG_FIELD_TYPE`; beside `contour` or `auto` it is `CONFIG_STRAY_MODE` (those modes state it in `contour.stray` and `auto.source.stray`). `propose` and `mesh-draft` never write it |
|
|
99
105
|
| `regions.<part>` | rig | **proposed**: the bone a rigid part rides. Every plan part is exactly one of a mesh or a region (`CONFIG_PART_ATTACHED`) |
|
|
100
106
|
| `motion.duration` | rig; check (the loop is measured at this time) | proposed as 40 frames at 12 fps, `40/12` s, written `3.3333333333333335` (issue #252; the reference proposed 4 s, and every period it drafted is scaled with it so each track keeps its cycles per idle); a whole number of 1/12 s ticks, because `check` renders at 12 fps and compares frame 0 with the frame at this time — read within 10^-9 s (`TIME_SLACK`, issue #244), since a whole number of frames is often not exact in binary: rigc's 40th frame sits at `40 × (1/12)` = `3.333333333333333`. Half a frame off is `CHECK_LOOP_LAST_FRAME_AT_DURATION` |
|
|
101
107
|
| `motion.tracks` | rig | **proposed**, then tuned. Single `{bone, prop, amp, period, phase, base?}` or chain `{chain, amps, period, phase, lag}` — one amplitude per link, link `i` at phase `phase + lag·i`. Every `period` must divide `duration` (`CONFIG_PERIOD_DIVIDES_DURATION`). A bone property is keyed by one track (`CONFIG_BONE_PROPERTY_KEYED_ONCE`): a chain keys `rotate` on every link, the blink's `eyes` group `scaley` and its `brows` group `translatey` on every member, so a single track on any of those is a second track on it — rigc would refuse it one stage later, `animation "idle" has two tracks on eye.scaley`. The proposed breath (issues #252, #270) is `chest` `translatey` travelling 2.5 % of the torso's length peak to peak — the distance from the `neck` bone to the `hip` bone as the proposal writes them, the run the chest sits half way along, whichever rule placed them — (amplitude half of it to two decimals, `base` the amplitude, so the chest rises from the setup pose and returns); the `breath:` note prints the fraction, the length, the two bones and the pixels. Until #270 it was 2.5 % of the `topwear` part's height, and a sweater to the thighs (`scarf`, 690 px) breathed 2.9 times as deep as `demo`; on neck → hip `scarf` reads 431 px (10.78 px) and `demo` 192 px (4.80 px). Neck and hip on one point: no length to scale by, so the breath keeps the reference's amplitude 1.3 (2.6 px peak to peak) and the note says so — scale it to the figure. `chest` `scalex` and the `head` and `neck` rolls are a ratio and angles and are proposed the same on every figure. A chain link is turned along its chain (the `bones` row), so a `translatex`/`translatey` key on a bone whose parent is a turned link, or a `scale`/`shear` key on a turned link, would move or stretch along the link and not along the picture's axis: the rig stage refuses it (`RIG_KEY_FRAME_UNTURNED`); `rotate` is keyed on any bone |
|
|
@@ -181,10 +187,58 @@ template the proposer wrote before issue #249 fires it on any head tilted more t
|
|
|
181
187
|
degrees (the trailer character, 23.7 degrees: all six links; `reference-demo`, 3.2
|
|
182
188
|
degrees, and `reference-sample`, -4.9 degrees: one link each).
|
|
183
189
|
|
|
184
|
-
**
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
190
|
+
**Two chains on one lattice (issue #314).** `lint` swings every pair of chains a lattice
|
|
191
|
+
mesh's `segments` both name, both keyed by a chain track, on the rig stage's own lattice and
|
|
192
|
+
weights (`src/squeeze.ts`: the part padded as the rig stage pads it, `latticeMesh`, and
|
|
193
|
+
`influences` under the mesh's `r`, `exponent`, `influences` and `stray`, rounded as the
|
|
194
|
+
lattice rounds — so its vertex and triangle numbers are the ones `rig.json` and `check`
|
|
195
|
+
use). Each link turns as the idle's sine states it at every frame `check` renders, every
|
|
196
|
+
other bone held at the setup pose, and each edge is read by `check`'s own reader. A pair
|
|
197
|
+
whose worst edge is past `TEXTURE_STRETCH`'s bar (max(ratio, 1/ratio) above 1.926544)
|
|
198
|
+
prints
|
|
199
|
+
`LINT <a> and <b> on mesh '<part>' squeeze it: swung together, every other bone held, edge <i>-<j> of triangle <t> closes to <r> times its rest length at idle frame <f> (max(ratio, 1/ratio) <s>; <= 1.926544 is required, check's TEXTURE_STRETCH bar) — vertex <i> rides <bone> <w>, vertex <j> rides <bone> <w>; alone, <a> reads <x> and <b> <y>. Their tips are <d> px apart and …`
|
|
200
|
+
(`stretch it` and `opens` when the edge grows). The end names the amplitudes and the
|
|
201
|
+
remedies whose own figure passes the bar: with the two chains' amplitudes opposed link for
|
|
202
|
+
link, `give both the same sign (then <s'>)` — `<s'>` the same reading with the second
|
|
203
|
+
chain's signs turned; `drop one chain` when each alone passes, or `drop <b>, which alone is
|
|
204
|
+
past the bar too` when only one does; and, when none passes,
|
|
205
|
+
`lower the amplitudes`. A contour or automatic mesh, or `rule: "heat"`, is not rebuilt here:
|
|
206
|
+
a `note: squeeze not read: …` line names the mesh and its pairs. What it predicts is
|
|
207
|
+
`check`'s measurement without the other bones' motion. Measured: on `fixtures/squeeze.ts`
|
|
208
|
+
(two chains 39 px apart at their tips, the proposer's mirrored back-hair amplitudes) it
|
|
209
|
+
names the triangle, edge and frame `check` fails, 2.494 predicted against 2.488 measured,
|
|
210
|
+
and one sign passes both (1.054); on the four public examples it prints nothing; on
|
|
211
|
+
`reference-demo` the back-hair pair reads 1.393 at `hair_back` edge 43-42, frame 26 — the
|
|
212
|
+
edge and frame `check` reports as that example's worst, 1.388, the figure the bar is the
|
|
213
|
+
square of — and 1.075 with one sign; on `reference-sample` the sleeve pair reads 1.230 at
|
|
214
|
+
the edge and frame `check` reads 1.227 at.
|
|
215
|
+
|
|
216
|
+
**Why the back hair mirrors.** The proposer drafts `hairback_r` with amplitudes
|
|
217
|
+
`[0.6, 1.4, 2.4]` and `hairback_l` with their negatives, while the fringe, lock and skirt chains share one sign (the two sleeve chains are mirrored
|
|
218
|
+
the same way). The mirror is the reference proposer's draft,
|
|
219
|
+
ported as it was (`src/propose.ts`, `SIDES`); no reason is recorded with it. Opposed, the
|
|
220
|
+
two tips swing towards each other and apart on the same beat. On two hanks far apart that
|
|
221
|
+
costs nothing a bar reads (`demo`, tips 371 px apart: 1.050 for the pair, as for either
|
|
222
|
+
alone), and on one mass with the two chains close it squeezes the lattice between them
|
|
223
|
+
(issue #314: tips 39 px apart, an edge at 0.065 of its rest length). Whether the hair is one
|
|
224
|
+
mass is not something the proposer can read off the opaque shape — both chains always hang
|
|
225
|
+
on the one `back hair` part — so the draft is unchanged and the squeeze is measured instead,
|
|
226
|
+
by the lint above.
|
|
227
|
+
|
|
228
|
+
**A posed figure: `propose --keypoints`.** Without joints the proposer reads the
|
|
229
|
+
torso by screen y: the hip 0.14 face heights below `bottomwear`'s top edge (or below
|
|
230
|
+
the waist: *The hip*, below), the chest half way up to the neck, sleeves hanging from the
|
|
231
|
+
shoulders. A figure whose joints are not where those rules put them — a reclining
|
|
232
|
+
figure, an arm raised or crossed, or a seated figure whose skirt does not start at
|
|
233
|
+
the hip — is told where its joints are with one explicit file (issue #75,
|
|
234
|
+
`src/keypoints.ts`). Sitting alone does not call for it: a seated figure whose skirt
|
|
235
|
+
starts at the waist has its hip there (issue #314: a seated character proposed without
|
|
236
|
+
joints, its hip placed and `lint` clean, built green once its back-hair chains were
|
|
237
|
+
fixed). But a clean `lint` does not say the hip is right: the screen-y rules ask only
|
|
238
|
+
that the hip be below the chest and below 0.25 of the figure's height, and a hip at a
|
|
239
|
+
seated skirt's top passes both (selftest `PR56`: the rule's hip 28 px above where the
|
|
240
|
+
thighs leave the torso, no LINT line) — read the overlay, and where the hip or a sleeve
|
|
241
|
+
is off its joint, give the joints. A pose file named by
|
|
188
242
|
`generation.control.skeleton` is not that file and is not offered as its default:
|
|
189
243
|
the control skeleton is what was asked of the model, not where the joints ended up
|
|
190
244
|
(a consumer measured a generated picture not following the control's raised hand),
|
|
@@ -396,7 +450,7 @@ The default does not move; a fold is today found by looking at a build that pass
|
|
|
396
450
|
bar, and this field is what there is to turn once one is seen.
|
|
397
451
|
|
|
398
452
|
**What it trades.** Every figure below is issue #284 Stage E's, verbatim from
|
|
399
|
-
[`docs/evidence/weight-cap.md`](evidence/weight-cap.md), on every lattice mesh of `demo`,
|
|
453
|
+
[`docs/evidence/weight-cap.md`](https://github.com/rig-c/parts/blob/main/docs/evidence/weight-cap.md), on every lattice mesh of `demo`,
|
|
400
454
|
`scarf` and the trailer (`rig-c/trailer` at a99d976): the inverted triangles at the bend
|
|
401
455
|
sets (±15° on every chain link; on the trailer also ± the film's own bends, after the
|
|
402
456
|
slash), the largest idle displacement against today's rig in rig px (the part in the
|
|
@@ -444,6 +498,48 @@ contour region is (each share to 5 places, a 0 dropped, the remainder to the hea
|
|
|
444
498
|
the cut it is rounded as the lattice always was. In the contour mode a region's bone counts
|
|
445
499
|
toward the cap like any other (*The vertex's weights* in `src/localweights.ts`).
|
|
446
500
|
|
|
501
|
+
### Which mode comes out smaller (issue #307)
|
|
502
|
+
|
|
503
|
+
The names suggest that `auto`, the mode that reduces a mesh, is the smallest. Measured on one
|
|
504
|
+
figure, it is not always: a reduction held to a large declared bend keeps many vertices to stay
|
|
505
|
+
near its dense source, and on such a part the outline `mesh-draft` drafts over a coarse grid
|
|
506
|
+
came out two to three times lighter. On parts that bend little, `auto` was far the smallest.
|
|
507
|
+
|
|
508
|
+
The figure is the trailer's (`rig-c/trailer`, 1108 px tall). Triangles per part, as the rig
|
|
509
|
+
stage's `mesh` lines print them: the kept modes from commit 45becfb; the `auto` counts of the
|
|
510
|
+
three parts that left it from the commit before, 24bd8ec (each `auto` with the film's bends
|
|
511
|
+
declared as `auto.stimulus` and `auto.motion.maxLocalDeformation` 3 px); the lattice column each
|
|
512
|
+
part at `"grid": 30`, the spacing `propose` drafts for this figure, in 45becfb's config
|
|
513
|
+
(`topwear` left on `auto`); and `mesh-draft` run over that lattice config. The bends are the
|
|
514
|
+
largest turns the trailer's `WORKING.md` states for its film, not re-measured here.
|
|
515
|
+
|
|
516
|
+
| part | the film bends it | `auto`, bends declared, 3 px | `mesh-draft` | lattice at `"grid": 30` |
|
|
517
|
+
| --- | --- | --- | --- | --- |
|
|
518
|
+
| `bottomwear` | 24° | 276 | 132 | 140 |
|
|
519
|
+
| `handwear_r` | 33° | 148 | 49 | 52 |
|
|
520
|
+
| `hairpin` | 95° (refused by `auto`; `contour` at its own spacing 13: 120) | — | 47, kept on its lattice (below) | 46 |
|
|
521
|
+
| `legwear` | 12° | 77 | — | 176 |
|
|
522
|
+
| `hair_back` | a few degrees | 28 | — | 120 |
|
|
523
|
+
| `handwear_l` | 4° | 31 | — | 72 |
|
|
524
|
+
| `neck` | — | 7 | — | 12 |
|
|
525
|
+
| `hair_front` | 11° | 112 | — | 114 |
|
|
526
|
+
|
|
527
|
+
Every count reproduces with `@rig-c/parts` 1.11.0 and rig-c 2.47.0 (the trailer's pins at
|
|
528
|
+
45becfb, both configs over the same assembled parts), and the lattice and `mesh-draft` columns
|
|
529
|
+
again with this package on rig-c 2.40.0. `mesh-draft` kept the hairpin on its lattice: its
|
|
530
|
+
candidate, 47 triangles, sat 1.055 rig px from the lattice over the idle against a line of 1, and
|
|
531
|
+
had one triangle more than the lattice's 46 (with the hairpin's lattice declaring
|
|
532
|
+
`influences: {floor: "continuous"}`, as 45becfb's contour entry does, the idle reads 0.822 and
|
|
533
|
+
passes, and the triangle line alone keeps it). The trailer's 47 is that candidate, written by
|
|
534
|
+
hand. The film's two cuts were compared at their most different frame, enlarged; no difference
|
|
535
|
+
showed, and every `check` bar passed on both.
|
|
536
|
+
|
|
537
|
+
So, before keeping an `auto` entry on a part a chain or physics bends far: build the part once on
|
|
538
|
+
a lattice, run `mesh-draft` (§4, step 12), and compare the two `mesh` lines. Nothing else reports
|
|
539
|
+
the difference; `mesh-draft` names every `auto` or `contour` entry as not compared, because it
|
|
540
|
+
drafts lattice entries only. This is one figure, and the two examples here were not measured this
|
|
541
|
+
way.
|
|
542
|
+
|
|
447
543
|
### A contour mesh (`meshes.<part>.contour`, issue #84)
|
|
448
544
|
|
|
449
545
|
The lattice keeps every grid cell that holds an art pixel, so its boundary and its interior
|
|
@@ -1054,7 +1150,7 @@ file in rig-c's motion-spec shape beside the config and name it:
|
|
|
1054
1150
|
```
|
|
1055
1151
|
|
|
1056
1152
|
`build` writes `surprised` into `rig/motion.json` after `idle`, gates it with the rig, and
|
|
1057
|
-
`check` names it on a line of its own (`examples/reference-sample` carries one, `animations.json` with `hop`, the
|
|
1153
|
+
`check` names it on a line of its own ([`examples/reference-sample`](https://github.com/rig-c/parts/tree/main/examples/reference-sample), in the repository, carries one, `animations.json` with `hop`, the
|
|
1058
1154
|
recipe below). With exactly this file beside `examples/reference-sample`'s config in its place,
|
|
1059
1155
|
`build` printed (this tree, rig-c as `package.json` pins it):
|
|
1060
1156
|
|
|
@@ -1067,10 +1163,10 @@ recipe below). With exactly this file beside `examples/reference-sample`'s confi
|
|
|
1067
1163
|
A bone the rig lacks is rigc's refusal at the rig stage, in rigc's words (`RIG_RIGC_GREEN`); a
|
|
1068
1164
|
fault in the file itself is the loader's (the row above names each one).
|
|
1069
1165
|
|
|
1070
|
-
**Worked sets.** `examples/demo/animations.json` and `examples/scarf/animations.json`
|
|
1071
|
-
(issue #224) carry `tilt`, `look_l`, `look_r`, `smile`, `startled`, a gesture (`wave` on
|
|
1166
|
+
**Worked sets.** [`examples/demo/animations.json`](https://github.com/rig-c/parts/blob/main/examples/demo/animations.json) and [`examples/scarf/animations.json`](https://github.com/rig-c/parts/blob/main/examples/scarf/animations.json)
|
|
1167
|
+
(issue #224; in the repository, not the package) carry `tilt`, `look_l`, `look_r`, `smile`, `startled`, a gesture (`wave` on
|
|
1072
1168
|
`demo`, `bow` on `scarf`) and `hop`, each a one-shot that keys only what it needs; the
|
|
1073
|
-
examples' READMEs list what each keys and why. Two rules make a clip layer over the idle on
|
|
1169
|
+
examples' READMEs ([demo](https://github.com/rig-c/parts/blob/main/examples/demo/README.md), [scarf](https://github.com/rig-c/parts/blob/main/examples/scarf/README.md)) list what each keys and why. Two rules make a clip layer over the idle on
|
|
1074
1170
|
a player's second track rather than replace it:
|
|
1075
1171
|
|
|
1076
1172
|
- **Key the bones the idle leaves alone.** The idle turns and breathes the `*_ctl` bones
|
|
@@ -1083,10 +1179,33 @@ a player's second track rather than replace it:
|
|
|
1083
1179
|
|
|
1084
1180
|
**Strands that trail.** A chain whose links lag the body is one `physics` constraint per
|
|
1085
1181
|
link in `constraints`, on the link bone (`hairback_r0`, not `hairback_r0_ctl`), driving
|
|
1086
|
-
`rotate`; the examples soften it down the chain
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1182
|
+
`rotate`; the examples soften it down the chain: every link takes the root link's `inertia`,
|
|
1183
|
+
`damping`, `mass` and `mix`, and link i of n (i = 0 at the root) takes the root link's `strength` times
|
|
1184
|
+
1 − 0.35 · i / (n − 1), so the last link is the softest at 0.65 of the root's. `demo`'s right
|
|
1185
|
+
twin tail, the three links of chain `hairback_r`, as
|
|
1186
|
+
[`examples/demo/config.json`](https://github.com/rig-c/parts/blob/main/examples/demo/config.json) (in the repository)
|
|
1187
|
+
holds it:
|
|
1188
|
+
|
|
1189
|
+
```json
|
|
1190
|
+
"constraints": [
|
|
1191
|
+
{ "type": "physics", "name": "hairback_r0_phys", "bone": "hairback_r0", "rotate": 1, "inertia": 0.8, "strength": 90.0, "damping": 0.85, "mass": 1, "mix": 1 },
|
|
1192
|
+
{ "type": "physics", "name": "hairback_r1_phys", "bone": "hairback_r1", "rotate": 1, "inertia": 0.8, "strength": 74.25, "damping": 0.85, "mass": 1, "mix": 1 },
|
|
1193
|
+
{ "type": "physics", "name": "hairback_r2_phys", "bone": "hairback_r2", "rotate": 1, "inertia": 0.8, "strength": 58.5, "damping": 0.85, "mass": 1, "mix": 1 },
|
|
1194
|
+
… ]
|
|
1195
|
+
```
|
|
1196
|
+
|
|
1197
|
+
`scarf`'s scarf ends, four links each, take the same shape at inertia 0.7: `strength` 70,
|
|
1198
|
+
61.8333, 53.6667 and 45.5 down `robe_r` ([`examples/scarf/config.json`](https://github.com/rig-c/parts/blob/main/examples/scarf/config.json)).
|
|
1199
|
+
What these values do, measured on the clips and not by any bar: in `demo`'s `hop` the last
|
|
1200
|
+
link of each tail sat 46.6 and 45.3 rig px from where the keys put it relative to `head` at
|
|
1201
|
+
the landing (0.73 s); inertia 1 tore `hair_back` in that hop (`TEXTURE_STRETCH` 3.258 against
|
|
1202
|
+
1.926544), and lowering `strength` instead of raising inertia saturates (the demo README,
|
|
1203
|
+
*The strands*). A single bone with no `length` (a bow, an earring, a bun) cannot take a
|
|
1204
|
+
`rotate` drive (rig-c's `A23`) and takes `x`/`y` instead — `demo`'s bows `"x": 0.5, "y": 1`,
|
|
1205
|
+
inertia 0.3, strength 160. The values that read on the examples, and the ones refused on the
|
|
1206
|
+
way there, are in their READMEs, in the repository:
|
|
1207
|
+
[`examples/demo/README.md`](https://github.com/rig-c/parts/blob/main/examples/demo/README.md) and
|
|
1208
|
+
[`examples/scarf/README.md`](https://github.com/rig-c/parts/blob/main/examples/scarf/README.md).
|
|
1090
1209
|
|
|
1091
1210
|
**Limits.** Every slot holds one attachment, the part's own image, so an expression moves,
|
|
1092
1211
|
turns and scales the face's parts and never swaps one for another: there is no second mouth
|
|
@@ -1101,7 +1220,7 @@ against 1.926544).
|
|
|
1101
1220
|
|
|
1102
1221
|
A jiggle (a bust, the hips) is a patch of one part that lags behind the body. The package
|
|
1103
1222
|
proposes none and judges none; what it gives is the three pieces to build one, all in the
|
|
1104
|
-
config. `examples/reference-sample` carries a worked one (issue #183, PR #187), and its config is the
|
|
1223
|
+
config. [`examples/reference-sample`](https://github.com/rig-c/parts/tree/main/examples/reference-sample) carries a worked one (issue #183, PR #187), and its config is the
|
|
1105
1224
|
fragment below, cut to the bust:
|
|
1106
1225
|
|
|
1107
1226
|
```jsonc
|
|
@@ -1154,10 +1273,12 @@ idle moves the bust at most 0.066 rig px, idle frame 2). Faster keys on the pare
|
|
|
1154
1273
|
a turn, in a named animation (the recipe above) or a consumer's own — are what the spring
|
|
1155
1274
|
answers. `reference-sample`'s `animations.json` holds one, `hop` (1 s: `hip` `translate` y down 5, up 24,
|
|
1156
1275
|
landing at -6 at 0.45 s, settling at 0.55 s; nothing keys the jiggle bones): rendered at 30 fps
|
|
1157
|
-
against the same build without its constraints, the bust moves at most 6.
|
|
1158
|
-
(`hip_phys` inertia 0.2, strength 160, damping 0.88, mass 1.5) at most 4.
|
|
1159
|
-
|
|
1160
|
-
|
|
1276
|
+
against the same build without its constraints, the bust moves at most 6.702 rig px and the hips
|
|
1277
|
+
(`hip_phys` inertia 0.2, strength 160, damping 0.88, mass 1.5) at most 4.609 (frame 14, at the
|
|
1278
|
+
landing), and both overshoot after it, 3.27 and 1.35 rig px (frames 21 and 22). These are rig-c
|
|
1279
|
+
2.45.2's renders, whose physics no longer ends a frame on a step's tie; on rig-c 2.40.0 the same
|
|
1280
|
+
build read 6.583 and 4.432 (frame 13) and 3.38 and 1.38, which
|
|
1281
|
+
[`docs/evidence/sample-hop.png`](https://github.com/rig-c/parts/blob/main/docs/evidence/sample-hop.png) shows. No bar here judges the jiggle, and two limits follow from that:
|
|
1161
1282
|
|
|
1162
1283
|
- **The region's `band` caps the displacement.** The patch moves as one piece and the band is
|
|
1163
1284
|
where the mesh stretches to follow it, so physics values that carry the patch further than
|
|
@@ -1166,8 +1287,8 @@ into the landing), and both overshoot after it, 3.38 and 1.38 rig px (frames 21
|
|
|
1166
1287
|
geometry with PR #187's values (inertia 0.5, strength 100, damping 0.85, mass 1, a bone
|
|
1167
1288
|
displacement of 9.85 rig px against bands of 16 and 12) gives
|
|
1168
1289
|
`CHECK_TEXTURE_STRETCH: mesh "bottomwear" triangle 13 (vertices 5 183 6), edge 6-5, idle frame 13 — the edge is 0.233 times its rest length (max(ratio, 1/ratio) 4.29); <= 1.926544 is required`
|
|
1169
|
-
and `topwear` 2.597; with the values tracked now it reads 1.
|
|
1170
|
-
(`bottomwear`). Tune the constraint against the animation that drives it, not the idle.
|
|
1290
|
+
and `topwear` 2.597; with the values tracked now it reads 1.719 (`topwear`) and 1.602
|
|
1291
|
+
(`bottomwear`) (1.697 and 1.566 on rig-c 2.40.0, before 2.45.2's render clock). Tune the constraint against the animation that drives it, not the idle.
|
|
1171
1292
|
|
|
1172
1293
|
#### A part only physics moves, in the automatic mode
|
|
1173
1294
|
|
|
@@ -1252,8 +1373,26 @@ full loader before its assemble stage writes anything.
|
|
|
1252
1373
|
6. `rig-parts assemble --propose-plan --source … --full … --head … --config config.json`
|
|
1253
1374
|
→ paste `plan` and `extend_below_crop` into `config.assemble`. Config: the
|
|
1254
1375
|
`layers` row, with `head_box`.
|
|
1255
|
-
Read `notes`:
|
|
1256
|
-
|
|
1376
|
+
Read `notes`: every layer not planned — each tag a layer of either run holds that no
|
|
1377
|
+
row takes — is named there once, `<tag>: in no plan row — …`, with why, run by run: the
|
|
1378
|
+
run holds no such layer; the proposer takes that tag from the other run only
|
|
1379
|
+
(`PROPOSE_HEAD_TAGS` in `src/assemble.ts` lists the tags it takes from the head run,
|
|
1380
|
+
and every other tag comes from the full run); the layer is empty, its opaque count (run
|
|
1381
|
+
pixels of alpha above 8 after ghost clean-up) below the proposer's floor of 150
|
|
1382
|
+
(`PROPOSE_MIN_PX`, `src/assemble.ts`); or it crosses a plausibility rule, and the
|
|
1383
|
+
layer's own note, last, gives its figures and the rule (§6, *Plausibility*; a layer
|
|
1384
|
+
only such a note leaves out is named by it alone). On the four examples the
|
|
1385
|
+
`neckwear`, `tail`, `wings`, `objects` and `eyewear` layers hold 62 to 74 px in each
|
|
1386
|
+
run, so each is named empty (or taken from the other run only). `nose` is never
|
|
1387
|
+
planned — the reference implementation's rule, which this port keeps; the reference
|
|
1388
|
+
records no reason — and its note gives both runs' counts and what a nose part buys:
|
|
1389
|
+
`propose`'s `head pitch:` note reads where the nose sits between the eye midpoint and
|
|
1390
|
+
the mouth only off a part tagged `nose`, so the note names the row to add,
|
|
1391
|
+
`["nose", "head", "nose"]` after the row that takes `face` (the run whose layer holds
|
|
1392
|
+
more of the nose). With that one row added to a copy of each config, `demo` reads
|
|
1393
|
+
0.474 and `scarf` 0.564 (the figures `FRONTAL_REFERENCE` in `src/propose.ts` quotes),
|
|
1394
|
+
and the recomposite moves by 2 error px on `demo` (14,570 to 14,568) and none on
|
|
1395
|
+
`scarf`, uncovered error px unchanged on both. A full-run layer holding a body
|
|
1257
1396
|
no planned part covers — long hair that leaves the head crop sideways, or a
|
|
1258
1397
|
head-run part that stops above the crop line so `extend_below_crop` continues
|
|
1259
1398
|
nothing — is named with the body, the rule that skipped it and the two
|
|
@@ -1305,7 +1444,10 @@ full loader before its assemble stage writes anything.
|
|
|
1305
1444
|
rules for `bones`, `meshes`, `regions` and `motion`.
|
|
1306
1445
|
9. `rig-parts build --config config.json --source inputs/painting.png --full … --head … --out out [--loop]`
|
|
1307
1446
|
— assemble, rig and check in one process. `propose` is not part of it, on purpose:
|
|
1308
|
-
a proposal is a draft, and the config you corrected is the input.
|
|
1447
|
+
a proposal is a draft, and the config you corrected is the input. How long it takes
|
|
1448
|
+
is §8 (the two reference examples, 12.7 s and 27.5 s wall clock on one machine): a
|
|
1449
|
+
run your harness stopped before its last line printed no verdict, which is not a
|
|
1450
|
+
failed build — the build's verdict is its `check:` line or a named refusal (§5, §6).
|
|
1309
1451
|
`--idle-keys direct` is forwarded to the rig stage as `rig` takes it; a config
|
|
1310
1452
|
with a two-bone ik over chain links the idle keys needs it (§3, `constraints`).
|
|
1311
1453
|
Every flag `check` takes is forwarded to the check stage, taken by `build` as
|
|
@@ -1373,7 +1515,10 @@ full loader before its assemble stage writes anything.
|
|
|
1373
1515
|
The two divisors are calibrated on three figures of similar size (1106 to
|
|
1374
1516
|
1185 px), and the bend set is a calibration, not your animation: a chain
|
|
1375
1517
|
your animations or physics bend further than 15° a link was not measured
|
|
1376
|
-
there. An `auto` or `contour` entry is yours and is left as it is
|
|
1518
|
+
there. An `auto` or `contour` entry is yours and is left as it is, and it
|
|
1519
|
+
is compared with nothing: a `NOT COMPARED` line and the report's
|
|
1520
|
+
`not_compared` name each such part, since which mode comes out smaller is
|
|
1521
|
+
measured, not named (§3, *Which mode comes out smaller*; issue #307). A
|
|
1377
1522
|
relative `motion.animations_from` or `generation.control.skeleton` keeps its
|
|
1378
1523
|
text, so it resolves against `draft/`; the command says so.
|
|
1379
1524
|
|
|
@@ -1387,7 +1532,7 @@ proposal in as the steps above say (`RL01`); every step must exit 0.
|
|
|
1387
1532
|
| --- | --- | --- | --- |
|
|
1388
1533
|
| `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*) |
|
|
1389
1534
|
| `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 |
|
|
1390
|
-
| `assemble` | one line per part, the `pixels:` totals (opaque = visible + occluded; taken; visible but not projected), then `recomposite vs source: mean \|d\|, within 8, error px > 40, uncovered error px`, then `uncovered holes (8-connected): N` and the largest five as `uncovered hole K: <px> px at x,y wxh (between "<part>" <px> px, …)`, then one `uncovered: <n> of the <N> uncovered error px lie on the full run's "<tag>", in a body of <px> px at x,y wxh; <the rule that left it out>` line per full-run layer the plan does not take from the full run whose uncovered error holds a body (5x5-opened, 8-connected, at least 150 full-run px in rig px), 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) |
|
|
1535
|
+
| `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) |
|
|
1391
1536
|
| `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 |
|
|
1392
1537
|
| `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 |
|
|
1393
1538
|
| `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` |
|
|
@@ -1396,6 +1541,14 @@ proposal in as the steps above say (`RL01`); every step must exit 0.
|
|
|
1396
1541
|
| `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 |
|
|
1397
1542
|
| `loop` (inside `build --loop`, or `loop --frames … --out …`) | the dropped-duplicate line (under `build --lead-in`, the lead-in line in its place: the frames kept and the jump at the wrap), each file's line, then `loop: idle.png N B (lossless); idle-indexed.png N B (max …, mean …); idle.gif N B (max …, mean …)` | `f0048.png equals f0000.png byte for byte, so it is dropped` | `LOOP_ENCODE` (§6) |
|
|
1398
1543
|
|
|
1544
|
+
`RECOMPOSITE_HOLES` is `REPORTED`, never judged, and its count reads large: for scale, the
|
|
1545
|
+
four examples, each a green build, report 259 (`reference-sample`), 291 (`scarf`), 453
|
|
1546
|
+
(`reference-demo`) and 1,020 (`demo`) uncovered holes, holding 1,185, 1,365, 1,564 and
|
|
1547
|
+
2,939 uncovered error px, the largest hole 94, 63, 70 and 48 px (each example's
|
|
1548
|
+
`expected/parts.json`, its `recomposite` block, in the repository) — hundreds of slivers
|
|
1549
|
+
along part edges are what a green build reports; one hole of hundreds of px is the red
|
|
1550
|
+
the `assemble` row above describes.
|
|
1551
|
+
|
|
1399
1552
|
`loop` writes three files from one frame set, and they are not interchangeable.
|
|
1400
1553
|
`idle.png` (`loop --out x.png`) is the lossless APNG: every frame decodes to the
|
|
1401
1554
|
rendered frame byte for byte, so it is the exactness record. `idle-indexed.png`
|
|
@@ -1406,8 +1559,10 @@ entry, no dithering, filter None) — and is the small file to show. `idle.gif`
|
|
|
1406
1559
|
print their palette error, per channel over R, G and B of every frame (and alpha's
|
|
1407
1560
|
max for the APNG); a figure is a measurement of the file, not a bar. On the demo
|
|
1408
1561
|
(the README's animation since issue #224's follow-up: `build --loop --lead-in 3`), with
|
|
1409
|
-
the breath of issue #270 (2.5 % of neck -> hip, 4.80 px peak to peak): 4,
|
|
1410
|
-
|
|
1562
|
+
the breath of issue #270 (2.5 % of neck -> hip, 4.80 px peak to peak): 4,449,233 B lossless,
|
|
1563
|
+
703,909 B indexed and 760,058 B GIF, both palette files at max 71, mean 0.636 (rig-c 2.45.2
|
|
1564
|
+
and later, whose render no longer ends a frame on a physics step's tie; on rig-c 2.40.0,
|
|
1565
|
+
4,446,263, 704,009 and 760,294 B at max 70, mean 0.631); on the
|
|
1411
1566
|
40-frame idle of issue #252 (rig-c 2.40.0, the breath 2.5 % of the topwear's height, 5.92 px):
|
|
1412
1567
|
4,514,756 B lossless, 725,845 B indexed and 784,074 B GIF, at the same error; on the 4 s idle before it
|
|
1413
1568
|
(rig-c 2.33.0): 5,148,992, 727,486 and 781,526 B at max 69, mean 0.630 — the two share one quantiser, so their error is the same by
|
|
@@ -1424,7 +1579,7 @@ renders the idle played n + 1 times back to back (`idle_lead_in`, the build's ot
|
|
|
1424
1579
|
animations kept so the viewport is fitted as for the idle frames), keeps the last
|
|
1425
1580
|
period, drops its end frame (the next period's first) and prints how far that end frame
|
|
1426
1581
|
is from the first kept one — the jump the loop will show. The settling is the rig's, not
|
|
1427
|
-
a constant: on the demo's 4 s idle, `--lead-in 1` and `2` each still read max |d| 117, 305 px over 40, and `3` reads max 1, 0 px over 40; on its 40-frame idle (issue #252, a shorter period and a breath twice as far), `3` reads max
|
|
1582
|
+
a constant: on the demo's 4 s idle, `--lead-in 1` and `2` each still read max |d| 117, 305 px over 40, and `3` reads max 1, 0 px over 40; on its 40-frame idle (issue #252, a shorter period and a breath twice as far), `3` reads max 1, 0 px over 40 (max 7 before rig-c 2.45.2, whose render no longer ends a frame on a physics step's tie). The idle
|
|
1428
1583
|
must repeat without an invented value — every track keyed from 0 to the duration, ending
|
|
1429
1584
|
where it starts — or the build refuses it (`LOOP_LEAD_IN_IDLE`). `check` and its bars
|
|
1430
1585
|
read `check/idle_frames/` as before; only the loop files move. On reference-demo with `--seam silhouette`
|
|
@@ -1844,6 +1999,7 @@ See-through with another seed.
|
|
|
1844
1999
|
| `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` |
|
|
1845
2000
|
| `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` |
|
|
1846
2001
|
| `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` |
|
|
2002
|
+
| `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` |
|
|
1847
2003
|
| `CONFIG_PATCH_BOX` | an `assemble.patches` box with `x1 <= x0` or `y1 <= y0` | that patch's `box` (`x1`, `y1` are exclusive) |
|
|
1848
2004
|
| `CONFIG_AMPS_MATCH_CHAIN` | a chain track's `amps` is not one per link | that track's `amps` |
|
|
1849
2005
|
| `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` |
|
|
@@ -1967,7 +2123,7 @@ exits 0, and `mesh_draft.json` and the console name the reading and the amount.
|
|
|
1967
2123
|
| `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) |
|
|
1968
2124
|
| `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 |
|
|
1969
2125
|
| `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 |
|
|
1970
|
-
| `CHECK_TEXTURE_STRETCH` | a mesh triangle's edge, in some idle frame, is more than 1.926544 times its rest length or less than 1/1.926544 of it (the mesh, triangle, its three vertices, the edge and the frame are named); or a rest edge has length 0 | the chain tracks' `amps` on the bones that mesh is weighted to (the stretch grows with them), or the mesh's `segments` — a vertex blending two bones that swing against each other |
|
|
2126
|
+
| `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*) |
|
|
1971
2127
|
| `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 |
|
|
1972
2128
|
| `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 |
|
|
1973
2129
|
| `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 |
|
package/docs/STABILITY.md
CHANGED
|
@@ -124,7 +124,7 @@ part name, `[i]` an entry of a list):
|
|
|
124
124
|
- **assemble.cuts[i].draw**, when an object — required: `before`
|
|
125
125
|
- **bones[i]**, a single bone — required: `name`, `parent`, `at`; optional: `tip`
|
|
126
126
|
- **bones[i]**, a chain — required: `chain`, `parent`, `points`, `tip`
|
|
127
|
-
- **meshes.<part>** — exactly one of `grid`, `contour`, `auto`; required in every mode: `r`, `segments`; optional in every mode: `exponent`, `rule`; optional with `contour` or `auto`: `ribs`; optional with `grid` or `contour`: `influences` (issue #284; beside `auto` it is refused, CONFIG_INFLUENCES_MODE)
|
|
127
|
+
- **meshes.<part>** — exactly one of `grid`, `contour`, `auto`; required in every mode: `r`, `segments`; optional in every mode: `exponent`, `rule`; optional with `contour` or `auto`: `ribs`; optional with `grid` or `contour`: `influences` (issue #284; beside `auto` it is refused, CONFIG_INFLUENCES_MODE); optional with `grid`: `stray` (issue #303; beside `contour` or `auto` it is refused, CONFIG_STRAY_MODE)
|
|
128
128
|
- **meshes.<part>.influences** — optional, at least one: `maxInfluences` (a whole number, 1 or more, or null for no cap), `floor` ("cut" or "continuous")
|
|
129
129
|
- **meshes.<part>.ribs.<chain>** — required: `stations`
|
|
130
130
|
- **meshes.<part>.contour** — required: `tolerance`, `margin`, `spacing`; optional: `maxEdge`, `budget`, `stray`, `regions`
|
|
@@ -171,11 +171,11 @@ every number) are AUTHORING §3's tables, and the loader refuses any other by na
|
|
|
171
171
|
| --- | --- | --- |
|
|
172
172
|
| `parts.json`, `parts/<name>.png` | `assemble`, `build` | one record per part: `from` (`<run>:<tag>` with a See-through v3 tag, `<run>:author:<label>` for a layer the author made — issue #256, read by no role rule — or `painting:<name>` for a patch), `cut_from` on a cut's piece only (the plan part it was cut from, issue #230), the box `x`, `y`, `w`, `h` (rig px), the pixel counts `src/parts.ts` documents (`opaque_px`, `visible_px`, `occluded_px`, `projected_core_px`, `source_px_taken`, `visible_not_projected_px`, `refused_drift_px`, `merged_px`, `seam_override_px`, and `fringe_pushed_back` when not empty); `rig_size`, `scale_rig_per_source`, `ghost_px`, `recomposite`, and `scene` (`figure_alpha_above`, `figure_px`, `figure_mask`) under `config.scene` only, with the figure's mask `figure_rig.png` beside the recomposite (issue #242) |
|
|
173
173
|
| `rig/rig.json`, `rig/motion.json`, `rig/images/` | `rig`, `build`, `compose` | rig-c's rig spec and motion spec, `spec` `rigc-rig/1` and `rigc-motion/1`: the format is rig-c's, and this package writes only what rig-c's parser accepts |
|
|
174
|
-
| `rig/mesh_report.json` | `rig`, `build` | one row per mesh: `part`, `vertices`, `triangles`, `hull`, `bones`, `max_influences`, `mean_influences`, `art_coverage`, then `grid` (a lattice); `mode` "contour" with `params`, `contour`, `regions` (`params.maxEdge` and `contour.outlineCut` only when the mesh declares `contour.maxEdge`); or `mode` "auto" with `settings`, `source`, `result`, `residuals`, `worst_residual`, `worst_region`, `motion_amplitude`, `termination`, `weights`, `regions`, `deformation`, `quality_report` (rig-c's `mesh-quality-report/1` document whole), `motion_report`, and, only when they apply, `stray_cleared` (after `source`, when `source.stray` is declared), `skinning_residual` and `replay` (`AutoMeshReport` in `src/rig.ts`); in every mode, `exponent` when the mesh declares one (after `grid`, or after `mode`); `influences`, as declared, when a lattice or contour mesh declares it (after `exponent`, or where `exponent` would be); `ribs` when a contour or auto mesh declares them (after `exponent`, or after `mode`), and then `contour.ribs` (`source.contour.ribs` in the automatic mode) |
|
|
174
|
+
| `rig/mesh_report.json` | `rig`, `build` | one row per mesh: `part`, `vertices`, `triangles`, `hull`, `bones`, `max_influences`, `mean_influences`, `art_coverage`, then `grid` (a lattice); `mode` "contour" with `params`, `contour`, `regions` (`params.maxEdge` and `contour.outlineCut` only when the mesh declares `contour.maxEdge`); or `mode` "auto" with `settings`, `source`, `result`, `residuals`, `worst_residual`, `worst_region`, `motion_amplitude`, `termination`, `weights`, `regions`, `deformation`, `quality_report` (rig-c's `mesh-quality-report/1` document whole), `motion_report`, and, only when they apply, `stray_cleared` (after `source`, when `source.stray` is declared), `skinning_residual` and `replay` (`AutoMeshReport` in `src/rig.ts`); in every mode, `exponent` when the mesh declares one (after `grid`, or after `mode`); `influences`, as declared, when a lattice or contour mesh declares it (after `exponent`, or where `exponent` would be); `stray` and `stray_cleared` when a lattice mesh declares `stray` (after `influences`, or where `influences` would be); `ribs` when a contour or auto mesh declares them (after `exponent`, or after `mode`), and then `contour.ribs` (`source.contour.ribs` in the automatic mode) |
|
|
175
175
|
| `check/check.json` and the rest of `check/` | `check`, `build`, `compose` | the reference's fields in its order (`gate_spine_html_green`, `rigc_entry`, `pack_mode`, `loop_max_diff`, the seam figures — `seam_mean`, `seam_px_over_40`, `seam_px_over_80` and, from issue #216, `seam_frame_scale`, the frame scale the bar divides the count by), `loop_physics` after `loop_max_diff` when the rig declares a physics constraint, `seam_border` after the seam figures when `parts.json` declares a scene (issue #242), `seam_pairs` after the seam figures when the seam bar fails or `--seam-pairs` asks (each row's picture under `check/seam/`; `--keep-stills` leaves the setup-pose still and its `frames.json` under `check/setup_still/`), then the judgement lines (`BREATH_VISIBLE`, `BLINK_NO_HOLE`, `CHAIN_LAG`, `TIP_OVER_ROOT`, `STILL_REGIONS_DARK`, `TEXTURE_STRETCH`), `RECOMPOSITE_HOLES` (its first figure `declared_scene` when `parts.json` declares a scene), `SETUP_POSE_VS_SOURCE`, `skipped`, a `requirements` block under `--requirements`, and `PASS`; `check/build/skeleton.json`, `.atlas` and `.png` are the packed artifact rig-c writes |
|
|
176
176
|
| `proposal.json`, `render/landmarks*.png` | `propose` | the config's four rig sections, `turn` with `--full`/`--head`, and `notes` |
|
|
177
177
|
| `basis.json` | `propose` | spec `spine-parts-basis/1` |
|
|
178
|
-
| `config.json`, `mesh_draft.json` | `mesh-draft` | `config.json` is the config read, byte for byte, but for each drafted part's `meshes` entry; `mesh_draft.json` is spec `rig-parts-mesh-draft/1`: `rules`, `lattice_check`, `draft_check`, `figure_overdraw`, and per lattice part `part`, `mode`, `lattice`, `candidate`, `delta` (under `--more-triangles` only), `readings`, `gate` (each line's `reading`, `pass`, `text`, `margin`), `note` |
|
|
178
|
+
| `config.json`, `mesh_draft.json` | `mesh-draft` | `config.json` is the config read, byte for byte, but for each drafted part's `meshes` entry; `mesh_draft.json` is spec `rig-parts-mesh-draft/1`: `rules`, `lattice_check`, `draft_check`, `figure_overdraw`, and per lattice part `part`, `mode`, `lattice`, `candidate`, `delta` (under `--more-triangles` only), `readings`, `gate` (each line's `reading`, `pass`, `text`, `margin`), `note`; and `not_compared` (issue #307), only when the config holds an `auto` or `contour` entry: per such entry, in config order, `part`, `mode` and `note` — the part was neither drafted nor compared, and a config of lattices alone writes no such key |
|
|
179
179
|
| the scene report | `compose` | spec `spine-parts-scene-report/1` |
|
|
180
180
|
| `idle.png`, `idle-indexed.png`, `idle.gif` | `loop`, `build --loop` | APNG and GIF encodings of the rendered idle |
|
|
181
181
|
|