spine-rigc 0.3.0 → 0.4.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 +27 -3
- package/cli.ts +19 -2
- package/docs/AUTHORING.md +416 -47
- package/docs/SPEC_COVERAGE.md +5 -4
- package/package.json +1 -1
- package/src/check.ts +560 -24
- package/src/framing.ts +280 -0
- package/src/render.ts +21 -0
- package/src/slots.ts +102 -4
package/README.md
CHANGED
|
@@ -138,6 +138,21 @@ per animation and per frame:
|
|
|
138
138
|
land in the box `frames.json` records is measured there, exactly, and the rest
|
|
139
139
|
share one fitted framing. `--framing shared` measures every set in the shared one
|
|
140
140
|
— the whole-root behaviour before issue #100, and worth 15–25 MAE on a character.
|
|
141
|
+
A **fitted** framing then gets one last pass that searches whole-pixel offsets
|
|
142
|
+
(±2 px) for the lowest MAE and takes the best one, because a fit registers extent
|
|
143
|
+
and the best fit of two extents is not the best alignment of two pictures — a
|
|
144
|
+
constant pixel is worth up to 30 % of a set's figure (issue #146). The line says
|
|
145
|
+
what it moved and what that was worth, and it says so when the identity won as
|
|
146
|
+
well. A box that is **not** an estimate — `frames.json`'s own, or one you pinned —
|
|
147
|
+
is never moved: there the same search is reported as a finding, because a constant
|
|
148
|
+
pixel inside the right box is the candidate's own figure sitting off, not framing.
|
|
149
|
+
- **The whole shot, against the contact sheet** — a set that ships a couple of
|
|
150
|
+
stills and folds every sampled frame into one `contact.png` (rung 2's do,
|
|
151
|
+
spineboy's `@30fps` sets do) used to be compared on the stills alone, honestly
|
|
152
|
+
reported and empty behind: nothing at all was measured about the frames in
|
|
153
|
+
between. `check` now samples the candidate at the set's own rate and compares it
|
|
154
|
+
against the sheet's own tiles, whose grid it measures off the sheet (issue #36).
|
|
155
|
+
MAE only, and a sheet that is not a grid of those frames is refused by name.
|
|
141
156
|
- **Per-frame change** — how many pixels each side moved since **its own** previous
|
|
142
157
|
frame, compared against each other. It is the only measure here that looks at the
|
|
143
158
|
relation between two frames rather than at one, and it is what catches a held pose
|
|
@@ -146,7 +161,8 @@ per animation and per frame:
|
|
|
146
161
|
- **Per-slot drift** — where each of the candidate's own slots landed against the
|
|
147
162
|
reference frame, in pixels. MAE says *how wrong*; a slot's drift says *which
|
|
148
163
|
part, which way, how far*. Where the reference merged two parts into one blob —
|
|
149
|
-
the trap [AUTHORING §8](docs/AUTHORING.md) opens with
|
|
164
|
+
the trap [AUTHORING §8](docs/AUTHORING.md) opens with, and it counts as merged
|
|
165
|
+
even when one part is most of the blob (issue #37) — the slot is
|
|
150
166
|
template-matched against its own rendered pixels instead, with a confidence; and
|
|
151
167
|
where nothing inside the distance that slot could plausibly have moved matches
|
|
152
168
|
it, the answer is **no match** rather than a number about some other part.
|
|
@@ -175,14 +191,19 @@ same pixels whatever coordinates they were authored in, an invisible transparent
|
|
|
175
191
|
margin cannot move the result, and no single quad corner in a single frame can set
|
|
176
192
|
the scale for a run.
|
|
177
193
|
|
|
178
|
-
There is no pass mark
|
|
194
|
+
There is no pass mark **in the tool**, for the same reason `diff` has none. The
|
|
195
|
+
ladder's pass definition and its thresholds are a document read by a person over
|
|
196
|
+
the whole table — [docs/LADDER.md](docs/LADDER.md)'s *Operating rules* — and not an
|
|
197
|
+
exit code either command could produce.
|
|
179
198
|
|
|
180
199
|
### Benchmark ladder — the rungs, and where they stand
|
|
181
200
|
|
|
182
201
|
**[docs/LADDER.md](docs/LADDER.md) is the live ledger**: the rung order
|
|
183
202
|
(blockers → rung 3 first → 1 · 2 · 4 · 5 → 6 → 8 → 7 → spineboy), what each
|
|
184
203
|
rung gates on, how a rung is scored, the honesty rule that keeps the reference
|
|
185
|
-
export away from the authoring agent,
|
|
204
|
+
export away from the authoring agent, the operating rules — what a pass is, and
|
|
205
|
+
the numbered thresholds of the current gate (**gate v2**) that decide one — and a status table. Run
|
|
206
|
+
one with:
|
|
186
207
|
|
|
187
208
|
```bash
|
|
188
209
|
bun cli.ts bench 3 --candidate path/to/candidate/spine
|
|
@@ -567,6 +588,9 @@ for a result, and there is no flag that changes that.
|
|
|
567
588
|
- [docs/LADDER.md](docs/LADDER.md) is the benchmark: the same job, from a brief
|
|
568
589
|
and rendered frames, scored. [docs/PILOT.md](docs/PILOT.md) is how to run an
|
|
569
590
|
agent through it and score what comes back.
|
|
591
|
+
- 🤖 **Handing the authoring to an AI agent?**
|
|
592
|
+
[docs/PROMPTING.md](docs/PROMPTING.md) is the operator's page — the six prompt
|
|
593
|
+
clauses a measured pilot run paid for, and what you can leave unsaid.
|
|
570
594
|
|
|
571
595
|
## Usage
|
|
572
596
|
|
package/cli.ts
CHANGED
|
@@ -523,9 +523,18 @@ function cmdBench(flags: Record<string, string>, positional: string[]): void {
|
|
|
523
523
|
: framing.source === 'declared'
|
|
524
524
|
? `frames.json's own box, the candidate measured into it`
|
|
525
525
|
: `fitted to the candidate's pixels, ${framing.passes} pass(es)${framing.settled ? '' : framing.cycled ? ', cycling' : ', unsettled'}`;
|
|
526
|
+
// The MAE-refined offset belongs on this line rather than only in `check`'s
|
|
527
|
+
// own table: it moved the box every figure below was measured in, so a row
|
|
528
|
+
// that quoted the figures without it would not say what they were measured
|
|
529
|
+
// against — issue #146's own version of the #34 lesson above.
|
|
530
|
+
const r = framing.refinement;
|
|
531
|
+
const refined =
|
|
532
|
+
r === null || !r.applied
|
|
533
|
+
? ''
|
|
534
|
+
: ` MAE-refined ${signed(r.dx)}, ${signed(r.dy)}px (${r.before.toFixed(2)} → ${r.after.toFixed(2)} ref)`;
|
|
526
535
|
console.log(
|
|
527
536
|
` framing fit x${framing.fit.scale.toFixed(6)} rms ${framing.fit.rms.toFixed(2)}px union residual ` +
|
|
528
|
-
`${signed(framing.fit.residualWidth)} x ${signed(framing.fit.residualHeight)}px (${how})`,
|
|
537
|
+
`${signed(framing.fit.residualWidth)} x ${signed(framing.fit.residualHeight)}px (${how})${refined}`,
|
|
529
538
|
);
|
|
530
539
|
}
|
|
531
540
|
for (const anim of check.animations) {
|
|
@@ -551,9 +560,17 @@ function cmdBench(flags: Record<string, string>, positional: string[]): void {
|
|
|
551
560
|
// carried here and not only in `check`'s own table because this is the line a
|
|
552
561
|
// loop reads between builds, and `mean=` has a denominator the candidate can
|
|
553
562
|
// grow — see `FrameCheck.maeReference`.
|
|
563
|
+
// ...and the contact sheet, when the set ships one: a row reading "over 2
|
|
564
|
+
// frame(s)" for a 311-frame shot is the hole issue #36 closed, and the whole
|
|
565
|
+
// -shot figure is the one that says the frames between the stills were seen.
|
|
566
|
+
const sheet =
|
|
567
|
+
anim.sheet === null
|
|
568
|
+
? ''
|
|
569
|
+
: `, sheet ${anim.sheet.compared} tile(s) mean=${anim.sheet.meanMae.toFixed(2)} ` +
|
|
570
|
+
`worst=${anim.sheet.worstMae.toFixed(2)}`;
|
|
554
571
|
console.log(
|
|
555
572
|
` ${anim.dir.padEnd(10)} MAE mean=${anim.meanMae.toFixed(2)} worst=${anim.worstMae.toFixed(2)} ` +
|
|
556
|
-
`ref=${anim.meanMaeReference.toFixed(2)} over ${anim.compared} frame(s) ${drift}${change}${chain}`,
|
|
573
|
+
`ref=${anim.meanMaeReference.toFixed(2)} over ${anim.compared} frame(s) ${drift}${change}${chain}${sheet}`,
|
|
557
574
|
);
|
|
558
575
|
}
|
|
559
576
|
} else {
|