@rig-c/core 2.82.0 → 2.82.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,7 +26,7 @@ name. Both remain published alongside it with the same product files.
26
26
 
27
27
  <p align="center"><em>Fourteen part PNGs drawn from scratch for this repo, one rig spec, one motion spec — the assembly,
28
28
  the breathing and the wave are all rigc-compiled Spine animations, rendered with
29
- <code>rigc render</code>. A <a href="https://raw.githubusercontent.com/rig-c/core/main/assets/rigc-demo@2x.gif">2x version</a> (1200x810) sits beside it.</em></p>
29
+ <code>rigc render</code>. A <a href="https://raw.githubusercontent.com/rig-c/core/main/assets/rigc-demo@2x.gif">2x assembly film</a> (1200x810) sits beside it.</em></p>
30
30
 
31
31
  Loose part PNGs and two small JSON files in; **Spine 4.3 skeleton data out** — a
32
32
  `skeleton.json` and a `skeleton.atlas` that load in any Spine runtime and **import
@@ -44,13 +44,29 @@ installed.
44
44
  | a compiled rig and a question about its geometry | `rigc inspect` | one picture of its bones, axes, mesh edges and hulls, one bone's weights, the triangles folded over, the draw order, a world grid or a declared axis over the art — at the setup pose, one time or a sheet of several, zoomed to a bone or a slot, or beside a second build on one transform — and a legend that puts every mark back in world units |
45
45
  | a compiled rig | `rigc preview` | one self-contained `.html` that plays it in Spine's own web player |
46
46
  | two to four compiled rigs | `rigc vote` | one ballot page a human picks from, and the answer checked into a ledger |
47
- | a picture of a key pose | `rigc pose` | where each loose part PNG sits in it, in spec coordinates — the movement between two poses is then yours to key ([docs/MOTION.md](docs/MOTION.md)) |
47
+ | a picture of a key pose | `rigc pose` | where each loose part PNG sits in it, in spec coordinates — the movement between two poses is then yours to key ([the motion recipe](docs/MOTION.md)) |
48
48
  | the same picture, and a rig | `rigc chainfit` | the parts `pose` refuses because something is drawn over them — read through the candidate's own draw order and hierarchy, with the share of each part the answer was measured on |
49
49
 
50
50
  Everything in that table needs Bun and this package — `preview` and `vote` also
51
51
  `@esotericsoftware/spine-core` installed beside it (see below) — and no clone, no
52
52
  reference art, no art pipeline, no server.
53
53
 
54
+ ### Depth-driven rigging
55
+
56
+ Explicit depth, which a drawing alone does not state, makes facial features
57
+ shift by different amounts during a small head turn: [the portrait depth example](https://github.com/rig-c/core/tree/main/gallery/portrait)
58
+ uses per-part depths, while [the mesh-depth look example](https://github.com/rig-c/core/tree/main/gallery/look)
59
+ samples a depth map at the mesh vertices.
60
+ With [`@rig-c/parts`' depth fields](https://github.com/rig-c/parts/blob/main/docs/AUTHORING.md#per-layer-depth-sheets-773),
61
+ See-through's per-layer sheets are bound explicitly with `near` and `zScale`,
62
+ then consumed by head-turn roles in `turn.roles`.
63
+ The [depth-yaw flow](docs/FACE.md#a-measured-alpha-aperture) shows how a turning
64
+ surface and its alpha clipping aperture move together.
65
+ The [value-driven turn](docs/FACE.md#the-turn-as-a-value-rather-than-a-time) is a
66
+ rig control; the consumer chooses when to move it, and
67
+ [getting-started](https://github.com/rig-c/getting-started) is the painting-to-rig
68
+ walkthrough.
69
+
54
70
  ### Alpha-derived clipping
55
71
 
56
72
  Alpha-derived clipping takes a named source slot/skin/attachment plus explicit
@@ -59,7 +75,8 @@ Region, authored/resolved linked mesh and generated grid/contour depth sources u
59
75
  ordinary weighted clipping, with the existing validation gate before emission.
60
76
  See [AUTHORING: Alpha-derived clipping](docs/AUTHORING.md#alpha-derived-clipping)
61
77
  for source-motion limits, fit reports and named refusals, and
62
- [the face guide](docs/FACE.md#a-measured-alpha-aperture) for the depth-yaw flow.
78
+ [the face guide](docs/FACE.md#a-measured-alpha-aperture) for the depth-yaw flow
79
+ used in depth-driven rigging.
63
80
 
64
81
  ## What rigc is, and what it is not
65
82
 
@@ -89,45 +106,7 @@ it cuts both ways:
89
106
 
90
107
  ### Licensing, stated plainly
91
108
 
92
- rigc's own code is MIT (see [LICENSE](LICENSE)). That says nothing about Spine, and
93
- the following is a restatement of Esoteric Software's terms, not a term of ours:
94
-
95
- 1. rigc's output **is Spine skeleton data**.
96
- 2. A product that plays it with **a Spine Runtime** — the official runtimes, the Web
97
- Player — has integrated the Spine Runtimes. rigc also writes the model document
98
- its own core poses, and a product may play that or anything else; what the terms
99
- turn on is the integration.
100
- 3. Integrating a Spine Runtime into a product is permitted **under Section 2 of the
101
- [Spine Editor License Agreement](https://esotericsoftware.com/spine-editor-license)**,
102
- or otherwise on the condition that **each user of the product obtains their own
103
- Spine editor licence** and the product carries the Runtimes licence and copyright
104
- notice — the Runtimes licence's own two routes, in its words.
105
- 4. The published rigc **links no Spine runtime**. This repository does — `spine-core`
106
- as a development dependency, for its own gate — and so does an install with the
107
- runtime added beside it.
108
-
109
- > **If a product integrates a Spine Runtime to play rigc's output, that integration
110
- > is subject to the terms above** — rigc neither adds those terms nor removes them.
111
- > Running the published rigc links no Spine runtime, and whether its output is then
112
- > played by one, by rigc's own core, or by something else is the consumer's choice.
113
-
114
- See [NOTICE.md](NOTICE.md) for the full notice.
115
-
116
- 📐 **What of Esoteric Software's is in this repository, and under what grant.** No
117
- example asset is committed: `bun run fetch-examples` downloads the example projects
118
- into a gitignored `examples/`. What *is* committed is `bench/reference/` — 1,293 PNG
119
- frames **this project renders** from those examples' own exports, so a frame carries
120
- those images' pixels and committing one **is** redistribution. Each example's own
121
- `license.txt` permits exactly that, *"as long as they are accompanied by this license
122
- file"*, and a verbatim copy of it sits at each example root here — all eight, written
123
- there by the render script rather than left to memory. The same file's
124
- **non-commercial** condition rides along with those images, and
125
- [LICENSE](LICENSE) says so: rigc's MIT grant covers rigc's own code, documentation
126
- and art, not this material. `7-anticipation` publishes no `license.txt` upstream, so
127
- no such grant exists for it and its frames are never committed — they render only
128
- into a gitignored directory, enforced by `git check-ignore`. Full reasoning:
129
- [`bench/reference/README.md`](https://github.com/rig-c/core/blob/main/bench/reference/README.md)
130
- (repository material, not in the npm package).
109
+ See [the licensing notice](NOTICE.md) for licensing and third-party terms.
131
110
 
132
111
  The problem rigc is aimed at is narrow. An agent asked to author a rig has no way
133
112
  to tell whether it succeeded: Spine's JSON parser accepts a great deal of nonsense
@@ -211,7 +190,7 @@ reference frames this project renders from them, which **are** committed, each
211
190
  example's own `license.txt` beside them under the redistribution grant those files
212
191
  carry; the images stay **non-commercial only**. The reasoning is in
213
192
  [`bench/reference/README.md`](https://github.com/rig-c/core/blob/main/bench/reference/README.md)
214
- and the terms in [NOTICE.md](NOTICE.md). It needs a clone and `bun run
193
+ and the terms in [the reference-image notice](NOTICE.md). It needs a clone and `bun run
215
194
  fetch-examples`, and says so by name when the corpus is absent. `check` is not one
216
195
  of them: it reads whatever frames you point it at, so it runs from the installed
217
196
  package on pictures of your own — which is what *Where to go next* below tells you
@@ -467,39 +446,7 @@ origin and tip in world units and in pixels, so a position read off the picture
467
446
  straight back into the spec. [AUTHORING §13](docs/AUTHORING.md#13-asking-the-picture-a-question--rigc-inspect)
468
447
  maps each question to its view.
469
448
 
470
- **`render`** samples every animation at 12 fps and writes `render/<animation>/f0000.png…`
471
- with a `contact.png` beside them — every frame of the shot as one labelled grid,
472
- which is the picture to open first, because spacing is a comparison *across*
473
- frames. It draws with rigc's own rasteriser (the one `check` measures with), so
474
- it needs no browser and no network, and the `frames.json` it leaves beside the
475
- directories makes the result a frame set like any other — the world box every
476
- frame is a picture of. `--animation <name>` narrows it to one, `--fps` and
477
- `--max` change the rate and the frame size. A set drawn at any rate but the
478
- default is written to `<anim>@<fps>fps/` rather than `<anim>/`, so two rates sit
479
- side by side: `--fps 24` writes `<anim>@24fps/`, and the default 12 writes
480
- `<anim>/`. Each set's summary line ends with the directory it wrote.
481
-
482
- > 🚨 **`--skin <name>` if your rig has more than one.** With no `--skin` no skin
483
- > is set at all, so every slot resolves through the **default** skin alone — and
484
- > a slot whose art lives only in a named skin draws *nothing*. That is not a
485
- > quirk of `render`: `check` compares `render`'s frames, so a multi-skin rig
486
- > checked with no skin compares blank against blank and reports a perfect
487
- > `0.0000` about art nobody drew. `render --skin` records the name in
488
- > `frames.json`, `check --skin` poses the candidate under it, and a candidate
489
- > scored against frames rendered under a *different* skin is refused by name
490
- > rather than measured.
491
-
492
- **`preview`** writes a single self-contained `.html`: your skeleton, your atlas
493
- and every page's PNG bytes are embedded in it as data URIs, and it plays them in
494
- the **official [Spine Web Player](https://esotericsoftware.com/spine-player)**.
495
- Double-click it, or attach it to a message — the file carries the whole artifact.
496
- It is also the strongest interop statement in this repository: a rig that plays
497
- there has been played by Esoteric Software's own runtime rather than by ours.
498
-
499
- > ⚖️ The player itself is **referenced, not embedded** — the page loads it from
500
- > unpkg, so the first open needs a network, and rigc redistributes nothing
501
- > Esoteric Software owns (see [NOTICE.md](NOTICE.md)). Everything the player
502
- > draws is inside your file.
449
+ **`render`** writes PNG frames and a contact sheet; **`preview`** writes a playable HTML file — see [the render and preview reference](docs/AUTHORING.md#0-the-loop).
503
450
 
504
451
  **7. Let someone choose.** Sooner or later you will have two builds that both pass
505
452
  the gate and no instrument that can separate them. `vote` puts them in one page
@@ -519,11 +466,11 @@ that does not belong to it. See
519
466
 
520
467
  **Where to go next.**
521
468
 
522
- - 📘 **[docs/AUTHORING.md](docs/AUTHORING.md)** is the real guide — both files
469
+ - 📘 **[the authoring guide](docs/AUTHORING.md)** is the real guide — both files
523
470
  field by field, the emission rules, every named failure mapped to the file that
524
471
  has to change, and §8–§9 for reproducing a shot you were given as pictures. It
525
472
  ships inside the npm package too, at
526
- `node_modules/rig-c/docs/AUTHORING.md`.
473
+ `node_modules/@rig-c/core/docs/AUTHORING.md`.
527
474
  - `rigc explain --rig buoy.rig.json --motion buoy.motion.json --out spine` prints
528
475
  the compiled rig as a table — every bone with its resolved parent, the slots in
529
476
  draw order, every timeline key by key — and writes nothing. It is what to reach
@@ -543,11 +490,11 @@ that does not belong to it. See
543
490
  it, so a figure is read against that rather than against a number from a page;
544
491
  AUTHORING.md §9.2 says what the two halves of that bound are and why the floor
545
492
  is not zero.
546
- - [docs/LADDER.md](https://github.com/rig-c/core/blob/main/docs/LADDER.md) is the benchmark: the same job, from a brief
493
+ - [the benchmark ladder](https://github.com/rig-c/core/blob/main/docs/LADDER.md) is the benchmark: the same job, from a brief
547
494
  and rendered frames, scored. [docs/PILOT.md](https://github.com/rig-c/core/blob/main/docs/PILOT.md) is how to run an
548
495
  agent through it and score what comes back.
549
496
  - 🤖 **Handing the authoring to an AI agent?**
550
- [docs/PROMPTING.md](docs/PROMPTING.md) is the operator's page — the six prompt
497
+ [the prompting guide](docs/PROMPTING.md) is the operator's page — the six prompt
551
498
  clauses a measured pilot run paid for, and what you can leave unsaid.
552
499
 
553
500
  ## See what you built, and let someone choose
@@ -567,7 +514,7 @@ a rig compiles green, because green says nothing at all about the picture.
567
514
  conditions, <code>rigc pose</code> reads where every part sits in each picture, two
568
515
  candidate in-betweenings are compiled from the same pair — and a real
569
516
  <code>rigc vote</code> ballot picks the winner, because the movement between the poses
570
- is the one thing no instrument here will grade. A <a href="https://raw.githubusercontent.com/rig-c/core/main/assets/rigc-keypose@2x.gif">2x version</a> (1200x810) sits beside it.</em></p>
517
+ is the one thing no instrument here will grade. A <a href="https://raw.githubusercontent.com/rig-c/core/main/assets/rigc-keypose@2x.gif">2x key-pose film</a> (1200x810) sits beside it.</em></p>
571
518
 
572
519
  Three properties of `vote` are worth stating, because they are what make its ledger
573
520
  usable by the next agent rather than by a reader: **a tie is a recorded outcome, not a
@@ -578,7 +525,7 @@ anywhere; and **every line carries a reason code** from a closed enumeration tha
578
525
  enforced, so *"tie, because this one is better"* is refused.
579
526
 
580
527
  🎞️ **Authoring the movement those pages show you** — key poses, in-betweening, and how
581
- to spread candidates so a ballot informs — is [docs/MOTION.md](docs/MOTION.md).
528
+ to spread candidates so a ballot informs — is [the motion authoring guide](docs/MOTION.md).
582
529
 
583
530
  📐 **`rigc pose --images parts/ --frame poseA.png` runs the other way.** Every command
584
531
  above takes something you authored and tells you about it; this one takes a **picture
@@ -621,7 +568,7 @@ while <code>gaze</code> and <code>turn</code> return to rest, so the hand-offs m
621
568
  differing pixels — and the composing is the consumer's. Authorable on plain Spine 4.3, no
622
569
  plugin, no runtime patch; what the turn costs is authoring rather than runtime capability,
623
570
  and that cost is one stated expression per key. Compiled and rendered entirely by the
624
- published package. A <a href="https://raw.githubusercontent.com/rig-c/core/main/assets/rigc-scene@2x.gif">2x version</a> (1200x810) sits beside it.</em></p>
571
+ published package. A <a href="https://raw.githubusercontent.com/rig-c/core/main/assets/rigc-scene@2x.gif">2x portrait film</a> (1200x810) sits beside it.</em></p>
625
572
 
626
573
  🎞️ **How the three films on this page were made** is kept with them, one directory per
627
574
  film in [`films/`](https://github.com/rig-c/core/tree/main/films) — a `run.sh` that
@@ -631,203 +578,44 @@ material, like the gallery: a clone runs them.
631
578
 
632
579
  ## Commands
633
580
 
634
- Every command takes its paths explicitly. `rigc <command> --help` prints its flags —
635
- `rigc help <command>` prints the same page — and
636
- [AUTHORING.md §0](docs/AUTHORING.md) is the same list with what each flag means, which
637
- commands take it and what its default is.
581
+ `rigc help <command>` prints the command’s flags; [AUTHORING §0](docs/AUTHORING.md#0-the-loop) is the CLI reference.
638
582
 
639
583
  | Command | Does |
640
584
  | --- | --- |
641
- | `build --rig … --motion … --out …` | compiles, gates, and **writes only if the gate is green**. `--images <dir>` says where the rig spec's `image` names resolve, `--manifest` adds measured art, and `--copy-images` copies every page PNG into `--out` so the directory is self-contained, with `skeleton.images` pointing at it so the editor's import finds the parts |
642
- | `build … --pack` | the same build with every part arranged onto **shared** atlas pages, written into `--out` — losslessly, and gated a second time as the pair that ships. `--page-size`, `--padding`, `--page-edges` and `--pack-shape` tune it — `--pack-shape polygon` lets a neighbour sit inside a mesh's rectangle where its hull is not, and with `--page-edges free` costs 12–56 times `rect`'s pack (3–11 s against 0.2–0.3 s on 90–144 parts over two to four pages; past 5 s from about 60 parts, a second or so below 45 on one page — AUTHORING §0.1) |
643
- | `build … --atlas-in <file.atlas>` | the same build with every part resolved to a **region of an existing pack** instead of a loose PNG; a name the atlas lacks, a size the spec disagrees with or a rectangle off its page is refused by name |
644
- | `validate <dir>` | re-gates artifacts already on disk |
645
- | `repack <dir> --out <dir>` | a packed build **repacked from its own output** — `skeleton.json`, `skeleton.atlas` and the pages, with no parts kept — under the packing flags `build --pack` takes, so a packer improvement reaches a build whose parts are gone. Every region is lifted off its page, the skeleton read back with `ingest`, and `build --pack` run over the lifted parts with the same gate; it writes only after every region is shown pixel-identical to the input's, the skeleton byte-identical and the gate green, and refuses by name an atlas it cannot lift exactly. A skeleton the rebuild does not reproduce byte for byte — a build written before 2.2.0, whose header box was its stage — is refused naming every differing path, and written, every path printed, only under `--accept-skeleton-differences`. `--stage-box <slot>` reads the stage from the box a build carries for it (`skeleton.stageBox`), the one way the three files alone carry the stage exactly ([AUTHORING §0.4](docs/AUTHORING.md)) |
646
- | `repack <dir> --out <dir> --keep-pages` | **`skeleton.model.json` alone, for the pages already in place** — for a player that reads the document beside an atlas and pages that already shipped. The same read and stage rules, then `build --atlas-in` over the input atlas in place of the lift and the pack; it writes the document, and nothing else, only after its `pages` are shown to state the atlas as it stands, the rebuilt skeleton byte-identical to the one on disk (so `spine.sha256` names it — no acceptance flag here) and the gate green. `--out` is usually the build's own directory and must not already hold a `skeleton.model.json`; a page or region line the document has no field for is refused by name ([AUTHORING §0.4](docs/AUTHORING.md)) |
647
- | `ingest <skeleton.json> --out <dir>` | `build` run backwards: reads a Spine 4.3 skeleton and writes the rig spec and motion spec that **rebuild it**, plus a findings report naming everything it could not carry. a skeleton that declares no stage is carried as declaring none, `--stage x,y,w,h` adds a box to one — and is refused, rather than ignored, beside one that declares a box — and `--images <dir>` writes the spec's own images directory — the opposite direction from `build --images`, which overrides it — so the rebuild carries no flag at all |
648
- | `split --rig … --motion … --slot <name> --out <dir>` | the answer to a mesh refused because its triangles are **several pieces that share no vertex** — two legs after the triangles bridging them were deleted. It reads the two specs and writes them back into an absent or empty `--out` with one mesh per piece: piece 1 stays in the slot, piece k gets a new slot `<slot>_<k>` after it, each with the original's uvs and weights unchanged, its triangles renumbered outline first where the hull rule needs it, and every deform key re-sliced to the new indices — plus `split.json`, where every original vertex and triangle went. One piece is said so and nothing is written; what it cannot carry is refused by name ([AUTHORING §3.4.11](docs/AUTHORING.md)) |
649
- | `explain --rig … --motion …` | the compiled rig as a table — every bone with its resolved parent, the slots in draw order, every timeline key by key. Writes nothing. What to reach for when a rig compiles and still looks wrong |
650
- | `render --candidate <dir>` | PNG frames plus a contact sheet, in `render/`, one directory per set: `<anim>@<fps>fps/` rather than `<anim>/` at any rate but the default — `--fps 24` writes `<anim>@24fps/`, and the default 12 writes `<anim>/`. `--hide <slot,…>` or `--slot <slot,…>` draws part of the rig on the **same grid** as the whole, so the two frames overlay and the difference is the part; `frames.json` records the subset and `check` refuses such a set as a reference. `--geometry` adds a `geometry.json` per set: every frame's bone world transforms and skinned attachment vertices, with the rest geometry, on the frames' own grid. `--folds` adds a `folds.json` per set and prints one line per mesh with a triangle turned over against the setup pose: the frames, the worst frame's count and which triangles, their world box and their setup-pose area. `--pass-through <cloth>:<leg>` adds a `pass-through.json` per set and prints the frames where a cloth drawn over a leg has its side inside the leg's drawn outline, with the depth and the world box — a reading, not a gate. `--seam <slot>:<slot>` adds a `seam.json` per set and prints, per pair, the frames where two slots that meet open background inside the joint (a gap) or show the overlap band of one past the other (a ghost), with the worst frame's cell count and world box; `ghostA` and `ghostB` partition the same ghost by which named pair member drew it, each with its own frames, spans and worst; `gapOpen` and `gapCovered` partition `gap` by zero versus positive rendered alpha from the whole skeleton, including faint and clipped drawings ([AUTHORING §8.8](docs/AUTHORING.md#88-where-two-slots-stop-meeting--render---seam)) — a reading, not a gate; the exit status never moves. `--overlaps` adds an `overlaps.json` per set and prints one `OVERLAP "<under>" under "<over>"` line per pair of slots where the one drawn later covers the earlier one and the motion moves it — the frames, and the most pixels covered and the frame of them — with an outline plate per covered frame; the render reports what was drawn, and the draw-order key is the author's remedy — a reading, not a gate. `--extremes` adds `extremes.json` and a native six-panel `extremes.png` (setup, geometry-pair min/max and three premultiplied RGBA diffs with a legend), plus one `EXTREMES` line per set. Per-channel minima/maxima and the farthest original-vertex geometry pair are distinct readings; valid channel extrema survive a geometry/image SKIP, with channel refusals reported separately; still or uncomparable geometry reports a named SKIP without changing render exit status. `--extremes-only` writes the same `extremes.json` and readable `extremes.png` bytes while skipping ordinary frame rasterization/encoding, `contact.png` and `frames.json`; it implies `--extremes` and takes no other diagnostic or sheet output flags. Look at min, max and diff before a person does ([AUTHORING §8.11](docs/AUTHORING.md#811-min-max-and-diff-before-a-person-looks--render---extremes)). `--angle-range <bone>:<relative-to>` prints how far one bone turns against another over each set: the lowest and highest angle and the frames they fall on — a reading, not a gate. `--viewport <x,y,w,h>` or `--viewport-from <frames.json>` draws over a given box instead of a fitted one, so two builds land on one pixel grid; a slot that reaches past it is named by set and frame, and `frames.json` records it. `--environment <schedule.json>` draws the rig under the wind and gravity its physics answers, in time — the same frames on the core and on spine-core; an inspection of the response the rig states, not a scene. `--sheet [--sheet-format json-hash] [--page-edges pot\|free]` also packs each set's straight-alpha transparent frames into `sheet.png` + `sheet.json` (TexturePacker JSON Hash with a shared world-origin `anchor` and `2`-px clamped edge extrusion, verified through `pixi.js@8.22.0` and `phaser@3.90.0` by `tools/sheet_readers.ts`) and `sheet-manifest.json` (`rigc-sheet/1`), leaving diagnostic `f####.png` and `contact.png` unchanged ([AUTHORING §8.10](docs/AUTHORING.md#810-sprite-sheets-from-a-render--render---sheet)) — a self-contained sprite object per animation set; when animations play and how a scene is composed remains the consumer's |
651
- | `preview --candidate <dir>` | one self-contained `.html` that plays it, headed by the line `validate <dir>` prints for it and the rigc version — a refused candidate is still previewed, and its header says so in the gate's words. Repeat `--candidate` for one page with a pane per candidate, in the order given; a green `build` ends by naming this command for its own `--out` |
652
- | `vote --candidate a --candidate b` | one `.html` that asks a human which; `vote --record <file>` checks the answer into `votes.jsonl` |
653
- | `pose --images <dir> --frame <png>` | reads part placements **out of** a picture |
654
- | `chainfit --candidate <dir> --images <dir> --frame <png>` | reads the parts `pose` refuses, through the candidate's own draw order and hierarchy: masked residuals over **visible** pixels, one hinge per child instead of four degrees of freedom, and the `rotate` key value each answer implies. A bone with two or more anchored descendants is **determined** rather than searched, and the residual that over-determination leaves is reported |
655
- | `diff <candidate.json> <reference.json>` | structural comparison of two skeletons, one ratio per measure and deliberately no combined score |
656
- | `bonedist --candidate … --reference … --bones …` | per-frame, per-bone world-transform distance against another skeleton — the ladder's stage 3, run on its own. `--bones <correspondence.json \| identity>` is required rather than defaulted: a candidate is entitled to its own bone names, so the pairing is stated |
657
- | `check --candidate <dir> --frames <dir> [--out <dir>]` | the candidate against reference pictures — the only instrument here that can see a *wrong animation*. `--out` also writes, for every frame the table lists, the picture its figures came from: reference, candidate, difference and overlay at native size |
658
- | `bench <rung> --candidate <dir>` | one rung of the benchmark ladder |
659
- | `guide <RULE>` / `guide §<n>[.<m>[.<k>]] [--all]` | the guide's row for the rule a failure line names — every `FAIL` line, `vote --record` refusal, `ingest` finding and coded compile error ends with ` (see rigc guide <RULE>)`; only legacy uncoded library errors point at `§5.1` — or a section's heading, own prose and subsection index, read from the installed `docs/AUTHORING.md` when it runs. `--all` includes the subsection bodies; a leaf prints its full text either way. Sizes describe full ledger spans. `--all` with a rule is refused, exit 2; an unknown name is refused with the nearest real ones, exit 1 |
660
- | `skills install [--dir …] [--copy]` | links every agent skill the package ships into `.agents/skills` (or `--dir`) as relative symlinks, or copies them with `--copy` — where Codex, Gemini CLI and Antigravity look. A second run has nothing to do; an entry already there that is not this command's is refused by name and nothing is written |
661
- | `review <dir> […]` | the human review of a build, handed to the `rig-review` bin of `@rig-c/review` installed beside the package; rigc does not depend on it and never installs it. `rigc review <dir> [--reference <video>] [--animation <name>] [--compare <dir>]` is `rig-review open <dir> …` with those flags 1:1 and prints the loopback URL to give a person; a first argument that is one of review's own words (`open`, `check`, `feedback`, `control`, `strip`, `compare`) or starts with `-` (`--help`, `--`) is handed over untouched. stdout is review's byte for byte, stderr review's plus the launcher's own refusals, the exit code review's. Refused by name, exit 2, before the bin starts: `REVIEW_OUTPUT_MISSING <path>` (the target is not a directory); `REVIEW_NOT_INSTALLED` with two lines, `bun add -d @rig-c/review` and `bunx @rig-c/review open <dir> …` carrying the flags given — the same on a terminal and off, with nothing installed or written; `REVIEW_BUN_TOO_OLD: Bun <found>, @rig-c/review needs <required>`, the floor read off the installed package's `engines.bun`; and an empty argument (`""`) under a Bun that drops one (Bun 1.2.0, measured by a probe), `rigc review: argument N is empty, and Bun <version>, the Bun running this, drops an empty argument when it starts a process — …`. docs/AUTHORING.md lists every line |
662
-
663
- `diff`, `bonedist`, `check` and `bench` measure against something you were given; the
664
- first three work on any reference you have, and `bench` is a repository workflow that needs a clone
665
- and `bun run fetch-examples`. The reasoning behind them is in
666
- [the benchmark dossier](https://github.com/rig-c/core/blob/main/docs/BENCHMARK.md).
667
-
668
- `build` and `validate` both default to `--profile spine` — the 36 validity rules, which
669
- ask *is this valid Spine 4.3 that any runtime plays correctly?* `--profile rig-play`
670
- adds all 50: the other 14 are one renderer's policy and one canvas budget's, and they
671
- fire on perfectly correct editor-produced Spine data, which is why they are opt-in.
672
- ⇒ **That reason is about foreign data and does not carry to a rig you are authoring
673
- yourself: author under `--profile rig-play` and read the extra 14 as findings, and
674
- gate the release under `--profile spine`.** A `deform` key that folds a mesh inside
675
- out is written out under the default and refused by name under `rig-play`, which
676
- is the shape of what that split buys you. A report always names
677
- the profile it ran and lists what that profile left out.
678
-
679
- Several cuts can also be registered in a `cuts.json` and built by name
680
- (`build --cut my_cut --cuts path/to/cuts.json`); every path in that table resolves
681
- relative to the `cuts.json` file itself, so the table lives with the project that owns
682
- the art. Its shape is under
683
- [Usage](https://github.com/rig-c/core/blob/main/docs/BENCHMARK.md#usage).
684
-
685
- ### Starting from a skeleton you already have
686
-
687
- `rigc ingest` reads a Spine 4.3 `skeleton.json` and writes the two spec files that
688
- rebuild it. It is the only command that runs against `build`'s direction, and the
689
- only one whose contract is an equality rather than a rulebook:
690
-
691
- ```bash
692
- rigc ingest hero.json --out specs/ --images parts/
693
- rigc build --rig specs/rig.json --motion specs/motion.json --out build/
694
- rigc diff build/skeleton.json hero.json
695
- ```
696
-
697
- `--images parts/` is what makes the second line carry no flag: it writes the spec's
698
- own `images` directory, spelled from `--out`, so the specs are self-contained from
699
- there on. Leave it off and the `image` names resolve against `specs/` itself, which
700
- holds no art — every rebuild then has to repeat `build --images parts/`.
701
-
702
- **`build(ingest(x))` is `x`.** Over the eleven rigs this repository builds — the seven
703
- gallery examples, the three generated probes and a coverage probe written for the
704
- purpose — the rebuilt `skeleton.json` is byte for byte the file the decompiler read.
705
- The atlas is held to a weaker
706
- claim on purpose, and the weakening is measured rather than assumed: it comes back
707
- equal as a **multiset of region blocks**, because the order the pages are collected in
708
- is in no field of the skeleton.
709
-
710
- **And over twelve skeletons nobody here wrote.** Every editor export in the fetched
711
- example corpus, ingested, rebuilt through the pack beside it and `diff`ed against the
712
- source, comes back **12 of 12, no blockers, 1.000 on every measure the report
713
- carries** — and each rebuild is its export's own text in canonical form, apart from
714
- the header's `hash` and `spine`: the editor's project hash and the runtime version
715
- rigc stamps, the two keys the rig spec has no field for by design (12 of 12) — and
716
- the header's box, which `build` computes rather than carries (issue #907): the rebuild
717
- writes spine-core's `getBounds` over the export on the header's 1e-6 grid at float32, equal on all twelve,
718
- where the editor wrote its own arithmetic, up to 0.0071 units away.
719
- [INGEST.md §2.3](docs/INGEST.md) states that pass line and why those two are the
720
- exceptions.
721
-
722
- **What it reads is skeleton JSON and nothing else** — no `.spine` project, no binary
723
- `.skel`, no atlas, no art. So it never invents, and the things it cannot get out of
724
- the file are **findings** with codes rather than plausible values: a construct the
725
- spec format cannot hold (`point`, a `sequence` block, an unknown field
726
- on a bone, slot or constraint) is a blocker, the command exits non-zero, and both
727
- specs are still written — a spec plus a list of what is missing from it beats no spec.
728
-
729
- ⚠️ **Two values are not in a skeleton at all.**
730
-
731
- - **The stage.** `skeleton.width`/`height`. A skeleton that declares none is carried as
732
- declaring none — the rig spec states `"width": null, "height": null` and the rebuild
733
- carries no box either, byte for byte — and `--stage x,y,w,h` is how a
734
- caller *adds* one, recorded as a judgement. It is not derivable — posing the rig gives
735
- the *animated* extent, which is a different number from the setup box. ⛔ **And `--stage` beside a box the file already states is refused
736
- too**, for the opposite reason: two sources for one value, where the file is the record
737
- of what was measured. **All twelve exports in the example corpus carry a stage** and
738
- none of them needs the flag. It is the value that costs least to get wrong, because
739
- `diff` reports the box and gates nothing on it. 🔁 The box an export's header carries
740
- is its setup-pose bounding box, and it becomes the rebuild's *stage*; the rebuild's own
741
- header is computed again, because since issue #907 `build` writes the setup-pose
742
- bounding box there — never the stage — held to spine-core's `getBounds`. 📦 A rig
743
- that has to carry its stage in the Spine files asks for it as a bounding box
744
- (`skeleton.stageBox`, written by `build` from the stage and held by
745
- `A50_STAGE_BOX_IS_THE_STAGE`), and `ingest --stage-box <slot>` reads that box back as
746
- the rebuild's stage — [AUTHORING §3.1](docs/AUTHORING.md) has the field and the
747
- paragraph for a consumer of the files.
748
- - **An animation's duration.** The format has no such field. The largest key time is
749
- the only derivable answer and it is what a runtime plays to; it is wrong for an
750
- animation that holds its last pose past its last key, so it is recorded as a finding
751
- on every animation rather than chosen quietly.
752
-
753
- Both specs carry a `note` that `ingest` writes itself, saying the file is decompiled
754
- and naming the skeleton it came from — because a decompiled spec is indistinguishable
755
- from an authored one by inspection, every gate here calls it green (it *is* green),
756
- and no gate can catch a missing note.
757
-
758
- [docs/INGEST.md](docs/INGEST.md) is the whole page on working from a file you were
759
- handed; [docs/AUTHORING.md](docs/AUTHORING.md) §0.3 is the loop.
760
-
761
- ### The editor round trip — for a licence holder, never in CI
762
-
763
- `tools/editor_roundtrip.ts` drives the loop the output's whole premise rests on:
764
- build → **import into the Spine editor** → export back to JSON → gate, `diff`,
765
- `render` and `check` the export against the build it came from.
766
-
767
- ```
768
- bun cli.ts build --rig … --motion … --out build/ --copy-images
769
- bun tools/editor_roundtrip.ts --build build/ --editor /Applications/Spine.app/Contents/MacOS/Spine
770
- ```
771
-
772
- Of the editor's `--version` it records one line, the `Spine <x.y.z> …` line that
773
- carries the version, and nothing else that command prints — the rest of it
774
- names the licence holder — or `editor version: not found in --version output`
775
- where no such line is there. That call carries the same `-u` as the import and
776
- the export, so a trip pinned with `--editor-version <v>` names the editor it
777
- pinned and says so on the line (`(read from --version under -u <v>, …)`); an
778
- unpinned trip names the launcher's default. Once the export exists the version
779
- is held against the export's own `skeleton.spine`, and a disagreement is a FAIL
780
- naming both values — the line would otherwise name an editor the trip did not
781
- run on. It prints the import and export exit codes, the
782
- validator's verdict on the export, every `diff` measure that moved, `check`'s mean MAE and worst drift per
783
- animation **for each skin the build and the export both declare** — one
784
- render-and-check block per skin, with a per-skin roll-up under them, because a
785
- rig's contested art lives in its named skins and a single un-skinned check draws
786
- none of it; a skin only one side declares is a FAIL naming it as **lost** (or
787
- **added**) **by the export**, with `diff`'s `attachments.skins` beside it, and is
788
- rendered on neither side — and a
789
- field-by-field list of what the editor rewrote. Every step quotes what its child
790
- said when that child did not do what it was for, the renderers included — the
791
- editor's words in full and in order, except its `Licensed to:` line, which names
792
- the licence holder and is replaced by a line saying it was withheld; a skin
793
- **neither** side can draw — a hit-box rig, say — is a **SKIP** naming that, not a
794
- red, because `check` had nothing to compare and `diff` and `validate` have
795
- already measured the rig. One side drawing where the other does not is the
796
- divergence the trip exists to find and stays a failure. A human edit made in the
797
- editor survives the trip back.
798
-
799
- 🔒 **It requires a licensed Spine editor on the machine, by construction**, and
800
- drives only the [documented command line](https://esotericsoftware.com/spine-command-line-interface)
801
- — never the UI, and it produces nothing the editor did not produce. With no
802
- editor present it refuses by name and exits non-zero, and so does the **trial**:
803
- the trial cannot save projects or export animation data, so the refusal names
804
- what it found — the executable, the bundle, the `CFBundleName` that bundle
805
- declares, or the banner the binary prints about itself — rather than starting it
806
- and failing downstream. Both refusals point at `--exported <file>`, which
807
- measures an export the editor already made and is the half of this tool that
808
- needs no editor at all. A build whose `skeleton.json` is missing, is not JSON, or
809
- holds JSON that is not one object is refused by name before the editor starts,
810
- and so is a build with no atlas or an atlas that is a directory, or an
811
- `--exported` file that is not one JSON object.
812
-
813
- ⛔ **Run the round trip by hand, on a machine that has the editor.** CI has no
814
- editor, so no automated check runs it. The by-hand measurement before a landing
815
- trips the production rigs and one **parts-built** rig, the exam's task-01
816
- painting through `@rig-c/parts`. The production rigs were authored in the editor,
817
- so they are already in the editor's own shape. A refusal that only a generated
818
- rig carries cannot show up on them. Issue #1407 was such a refusal: a green build
819
- whose meshes listed their bones in two orders, which the editor would not import.
820
-
821
- ⚠️ Build with `--copy-images`. An ordinary build's atlas names its pages by a
822
- relative path back to the art directory, and the round trip copies that atlas to
823
- a directory at another depth — the tool refuses such a build by name rather than
824
- letting `A17` blame the editor for the harness's own doing.
585
+ | `build` | Compile, gate and write the rig. [`build` in the CLI reference](docs/AUTHORING.md#cmd-build) |
586
+ | `validate` | Re-gate artifacts already on disk. [`validate` in the CLI reference](docs/AUTHORING.md#cmd-validate) |
587
+ | `repack` | Repack a build from its output. [`repack` in the CLI reference](docs/AUTHORING.md#cmd-repack) |
588
+ | `ingest` | Read a skeleton back into specs. [`ingest` in the CLI reference](docs/AUTHORING.md#cmd-ingest) |
589
+ | `split` | Separate disconnected mesh pieces. [`split` in the CLI reference](docs/AUTHORING.md#cmd-split) |
590
+ | `explain` | Print the compiled rig as a table. [`explain` in the CLI reference](docs/AUTHORING.md#cmd-explain) |
591
+ | `render` | Write PNG frames and a contact sheet. [`render` in the CLI reference](docs/AUTHORING.md#cmd-render) |
592
+ | `preview` | Write a playable HTML preview. [`preview` in the CLI reference](docs/AUTHORING.md#cmd-preview) |
593
+ | `vote` | Make a ballot and record its answer. [`vote` in the CLI reference](docs/AUTHORING.md#cmd-vote) |
594
+ | `pose` | Read part placements from a picture. [`pose` in the CLI reference](docs/AUTHORING.md#cmd-pose) |
595
+ | `chainfit` | Read occluded parts through a candidate rig. [`chainfit` in the CLI reference](docs/AUTHORING.md#cmd-chainfit) |
596
+ | `diff` | Compare two skeletons structurally. [`diff` in the CLI reference](docs/AUTHORING.md#cmd-diff) |
597
+ | `bonedist` | Measure per-bone world-transform distance. [`bonedist` in the CLI reference](docs/AUTHORING.md#cmd-bonedist) |
598
+ | `check` | Compare a candidate against reference pictures. [`check` in the CLI reference](docs/AUTHORING.md#cmd-check) |
599
+ | `bench` | Run a rung of the benchmark ladder. [`bench` in the CLI reference](docs/AUTHORING.md#cmd-bench) |
600
+ | `guide` | Read a named failure or guide section. [`guide` in the CLI reference](docs/AUTHORING.md#cmd-guide) |
601
+ | `skills install` | Install the packaged agent skills. [`skills install` in the CLI reference](docs/AUTHORING.md#cmd-skills-install) |
602
+ | `review` | Hand a build to the review package. [`review` in the CLI reference](docs/AUTHORING.md#cmd-review) |
603
+
604
+ ### Existing skeletons and the editor
605
+
606
+ <a id="starting-from-a-skeleton-you-already-have"></a>
607
+ <a id="the-editor-round-trip--for-a-licence-holder-never-in-ci"></a>
608
+
609
+ For a skeleton you already have, [the ingest-and-rebuild loop](docs/INGEST.md#starting-from-a-skeleton-you-already-have)
610
+ turns a Spine 4.3 export into rig and motion specs, then checks that rebuilding them reproduces it.
611
+ For a licence holder, [the editor round trip](docs/INGEST.md#the-editor-round-trip--for-a-licence-holder-never-in-ci)
612
+ imports a build into the Spine editor and checks the export against that build with the gate, structural diff and rendered frames; it never runs in CI.
825
613
 
826
614
  ## Documentation
827
615
 
828
616
  | Document | For |
829
617
  | --- | --- |
830
- | 📘 **[docs/AUTHORING.md](docs/AUTHORING.md)** | **the format guide, and the one to read before writing a spec.** Both input files field by field with a complete minimal example each, every field with its Spine meaning, the rules that decide what is emitted, the build → read the report → fix → repeat loop, the map from every named failure to the file that has to change, and the features rigc refuses by name so you do not spend a loop discovering them. It travels **inside the npm package**, at `node_modules/rig-c/docs/AUTHORING.md` |
618
+ | 📘 **[docs/AUTHORING.md](docs/AUTHORING.md)** | **the format guide, and the one to read before writing a spec.** Both input files field by field with a complete minimal example each, every field with its Spine meaning, the rules that decide what is emitted, the build → read the report → fix → repeat loop, the map from every named failure to the file that has to change, and the features rigc refuses by name so you do not spend a loop discovering them. It travels **inside the npm package**, at `node_modules/@rig-c/core/docs/AUTHORING.md` |
831
619
  | 🦴 **[docs/RIGGING.md](docs/RIGGING.md)** | **authoring the hierarchy.** Where a bone goes and why the art is pushed out on an offset, why a pivot in the wrong place looks like a search failure and what identifies one, moving a pivot and the child row that gets forgotten, gauges, siblings-not-a-chain, what a chain can reach and how many links it needs, why a local key is not a world key, duplicate art at mirrored pivots, and constraints as structure. Every section is a stumble the run records hold more than once, ranked by how often. Ships in the package too |
832
620
  | 🎞️ **[docs/MOTION.md](docs/MOTION.md)** | **the key-pose recipe.** How to get two poses, what a pair of poses does and does not fix, the in-betweening rules and where each comes from, and how to spread candidates so a ballot informs. Ships in the package too |
833
621
  | 🙂 **[docs/FACE.md](docs/FACE.md)** | **authoring a face.** A blink, a gaze and a 2.5D head turn on plain Spine data: the one line of yaw arithmetic every number in a turn comes from, depth as the parameter you are actually authoring, where to put a grid's columns and the angle at which any grid folds, what foreshortens and what does not, channel allocation before the first key, and the three cliffs with their angles. Also the deform audit gap, demonstrated — a folded mesh gates green — and the differential check that works today |
@@ -836,11 +624,12 @@ letting `A17` blame the editor for the harness's own doing.
836
624
  | 🔬 **[docs/SPEC_COVERAGE.md](docs/SPEC_COVERAGE.md)** | **the Spine 4.3 format, field by field.** Every key the 4.3 JSON parser and atlas reader take, what each defaults to, and the parser line it comes from — the rows rigc's refusals cite by part number. Ships in the package too |
837
625
  | 🎓 **[the benchmark dossier](https://github.com/rig-c/core/blob/main/docs/BENCHMARK.md)** | **why you can trust the output.** The yardstick, `diff` and `check` and what neither can see, the eight-rung ladder and the spineboy graduation exam, the run viewer, the 50 named assertions with their profiles, and the selftest that has watched every one of them fire. Repository material — it is not in the npm package |
838
626
  | 📋 [LADDER.md](https://github.com/rig-c/core/blob/main/docs/LADDER.md) · [GATE.md](https://github.com/rig-c/core/blob/main/docs/GATE.md) · [PILOT.md](https://github.com/rig-c/core/blob/main/docs/PILOT.md) | the live rung ledger, the clause statements a candidate is graded against, and how to run an agent through the ladder and score what comes back |
839
- | 🔬 [SURVEY_2026-08-22.md](https://github.com/rig-c/core/blob/main/docs/SURVEY_2026-08-22.md) | the survey the ladder was climbed by: rigc and the official examples as measured on 2026-08-22, and the gap list ordered by rung. A dated record, not kept current. Repository material |
840
627
  | 🧬 [GENERATIONS.md](https://github.com/rig-c/core/blob/main/docs/GENERATIONS.md) | **Spine data from another generation.** Why a 3.8–4.2 file read as 4.3 fails in silence, the policy that follows (detect from `skeleton.spine`, never guess, play on the matching runtime), what `A16` and `ingest` do with such a file, and the editor as the migration path. Repository material |
841
628
  | 📓 [CASES.md](https://github.com/rig-c/core/blob/main/docs/CASES.md) | **converting a Live2D model to Spine, and verifying the conversion.** The method — the source's own player headless, parts from its texture along the drawables, motion baked as deform keys, reference frames first, `check` — run once end to end on two Live2D sample models with no editor and no converter, and verified against the source's renderer and Spine's own runtime: the three instruments, the two rigc defects verifying it led to and v1.2.1 fixed, and where the method stops. Figures only — the models' licence keeps every asset out. Repository material |
842
629
  | 🗺️ [ROADMAP.md](https://github.com/rig-c/core/blob/main/ROADMAP.md) | where this is going, and where it has been. What 1.0 had to mean before the number was claimed, and what it was claimed on — conditions rather than a feature list, because direction here comes from what users hit |
843
- | 📐 [CLAUDE.md](https://github.com/rig-c/core/blob/main/CLAUDE.md) | **the doctrine** — why the validator's messages are the product, why nothing reaches disk before green, why no number is ever invented, and what a change has to keep. [CONTRIBUTING.md](https://github.com/rig-c/core/blob/main/CONTRIBUTING.md) calls it worth ten minutes before a first patch. Repository material |
630
+ | 📐 [CLAUDE.md](https://github.com/rig-c/core/blob/main/CLAUDE.md) | **the doctrine** — why the validator's messages are the product, why nothing reaches disk before green, why no number is ever invented, and what a change has to keep. [the contribution guide](https://github.com/rig-c/core/blob/main/CONTRIBUTING.md) calls it worth ten minutes before a first patch. Repository material |
631
+
632
+ [Dated survey](https://github.com/rig-c/core/blob/main/docs/SURVEY_2026-08-22.md).
844
633
 
845
634
  ## Why you can trust the output
846
635
 
@@ -862,7 +651,7 @@ attributability is **measured** to be capped below the bar reads down when every
862
651
  observable about it is independently verified strict. Every other rung and the
863
652
  graduation exam pass on the clause itself. Recompiling a stored candidate reproduces its
864
653
  record **to the digit within one gate**; across an instrument change the digits move,
865
- and [docs/LADDER.md](https://github.com/rig-c/core/blob/main/docs/LADDER.md) records
654
+ and [the gate re-inspection ledger](https://github.com/rig-c/core/blob/main/docs/LADDER.md) records
866
655
  where. The standing figures quoted above are from its *gate-v2.4 re-inspection*, which
867
656
  is the current sweep.
868
657
 
@@ -881,13 +670,13 @@ a from-zero run is a tooling-progress measurement rather than a re-climb, which
881
670
  why the certification above is scoped to tool + guide + protocol. One of those
882
671
  attempts states the residual in its own words: *"in motion it is not at editor
883
672
  quality."* All six, with their verdicts, are in
884
- [docs/LADDER.md](https://github.com/rig-c/core/blob/main/docs/LADDER.md).
673
+ [the from-zero attempt records](https://github.com/rig-c/core/blob/main/docs/LADDER.md).
885
674
 
886
675
  The whole dossier — the yardstick, `diff` and `check` and what neither of them can
887
676
  see, every rung, the run viewer, the 50 assertions and the selftest behind them — is
888
677
  [docs/BENCHMARK.md](https://github.com/rig-c/core/blob/main/docs/BENCHMARK.md).
889
678
  Live rung status is
890
- [docs/LADDER.md](https://github.com/rig-c/core/blob/main/docs/LADDER.md).
679
+ [recorded in the ladder ledger](https://github.com/rig-c/core/blob/main/docs/LADDER.md).
891
680
 
892
681
  ## Contributing
893
682
 
@@ -897,5 +686,4 @@ has to clear before it lands. Releases are cut by release-please —
897
686
 
898
687
  ## Licence
899
688
 
900
- MIT — see [LICENSE](LICENSE). Third-party terms, including the Spine editor licence
901
- requirement that this project inherits, are in [NOTICE.md](NOTICE.md).
689
+ See [NOTICE.md](NOTICE.md) for licensing and third-party terms.