spine-rigc 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -9
- package/cli.ts +50 -8
- package/docs/AUTHORING.md +232 -32
- package/docs/INGEST.md +25 -14
- package/docs/SPEC_COVERAGE.md +6 -5
- package/package.json +1 -1
- package/skills/ingest/SKILL.md +6 -5
- package/src/check.ts +12 -0
- package/src/compile.ts +328 -10
- package/src/deformmeasure.ts +7 -2
- package/src/ingest.ts +208 -48
- package/src/motion.ts +82 -1
- package/src/rig.ts +145 -3
- package/src/timelines.ts +94 -6
- package/src/types.ts +63 -0
- package/src/validate.ts +440 -72
package/README.md
CHANGED
|
@@ -516,7 +516,7 @@ commands take it and what its default is.
|
|
|
516
516
|
| `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` and `--padding` tune it |
|
|
517
517
|
| `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 |
|
|
518
518
|
| `validate <dir>` | re-gates artifacts already on disk |
|
|
519
|
-
| `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. `--stage x,y,w,h`
|
|
519
|
+
| `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 |
|
|
520
520
|
| `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 |
|
|
521
521
|
| `render --candidate <dir>` | PNG frames plus a contact sheet, in `render/` |
|
|
522
522
|
| `preview --candidate <dir>` | one self-contained `.html` that plays it |
|
|
@@ -533,9 +533,9 @@ first three work on any reference you have, and `bench` is a repository workflow
|
|
|
533
533
|
and `bun run fetch-examples`. The reasoning behind them is in
|
|
534
534
|
[the benchmark dossier](https://github.com/firejune/rigc/blob/main/docs/BENCHMARK.md).
|
|
535
535
|
|
|
536
|
-
`build` and `validate` both default to `--profile spine` — the
|
|
536
|
+
`build` and `validate` both default to `--profile spine` — the 32 validity rules, which
|
|
537
537
|
ask *is this valid Spine 4.3 that any runtime plays correctly?* `--profile spine-html`
|
|
538
|
-
adds all
|
|
538
|
+
adds all 47: the other 15 are one renderer's policy and one canvas budget's, and they
|
|
539
539
|
fire on perfectly correct editor-produced Spine data, which is why they are opt-in.
|
|
540
540
|
⇒ **That reason is about foreign data and does not carry to a rig you are authoring
|
|
541
541
|
yourself: author under `--profile spine-html` and read the extra 15 as findings, and
|
|
@@ -595,10 +595,12 @@ One thing it drops on purpose and says so: a path attachment's `lengths`, which
|
|
|
595
595
|
|
|
596
596
|
⚠️ **Two values are not in a skeleton at all.**
|
|
597
597
|
|
|
598
|
-
- **The stage.** `skeleton.width`/`height
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
598
|
+
- **The stage.** `skeleton.width`/`height`. A skeleton that declares none is carried as
|
|
599
|
+
declaring none — the rig spec states `"width": null, "height": null` and the rebuild
|
|
600
|
+
carries no box either, byte for byte
|
|
601
|
+
([#714](https://github.com/firejune/rigc/issues/714)) — and `--stage x,y,w,h` is how a
|
|
602
|
+
caller *adds* one, recorded as a judgement. It is not derivable — posing the rig gives
|
|
603
|
+
the *animated* extent, which is a different number from the setup box. ⛔ **And `--stage` beside a box the file already states is refused
|
|
602
604
|
too**, for the opposite reason: two sources for one value, where the file is the record
|
|
603
605
|
of what was measured. It used to be read after the box and therefore never
|
|
604
606
|
([#626](https://github.com/firejune/rigc/issues/626)). ⚠️ This said *"an editor export carries none"* until #594 measured
|
|
@@ -681,7 +683,7 @@ letting `A17` blame the editor for the harness's own doing.
|
|
|
681
683
|
| 📥 **[docs/INGEST.md](docs/INGEST.md)** | **working with a skeleton you did not author.** What every command can and cannot do with a foreign `skeleton.json`, reading it with the toolchain, transcription as the route that makes it yours, what each validator complaint means on an export, and the re-pivot/rename/extend recipes. Ships in the package too |
|
|
682
684
|
| 🤖 **[docs/PROMPTING.md](docs/PROMPTING.md)** | **handing the authoring to an AI agent** — the prompt clauses a measured pilot run paid for, and what you can leave unsaid. Ships in the package too |
|
|
683
685
|
| 🔬 **[docs/SPEC_COVERAGE.md](docs/SPEC_COVERAGE.md)** | Spine 4.3's full export surface against what rigc emits and what the official examples measurably use, with the ordered gap list |
|
|
684
|
-
| 🎓 **[the benchmark dossier](https://github.com/firejune/rigc/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
|
|
686
|
+
| 🎓 **[the benchmark dossier](https://github.com/firejune/rigc/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 47 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 |
|
|
685
687
|
| 📋 [LADDER.md](https://github.com/firejune/rigc/blob/main/docs/LADDER.md) · [GATE.md](https://github.com/firejune/rigc/blob/main/docs/GATE.md) · [PILOT.md](https://github.com/firejune/rigc/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 |
|
|
686
688
|
| 🗺️ [ROADMAP.md](https://github.com/firejune/rigc/blob/main/ROADMAP.md) | where this is going, and where it has been. What 1.0 has to mean before the number is claimed — conditions rather than a feature list, because direction here comes from what users hit |
|
|
687
689
|
| 📐 [CLAUDE.md](https://github.com/firejune/rigc/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/firejune/rigc/blob/main/CONTRIBUTING.md) calls it worth ten minutes before a first patch. Repository material |
|
|
@@ -738,7 +740,7 @@ quality."* All six, with their verdicts, are in
|
|
|
738
740
|
[docs/LADDER.md](https://github.com/firejune/rigc/blob/main/docs/LADDER.md).
|
|
739
741
|
|
|
740
742
|
The whole dossier — the yardstick, `diff` and `check` and what neither of them can
|
|
741
|
-
see, every rung, the run viewer, the
|
|
743
|
+
see, every rung, the run viewer, the 47 assertions and the selftest behind them — is
|
|
742
744
|
[docs/BENCHMARK.md](https://github.com/firejune/rigc/blob/main/docs/BENCHMARK.md).
|
|
743
745
|
Live rung status is
|
|
744
746
|
[docs/LADDER.md](https://github.com/firejune/rigc/blob/main/docs/LADDER.md).
|
package/cli.ts
CHANGED
|
@@ -1746,6 +1746,46 @@ function readPositiveNumber(flags: Record<string, string>, key: string, fallback
|
|
|
1746
1746
|
return value;
|
|
1747
1747
|
}
|
|
1748
1748
|
|
|
1749
|
+
/**
|
|
1750
|
+
* Does this skeleton declare a setup stage — a numeric width AND height?
|
|
1751
|
+
*
|
|
1752
|
+
* Read off the loaded `SkeletonData` for `render` and off the file's header for
|
|
1753
|
+
* `preview`, which never loads one; both are the same two fields, because
|
|
1754
|
+
* `SkeletonJson` copies them across unconditionally (`SkeletonJson.js:70-73`),
|
|
1755
|
+
* so a header that omits them leaves `undefined` on a field typed `number`.
|
|
1756
|
+
*/
|
|
1757
|
+
function declaresSetupStage(header: { width?: unknown; height?: unknown }): boolean {
|
|
1758
|
+
return typeof header.width === 'number' && typeof header.height === 'number';
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
/** The `skeleton` block of a skeleton file's text, or an empty one where it has none. */
|
|
1762
|
+
function skeletonHeaderOf(skeletonText: string): { width?: unknown; height?: unknown } {
|
|
1763
|
+
const root = JSON.parse(skeletonText) as { skeleton?: { width?: unknown; height?: unknown } };
|
|
1764
|
+
return root.skeleton ?? {};
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
/**
|
|
1768
|
+
* What `render` and `preview` say of their framing on a skeleton that declares
|
|
1769
|
+
* no stage (issue #714).
|
|
1770
|
+
*
|
|
1771
|
+
* ⚠️ **Neither frames to a stage on ANY skeleton**, so this is not a fallback
|
|
1772
|
+
* being announced: `framingViewport` is the union of every animation's posed
|
|
1773
|
+
* bounds, and the Spine Web Player's `calculateAnimationViewport` samples the
|
|
1774
|
+
* playing animation's bounds whenever its config states no viewport box, which
|
|
1775
|
+
* `buildPreview` never does. The line is printed only where a stage is absent
|
|
1776
|
+
* because that is the one case where a reader can ask *what box stood in for
|
|
1777
|
+
* it* — and the answer has to be "none", said, rather than a rectangle that looks
|
|
1778
|
+
* like a default. On a staged skeleton the output is the bytes it always was.
|
|
1779
|
+
*/
|
|
1780
|
+
const STAGELESS_FRAMING = {
|
|
1781
|
+
render:
|
|
1782
|
+
'framing the posed extent of every animation, padded — this skeleton declares no stage, and nothing stands ' +
|
|
1783
|
+
'in for one: render frames to the posed extent whether or not a stage is declared',
|
|
1784
|
+
preview:
|
|
1785
|
+
"framing the Spine Web Player's own: the posed extent of the animation it plays — this skeleton declares no " +
|
|
1786
|
+
'stage, and nothing stands in for one: the player frames that way whether or not a stage is declared',
|
|
1787
|
+
} as const;
|
|
1788
|
+
|
|
1749
1789
|
/**
|
|
1750
1790
|
* render — the frame series, drawn by the same rasteriser `check` measures with.
|
|
1751
1791
|
*
|
|
@@ -1788,6 +1828,7 @@ function cmdRender(flags: Record<string, string>): void {
|
|
|
1788
1828
|
const sampled: Map<string, Frame[]> =
|
|
1789
1829
|
only === undefined ? sampleAll(data, fps, pose) : new Map([[only, sampleAnimation(data, only, fps, pose)]]);
|
|
1790
1830
|
console.log(` .. ${viewport.width}x${viewport.height}px at ${fps} fps, ${sampled.size} set(s) -> ${outRoot}`);
|
|
1831
|
+
if (!declaresSetupStage(data)) console.log(` .. ${STAGELESS_FRAMING.render}`);
|
|
1791
1832
|
|
|
1792
1833
|
mkdirSync(outRoot, { recursive: true });
|
|
1793
1834
|
const sets: FrameSet[] = [];
|
|
@@ -1903,6 +1944,7 @@ function cmdPreview(flags: Record<string, string>): void {
|
|
|
1903
1944
|
for (const page of pages) {
|
|
1904
1945
|
console.log(` .. page ${page.name.padEnd(28)} ${(page.bytes.length / 1024).toFixed(1)} KiB`);
|
|
1905
1946
|
}
|
|
1947
|
+
if (!declaresSetupStage(skeletonHeaderOf(skeletonText))) console.log(` .. ${STAGELESS_FRAMING.preview}`);
|
|
1906
1948
|
|
|
1907
1949
|
const html = buildPreview({
|
|
1908
1950
|
skeletonText,
|
|
@@ -3263,9 +3305,10 @@ const FLAG_MEANINGS: Record<string, string> = {
|
|
|
3263
3305
|
'--images <dir>` on every rebuild), `none` states width/height only for `build --atlas-in <pack>` to ' +
|
|
3264
3306
|
'resolve (default: loose)',
|
|
3265
3307
|
stage:
|
|
3266
|
-
'the setup bounding box — `skeleton.x,y,width,height` —
|
|
3308
|
+
'the setup bounding box — `skeleton.x,y,width,height` — to ADD to a skeleton that declares none. It cannot be ' +
|
|
3267
3309
|
'derived: posing the rig gives the ANIMATED extent, which is a different number from the setup box, so this ' +
|
|
3268
|
-
"is the caller's value, and without it the
|
|
3310
|
+
"is the caller's value, and without it the absence is carried: the spec states `\"width\": null, \"height\": " +
|
|
3311
|
+
'null` and the rebuild declares no stage either. ⚠️ An editor export MAY ' +
|
|
3269
3312
|
'carry none; every editor export measured for this project carries one and ingest reads it straight through, ' +
|
|
3270
3313
|
'so the flag is for a file that really has none rather than for editor exports as a class. ⛔ Beside a ' +
|
|
3271
3314
|
'skeleton that already declares a box it is REFUSED rather than ignored: two sources for one value, and the ' +
|
|
@@ -3677,12 +3720,11 @@ const USAGE = [
|
|
|
3677
3720
|
' rigc ingest hero.json --out specs/ --images parts/ rig.json + motion.json',
|
|
3678
3721
|
'The contract is an equality, not a rulebook: build(ingest(x)) is x, byte for byte.',
|
|
3679
3722
|
'It reads the skeleton and nothing else — no .spine project, no binary .skel, no',
|
|
3680
|
-
'atlas — so
|
|
3681
|
-
'setup stage
|
|
3682
|
-
'
|
|
3683
|
-
'
|
|
3684
|
-
'
|
|
3685
|
-
'no flag.',
|
|
3723
|
+
'atlas — so how the spec reaches the art is the caller\'s (--art) and is not guessed.',
|
|
3724
|
+
'A setup stage the skeleton states is read; one it does not state is carried as',
|
|
3725
|
+
'absent, and --stage is how a caller adds a box to such a file — beside a box the',
|
|
3726
|
+
'file states, the flag is refused rather than ignored. --images <dir> WRITES the rig',
|
|
3727
|
+
'spec\'s own images directory, relative to --out, so the rebuild needs no flag.',
|
|
3686
3728
|
'Everything the spec format cannot hold is printed as a named finding and',
|
|
3687
3729
|
'exits non-zero, with both files still written, because a spec plus a list of what',
|
|
3688
3730
|
'is missing from it beats no spec at all.',
|