@rig-c/parts 1.5.4 → 1.6.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/NOTICE.md +23 -10
- package/README.md +56 -55
- package/cli.ts +10 -2
- package/docs/AUTHORING.md +196 -114
- package/docs/STABILITY.md +2 -2
- package/package.json +1 -1
- package/skills/rig-parts/SKILL.md +2 -2
- package/src/assemble.ts +329 -9
- package/src/build.ts +2 -1
- package/src/check.ts +224 -28
- package/src/instruments.ts +34 -10
- package/src/parts.ts +39 -2
- package/src/propose.ts +97 -39
- package/src/requirements.ts +58 -3
package/docs/AUTHORING.md
CHANGED
|
@@ -6,12 +6,19 @@ 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/sample`](../examples/sample): its
|
|
9
|
+
The worked example throughout is [`examples/reference-sample`](../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/sample/inputs/`.
|
|
14
|
+
into `examples/reference-sample/inputs/`.
|
|
15
|
+
|
|
16
|
+
The examples' names: `reference-sample` and `reference-demo` are the two characters
|
|
17
|
+
the reference implementation ran (published as `sample` and `demo` until issue #227),
|
|
18
|
+
kept as fixtures because their `expected/` is that implementation's own output; every
|
|
19
|
+
figure this guide quotes for them was measured on them. `demo` is the painting the
|
|
20
|
+
README shows since issue #227 and `scarf` the hanging-element example; both have
|
|
21
|
+
`expected/` from this port's own build, and a figure quoted for them says so.
|
|
15
22
|
|
|
16
23
|
## 1. Prerequisites
|
|
17
24
|
|
|
@@ -244,8 +251,8 @@ box every rule scales by is derived from the head run's hair (`front hair`,
|
|
|
244
251
|
`back hair`: their highest top) and its `neck` (its top, and its centre x for the
|
|
245
252
|
axis): with `L` the span from the hair's top to the neck's top, the face is
|
|
246
253
|
1.067 `L` tall, its top 0.131 `L` below the hair's, its width 0.798 of its height.
|
|
247
|
-
Those ratios are the means of the two public examples (`demo` 1.073 / 0.105 /
|
|
248
|
-
0.820, `sample` 1.061 / 0.158 / 0.777) — a sample of two. On each example
|
|
254
|
+
Those ratios are the means of the two public examples (`reference-demo` 1.073 / 0.105 /
|
|
255
|
+
0.820, `reference-sample` 1.061 / 0.158 / 0.777) — a sample of two. On each example
|
|
249
256
|
re-assembled without its face, the derived box put `head` and `neck` within
|
|
250
257
|
5.0 px (0.038 face heights) of the with-face proposal's, `chest` and `hip` at
|
|
251
258
|
the same pixel. The first note says so —
|
|
@@ -270,7 +277,7 @@ Two rules read the figure rather than one tag, and each says so in a note:
|
|
|
270
277
|
0.8 of the shoulders — or `hip from 0.32 of figure height (no waist found: …)`,
|
|
271
278
|
naming why. Without `bottomwear` the hip is 0.32 of the figure height, as before
|
|
272
279
|
(`no bottomwear: hip from 0.32 of figure height`). Neither published example
|
|
273
|
-
meets either branch: their hips sit at 0.436 (`demo`) and 0.342 (`sample`) of
|
|
280
|
+
meets either branch: their hips sit at 0.436 (`reference-demo`) and 0.342 (`reference-sample`) of
|
|
274
281
|
their figures.
|
|
275
282
|
- **Clasped hands.** When every `handwear` part together is one blob (over
|
|
276
283
|
500 px) at most half the shoulders' width and centred within a quarter of it
|
|
@@ -289,7 +296,7 @@ sub-shape of the layer's **pendant rows** (the run of rows at the bottom narrowe
|
|
|
289
296
|
than 35 % of its widest row; the whole layer for `earwear` or a layer that is over
|
|
290
297
|
80 % pendant) that is at least **3×** as tall as wide, at least **0.2** of the
|
|
291
298
|
layer's height and at least **10** rows. On the public examples nothing is one: the
|
|
292
|
-
demo's hairpin pendant sub-shapes measure 0.54 and 0.89 tall-per-wide and its
|
|
299
|
+
reference-demo's hairpin pendant sub-shapes measure 0.54 and 0.89 tall-per-wide and its
|
|
293
300
|
earrings 1.04 and 1.08, so both proposals are unchanged. Every layer with strands
|
|
294
301
|
gets exactly one note carrying each strand's column centroid, first–last row and
|
|
295
302
|
width, and what became of it (two of the selftest's fixtures, PR12 and PR15):
|
|
@@ -323,7 +330,7 @@ the eyewhite's top with no art across its whole width, the lowest such row is pr
|
|
|
323
330
|
`motion.blink.still` on `head`, and the rows above it stop blinking; when it has none, the
|
|
324
331
|
note says so and nothing is cut — clear a row between the crease and the lash line in the
|
|
325
332
|
part, or leave the crease to blink. The cut has to be a clear row: two pieces cut through
|
|
326
|
-
art are each resampled against their own transparent edge, and on the demo example a cut
|
|
333
|
+
art are each resampled against their own transparent edge, and on the reference-demo example a cut
|
|
327
334
|
through its lash line changed 36 px of the setup-pose render (up to 7 levels, at render
|
|
328
335
|
scale 0.942) and up to 21 levels in the idle frames where the head rolls; a clear-row cut
|
|
329
336
|
changed none, at rest or rolled. The eye bone is not moved: scaling about the eyewhite's
|
|
@@ -442,23 +449,23 @@ crescent; the other four 1.5 or less). No cell refused overshoot, and along each
|
|
|
442
449
|
a margin passed every larger one passed — where the offset this replaced moved an acute corner
|
|
443
450
|
up to 4 × margin and closed the window from above. That is the generated shapes: on a real part
|
|
444
451
|
a larger margin can close a gap whose enclosed pocket lies further from the art than the bound,
|
|
445
|
-
which the overshoot check refuses (
|
|
452
|
+
which the overshoot check refuses (reference-demo's hairpin builds at margin 1 and refuses at 1.5, 2
|
|
446
453
|
and 3: 5.39 px). On the public examples at tolerance 1, margin 1, `stray` 4 and spacing = the
|
|
447
|
-
part's grid, 13 of the 14 mesh parts build; the 14th is
|
|
454
|
+
part's grid, 13 of the 14 mesh parts build; the 14th is reference-demo's earring, two pieces.
|
|
448
455
|
|
|
449
|
-
**When not to use it.** A part that is two pieces (
|
|
456
|
+
**When not to use it.** A part that is two pieces (reference-demo's earring: 411 and 358 px) — keep
|
|
450
457
|
the lattice, which bridges islands, or split the part. And a part nothing deforms locally: at
|
|
451
458
|
tolerance 1 the contour outline is dense, and on the examples' 13 parts the contour mesh used
|
|
452
|
-
more vertices than the lattice at the same spacing (demo 1785 against 1431, sample 974 against
|
|
453
|
-
852) while enclosing 5.8 and 9.8 times less transparent area (demo 25078 against 144782 px², sample
|
|
459
|
+
more vertices than the lattice at the same spacing (reference-demo 1785 against 1431, reference-sample 974 against
|
|
460
|
+
852) while enclosing 5.8 and 9.8 times less transparent area (reference-demo 25078 against 144782 px², reference-sample
|
|
454
461
|
6563 against 64445), with thinner triangles — smallest angles 2.46°–11.31° against the lattice's
|
|
455
|
-
12.09°–45° (#106). Switched, every part that builds:
|
|
456
|
-
`TEXTURE_STRETCH` 1.227 → 1.384, ceiling 1.927);
|
|
462
|
+
12.09°–45° (#106). Switched, every part that builds: reference-sample passes `check` (9 of 9;
|
|
463
|
+
`TEXTURE_STRETCH` 1.227 → 1.384, ceiling 1.927); reference-demo's gate is green but `check` refuses
|
|
457
464
|
`TEXTURE_STRETCH` on its back hair (2.535: an edge of a contour triangle squeezed to 0.394 of
|
|
458
465
|
its length in the idle), and with the back hair left on the lattice it passes 9 of 9 (1.388 →
|
|
459
466
|
1.68).
|
|
460
467
|
|
|
461
|
-
**Why
|
|
468
|
+
**Why reference-demo's back hair fails, and what passes** (issue #115). The squeezed edge is an
|
|
462
469
|
outline edge 2 px long, near the hair's tip, whose two ends sit either side of a step in the
|
|
463
470
|
weight field: one end keeps `hairback_l1` at 0.031, the other drops it, because a weight under
|
|
464
471
|
0.03 is dropped (`src/weights.ts`, the reference's `>= 0.03`). `hairback_l1` and `hairback_r2`
|
|
@@ -469,7 +476,7 @@ gives 1.316 on the contour mesh and 1.336 on the lattice: the lattice's 36 px ed
|
|
|
469
476
|
step, the outline's 2 px edges show it. Interior vertices cannot change it — an outline edge is
|
|
470
477
|
in every triangulation — so the background spacing does not move the figure (36, 24, 18 and
|
|
471
478
|
12 px all give 2.535). Raising `tolerance` to 1.5 removes every short edge across a step (the
|
|
472
|
-
shortest is then 8.2 px) and the part passes (1.345; with every buildable demo part switched,
|
|
479
|
+
shortest is then 8.2 px) and the part passes (1.345; with every buildable reference-demo part switched,
|
|
473
480
|
`check` passes 9 of 9 at 1.68), at 313 vertices against the lattice's 268 and 18155.5 px²
|
|
474
481
|
enclosed against 58346. The window is one value wide on this part: 1.25 keeps the same 2 px
|
|
475
482
|
edge (2.535) and 1.75 leaves art uncovered at margin 1. No other switched part of either
|
|
@@ -481,7 +488,7 @@ generated fixture of `tools/local_compare.ts` it reached a local shape error (0.
|
|
|
481
488
|
in #106, the same figures).
|
|
482
489
|
|
|
483
490
|
**On real parts the generated result did not carry over unchanged** (issues #107 and #110,
|
|
484
|
-
`bun tools/real_compare.ts --work <dir> --examples demo,sample --builds --sweep`, a declared test region on two demo
|
|
491
|
+
`bun tools/real_compare.ts --work <dir> --examples reference-demo,reference-sample --builds --sweep`, a declared test region on two reference-demo
|
|
485
492
|
parts — a place to measure, not a claim about the painting; the region spacing chosen by vertex
|
|
486
493
|
count alone). On `bottomwear` (a region of radius 65 px inside the part) the contour mesh passes
|
|
487
494
|
the same rule: 336 vertices against the lattice's 352, largest local shape error 1.535 px against
|
|
@@ -922,7 +929,7 @@ that crosses the region with no point of it inside to split at — is still stop
|
|
|
922
929
|
### Recipe: expressions and other named animations
|
|
923
930
|
|
|
924
931
|
The package proposes no expression and keys nothing but the idle; what it gives is a rig whose
|
|
925
|
-
face is bones (`eye_r`, `eye_l`, `brow_r`, `brow_l`, `mouth` on `sample`) and one door for
|
|
932
|
+
face is bones (`eye_r`, `eye_l`, `brow_r`, `brow_l`, `mouth` on `reference-sample`) and one door for
|
|
926
933
|
animations you write over them, `motion.animations_from` (the row above, issue #183). Write a
|
|
927
934
|
file in rig-c's motion-spec shape beside the config and name it:
|
|
928
935
|
|
|
@@ -941,8 +948,8 @@ file in rig-c's motion-spec shape beside the config and name it:
|
|
|
941
948
|
```
|
|
942
949
|
|
|
943
950
|
`build` writes `surprised` into `rig/motion.json` after `idle`, gates it with the rig, and
|
|
944
|
-
`check` names it on a line of its own (`examples/sample` carries one, `animations.json` with `hop`, the
|
|
945
|
-
recipe below). With exactly this file beside `examples/sample`'s config in its place,
|
|
951
|
+
`check` names it on a line of its own (`examples/reference-sample` carries one, `animations.json` with `hop`, the
|
|
952
|
+
recipe below). With exactly this file beside `examples/reference-sample`'s config in its place,
|
|
946
953
|
`build` printed (this tree, rig-c as `package.json` pins it):
|
|
947
954
|
|
|
948
955
|
```
|
|
@@ -954,16 +961,41 @@ recipe below). With exactly this file beside `examples/sample`'s config in its p
|
|
|
954
961
|
A bone the rig lacks is rigc's refusal at the rig stage, in rigc's words (`RIG_RIGC_GREEN`); a
|
|
955
962
|
fault in the file itself is the loader's (the row above names each one).
|
|
956
963
|
|
|
964
|
+
**Worked sets.** `examples/demo/animations.json` and `examples/scarf/animations.json`
|
|
965
|
+
(issue #224) carry `tilt`, `look_l`, `look_r`, `smile`, `startled`, a gesture (`wave` on
|
|
966
|
+
`demo`, `bow` on `scarf`) and `hop`, each a one-shot that keys only what it needs; the
|
|
967
|
+
examples' READMEs list what each keys and why. Two rules make a clip layer over the idle on
|
|
968
|
+
a player's second track rather than replace it:
|
|
969
|
+
|
|
970
|
+
- **Key the bones the idle leaves alone.** The idle turns and breathes the `*_ctl` bones
|
|
971
|
+
the rig stage writes (`head_ctl`, `chest_ctl`, a chain's `<chain><i>_ctl`) and `neck`; the
|
|
972
|
+
bone under each (`head`, `chest`, `<chain><i>`) is free. A `look_l` that keys `head` alone
|
|
973
|
+
leaves the idle's sway alive under it; one that keys `head_ctl` or `neck` stops it for as
|
|
974
|
+
long as the clip holds the key.
|
|
975
|
+
- **Key no constraint, draw order, deform or attachment.** A player mixing tracks refuses
|
|
976
|
+
those; bones are all a clip needs.
|
|
977
|
+
|
|
978
|
+
**Strands that trail.** A chain whose links lag the body is one `physics` constraint per
|
|
979
|
+
link in `constraints`, on the link bone (`hairback_r0`, not `hairback_r0_ctl`), driving
|
|
980
|
+
`rotate`; the examples soften it down the chain. A single bone with no `length` (a bow, an
|
|
981
|
+
earring, a bun) cannot take a `rotate` drive (rig-c's `A23`) and takes `x`/`y` instead. The
|
|
982
|
+
values that read on the examples, and the ones refused on the way there, are in their
|
|
983
|
+
READMEs.
|
|
984
|
+
|
|
957
985
|
**Limits.** Every slot holds one attachment, the part's own image, so an expression moves,
|
|
958
986
|
turns and scales the face's parts and never swaps one for another: there is no second mouth
|
|
959
|
-
shape to key, and no lip-sync. `check` measures the idle alone: an animation beside it
|
|
960
|
-
passed rigc's gate and nothing else — no seam, stretch or hole bar has read it.
|
|
987
|
+
or eye shape to key, and no lip-sync. `check` measures the idle alone: an animation beside it
|
|
988
|
+
has passed rigc's gate and nothing else — no seam, stretch or hole bar has read it. On the
|
|
989
|
+
examples each clip was read by `check`'s own `TEXTURE_STRETCH` reading applied to the clip's
|
|
990
|
+
`rigc render --geometry` (their READMEs give the figures); that is a measurement, not a
|
|
991
|
+
gate, and it is where an arm raised overhead was found to tear `demo`'s elbow (5.327
|
|
992
|
+
against 1.926544).
|
|
961
993
|
|
|
962
994
|
### Recipe: a soft region driven by physics
|
|
963
995
|
|
|
964
996
|
A jiggle (a bust, the hips) is a patch of one part that lags behind the body. The package
|
|
965
997
|
proposes none and judges none; what it gives is the three pieces to build one, all in the
|
|
966
|
-
config. `examples/sample` carries a worked one (issue #183, PR #187), and its config is the
|
|
998
|
+
config. `examples/reference-sample` carries a worked one (issue #183, PR #187), and its config is the
|
|
967
999
|
fragment below, cut to the bust:
|
|
968
1000
|
|
|
969
1001
|
```jsonc
|
|
@@ -983,14 +1015,14 @@ fragment below, cut to the bust:
|
|
|
983
1015
|
bone and no constraint; it is yours, and nothing keys it — the constraint moves it.
|
|
984
1016
|
- **A region in a `contour` (or `auto`) mesh** that hands the patch to that bone: weight 1
|
|
985
1017
|
inside the shape, falling to 0 across `band` (*A contour mesh*, above). A `grid` mesh carries
|
|
986
|
-
no region, so the part moves from the lattice to the outline mode first; `sample` traced
|
|
1018
|
+
no region, so the part moves from the lattice to the outline mode first; `reference-sample` traced
|
|
987
1019
|
`topwear` at its former grid spacing (18) and `bottomwear` at 28. Place the shape on the
|
|
988
|
-
patch alone: on `sample` one circle at the hip centre reached the clasped hands, painted
|
|
1020
|
+
patch alone: on `reference-sample` one circle at the hip centre reached the clasped hands, painted
|
|
989
1021
|
inside `bottomwear`, so the hips are two side circles (`hip_r`, `hip_l`) on one bone.
|
|
990
1022
|
- **A `physics` constraint** on that bone in `constraints`, in rig-c's shape; every field but
|
|
991
1023
|
the bone is rigc's to accept.
|
|
992
1024
|
|
|
993
|
-
`build` on `sample` as tracked (PR #187; the values above are the ones tuned for its `hop`, issue #183):
|
|
1025
|
+
`build` on `reference-sample` as tracked (PR #187; the values above are the ones tuned for its `hop`, issue #183):
|
|
994
1026
|
|
|
995
1027
|
```
|
|
996
1028
|
check: PASS; 9 of 9 bar(s) measured, 0 skipped
|
|
@@ -1004,7 +1036,7 @@ by whatever the spring is still doing; the bar is read off the same rig with eve
|
|
|
1004
1036
|
constraint left out, and the constraints left out are listed, reported and not judged
|
|
1005
1037
|
(`check.json`'s `loop_physics`, PR #184). It is not a measure of the jiggle.
|
|
1006
1038
|
|
|
1007
|
-
**Limits.** The idle drives the spring, and a slow idle barely moves it. Measured on `sample`
|
|
1039
|
+
**Limits.** The idle drives the spring, and a slow idle barely moves it. Measured on `reference-sample`
|
|
1008
1040
|
(PR #187, rig-c `render --geometry`, the physics build against the same build with
|
|
1009
1041
|
`constraints` removed): under its 4 s breath (`chest` `translatey` amplitude 1.3 px), the bust
|
|
1010
1042
|
moves at most 0.155 rig px (idle frame 3, t 0.25 s); the hips move 0.000 at all 49 frames,
|
|
@@ -1014,7 +1046,7 @@ frequency, about 0.2 px (PR #187, from the definition): no setting makes a 4 s b
|
|
|
1014
1046
|
jiggle (with the values tracked now, `bust_phys` inertia 0.25, strength 120, damping 0.92, the
|
|
1015
1047
|
idle moves the bust at most 0.066 rig px, idle frame 2). Faster keys on the parent bone — a hop,
|
|
1016
1048
|
a turn, in a named animation (the recipe above) or a consumer's own — are what the spring
|
|
1017
|
-
answers. `sample`'s `animations.json` holds one, `hop` (1 s: `hip` `translate` y down 5, up 24,
|
|
1049
|
+
answers. `reference-sample`'s `animations.json` holds one, `hop` (1 s: `hip` `translate` y down 5, up 24,
|
|
1018
1050
|
landing at -6 at 0.45 s, settling at 0.55 s; nothing keys the jiggle bones): rendered at 30 fps
|
|
1019
1051
|
against the same build without its constraints, the bust moves at most 6.583 rig px and the hips
|
|
1020
1052
|
(`hip_phys` inertia 0.2, strength 160, damping 0.88, mass 1.5) at most 4.432 (frame 13, the fall
|
|
@@ -1059,7 +1091,7 @@ not run through. Raising the bound is the author's choice, not the package's; mo
|
|
|
1059
1091
|
is the fix.
|
|
1060
1092
|
- **An added animation can move the idle's figures.** The render's viewport is fitted over
|
|
1061
1093
|
every animation, and the idle frames share it, so an animation that travels further than the
|
|
1062
|
-
idle redraws the idle at another size: adding `hop` to `sample` narrowed the idle render from
|
|
1094
|
+
idle redraws the idle at another size: adding `hop` to `reference-sample` narrowed the idle render from
|
|
1063
1095
|
201 to 198 px wide and moved `check.json`'s `BREATH_VISIBLE` `torso_heat_mean` from 7.8 to
|
|
1064
1096
|
7.705, every status unchanged, although `check` reads the idle alone.
|
|
1065
1097
|
|
|
@@ -1109,14 +1141,20 @@ full loader before its assemble stage writes anything.
|
|
|
1109
1141
|
5. **See-through, head run** (external), on that crop. See-through's own second,
|
|
1110
1142
|
head stage does not replace it: that stage's layers are pasted back at the full
|
|
1111
1143
|
run's scale on every route that was read (README *Getting See-through layers*),
|
|
1112
|
-
so the full run's eyes stay at its density — 22×13 px for
|
|
1144
|
+
so the full run's eyes stay at its density — 22×13 px for reference-demo's right eye
|
|
1113
1145
|
white at `resolution` 1024, against 60×38 px in the head run.
|
|
1114
1146
|
6. `rig-parts assemble --propose-plan --source … --full … --head … --config config.json`
|
|
1115
1147
|
→ paste `plan` and `extend_below_crop` into `config.assemble`. Config: the
|
|
1116
1148
|
`layers` row, with `head_box`.
|
|
1117
1149
|
Read `notes`: a layer left out by a plausibility rule is named there with its
|
|
1118
|
-
figures and the rule (§6, *Plausibility*)
|
|
1119
|
-
|
|
1150
|
+
figures and the rule (§6, *Plausibility*), and a full-run layer holding a body
|
|
1151
|
+
no planned part covers — long hair that leaves the head crop sideways, or a
|
|
1152
|
+
head-run part that stops above the crop line so `extend_below_crop` continues
|
|
1153
|
+
nothing — is named with the body, the rule that skipped it and the two
|
|
1154
|
+
continuations (take the part from the full run, or add the full-run layer as a
|
|
1155
|
+
second part behind it). The plan is not changed; which continuation fits is
|
|
1156
|
+
yours.
|
|
1157
|
+
7. `rig-parts assemble … --out work` — read its `uncovered hole` and `uncovered:` lines and look at
|
|
1120
1158
|
`work/render/recomposite_error_rig.png` (§5): red is painting no part holds, which
|
|
1121
1159
|
no later stage can see — then
|
|
1122
1160
|
`rig-parts propose --parts work/rig --source inputs/painting.png --out work` →
|
|
@@ -1197,8 +1235,8 @@ proposal in as the steps above say (`RL01`); every step must exit 0.
|
|
|
1197
1235
|
| --- | --- | --- | --- |
|
|
1198
1236
|
| `layers` | the table, then the `WARN` lines | every tag the plan will need has opaque pixels; one `face` in the head run; `0 WARN line(s)` | a run whose layer PNG is not its box's size (`LAYERS_PNG_MATCHES_BBOX`); a `WARN PLAN_LAYER_…` line (§6, *Plausibility*) |
|
|
1199
1237
|
| `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 |
|
|
1200
|
-
| `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, …)
|
|
1201
|
-
| `propose` | `note:` lines, `LINT` lines, the `coverage` lines, `landmarks.png`, `basis.json` | no LINT line: every chain link lies on its mesh's art, and the hip is below the chest and the figure's top quarter; the `coverage:` summary says how many bones that verdict covers — a `not checked` bone was read by no check (its line says why), and a `ratio` or `fallback` bone in `basis.json` is a guess | a link off the art (a bone on the background) — move it onto the layer; `LINT hip at [x, y] is not below chest at [x, y]: …` or `LINT hip at [x, y] is above 0.25 of the figure height (figure y T..B, so hip y must be at least L): a hip at the shoulders` — move `hip` down to the waist (and `chest` between it and the neck); a `hanging strand … -- no chain proposed` note — that strand hangs stiff until you add a chain down the x and rows it names (§3); a `no blink: …` or `blink without brows: …` note — the idle will not blink (or its brows will not drop), because no part came from an `eyewhite` (or `eyebrow`) layer; the note names the tags looked for; a `no eyewhite part for eye_<s> …` note — the iris and lash parts it names ride `head` and do not blink, because no `eyewhite-<s>` part made that side's eye bone: take the eyewhite from the other run, or keep them on `head`; a `no face part: face box derived from …` note (always the first) — `head`, `neck` and every face-height scale come from a box guessed off the hair and neck (§3): check `head` and `neck` on `landmarks_head.png` and move them; when it adds `the blink shuts the eyes over no face part`, read `BLINK_NO_HOLE` after `check` — an eye with no face under it can open a hole (the `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 |
|
|
1238
|
+
| `assemble` | one line per part, the `pixels:` totals (opaque = visible + occluded; taken; visible but not projected), then `recomposite vs source: mean \|d\|, within 8, error px > 40, uncovered error px`, then `uncovered holes (8-connected): N` and the largest five as `uncovered hole K: <px> px at x,y wxh (between "<part>" <px> px, …)`, then one `uncovered: <n> of the <N> uncovered error px lie on the full run's "<tag>", in a body of <px> px at x,y wxh; <the rule that left it out>` line per full-run layer the plan does not take from the full run whose uncovered error holds a body (5x5-opened, 8-connected, at least 150 full-run px in rig px); and look at `render/recomposite_error_rig.png`. Between the part lines and the totals, one `cut: "<part>" opaque <n> = "<part>" <kept> + "<piece>" <taken> …` line per part an `assemble.cuts` entry cut (below; it ends `; under <n> px filled, <m> px left empty` when a cut of that part has `under`), then one `fringe pushed back: "<part>" <px> px, where the painting shows "<holder>" <px> px, …` line per part whose fringe was cleared (below) | on the examples: `reference-sample` 0.83 / 98.0 % / 4,359 / 1,185, 259 holes, the largest 94 px; `reference-demo` 2.34 / 95.8 % / 10,340 / 1,564, 453 holes, the largest 70 px (default rule) — many slivers along part edges, no hole a region could hide | one large hole: part of the figure is in no layer — a plan entry is missing, hair left the head crop sideways (reference-demo's `hair_back` is taken from the full run for that reason), or See-through split one garment into two and left the space between them in neither (a skirt as two trouser legs); the `between` parts say where. When neither run holds it at all, an `assemble.patches` entry cuts it from the painting (below) |
|
|
1239
|
+
| `propose` | `note:` lines, `LINT` lines, the `coverage` lines, `landmarks.png`, `basis.json` | no LINT line: every chain link lies on its mesh's art, and the hip is below the chest and the figure's top quarter; the `coverage:` summary says how many bones that verdict covers — a `not checked` bone was read by no check (its line says why), and a `ratio` or `fallback` bone in `basis.json` is a guess | a link off the art (a bone on the background) — move it onto the layer; `LINT hip at [x, y] is not below chest at [x, y]: …` or `LINT hip at [x, y] is above 0.25 of the figure height (figure y T..B, so hip y must be at least L): a hip at the shoulders` — move `hip` down to the waist (and `chest` between it and the neck); a `hanging strand … -- no chain proposed` note — that strand hangs stiff until you add a chain down the x and rows it names (§3); a `no blink: …` or `blink without brows: …` note — the idle will not blink (or its brows will not drop), because no part came from an `eyewhite` (or `eyebrow`) layer; the note names the tags looked for; a `no eyewhite part for eye_<s> …` note — the iris and lash parts it names ride `head` and do not blink, because no `eyewhite-<s>` part made that side's eye bone: take the eyewhite from the other run, or keep them on `head`; a `no face part: face box derived from …` note (always the first) — `head`, `neck` and every face-height scale come from a box guessed off the hair and neck (§3): check `head` and `neck` on `landmarks_head.png` and move them; when it adds `the blink shuts the eyes over no face part`, read `BLINK_NO_HOLE` after `check` — an eye with no face under it can open a hole (the `reference-sample` with only its face removed: 587 px). Under `--keypoints`: the `lint rule set:` line first (joints, or screen and why), then the joint notes — `missing: the rule "…" placed bone X instead` is a bone still guessed; `not used — …` names why an arm's joints did not place its sleeve (for a wrist on no part, the nearest part and the `--wrist-snap` that would bind it); a `wrist snap: …` note is a wrist bound past 15 px by the flag — check that chain's tip on `landmarks.png`; a `one handwear part holds both wrists` note is two chains on one mesh — cut the part with `assemble.cuts` to separate them; `LINT chest at … is not between the neck joint …`, `LINT hip at … is not past chest …`, `LINT hip at … is nearer the neck joint …` and `LINT <chain><i> at … does not advance from <s>_shoulder toward <s>_wrist` are the joint-frame lines: move that bone between, past or along the joints they name |
|
|
1202
1240
|
| `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 |
|
|
1203
1241
|
| `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` |
|
|
1204
1242
|
| `check` (inside `build`) | the gate lines verbatim, the pack line, `loop:` (and `loop physics:` when the rig declares a physics constraint, §7), `seam:`, the six judgement lines, `RECOMPOSITE_HOLES` and, under `--source`, `SETUP_POSE_VS_SOURCE` (§7), `check.json`; the last line says how many of the nine bars measured and names the ones that said SKIP | `check: PASS; 9 of 9 bar(s) measured, 0 skipped` on the examples, and a judgement line SKIP only where the character lacks what it reads; on a rig spec with no `parts.json` or no `idle` (a merged rig, §7 *Measuring a rig rig-parts did not assemble*), PASS with the skipped bars named | `CHECK_SEAM_WITHIN_BAR` or `CHECK_LOOP_CLOSES` (§6) |
|
|
@@ -1214,25 +1252,27 @@ every frame (255 median-cut colours and one transparent entry, alpha graded per
|
|
|
1214
1252
|
entry, no dithering, filter None) — and is the small file to show. `idle.gif`
|
|
1215
1253
|
(`loop --out x.gif`) is the same median cut in a GIF. The indexed APNG and the GIF
|
|
1216
1254
|
print their palette error, per channel over R, G and B of every frame (and alpha's
|
|
1217
|
-
max for the APNG); a figure is a measurement of the file, not a bar. On the demo
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1255
|
+
max for the APNG); a figure is a measurement of the file, not a bar. On the demo
|
|
1256
|
+
(the README's animation since issue #227: `build --loop`, default flags, rig-c 2.33.0):
|
|
1257
|
+
5,832,634 B lossless, 827,857 B indexed and 889,063 B GIF, both palette files at
|
|
1258
|
+
max 65, mean 0.879 — the two share one quantiser, so their error is the same by
|
|
1259
|
+
construction and the size is the difference. On reference-demo with `--seam silhouette`
|
|
1260
|
+
(the README's animation until issue #227, rig-c 2.1.3, and 2.10.1 to the byte):
|
|
1261
|
+
13,645,503 B lossless, 1,706,719 B indexed and 1,812,288 B GIF at max 57, mean 1.601;
|
|
1262
|
+
with `--pack-shape rect` the same build writes 13,645,350, 1,706,520 and 1,812,238 B,
|
|
1263
|
+
and with `--page-edges pot --pack-shape rect` 13,645,519, 1,706,785 and 1,812,625 B,
|
|
1264
|
+
all at the same error (2.10.1 reproduces both). The loop shows the blink closed: the
|
|
1225
1265
|
eyes' hold is at least one 12 fps frame (below), so whatever `motion.blink.t` is, one
|
|
1226
1266
|
idle frame lands inside it, and `check.json`'s `BLINK_NO_HOLE.idle_frames_closed`
|
|
1227
|
-
names it — `[29]` on
|
|
1267
|
+
names it — `[29]` on the two reference examples and on the demo.
|
|
1228
1268
|
|
|
1229
1269
|
`--seam near-white` (the default) is the reference implementation's rule: where the
|
|
1230
1270
|
flat stack of parts differs from the painting by more than 60, the top part takes the
|
|
1231
1271
|
painting's colour — except where the painting is near-white, which protects the page
|
|
1232
1272
|
and also every white garment. `--seam silhouette` protects near-white pixels only
|
|
1233
|
-
outside the figure. On
|
|
1234
|
-
8,644 (`assemble`'s `error px > 40`, at v1.5.2); on
|
|
1235
|
-
(4,359 under both). At v0.14.0
|
|
1273
|
+
outside the figure. On reference-demo it lowers recomposite error pixels from 10,340 to
|
|
1274
|
+
8,644 (`assemble`'s `error px > 40`, at v1.5.2); on reference-sample it changes nothing
|
|
1275
|
+
(4,359 under both). At v0.14.0 reference-demo's were 11,050 and 9,540, and no check bar
|
|
1236
1276
|
changed. The default stays
|
|
1237
1277
|
the reference's so the examples stay comparable with it.
|
|
1238
1278
|
|
|
@@ -1253,8 +1293,8 @@ and a cleared bridge to opaque art is put back, so no part gains an island
|
|
|
1253
1293
|
(`CONTOUR_ONE_ISLAND` reads the islands it read before). `parts.json` records each part's cleared pixels by holder
|
|
1254
1294
|
(`fringe_pushed_back`), the counts in it are taken after, and the assemble line above
|
|
1255
1295
|
names them. On the examples (default flags, measured against the v0.14.0 build of
|
|
1256
|
-
the same inputs): `demo` 1,193 px over 16 parts, recomposite error pixels 11,050 →
|
|
1257
|
-
10,340; `sample` 276 px over 15 parts, 4,512 → 4,359; uncovered error pixels and
|
|
1296
|
+
the same inputs): `reference-demo` 1,193 px over 16 parts, recomposite error pixels 11,050 →
|
|
1297
|
+
10,340; `reference-sample` 276 px over 15 parts, 4,512 → 4,359; uncovered error pixels and
|
|
1258
1298
|
holes unchanged on both, `check` 9 of 9 on both. The `--project` comparison in
|
|
1259
1299
|
this section and the `SETUP_POSE_VS_SOURCE` example figures in §7 were measured
|
|
1260
1300
|
before it, at v0.14.0; the `--seam` figures above are v1.5.2's.
|
|
@@ -1272,10 +1312,10 @@ to 2.1.3's):
|
|
|
1272
1312
|
|
|
1273
1313
|
| build | page | covered | page opaque | page / figure |
|
|
1274
1314
|
| --- | --- | --- | --- | --- |
|
|
1275
|
-
| demo, `pot` | 1024x2048 | 56.3 % | 36.8 % | 2.651 |
|
|
1276
|
-
| demo, `free` | 967x1338 | 91.2 % | 59.7 % | 1.636 |
|
|
1277
|
-
| sample, `pot` | 512x2048 | 49.7 % | 28.7 % | 3.294 |
|
|
1278
|
-
| sample, `free` | 479x1166 | 93.4 % | 53.9 % | 1.755 |
|
|
1315
|
+
| reference-demo, `pot` | 1024x2048 | 56.3 % | 36.8 % | 2.651 |
|
|
1316
|
+
| reference-demo, `free` | 967x1338 | 91.2 % | 59.7 % | 1.636 |
|
|
1317
|
+
| reference-sample, `pot` | 512x2048 | 49.7 % | 28.7 % | 3.294 |
|
|
1318
|
+
| reference-sample, `free` | 479x1166 | 93.4 % | 53.9 % | 1.755 |
|
|
1279
1319
|
|
|
1280
1320
|
rigc's help states the cost: *"a smaller page, at the cost of region attachments
|
|
1281
1321
|
sampling within 1 LSB of the loose build rather than exactly"*. On these builds
|
|
@@ -1284,10 +1324,10 @@ in any channel:
|
|
|
1284
1324
|
|
|
1285
1325
|
| example | idle frames that differ | pixels that differ (all 49 frames) | max \|d\| |
|
|
1286
1326
|
| --- | --- | --- | --- |
|
|
1287
|
-
| demo | 49 of 49 | 2,373 | 1 |
|
|
1288
|
-
| sample | 49 of 49 | 651 | 1 |
|
|
1327
|
+
| reference-demo | 49 of 49 | 2,373 | 1 |
|
|
1328
|
+
| reference-sample | 49 of 49 | 651 | 1 |
|
|
1289
1329
|
|
|
1290
|
-
Only one check figure moved. It had no bar: sample's reported screen-space face
|
|
1330
|
+
Only one check figure moved. It had no bar: reference-sample's reported screen-space face
|
|
1291
1331
|
mean in `STILL_REGIONS_DARK`, 11.475 under `pot` and 11.472 under `free` (a pixel
|
|
1292
1332
|
figure the line no longer reports since issue #123; it reads geometry, which the page
|
|
1293
1333
|
does not enter). Every
|
|
@@ -1312,10 +1352,10 @@ both shapes and both edges (the full entry, spine-core 4.3.13 beside it),
|
|
|
1312
1352
|
|
|
1313
1353
|
| build | page | page area | covered | page opaque | page / figure |
|
|
1314
1354
|
| --- | --- | --- | --- | --- | --- |
|
|
1315
|
-
| demo, `rect` | 967x1338 | 1,293,846 | 91.2 % | 59.7 % | 1.636 |
|
|
1316
|
-
| demo, `polygon` | 922x1348 | 1,242,856 (−3.9 %) | 95.0 % | 62.1 % | 1.571 |
|
|
1317
|
-
| sample, `rect` | 479x1166 | 558,514 | 93.4 % | 53.9 % | 1.755 |
|
|
1318
|
-
| sample, `polygon` | 477x1151 | 549,027 (−1.7 %) | 95.0 % | 54.8 % | 1.725 |
|
|
1355
|
+
| reference-demo, `rect` | 967x1338 | 1,293,846 | 91.2 % | 59.7 % | 1.636 |
|
|
1356
|
+
| reference-demo, `polygon` | 922x1348 | 1,242,856 (−3.9 %) | 95.0 % | 62.1 % | 1.571 |
|
|
1357
|
+
| reference-sample, `rect` | 479x1166 | 558,514 | 93.4 % | 53.9 % | 1.755 |
|
|
1358
|
+
| reference-sample, `polygon` | 477x1151 | 549,027 (−1.7 %) | 95.0 % | 54.8 % | 1.725 |
|
|
1319
1359
|
|
|
1320
1360
|
Covered is Σ region rectangles over page area, as rigc prints it; under `polygon` the
|
|
1321
1361
|
rectangles may overlap where a hull leaves room, so it is not a union and can exceed
|
|
@@ -1328,8 +1368,8 @@ idle --fps 12 --max 640`, compared frame by frame, max over R, G, B and A):
|
|
|
1328
1368
|
|
|
1329
1369
|
| example | idle frames that differ | pixels that differ (all 49 frames) | max \|d\| |
|
|
1330
1370
|
| --- | --- | --- | --- |
|
|
1331
|
-
| demo | 49 of 49 | 2,594 | 1 |
|
|
1332
|
-
| sample | 49 of 49 | 740 | 1 |
|
|
1371
|
+
| reference-demo | 49 of 49 | 2,594 | 1 |
|
|
1372
|
+
| reference-sample | 49 of 49 | 740 | 1 |
|
|
1333
1373
|
|
|
1334
1374
|
That is the class `free` already costs (the table above, measured by the same
|
|
1335
1375
|
comparison), a little larger. No figure in `check.json` moved but `pack_mode`: every
|
|
@@ -1339,11 +1379,11 @@ they are byte-identical to rigc 2.0.3's `--page-edges free` build of the same ri
|
|
|
1339
1379
|
skeleton JSON differs only in its relative `images` path), and selftest `CK53` holds
|
|
1340
1380
|
`rect` to rigc's own rectangle page.
|
|
1341
1381
|
|
|
1342
|
-
The hull ceiling (rig-parts #58: hull area over rectangle area, 0.812 on demo and
|
|
1343
|
-
0.814 on sample) is not what the packer realises here: the hollows inside the meshes'
|
|
1382
|
+
The hull ceiling (rig-parts #58: hull area over rectangle area, 0.812 on reference-demo and
|
|
1383
|
+
0.814 on reference-sample) is not what the packer realises here: the hollows inside the meshes'
|
|
1344
1384
|
rectangles are worth only what fits into them. On the polygon pages, read off the
|
|
1345
|
-
atlas, demo's packed rectangles overlap in 21 pairs (17 a region attachment inside a
|
|
1346
|
-
mesh's rectangle, 4 a mesh inside another's) and sample's in 12 (10 and 2); no two
|
|
1385
|
+
atlas, reference-demo's packed rectangles overlap in 21 pairs (17 a region attachment inside a
|
|
1386
|
+
mesh's rectangle, 4 a mesh inside another's) and reference-sample's in 12 (10 and 2); no two
|
|
1347
1387
|
region attachments overlap. Meshes in place of regions would be rigc's stage 2 of
|
|
1348
1388
|
polygon packing (firejune/rigc#1093), which rigc measured and folded: on the three
|
|
1349
1389
|
production rigs most favourable to it, it adds 0.15 % of the rectangle area over
|
|
@@ -1356,7 +1396,7 @@ so a part a few pixels wide (a lash, a brow, an iris) takes none. `--project vis
|
|
|
1356
1396
|
keeps the erosion only along a rim where a later layer of the run is in front, and
|
|
1357
1397
|
takes every other top-most `alpha >= 250` pixel; neither rule takes a fringe pixel
|
|
1358
1398
|
(alpha below 250). On the examples it lowered the pixels that are visible but not
|
|
1359
|
-
projected from 36,227 to 22,476 (`sample`) and 76,801 to 49,672 (`demo`), recomposite
|
|
1399
|
+
projected from 36,227 to 22,476 (`reference-sample`) and 76,801 to 49,672 (`reference-demo`), recomposite
|
|
1360
1400
|
error pixels from 4,512 to 4,116 and 11,050 to 9,820, and the check seam from 0.207 to
|
|
1361
1401
|
0.206 and 0.326 to 0.325, with no other check figure changed. The default stays the
|
|
1362
1402
|
reference's so the examples stay comparable with it. `build` takes both flags.
|
|
@@ -1375,10 +1415,10 @@ drive M mesh attachment(s) totalling V vertices …`, which the stage prints; wi
|
|
|
1375
1415
|
mesh-driving bone keyed it declares nothing, because rigc refuses a declaration
|
|
1376
1416
|
that switches nothing off. The two write the same slots, skins and keys (`RG18`).
|
|
1377
1417
|
Measured on the examples with `bun tools/idle_cost.ts` (rig-parts #13): `direct`
|
|
1378
|
-
has 41 bones for
|
|
1418
|
+
has 41 bones for reference-demo's 72 and 32 for reference-sample's 56; every shown mesh moves on
|
|
1379
1419
|
every idle frame under both (8 of 8 and 6 of 6, so 0 a dirty-skip renderer could
|
|
1380
|
-
skip); the pose costs 14.8 against 15.3 us per frame (demo) and 8.3 against 8.8 us
|
|
1381
|
-
(sample), the difference all in `updateWorldTransform`; the rendered idle frames
|
|
1420
|
+
skip); the pose costs 14.8 against 15.3 us per frame (reference-demo) and 8.3 against 8.8 us
|
|
1421
|
+
(reference-sample), the difference all in `updateWorldTransform`; the rendered idle frames
|
|
1382
1422
|
differ by at most one level in a channel. The default stays `ctl`: the examples'
|
|
1383
1423
|
`expected/rig.json` and `motion.json` are the reference's output, and the
|
|
1384
1424
|
declaration is in the rig spec only, so `rigc validate <build> --profile spine-html`
|
|
@@ -1465,14 +1505,25 @@ immediately behind `X`; `"front"` patches last, then `"front"` pieces). Its coun
|
|
|
1465
1505
|
A part's `from` is `<full|head>:<tag>` — the See-through run and tag, which every
|
|
1466
1506
|
role (`propose`) and every judgement-line region (`check`) is read from — or, for a
|
|
1467
1507
|
patch, `painting:<its own name>`; a cut's piece carries the `<run>:<tag>` of the part
|
|
1468
|
-
it was cut from, so two records may share one
|
|
1508
|
+
it was cut from, so two records may share one, and names that part in `cut_from` (issue
|
|
1509
|
+
#230; written on a piece only). The records are in draw order, so a piece drawn `"back"`
|
|
1510
|
+
or before its base comes first, and only `cut_from` says which of the two the cut made.
|
|
1511
|
+
The reader refuses a `cut_from` that names no part of the file, the piece itself, another
|
|
1512
|
+
piece, or a part on another layer (`PARTS_CUT_FROM_KNOWN`). A `parts.json` written before
|
|
1513
|
+
1.5.6 has no `cut_from` and still reads; `propose` alone refuses it when two of its parts
|
|
1514
|
+
share a layer (`PROPOSE_CUT_FROM_RECORDED`): re-run assemble. **A patch is 100 % source**: every pixel is the
|
|
1469
1515
|
painting's, so it is all visible and all taken — `visible_px`, `projected_core_px`
|
|
1470
1516
|
and `source_px_taken` equal `opaque_px`, and `occluded_px`,
|
|
1471
1517
|
`visible_not_projected_px`, `refused_drift_px` and `merged_px` are 0. The reader
|
|
1472
1518
|
refuses a `painting:` record that says anything else, or that names another part
|
|
1473
1519
|
(`PARTS_FROM_KNOWN`, `PARTS_COUNTS_ADD_UP`). No tag rule reads a patch: `propose`
|
|
1474
1520
|
puts it on the nearest trunk bone as a region with a note, and `check` counts it
|
|
1475
|
-
in no region.
|
|
1521
|
+
in no region. No tag rule reads a cut's piece either (issue #230): its base already took
|
|
1522
|
+
the tag's rule, and a rule that runs once per part of a tag would name the base's bones
|
|
1523
|
+
and chains a second time, so the piece rides the nearest trunk bone as a region with a
|
|
1524
|
+
note saying so — give it a mesh in `meshes` if it should bend. The one exception is the
|
|
1525
|
+
sleeve rule, which names its chains by side and takes a cut sleeve as a blob of its own
|
|
1526
|
+
(the `one handwear part holds both wrists` note, §3).
|
|
1476
1527
|
|
|
1477
1528
|
`visible_px + occluded_px = opaque_px`, and every projected pixel is visible; the stage
|
|
1478
1529
|
refuses (`ASSEMBLE_COUNTS_ADD_UP`) rather than write counts that break either, and the
|
|
@@ -1544,15 +1595,15 @@ above 8, the table's `opaque_px`), on the layer as read:
|
|
|
1544
1595
|
| `background` | the share of opaque pixels whose own colour (straight alpha) has a min channel above 235 — the seam rule's "near-white", applied to the layer |
|
|
1545
1596
|
| `area` | opaque pixels over the opaque pixels of the union of every **other** layer of the run ("the rest of the figure"); `-` when no other layer has any |
|
|
1546
1597
|
|
|
1547
|
-
Not over alpha above 0: See-through hazes whole canvases at alpha 1..8 (
|
|
1598
|
+
Not over alpha above 0: See-through hazes whole canvases at alpha 1..8 (reference-demo's
|
|
1548
1599
|
full-run face is 99.1 % translucent that way and 4.2 % over its opaque pixels). Not
|
|
1549
1600
|
over the whole union: a layer is part of it, so it could never be more than 1x.
|
|
1550
1601
|
|
|
1551
1602
|
| rule | crossed when | [observed] on the two examples' 116 layers (four runs) |
|
|
1552
1603
|
| --- | --- | --- |
|
|
1553
|
-
| `PLAN_LAYER_TRANSLUCENT` | judged, and `translucent` above 50 % | the most translucent judged layer is 17.8 % (sample, full run, `front hair`) |
|
|
1554
|
-
| `PLAN_LAYER_BACKGROUND` | judged, `background` above 50 %, and `translucent` above 25 % | the most background-coloured judged layer is 21.9 % (demo, head run, `topwear`, a white dress); of judged layers above 10 % background, the most translucent is 5.6 % (demo, full run, `handwear-r`) |
|
|
1555
|
-
| `PLAN_LAYER_OVERSIZED` | `area` above 4x | the largest is 1.681x (demo, head run, `back hair`, which fills the crop) |
|
|
1604
|
+
| `PLAN_LAYER_TRANSLUCENT` | judged, and `translucent` above 50 % | the most translucent judged layer is 17.8 % (reference-sample, full run, `front hair`) |
|
|
1605
|
+
| `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`) |
|
|
1606
|
+
| `PLAN_LAYER_OVERSIZED` | `area` above 4x | the largest is 1.681x (reference-demo, head run, `back hair`, which fills the crop) |
|
|
1556
1607
|
|
|
1557
1608
|
**Judged** means `area` at least 0.05x (or `-`). The two colour rules skip smaller
|
|
1558
1609
|
layers on purpose: **[observed]** all 27 example layers of 150 px or more that are above
|
|
@@ -1649,13 +1700,14 @@ See-through with another seed.
|
|
|
1649
1700
|
| `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 |
|
|
1650
1701
|
| `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) |
|
|
1651
1702
|
| `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 |
|
|
1703
|
+
| `PROPOSE_CUT_FROM_RECORDED` | two parts share one layer and none of them records `cut_from`: a `parts.json` an `assemble` before 1.5.6 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.5.6+) to record `cut_from` |
|
|
1652
1704
|
| `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 |
|
|
1653
1705
|
| `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*) |
|
|
1654
1706
|
| `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 |
|
|
1655
1707
|
| `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 |
|
|
1656
1708
|
| `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>` |
|
|
1657
1709
|
| `KEYPOINTS_IMAGE_SIZE` | the file's `width`x`height` is not the `--source` painting's | a file measured on this painting |
|
|
1658
|
-
| `PARTS_*` (`PARTS_FILE_PRESENT`, `PARTS_IS_JSON`, `PARTS_KEY_KNOWN`, `PARTS_FIELD_PRESENT`, `PARTS_FIELD_TYPE`, `PARTS_NAME_UNIQUE`, `PARTS_FROM_KNOWN`, `PARTS_BOX_INSIDE_RIG`, `PARTS_COUNTS_ADD_UP`, `PARTS_HOLES_LARGEST_FIRST`, `PARTS_HOLE_PART_KNOWN`) | the `parts.json` read is not assemble's contract (`PARTS_COUNTS_ADD_UP`: `visible_px + occluded_px` is not `opaque_px`, `visible_not_projected_px` is above `visible_px`, or the `recomposite` block's figures disagree — more uncovered than error pixels, a hole larger than its box, the wrong number of holes listed, listed areas that do not sum to `uncovered_error_px`; the last two codes are the block's order and its border names, §5) | re-run assemble; do not edit `parts.json` |
|
|
1710
|
+
| `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` |
|
|
1659
1711
|
|
|
1660
1712
|
### rig
|
|
1661
1713
|
|
|
@@ -1701,14 +1753,16 @@ See-through with another seed.
|
|
|
1701
1753
|
| `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` |
|
|
1702
1754
|
| `BUILD_ARTIFACT_PRESENT` | the packed build lacks its `.json`, `.atlas` or page | a rigc problem; report it |
|
|
1703
1755
|
| `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 |
|
|
1704
|
-
| `REQUIREMENTS_FIELD` | a field of the file is missing, of the wrong type, or not one the format reads: `spec`, `fps` (no default), `requirements`, each requirement's `name` (letters, digits, underscores; once each), `kind`, `animation` and its kind's fields — every bar among them (`within_px`, `fraction`, `tolerance`, `least_drive` above 0, `within_degrees` from 0 to 180, `lo_degrees` ≤ `hi_degrees`, `within_ratio` ≥ 1) — and each target's `bone`, `animation` and exactly one of `at` and `keys` (times strictly increasing). `note`, `*_note` (strings) and `x-…` (any value) are read by nothing, as in the config | write the field; the bar is yours |
|
|
1705
|
-
| `REQUIREMENTS_RESOLVES` | a bone, an `ik` or `transform` constraint (by name and `constraint_type`, as rig-c resolves it), a slot, a mesh attachment or an animation the file names is not in `rig.json` or `motion.json`, or a seam's part is not in `parts.json` — the detail lists the ones that are; or an animation whose name cannot be a directory. Refused before anything is built | the name as the rig spells it |
|
|
1756
|
+
| `REQUIREMENTS_FIELD` | a field of the file is missing, of the wrong type, or not one the format reads: `spec`, `fps` (no default), `requirements`, each requirement's `name` (letters, digits, underscores; once each), `kind`, `animation` and its kind's fields — every bar among them (`within_px`, `fraction`, `tolerance`, `least_drive` above 0, `within_degrees` from 0 to 180, `lo_degrees` ≤ `hi_degrees`, `within_ratio` ≥ 1) — and each target's `bone`, `animation` and exactly one of `at` and `keys` (times strictly increasing), and `not_planted`, `not_swinging` and `rises` when given (each a non-empty list of part names, each once; no part both in `not_swinging` and in `rises`). `note`, `*_note` (strings) and `x-…` (any value) are read by nothing, as in the config | write the field; the bar is yours |
|
|
1757
|
+
| `REQUIREMENTS_RESOLVES` | a bone, an `ik` or `transform` constraint (by name and `constraint_type`, as rig-c resolves it), a slot, a mesh attachment or an animation the file names is not in `rig.json` or `motion.json`, or a seam's part or a `not_planted`, `not_swinging` or `rises` name is not in `parts.json` — the detail lists the ones that are; or an animation whose name cannot be a directory. Refused before anything is built | the name as the rig spells it |
|
|
1706
1758
|
| `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 |
|
|
1707
1759
|
| `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 |
|
|
1708
1760
|
| `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 |
|
|
1709
1761
|
| `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 |
|
|
1710
1762
|
| `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 |
|
|
1711
1763
|
| `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 |
|
|
1764
|
+
| `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 |
|
|
1765
|
+
| `REQUIREMENTS_TIP_EXCEPTION` | a `not_swinging` or `rises` name is a part `TIP_OVER_ROOT` does not read — not from a See-through `handwear` or `bottomwear` layer — or there is no `parts.json` (refused before anything is built); or a `rises` part is not carried by a chain that rises: the chain's first link to its last, at the setup pose, runs other than up, the detail giving the direction measured (refused after the idle is rendered, before `check.json` is written) (issue #231) | a swinging part's name; for `rises`, a part whose chain does rise |
|
|
1712
1766
|
| `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` |
|
|
1713
1767
|
|
|
1714
1768
|
### compose
|
|
@@ -1749,7 +1803,7 @@ assemble*, at the end of this section):
|
|
|
1749
1803
|
- `gate_spine-html.txt`: every summary line `(N passed, 0 failed)` — the packed build
|
|
1750
1804
|
under the `spine-html` profile, gated once over the compile and once over the packed
|
|
1751
1805
|
pages on disk. There is no `spine` gate of its own: `spine-html` holds every rule
|
|
1752
|
-
`spine` measures (on
|
|
1806
|
+
`spine` measures (on reference-demo, rigc 1.5.1 and 2.0.3: `validate --profile spine`'s 14
|
|
1753
1807
|
measured rules are all among the build's 23, the 15 others not in `spine`; rigc
|
|
1754
1808
|
2.1.3 and 2.10.1: the same 14 among the build's 24, which adds
|
|
1755
1809
|
`A49_PACKED_FOOTPRINTS_DO_NOT_OVERLAP` on the packed pass, 16 not in `spine`; `CH09`
|
|
@@ -1760,19 +1814,19 @@ assemble*, at the end of this section):
|
|
|
1760
1814
|
prints and `check.json`'s `seam_frame_scale` holds (issue #216). The frame
|
|
1761
1815
|
holds s² pixels per rig pixel, so a stack that parts from the render over a
|
|
1762
1816
|
fixed area of the rig reads s² times as many frame pixels: on the public
|
|
1763
|
-
`sample` a part moved 2 rig px read 400, 891 and 1,560 frame px over 40 at
|
|
1764
|
-
s = 1.0, 1.5 and 2.0, and 400, 396 and 390 rig px;
|
|
1817
|
+
`reference-sample` a part moved 2 rig px read 400, 891 and 1,560 frame px over 40 at
|
|
1818
|
+
s = 1.0, 1.5 and 2.0, and 400, 396 and 390 rig px; reference-sample as built read
|
|
1765
1819
|
3, 3 and 7 frame px [measured, issue #216]. Divided by s² the bar reads the
|
|
1766
1820
|
same rig at every scale, and at s = 1 it is the reference's count. The mean
|
|
1767
1821
|
is a share of the frame and needs no such division (0.242, 0.188 and 0.226 on
|
|
1768
|
-
|
|
1822
|
+
reference-sample as built; 0.353, 0.305 and 0.340 with the part moved).
|
|
1769
1823
|
`seam_px_over_40` and `seam_px_over_80` stay frame pixels, and so does each
|
|
1770
1824
|
pair's count below. The bar reads one
|
|
1771
1825
|
frame, the setup-pose still, never the idle. When it fails (or when `check
|
|
1772
1826
|
--seam-pairs` asks, pass or fail), the pixels over 40 are split by the pair of
|
|
1773
1827
|
parts that answers for each (issue #202): the two parts drawn last among those
|
|
1774
1828
|
whose art (alpha above 0) lies in the 2x2 rig pixels the composite's bilinear
|
|
1775
|
-
sample reads for that frame pixel, lower first, `(no art)` standing in where
|
|
1829
|
+
reference-sample reads for that frame pixel, lower first, `(no art)` standing in where
|
|
1776
1830
|
fewer than two do. Each pair is a console line `seam pair <i> of <n>: "<a>" /
|
|
1777
1831
|
"<b>" at the setup pose: <count> px over 40 (<count> over 80), frame box x
|
|
1778
1832
|
<x0>..<x1>, y <y0>..<y1>, rig box …, picture seam/<i>_<a>_<b>.png` (in the
|
|
@@ -1818,8 +1872,8 @@ assemble*, at the end of this section):
|
|
|
1818
1872
|
`loop_max_diff`; they are reported, not judged. A rig with none is measured from the
|
|
1819
1873
|
idle render itself, exactly as before, and writes no such line or key.
|
|
1820
1874
|
|
|
1821
|
-
On the examples: `sample` 23/23, seam 0.207 with 0 pixels over 40, loop 0;
|
|
1822
|
-
`demo` (default rule) 23/23, seam 0.326 with 2 pixels over 40, loop 0.
|
|
1875
|
+
On the examples: `reference-sample` 23/23, seam 0.207 with 0 pixels over 40, loop 0;
|
|
1876
|
+
`reference-demo` (default rule) 23/23, seam 0.326 with 2 pixels over 40, loop 0.
|
|
1823
1877
|
|
|
1824
1878
|
A green gate cannot see a wrong animation, so `check` also writes six **judgement
|
|
1825
1879
|
lines** (issue #11; `TEXTURE_STRETCH`, issue #31), each a key of `check.json` and a console line
|
|
@@ -1836,10 +1890,10 @@ model itself fixes (a part on an unkeyed bone does not move, a lag is above 0, a
|
|
|
1836
1890
|
is 0 pixels) is that value, not a margin — and where the model's value is an error
|
|
1837
1891
|
the model fixes at "nothing moves" and the instrument reads exactly (the still regions,
|
|
1838
1892
|
from geometry since issue #123), the bar is the arithmetic's own rounding, derived, not
|
|
1839
|
-
measured. A bar is set once, from the figures of the day it was set, and is not chased: the torso floor 3.809 is half of sample's 7.618, which reads 7.617 since the chain links are turned (issue #73), a factor of 1.9997. The figures are this port's, measured on
|
|
1893
|
+
measured. A bar is set once, from the figures of the day it was set, and is not chased: the torso floor 3.809 is half of reference-sample's 7.618, which reads 7.617 since the chain links are turned (issue #73), a factor of 1.9997. The figures are this port's, measured on
|
|
1840
1894
|
the two examples [observed]:
|
|
1841
1895
|
|
|
1842
|
-
| line | measures | bar | `demo` | `sample` | SKIP when |
|
|
1896
|
+
| line | measures | bar | `reference-demo` | `reference-sample` | SKIP when |
|
|
1843
1897
|
| --- | --- | --- | --- | --- | --- |
|
|
1844
1898
|
| `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` or no `footwear` part |
|
|
1845
1899
|
| `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 |
|
|
@@ -1856,27 +1910,27 @@ centroid of every pixel that was not the background; its fields were `root_px` a
|
|
|
1856
1910
|
mercy of which edge pixels the grid flips: over `--max` 620–660 the pixel figure
|
|
1857
1911
|
scattered around the exact one by up to 0.3 frame px whatever the travel [observed,
|
|
1858
1912
|
13 half-bands on the three examples and a variant], and every **root** half on every
|
|
1859
|
-
example travels 0.04–0.6 frame px, so the ratio's denominator was noise — sample's
|
|
1860
|
-
`bottomwear` read 4.187–6.849 over the sweep, demo's `sleeves` 2.960–6.503, and sample
|
|
1913
|
+
example travels 0.04–0.6 frame px, so the ratio's denominator was noise — reference-sample's
|
|
1914
|
+
`bottomwear` read 4.187–6.849 over the sweep, reference-demo's `sleeves` 2.960–6.503, and reference-sample
|
|
1861
1915
|
with its skirt amplitudes ×0.1 read 0.512–13.53, FAIL or PASS by the grid. The exact
|
|
1862
1916
|
reading of the same definition is the same at every size (4.007 on that skirt, a PASS).
|
|
1863
1917
|
The fields are now `root_rig_px` and `tip_rig_px`, rig px, beside `instrument:
|
|
1864
1918
|
"geometry"`, so an old and a new `check.json` are not read as one instrument. The bar
|
|
1865
|
-
is the one set from the pixel instrument (half of demo's `bottomwear` 2.945, by the
|
|
1866
|
-
rule above, not chased); demo's exact 3.222 clears it 2.19 times. The figures the two
|
|
1919
|
+
is the one set from the pixel instrument (half of reference-demo's `bottomwear` 2.945, by the
|
|
1920
|
+
rule above, not chased); reference-demo's exact 3.222 clears it 2.19 times. The figures the two
|
|
1867
1921
|
instruments give the examples, and `scarf` (whose `bottomwear` is tracked in contour
|
|
1868
1922
|
mode because its lattice fails the line — its README):
|
|
1869
1923
|
|
|
1870
1924
|
| part | pixel, `--max 640` (until #118) | geometry |
|
|
1871
1925
|
| --- | --- | --- |
|
|
1872
|
-
| `demo` `bottomwear`, `sleeves` | 2.990, 3.287 | 3.222, 4.721 |
|
|
1873
|
-
| `sample` `bottomwear`, `sleeves` | 4.396, 12.475 | 4.956, 11.830 |
|
|
1926
|
+
| `reference-demo` `bottomwear`, `sleeves` | 2.990, 3.287 | 3.222, 4.721 |
|
|
1927
|
+
| `reference-sample` `bottomwear`, `sleeves` | 4.396, 12.475 | 4.956, 11.830 |
|
|
1874
1928
|
| `scarf` `handwear_r`, `handwear_l` | 6.242, 5.558 | 6.683, 5.345 |
|
|
1875
1929
|
| `scarf` `bottomwear`, lattice / contour | 4.537 / 2.661 | 1.207 / 1.738 |
|
|
1876
1930
|
|
|
1877
1931
|
The part rendered alone at up to `--max 8000` — the motion spanning pixels — converges
|
|
1878
1932
|
on the geometric figure (`scarf`'s lattice `bottomwear` 1.337, 1.316, 1.285, 1.270 at
|
|
1879
|
-
1200, 2400, 4800, 8000), with one gap not explained: `sample`'s `bottomwear` tip reads
|
|
1933
|
+
1200, 2400, 4800, 8000), with one gap not explained: `reference-sample`'s `bottomwear` tip reads
|
|
1880
1934
|
2.342 rig px there against 2.596 from geometry, its root agreeing to 0.4 %.
|
|
1881
1935
|
|
|
1882
1936
|
**`STILL_REGIONS_DARK` is measured from geometry too, and its scope changed (issue #123).**
|
|
@@ -1889,8 +1943,8 @@ on the geometric figure (`scarf`'s lattice `bottomwear` 1.337, 1.316, 1.285, 1.2
|
|
|
1889
1943
|
|
|
1890
1944
|
Both were means of about one level, and both moved with the grid. Over `--max` 620–660
|
|
1891
1945
|
on the three examples:
|
|
1892
|
-
- demo read 1.03–1.16 times its calibration;
|
|
1893
|
-
- sample read 0.95–1.07;
|
|
1946
|
+
- reference-demo read 1.03–1.16 times its calibration;
|
|
1947
|
+
- reference-sample read 0.95–1.07;
|
|
1894
1948
|
- scarf read 0.99–1.38, with its head-frame mean between 1.350 and 1.869.
|
|
1895
1949
|
|
|
1896
1950
|
The feet half was a screen-space heat mean held to 3.244.
|
|
@@ -1902,7 +1956,7 @@ In all three examples `hair_front` is drawn over the face and weighted to `head`
|
|
|
1902
1956
|
bang bones. Its art swings into the face outline, relative to the head, on every idle
|
|
1903
1957
|
frame:
|
|
1904
1958
|
|
|
1905
|
-
| | `demo` | `sample` | `scarf` |
|
|
1959
|
+
| | `reference-demo` | `reference-sample` | `scarf` |
|
|
1906
1960
|
| --- | --- | --- | --- |
|
|
1907
1961
|
| deepest reach into the face | 2.816 rig px | 2.194 rig px | 2.479 rig px |
|
|
1908
1962
|
| most face area covered on one frame | 89.395 rig px² | 50.605 rig px² | 31.908 rig px² |
|
|
@@ -1960,7 +2014,7 @@ reported `crossing` depth is the only instrument for it.
|
|
|
1960
2014
|
**Before and after, the same builds, only `IDLE_MAX_PX` changed** (scratch copies of the
|
|
1961
2015
|
tree):
|
|
1962
2016
|
|
|
1963
|
-
| `--max` | before: face mean / calibration (ratio), feet mean, demo · sample · scarf | after: face `max_rig_px`, feet `max_rig_px`, all three |
|
|
2017
|
+
| `--max` | before: face mean / calibration (ratio), feet mean, reference-demo · reference-sample · scarf | after: face `max_rig_px`, feet `max_rig_px`, all three |
|
|
1964
2018
|
| --- | --- | --- |
|
|
1965
2019
|
| 620 | 1.283 / 1.196 (1.07), 1.504 · 0.933 / 0.900 (1.04), 0 · 1.350 / 1.360 (0.99), 0 | 4.202e-13, 0 · 4.418e-13, 0 · 4.224e-13, 0 |
|
|
1966
2020
|
| 640 | 1.328 / 1.145 (1.16), 1.619 · 0.898 / 0.897 (1.00), 0 · 1.869 / 1.352 (1.38), 0 | the same |
|
|
@@ -1978,7 +2032,7 @@ The selftest's planted cases (by hand):
|
|
|
1978
2032
|
|
|
1979
2033
|
After them, one **reported line** with no bar:
|
|
1980
2034
|
|
|
1981
|
-
| line | reports | bar | `demo` | `sample` | SKIP when |
|
|
2035
|
+
| line | reports | bar | `reference-demo` | `reference-sample` | SKIP when |
|
|
1982
2036
|
| --- | --- | --- | --- | --- | --- |
|
|
1983
2037
|
| `RECOMPOSITE_HOLES` | `parts.json`'s `recomposite` block (§5), read rather than measured: `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) |
|
|
1984
2038
|
|
|
@@ -1996,16 +2050,16 @@ look at `recomposite_error_rig.png` when the largest hole is more than a sliver.
|
|
|
1996
2050
|
Under `--source <painting.png>`, a second reported line, also never a FAIL
|
|
1997
2051
|
(issue #77):
|
|
1998
2052
|
|
|
1999
|
-
| line | reports | bar | `demo` | `sample` | SKIP when |
|
|
2053
|
+
| line | reports | bar | `reference-demo` | `reference-sample` | SKIP when |
|
|
2000
2054
|
| --- | --- | --- | --- | --- | --- |
|
|
2001
2055
|
| `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` |
|
|
2002
2056
|
|
|
2003
2057
|
The figures are assemble's by construction, not a second definition beside them;
|
|
2004
2058
|
what differs is what they are taken of — the pose rigc draws, not the flat stack —
|
|
2005
2059
|
and the gap between the two columns above is that drawing: the render's resampling at
|
|
2006
|
-
its scale (0.942 on
|
|
2060
|
+
its scale (0.942 on reference-demo, 1.012 on reference-sample) and the warp back onto the stage,
|
|
2007
2061
|
which soften every part edge by a pixel or two. It moves with the render's grid
|
|
2008
|
-
[observed,
|
|
2062
|
+
[observed, reference-demo's still rendered at four sizes: mean 2.663 at scale 1.0003, 3.091
|
|
2009
2063
|
at 1.0073, 3.146 at 0.942, 3.186 at 1.884], so compare the line with itself across
|
|
2010
2064
|
rigs or edits, and with `RECOMPOSITE_HOLES` for where a hole is, not digit for digit
|
|
2011
2065
|
with the recomposite. On the examples the line reads the same with and without
|
|
@@ -2035,11 +2089,11 @@ What each figure is, and is not:
|
|
|
2035
2089
|
chains of both examples are written the first way — so the reading folds a step into
|
|
2036
2090
|
(−¼, ¼] of a cycle and reports amplitudes unsigned. A lag of a quarter cycle or more
|
|
2037
2091
|
cannot be told from a lead. Tracks whose keys are not a sampled sine are listed as
|
|
2038
|
-
`unread`, and a keyed bone under a keyed ancestor of another period (
|
|
2092
|
+
`unread`, and a keyed bone under a keyed ancestor of another period (reference-demo's
|
|
2039
2093
|
tassel under the head) is listed in `other_period` and not compared.
|
|
2040
2094
|
- **Tip over root is a centroid, not a displacement.** Art entering or leaving a half
|
|
2041
2095
|
moves its centroid too. The halves' mean heat was the brief's first choice and was
|
|
2042
|
-
rejected: heat is texture times motion, and on
|
|
2096
|
+
rejected: heat is texture times motion, and on reference-demo's sleeves the lower half's
|
|
2043
2097
|
mean heat is 1.1 times the upper half's while its centroid travels 3.7 times as far.
|
|
2044
2098
|
The halves split the box across its rows, which assumes the part hangs — true of a
|
|
2045
2099
|
front-facing standing figure, the only input this tool takes.
|
|
@@ -2047,9 +2101,9 @@ What each figure is, and is not:
|
|
|
2047
2101
|
distorts a texture as much as stretch — an edge at half its rest length squeezes
|
|
2048
2102
|
the texels on it by the factor an edge at twice its length spreads them — so the
|
|
2049
2103
|
figure is max(ratio, 1/ratio), and on both examples the worst triangle is a
|
|
2050
|
-
compression (demo 0.720, sample 0.815). The ceiling rule is applied to the quantity
|
|
2104
|
+
compression (reference-demo 0.720, reference-sample 0.815). The ceiling rule is applied to the quantity
|
|
2051
2105
|
whose zero means "nothing happened", as it is for heat: for a ratio that is |ln r|,
|
|
2052
|
-
so twice demo's |ln 1.388| is ln(1.388²) = ln 1.926544 and sample clears it by 3.2
|
|
2106
|
+
so twice reference-demo's |ln 1.388| is ln(1.388²) = ln 1.926544 and reference-sample clears it by 3.2
|
|
2053
2107
|
times. Doubling the ratio itself (2.776) was rejected: its zero is not at 1, and it
|
|
2054
2108
|
passes an edge drawn at 2.7 times its rest length. The rest is the art's own
|
|
2055
2109
|
proportions — on both examples every rest edge equals its `uvs` edge times the
|
|
@@ -2080,7 +2134,7 @@ What each figure is, and is not:
|
|
|
2080
2134
|
its depth is reported per slot in `crossing`, which no bar reads.
|
|
2081
2135
|
- **The feet are measured in screen space.** They ride the root, which the idle does not
|
|
2082
2136
|
key, so the screen is their own frame.
|
|
2083
|
-
- Until #123 the feet half read the screen-space heat. On
|
|
2137
|
+
- Until #123 the feet half read the screen-space heat. On reference-demo the long skirt,
|
|
2084
2138
|
drawn under the shoes, swings beside them and lit their rim to 1.622.
|
|
2085
2139
|
- From the geometry, nothing drawn over the shoes enters them on any example, and
|
|
2086
2140
|
the shoes move exactly 0.
|
|
@@ -2116,7 +2170,7 @@ it reads is there, and says SKIP with the reason when it is not:
|
|
|
2116
2170
|
`PASS` reads every bar that measured, and the last console line says how many did:
|
|
2117
2171
|
`check: PASS; 1 of 9 bar(s) measured, 8 skipped (loop, seam, …)` is a rig whose gate is
|
|
2118
2172
|
green and nothing else was looked at. Without an idle no idle is rendered
|
|
2119
|
-
(`idle_frames/`, `contact.png` and `motion_heat.png` are not written).
|
|
2173
|
+
(`idle_frames/`, `contact.png` and `motion_heat.png` are not written). Reference-demo's own
|
|
2120
2174
|
rig directory, copied away from its `parts.json`, reads `4 of 9`: the gate, the loop,
|
|
2121
2175
|
`CHAIN_LAG` and `TEXTURE_STRETCH`.
|
|
2122
2176
|
|
|
@@ -2152,7 +2206,7 @@ What is composed:
|
|
|
2152
2206
|
|
|
2153
2207
|
- **Images are `<id>.<file>`, not `<id>:<file>`.** rig-c names an atlas region
|
|
2154
2208
|
by its PNG's basename, and an atlas region line that holds `:` is read as a
|
|
2155
|
-
`key: value` line: measured through rig-c 2.15.0 on
|
|
2209
|
+
`key: value` line: measured through rig-c 2.15.0 on reference-demo renamed
|
|
2156
2210
|
`demo:<name>` with images `demo:<file>`, `A07_ATLAS_TEXT_SHAPE` fails once per
|
|
2157
2211
|
region; with the images under a `demo/` folder the rig gates green but the region
|
|
2158
2212
|
keeps the bare basename, so two characters' `face` would collide. So the
|
|
@@ -2266,6 +2320,34 @@ unit (the stage box maps to the world by a translation and the y flip,
|
|
|
2266
2320
|
}
|
|
2267
2321
|
```
|
|
2268
2322
|
|
|
2323
|
+
**Feet that are not planted** (issue #231). The feet halves of `BREATH_VISIBLE` and
|
|
2324
|
+
`STILL_REGIONS_DARK` assume a figure that stands: every `footwear` part holds still.
|
|
2325
|
+
Whether the figure stands is the scene's knowledge, so a scene where it sits and its
|
|
2326
|
+
legs swing says so here, by part: `"not_planted": ["shoes"]`. Each name must be a
|
|
2327
|
+
`footwear` part in `parts.json` (`REQUIREMENTS_RESOLVES`, `REQUIREMENTS_NOT_PLANTED`).
|
|
2328
|
+
A declared part is left out of both feet halves, and the declaration is the first
|
|
2329
|
+
figure of each line it relaxes — `declared_not_planted` in `BREATH_VISIBLE`, and in
|
|
2330
|
+
`STILL_REGIONS_DARK`'s `feet` — in `check.json` and on the console, so a relaxed bar
|
|
2331
|
+
never reads as a passed one. With every foot declared, the torso is still measured
|
|
2332
|
+
(`feet_parts` `[]`, `feet_heat_max` null) and the feet half reads `unmeasured` with
|
|
2333
|
+
the reason. The field absent, nothing changes: every `footwear` part is a planted foot.
|
|
2334
|
+
|
|
2335
|
+
**Swinging parts that do not hang** (issue #231). `TIP_OVER_ROOT` reads every
|
|
2336
|
+
`handwear` and `bottomwear` part as hanging: the lower half of its box is the tip's.
|
|
2337
|
+
Two declarations, by part, say where that does not hold. `"not_swinging": ["under"]`
|
|
2338
|
+
— a piece cut off and left still — leaves the part out of the bar; its row reads
|
|
2339
|
+
`unmeasured` with the reason. `"rises": ["arm"]` — a forearm raised from the elbow —
|
|
2340
|
+
reads the part's **upper** half as the tip's (its row carries `tip_half: "upper"`),
|
|
2341
|
+
and only after checking the chain that carries it does rise: the part's bound bones
|
|
2342
|
+
walked up to a chain `CHAIN_LAG` reads, its first link's origin to its last at the
|
|
2343
|
+
setup pose, read along its longer axis, must run up, or the declaration is refused
|
|
2344
|
+
naming the direction measured. The line's first figures after `status` are
|
|
2345
|
+
`declared_not_swinging` and `declared_rises`. Each name must be a swinging part in
|
|
2346
|
+
`parts.json`, and no part may be in both lists.
|
|
2347
|
+
|
|
2348
|
+
`fps` and `requirements` are required as always; a file that declares only exceptions
|
|
2349
|
+
is `{ "spec": "spine-parts-requirements/1", "fps": 12, "requirements": [], "not_planted": ["shoes"], "not_swinging": ["under"], "rises": ["arm"] }`.
|
|
2350
|
+
|
|
2269
2351
|
**Four outcomes, never merged** (#87):
|
|
2270
2352
|
|
|
2271
2353
|
| outcome | when | what it does to the run |
|
|
@@ -2367,21 +2449,21 @@ is built (`CK83`–`CK85`, `RQ30`–`RQ35`).
|
|
|
2367
2449
|
|
|
2368
2450
|
## 8. What one character costs
|
|
2369
2451
|
|
|
2370
|
-
| step | sample | demo | source |
|
|
2452
|
+
| step | reference-sample | reference-demo | source |
|
|
2371
2453
|
| --- | --- | --- | --- |
|
|
2372
|
-
| painting (GPU) | 20.2 s | 18.3 s | `generation.json` `elapsed_s`, in [
|
|
2454
|
+
| painting (GPU) | 20.2 s | 18.3 s | `generation.json` `elapsed_s`, in [parts-examples](https://github.com/rig-c/parts-examples) |
|
|
2373
2455
|
| See-through full run (GPU) | 194.9 s | 198.5 s | `inputs/layers/full/meta.json` `elapsed_s` |
|
|
2374
2456
|
| See-through head run (GPU) | 170.9 s | 171.4 s | `inputs/layers/head/meta.json` `elapsed_s` |
|
|
2375
2457
|
| `build` (CPU, user + sys) | 14.6 s | 30.7 s | measured with `/usr/bin/time -p` on an Apple M4 machine under other load, rigc's child processes included; wall clock 12.7 s and 27.5 s |
|
|
2376
2458
|
|
|
2377
2459
|
About 6.5 minutes of GPU and under a minute of CPU per character, before any hand
|
|
2378
2460
|
correction. The GPU figures are one run each on one machine; the painting's figure
|
|
2379
|
-
excludes choosing among seeds (
|
|
2461
|
+
excludes choosing among seeds (reference-demo was chosen from eighteen candidates).
|
|
2380
2462
|
Since issue #33 `check` runs one more `rigc build` and one more idle render (the face
|
|
2381
2463
|
calibration, §7); the idle's `geometry.json` is the one issue #31 already writes. The `build` row
|
|
2382
2464
|
was not re-measured: A/B against the tree before that change, alternating on one
|
|
2383
2465
|
machine under a load average of 5 to 11, the difference in user + sys was +5.6 and
|
|
2384
|
-
+0.8 s on
|
|
2385
|
-
the load moves the same build by (the pre-change demo build alone took 43.6 to
|
|
2466
|
+
+0.8 s on reference-demo and +6.5 and −1.6 s on reference-sample over two rounds — inside what
|
|
2467
|
+
the load moves the same build by (the pre-change reference-demo build alone took 43.6 to
|
|
2386
2468
|
45.8 s there). Since issue #123 that build and render are gone again — the still regions read the
|
|
2387
2469
|
idle's geometry — and the `build` row was not re-measured for it either.
|