spine-rigc 0.16.0 → 0.18.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/docs/FACE.md CHANGED
@@ -245,6 +245,167 @@ shape the drawing only implies. Two readings that help:
245
245
  measured 5.406 on the artifact. If the fringe does not read as separate,
246
246
  this is the one number to move, and moving it moves nothing else.
247
247
 
248
+ ### 2.1 One depth per part, and the limit of that
249
+
250
+ Everything above states **one depth per part** — a stand-off the whole plate
251
+ shares. That is the right resolution for a part list: the fringe is 26 in front
252
+ of the skull, and arguing about which *pixel* of the fringe is 26 would be
253
+ arguing past what the drawing says.
254
+
255
+ It stops being the right resolution the moment a part's own surface is the
256
+ subject. §4 meshes the face plate into columns precisely because the plate is not
257
+ flat, and §4.2 then finds that refining those columns makes the fold **worse**,
258
+ not better — the columns are sampling a cylinder that was never the shape of a
259
+ face. A cylinder is one number pretending to be a surface, and past a certain
260
+ density the pretence is what fails.
261
+
262
+ ⭐ **Two things had to arrive together, and both are now generated rather than
263
+ written.** The lattice itself was hand-numbered — this example's 25 vertex pairs,
264
+ 32 triangles and hull walk were a person's arithmetic — and
265
+ [AUTHORING §3.4](AUTHORING.md#grid--a-lattice-over-the-part-window)'s `grid`
266
+ generator now builds it from the column positions alone, reproducing this one
267
+ exactly. That is the prerequisite: a turn needs interior vertices to move, and
268
+ §4.3's contour has none.
269
+
270
+ ⭐ **And a depth map is the number above becoming a surface.** A greyscale sheet in the
271
+ part's own pixel grid gives every mesh vertex its own `z`, sampled where the
272
+ vertex actually is, and `yaw`/`pitch` project off it with the same closed form as
273
+ §1 — only the source of `z` changes. What it buys is stated where it is authored:
274
+ [AUTHORING §3.4](AUTHORING.md#depth--give-every-vertex-its-own-z-instead-of-one-cylinder-radius),
275
+ with the sampling order, the refusals and the one that matters most (a sheet cut
276
+ to the art covers **none** of a contour mesh's vertices, because they all sit on
277
+ the silhouette and outside it).
278
+
279
+ ⭐ **And the mesh really is evaluating the pixels' model — measured, not
280
+ asserted.** A consumer that renders the same sheet in a shader displaces every
281
+ PIXEL by its own depth; a mesh displaces vertices and interpolates across
282
+ triangles. On a dome (a ramp would prove nothing — linear interpolation is exact
283
+ on a linear field) at 18°, the two evaluations converge as the lattice refines:
284
+
285
+ | lattice | 3×3 | 5×5 | 9×9 | 17×17 | 33×33 |
286
+ | --- | --- | --- | --- | --- | --- |
287
+ | mean disagreement, px | 6.4141 | 1.8452 | 0.5887 | 0.2276 | **0.0926** |
288
+ | the same lattice reading a **cylinder** instead | 3.8972 | 3.1628 | 3.2558 | 3.3429 | **3.3777** |
289
+
290
+ 🚨 **Read the second row before the first.** A mesh evaluating the wrong surface
291
+ does not converge — it settles at ~3.4px however dense it gets — and at 3×3 it
292
+ reads *better* than the right one. So one measurement at one density cannot tell
293
+ the two models apart, and would have picked the wrong one. The claim is the
294
+ convergence, never a single number. (`CS01`–`CS03` in `selftest.ts`; the worst
295
+ case falls more slowly than the mean and is expected to, because the dome's rim
296
+ has an unbounded depth gradient.)
297
+
298
+ ⚠️ **This is not the same quantity as §4.2's fold angle, which refining makes
299
+ WORSE.** Both are true: a finer lattice buys fidelity to the model and costs the
300
+ angle at which a column pair inverts. This measures the first; `A39` refuses the
301
+ second.
302
+
303
+ ⚠️ **It does not make depth measurable.** The map is relative — 8 bits of level
304
+ say nothing about world units — so `zScale` is authored exactly as the fringe's
305
+ 26 was, and the two warnings above survive intact: get it right and the parallax
306
+ is free, get it wrong and nothing complains. What the map removes is the
307
+ *resolution* limit, not the judgement.
308
+
309
+ ### 2.2 The angle belongs to the map, not to the mesh
310
+
311
+ §2.1 leaves an open question and it has now been measured. §4.2 finds that
312
+ refining the lattice makes the fold **worse**, and read that as the cylinder's
313
+ error surfacing — so per-vertex depth ought to have bought the angle back. ⛔ **It
314
+ does not, and it never could have.**
315
+
316
+ Two neighbouring vertices swap places when the turn tips one past the other,
317
+ which is `tan t ≥ Δu/Δz` — so the largest turn a part supports is
318
+
319
+ tan t_max = 1 / max |dz/du|
320
+
321
+ **the reciprocal of the steepest slope anywhere in its depth map**, and there is
322
+ no mesh in that formula at all. Refining the lattice does not change the angle;
323
+ it changes which slopes the lattice is close enough to *find*. A map with a
324
+ vertical edge has an infinite slope there, so a fine enough mesh folds at any
325
+ angle you name.
326
+
327
+ ⭐ **Which is exactly what a dome is.** `z = Z√(1 − r²)` is vertical at its rim,
328
+ and an even lattice over it folds at `tan t = √h·√(R/2)/Z` for spacing
329
+ `h = W/(side−1)` — a **√h** that goes to zero. Measured against that closed form
330
+ over a 1,300× range of vertex counts, agreeing to ≤ 1.2°:
331
+
332
+ | lattice | 5×5 | 17×17 | 33×33 | 65×65 | 129×129 | 181×181 |
333
+ | --- | --- | --- | --- | --- | --- | --- |
334
+ | **dome**, largest turn admitted | 62° | 41° | 31° | 23° | 17° | **14°** |
335
+ | the closed form above | 59.0° | 39.8° | 30.5° | 22.6° | 16.4° | **14.0°** |
336
+ | **raised cosine**, slope bounded | 73° | 65° | 64° | 64° | 64° | **63°** |
337
+ | its closed form, `atan(2R/Zπ)` | 64.8° | 64.8° | 64.8° | 64.8° | 64.8° | **64.8°** |
338
+
339
+ ⇒ **Author the map so its slope is bounded, and the angle stops depending on the
340
+ mesh.** A raised cosine — flat at the centre, flat again at the rim — holds
341
+ 63–64° from 289 vertices to 32,761. The dome loses three quarters of its angle
342
+ over the same refinement. Both are "correct" depth; only one of them is a
343
+ *surface a turn can be built on*, and the difference is entirely in the input.
344
+
345
+ 🚨 **So a map traced straight off a rendered normal or a photogrammetry pass is
346
+ the dome case, not the cosine case.** Where the part curves away to its
347
+ silhouette is where every such map goes vertical. Flattening it there — letting
348
+ z reach its floor *before* the outline rather than at it — is the edit that buys
349
+ the angle, and it is an edit to the sheet. rigc will not do it for you: the
350
+ compiler never invents a value that is not in the spec, and a depth map is a
351
+ measurement.
352
+
353
+ ⚠️ **This does not touch §2.1's convergence.** A finer lattice still evaluates
354
+ the map's own surface more faithfully; it also finds steeper slopes in it. Those
355
+ are two different quantities and both are true — §2.1 measures the first, `A39`
356
+ refuses the second. What is new here is that the second is a fact about the
357
+ sheet, and can be fixed there.
358
+
359
+ ⭐ **And you no longer have to find the ceiling by building into it.** `build`
360
+ and `explain` print it for any mesh with a depth map — per axis, per direction,
361
+ naming the triangle that goes first — from `tan t = A₀/A_axis` on the mesh's own
362
+ geometry ([AUTHORING §3.4](AUTHORING.md)):
363
+
364
+ ```
365
+ turn ceiling yaw +31.41° / -32.01° pitch +32.01° / -31.41°
366
+ 1st pct yaw +31.55° x1.004 of 1004 / -32.10° x1.003 of 1044 pitch +32.10° x1.003 of 1044 / -31.55° x1.004 of 1004
367
+ first to fold: yaw + at 31.41°, triangle 960 [113,112,593], the sheet steps 12.52 level(s) across it
368
+ ```
369
+
370
+ Read it as a fact about **the sheet**. If the number is too small, the fix is in
371
+ the map — flatten it where the part curves away — and not in the lattice.
372
+
373
+ 📐 Method, harness and the full ladders live in the repository rather than in
374
+ this package, as
375
+ [`bench/studies/2026-09-05-density`](https://github.com/firejune/rigc/tree/main/bench/studies/2026-09-05-density) —
376
+ the same study also measures why `contour` is the wrong generator for a turn: it
377
+ saturates at 868 vertices however fine the tolerance, its vertices all sit on the
378
+ silhouette so it samples **2 %** of the depth range, and its ear-clipped interior
379
+ holds triangles three orders of magnitude apart in area, the smallest of which
380
+ reverse under a fraction of a pixel.
381
+
382
+ 🚨 **The sheet's grain is a slope too, and the ceiling reads it.** Because
383
+ `max|dz/du|` is a maximum over sampled gradients, there is no averaging anywhere
384
+ in it. On a sheet whose true ceiling is 64.77°, measured at 4,225 vertices:
385
+ **±1 level** of noise reports 61.37°, **±8 levels** reports 45.34°, and **one
386
+ stray pixel out of 160,000** reports 6.08° — and `A39` refuses at each of those
387
+ angles, so the rig is as damaged as the report says. Refining the lattice makes
388
+ every one of them worse. Two hard bounds follow, both independent of the form:
389
+ a sheet can never report above `atan(255·h / zScale)` for cell size `h`, and
390
+ below one texel per cell the answer saturates at the steepest adjacent-texel
391
+ step. ⇒ **Author the sheet so it changes by at least ~8 levels across one mesh
392
+ cell**, and spend its whole 0–255 range on the part — a map using an eighth of
393
+ the range describes the same surface and reports 5.8° less of it. Method and
394
+ ladders:
395
+ [`bench/studies/2026-09-05-noise`](https://github.com/firejune/rigc/tree/main/bench/studies/2026-09-05-noise).
396
+
397
+ ⭐ **And you do not have to guess which of the two you are looking at.** The two
398
+ lines under the ceiling say it ([#412](https://github.com/firejune/rigc/issues/412)):
399
+ the **1st percentile over the ceiling** is near 1 when a band of the mesh reaches
400
+ the limit together, which is a form, and near 10 when one triangle does, which is
401
+ a texel — 1.003 against 10.652 for the two sheets above. The **depth step across
402
+ the triangle that folds first**, in levels, is the other half: below about 3 the
403
+ ceiling is quantisation, and at 1 it is `atan(255·h / zScale)` and carries nothing
404
+ about the form at all. Both are reports and neither moves the ceiling — ⛔ rigc
405
+ will not filter a depth map, because a smoothed measurement would describe a
406
+ surface the deform key is not built from and `A39` would go on refusing at the
407
+ raw angle. [AUTHORING §3.4](AUTHORING.md) has the reading table.
408
+
248
409
  ---
249
410
 
250
411
  ## 3. One shared shift, then residuals
@@ -478,6 +639,30 @@ above the 16° §8 calls the instrument's ceiling. ⇒ **Then let the last band
478
639
  single wide one** — that is the direction that buys safety, and it is the
479
640
  opposite of refining.
480
641
 
642
+ 🎭 **The fourth way out, and the one a Live2D-style face actually takes: stop
643
+ drawing the part.** The ceiling only binds while the part is on screen, so a turn
644
+ that has to go past it fades the far cheek or ear out — `rgba` to alpha 0 — or
645
+ swaps the attachment away, and another part takes over. `A39` measures that: a
646
+ deform key whose slot draws **no pixels at that key's own time** is passed over by
647
+ name rather than refused, with the reason on the stats line and beside the key's
648
+ own figures in the `DEFORM` block
649
+ ([#401](https://github.com/firejune/rigc/issues/401)). Two things it is not — the
650
+ bar is alpha **exactly 0**, so a part faded halfway is still refused with the
651
+ alpha in the message; and it is per key and per time, so the same slot folding at
652
+ full alpha anywhere else is refused as before. ⛔ It is also not
653
+ `invariants.deformMayFold`: that field turns the check off for the slot at every
654
+ angle, including the ones where the part is fully visible.
655
+
656
+ 🚨 **Fade out *up to* the angle you cannot take, never *at* it — and the gate now
657
+ keeps that rule rather than asking you to.** The runtime interpolates between
658
+ keys, so an alpha-0 key landing exactly on the folding key leaves the frames just
659
+ before it drawn and nearly folded (§9.2 measures it: 8 reversed triangles at
660
+ alpha 0.20). `A39` scans the spans between consecutive keys as well and refuses
661
+ one by name, at a time solved for in closed form and then posed and measured
662
+ ([#403](https://github.com/firejune/rigc/issues/403), AUTHORING §4.11.3). ⇒ The
663
+ practical shape is unchanged and now checkable: **key the fade to 0 at or before
664
+ the last angle that gates green, and let the fold happen after it.**
665
+
481
666
  📘 **The identity above, used forwards on a `pitch`.**
482
667
  [`gallery/nod`](https://github.com/firejune/rigc/tree/main/gallery/nod)
483
668
  (repository material) picks its ceiling first and solves the *rows* out of it —
@@ -1018,6 +1203,77 @@ not a fold**: its winding survives. The angle A39 first fires at agrees with
1018
1203
  §4.2's `tan θ = Δx/Δz` to **0.0001°**, so the formula above is now checkable by
1019
1204
  running the gate instead of by rendering seven variants.
1020
1205
 
1206
+ 🆕 **And one thing it stopped doing, on 2026-09-05
1207
+ ([#401](https://github.com/firejune/rigc/issues/401)).** Build (b) is refused
1208
+ because the head is *drawn* while it folds. Fade that slot to alpha exactly 0 over
1209
+ the same keys — §4.2's fourth way out, and what a face past its ceiling actually
1210
+ does — and the same build is green, with the key still measured and the reason
1211
+ printed rather than passed over in silence:
1212
+
1213
+ ```
1214
+ DEFORM turn default/head/head key 1 t=0.500000 transform yaw radius=170 degrees=40
1215
+ skipped A39 reads no winding off this key: the slot's alpha is exactly 0 at this
1216
+ time (slot 0.0000 x attachment 1.0000), so this key draws no pixels — a
1217
+ triangle that draws no pixels cannot draw them backwards
1218
+ winding 24 of 32 kept, 0 collapsed <- a fold, and nothing gates it: this key draws no pixels
1219
+ ```
1220
+
1221
+ `A39`'s message says the mesh "draws its texture backwards there", and that
1222
+ sentence is false when the slot draws nothing — the assertion was not too strict,
1223
+ it was measuring something other than what it said. The bar is **alpha exactly
1224
+ 0**; at 0.5 build (b) is refused as before, with the alpha in the message. The
1225
+ same fold at full alpha in another animation is still refused, because the
1226
+ measurement is of one key at one time.
1227
+
1228
+ 🚨 **And the limit of that, measured rather than assumed: the gate read KEYS, and
1229
+ the geometry between two keys is interpolated.** Put the alpha-0 key exactly on
1230
+ the 40° key and 8 triangles are already reversed at `t=0.4`, where the slot is
1231
+ still drawing at **alpha 0.20**:
1232
+
1233
+ | t | slot alpha | reversed triangles |
1234
+ | --- | ---: | ---: |
1235
+ | 0.30 | 0.40 | 0 |
1236
+ | 0.40 | **0.20** | **8** |
1237
+ | 0.45 | 0.10 | 8 |
1238
+ | 0.49 | 0.02 | 8 |
1239
+ | 0.50 | 0.00 | 8 |
1240
+
1241
+ 📌 The table and the refusal below are on the **turn probe** — this head's own
1242
+ five columns and 32 triangles on a one-second timeline, which is why the times
1243
+ are not build (b)'s. It is `selftest.ts`'s fixture, so the rows are reproduced by
1244
+ every run rather than transcribed once.
1245
+
1246
+ 🆕 **Closed on 2026-09-05
1247
+ ([#403](https://github.com/firejune/rigc/issues/403)), and the shape of the fix
1248
+ is the reason it is here rather than in a paragraph of advice.** Every interval
1249
+ between two consecutive deform keys is scanned. A deform interpolated between two
1250
+ keys travels a **straight line through offset space**, so a triangle's signed
1251
+ area is a *quadratic in the interpolation fraction* — the fold is a root of it,
1252
+ solved for rather than searched, with no sample spacing anybody would have to
1253
+ defend. What that arithmetic names is then posed and measured by the same code
1254
+ that measures a key, **alpha read at that same instant**, so the fade a correct
1255
+ rig relies on is not refused and the frames it does not cover are:
1256
+
1257
+ ```
1258
+ FAIL A39_DEFORM_KEEPS_TRIANGLE_WINDING: animation "turn" deform head/head BETWEEN key 0
1259
+ (t=0s) and key 1 (t=0.5s), at t=0.444089s — 88.8% of the way from one to the other:
1260
+ 8 of 32 triangle(s) reverse winding … NO KEY LANDS THERE … at alpha 0.1118
1261
+ ```
1262
+
1263
+ ⇒ The rule this section gave — *fade out over the run up to the angle you cannot
1264
+ take, so that every key past the ceiling is one that draws nothing* — is
1265
+ unchanged. What changed is that it is now a **measurement**: land the alpha-0 key
1266
+ on the fold and the build is refused, with the frame it is refused for.
1267
+
1268
+ ⚠️ **What that scan still cannot see**, stated because the limit moved rather
1269
+ than vanished: the closed form holds the BONES still across the span. On an
1270
+ unweighted attachment that is exact — one matrix multiplies every vertex and its
1271
+ determinant cancels out of the sign comparison — but on a weighted mesh whose
1272
+ bones move across the span it is an approximation, and a prediction no
1273
+ measurement reproduced is reported (`deformSpansUnconfirmed`) rather than
1274
+ refused. A fold caused by the bones alone is not this rule's subject at all, and
1275
+ `check` against a trusted render (§9.3) is what sees it.
1276
+
1021
1277
  ⚠️ **One thing it deliberately does not do.** It is an **archetype** rule, so a
1022
1278
  `--profile spine` build reads `PROF` — the premise "a fold has no legitimate
1023
1279
  counter-example" turned out to be false when it was measured, an official
package/docs/MOTION.md CHANGED
@@ -104,6 +104,11 @@ about.
104
104
  | **frame rate** | *"at 12 fps"* | ⛔ **do not adopt one.** Spine's times are seconds and frames exist only for convenience (AUTHORING §10.3), so a rate belongs to `render --fps` and to nothing in either spec file |
105
105
  | **pose-frame scale** | almost never stated | search the default window once, read the `search` block back, and narrow it if the answer sits at a window edge — §2.2 |
106
106
 
107
+ 📖 **A request in an animator's words — *"heavier"*, *"follow through"*, *"keep
108
+ the volume"* — maps to a construct in §3.1.1's table.** Two of its rows are
109
+ corrections rather than translations, so read it before assuming a word means
110
+ here what it means elsewhere.
111
+
107
112
  ⚠️ **Read the intent adjectives before you read the pictures, and write down what
108
113
  you think they mean, in movement terms, before any measurement.** *"Snap"* means the
109
114
  extreme arrives early and the value settles late; *"heavy"* means the parts separate
@@ -270,6 +275,53 @@ it paraphrases.
270
275
  *unless the intent says otherwise*, exactly as AUTHORING §10 puts it, and the
271
276
  adjectives in §1 are what overrides them.
272
277
 
278
+ ### 3.1.1 The animator's words, in this vocabulary
279
+
280
+ A request arrives in an animator's words — *"make it feel heavier"*, *"keep the
281
+ volume when it lands"*, *"the cape should follow through"* — and this table is
282
+ the map from those to the construct that carries them. §1's intent-adjective
283
+ paragraph does this for three words; this is its full form.
284
+
285
+ ⚠️ **Two rows are corrections rather than translations**, and they are the
286
+ reason the table earns its place: Spine's `Ease in`/`Ease out` mean the
287
+ **opposite** of the web's, and a *moving hold* is not §3.3's *hold*. Both are
288
+ words an agent already thinks it knows.
289
+
290
+ Marks are §3.1's: 📗 stated on the linked page, 🧩 this guide's reading. Per
291
+ cell, because most rows are a sourced word mapped to an unsourced construct.
292
+
293
+ | The animator's word | What it means | rigc's construct |
294
+ | --- | --- | --- |
295
+ | **weight** — *"make it feel heavier"* | 📗 how an object answers a push: a light one reacts sooner than a heavy one ([twelve principles]) | 🧩 not one field. A longer `duration`, a slower attack on the leading `ease`, and **larger** offsets down §3.7's table — heavy is *parts separating in time*, which is what §1 already says the adjective means |
296
+ | **timing** | 📗 how many frames an action takes, which is its speed ([twelve principles]) | 📗 `duration` and the key times, **in seconds** — frames exist for convenience only ([Keys]) · §3.3 |
297
+ | **spacing** | 🧩 how far the value moves between one sampled frame and the next. Timing is *when the keys are*; spacing is *what happens between them* | 🧩 the `ease` on the key, not the key times. It has no field of its own — §2.1 sends you to the contact sheet because spacing is only visible across frames · §3.4 |
298
+ | **slow in / slow out** | 📗 a body needs time to accelerate and to stop, so more drawings fall near each end ([twelve principles]) | 📗 a named entry in `easings` · §3.4. 🚨 **Spine's preset names invert the web's**: its *Ease out* changes more slowly near **the key**, its *Ease in* more slowly near **the next key** ([Graph]). An agent carrying the CSS meaning picks the opposite shape |
299
+ | **arcs** | 📗 natural movement follows a curved path; straight lines read as mechanical ([twelve principles]) | 🧩 the **channel**, not a setting: `rotate` gives the arc free, `translate` draws the straight line. The question is never *arc or line*, it is *which channel carries this move* · §3.5 |
300
+ | **anticipation** — *"wind up first"* | 📗 a small preparation that makes the action read ([twelve principles]) | 🧩 §3.6's interior key, the other way. 🚨 It goes **after** `t: 0` at L1/L2 — `t: 0` is a given condition, not a pose to move |
301
+ | **follow-through** | 📗 loosely attached parts keep going after the body stops, then are pulled back ([twelve principles]) | 🧩 the trailing part's extreme lands later than its driver's **and overshoots once** — §3.7's last rows are that pull-back · §3.8 |
302
+ | **overlapping action** — *"don't let it move as one piece"* | 📗 parts of a body move on different timings from one another ([twelve principles]) | 📗 in the editor it is literally *moving keys in time*, which is what the offset button is for ([Keys]). 🧩 here: a later extreme per bone, or `groups` + `stagger` where members share a value · §3.7 |
303
+ | **drag** — *"it should lag"* | 📗 parts take a few frames to catch up when a body starts moving ([twelve principles]) | 🧩 the same offset applied at the **start** rather than at the stop. ⚠️ Convert the source's frames to a **fraction** of the duration — §3.7's offsets are fractions, so a 0.15 s snap and a 2 s idle share one table · §3.7 |
304
+ | **the wave principle** | 📗 Esoteric's own framing: the thing to understand for tails, hair, cloth and flags — anything that follows through (video 4) | 🧩 the offset **compounding down a chain**, so the lag travels: `groups` + `stagger` where the members are a chain. ⚠️ **`wave` already names something else here** — a deform transform kind (AUTHORING §4.11.1) that ripples an attachment's vertices, not a chain's timing |
305
+ | **squash and stretch** | 📗 what gives a drawing weight and flexibility ([twelve principles]); Spine notes the shear tool is used in small amounts for organic squash and stretch ([Tools]) | 🧩 two spellings. **Cheap:** a `scale` key whose two axes differ. **Full:** a `deform` timeline, which is what `gallery/squash` uses. §7 is rigid-first — land the movement, then deform · §4 |
306
+ | **keeping the volume** | 📗 in *realistic* animation a squashed object keeps its volume: stretch it one way and it must narrow the other ([twelve principles]) | 🧩 `x·y ≈ 1` on a `scale` key, which `explain` now prints beside it, and the `area` figure a `deform` key already carried. **A reading, never a rule** — a shadow, a zoom and a cartoon squash all change area on purpose. ⚠️ Say *scale product* in a message: `volume` already means an event's audio and 4.3's `ScaleYMode.Volume` |
307
+ | **overshoot and settle** | 📗 exaggeration — a motion that imitates reality exactly reads as dull ([twelve principles]) | 🧩 §3.8's interior key past the final value, then back. 🚨 The last key still carries the given end pose exactly |
308
+ | **a moving hold** — *"it should never be fully still"* | 📗 a character that is barely moving still breathes; two nearly-identical poses keep it from going lifeless ([twelve principles]) | 🧩 **not** §3.3's *hold*, which is two EQUAL keys meaning *nothing moves here*. A moving hold is the opposite: §3.3's 1.5–3 s idle band with a small excursion — §0's A=B case |
309
+ | **secondary action** | 📗 a supporting movement that emphasises the main one rather than competing with it ([twelve principles]) | 🧩 a whole extra timeline, and the **first thing to leave out of a first candidate**: a ballot spreading on both primary timing and a secondary action has asked two questions · §3.10 |
310
+ | **pose to pose** vs **straight ahead** | 📗 the two ways animation is made — extremes first and fill in, or forward frame by frame ([twelve principles]) | 🧩 a keyframed skeleton can only do the first. Nothing in the format means *"and then draw the next frame"* — §3.2 |
311
+
312
+ [twelve principles]: https://en.wikipedia.org/wiki/Twelve_basic_principles_of_animation
313
+ [Keys]: http://esotericsoftware.com/spine-keys
314
+ [Graph]: http://esotericsoftware.com/spine-graph
315
+ [Tools]: http://esotericsoftware.com/spine-tools
316
+
317
+ ⚠️ **The eight *Animating with Spine* videos are the obvious source for this
318
+ table and none of it comes from them.** Their captions could not be retrieved —
319
+ the manifest is served and the body is not — so nothing here is presented as
320
+ something said in one. Two rows cite a video's published *description*, which is
321
+ Esoteric's own prose and marked as such; everything else is the twelve
322
+ principles and Spine's written documentation. If the narration becomes readable,
323
+ this table is where it belongs.
324
+
273
325
  ### 3.2 📗 Pose to pose is the normal form, and it is one of two
274
326
 
275
327
  Animation is publicly catalogued as being made either **straight ahead** — drawn
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-rigc",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "description": "Rig compiler for Spine — declarative rig specs in, Spine 4.3 skeleton data out, verified by a spine-core round-trip. Built so AI agents can author rigs and check their own work; the output imports into the Spine editor.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -39,6 +39,7 @@
39
39
  "tools/contact.ts",
40
40
  "tools/png_probe.mjs",
41
41
  "tools/measure_contact_depth.ts",
42
+ "tools/editor_roundtrip.ts",
42
43
  "docs/AUTHORING.md",
43
44
  "docs/SPEC_COVERAGE.md",
44
45
  "docs/PROMPTING.md",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: motion
3
- description: Author a Spine animation with rigc from key poses — an idle, a loop, a move from one picture to another — with timing, easing, anticipation, follow-through, and candidate variants a person can choose between. Use when the request is a movement on an existing or planned rig, such as "animate this rig", "make it breathe" or "go from pose A to pose B", including reading the poses out of reference frames. Not for Live2D, separating an image into parts, or motion capture and real-time tracking.
3
+ description: Author a Spine animation with rigc from key poses — an idle, a loop, a move from one picture to another — with timing and spacing, ease in and out, anticipation, arcs, overlap, follow-through, squash and stretch, and candidate variants a person can choose between. Use when the request is a movement on an existing or planned rig, in the animator's words too: "animate this rig", "make it breathe", "go from pose A to pose B", "make it feel heavier", "the cape should follow through". Not for Live2D, separating an image into parts, or real-time tracking.
4
4
  license: MIT
5
5
  compatibility: Requires Bun 1.2 or later and the npm package spine-rigc.
6
6
  ---