spine-rigc 0.34.0 → 0.35.1
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 +5 -5
- package/cli.ts +37 -6
- package/docs/AUTHORING.md +417 -43
- package/docs/INGEST.md +64 -16
- package/docs/SPEC_COVERAGE.md +1 -1
- package/package.json +1 -1
- package/src/compile.ts +164 -21
- package/src/ingest.ts +196 -26
- package/src/keyorder.ts +547 -0
- package/src/mesh.ts +54 -17
- package/src/rig.ts +119 -9
- package/src/types.ts +38 -18
- package/src/validate.ts +129 -12
package/README.md
CHANGED
|
@@ -578,11 +578,11 @@ is in no field of the skeleton.
|
|
|
578
578
|
**And over twelve skeletons nobody here wrote.** The same run ingests every editor
|
|
579
579
|
export in the fetched example corpus, rebuilds it through the pack beside it and
|
|
580
580
|
`diff`s the result against the source: **12 of 12, no blockers, 1.000 on every measure
|
|
581
|
-
the report carries
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
[INGEST.md §2.3](docs/INGEST.md)
|
|
585
|
-
|
|
581
|
+
the report carries** — and each rebuild is its export's own text in canonical form,
|
|
582
|
+
apart from the header's `hash` and `spine`: the editor's project hash and the runtime
|
|
583
|
+
version rigc stamps, the two keys the rig spec has no field for by design (`IG83`,
|
|
584
|
+
12 of 12). [INGEST.md §2.3](docs/INGEST.md) states that pass line and why those two
|
|
585
|
+
are the exceptions.
|
|
586
586
|
|
|
587
587
|
**What it reads is skeleton JSON and nothing else** — no `.spine` project, no binary
|
|
588
588
|
`.skel`, no atlas, no art. So it never invents, and the things it cannot get out of
|
package/cli.ts
CHANGED
|
@@ -86,6 +86,7 @@ import {
|
|
|
86
86
|
type AtlasRegion,
|
|
87
87
|
} from './src/atlas.ts';
|
|
88
88
|
import { parseJsonWithPosition } from './src/json-position.ts';
|
|
89
|
+
import { PARSER_DEFAULTS, parserReading } from './src/keyorder.ts';
|
|
89
90
|
import { float32Step } from './src/timelines.ts';
|
|
90
91
|
import { findRung, RUNG_IDS, type RungSkeleton } from './src/ladder.ts';
|
|
91
92
|
import {
|
|
@@ -1183,6 +1184,30 @@ const SCALE_PRODUCT_NOTE =
|
|
|
1183
1184
|
* foreign data. There is no honest SKIP either: an absent declaration is not
|
|
1184
1185
|
* "nothing to measure", it is "no way to know what was meant".
|
|
1185
1186
|
*/
|
|
1187
|
+
/**
|
|
1188
|
+
* An emitted key as the 4.3 parser reads it: every field its kind's
|
|
1189
|
+
* `PARSER_DEFAULTS` row lists and the key leaves out, at the row's value, then
|
|
1190
|
+
* the key's own fields. The emitter leaves a field at its parser default out
|
|
1191
|
+
* (issue #716), so a report that reads the file needs the row to say what the
|
|
1192
|
+
* runtime reads there — and reads it from the one table the emitter used.
|
|
1193
|
+
*/
|
|
1194
|
+
function asParsed(kind: string, key: Record<string, unknown>): Record<string, unknown> {
|
|
1195
|
+
const row = PARSER_DEFAULTS[kind];
|
|
1196
|
+
if (row === undefined) return key;
|
|
1197
|
+
const site = { object: key, previous: () => null };
|
|
1198
|
+
const filled: Record<string, unknown> = {};
|
|
1199
|
+
for (const field of Object.keys(row)) {
|
|
1200
|
+
const value = parserReading(row, site, field);
|
|
1201
|
+
if (value !== undefined) filled[field] = value;
|
|
1202
|
+
}
|
|
1203
|
+
return { ...filled, ...key };
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
/** An emitted key's time as the parser reads it — `0` where the key leaves it out. */
|
|
1207
|
+
function keyTimeOf(kind: string, key: Record<string, unknown>): unknown {
|
|
1208
|
+
return asParsed(kind, key).time;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1186
1211
|
function scaleProduct(timelineName: string, key: Record<string, unknown>): string {
|
|
1187
1212
|
if (timelineName !== 'scale') return '';
|
|
1188
1213
|
const x = key.x;
|
|
@@ -2830,7 +2855,11 @@ function cmdExplain(flags: Record<string, string>): void {
|
|
|
2830
2855
|
for (const [timelineName, keys] of Object.entries(timelines)) {
|
|
2831
2856
|
console.log(` ${boneName}.${timelineName} ${keys.length} key(s)${drives}`);
|
|
2832
2857
|
if (timelineName === 'scale') console.log(` ${SCALE_PRODUCT_NOTE}`);
|
|
2833
|
-
for (const
|
|
2858
|
+
for (const emitted of keys) {
|
|
2859
|
+
// Every channel, as the parser reads it: a channel at its parser
|
|
2860
|
+
// default is not in the file (issue #716), and this list shows the
|
|
2861
|
+
// value a reader has to reason about rather than the bytes.
|
|
2862
|
+
const key = asParsed(`bone ${timelineName} key`, emitted);
|
|
2834
2863
|
const fields = Object.entries(key)
|
|
2835
2864
|
.filter(([k]) => k !== 'time' && k !== 'curve')
|
|
2836
2865
|
.map(([k, v]) => `${k}=${String(v)}`)
|
|
@@ -2847,7 +2876,8 @@ function cmdExplain(flags: Record<string, string>): void {
|
|
|
2847
2876
|
for (const [slotName, timelines] of Object.entries(anim.slots ?? {})) {
|
|
2848
2877
|
for (const [timelineName, keys] of Object.entries(timelines)) {
|
|
2849
2878
|
console.log(` ${slotName}.${timelineName} ${keys.length} key(s)`);
|
|
2850
|
-
for (const
|
|
2879
|
+
for (const emitted of keys) {
|
|
2880
|
+
const key = asParsed(`slot ${timelineName} key`, emitted);
|
|
2851
2881
|
const curve = key.curve;
|
|
2852
2882
|
const shape = Array.isArray(curve)
|
|
2853
2883
|
? `bezier[${curve.length}] ${curve.slice(12).join(', ')} <- alpha channel, absolute (t,v)`
|
|
@@ -2875,7 +2905,7 @@ function cmdExplain(flags: Record<string, string>): void {
|
|
|
2875
2905
|
.map(([k, v]) => `${k}=${String(v)}`)
|
|
2876
2906
|
.join(' ');
|
|
2877
2907
|
const curve = Array.isArray(key.curve) ? `bezier[${key.curve.length}]` : key.curve === 'stepped' ? 'stepped' : 'linear';
|
|
2878
|
-
console.log(` t=${String(key
|
|
2908
|
+
console.log(` t=${String(keyTimeOf(`${group} key`, key)).padEnd(7)} ${(fields || '(all defaults)').padEnd(46)} ${curve}`);
|
|
2879
2909
|
}
|
|
2880
2910
|
}
|
|
2881
2911
|
}
|
|
@@ -2892,7 +2922,7 @@ function cmdExplain(flags: Record<string, string>): void {
|
|
|
2892
2922
|
.map(([k, v]) => `${k}=${String(v)}`)
|
|
2893
2923
|
.join(' ');
|
|
2894
2924
|
const curve = Array.isArray(key.curve) ? `bezier[${key.curve.length}]` : key.curve === 'stepped' ? 'stepped' : 'linear';
|
|
2895
|
-
console.log(` t=${String(key
|
|
2925
|
+
console.log(` t=${String(keyTimeOf(`${group} ${timelineName} key`, key)).padEnd(7)} ${(fields || '(all defaults)').padEnd(46)} ${curve}`);
|
|
2896
2926
|
}
|
|
2897
2927
|
}
|
|
2898
2928
|
}
|
|
@@ -2906,7 +2936,8 @@ function cmdExplain(flags: Record<string, string>): void {
|
|
|
2906
2936
|
for (const [attName, timelines] of Object.entries(attMap)) {
|
|
2907
2937
|
for (const [timelineName, keys] of Object.entries(timelines)) {
|
|
2908
2938
|
console.log(` ${skinName}/${slotName}/${attName}.${timelineName} ${keys.length} key(s)`);
|
|
2909
|
-
for (const
|
|
2939
|
+
for (const emitted of keys) {
|
|
2940
|
+
const key = asParsed(`attachment ${timelineName} key`, emitted);
|
|
2910
2941
|
const run = Array.isArray(key.vertices) ? (key.vertices as number[]) : null;
|
|
2911
2942
|
const offset = typeof key.offset === 'number' ? key.offset : 0;
|
|
2912
2943
|
const span = run
|
|
@@ -2972,7 +3003,7 @@ function cmdExplain(flags: Record<string, string>): void {
|
|
|
2972
3003
|
.map((o) => `${o.slot}${o.offset >= 0 ? '+' : ''}${o.offset}`)
|
|
2973
3004
|
.join(' ')
|
|
2974
3005
|
: 'back to the setup order';
|
|
2975
|
-
console.log(` t=${String(key
|
|
3006
|
+
console.log(` t=${String(keyTimeOf('drawOrder key', key)).padEnd(7)} ${offsets}`);
|
|
2976
3007
|
}
|
|
2977
3008
|
}
|
|
2978
3009
|
}
|