spine-rigc 1.4.0 → 1.5.1
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/cli.ts +8 -5
- package/docs/AUTHORING.md +155 -27
- package/docs/INGEST.md +20 -13
- package/docs/MOTION.md +31 -17
- package/package.json +1 -1
- package/src/atlas.ts +145 -24
- package/src/check.ts +22 -0
- package/src/compile.ts +6 -1
- package/src/keys.ts +87 -0
- package/src/motion.ts +7 -1
- package/src/pose.ts +260 -13
- package/src/render.ts +192 -22
- package/src/rig.ts +46 -2
- package/src/validate.ts +34 -4
package/cli.ts
CHANGED
|
@@ -103,7 +103,6 @@ import {
|
|
|
103
103
|
DEFAULT_PADDING,
|
|
104
104
|
DEFAULT_PAGE_EDGES,
|
|
105
105
|
DEFAULT_PAGE_SIZE,
|
|
106
|
-
FREE_EDGE_STEP,
|
|
107
106
|
PAGE_EDGES,
|
|
108
107
|
packAtlas,
|
|
109
108
|
type PageEdges,
|
|
@@ -2054,6 +2053,9 @@ function cmdRender(flags: Record<string, string>): void {
|
|
|
2054
2053
|
if (skin !== undefined) console.log(` .. skin ${skin}`);
|
|
2055
2054
|
if (subset !== undefined) console.log(` .. ${subset.mode.padEnd(8)} ${subset.names.join(', ')}`);
|
|
2056
2055
|
|
|
2056
|
+
// `null` is a skeleton that posed no vertex at all. One that posed a vertex
|
|
2057
|
+
// it cannot frame — Infinity or NaN — is thrown from the framing as a
|
|
2058
|
+
// `GeometryError` naming the number (issue #873), and never reaches this.
|
|
2057
2059
|
const viewport = framingViewport(data, maxSide, pose);
|
|
2058
2060
|
if (!viewport) {
|
|
2059
2061
|
throw new UsageError(
|
|
@@ -3825,7 +3827,7 @@ const FLAG_MEANINGS: Record<string, string> = {
|
|
|
3825
3827
|
padding: `gutter each region reserves on every side, --pack only (default ${DEFAULT_PADDING}); it is filled by ` +
|
|
3826
3828
|
"extending the region's own edge pixels outwards, which is what stops a neighbour bleeding in",
|
|
3827
3829
|
'page-edges': `what a page's edges may be, --pack only (default ${DEFAULT_PAGE_EDGES}): pot is a power of two on ` +
|
|
3828
|
-
|
|
3830
|
+
'both; free tries every width from the widest part up, takes the height the placement needs and keeps ' +
|
|
3829
3831
|
'the least area — a smaller page, at the cost of region attachments sampling within 1 LSB of the loose ' +
|
|
3830
3832
|
'build rather than exactly',
|
|
3831
3833
|
'atlas-in':
|
|
@@ -4539,9 +4541,10 @@ try {
|
|
|
4539
4541
|
// the one reader's and already names the file, what it is and what rigc
|
|
4540
4542
|
// reads; a stack under it is the tool describing its own internals instead.
|
|
4541
4543
|
// Exit 1, like a compile error: the invocation was fine, a file was not.
|
|
4542
|
-
// A pose
|
|
4543
|
-
//
|
|
4544
|
-
//
|
|
4544
|
+
// A pose that is not finite (issues #864, #873): the invocation was fine and
|
|
4545
|
+
// the skeleton posed a NaN or an infinity, so exit 1 like a file that is not
|
|
4546
|
+
// a PNG. Raised by the geometry export and by the framing — the one sentence
|
|
4547
|
+
// naming the bone or vertex and its value — before the first file is written.
|
|
4545
4548
|
if (err instanceof GeometryError) {
|
|
4546
4549
|
console.error(`rigc render: ${err.message}`);
|
|
4547
4550
|
process.exit(1);
|
package/docs/AUTHORING.md
CHANGED
|
@@ -341,9 +341,12 @@ a gap:
|
|
|
341
341
|
|
|
342
342
|
Under `pot` turning shrank no page. Under `free` the largest gain, 13.37 %, is
|
|
343
343
|
inside the search's own noise: the neighbouring width on the 32-pixel grid
|
|
344
|
-
moves that set's unturned page by 18.13 %, and trying
|
|
345
|
-
finds an unturned page 10.22 % smaller. With every width
|
|
346
|
-
more than 5.05 % from turning — so the packer still never
|
|
344
|
+
`free` then searched moves that set's unturned page by 18.13 %, and trying
|
|
345
|
+
every width instead finds an unturned page 10.22 % smaller. With every width
|
|
346
|
+
tried, no set gains more than 5.05 % from turning — so the packer still never
|
|
347
|
+
turns a region. (The `free` column is that day's 32-pixel grid. `free` has
|
|
348
|
+
tried every width since issue #872 — below — so the 5.05 % is the turn gain on
|
|
349
|
+
the search that ships.)
|
|
347
350
|
- **no re-ordering of anything the skeleton says.** `skeleton.json` from a packed
|
|
348
351
|
build is **byte-identical** to the unpacked one, because sizes are still
|
|
349
352
|
measured from the loose PNGs and packing is an output arrangement.
|
|
@@ -383,7 +386,7 @@ every power-of-two pair up to `--page-size` in order of area and writes the firs
|
|
|
383
386
|
the pack fits — it never doubles past a smaller page that would do. So when the
|
|
384
387
|
parts' own area already exceeds the next power-of-two page down, no `pot` packer
|
|
385
388
|
can do better, and `free` is the lever left. Under `free` the candidate widths
|
|
386
|
-
are
|
|
389
|
+
are **every width** from the widest padded part up to `--page-size`; at each
|
|
387
390
|
width the parts are placed by the same MaxRects pass on a page `--page-size`
|
|
388
391
|
tall, and the height is the bottom edge of the lowest part. The page with the
|
|
389
392
|
least area wins, then the squarer one (smaller |width − height|), then the
|
|
@@ -391,13 +394,65 @@ narrower one — every candidate has a different width, so the order is total an
|
|
|
391
394
|
two builds of the same parts write the same bytes. Spilling, the packing order
|
|
392
395
|
and `--page-size` as the ceiling are the same as under `pot`.
|
|
393
396
|
|
|
397
|
+
Every width is affordable because of two bounds, and neither can change the
|
|
398
|
+
page: a width is not tried when the parts' area cannot fit it or when its
|
|
399
|
+
tallest part alone already makes it larger than the best page so far, and a
|
|
400
|
+
placement stops as soon as its lowest part makes it larger than that best page.
|
|
401
|
+
Both are strict, so a width that could tie the best is always placed to the end.
|
|
402
|
+
|
|
403
|
+
**Why every width, measured (issue #872).** Until then the widths were the
|
|
404
|
+
multiples of 32. On twelve region sets — the two painting rigs below and ten
|
|
405
|
+
production rigs of 20 to 22 parts, the sets of the rotation table above — and,
|
|
406
|
+
as a held-out check, on the ten atlases of the fetched `examples/` corpus, each
|
|
407
|
+
search was run against the every-width page (padding 2, `--page-size` 2048).
|
|
408
|
+
Area change against the 32-pixel grid:
|
|
409
|
+
|
|
410
|
+
| Set | 32 px (before) | step 8 | step 4 | coarse 32 → ±31 px of the best 2 | coarse 12 → ±11 px of the best | every width (now) |
|
|
411
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
412
|
+
| 22-part painting | 1888x697 | −1.58 % | −1.58 % | −1.68 % | −1.68 % | 967x1338, −1.68 % |
|
|
413
|
+
| 20-part painting | 480x1166 | 0.00 % | 0.00 % | −0.21 % | −0.21 % | 479x1166, −0.21 % |
|
|
414
|
+
| P1 | 416x1633 | −1.92 % | −2.88 % | −2.88 % | −2.88 % | 404x1633, −2.88 % |
|
|
415
|
+
| P2 | 1184x810 | 0.00 % | 0.00 % | −0.08 % | −0.08 % | 1183x810, −0.08 % |
|
|
416
|
+
| P3 | 480x1000 | 0.00 % | 0.00 % | 0.00 % | 0.00 % | 480x1000, 0.00 % |
|
|
417
|
+
| P4 | 864x1346 | −3.07 % | −3.07 % | −2.66 % | −3.15 % | 1231x915, −3.15 % |
|
|
418
|
+
| P5 | 1344x1768 | −9.90 % | −10.16 % | −10.22 % | −10.22 % | 1427x1495, −10.22 % |
|
|
419
|
+
| P6 | 800x1934 | −1.00 % | −1.50 % | −1.50 % | −1.50 % | 788x1934, −1.50 % |
|
|
420
|
+
| P7 | 1024x928 | −0.78 % | −0.78 % | −0.88 % | −0.88 % | 1015x928, −0.88 % |
|
|
421
|
+
| P8 | 608x1250 | 0.00 % | 0.00 % | −0.16 % | −0.16 % | 607x1250, −0.16 % |
|
|
422
|
+
| P9 | 1024x2037 | −2.34 % | −2.73 % | −2.93 % | −2.93 % | 994x2037, −2.93 % |
|
|
423
|
+
| P10 | 352x1433 | 0.00 % | −1.14 % | −1.70 % | −1.70 % | 346x1433, −1.70 % |
|
|
424
|
+
| worst miss of the every-width page, twelve sets | 11.38 % | 1.73 % | 0.58 % | 0.50 % | 0.00 % | 0.00 % |
|
|
425
|
+
| worst miss, the ten `examples/` atlases | 4.12 % | 2.67 % | 0.77 % | 0.82 % | 0.82 % | 0.00 % |
|
|
426
|
+
| cell placements, twelve sets | 12,361 | 49,063 | 98,021 | 40,230 | 38,371 | 47,978 |
|
|
427
|
+
|
|
428
|
+
The rule was the cheapest search that lands on the every-width page. Flipping
|
|
429
|
+
the packer's own last tie-break (leftmost before topmost) changes no page on any
|
|
430
|
+
of the 22 sets, so there is no tie-break noise to land "within": the target is
|
|
431
|
+
the page itself. The coarse-to-fine search that met it on all twelve sets missed
|
|
432
|
+
it on the first held-out atlas, and its failures do not follow its grid — on
|
|
433
|
+
the twelve sets, refining around the best width of a 9-pixel grid misses where
|
|
434
|
+
10 to 12 do not, and a 14-pixel grid misses again —
|
|
435
|
+
because the area as a function of the width has minima one pixel wide (a 4-pixel
|
|
436
|
+
grid refined around its best four widths still misses one). Every width is exact
|
|
437
|
+
by construction. Its placement count overstates its cost, because an abandoned
|
|
438
|
+
placement stops early: all twelve sets take 53 ms in the measuring harness,
|
|
439
|
+
against 22 ms for the 32-pixel grid and 810 ms for every width unbounded, and a
|
|
440
|
+
whole `build --pack --page-edges free` of the 22-part rig takes the same wall
|
|
441
|
+
time either way. ⚠️ The cost grows with the part count faster than the grid's:
|
|
442
|
+
on generated sets of 100 and 300 small parts, where no bound prunes much, the
|
|
443
|
+
search places 15 times the grid's cells.
|
|
444
|
+
|
|
394
445
|
The default stays `pot` because every runtime accepts a power-of-two page and
|
|
395
446
|
the editor's own packer writes one by default: 9 of the 10 atlases in the
|
|
396
447
|
fetched `examples/` corpus are power-of-two on both edges. What `free` costs is
|
|
397
448
|
the exactness above. `x / pageWidth` is no longer exact, so a **region**
|
|
398
449
|
attachment's samples join a mesh's at one least significant bit against the
|
|
399
450
|
loose build instead of 0. No region's bytes change: every one lifts back byte for
|
|
400
|
-
byte, as under `pot`. Observed on two painting rigs of 22 and 20 parts
|
|
451
|
+
byte, as under `pot`. Observed on two painting rigs of 22 and 20 parts, on the
|
|
452
|
+
32-pixel grid `free` shipped with (issue #860); every width now packs them at
|
|
453
|
+
967x1338 = 1,293,846 (−38.3 %, 91.2 % covered, 59.7 % opaque) and 479x1166 =
|
|
454
|
+
558,514 (−46.7 %, 93.4 % covered, 53.9 % opaque), and the render columns are
|
|
455
|
+
held to their bound of one by `PK72` on every build rather than re-measured here:
|
|
401
456
|
|
|
402
457
|
| Rig | `pot` page | `free` page | Area | Covered | Opaque (alpha > 0) | Render vs loose, region attachments only | Render vs loose, whole rig |
|
|
403
458
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
@@ -1243,6 +1298,14 @@ emitted as written, in the default skin or anywhere else.
|
|
|
1243
1298
|
`spec` must be exactly `"rigc-rig/1"`. `name` must be a non-empty string. `bones`
|
|
1244
1299
|
must be non-empty. `slots` must be present (it may be empty).
|
|
1245
1300
|
|
|
1301
|
+
🔢 **Every number in a rig spec is finite at float32 precision** — at most
|
|
1302
|
+
±3.4028234663852886e38 — whatever field it is in, so the ranges the tables below
|
|
1303
|
+
state are ranges *within* that. The skeleton is written as float32, and a number
|
|
1304
|
+
past that line would be emitted as Infinity, which JSON writes as `null`: `1e309`
|
|
1305
|
+
(which JSON reads as Infinity) and `1e308` (a finite double with no float32) are
|
|
1306
|
+
both refused by the field they are in, before anything is compiled (§5.1). The cut
|
|
1307
|
+
manifest and the motion spec are held to the same line.
|
|
1308
|
+
|
|
1246
1309
|
🚫 **Every example value below is invented.** Names, coordinates, vertex lists and
|
|
1247
1310
|
payloads in this guide are written to illustrate a field, never copied out of a
|
|
1248
1311
|
reference export — an example lifted from one would be handing an authoring agent an
|
|
@@ -1443,6 +1506,20 @@ renderers and reports its step 5 as a **SKIP** naming that, and the round trip
|
|
|
1443
1506
|
comes back green on the strength of `validate` and `diff`. A skin only **one** side
|
|
1444
1507
|
can draw is the other case entirely, and stays red.
|
|
1445
1508
|
|
|
1509
|
+
🔢 **"Nothing to draw" is said only of a skeleton that posed no vertex at all.** One
|
|
1510
|
+
whose attachment is there but posed to `Infinity` or `NaN` is refused by the bone or
|
|
1511
|
+
the vertex that holds it and the value — `rigc render: the setup pose: bone "head" has
|
|
1512
|
+
worldX Infinity; a world transform is finite`, or `… animation "turn" frame 31 at 60
|
|
1513
|
+
fps (t=0.5167s): bone "head" has a NaN; …` for a key, or `… slot "x" attachment "y"
|
|
1514
|
+
vertex 3 has x NaN; a posed vertex is finite` — exit 1, before anything is written.
|
|
1515
|
+
It is the sentence `render --geometry` refuses on (§8.2), from the same code, and
|
|
1516
|
+
`rigc check` prints it after `the candidate is posed to a number that is not finite,
|
|
1517
|
+
so no frame of it can be compared:`. The bone is named before its vertices because
|
|
1518
|
+
it is the cause; look for its value in the skeleton file — a setup `x`/`y`/`rotation`,
|
|
1519
|
+
or a timeline key at the time given — and, for a rig spec you wrote, in `rigc explain`,
|
|
1520
|
+
which prints every bone's local transform. A frame's time is the framing pass's own
|
|
1521
|
+
(every animation at 60 fps); the key that overflowed is at or just before it.
|
|
1522
|
+
|
|
1446
1523
|
**Region attachment** ([Spine: region attachments](http://esotericsoftware.com/spine-regions)),
|
|
1447
1524
|
the default `type`:
|
|
1448
1525
|
|
|
@@ -5359,6 +5436,16 @@ rather than linked, like the references at the top of this page: that page cites
|
|
|
5359
5436
|
corpus inventory, and a ladder run reads this guide without following its references
|
|
5360
5437
|
out of it.)
|
|
5361
5438
|
|
|
5439
|
+
🔢 **A fourth surface is a pose that is not finite**, which `render` and `check`
|
|
5440
|
+
refuse before drawing anything, naming the bone or vertex and its value.
|
|
5441
|
+
`A10_NO_NAN_AFTER_STEPPING` reads the same scan, so on a skeleton with an animation
|
|
5442
|
+
`validate` gets there first and in the same words: a bone `rotation` of `1e309`, in
|
|
5443
|
+
the setup pose or in a key, leaves the bone's world position finite and its matrix
|
|
5444
|
+
`NaN`, and A10 names the bone and the term. What it does not see is a skeleton with
|
|
5445
|
+
no animation (A10 SKIPs, so `render` is where that one is named) and a skin other
|
|
5446
|
+
than the default, which A10 does not pose. The sentence, and where to look for the
|
|
5447
|
+
number, is under *nothing to draw* in §3.4.
|
|
5448
|
+
|
|
5362
5449
|
### 5.1 Compile errors — before the gate
|
|
5363
5450
|
|
|
5364
5451
|
A `CompileError` names the object and the field, and nothing is written.
|
|
@@ -5482,6 +5569,7 @@ or the key's position in its own track. These are the frequent ones, verbatim:
|
|
|
5482
5569
|
| `a rig spec needs a non-empty "bones" array` | §3.2 — a rig with no bones has nothing to hang a slot on; every one has at least a root |
|
|
5483
5570
|
| `a rig spec needs a "slots" array (it may be empty; its ORDER is the draw order)` | §3.3 — write `[]` for a rig that draws nothing. ⚠️ These three arrive only when the key is really absent: **misspelt**, it is the unknown-key refusal above, naming what you wrote |
|
|
5484
5571
|
| `bone "X" names parent "Y", which is not declared before it` | move `Y` earlier in `bones` |
|
|
5572
|
+
| `<file>: <where> is Infinity; a number in this file is finite at float32 precision, at most ±3.4028234663852886e+38, because the skeleton is written as float32 — …` (also `is -Infinity`, `is 1e+308`, and `is NaN` from a library caller) | §3 — state the number you meant, inside float32's range. One walk over the whole file, run right after the key scan and before any other rig-spec check, so a range rule never prints `NaN`. `<where>` is every number in the rig spec — a bone (`bone "hip" x`), a slot, a skin's attachment down to its arrays (`skin "default" slot "s" attachment "a" weights[3][1].x`), a constraint (`constraint "aim" mixRotate`), an event, `skeleton`, `invariants.meshTriangles` — and the dotted path in the cut manifest (`crop.h`) and in the motion spec (`` `animations.idle.tracks[0].keys[1].v[0]` ``, after the motion spec's own field checks, which keep their sentences). ⚠️ It sees numbers only: `"x": "NaN"` is a string and is not refused by this row — write a number as a JSON number |
|
|
5485
5573
|
| `two bones are called "X"` | bone names are the join key; rename one |
|
|
5486
5574
|
| `two ik constraints are called "X" — a constraint resolves by name AND type (\`SkeletonData.findConstraint\`), so names are unique PER KIND: an ik and a transform constraint may share one, two of a kind may not` | §3.5 — rename one of the two. The kind in the sentence is the pair's own, so `two transform constraints are called "X"` is the same refusal on another kind; a name shared **across** kinds is not this error |
|
|
5487
5575
|
| `physics constraint "X" is declared in both the rig spec and the motion spec's physics table` | §4.6 — the rig spec declares a physics constraint's structure and the motion spec's `physics` table declares one outright; pick the file it belongs in. Per kind, like every other constraint name: an `ik` "X" in the rig spec beside a `physics` "X" here is two constraints and is not this error |
|
|
@@ -5707,7 +5795,7 @@ Fix A00 and run it again.
|
|
|
5707
5795
|
| `A07_ATLAS_TEXT_SHAPE` | both | atlas text: a region name with stray whitespace, or a blank line splitting a page block. rigc writes the atlas, so this means a hand-edited file. Three sentences are about blank lines and name three different repairs: `line 1: the file begins with a blank line` (or `with N blank lines` for a run, one finding) is a blank before the first page name — delete it; `line N: the file ends with a blank line` (or `with N blank lines`, one finding) is a blank after the last page block's final line — delete it, since rigc ends the file on one newline; `line N: consecutive blank lines` is two blank lines side by side between the first page and the last — delete one. None of the three is `the last page block declares no region`, which means a page name and its fields with no region after them. rigc writes none of the three: under `--atlas-in` the pack's blank lines are put in rigc's shape on re-emission (§0.2), so any of them means a file rigc did not write, handed to `validate`. ⚠️ An atlas with **no page block at all** — no non-blank line — is not one of those: its subject is absent, so this reports **SKIP** naming the byte count it read, and so do the four rules below whose subject is a page ([#608](https://github.com/firejune/rigc/issues/608)). A rig whose skins need no art writes exactly that file (§3.4), and before #608 this row refused it with two findings naming a page block that was not there. What an empty atlas does **not** excuse is an attachment that wants a region out of it — that is `A08` |
|
|
5708
5796
|
| `A08_REGION_NAMES_MATCH_ATTACHMENTS` | both | three things, and the message says which: an attachment whose `path` names **no region** of this atlas; a `path` carrying **stray whitespace**, printed quoted so you can see it; an **atlas region name** carrying stray whitespace (`A07` names that same line with its line number). The first two are read off the raw file **before** the loader is asked, so the miss is named here with the skin, the slot, the placeholder and the attachment's own name — the four things `AtlasAttachmentLoader`'s own `Region not found in atlas: <path> (attachment: <name>)` does not carry. There is no `spine-html` clause here — a placeholder is free to differ from the region its `path` names **SKIP** when no attachment names a region *and* the atlas declares none — both of its subjects at once |
|
|
5709
5797
|
| `A09_ANIMATION_DURATION_MATCHES_SPEC` | both | the loaded duration ≠ the declared one, or the two sides disagree about which animations exist (R7). Asymmetric by design: a frame of slack for an animation that ends early, and none worth the name for a key *past* the declared end, which is the same rule §4.5 states at compile time — held here against a skeleton the compiler never saw. **SKIP** when neither side has an animation at all — a static rig has no duration |
|
|
5710
|
-
| `A10_NO_NAN_AFTER_STEPPING` | both | stepping the animation produced a `
|
|
5798
|
+
| `A10_NO_NAN_AFTER_STEPPING` | both | stepping the animation produced a pose that is not finite. It reads the **whole world transform** — all six terms `a`, `b`, `c`, `d`, `worldX`, `worldY` of every bone — then every vertex of every region and mesh the slots show, at the **setup pose** and at every stepped frame of every animation, through the same scan `render` refuses on, so the two cannot disagree. The detail names where (`the setup pose`, or `animation "x" frame i of 120 (t=…s)`), then the bone and the term (`bone "x" has a NaN`), or the slot, attachment and vertex (`vertex 3 has x Infinity`) when every bone is finite and a vertex is not — a `scaleX` chain whose product stays under the largest double does that. A bone at `rotation: 1e309` has a finite position and a `NaN` matrix, which is why the position alone is not read. Look for a number past the largest double, a degenerate curve or a zero scale. 🦴 **It also poses every bone `inherit` key at its own time**: the runtime resolves a mode by folding the case of its first letter and nothing else, and a spelling that misses is stored as **NaN** — the world position stays finite, `updateWorldTransform` matches no mode, and the bone keeps the rotation, scale and shear it had. The detail names the animation, the bone, the key's time and its spelling, beside the five. A bone whose *setup* spelling misses poses no mode at all, and is named the same way from the stepping loop. Neither is reachable from a rig spec — `build` refuses both spellings by name (§5.1) — so on a green build this clause is about files rigc did not write. Which mode a correct spelling poses is not judged here, because the lookup that resolved it is the one that would be checked **SKIP** when the skeleton carries no animation: the NaN is produced by stepping, and a static rig is never stepped — the same subject `A09` skips on |
|
|
5711
5799
|
| `A11_NO_CLIPPING_ATTACHMENTS` | renderer | a clipping attachment; the target renderer skips them silently |
|
|
5712
5800
|
| `A12_NO_DARK_COLOR` | renderer | a slot `dark` colour or an `rgba2`/`rgb2` timeline; parsed, then ignored |
|
|
5713
5801
|
| `A13_MESH_BUDGET` | renderer | more mesh slots than the rig's `invariants.meshSlots`, or a mesh over its `invariants.meshTriangles`. Thin the mesh, or raise the budget in the rig spec. **SKIP** when the rig declares neither — which means *unmeasured*, not that the budget is inert: the same `meshSlots` is a **compile-time** refusal for rigc's own generators, before the gate (§3.7) **SKIP** also when the rig budgets **only** triangles and the skeleton carries no mesh. A declared slot budget still PASSes there, because zero mesh slots is a count measured against a ceiling |
|
|
@@ -6366,8 +6454,13 @@ show what the clip left of them. Bounding boxes, points, paths and clipping poly
|
|
|
6366
6454
|
draw nothing and are not listed. Numbers are printed the way every JSON file this
|
|
6367
6455
|
tool writes prints them — the shortest decimal that reads back as the same double —
|
|
6368
6456
|
so a vertex in the file *is* the runtime's vertex, not a rounding of it; a pose that
|
|
6369
|
-
is not finite is refused
|
|
6370
|
-
|
|
6457
|
+
is not finite is refused rather than written as `null`, naming where — the setup pose,
|
|
6458
|
+
`animation "a" frame i at F fps (t=…s)`, or the rest table — and then the bone and
|
|
6459
|
+
its world-transform field, or the slot, the attachment and the vertex, with the
|
|
6460
|
+
value. Bones come first, so a bone that overflowed is named as itself rather than as
|
|
6461
|
+
its first vertex. Since issue #873 plain `render` refuses the same pose in the same
|
|
6462
|
+
sentence while framing it (§3.4's note under *nothing to draw*), so the flag is not
|
|
6463
|
+
needed to find out which number it was.
|
|
6371
6464
|
|
|
6372
6465
|
**The two judgements the file was designed for**, written once so a consumer
|
|
6373
6466
|
implements what the file promises:
|
|
@@ -8732,7 +8825,7 @@ ambiguous one ends with a sentence saying which reading its figures support:
|
|
|
8732
8825
|
|
|
8733
8826
|
- **below the floor** — a 40x28 part of one flat colour, cut from a plain block it fits anywhere inside:
|
|
8734
8827
|
|
|
8735
|
-
> part is 40x28 px (span 40 frame px, opaque 1) with texture 0, detail 0;
|
|
8828
|
+
> part is 40x28 px (span 40 frame px, opaque 1) with texture 0, detail 0; 17 candidate(s), best 0.0000, next 0.0000, spread 0.0000 — below the measured floor (AUTHORING §11.5: detail 0.5, measured from 24 px up): pose placed 7% of the measured parts this plain, so this part is too plain for pose to tell its placements apart; that says nothing about whether the cut is right
|
|
8736
8829
|
|
|
8737
8830
|
- **above the floor** — a 200x150 black-and-white checker the frame does not hold:
|
|
8738
8831
|
|
|
@@ -8759,9 +8852,9 @@ Found within 2 px of the truth, out of 15 trials per cell (free search, default
|
|
|
8759
8852
|
|
|
8760
8853
|
| texture level (mean) | 24 px | 32 px | 48 px | 64 px | 96 px | 128 px | 192 px |
|
|
8761
8854
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
8762
|
-
| `native` (detail 3.49) |
|
|
8763
|
-
| `blur1` (detail 1.58) |
|
|
8764
|
-
| `blur2` (detail 0.59) |
|
|
8855
|
+
| `native` (detail 3.49) | 13/15 (2 amb) | 15/15 | 15/15 | 15/15 | 14/15 (1 wrong) | 14/15 (1 wrong) | 14/15 (1 wrong) |
|
|
8856
|
+
| `blur1` (detail 1.58) | 12/15 (3 amb) | 12/15 (3 amb) | 13/15 (2 amb) | 12/15 (3 amb) | 12/15 (2 amb, 1 wrong) | 11/15 (1 amb, 3 wrong) | 11/15 (2 amb, 2 wrong) |
|
|
8857
|
+
| `blur2` (detail 0.59) | 9/15 (5 amb, 1 wrong) | 9/15 (4 amb, 2 wrong) | 9/15 (4 amb, 2 wrong) | 8/15 (3 amb, 4 wrong) | 7/15 (3 amb, 5 wrong) | 6/15 (4 amb, 5 wrong) | 7/15 (3 amb, 5 wrong) |
|
|
8765
8858
|
| `flat` (detail 0.00) | 0/15 (14 amb, 1 wrong) | 0/15 (14 amb, 1 wrong) | 0/15 (13 amb, 2 wrong) | 0/15 (11 amb, 4 wrong) | 0/15 (13 amb, 2 wrong) | 0/15 (12 amb, 3 wrong) | 0/15 (12 amb, 3 wrong) |
|
|
8766
8859
|
|
|
8767
8860
|
The same trials, grouped by `detail`:
|
|
@@ -8769,14 +8862,14 @@ The same trials, grouped by `detail`:
|
|
|
8769
8862
|
| detail | found | ambiguous | wrong | refused |
|
|
8770
8863
|
| --- | --- | --- | --- | --- |
|
|
8771
8864
|
| under 0.25 | 8/119 | 89 | 22 | 0 |
|
|
8772
|
-
| 0.25–0.5 |
|
|
8773
|
-
| 0.5–0.75 |
|
|
8865
|
+
| 0.25–0.5 | 0/3 | 2 | 1 | 0 |
|
|
8866
|
+
| 0.5–0.75 | 49/81 | 13 | 19 | 0 |
|
|
8774
8867
|
| 0.75–1 | 17/34 | 14 | 3 | 0 |
|
|
8775
|
-
| 1–1.5 |
|
|
8776
|
-
| 1.5–2 | 34/48 |
|
|
8777
|
-
| 2–3 |
|
|
8778
|
-
| 3–4 |
|
|
8779
|
-
| 4 and over |
|
|
8868
|
+
| 1–1.5 | 25/25 | 0 | 0 | 0 |
|
|
8869
|
+
| 1.5–2 | 34/48 | 13 | 1 | 0 |
|
|
8870
|
+
| 2–3 | 40/44 | 1 | 3 | 0 |
|
|
8871
|
+
| 3–4 | 34/34 | 0 | 0 | 0 |
|
|
8872
|
+
| 4 and over | 31/32 | 1 | 0 | 0 |
|
|
8780
8873
|
|
|
8781
8874
|
**Method.** The truth set is `examples/spineboy`: its setup pose and one frame of
|
|
8782
8875
|
`walk` (a third of the way in). For every trial the figure is rendered twice with one
|
|
@@ -8798,8 +8891,8 @@ part has a low per-pixel gradient and still places — and size alone has no
|
|
|
8798
8891
|
measurable effect across 24–192 px at any level.
|
|
8799
8892
|
|
|
8800
8893
|
**The edge**, derived by `deriveFloor` as the largest rung of a fixed ladder under
|
|
8801
|
-
which at most a tenth of the trials were found: **`detail` 0.5**. Under it, **
|
|
8802
|
-
of the trials were found (
|
|
8894
|
+
which at most a tenth of the trials were found: **`detail` 0.5**. Under it, **6.6%**
|
|
8895
|
+
of the trials were found (8/122); at or over it, **77.2%** (230/298). A part is below
|
|
8803
8896
|
the floor when its `detail` is under 0.5, or when its own longest side is under 24 px,
|
|
8804
8897
|
the smallest size measured (there, nothing measured says `pose` can place it).
|
|
8805
8898
|
|
|
@@ -8813,17 +8906,48 @@ two anchors — and only 3 had it ranked under the old cutoff of three. The fine
|
|
|
8813
8906
|
took the grid from 185 to 227 trials found and those misses from 65 to 14, for about
|
|
8814
8907
|
10–14% more CPU over the grid (615 s of user time before it, 678 s and 704 s on two runs after).
|
|
8815
8908
|
|
|
8816
|
-
|
|
8817
|
-
|
|
8818
|
-
|
|
8909
|
+
The refinement then polishes each place down the pyramid, and at full resolution a
|
|
8910
|
+
polish that has stopped tries its scale **up by half a coarse rung** (2^(1/6)), re-fits
|
|
8911
|
+
the position there, and restarts if that scores better; fifteen places survive each
|
|
8912
|
+
level. Both were set on this grid too (issue #877): of the 14 misses left after #865,
|
|
8913
|
+
12 reached full resolution with the truth's place ranked first or second and the
|
|
8914
|
+
full-resolution objective preferring the truth, and stopped 2–7 px off it at a shrunk
|
|
8915
|
+
scale — the objective couples scale to position along a diagonal, so every
|
|
8916
|
+
one-axis step from there is worse while a joint one is better. None of them had
|
|
8917
|
+
accepted a worse residual. One more was the 24 px shin, its truth's place ranked
|
|
8918
|
+
15th at the 2x level and cut at twelve. Up only because the objective charges part
|
|
8919
|
+
pixels that land off the figure and nothing for figure left uncovered, so the
|
|
8920
|
+
reduced levels err small: every stuck point sat below scale 1. It took the grid from
|
|
8921
|
+
227 to 237 found and the misses from 14 to 8 (12 trials gained, 2 lost — each a
|
|
8922
|
+
blurred part now reported with a second placement at the same spot and another
|
|
8923
|
+
scale, one of them with the truth itself as its best answer), for 43% more
|
|
8924
|
+
refinement samples and the coarse pass untouched.
|
|
8925
|
+
|
|
8926
|
+
Since issue #886 the stopped polish tries **a quarter rung** (2^(1/12)) beside the
|
|
8927
|
+
half and keeps the better re-fit. The case was not a grid trial but §6's stationary
|
|
8928
|
+
post in [MOTION.md](MOTION.md): under `--scale 0.85,1.2` it came back at scale
|
|
8929
|
+
0.917, residual 0.0649, where the old placement at 0.975 still scores 0.0589. The
|
|
8930
|
+
half rung stepped from 0.917 to 1.029, where the best position scores 0.0980 — a part
|
|
8931
|
+
that fills its image pays for every pixel pushed past the figure, so above its truth
|
|
8932
|
+
the objective is a cliff, and half a rung crossed the basin onto it. With both, the
|
|
8933
|
+
post places at 0.971 (0.0593, 0.1 px from the old placement), and the grid goes from
|
|
8934
|
+
237 to 238 found and 8 to 6 misses (2 gained, 1 lost) for 16% more user CPU. The
|
|
8935
|
+
quarter alone found 234, losing the native arms #877 was made for. The one lost is a
|
|
8936
|
+
margin reading again: the blurred 32 px front shin (walk) now reports its truth as its
|
|
8937
|
+
best (0.07 px, 0.00968), with its old 0.51 px answer 0.0045 above it.
|
|
8938
|
+
|
|
8939
|
+
⚠️ **What this is and is not.** The grid is not a reliability line: six native cells
|
|
8940
|
+
place 14 or 15 of 15 and the trials at `detail` 3 and over place 65 of 66, but the
|
|
8941
|
+
goggles still place 13 of 42, and a threshold read off two dozen parts of one figure
|
|
8819
8942
|
would be a claim about that figure. What the grid can separate is **whose** failure a
|
|
8820
8943
|
failure is. `bun tools/pose_floor.ts` prints the residual at the truth for every
|
|
8821
8944
|
failed trial and marks it **missed** when the truth scores better than everything
|
|
8822
8945
|
reported and nothing reported is on it — a failure the search could fix. The other
|
|
8823
8946
|
failures are the objective preferring another placement (a blurred part shrunk into
|
|
8824
8947
|
its own region scores better than its truth) or the truth reported and tied, and no
|
|
8825
|
-
search can fix those. After
|
|
8826
|
-
|
|
8948
|
+
search can fix those. After #886, 6 of the 182 failed trials are misses, and 5 of
|
|
8949
|
+
those sit within 3.1 px of the truth rather than on another hill; the `--from`
|
|
8950
|
+
listing prints, for each, where the refinement left the truth level by level. All this was
|
|
8827
8951
|
measured on **ideal cuts**, the frame's own pixels, where a residual at the truth is
|
|
8828
8952
|
near zero. A generated cut also disagrees with its picture, which can only make it
|
|
8829
8953
|
harder to place. So the edge is where `pose` fails even on ideal cuts, and never a
|
|
@@ -8833,7 +8957,11 @@ Re-run it with `bun tools/pose_floor.ts --textures <level> --json <out>` (one le
|
|
|
8833
8957
|
process parallelises it), then `bun tools/pose_floor.ts --from <a.json>,<b.json>,…` to
|
|
8834
8958
|
print the table, derive the edge and list the misses per cell. `PO22` in
|
|
8835
8959
|
`bun run selftest` re-measures three of its cells, `PO24` holds those three cells to
|
|
8836
|
-
no miss at all, and `PO23` places the 48 px fist
|
|
8960
|
+
no miss at all, and `PO23` places the 48 px fist #865 was made for; `PO28` and
|
|
8961
|
+
`PO29` place the four trials #877 was made for and read where the shin survived the
|
|
8962
|
+
cutoff, and `PO26` holds every polish to strictly descending residuals, read through
|
|
8963
|
+
the same trace. `PO31` places §6's post at the old placement from the page's own
|
|
8964
|
+
input bytes, and `PO32` holds it to taking the quarter-rung escape and reading the same twice.
|
|
8837
8965
|
|
|
8838
8966
|
## 12. Reading the half of that picture `pose` refuses — `rigc chainfit`
|
|
8839
8967
|
|
package/docs/INGEST.md
CHANGED
|
@@ -370,6 +370,8 @@ rigc check --candidate examples/3-timing-and-spacing/export/3-timing-and-spacing
|
|
|
370
370
|
--frames ref3/light
|
|
371
371
|
```
|
|
372
372
|
|
|
373
|
+
**No run reproduces this:** abridged — the head's `atlas`, `frames`, `skin`, `scope`, `reference`, `content` and `in units` lines and its two ⚠️ notes are cut, so the `⤷ fit` line the run prints under `content` stands under `framed to`; the section's `frames` line and every `⤷` note are cut; and so is everything the run prints after `per-frame`
|
|
374
|
+
|
|
373
375
|
```
|
|
374
376
|
rigc check
|
|
375
377
|
candidate …/examples/3-timing-and-spacing/export/3-timing-and-spacing-ess.json
|
|
@@ -378,14 +380,14 @@ rigc check
|
|
|
378
380
|
declared frames.json's own box: TAKEN, coincident — a fit there asks for 0.00 px, under the 1 px that separates a candidate in the frames' coordinates from one in its own, over 21 frame(s).
|
|
379
381
|
|
|
380
382
|
── light — candidate animation "light", 12 fps ──
|
|
381
|
-
MAE mean 0.00 worst 0.00
|
|
382
|
-
slot drift worst 0.
|
|
383
|
+
MAE mean 0.00 worst 0.00 (exact: none of the 21 compared frame(s) differs from the reference) (0..255 over the union alpha; over the whole frame, mean 0.00)
|
|
384
|
+
slot drift worst 0.4 px "pendulum" at f0012
|
|
383
385
|
per-frame all 20 adjacent pair(s) change by as much as the reference's own frames do
|
|
384
386
|
```
|
|
385
387
|
|
|
386
388
|
Two things to take from the control, both of which you need before reading any real
|
|
387
389
|
number: the **framing** resolved to the frames' own box at 0.00 px, so the MAE is a
|
|
388
|
-
comparison of pictures rather than of framings; and **slot drift still reads 0.
|
|
390
|
+
comparison of pictures rather than of framings; and **slot drift still reads 0.4 px at
|
|
389
391
|
MAE 0.00**, which is that instrument's own floor rather than a difference.
|
|
390
392
|
|
|
391
393
|
⚠️ **`--texture-from` is not optional on ingest work, and the reason is structural.**
|
|
@@ -1339,7 +1341,9 @@ against one picture. A foreign export hands you a packed page instead, and point
|
|
|
1339
1341
|
`pose` at one is worse than useless — it treats the whole page as a single part and
|
|
1340
1342
|
answers confidently:
|
|
1341
1343
|
|
|
1342
|
-
```bash
|
|
1344
|
+
```bash setup
|
|
1345
|
+
rigc render --candidate examples/3-timing-and-spacing/export/3-timing-and-spacing-ess.json \
|
|
1346
|
+
--fps 4 --max 900 --out ref-big
|
|
1343
1347
|
mkdir -p packed-only
|
|
1344
1348
|
cp examples/3-timing-and-spacing/export/3-timing-and-spacing.png packed-only/
|
|
1345
1349
|
rigc pose --images packed-only --frame 'ref-big/light@4fps/f0002.png'
|
|
@@ -1350,12 +1354,12 @@ rigc pose
|
|
|
1350
1354
|
.. frame …/ref-big/light@4fps/f0002.png (900x409)
|
|
1351
1355
|
.. ground rgb(232, 232, 232) over 100% of the border ring
|
|
1352
1356
|
.. parts …/packed-only (1 png)
|
|
1353
|
-
.. search scale 0.5–2 in 7 step(s) · rotation -180°–180° step 15° · refuse above residual 0.25
|
|
1354
|
-
PLACE 3-timing-and-spacing.png x= 324.3 y= 188.
|
|
1355
|
-
found on a
|
|
1357
|
+
.. search scale 0.5–2 in 7 step(s) · rotation -180°–180° in 24 step(s) of 15° · refuse above residual 0.25
|
|
1358
|
+
PLACE 3-timing-and-spacing.png x= 324.3 y= 188.3 rot= -91.6° scale=0.630 residual=0.2085 unexplained= 30%
|
|
1359
|
+
found on a 14x7 anchor grid, step 4 at 16x reduction
|
|
1356
1360
|
```
|
|
1357
1361
|
|
|
1358
|
-
⚠️ **`residual=0.
|
|
1362
|
+
⚠️ **`residual=0.2085` is *under* the default 0.25 refusal bar**, so nothing refused
|
|
1359
1363
|
it, and `PLACE` rather than `AMBIG` means nothing flagged it either. With the same frame
|
|
1360
1364
|
and the two real loose parts, the answer is what it should be:
|
|
1361
1365
|
|
|
@@ -1365,12 +1369,15 @@ rigc pose --images examples/3-timing-and-spacing/images \
|
|
|
1365
1369
|
```
|
|
1366
1370
|
|
|
1367
1371
|
```
|
|
1372
|
+
rigc pose
|
|
1373
|
+
.. frame …/ref-big/light@4fps/f0002.png (900x409)
|
|
1374
|
+
.. ground rgb(232, 232, 232) over 100% of the border ring
|
|
1368
1375
|
.. parts …/examples/3-timing-and-spacing/images (2 png)
|
|
1369
|
-
.. search scale 0.3–0.6 in 4 step(s) · rotation -180°–180° step 15° · refuse above residual 0.25
|
|
1370
|
-
PLACE pendulum.png x= 319.3 y= 214.
|
|
1371
|
-
found on a
|
|
1372
|
-
PLACE square.png x= 437.
|
|
1373
|
-
found on a
|
|
1376
|
+
.. search scale 0.3–0.6 in 4 step(s) · rotation -180°–180° in 24 step(s) of 15° · refuse above residual 0.25
|
|
1377
|
+
PLACE pendulum.png x= 319.3 y= 214.6 rot= -88.9° scale=0.411 residual=0.0428 unexplained= 7%
|
|
1378
|
+
found on a 28x13 anchor grid, step 2 at 16x reduction
|
|
1379
|
+
PLACE square.png x= 437.1 y= 343.1 rot= 0.0° scale=0.410 residual=0.0334 unexplained= 4%
|
|
1380
|
+
found on a 113x51 anchor grid, step 2 at 4x reduction
|
|
1374
1381
|
```
|
|
1375
1382
|
|
|
1376
1383
|
⇒ **Check what is in `--images` before trusting a `pose` report on ingest work.** One
|
package/docs/MOTION.md
CHANGED
|
@@ -767,7 +767,7 @@ late, §3.8's overshoot is live; animation name → **`raise`**.
|
|
|
767
767
|
|
|
768
768
|
### 1. The art, and the two pictures
|
|
769
769
|
|
|
770
|
-
```bash
|
|
770
|
+
```bash setup
|
|
771
771
|
mkdir -p semaphore/parts && cd semaphore
|
|
772
772
|
bun -e '
|
|
773
773
|
const files = {
|
|
@@ -806,15 +806,15 @@ rigc pose
|
|
|
806
806
|
.. frame …/semaphore/poseA.png (160x200)
|
|
807
807
|
.. ground rgb(238, 238, 234) over 100% of the border ring
|
|
808
808
|
.. parts …/semaphore/parts (3 png)
|
|
809
|
-
.. search scale 0.5–2 in 7 step(s) · rotation -180°–180° step 15° · refuse above residual 0.25
|
|
810
|
-
PLACE arm.png x=
|
|
811
|
-
found on a 10x13 anchor grid, step 4 at 4x reduction
|
|
812
|
-
PLACE flag.png x= 104.7 y= 156.1 rot= 84.3° scale=0.955 residual=0.0135 unexplained= 0%
|
|
809
|
+
.. search scale 0.5–2 in 7 step(s) · rotation -180°–180° in 24 step(s) of 15° · refuse above residual 0.25
|
|
810
|
+
PLACE arm.png x= 92.0 y= 122.8 rot= 61.9° scale=0.970 residual=0.0320 unexplained= 4%
|
|
813
811
|
found on a 20x25 anchor grid, step 4 at 2x reduction
|
|
814
|
-
|
|
815
|
-
found on a
|
|
816
|
-
|
|
817
|
-
|
|
812
|
+
PLACE flag.png x= 104.7 y= 156.1 rot= 84.3° scale=0.955 residual=0.0135 unexplained= 0%
|
|
813
|
+
found on a 40x50 anchor grid, step 2 at 2x reduction
|
|
814
|
+
AMBIG post.png x= 79.9 y= 149.0 rot= -0.1° scale=0.971 residual=0.0593 unexplained= 16%
|
|
815
|
+
found on a 14x17 anchor grid, step 6 at 2x reduction
|
|
816
|
+
alt 2: x= 79.0 y= 141.7 rot= -0.5° scale=0.691 residual=0.0687 unexplained= 25%
|
|
817
|
+
ambiguous: part is 14x96 px (span 93.2 frame px, opaque 1) with texture 0.0146, detail 1.406; 43 candidate(s), best 0.0593, next 0.0687, spread 0.0095 — above the measured floor (AUTHORING §11.5: detail 0.5, measured from 24 px up), so size and texture do not explain this; either the frame holds more than one place this part fits, or every candidate missed the true one — a narrower --scale or --rotation window around what you know of the part tells the two apart
|
|
818
818
|
```
|
|
819
819
|
|
|
820
820
|
⚠️ **The post came back at scale 0.690 with two alternates trailing it down to 0.500 —
|
|
@@ -830,17 +830,31 @@ rigc pose --images parts --frame poseB.png --scale 0.85,1.2 --out poseB.json
|
|
|
830
830
|
```
|
|
831
831
|
|
|
832
832
|
```
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
833
|
+
rigc pose
|
|
834
|
+
.. frame …/semaphore/poseA.png (160x200)
|
|
835
|
+
.. ground rgb(238, 238, 234) over 100% of the border ring
|
|
836
|
+
.. parts …/semaphore/parts (3 png)
|
|
837
|
+
.. search scale 0.85–1.2 in 2 step(s) · rotation -180°–180° in 24 step(s) of 15° · refuse above residual 0.25
|
|
838
|
+
PLACE arm.png x= 91.9 y= 122.8 rot= 61.9° scale=0.970 residual=0.0320 unexplained= 4%
|
|
839
|
+
found on a 20x25 anchor grid, step 4 at 2x reduction
|
|
840
|
+
PLACE flag.png x= 104.7 y= 156.1 rot= 84.1° scale=0.956 residual=0.0135 unexplained= 0%
|
|
841
|
+
found on a 40x50 anchor grid, step 2 at 2x reduction
|
|
842
|
+
PLACE post.png x= 79.9 y= 148.5 rot= -0.1° scale=0.971 residual=0.0593 unexplained= 16%
|
|
843
|
+
found on a 14x17 anchor grid, step 6 at 2x reduction
|
|
837
844
|
```
|
|
838
845
|
|
|
839
846
|
```
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
847
|
+
rigc pose
|
|
848
|
+
.. frame …/semaphore/poseB.png (160x200)
|
|
849
|
+
.. ground rgb(238, 238, 234) over 100% of the border ring
|
|
850
|
+
.. parts …/semaphore/parts (3 png)
|
|
851
|
+
.. search scale 0.85–1.2 in 2 step(s) · rotation -180°–180° in 24 step(s) of 15° · refuse above residual 0.25
|
|
852
|
+
PLACE arm.png x= 102.5 y= 94.8 rot= -18.3° scale=0.974 residual=0.0305 unexplained= 4%
|
|
853
|
+
found on a 20x25 anchor grid, step 4 at 2x reduction
|
|
854
|
+
PLACE flag.png x= 137.4 y= 86.0 rot= -6.6° scale=0.956 residual=0.0134 unexplained= 0%
|
|
855
|
+
found on a 40x50 anchor grid, step 2 at 2x reduction
|
|
843
856
|
PLACE post.png x= 80.0 y= 148.0 rot= 0.0° scale=0.995 residual=0.0394 unexplained= 9%
|
|
857
|
+
found on a 14x17 anchor grid, step 6 at 2x reduction
|
|
844
858
|
```
|
|
845
859
|
|
|
846
860
|
Three things to read out of that pair, none of which is a score:
|
|
@@ -1168,7 +1182,7 @@ skeleton — AUTHORING §10.3 and PROMPTING clause 4 both price it. Keys are str
|
|
|
1168
1182
|
The bytes of `poseA.png` and `poseB.png`, so §6 runs end to end. Both are 160×200 on a
|
|
1169
1183
|
flat ground; both are invented.
|
|
1170
1184
|
|
|
1171
|
-
```bash
|
|
1185
|
+
```bash setup
|
|
1172
1186
|
bun -e '
|
|
1173
1187
|
const frames = {
|
|
1174
1188
|
"poseA.png": "iVBORw0KGgoAAAANSUhEUgAAAKAAAADICAYAAABvaOoaAAAJdklEQVR42u3c+1dP6R7A8fk/zprLMmbGuAyOSyQ0DE1yaSKJiOiiQS4hSRdEiqTojEvu3a8qRWWU0oWYTsh9yCXLObPmX/ic9TQr2vPdm/3dX2dazPuH90/W9sNnvdaz7ed5fD/6/ff/CFFf9RFDIAASAIkASAAkAiABkAiABEAiABIAiQBIACQCIAGQCIAEQCIAEgCJAEgAJAIgAZAIgARAIgASAIkASAAkAiABkAiABEACIIMgABIAiQBIACQCIAGQCIAEQCIAEgCJAEgAJAIgAZAIgARAIgASAIkASAAkAiABkAiABEAiABIAiQBIACQCIAGQCIAEQAIgEQAJgEQAJAASAZAASARAAiARAAmARAAkABIBkABIBEACIBEACYBEACQAEgGQAEgEQAIgEQAJgB926fvi5UJNBbMA4F/b0UMpstJ3tITM/Ew2rZjNTAD415R9+ois8Xfthte7kqJs5gPA/19ninMkPMjdBl5P6wPdmRMA333VVeUSudLbEF7vsk4dYmYAfDc1NtZJTLi/KXg9rfGfyOwA6FiPHz+Q+KhQu+D17ujBvcwRgI7V83VrpZW+I5khAB3fYrEKUJWesp05AtCxAuc6WwYYOnuQdHY+ZI4AtF7Mtl0OrYKpSZuZIwCtV1LVKkHzJ9kNL8z7CylMmS0vW+Lkdkc7swSgdYDxiWl24Tu9Y5o8bYiS31q3dleWk8wsAWgdoCpk0fS3wtv74xCp3uMiHYV+r/D1dK21iXkC0DrA3akZhvB2BQ+Ss7ucpTHd9VVd9Rs1ACtyE5knAK0DVIUGaI/iti8dKCXxYzXwerqZN89mFbzccIGZAtC+VkXtf9WikMhueDH+AyQ/zkkXXu+e1a7TAKzK38lMAWgdoMrbY8xb4fXUnj3HZhX8uaaMuQLQOsBxk38wDVDVeWG1BmBtEacjAHQAoOs0P/GZOd40wNYTs2xWwfNn85gtAK0DdJkyVyp3T3grvkPhw2WVVz+pPblEA7CpLI7ZAtA6QNWsaRMN4R2LGCHrfPq/+lreGjzCZhU8W3IKgACzDlCVFad9FWdGjZKIBV/q7hWeO6zdnG47xyoIQAcBuk/9A15e7GiJ9v/K+G6gVz/JjHWxWQXLCg4DkKwDVAV7DX7j8dz+1UOlNvWPfy/eLw/UALx3MU5evHgKQLIO0GnsBP1z4RVDpDrZRfOKbjk8Vf57JVaDsDTvAADJOkDVTNfXr9/EkEFSkehs+IFy94z2i/h5U5zcv38bgGQd4Ohxk2T7soFSsmPsW7dmmn6aJC+borT/FsxNASBZB6iKXDbO9Ob07aKFNh8kbW1XAUjWAY7/1t2uI7quhgjtvmDubgCSdYCqMD/zq+CtfF+bVbC5qRaApO2T/sNM99nnX9u1Cj6rW68BeC5vJwDJOkCVj9tA0wBv5My1WQXrLlYCkKwD/KTfQLtWwV+rtde1LhRuByA5ALD/MPGY+PZXsdqkVpvVu1ePs1kFqysLAUj2f4T05DJljlw6MFkXnjqWU8dzvU9N6jOXagA2lGwDIFkHqMo5sl33fqC6mPDnY7v45aNsVsGK0kwAknWAXV1PpDrV/fX9wLn9DS8sRMz/UtqLtRcVWiviAEjWAapnMzN2S8T8LwzhKZQKZ/fV/WMeNqtgedFRAALQOsDu5+ePsYGnrumr1/GfX9EPzgZpAHbUxAIQgI4BPJGh/V2ZA6uHSl2q/v8nuXLETX67Gqe9rpX/EwABaB2gau2SSbr3A/W6VxqgAdjZECePHt0HIACtAywtPGl6Y7r54GR52RytXQVzUwEIQOsAVfkp/qYR3in2t/kguXXzFwAC0DpAdbphzxHdi8uR2i/i3D0ABKB1gKqcfUHmr2sVLLBZBa9eaQAgAK0DrK89b9cq+PzShtc/anRisSTGhAAQgNYBqrLSwsxf18r1kcacIElY8XovsabqLAABaB2geo2awad++FL9AGYPPH+3j2We6z9ksedEOZGWIvujN0tiaLC0NNYDEIDmAXavgukbX0GrSR4vebFOcnjtP2Vv4DcS5TVAljl/Kn5DPpZlgz+VsEH9ZcvgARJtUP7JYwAEoHmAavWK8pwhm5y+kqihxrDMlrFnFwABaB5gysZwh9H1bl/EegAC0DzAI0kJ7xRgQmAAAAFoHmDe8QxL0LZ9M1CShg+R1JHD5KDTCDnhPFpyxo+VowvnAxCA5gHWVJZrYMUO+Vp2DhssySOGSvqo4ZIxZqScHuckBROcpezb8VL1natccpssDd9/p1uZtxcAAWgeYNv1K1Ls6iKVkyfKz1MnGcIyW62HGwABaB6guqpvBVrjDHdpcJ+i+2cPH9wBIP8tU9ub/s7zntMNof17eYB0bAiTezEb5WFCjHTuS5Bnh1Kk6+h+afH21H2m5XIdAAFoHmDxgnmGAB8lbevGpte1Rb66z5wvLgAgAM0DzFkeaAjw/tZIQ4BtwUt0nyk+chCAADQPMGvjekOAtzetNQR4c/Vy3Wdydu0AIB8h5s+CcxLiDQEqZEYAFU69Z7Le09MQAPYRwKJD6YYA1WvWCKB6PeuugKHBAASgeYDnCvMMAaoPDSOAvyZt1X2myM8XgAA0D7C5vtYQoNpqMQL4ZH+S/lew53QAAtA8wHt3bxlvOE//3hBgV0aa4XMABKBpgKo696mGmJ4d3GuIsMlgE/tG2zUAAtA8wDLvHwwBPk7ZaQjwqu8c3WfqqioBCEDzAPOXLDIE+HBntCHA6wELdZ8pzzwJQACaB5gVtsIQ4N3oDYYA23/UP0XJT0sBIADtABgTZQiwY/0qQ4Ad4St1n8mOiwYgAM0DzNuXbAiwfUWgIcC7Wzbon4asWQVAAJoHWHrquCHAX5Yu1MX39F/JcmfzOv1X8NLFAASgeYAXz5UbAmz2miE3wkKkLWixtC70kZY5s+Syh9sbL6yWzp0NQACaB6iu5jt6Hf99v5oPwD4E+Px55zsF+D5ezQdgHwJUVc3ysAtYzQx3OePrLblBAZIVvkay47dKQXqaVORlS8PFGlZAANoHsHiBTzesevcpUjHbUwr8/SR7ZahkbYmU3D2JcuZ4hlwoPyPXrjTKk86HH9xsAdjHAK9fbZbbHe1/29kCsI8B/t0DIAABCEAAEgABCEAAEgABCEAAEgABCEAAEgAB+CH+OBEBEIAABCAAGQIAAchHCAAJgAAEIAAJgAAEIAAJgAAEIAAJgAAEIAABCEAAEgCJAEgAJHoH/Q+vLpEQQGI1ugAAAABJRU5ErkJggg==",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spine-rigc",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "AI-authored Spine 2D rigging and animation, verified before it is written. rigc compiles a rig spec into Spine 4.3 skeleton data, round-trips it through spine-core and named assertions, and emits nothing that fails. Output imports into the Spine editor. Ships as an agent skill.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|