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/README.md +67 -6
- package/cli.ts +368 -19
- package/docs/AUTHORING.md +570 -99
- package/docs/FACE.md +256 -0
- package/docs/MOTION.md +52 -0
- package/package.json +2 -1
- package/skills/motion/SKILL.md +1 -1
- package/src/compile.ts +770 -41
- package/src/deformgen.ts +125 -18
- package/src/deformmeasure.ts +1469 -138
- package/src/depth.ts +610 -0
- package/src/mesh.ts +104 -1
- package/src/rig.ts +124 -0
- package/src/transform.ts +24 -0
- package/src/types.ts +66 -3
- package/src/validate.ts +464 -8
- package/tools/editor_roundtrip.ts +557 -0
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.
|
|
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",
|
package/skills/motion/SKILL.md
CHANGED
|
@@ -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,
|
|
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
|
---
|