spine-rigc 1.0.0 → 1.0.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 +35 -71
- package/docs/AUTHORING.md +727 -1160
- package/docs/FACE.md +205 -371
- package/docs/INGEST.md +155 -305
- package/docs/MOTION.md +11 -27
- package/docs/PROMPTING.md +1 -1
- package/docs/RIGGING.md +10 -26
- package/docs/SPEC_COVERAGE.md +27 -871
- package/package.json +1 -1
- package/src/atlas.ts +9 -8
- package/src/compile.ts +1 -1
- package/src/generation.ts +2 -1
- package/src/ladder.ts +1 -1
- package/src/rig.ts +4 -4
- package/src/validate.ts +20 -14
package/docs/FACE.md
CHANGED
|
@@ -36,7 +36,7 @@ hold its results.
|
|
|
36
36
|
[`gallery/portrait`](https://github.com/firejune/rigc/tree/main/gallery/portrait),
|
|
37
37
|
and its measurement half,
|
|
38
38
|
[`FINDINGS.md`](https://github.com/firejune/rigc/tree/main/gallery/portrait/FINDINGS.md)
|
|
39
|
-
- **The same closed forms on the other axis
|
|
39
|
+
- **The same closed forms on the other axis**:
|
|
40
40
|
[`gallery/nod`](https://github.com/firejune/rigc/tree/main/gallery/nod) is a
|
|
41
41
|
worked `pitch`, and this page stays written for a **yaw**. It re-derives §4.2's
|
|
42
42
|
fold angle on uneven *rows* and brackets it against `A39` at 33°/34°, and it
|
|
@@ -51,7 +51,7 @@ hold its results.
|
|
|
51
51
|
animation — a pointer, a gaze target, a game value
|
|
52
52
|
|
|
53
53
|
🚨 **A `deform` key's winding is gated; how far it moved the geometry is not, and
|
|
54
|
-
that half is the one you have to author around.**
|
|
54
|
+
that half is the one you have to author around.**
|
|
55
55
|
`A39_DEFORM_KEEPS_TRIANGLE_WINDING` refuses a key that turns the mesh inside out —
|
|
56
56
|
by name, by key and by triangle — and the build writes nothing. What no assertion
|
|
57
57
|
has an opinion about is **magnitude**: a band that stretches where the projection
|
|
@@ -135,8 +135,7 @@ agrees with the line, or it does not.
|
|
|
135
135
|
### 1.1 ⭐ And now the spec holds the line, not its results
|
|
136
136
|
|
|
137
137
|
**A `deform` key states this expression** (AUTHORING §4.11.1). The worked
|
|
138
|
-
example's held 12° yaw
|
|
139
|
-
and it is now four lines of which two are the angle:
|
|
138
|
+
example's held 12° yaw is four lines of which two are the angle:
|
|
140
139
|
|
|
141
140
|
```json
|
|
142
141
|
{ "t": 0.62, "transform": { "kind": "yaw", "radius": 170, "degrees": 12 }, "ease": "swell" },
|
|
@@ -146,79 +145,53 @@ and it is now four lines of which two are the angle:
|
|
|
146
145
|
⇒ **`radius` is `R` off the depth table (§2) and `degrees` is the angle.** The
|
|
147
146
|
compiler evaluates `dx = x·(cos t − 1) − z·sin t` at every vertex with
|
|
148
147
|
`z = √(R² − x²)`, writes the millimetre-level results into the artifact, and
|
|
149
|
-
`explain` prints both the model and the offsets it produced. What
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
- **The anticipation and the head-follow §3.6 and §7 priced out** were priced out
|
|
161
|
-
by the transcription, not by the format. 80 numbers for a tenth of a second is
|
|
162
|
-
now one key with a smaller `degrees`.
|
|
163
|
-
- **The audit changed shape.** A transcription can only be checked against the
|
|
148
|
+
`explain` prints both the model and the offsets it produced. What the key
|
|
149
|
+
states is a measurement of the shape the drawing implies, and nothing else.
|
|
150
|
+
|
|
151
|
+
Three things follow, and they are the reasons the construct exists rather than
|
|
152
|
+
side effects:
|
|
153
|
+
|
|
154
|
+
- **A second angle is a second number.** Each angle of §8's cliff sweep — 8, 12,
|
|
155
|
+
16, 20, 24, 28 and 32 degrees — is `"degrees": <n>` and a rebuild.
|
|
156
|
+
- **A small yaw is one key.** The anticipation MOTION §3.6 asks for and the
|
|
157
|
+
head-follow §7 prices are each one key with a smaller `degrees`.
|
|
158
|
+
- **The audit is two parameters.** A transcription can only be checked against the
|
|
164
159
|
line by hand, which is §9.3's gap; a stated model is checked by reading two
|
|
165
160
|
parameters. What is still unmeasured is the *consequence* — whether that angle
|
|
166
161
|
folds the mesh — and §4.2 and A39 are that half.
|
|
167
162
|
|
|
168
163
|
⚠️ **What it does not do.** It evaluates; it never chooses. The radius, the
|
|
169
164
|
angle, the depth table and whether 12° reads are all yours, and a wrong `radius`
|
|
170
|
-
|
|
171
|
-
|
|
165
|
+
produces 160 consistent wrong numbers at once — see §4's warning, which the
|
|
166
|
+
construct makes cheaper to get wrong rather than harder.
|
|
172
167
|
|
|
173
168
|
📌 **Author `t` in degrees, in the spec.** Radians appear nowhere: the key holds
|
|
174
|
-
the angle and the compiler holds the conversion.
|
|
175
|
-
section replaced — the angle used to live only in a comment beside the part list,
|
|
176
|
-
because the spec could not hold it, and §9 was what happened when a later reader
|
|
177
|
-
could not find it.
|
|
169
|
+
the angle and the compiler holds the conversion.
|
|
178
170
|
|
|
179
171
|
---
|
|
180
172
|
|
|
181
173
|
## 2. Depth is the parameter you are actually authoring
|
|
182
174
|
|
|
183
175
|
🚨 **A part list for a face is not a list of drawings. It is a list of
|
|
184
|
-
`(x, z)`.**
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
>
|
|
189
|
-
> ```bash
|
|
190
|
-
> grep -c '"z"' gallery/portrait/rig.json gallery/portrait/motion.json # 0 and 0
|
|
191
|
-
> ```
|
|
192
|
-
>
|
|
193
|
-
> The bones carried `x` (`eye_l` at `−62`, `nose` at `0`), the rig carried the mesh
|
|
194
|
-
> columns' `x`, and every `z` that produced every number lived **only in the
|
|
195
|
-
> README beside them**.
|
|
196
|
-
|
|
197
|
-
⚠️ **Read that as the reason the constructs below exist, not as the state of the
|
|
198
|
-
tool.** The `z` above never had a home because a track carries a value and not a
|
|
199
|
-
model — so a depth was consumed, arithmetic was done by hand, and the input
|
|
200
|
-
vanished. Both halves have since been given one (next paragraph), and `"z"` is
|
|
201
|
-
still `0` in both files because the field is spelled `radius` on a mesh key and
|
|
202
|
-
`depth` on a bone track.
|
|
203
|
-
|
|
204
|
-
⇒ **The instruction survives anyway: write the depth table down somewhere a
|
|
205
|
-
reader will find it.** The specs now hold the depths the turn *uses*; a project's
|
|
206
|
-
own reasoning about them — why the fringe stands off 26 and not 15 — still belongs
|
|
207
|
-
beside the rig, and in the worked example that is a table in its README.
|
|
208
|
-
|
|
209
|
-
⭐ **Every depth is now in the file, and both halves of that arrived as their own
|
|
210
|
-
construct.** Since [#294](https://github.com/firejune/rigc/issues/294) a `yaw`
|
|
176
|
+
`(x, z)`.** The bones carry `x` (`eye_l` at `−62`, `nose` at `0`) and the rig
|
|
177
|
+
carries the mesh columns' `x`; the `z` is in no drawing.
|
|
178
|
+
|
|
179
|
+
⭐ **Every depth goes in the file, and each half has its own construct.** A `yaw`
|
|
211
180
|
deform key states its `radius` (§1.1), which is the `R` of the cylinder that plate
|
|
212
|
-
is painted on — so the head's 170 and the fringe's 196 are in `motion.json`.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
181
|
+
is painted on — so the head's 170 and the fringe's 196 are in `motion.json`. A
|
|
182
|
+
**bone** track's key can state a `derive` model over a group, whose `depth` is one
|
|
183
|
+
number **per member** — so the feature depths, the hair depths and the sign flip
|
|
184
|
+
below are in the file too (§3, AUTHORING §4.5.1). Neither is spelled `"z"`: the
|
|
185
|
+
field is `radius` on a mesh key and `depth` on a bone track.
|
|
217
186
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
187
|
+
⇒ **Write the depth table down somewhere a reader will find it.** The specs hold
|
|
188
|
+
the depths the turn *uses*; a project's own reasoning about them — why the fringe
|
|
189
|
+
stands off 26 and not 15 — belongs beside the rig, and in the worked example that
|
|
190
|
+
is a table in its README.
|
|
191
|
+
|
|
192
|
+
⚠️ **A depth is a decision.** The table below is the thing to argue about before
|
|
193
|
+
authoring anything, and the point of writing it into the spec is that a reader of
|
|
194
|
+
the numbers can see the table that produced them:
|
|
222
195
|
|
|
223
196
|
```bash
|
|
224
197
|
grep -c '"depth"' gallery/portrait/motion.json # 8, one per derive key
|
|
@@ -272,12 +245,11 @@ not better — the columns are sampling a cylinder that was never the shape of a
|
|
|
272
245
|
face. A cylinder is one number pretending to be a surface, and past a certain
|
|
273
246
|
density the pretence is what fails.
|
|
274
247
|
|
|
275
|
-
⭐ **Two things
|
|
276
|
-
written.** The lattice itself was hand-numbered — this example's 25 vertex pairs,
|
|
277
|
-
32 triangles and hull walk were a person's arithmetic — and
|
|
248
|
+
⭐ **Two things arrive together, and both are generated rather than written.**
|
|
278
249
|
[AUTHORING §3.4](AUTHORING.md#grid--a-lattice-over-the-part-window)'s `grid`
|
|
279
|
-
generator
|
|
280
|
-
|
|
250
|
+
generator builds the lattice from the column positions alone, and reproduces this
|
|
251
|
+
example's hand-numbered 25 vertex pairs, 32 triangles and hull walk exactly. That
|
|
252
|
+
is the prerequisite: a turn needs interior vertices to move, and
|
|
281
253
|
§4.3's contour has none.
|
|
282
254
|
|
|
283
255
|
⭐ **And a depth map is the number above becoming a surface.** A greyscale sheet in the
|
|
@@ -295,7 +267,7 @@ PIXEL by its own depth; a mesh displaces vertices and interpolates across
|
|
|
295
267
|
triangles. On a dome (a ramp would prove nothing — linear interpolation is exact
|
|
296
268
|
on a linear field) at 18°, the two evaluations converge as the lattice refines:
|
|
297
269
|
|
|
298
|
-
**No run reproduces this:** the 2026-09-05 density study's figures, printed by `bench/studies/2026-09-05-density/tools/densprobe.ts` and kept in its `evidence/`; no command this page states re-takes them
|
|
270
|
+
**No run reproduces this:** the 2026-09-05 density study's figures, printed by `bench/studies/2026-09-05-density/tools/densprobe.ts` and kept in its `evidence/`; no command this page states re-takes them
|
|
299
271
|
|
|
300
272
|
| lattice | 3×3 | 5×5 | 9×9 | 17×17 | 33×33 |
|
|
301
273
|
| --- | --- | --- | --- | --- | --- |
|
|
@@ -306,7 +278,7 @@ on a linear field) at 18°, the two evaluations converge as the lattice refines:
|
|
|
306
278
|
does not converge — it settles at ~3.4px however dense it gets — and at 3×3 it
|
|
307
279
|
reads *better* than the right one. So one measurement at one density cannot tell
|
|
308
280
|
the two models apart, and would have picked the wrong one. The claim is the
|
|
309
|
-
convergence, never a single number. (
|
|
281
|
+
convergence, never a single number. (The worst
|
|
310
282
|
case falls more slowly than the mean and is expected to, because the dome's rim
|
|
311
283
|
has an unbounded depth gradient.)
|
|
312
284
|
|
|
@@ -323,7 +295,7 @@ is free, get it wrong and nothing complains. What the map removes is the
|
|
|
323
295
|
|
|
324
296
|
### 2.2 The angle belongs to the map, not to the mesh
|
|
325
297
|
|
|
326
|
-
§2.1 leaves an open question and it
|
|
298
|
+
§2.1 leaves an open question, and it is measured here. §4.2 finds that
|
|
327
299
|
refining the lattice makes the fold **worse**, and read that as the cylinder's
|
|
328
300
|
error surfacing — so per-vertex depth ought to have bought the angle back. ⛔ **It
|
|
329
301
|
does not, and it never could have.**
|
|
@@ -373,7 +345,7 @@ are two different quantities and both are true — §2.1 measures the first, `A3
|
|
|
373
345
|
refuses the second. What is new here is that the second is a fact about the
|
|
374
346
|
sheet, and can be fixed there.
|
|
375
347
|
|
|
376
|
-
⭐ **And you
|
|
348
|
+
⭐ **And you do not have to find the ceiling by building into it.** `build`
|
|
377
349
|
and `explain` print it for any mesh with a depth map — per axis, per direction,
|
|
378
350
|
naming the triangle that goes first — from `tan t = A₀/A_axis` on the mesh's own
|
|
379
351
|
geometry ([AUTHORING §3.4](AUTHORING.md)):
|
|
@@ -426,8 +398,7 @@ share pins at **0.92–0.99** where rigc's own gallery reads 0.112 and 0.468.
|
|
|
426
398
|
slope. That is the input this whole section is about.
|
|
427
399
|
|
|
428
400
|
⛔ rigc will not decide that your sheet is the wrong kind of thing. It has every
|
|
429
|
-
authority to say what it measured, and the step share is that
|
|
430
|
-
([#448](https://github.com/firejune/rigc/issues/448)).
|
|
401
|
+
authority to say what it measured, and the step share is that.
|
|
431
402
|
|
|
432
403
|
📐 Method, harness and the full ladders live in the repository rather than in
|
|
433
404
|
this package, as
|
|
@@ -438,7 +409,7 @@ silhouette so it samples **2 %** of the depth range, and its ear-clipped interio
|
|
|
438
409
|
holds triangles three orders of magnitude apart in area, the smallest of which
|
|
439
410
|
reverse under a fraction of a pixel.
|
|
440
411
|
|
|
441
|
-
**No run reproduces this:** the ladder in the paragraph below is the 2026-09-05 noise study's, taken with `bench/studies/2026-09-05-noise/tools/noiseprobe.ts
|
|
412
|
+
**No run reproduces this:** the ladder in the paragraph below is the 2026-09-05 noise study's, taken with `bench/studies/2026-09-05-noise/tools/noiseprobe.ts`, one evidence file per experiment; no command this page states re-takes it
|
|
442
413
|
|
|
443
414
|
🚨 **The sheet's grain is a slope too, and the ceiling reads it.** Because
|
|
444
415
|
`max|dz/du|` is a maximum over sampled gradients, there is no averaging anywhere
|
|
@@ -456,9 +427,7 @@ ladders:
|
|
|
456
427
|
[`bench/studies/2026-09-05-noise`](https://github.com/firejune/rigc/tree/main/bench/studies/2026-09-05-noise).
|
|
457
428
|
|
|
458
429
|
⭐ **And you do not have to guess which of the three you are looking at.** The
|
|
459
|
-
lines under the ceiling say it
|
|
460
|
-
([#412](https://github.com/firejune/rigc/issues/412),
|
|
461
|
-
[#448](https://github.com/firejune/rigc/issues/448)): the **1st percentile over
|
|
430
|
+
lines under the ceiling say it: the **1st percentile over
|
|
462
431
|
the ceiling** is near 1 when a band of the mesh reaches the limit together and
|
|
463
432
|
near 10 when one triangle does, which is a texel — 1.003 against 10.652 for the
|
|
464
433
|
two sheets above. The **depth step across the triangle that folds first**, in
|
|
@@ -514,7 +483,7 @@ rigging one**, and given §9 that is the whole argument for it.
|
|
|
514
483
|
|
|
515
484
|
### 3.1 ⭐ And now the spec holds this split, not its results
|
|
516
485
|
|
|
517
|
-
|
|
486
|
+
The pattern above is a
|
|
518
487
|
named construct rather than a page of advice: **one group track whose key states
|
|
519
488
|
the model, with a depth per member** (AUTHORING §4.5.1). The worked example's six
|
|
520
489
|
residuals and six scale factors are two tracks:
|
|
@@ -533,15 +502,14 @@ residuals and six scale factors are two tracks:
|
|
|
533
502
|
`faceshift` bone already applies, so what each member keys is exactly the residual
|
|
534
503
|
this section derives. Drop it — write `carried: 0` or leave it out — and the same
|
|
535
504
|
kind emits the **full** `dx` instead, which is what the parts hanging off `head`
|
|
536
|
-
rather than off `faceshift` need. ⇒ **The split the
|
|
537
|
-
about is now the one parameter, and the seam falls where the parent chain already
|
|
505
|
+
rather than off `faceshift` need. ⇒ **The split is the one parameter, and the seam falls where the parent chain already
|
|
538
506
|
put it** (AUTHORING §4.5.1 refuses a model over members under different parents,
|
|
539
507
|
for exactly that reason).
|
|
540
508
|
|
|
541
509
|
⭐ **`explain` then prints the column of six, which is what the argument above
|
|
542
510
|
asked for.** The `MEMBER` block (AUTHORING §4.5.2) is a row per member — the
|
|
543
511
|
emitted value, the `x` it read off the rig, and the depth the spec stated — so the
|
|
544
|
-
nose diagnostic below is
|
|
512
|
+
nose diagnostic below is a line you read rather than arithmetic you redo:
|
|
545
513
|
|
|
546
514
|
**No run reproduces this:** abridged — the five derivation lines the run prints between this record's head and its rows are cut; AUTHORING §4.5.2 quotes them
|
|
547
515
|
```
|
|
@@ -735,22 +703,21 @@ that has to go past it fades the far cheek or ear out — `rgba` to alpha 0 —
|
|
|
735
703
|
swaps the attachment away, and another part takes over. `A39` measures that: a
|
|
736
704
|
deform key whose slot draws **no pixels at that key's own time** is passed over by
|
|
737
705
|
name rather than refused, with the reason on the stats line and beside the key's
|
|
738
|
-
own figures in the `DEFORM` block
|
|
739
|
-
([#401](https://github.com/firejune/rigc/issues/401)). Two things it is not — the
|
|
706
|
+
own figures in the `DEFORM` block. Two things it is not — the
|
|
740
707
|
bar is alpha **exactly 0**, so a part faded halfway is still refused with the
|
|
741
708
|
alpha in the message; and it is per key and per time, so the same slot folding at
|
|
742
|
-
full alpha anywhere else is refused
|
|
709
|
+
full alpha anywhere else is refused. ⛔ It is also not
|
|
743
710
|
`invariants.deformMayFold`: that field turns the check off for the slot at every
|
|
744
711
|
angle, including the ones where the part is fully visible.
|
|
745
712
|
|
|
746
|
-
🚨 **Fade out *up to* the angle you cannot take, never *at* it — and the gate
|
|
713
|
+
🚨 **Fade out *up to* the angle you cannot take, never *at* it — and the gate
|
|
747
714
|
keeps that rule rather than asking you to.** The runtime interpolates between
|
|
748
715
|
keys, so an alpha-0 key landing exactly on the folding key leaves the frames just
|
|
749
716
|
before it drawn and nearly folded (§9.2 measures it: 8 reversed triangles at
|
|
750
717
|
alpha 0.20). `A39` scans the spans between consecutive keys as well and refuses
|
|
751
718
|
one by name, at a time solved for in closed form and then posed and measured
|
|
752
|
-
(
|
|
753
|
-
practical shape is
|
|
719
|
+
(AUTHORING §4.11.3). ⇒ The
|
|
720
|
+
practical shape is checkable: **key the fade to 0 at or before
|
|
754
721
|
the last angle that gates green, and let the fold happen after it.**
|
|
755
722
|
|
|
756
723
|
📘 **The identity above, used forwards on a `pitch`.**
|
|
@@ -766,19 +733,17 @@ That is this table checked from the other end, on the other axis.
|
|
|
766
733
|
⚠️ **A grid's perimeter is 16 of its 25 vertices, and in row-major order they are
|
|
767
734
|
interleaved with the interior.** Spine's `hull` is the first `hull` vertices of
|
|
768
735
|
the list, in order — the editor draws the outline by joining them in sequence — so
|
|
769
|
-
a row-major grid cannot declare one. And an undeclared hull is not neutral:
|
|
770
|
-
|
|
736
|
+
a row-major grid cannot declare one. And an undeclared hull is not neutral: the
|
|
737
|
+
editor's import repairs a `hull: 0` by making
|
|
771
738
|
**every** vertex a hull vertex in list order, which is a self-intersecting outline
|
|
772
|
-
on the mesh the person refining the draft sees
|
|
773
|
-
([#368](https://github.com/firejune/rigc/issues/368) records the round trip that
|
|
774
|
-
found it). So the list is written the way the editor writes one: **the perimeter
|
|
739
|
+
on the mesh the person refining the draft sees. So the list is written the way the editor writes one: **the perimeter
|
|
775
740
|
first, walked around — top row, right column, bottom row, left column — then the
|
|
776
741
|
interior, row-major.** rigc derives `hull` from the triangles (AUTHORING §3.4) and
|
|
777
742
|
refuses any other order with the walk to renumber along, so getting this wrong
|
|
778
743
|
costs one loop rather than a silent file.
|
|
779
744
|
|
|
780
745
|
**What it costs the reader.** `explain` prints one offset per vertex in list
|
|
781
|
-
order, so the run
|
|
746
|
+
order, so the run does not read as one row of five values repeated down the
|
|
782
747
|
grid: entries 0–15 walk the perimeter and 16–24 are the interior. The column
|
|
783
748
|
table is still what to check it against — a vertex's offset depends on its column
|
|
784
749
|
alone — and the right column's five entries (4–8) carrying one value is the
|
|
@@ -809,9 +774,7 @@ scaleX = cos(α − t) / cos α where α = atan2(x, z)
|
|
|
809
774
|
```
|
|
810
775
|
|
|
811
776
|
The far eye narrows to 89%, the near eye widens to 106% (**derived**: 0.8922 and
|
|
812
|
-
1.0641). Parts on the axis get `cos t = 0.9781
|
|
813
|
-
track — the nose and mouth did, through a `groups` entry, and it was the only
|
|
814
|
-
place in the worked example's turn where two parts could (§7).
|
|
777
|
+
1.0641). Parts on the axis get `cos t = 0.9781`.
|
|
815
778
|
|
|
816
779
|
📘 **How much this is worth depends on the axis, and there is a worked case for
|
|
817
780
|
the other one.** The same closed form on the `pitch` of
|
|
@@ -822,12 +785,12 @@ the **0.892 … 1.064** above — a wider span at the *identical* angle, because
|
|
|
822
785
|
than it is deep. ⇒ **The foreshortening buys more on a nod than on a turn**, and
|
|
823
786
|
that is arithmetic rather than a judgement about the art.
|
|
824
787
|
|
|
825
|
-
📌 **
|
|
788
|
+
📌 **The on-axis pair needs no `groups` entry.** `scalex` is the
|
|
826
789
|
foreshortening projection of the same `derive` kind §3.1 uses (AUTHORING §4.5.1),
|
|
827
790
|
so all six features are one track and the on-axis pair's shared value **falls out
|
|
828
791
|
of the arithmetic** — `α = atan2(0, z)` is 0, so `cos(α − t)/cos α` is `cos t`.
|
|
829
|
-
A coincidence between two members
|
|
830
|
-
|
|
792
|
+
A coincidence between two members is not something an author has to notice and
|
|
793
|
+
spend a group on.
|
|
831
794
|
|
|
832
795
|
### 🚨 The iris does not foreshorten, and this is the finding
|
|
833
796
|
|
|
@@ -849,14 +812,14 @@ look_r: [iris_r, spark_r] scalex = 1 / 1.0641 = 0.9398
|
|
|
849
812
|
```
|
|
850
813
|
|
|
851
814
|
⭐ **These two stay a shared value on a group, and they are the case where the
|
|
852
|
-
per-member construct is the wrong tool** — stated here because "
|
|
853
|
-
|
|
815
|
+
per-member construct is the wrong tool** — stated here because "there is a
|
|
816
|
+
model" is exactly the reasoning that would spoil them. A counter-scale belongs to
|
|
854
817
|
the **socket**, not to the part: `spark_l` sits at local `x = −11` and takes the
|
|
855
818
|
same `1.1208` as `iris_l` at `0`, because what is being cancelled is the socket's
|
|
856
819
|
foreshortening and not the highlight's own. ⇒ **The value is precisely NOT a
|
|
857
820
|
function of the member's position**, so a `groups` entry with one number is the
|
|
858
821
|
true statement and a `derive` over `iris_l`/`spark_l` would be a fiction that
|
|
859
|
-
happened to use the
|
|
822
|
+
happened to use the `derive` field.
|
|
860
823
|
|
|
861
824
|
⭐ **Their positions still ride the socket, and that is the part that makes it
|
|
862
825
|
correct rather than a hack.** A bone's scale moves its children's local
|
|
@@ -864,7 +827,7 @@ translation, so the highlight at local `(−11, +11)` under the far socket's 0.8
|
|
|
864
827
|
lands at `−9.81` — it slides 1.19 units inward, toward the surface it reflects
|
|
865
828
|
off (**derived**). Only the *shape* is held.
|
|
866
829
|
|
|
867
|
-
**No run reproduces this:** a person's judgement over seven renders, kept in the `gallery/portrait` record
|
|
830
|
+
**No run reproduces this:** a person's judgement over seven renders, kept in the `gallery/portrait` record (`FINDINGS.md`, *The measured sweep*); no instrument in this repository grades a turn, so nothing re-takes it and nothing can
|
|
868
831
|
|
|
869
832
|
📊 **Measured effect on the cliff, by the worked example's own sweep — a
|
|
870
833
|
looked-at judgement over seven renders, not a computed figure:** without the
|
|
@@ -909,28 +872,18 @@ are all timing:
|
|
|
909
872
|
blink key sits at `0.399999` (AUTHORING §4.5). **A continuous channel does not
|
|
910
873
|
care where the samples land.**
|
|
911
874
|
|
|
912
|
-
⚠️ **
|
|
875
|
+
⚠️ **One constraint on the lid's own drawing, and it is an art decision the rig
|
|
913
876
|
cannot express.**
|
|
914
877
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
2. ~~**Run its sides flush to the window edge.**~~ ✅ **No longer needed.** This
|
|
925
|
-
was a workaround for [#292](https://github.com/firejune/rigc/issues/292):
|
|
926
|
-
`rigc render`'s bilinear filter sampled straight alpha, so **every
|
|
927
|
-
atlas-region edge drew a one-pixel dark rim** over what was behind it, and
|
|
928
|
-
running the art flush to its window gave the sampler nothing dark to reach
|
|
929
|
-
into. The sampler now interpolates premultiplied and a transparent texel gets
|
|
930
|
-
no vote in the colour, so **a lid plate may have whatever margin its drawing
|
|
931
|
-
wants.** §9.1 keeps the record of how the rim was found, because the lesson
|
|
932
|
-
there — that scene work exercises a renderer where game-part work does not —
|
|
933
|
-
outlives this particular defect.
|
|
878
|
+
**Fade its top edge out, and size the fade in pixels.** A flat plate of skin
|
|
879
|
+
translating down a forehead has a visible edge; fading its top 30 pixels
|
|
880
|
+
removes it. ⛔ **Do not write that fade proportionally.** In the worked example
|
|
881
|
+
it was first authored as `offset 0.34` in `objectBoundingBox` units — 34% of
|
|
882
|
+
*whatever height the plate happened to be* — and when the plate grew from 88 to
|
|
883
|
+
112 to cover the eye, the faded band grew with it and stopped covering the top
|
|
884
|
+
of the shut eye. In `userSpaceOnUse` with `y2="30"` the height becomes a free
|
|
885
|
+
variable and the coverage becomes a stated one: `106 − 30 = 76` opaque pixels
|
|
886
|
+
above the lash, against a 70-unit eye.
|
|
934
887
|
|
|
935
888
|
📌 **Blink both lids on one `groups` track.** An L/R offset of one frame was
|
|
936
889
|
tried in the worked example and rejected: at 25 fps it does not read as a soft
|
|
@@ -1004,20 +957,14 @@ face-specific part is which bone leads. The worked example's ordering
|
|
|
1004
957
|
| `headroll` translatex + rotate | **0.40 s** | the head follows **+12% of the duration after the eyes**. A rigid 3.4-unit slide and a −1.2° roll |
|
|
1005
958
|
| `lock_l` / `lock_r` / `ahoge` rotate | 0.72 / 0.76 / 0.82 s | **+21% / +24% / +28% after the head**, each with one overshoot crossing of opposite sign |
|
|
1006
959
|
|
|
1007
|
-
🩹 **The head's follow there is a rigid slide plus a roll, not a small yaw
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
third pair of `deform` keys — 80 more hand-written numbers — for a motion a
|
|
1011
|
-
viewer reads as *"her head moved a little"*. ✅ **§1.1 took that price away**: it
|
|
1012
|
-
is one `transform` key with a smaller `degrees`, the same edit §8's seven-angle
|
|
1013
|
-
sweep is now made of. ⇒ What is left to weigh is not the typing, it is §7's
|
|
960
|
+
🩹 **The head's follow there is a rigid slide plus a roll, not a small yaw.** A
|
|
961
|
+
head following a gaze really does yaw a few degrees, and that is one `transform`
|
|
962
|
+
key with a smaller `degrees` (§1.1). ⇒ What there is to weigh is §7's
|
|
1014
963
|
table — a yaw on the `gaze` channel is a second animation keying the head mesh's
|
|
1015
964
|
deform, which `turn` already owns, and that collision is the thing the format
|
|
1016
965
|
cannot express. Same trade in the turn's anticipation: MOTION §3.6 asks
|
|
1017
966
|
for a counter-move, and the worked example's is a **−0.9° counter-roll on the
|
|
1018
|
-
neck bone rather than a counter-yaw**,
|
|
1019
|
-
the fringe it cost then and at one more `transform` key now. ⚠️ Neither has been
|
|
1020
|
-
re-authored, so what this page measures is still the motion the example ships.
|
|
967
|
+
neck bone rather than a counter-yaw**, which would be one more `transform` key.
|
|
1021
968
|
|
|
1022
969
|
⭐ **A roll channel is worth having for a second reason: it is where a turn's arc
|
|
1023
970
|
comes from.** A yaw shift is a straight horizontal line and `translatex` draws
|
|
@@ -1037,7 +984,7 @@ expensive thing to change.
|
|
|
1037
984
|
rendered and looked at. The geometry columns are **derived**; the last column is
|
|
1038
985
|
the record's looked-at judgement:
|
|
1039
986
|
|
|
1040
|
-
**No run reproduces this:** the geometry columns are §1's line evaluated by hand and the last column is a person's, from the sweep in the
|
|
987
|
+
**No run reproduces this:** the geometry columns are §1's line evaluated by hand and the last column is a person's, from the sweep in the `gallery/portrait` record; each of the seven builds is `"degrees": <n>` and a rebuild, but no command this page states takes them
|
|
1041
988
|
|
|
1042
989
|
| yaw | centre shift | far band 42 → | ratio | 9-unit ink → | reads as a turn? |
|
|
1043
990
|
| --- | --- | --- | --- | --- | --- |
|
|
@@ -1094,38 +1041,28 @@ not a format problem, it is a parts-and-labour problem.
|
|
|
1094
1041
|
| `gaze` | 1.5 s | 8 | 32 | 0 | 0 | 0 |
|
|
1095
1042
|
| **`turn`** | 2.2 s | **8** | **33** | 2 | 8 | **0** |
|
|
1096
1043
|
|
|
1097
|
-
⇒ **`idle` and `gaze` cost what an ordinary MOTION.md shot costs, and the turn
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
figures barely moved. What they ARE changed completely.** The 20-track turn stated
|
|
1113
|
-
**32 residuals and scale factors** across its held keys; the 8-track one states
|
|
1114
|
-
**34 depths** — of which **11 are distinct**, the rest being the same table
|
|
1115
|
-
repeated on the second held key and on the `scalex` track. ⇒ The saving is not
|
|
1116
|
-
arithmetic, it is **auditability**: a residual of `1.14` is a number a reader can
|
|
1117
|
-
only take on trust, and `brow_r at depth 158` is a claim they can argue with. §3
|
|
1118
|
-
is why that is the whole point, and §2 is why the depths had nowhere else to live.
|
|
1044
|
+
⇒ **`idle` and `gaze` cost what an ordinary MOTION.md shot costs, and the turn
|
|
1045
|
+
has no transcription in it.** The deform is four `transform` keys (§1.1) and the
|
|
1046
|
+
compiler writes the run: **five distinct values** per head key (one per column,
|
|
1047
|
+
repeated down five rows), with **25 of its 50 slots structurally `0`** because a
|
|
1048
|
+
yaw has no vertical component. The **tracks** column is 8 because the features are
|
|
1049
|
+
two group tracks whose keys state a model (§3, AUTHORING §4.5.1) and the four hair
|
|
1050
|
+
parts are one.
|
|
1051
|
+
|
|
1052
|
+
🚨 **And here is the number that matters more than either count: what the
|
|
1053
|
+
hand-written figures ARE.** The turn states **34 depths** — of which **11 are
|
|
1054
|
+
distinct**, the rest being the same table repeated on the second held key and on
|
|
1055
|
+
the `scalex` track. ⇒ The point is **auditability**: a residual of `1.14` is a
|
|
1056
|
+
number a reader can only take on trust, and `brow_r at depth 158` is a claim they
|
|
1057
|
+
can argue with. §3 is why that is the whole point, and §2 is why the depths had
|
|
1058
|
+
nowhere else to live.
|
|
1119
1059
|
|
|
1120
1060
|
⚠️ **A plain `groups` entry still buys almost nothing on a face, and that is
|
|
1121
1061
|
structural rather than an oversight.** Keying several bones **identically** is
|
|
1122
1062
|
right for a wheel pair, and **every part needing a different number is what
|
|
1123
|
-
parallax means.**
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
authoring concept**: the on-axis pair's shared `cos t` now falls out of the same
|
|
1127
|
-
closed form as everybody else's value, so `axis` is gone from the spec while
|
|
1128
|
-
`look_l`/`look_r` stay — because those two really are one shared number (§5).
|
|
1063
|
+
parallax means.** The on-axis pair's shared `cos t` falls out of the same closed
|
|
1064
|
+
form as everybody else's value, so it needs no group, while `look_l`/`look_r` stay
|
|
1065
|
+
one — because those two really are one shared number (§5).
|
|
1129
1066
|
|
|
1130
1067
|
### The turn as a value rather than a time
|
|
1131
1068
|
|
|
@@ -1225,15 +1162,15 @@ breaks the moment the two share a target — in the worked example both `turn` a
|
|
|
1225
1162
|
`tilt` key `headroll`. §7's paragraph on sliders is the mechanism and
|
|
1226
1163
|
`A40_SLIDERS_COMPOSE_ON_A_SHARED_TARGET` is the refusal.
|
|
1227
1164
|
|
|
1228
|
-
✅ **And the space between the two dials is measured rather than inferred
|
|
1229
|
-
|
|
1165
|
+
✅ **And the space between the two dials is measured rather than inferred.**
|
|
1166
|
+
Two additive sliders posed
|
|
1230
1167
|
at a grid of *both* values — and over a rotation and a translation, so the claim
|
|
1231
1168
|
is not one property's — are the closed-form sum at every cell of it, to float64:
|
|
1232
1169
|
each slider maps its own reading to a time by §3.5.2's rule, its animation is read
|
|
1233
1170
|
there, and the two contributions add. ⭐ That is a property of the **interior**
|
|
1234
|
-
and not of the corners, which is the whole reason it needed a grid: `
|
|
1235
|
-
|
|
1236
|
-
|
|
1171
|
+
and not of the corners, which is the whole reason it needed a grid: with an `ease` on one of the two
|
|
1172
|
+
animations, every corner of the space still reads as correct while most of the
|
|
1173
|
+
inside has moved. ⇒ **a
|
|
1237
1174
|
lookup table wants linear keys for a second reason** — not only that the face
|
|
1238
1175
|
would drift while the value sat still, but that a curve is invisible to any check
|
|
1239
1176
|
that reads an axis at its ends.
|
|
@@ -1263,16 +1200,13 @@ and the yaw dial also fades it, one of the two has to stop: key that property
|
|
|
1263
1200
|
from **one** slider, or move both edits into the animation a single slider
|
|
1264
1201
|
applies. `A40` refuses the rest by name, and AUTHORING §3.5.2 is the mechanism.
|
|
1265
1202
|
|
|
1266
|
-
✅ **And which of the two a timeline is, the gate
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
accumulated. The same measurement retired a refusal no pose could have told
|
|
1274
|
-
apart: two dials whose animations both fire **events** were refused, and a slider
|
|
1275
|
-
fires no event at all — it applies its animation with `firedEvents` null.
|
|
1203
|
+
✅ **And which of the two a timeline is, the gate poses rather than asks.**
|
|
1204
|
+
`A40` applies the shared timeline twice with `add` set and reads whether the second
|
|
1205
|
+
application accumulated, rather than reading `Timeline.additive`, the runtime's own
|
|
1206
|
+
declaration, which two classes state falsely about themselves — a path
|
|
1207
|
+
constraint's `mix` and a slider's `time`, both in the composing list above. Two
|
|
1208
|
+
dials whose animations both fire **events** are not refused either: a slider fires
|
|
1209
|
+
no event at all — it applies its animation with `firedEvents` null.
|
|
1276
1210
|
|
|
1277
1211
|
⭐ **Three dials are the same sum as two — as long as every one of them is
|
|
1278
1212
|
additive.** The case worth knowing is a non-additive dial in the *middle* of
|
|
@@ -1318,13 +1252,10 @@ on this page that multiplies rather than adds. ⚠️ **It only works downward t
|
|
|
1318
1252
|
the `constraints` array.** A slider reads its own authority when its turn comes
|
|
1319
1253
|
and the array is the update order, so a dial that keys the `mix` of a slider
|
|
1320
1254
|
*earlier* than itself writes a number that slider has already read past: the
|
|
1321
|
-
driven axis is dead at every position, every frame. ✅ **The gate names that
|
|
1322
|
-
|
|
1323
|
-
sliders, the property and both array indices, and says which way to move them
|
|
1324
|
-
|
|
1325
|
-
for a reason worth knowing: a slider whose `mix` is keyed at all leaves `A40`'s
|
|
1326
|
-
comparison, so nothing in the tool was looking at that pair. ⇒ put the driving
|
|
1327
|
-
slider **first**, which is what the refusal tells you to do.
|
|
1255
|
+
driven axis is dead at every position, every frame. ✅ **The gate names that
|
|
1256
|
+
pair** — `A42_DRIVEN_CONSTRAINTS_UPDATE_AFTER_THEIR_DRIVER` refuses it with both
|
|
1257
|
+
sliders, the property and both array indices, and says which way to move them.
|
|
1258
|
+
⇒ put the driving slider **first**, which is what the refusal tells you to do.
|
|
1328
1259
|
|
|
1329
1260
|
🚨 **And a dial cannot turn itself on.** `Slider.update` reads its own `mix` as
|
|
1330
1261
|
the alpha it applies the animation with, before that animation runs, so a slider
|
|
@@ -1343,8 +1274,7 @@ it when its own turn comes, and that turn is its place in `constraints`. A
|
|
|
1343
1274
|
number in that constraint's pose and moves nothing at all: [measured] the bone a
|
|
1344
1275
|
physics constraint drives travels `0.000e+0` across the dial with the constraint
|
|
1345
1276
|
declared first and `4.256e+2` with it declared last, and a path constraint's
|
|
1346
|
-
rider `0.000e+0` against `1.620e+2`
|
|
1347
|
-
([#665](https://github.com/firejune/rigc/issues/665)). ✅ `A42` names those pairs
|
|
1277
|
+
rider `0.000e+0` against `1.620e+2`. ✅ `A42` names those pairs
|
|
1348
1278
|
too, with the constraint's kind and both array indices. ⇒ **every constraint a
|
|
1349
1279
|
dial drives goes after that dial in `constraints`** — which, for a face, means
|
|
1350
1280
|
the dials come first and the jiggles, paths and aim constraints they scale come
|
|
@@ -1356,8 +1286,7 @@ its SKIP rather than asking you to move anything.
|
|
|
1356
1286
|
🔸 **The bone-less slider is the same story one field over.** A slider with no
|
|
1357
1287
|
`bone` takes its time from `slider.<name>.time`, which any animation can key — and
|
|
1358
1288
|
two dials keying it *add*, so a time-driven axis composes like everything else
|
|
1359
|
-
here, and
|
|
1360
|
-
agrees: it used to refuse exactly this rig. The same array rule applies, for the
|
|
1289
|
+
here, and the gate agrees. The same array rule applies, for the
|
|
1361
1290
|
same reason — and `A42` refuses it there too, naming `time` instead of `mix`.
|
|
1362
1291
|
⚠️ Two things the bone
|
|
1363
1292
|
form does and this one does not: there is no `Math.max(0, time)` and no wrap, so a
|
|
@@ -1377,9 +1306,8 @@ about it because the pair genuinely never meets.
|
|
|
1377
1306
|
axis: the arithmetic, the flag, and the non-additive-in-the-middle case all read
|
|
1378
1307
|
exactly as they do above. Write `"additive": true` on all of them.
|
|
1379
1308
|
|
|
1380
|
-
✅ **The editor half, measured.**
|
|
1381
|
-
|
|
1382
|
-
version 4.3.26) against a 4.3.13 build of
|
|
1309
|
+
✅ **The editor half, measured.** The round trip was taken with
|
|
1310
|
+
`tools/editor_roundtrip.ts` on a licensed editor (data version 4.3.26) against a 4.3.13 build of
|
|
1383
1311
|
[`gallery/look`](https://github.com/firejune/rigc/tree/main/gallery/look) — this
|
|
1384
1312
|
subsection's worked case, not the `gallery/portrait` this page names at the top,
|
|
1385
1313
|
which declares no constraints at all and so can carry no slider. What it found:
|
|
@@ -1389,39 +1317,32 @@ which declares no constraints at all and so can carry no slider. What it found:
|
|
|
1389
1317
|
field, and the two keep their places in the `constraints` array. `mix: 1` and
|
|
1390
1318
|
`to: 0` are dropped, and those are the format's own defaults (`SkeletonJson`
|
|
1391
1319
|
reads `mix` as 1 and `to` as 0 when absent) — an elision, not a loss.
|
|
1392
|
-
- ⚠️ **The animation each slider *names*
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
`yaw -> "
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
the round trip below. On the same rig through the same editor that
|
|
1402
|
-
restored `yaw -> "turn"` and took the re-rendered mean absolute error from
|
|
1403
|
-
10.4655 / 8.4961 / 8.7140 (`sweep` / `tilt` / `turn`) to
|
|
1404
|
-
0.3035 / 0.0769 / 0.0588, worst drift 16.535 px to 3.947 px.
|
|
1320
|
+
- ⚠️ **The animation each slider *names* comes back because rigc emits
|
|
1321
|
+
animations in the editor's own order** — natural and case-insensitive. The
|
|
1322
|
+
editor re-sorts the `animations` object and a slider's animation is an ordinal
|
|
1323
|
+
in the format, so out of that order `yaw -> "turn"` returns as
|
|
1324
|
+
`yaw -> "sweep"` — the first animation of the sorted list. In order, on the
|
|
1325
|
+
same rig through the same editor, `yaw -> "turn"` comes back and the
|
|
1326
|
+
re-rendered mean absolute error is 0.3035 / 0.0769 / 0.0588
|
|
1327
|
+
(`sweep` / `tilt` / `turn`) against 10.4655 / 8.4961 / 8.7140 out of order,
|
|
1328
|
+
worst drift 3.947 px against 16.535 px.
|
|
1405
1329
|
- 🚨 **The physics constraint on the cowlick comes back driving nothing.**
|
|
1406
1330
|
`rotate: 1` is absent from the export, and an absent `rotate` parses as **0**
|
|
1407
1331
|
(`SkeletonJson`), so the returned file states *drives nothing* rather than
|
|
1408
1332
|
omitting a default — which is why `A23_PHYSICS_CONSTRAINT_EFFECTIVE` refuses it
|
|
1409
|
-
by name. Independent of the ordering
|
|
1410
|
-
[#536](https://github.com/firejune/rigc/issues/536).
|
|
1333
|
+
by name. Independent of the ordering.
|
|
1411
1334
|
|
|
1412
|
-
✅ **Why, measured
|
|
1335
|
+
✅ **Why, measured.** It is not elision and not a defect in one field:
|
|
1413
1336
|
the editor's physics model holds `x` and `y` and nothing else, with no limit on
|
|
1414
1337
|
how many at once. Three rigs, twelve constraints, predictions written before the
|
|
1415
1338
|
round trip — a lone `y` came back, `x` and `y` together came back, and a lone
|
|
1416
1339
|
`rotate`, a lone `scaleX` and a lone `shearX` each came back as **no components
|
|
1417
1340
|
at all**, with every constraint's fixed-point `strength` returning exactly so a
|
|
1418
|
-
silent harness failure could not read as a finding
|
|
1419
|
-
([#540](https://github.com/firejune/rigc/issues/540)). ⇒ **A rotation-driven
|
|
1341
|
+
silent harness failure could not read as a finding. ⇒ **A rotation-driven
|
|
1420
1342
|
jiggle does not survive the editor, and no `scaleY` mode substitutes for it.**
|
|
1421
1343
|
|
|
1422
|
-
✅ **And the locus is measured: the loss is at EXPORT** —
|
|
1423
|
-
|
|
1424
|
-
project format. `gallery/look`'s build and three variants of its
|
|
1344
|
+
✅ **And the locus is measured: the loss is at EXPORT** — against Spine
|
|
1345
|
+
4.3.26 and without decoding the project format. `gallery/look`'s build and three variants of its
|
|
1425
1346
|
`skeleton.json` were each imported with the documented CLI, the project files
|
|
1426
1347
|
inflated, and compared byte by byte. **Two imports of the same file differ
|
|
1427
1348
|
only at bytes 13–28** — a timestamp or a hash — so that is the noise floor,
|
|
@@ -1435,14 +1356,14 @@ which declares no constraints at all and so can carry no slider. What it found:
|
|
|
1435
1356
|
the exporter wrote nothing for it. It is the editor's **writer**, not its
|
|
1436
1357
|
reader, and not rigc's emitter.
|
|
1437
1358
|
|
|
1438
|
-
✅ **And the gate
|
|
1359
|
+
✅ **And the gate says so before the trip, not after.** A face rig that is
|
|
1439
1360
|
authored to come back out of the editor declares
|
|
1440
1361
|
`"invariants": { "editorRoundTrip": true }` (AUTHORING §3.7) and
|
|
1441
1362
|
`A41_PHYSICS_SURVIVES_EDITOR_ROUND_TRIP` refuses the constraint by name at build
|
|
1442
1363
|
time, with the fix in the message: drive it in `x`/`y`, or drop the declaration.
|
|
1443
1364
|
⚠️ A rig that declares nothing is **not** silent either — A41 SKIPs and the skip
|
|
1444
1365
|
names the constraint and the component, which is the whole reason the rule is
|
|
1445
|
-
opt-in rather than default-off. rigc's own output
|
|
1366
|
+
opt-in rather than default-off. rigc's own output is not wrong here: a
|
|
1446
1367
|
rotation jiggle is valid Spine 4.3 that every runtime plays, and refusing it for
|
|
1447
1368
|
everybody would be refusing correct data on behalf of one consumer. ⇒ A23 and
|
|
1448
1369
|
A41 are the same loss from opposite sides of the trip: A41 fires on what goes
|
|
@@ -1452,35 +1373,20 @@ which declares no constraints at all and so can carry no slider. What it found:
|
|
|
1452
1373
|
the clean one included. Visually small once the ordering is fixed — but it is
|
|
1453
1374
|
98% of the keys, and *small* is not *explained*. ⚠️ **[measured] by
|
|
1454
1375
|
`tools/editor_roundtrip.ts` on the trips this subsection records, and no
|
|
1455
|
-
command this page states re-takes it** — the
|
|
1456
|
-
(#536's measurement above is the tenth), so read the figure as those runs' and
|
|
1376
|
+
command this page states re-takes it** — so read the figure as those runs' and
|
|
1457
1377
|
not as a property the gate holds.
|
|
1458
1378
|
|
|
1459
|
-
✅ **
|
|
1460
|
-
measured, and both came back safe** — [#544](https://github.com/firejune/rigc/issues/544)
|
|
1461
|
-
is the card for having left the sentence standing:
|
|
1379
|
+
✅ **Two more things are measured, and both came back safe:**
|
|
1462
1380
|
|
|
1463
1381
|
- **More than one event is safe.** The editor re-keys `events` the way it re-keys
|
|
1464
1382
|
`animations` — `zebra, mike, alpha` came back `alpha, mike, zebra` — but every
|
|
1465
|
-
firing resolved **by name**, `0.3 -> mike` and `0.6 -> alpha`, payloads intact
|
|
1466
|
-
([#539](https://github.com/firejune/rigc/issues/539)). The ordinal shape does
|
|
1383
|
+
firing resolved **by name**, `0.3 -> mike` and `0.6 -> alpha`, payloads intact. The ordinal shape does
|
|
1467
1384
|
*not* bite here, and rigc emits events in the order you declare them.
|
|
1468
|
-
- **More than one skin imports
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
`default/patch`, `alpha/patch`, `mike/patch`, `zulu/patch` as the attachment
|
|
1474
|
-
names. ⚠️ **The editor was never silent**: it named the section, the attachment
|
|
1475
|
-
and the rule, and `tools/editor_roundtrip.ts` had discarded its stdout and
|
|
1476
|
-
stderr. What changed is [#552](https://github.com/firejune/rigc/issues/552) —
|
|
1477
|
-
the composed `<skin>/<placeholder>` name, with `default` pinned first; the
|
|
1478
|
-
composition was retired by [#796](https://github.com/firejune/rigc/issues/796),
|
|
1479
|
-
which measured that it was never what the editor objected to — and what
|
|
1480
|
-
still binds is [#567](https://github.com/firejune/rigc/issues/567): a
|
|
1481
|
-
`CompileError` when the default skin shares a placeholder with a named one. ⇒
|
|
1482
|
-
Skins are not the reason to stay at one, and every figure on this page was
|
|
1483
|
-
still taken on a rig carrying exactly one (AUTHORING §10.1).
|
|
1385
|
+
- **More than one skin imports.** A four-skin rig imports in **both build
|
|
1386
|
+
modes** — default and `--copy-images` — **exit 0, project written**. What binds
|
|
1387
|
+
is a `CompileError` when the default skin shares a placeholder with a named
|
|
1388
|
+
one. ⇒ Skins are not the reason to stay at one, and every figure on this page
|
|
1389
|
+
was taken on a rig carrying exactly one (AUTHORING §10.1).
|
|
1484
1390
|
|
|
1485
1391
|
Every figure above was read back through `spine-core`.
|
|
1486
1392
|
|
|
@@ -1497,16 +1403,14 @@ Every figure above was read back through `spine-core`.
|
|
|
1497
1403
|
| **3–4× on the eyes** | because that is where a reader will look, and a face has no other equivalent |
|
|
1498
1404
|
|
|
1499
1405
|
📊 **Four of the five art defects in the worked example were invisible at contact
|
|
1500
|
-
sheet scale** and all four were found at 1:1 or better: the dark seam
|
|
1501
|
-
([#292](https://github.com/firejune/rigc/issues/292)), the lid's fade letting a
|
|
1406
|
+
sheet scale** and all four were found at 1:1 or better: the dark seam, the lid's fade letting a
|
|
1502
1407
|
shut eye's lash show through as a grey smudge, the iris crossing its own lash at
|
|
1503
1408
|
the gaze extreme, and a forehead highlight turning the lid's soft edge into a
|
|
1504
1409
|
tonal step.
|
|
1505
1410
|
|
|
1506
|
-
⚠️ **A portrait
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
cannot be seen. ⇒ **Scene work exercises a renderer where game-part work does
|
|
1411
|
+
⚠️ **A portrait's plates are *supposed* to overlap invisibly**, and that is
|
|
1412
|
+
where a renderer's edge defect shows: a part that carries an ink outline at its
|
|
1413
|
+
edge hides one, because a dark rim on a dark line cannot be seen. ⇒ **Scene work exercises a renderer where game-part work does
|
|
1510
1414
|
not.** Expect to find renderer defects on your first face, and check a suspicious
|
|
1511
1415
|
edge against a **region build** before reading a single vertex — which is the
|
|
1512
1416
|
next item.
|
|
@@ -1534,9 +1438,8 @@ the wrong part.
|
|
|
1534
1438
|
|
|
1535
1439
|
### 9.2 🚨 The half nothing measures — three builds, one of them refused
|
|
1536
1440
|
|
|
1537
|
-
**The setup geometry is measured; the deformed geometry
|
|
1538
|
-
|
|
1539
|
-
claim as three builds of the same rig, each command runnable verbatim from a
|
|
1441
|
+
**The setup geometry is measured; one half of the deformed geometry is not.**
|
|
1442
|
+
Here is that claim as three builds of the same rig, each command runnable verbatim from a
|
|
1540
1443
|
clean checkout. Start from the good one:
|
|
1541
1444
|
|
|
1542
1445
|
```bash
|
|
@@ -1556,12 +1459,7 @@ bun cli.ts render --candidate gallery/portrait/build --fps 25 --max 640 \
|
|
|
1556
1459
|
.. profile spine-html — every assertion applies
|
|
1557
1460
|
```
|
|
1558
1461
|
|
|
1559
|
-
Green — the profile line above says so in the tool's own words
|
|
1560
|
-
left to the tool: `bun run selftest` prints this build's live assertion and skip
|
|
1561
|
-
counts on its `GALLERY_EXAMPLE_IS_GREEN[portrait/spine-html]`
|
|
1562
|
-
line. One written here would be a figure nothing in the tree compares against a
|
|
1563
|
-
run, sitting inside a fence that reads as a transcript — and rigc prints no tally
|
|
1564
|
-
line, so it never was one.
|
|
1462
|
+
Green — the profile line above says so in the tool's own words.
|
|
1565
1463
|
|
|
1566
1464
|
Now break the projection two ways. Both scripts write a variant motion spec
|
|
1567
1465
|
beside the originals and touch nothing in the repository:
|
|
@@ -1606,57 +1504,22 @@ bun cli.ts build --rig gallery/portrait/rig.json --motion /tmp/folded.motion.jso
|
|
|
1606
1504
|
--out /tmp/folded --profile spine-html
|
|
1607
1505
|
```
|
|
1608
1506
|
|
|
1609
|
-
⚠️ **Both scripts were rewritten on 2026-09-03 and the old ones did nothing.**
|
|
1610
|
-
They keyed off `if (k.vertices)`, which was true of every key until §1.1 put the
|
|
1611
|
-
model on it — after that re-authoring the guard matched nothing, both scripts
|
|
1612
|
-
wrote an unchanged motion spec, and builds (a) and (b) were the good build. That
|
|
1613
|
-
is a doc command silently passing rather than silently failing, which is the
|
|
1614
|
-
worse of the two: build (b) reported `A39 PASS` and the table below said `FAIL`.
|
|
1615
|
-
Both are re-run above.
|
|
1616
|
-
|
|
1617
|
-
⚠️ **And script (a) broke a second time, the same way, on 2026-09-04.** It wrote
|
|
1618
|
-
one row of five shifts and repeated it five times, which was the mesh's own
|
|
1619
|
-
column order while the vertex list was row-major.
|
|
1620
|
-
[#375](https://github.com/firejune/rigc/issues/375) renumbered both gallery
|
|
1621
|
-
grids along their outline walk — perimeter first, then the interior, the order
|
|
1622
|
-
Spine's `hull` needs — and the row went on landing at the same *positions* in a
|
|
1623
|
-
list that no longer meant columns. The build stayed green and stayed wrong, so
|
|
1624
|
-
nothing on the page moved; what it stopped being was **an inverted band**, which
|
|
1625
|
-
is the one thing the table below reads it as. The figures in that table were
|
|
1626
|
-
right the whole time and the command under them had stopped producing
|
|
1627
|
-
them — a stale figure shows up at one site, and a broken command shows up at
|
|
1628
|
-
every figure it feeds, which is how the two are told apart: this one also
|
|
1629
|
-
contradicted §9.3's `check` row, `0.33 / 0.61` against a table saying
|
|
1630
|
-
`0.20 / 0.38`. ⭐ **The repair is the doctrine's own**: the script resolves each
|
|
1631
|
-
shift through the vertex's coordinate instead of its index, so the next
|
|
1632
|
-
renumbering cannot move it. A `vertices` run is positional by format — that is
|
|
1633
|
-
`fromVertex`'s whole job — and a *generator* of one has no reason to be.
|
|
1634
|
-
|
|
1635
|
-
🔒 **And that repair is now measured rather than asserted.** `bun run selftest`
|
|
1636
|
-
runs this script again against a rig whose vertices have been renumbered every
|
|
1637
|
-
way the compiler accepts — the outline rotated along its own walk, the outline
|
|
1638
|
-
reflected, the interior reordered — and requires the run it writes to come back
|
|
1639
|
-
as the same geometry once the renumbering is undone, while the run's own
|
|
1640
|
-
positions have visibly moved. Nothing here declares that property: the subject
|
|
1641
|
-
is any script on any page whose product is a `vertices` run, read off the
|
|
1642
|
-
product.
|
|
1643
|
-
|
|
1644
1507
|
**What comes back from both:**
|
|
1645
1508
|
|
|
1646
1509
|
| | good | (a) one band inverted | (b) mesh folded |
|
|
1647
1510
|
| --- | --- | --- | --- |
|
|
1648
|
-
| `--profile spine-html`, **
|
|
1511
|
+
| `--profile spine-html`, **without `A39`** | green | **green, and the same counts** | **green, and the same counts** |
|
|
1649
1512
|
| `A35_DEFORM_KEYS_FIT_THE_ATTACHMENT` | PASS | **PASS** | **PASS** |
|
|
1650
1513
|
| the `MESH` coverage line | 100.00%, 95.90px past | **byte-identical** | **byte-identical** |
|
|
1651
|
-
|
|
|
1652
|
-
| `--profile spine-html`, **
|
|
1653
|
-
|
|
|
1654
|
-
|
|
|
1514
|
+
| `A39_DEFORM_KEEPS_TRIANGLE_WINDING` | PASS | PASS | **FAIL, both keys, 8 of 32 triangles** |
|
|
1515
|
+
| `--profile spine-html`, **with `A39`** | green | green | **refused, and nothing written** |
|
|
1516
|
+
| the `DEFORM` block, `head` key 1 `area` | x0.637174 … x1.319122 | **x0.765250 … x1.362834** | **x−0.288121 … x1.820211** |
|
|
1517
|
+
| … and its `winding` | 32 of 32 kept | 32 of 32 kept | **24 of 32 kept** |
|
|
1655
1518
|
|
|
1656
1519
|
🚨 **All three were green, and the coverage line is the same string in all three,
|
|
1657
|
-
because it reports the SETUP pose.** The `--profile spine-html` row is
|
|
1658
|
-
|
|
1659
|
-
|
|
1520
|
+
because it reports the SETUP pose.** The `--profile spine-html` row with `A39` is
|
|
1521
|
+
the only verdict that separates them, and the two rows above it measure only the
|
|
1522
|
+
setup geometry: `A35` is silent about build (b). `A35` checks that a deform run *fits* its
|
|
1660
1523
|
attachment — an honest and useful check, and orthogonal to whether the numbers in
|
|
1661
1524
|
it mean anything.
|
|
1662
1525
|
|
|
@@ -1696,19 +1559,9 @@ the two bands the swapped columns bound move at all: the 0 → 120 and 120 → 1
|
|
|
1696
1559
|
bands still read **1.064** and **1.319**, exactly as §4.1 tables them. `authored table` on the key line is the other half of the diagnosis:
|
|
1697
1560
|
the model is gone, so nothing is left to check the ratios against but the ratios.
|
|
1698
1561
|
|
|
1699
|
-
`rigc explain` is the instrument that prints every
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
either `back to the setup pose` or `deform[0..50] 25 pair(s)` — the extent of the
|
|
1703
|
-
run and how many pairs are in it, and not one of the numbers.
|
|
1704
|
-
|
|
1705
|
-
⇒ **`25 pair(s)` was the whole of what `explain` would tell you about a face
|
|
1706
|
-
turn**, against a scalar track two lines up in the same report printing
|
|
1707
|
-
`value=-35.345`. That asymmetry is
|
|
1708
|
-
[#296](https://github.com/firejune/rigc/issues/296), and both of its halves have
|
|
1709
|
-
now closed: §1.1's construct put the model and every offset it produced into the
|
|
1710
|
-
same report (AUTHORING §4.11.1), and the `DEFORM` block put the geometry there
|
|
1711
|
-
(AUTHORING §4.11.2) —
|
|
1562
|
+
`rigc explain` is the instrument that prints every timeline's actual values, and
|
|
1563
|
+
on a deform that is the model and every offset it produced (AUTHORING §4.11.1)
|
|
1564
|
+
and the `DEFORM` block's geometry (AUTHORING §4.11.2) —
|
|
1712
1565
|
|
|
1713
1566
|
```bash
|
|
1714
1567
|
bun cli.ts explain --rig gallery/portrait/rig.json \
|
|
@@ -1724,13 +1577,13 @@ bun cli.ts explain --rig gallery/portrait/rig.json \
|
|
|
1724
1577
|
winding 32 of 32 kept, 0 collapsed
|
|
1725
1578
|
```
|
|
1726
1579
|
|
|
1727
|
-
⇒ **`0.637` is
|
|
1728
|
-
`explain` takes no `--profile` and gates nothing,
|
|
1580
|
+
⇒ **`0.637` is a figure the tool prints.** It is a *report* and not a bar —
|
|
1581
|
+
`explain` takes no `--profile` and gates nothing, because a deliberate
|
|
1729
1582
|
3× stretch is a real thing to author, and the one deformed-geometry fault with no
|
|
1730
1583
|
legitimate counter-example is the fold, which is `A39`'s.
|
|
1731
1584
|
|
|
1732
|
-
|
|
1733
|
-
|
|
1585
|
+
**`A39_DEFORM_KEEPS_TRIANGLE_WINDING` closes the half of that gap the fold
|
|
1586
|
+
lives in** — `--profile spine-html`. Build (b) above is refused
|
|
1734
1587
|
by name, on both its keys, with the triangles listed:
|
|
1735
1588
|
|
|
1736
1589
|
```
|
|
@@ -1741,11 +1594,10 @@ FAIL A39_DEFORM_KEEPS_TRIANGLE_WINDING: animation "turn" deform head/head key 1
|
|
|
1741
1594
|
|
|
1742
1595
|
and builds (a) and the good one both still PASS it, because **an inverted band is
|
|
1743
1596
|
not a fold**: its winding survives. The angle A39 first fires at agrees with
|
|
1744
|
-
§4.2's `tan θ = Δx/Δz` to **0.0001°**, so the formula above is
|
|
1597
|
+
§4.2's `tan θ = Δx/Δz` to **0.0001°**, so the formula above is checkable by
|
|
1745
1598
|
running the gate instead of by rendering seven variants.
|
|
1746
1599
|
|
|
1747
|
-
|
|
1748
|
-
([#401](https://github.com/firejune/rigc/issues/401)).** Build (b) is refused
|
|
1600
|
+
**And one thing it does not refuse.** Build (b) is refused
|
|
1749
1601
|
because the head is *drawn* while it folds. Fade that slot to alpha exactly 0 over
|
|
1750
1602
|
the same keys — §4.2's fourth way out, and what a face past its ceiling actually
|
|
1751
1603
|
does — and the same build is green, with the key still measured and the reason
|
|
@@ -1760,14 +1612,13 @@ printed rather than passed over in silence:
|
|
|
1760
1612
|
```
|
|
1761
1613
|
|
|
1762
1614
|
`A39`'s message says the mesh "draws its texture backwards there", and that
|
|
1763
|
-
sentence is false when the slot draws nothing
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
same fold at full alpha in another animation is still refused, because the
|
|
1615
|
+
sentence is false when the slot draws nothing. The bar is **alpha exactly
|
|
1616
|
+
0**; at 0.5 build (b) is refused, with the alpha in the message. The
|
|
1617
|
+
same fold at full alpha in another animation is refused, because the
|
|
1767
1618
|
measurement is of one key at one time.
|
|
1768
1619
|
|
|
1769
|
-
🚨 **And
|
|
1770
|
-
|
|
1620
|
+
🚨 **And a key is not the whole of it: the geometry between two keys is
|
|
1621
|
+
interpolated.** Put the alpha-0 key exactly on
|
|
1771
1622
|
the 40° key and 8 triangles are already reversed at `t=0.4`, where the slot is
|
|
1772
1623
|
still drawing at **alpha 0.20**:
|
|
1773
1624
|
|
|
@@ -1781,13 +1632,9 @@ still drawing at **alpha 0.20**:
|
|
|
1781
1632
|
|
|
1782
1633
|
📌 The table and the refusal below are on the **turn probe** — this head's own
|
|
1783
1634
|
five columns and 32 triangles on a one-second timeline, which is why the times
|
|
1784
|
-
are not build (b)'s.
|
|
1785
|
-
every run rather than transcribed once.
|
|
1635
|
+
are not build (b)'s.
|
|
1786
1636
|
|
|
1787
|
-
|
|
1788
|
-
([#403](https://github.com/firejune/rigc/issues/403)), and the shape of the fix
|
|
1789
|
-
is the reason it is here rather than in a paragraph of advice.** Every interval
|
|
1790
|
-
between two consecutive deform keys is scanned. A deform interpolated between two
|
|
1637
|
+
**Every interval between two consecutive deform keys is scanned.** A deform interpolated between two
|
|
1791
1638
|
keys travels a **straight line through offset space**, so a triangle's signed
|
|
1792
1639
|
area is a *quadratic in the interpolation fraction* — the fold is a root of it,
|
|
1793
1640
|
solved for rather than searched, with no sample spacing anybody would have to
|
|
@@ -1799,15 +1646,14 @@ and how far along the segment that is, the reversed triangles with their signed
|
|
|
1799
1646
|
`NO KEY LANDS THERE` in those words, and the alpha read at that same instant — so what
|
|
1800
1647
|
it refuses is legible as a frame rather than as a key. AUTHORING §4.11.3 reads it field
|
|
1801
1648
|
by field and [`src/validate.ts`](../src/validate.ts) builds it; no spec this repository
|
|
1802
|
-
ships produces one
|
|
1649
|
+
ships produces one.
|
|
1803
1650
|
|
|
1804
|
-
⇒ The rule
|
|
1805
|
-
take, so that every key past the ceiling is one that draws nothing* — is
|
|
1806
|
-
|
|
1651
|
+
⇒ The rule — *fade out over the run up to the angle you cannot
|
|
1652
|
+
take, so that every key past the ceiling is one that draws nothing* — is a
|
|
1653
|
+
**measurement**: land the alpha-0 key
|
|
1807
1654
|
on the fold and the build is refused, with the frame it is refused for.
|
|
1808
1655
|
|
|
1809
|
-
⚠️ **What that scan
|
|
1810
|
-
than vanished: the closed form holds the BONES still across the span. On an
|
|
1656
|
+
⚠️ **What that scan cannot see**: the closed form holds the BONES still across the span. On an
|
|
1811
1657
|
unweighted attachment that is exact — one matrix multiplies every vertex and its
|
|
1812
1658
|
determinant cancels out of the sign comparison — but on a weighted mesh whose
|
|
1813
1659
|
bones move across the span it is an approximation, and a prediction no
|
|
@@ -1817,7 +1663,7 @@ refused. A fold caused by the bones alone is not this rule's subject at all, and
|
|
|
1817
1663
|
|
|
1818
1664
|
⚠️ **One thing it deliberately does not do.** It is an **archetype** rule, so a
|
|
1819
1665
|
`--profile spine` build reads `PROF` — the premise "a fold has no legitimate
|
|
1820
|
-
counter-example"
|
|
1666
|
+
counter-example" is false: an official
|
|
1821
1667
|
`spineboy-pro` export reverses one of `hoverboard-board`'s 101 triangles, and a
|
|
1822
1668
|
`validity` rule would have told its author to change correct data. ⇒ `explain`'s
|
|
1823
1669
|
`DEFORM` block is the surface with **no profile at all**, so the winding count is
|
|
@@ -1838,15 +1684,15 @@ bun cli.ts check --candidate /tmp/swapped --frames gallery/portrait/re
|
|
|
1838
1684
|
bun cli.ts check --candidate /tmp/folded --frames gallery/portrait/render/turn@25fps
|
|
1839
1685
|
```
|
|
1840
1686
|
|
|
1841
|
-
⚠️ **The third of those needs a build §9.2's own command will not write.**
|
|
1842
|
-
|
|
1687
|
+
⚠️ **The third of those needs a build §9.2's own command will not write.** Build (b)
|
|
1688
|
+
under `--profile spine-html` is refused and nothing
|
|
1843
1689
|
lands in `/tmp/folded` — which is the row above it in §9.2's table, working. Take
|
|
1844
1690
|
that candidate from the **default** profile, where `A39` reads `PROF` and the
|
|
1845
1691
|
artifact is written — a profile selects which assertions apply and not what is
|
|
1846
1692
|
emitted, and on this rig the two profiles write a `skeleton.json` and a
|
|
1847
1693
|
`skeleton.atlas` that are identical byte for byte.
|
|
1848
1694
|
|
|
1849
|
-
**No run reproduces this:** the three commands above read a build directory and two `/tmp` paths this repository does not track, so no gate reaches them; re-taken by hand
|
|
1695
|
+
**No run reproduces this:** the three commands above read a build directory and two `/tmp` paths this repository does not track, so no gate reaches them; re-taken by hand against a render of the good build
|
|
1850
1696
|
|
|
1851
1697
|
| Candidate | MAE mean | worst | at |
|
|
1852
1698
|
| --- | --- | --- | --- |
|
|
@@ -1884,15 +1730,14 @@ block as it survived `A39`.
|
|
|
1884
1730
|
📌 **`explain`'s `MEMBER` block (§3.1, AUTHORING §4.5.2) does the same for the
|
|
1885
1731
|
bone half, and it takes the **nose test** off the procedure below.** §3 makes the
|
|
1886
1732
|
nose the diagnostic — *if the nose's residual is not negative, the depths are
|
|
1887
|
-
wrong* — and
|
|
1888
|
-
depth table. The block prints the six residuals in a column with the depth that
|
|
1733
|
+
wrong* — and the block prints the six residuals in a column with the depth that
|
|
1889
1734
|
produced each one, so the check is reading one sign. ⚠️ It still cannot say
|
|
1890
1735
|
whether the **depth** was right: `nose at depth 192` evaluates as consistently
|
|
1891
1736
|
wrong as it does right, and no reference frame separates a plausible depth table
|
|
1892
1737
|
from the intended one.
|
|
1893
1738
|
|
|
1894
|
-
⇒ **So the honest procedure — thinner
|
|
1895
|
-
|
|
1739
|
+
⇒ **So the honest procedure — thinner for `A39` and the two report blocks, and
|
|
1740
|
+
still a procedure, because none of the three limits above is one they
|
|
1896
1741
|
lift:** state the model on the key rather than deriving a table (§1.1 for the
|
|
1897
1742
|
mesh, §3.1 for the bones), so what a reviewer reads is a radius, an angle and a
|
|
1898
1743
|
depth per part; read the **nose's sign** off the `MEMBER` block and check the
|
|
@@ -1901,13 +1746,11 @@ still yours, and a stated model evaluates a wrong radius as consistently as a
|
|
|
1901
1746
|
right one — then render, **look at three scales**, and keep a render of the last
|
|
1902
1747
|
build you trusted so `check` has something to be differential against.
|
|
1903
1748
|
|
|
1904
|
-
📌 **What §1.1
|
|
1905
|
-
|
|
1906
|
-
produced, so *what a key claims* is readable; the `DEFORM` block prints what the
|
|
1749
|
+
📌 **What §1.1 and §9.2's block make readable, and what neither does.**
|
|
1750
|
+
`explain` prints the model beside the offsets it produced, so *what a key claims* is readable; the `DEFORM` block prints what the
|
|
1907
1751
|
key **did** — the area and stretch extremes, the displacement and the winding —
|
|
1908
1752
|
so *what the claim came to* is readable too, per key and with no reference
|
|
1909
|
-
(
|
|
1910
|
-
catches the fold inside it). *Whether the claim is right* is unchanged: **nothing
|
|
1753
|
+
(`A39` catches the fold inside it). *Whether the claim is right* is not: **nothing
|
|
1911
1754
|
measures whether 12° was the angle the shot wanted**, and nothing above is a
|
|
1912
1755
|
substitute for looking at three scales.
|
|
1913
1756
|
|
|
@@ -1975,24 +1818,22 @@ the report names what the profile leaves out rather than this page counting it.
|
|
|
1975
1818
|
there; `A13_MESH_BUDGET` and `A15_IDLE_NO_MESH_BONE_KEYS` are among the rules
|
|
1976
1819
|
the default profile excludes.
|
|
1977
1820
|
|
|
1978
|
-
**No run reproduces this:** the three rows below come from commands that read the build directory this repository does not track, so no gate reaches them; re-taken by hand
|
|
1821
|
+
**No run reproduces this:** the three rows below come from commands that read the build directory this repository does not track, so no gate reaches them; re-taken by hand from a clean `gallery/portrait`
|
|
1979
1822
|
|
|
1980
1823
|
| Command | What came back |
|
|
1981
1824
|
| --- | --- |
|
|
1982
1825
|
| `render --fps 25 --max 640` | **81 + 39 + 56 frames**, 478×640, three contact sheets |
|
|
1983
1826
|
| `loop_seam.ts` ×3 | **0 / 255**, **0 of 305 920 pixels** differing, for all three |
|
|
1984
|
-
| `preview` | one **414.5 KiB** HTML file, 22 pages embedded as data URIs — the figure the tool prints
|
|
1827
|
+
| `preview` | one **414.5 KiB** HTML file, 22 pages embedded as data URIs — the figure the tool prints |
|
|
1985
1828
|
|
|
1986
1829
|
📊 **Figures this page took from the record rather than re-deriving**, because
|
|
1987
1830
|
they need the artifact's own pixels: the blink's occlusion (hiding the whole eye
|
|
1988
1831
|
assembly at the shut hold changes **0 of 305 920** pixels; positive control at
|
|
1989
1832
|
rest moves **8 183**), the per-edge narrowing displacements, the `spine-core`
|
|
1990
1833
|
agreement of every posed column and scale with §1's line to **under 0.001 px**,
|
|
1991
|
-
and the Web Player interop pass (**0 console errors, 0 page exceptions**).
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
`setup: { "slot": null }` no longer crashes with a raw `TypeError` — it is a
|
|
1995
|
-
named `rigc compile error` that gives the spelling. Measured on a copy of this
|
|
1834
|
+
and the Web Player interop pass (**0 console errors, 0 page exceptions**).
|
|
1835
|
+
`setup: { "slot": null }`, the obvious way to hide one slot, is a named
|
|
1836
|
+
`rigc compile error` that gives the spelling. Measured on a copy of this
|
|
1996
1837
|
example's `motion.json` carrying one such entry, with the path the run echoes
|
|
1997
1838
|
shortened and the line wrapped:
|
|
1998
1839
|
|
|
@@ -2003,13 +1844,11 @@ nothing there write `"eye_l": { "attachment": null }`, and to show an attachment
|
|
|
2003
1844
|
write `"eye_l": { "attachment": "<name>" }`
|
|
2004
1845
|
```
|
|
2005
1846
|
|
|
2006
|
-
⚠️ **
|
|
2007
|
-
refusal says why.** Writing the spelling that message names on a slot this rig
|
|
1847
|
+
⚠️ **And the second refusal says where that edit goes.** Writing the spelling that message names on a slot this rig
|
|
2008
1848
|
gives an attachment to is refused in turn — `slot "eye_l" has a setup attachment
|
|
2009
1849
|
in the rig spec AND in the motion spec; the setup pose has one author` — so on
|
|
2010
|
-
the worked example hiding one slot is
|
|
2011
|
-
than a line in the motion spec.
|
|
2012
|
-
refusals with a name and a fix in them, where one used to be a stack trace.
|
|
1850
|
+
the worked example hiding one slot is an edit to the **rig** spec rather
|
|
1851
|
+
than a line in the motion spec.
|
|
2013
1852
|
|
|
2014
1853
|
⭐ **Vela is a second cast member and that was deliberate**, against the gallery's
|
|
2015
1854
|
own rule that its examples share one drawing. A 2.5D turn reads off four things: a
|
|
@@ -2025,16 +1864,14 @@ mesh is built**, and that is worth saying to the user before you build it.
|
|
|
2025
1864
|
|
|
2026
1865
|
## 11. Non-goals — stated, so nobody proposes them as gaps
|
|
2027
1866
|
|
|
2028
|
-
🚫 **No command generates a turn, and neither construct
|
|
1867
|
+
🚫 **No command generates a turn, and neither model construct is one.**
|
|
2029
1868
|
§1 is one line of arithmetic; a `rigc yaw --degrees 12` would be guessing at
|
|
2030
1869
|
every depth in §2 on the user's behalf, and depth is the parameter the *author*
|
|
2031
|
-
is choosing.
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
bones) — so the radius, the angle and **every depth** still arrive from the
|
|
2035
|
-
author and the compiler only evaluates. Neither one generates an in-between
|
|
1870
|
+
is choosing. Both constructs are the other thing — **a way to say the model in
|
|
1871
|
+
the spec** (§1.1 for the mesh, §3.1 for the bones) — so the radius, the angle and
|
|
1872
|
+
**every depth** arrive from the author and the compiler only evaluates. Neither one generates an in-between
|
|
2036
1873
|
either: a model is evaluated at one key, and sweeping an angle is editing one
|
|
2037
|
-
number per key. What the toolchain owes is
|
|
1874
|
+
number per key. What the toolchain owes is that the file is checkable,
|
|
2038
1875
|
that you can look, and that a person can choose.
|
|
2039
1876
|
|
|
2040
1877
|
🚫 **No pass bar for a face, and nothing here to hang one on.** MOTION.md's
|
|
@@ -2051,11 +1888,9 @@ the entire point of that section.
|
|
|
2051
1888
|
⚠️ **Not a Live2D comparison, and not a recommendation between formats.** What
|
|
2052
1889
|
the worked example measured is that a portrait turn is authorable on plain Spine
|
|
2053
1890
|
4.3 at draft quality — nothing outside the format, no plugin, no runtime patch —
|
|
2054
|
-
and that the **split is authoring cost rather than runtime capability**.
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
[#295](https://github.com/firejune/rigc/issues/295) — which moves the remaining
|
|
2058
|
-
cost off the keyboard and onto the **parts**: per-eye meshes, a meshed neck, a
|
|
1891
|
+
and that the **split is authoring cost rather than runtime capability**. Neither
|
|
1892
|
+
the deform table nor the track table is transcribed (§1.1, §3.1), so the
|
|
1893
|
+
remaining cost is not on the keyboard but on the **parts**: per-eye meshes, a meshed neck, a
|
|
2059
1894
|
second art layer for the far cheek (§8). Whether to pay *that* is a project's
|
|
2060
1895
|
decision and this page does not make it.
|
|
2061
1896
|
|
|
@@ -2064,8 +1899,7 @@ rather than an unbuilt feature, and it runs in both directions.** rigc's inputs
|
|
|
2064
1899
|
are a rig spec and a motion spec; its outputs are Spine 4.3 skeleton data and an
|
|
2065
1900
|
atlas. There is no importer, no exporter and no converter for `.moc3`, `.cmo3`,
|
|
2066
1901
|
`.model3.json` or anything else in that family, and nothing in this repository
|
|
2067
|
-
claims compatibility with that format in either direction
|
|
2068
|
-
([#399](https://github.com/firejune/rigc/issues/399) is where that was settled).
|
|
1902
|
+
claims compatibility with that format in either direction.
|
|
2069
1903
|
⭐ **What is in scope is an authoring idea, stated on its own terms rather than
|
|
2070
1904
|
as anybody's feature: that a face angle can be a value rather than a time.**
|
|
2071
1905
|
§8's *The turn as a value rather than a time* is that idea on Spine's own
|