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 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.** Byte identity is not the claim there and the reason is the input
582
- rather than the round trip — an editor header carries `hash` and `audio`, which the rig
583
- spec has no field for — so the contract is the structural one `diff` measures.
584
- [INGEST.md §2.3](docs/INGEST.md) has the three kinds of difference that remain, with
585
- what each is worth.
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 key of keys) {
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 key of keys) {
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.time).padEnd(7)} ${(fields || '(all defaults)').padEnd(46)} ${curve}`);
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.time).padEnd(7)} ${(fields || '(all defaults)').padEnd(46)} ${curve}`);
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 key of keys) {
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.time).padEnd(7)} ${offsets}`);
3006
+ console.log(` t=${String(keyTimeOf('drawOrder key', key)).padEnd(7)} ${offsets}`);
2976
3007
  }
2977
3008
  }
2978
3009
  }