rig-c 0.0.0-stage → 2.20.4

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.
Files changed (213) hide show
  1. package/.claude-plugin/marketplace.json +19 -0
  2. package/.claude-plugin/plugin.json +13 -0
  3. package/LICENSE +30 -0
  4. package/NOTICE.md +145 -0
  5. package/README.md +817 -3
  6. package/bin/rigc.cjs +83 -0
  7. package/cli.ts +61 -0
  8. package/cli_core.ts +46 -0
  9. package/docs/AUTHORING.md +9923 -0
  10. package/docs/FACE.md +1948 -0
  11. package/docs/INGEST.md +1488 -0
  12. package/docs/MOTION.md +1241 -0
  13. package/docs/PROMPTING.md +109 -0
  14. package/docs/RIGGING.md +1441 -0
  15. package/docs/SPEC_COVERAGE.md +357 -0
  16. package/package.json +108 -4
  17. package/skills/rigc/SKILL.md +133 -0
  18. package/skills/rigc-face/SKILL.md +60 -0
  19. package/skills/rigc-ingest/SKILL.md +78 -0
  20. package/skills/rigc-motion/SKILL.md +51 -0
  21. package/skills/rigc-rigging/SKILL.md +49 -0
  22. package/src/areaband.ts +159 -0
  23. package/src/assertions/bodies/a01.ts +23 -0
  24. package/src/assertions/bodies/a02.ts +21 -0
  25. package/src/assertions/bodies/a03.ts +27 -0
  26. package/src/assertions/bodies/a04.ts +40 -0
  27. package/src/assertions/bodies/a05.ts +56 -0
  28. package/src/assertions/bodies/a06.ts +245 -0
  29. package/src/assertions/bodies/a07.ts +68 -0
  30. package/src/assertions/bodies/a08.ts +76 -0
  31. package/src/assertions/bodies/a09.ts +82 -0
  32. package/src/assertions/bodies/a10.ts +116 -0
  33. package/src/assertions/bodies/a11.ts +15 -0
  34. package/src/assertions/bodies/a12.ts +30 -0
  35. package/src/assertions/bodies/a13.ts +51 -0
  36. package/src/assertions/bodies/a14.ts +35 -0
  37. package/src/assertions/bodies/a15.ts +97 -0
  38. package/src/assertions/bodies/a16.ts +24 -0
  39. package/src/assertions/bodies/a17.ts +26 -0
  40. package/src/assertions/bodies/a18.ts +62 -0
  41. package/src/assertions/bodies/a19.ts +404 -0
  42. package/src/assertions/bodies/a20.ts +122 -0
  43. package/src/assertions/bodies/a21.ts +190 -0
  44. package/src/assertions/bodies/a22.ts +39 -0
  45. package/src/assertions/bodies/a23.ts +305 -0
  46. package/src/assertions/bodies/a24.ts +68 -0
  47. package/src/assertions/bodies/a25.ts +39 -0
  48. package/src/assertions/bodies/a26.ts +61 -0
  49. package/src/assertions/bodies/a27.ts +33 -0
  50. package/src/assertions/bodies/a28.ts +70 -0
  51. package/src/assertions/bodies/a29.ts +34 -0
  52. package/src/assertions/bodies/a30.ts +50 -0
  53. package/src/assertions/bodies/a31.ts +61 -0
  54. package/src/assertions/bodies/a32.ts +44 -0
  55. package/src/assertions/bodies/a33.ts +110 -0
  56. package/src/assertions/bodies/a34.ts +133 -0
  57. package/src/assertions/bodies/a35.ts +160 -0
  58. package/src/assertions/bodies/a36.ts +81 -0
  59. package/src/assertions/bodies/a37.ts +77 -0
  60. package/src/assertions/bodies/a38.ts +73 -0
  61. package/src/assertions/bodies/a39.ts +303 -0
  62. package/src/assertions/bodies/a40.ts +128 -0
  63. package/src/assertions/bodies/a42.ts +97 -0
  64. package/src/assertions/bodies/a43.ts +181 -0
  65. package/src/assertions/bodies/a44.ts +23 -0
  66. package/src/assertions/bodies/a45.ts +172 -0
  67. package/src/assertions/bodies/a46.ts +224 -0
  68. package/src/assertions/bodies/a47.ts +126 -0
  69. package/src/assertions/bodies/a48.ts +83 -0
  70. package/src/assertions/bodies/a49.ts +81 -0
  71. package/src/assertions/bodies/a50.ts +97 -0
  72. package/src/assertions/constraint_words.ts +169 -0
  73. package/src/assertions/emitted/index.ts +148 -0
  74. package/src/assertions/facts/animated_bones.ts +30 -0
  75. package/src/assertions/facts/animation_durations.ts +37 -0
  76. package/src/assertions/facts/atlas_pages.ts +19 -0
  77. package/src/assertions/facts/atlas_regions.ts +52 -0
  78. package/src/assertions/facts/bone_timelines.ts +37 -0
  79. package/src/assertions/facts/constraint_targets.ts +56 -0
  80. package/src/assertions/facts/constraints.ts +155 -0
  81. package/src/assertions/facts/deform_survey.ts +27 -0
  82. package/src/assertions/facts/event_keys.ts +55 -0
  83. package/src/assertions/facts/linked_meshes.ts +38 -0
  84. package/src/assertions/facts/mesh_attachments.ts +100 -0
  85. package/src/assertions/facts/region_joins.ts +34 -0
  86. package/src/assertions/facts/sequences.ts +85 -0
  87. package/src/assertions/facts/skeleton_roster.ts +45 -0
  88. package/src/assertions/facts/skin_entries.ts +37 -0
  89. package/src/assertions/facts/skin_members.ts +53 -0
  90. package/src/assertions/facts/slider_composition.ts +78 -0
  91. package/src/assertions/facts/slot_colour.ts +43 -0
  92. package/src/assertions/facts/stage.ts +27 -0
  93. package/src/assertions/facts/stage_box.ts +65 -0
  94. package/src/assertions/facts/stepped_poses.ts +74 -0
  95. package/src/assertions/facts/two_colour.ts +52 -0
  96. package/src/assertions/facts/vertex_polygons.ts +53 -0
  97. package/src/assertions/footprints.ts +367 -0
  98. package/src/assertions/harness.ts +109 -0
  99. package/src/assertions/inward_advance.ts +58 -0
  100. package/src/assertions/kinds.ts +105 -0
  101. package/src/assertions/mesh_kinds.ts +56 -0
  102. package/src/assertions/model/animated_bones.ts +38 -0
  103. package/src/assertions/model/animation_durations.ts +57 -0
  104. package/src/assertions/model/atlas_pages.ts +15 -0
  105. package/src/assertions/model/atlas_regions.ts +76 -0
  106. package/src/assertions/model/bone_timelines.ts +58 -0
  107. package/src/assertions/model/constraint_targets.ts +82 -0
  108. package/src/assertions/model/constraints.ts +233 -0
  109. package/src/assertions/model/declared.ts +125 -0
  110. package/src/assertions/model/deform_survey.ts +24 -0
  111. package/src/assertions/model/event_keys.ts +45 -0
  112. package/src/assertions/model/given.ts +45 -0
  113. package/src/assertions/model/index.ts +398 -0
  114. package/src/assertions/model/linked_meshes.ts +24 -0
  115. package/src/assertions/model/mesh_attachments.ts +119 -0
  116. package/src/assertions/model/parse.ts +146 -0
  117. package/src/assertions/model/region_joins.ts +67 -0
  118. package/src/assertions/model/runtime_timelines.ts +78 -0
  119. package/src/assertions/model/sequences.ts +157 -0
  120. package/src/assertions/model/skeleton_roster.ts +23 -0
  121. package/src/assertions/model/skin_entries.ts +69 -0
  122. package/src/assertions/model/skin_members.ts +64 -0
  123. package/src/assertions/model/slider_composition.ts +193 -0
  124. package/src/assertions/model/slot_colour.ts +81 -0
  125. package/src/assertions/model/stage.ts +28 -0
  126. package/src/assertions/model/stage_box.ts +51 -0
  127. package/src/assertions/model/stepped_poses.ts +105 -0
  128. package/src/assertions/model/two_colour.ts +61 -0
  129. package/src/assertions/model/vertex_polygons.ts +72 -0
  130. package/src/assertions/reasons.ts +129 -0
  131. package/src/assertions/region_lookups.ts +61 -0
  132. package/src/assertions/report.ts +189 -0
  133. package/src/assertions/values.ts +39 -0
  134. package/src/atlas.ts +2870 -0
  135. package/src/ballot.ts +866 -0
  136. package/src/bonedist.ts +643 -0
  137. package/src/chainfit.ts +2752 -0
  138. package/src/chains.ts +170 -0
  139. package/src/check.ts +4303 -0
  140. package/src/checkpics.ts +295 -0
  141. package/src/cli/core_commands.ts +1627 -0
  142. package/src/cli/repack.ts +414 -0
  143. package/src/cli/shared.ts +2776 -0
  144. package/src/cli/spine_commands.ts +820 -0
  145. package/src/compile.ts +9414 -0
  146. package/src/core/additive.ts +458 -0
  147. package/src/core/animation.ts +1050 -0
  148. package/src/core/clipping.ts +696 -0
  149. package/src/core/constraints.ts +1876 -0
  150. package/src/core/constraints_path.ts +964 -0
  151. package/src/core/constraints_physics.ts +881 -0
  152. package/src/core/constraints_slider.ts +635 -0
  153. package/src/core/deform.ts +613 -0
  154. package/src/core/draw_order.ts +125 -0
  155. package/src/core/events.ts +135 -0
  156. package/src/core/hooks.ts +249 -0
  157. package/src/core/index.ts +1400 -0
  158. package/src/core/raw.ts +739 -0
  159. package/src/core/skins.ts +129 -0
  160. package/src/core/uvs.ts +469 -0
  161. package/src/core/vertices.ts +490 -0
  162. package/src/core/walk.ts +197 -0
  163. package/src/core/world.ts +289 -0
  164. package/src/correspondence.ts +15 -0
  165. package/src/deformbuild.ts +60 -0
  166. package/src/deformgen.ts +630 -0
  167. package/src/deformmeasure.ts +732 -0
  168. package/src/deformreport.ts +373 -0
  169. package/src/deformstructure.ts +386 -0
  170. package/src/deformsurvey.ts +2162 -0
  171. package/src/depth.ts +784 -0
  172. package/src/diff.ts +2252 -0
  173. package/src/emit.ts +134 -0
  174. package/src/emit_spine.ts +854 -0
  175. package/src/errors.ts +53 -0
  176. package/src/framing.ts +819 -0
  177. package/src/generation.ts +139 -0
  178. package/src/ingest.ts +2293 -0
  179. package/src/json-position.ts +253 -0
  180. package/src/keyorder.ts +587 -0
  181. package/src/keys.ts +486 -0
  182. package/src/ladder.ts +121 -0
  183. package/src/mesh.ts +2382 -0
  184. package/src/meshcompare.ts +1188 -0
  185. package/src/meshquality.ts +2042 -0
  186. package/src/meshrasters.ts +944 -0
  187. package/src/meshreduce.ts +1425 -0
  188. package/src/model.ts +1245 -0
  189. package/src/motion.ts +809 -0
  190. package/src/nonfinite.ts +54 -0
  191. package/src/package_meta.ts +48 -0
  192. package/src/png.ts +297 -0
  193. package/src/pose.ts +2324 -0
  194. package/src/preview.ts +434 -0
  195. package/src/region_joins.ts +54 -0
  196. package/src/render.ts +1013 -0
  197. package/src/render_core.ts +871 -0
  198. package/src/render_shared.ts +2958 -0
  199. package/src/repack.ts +495 -0
  200. package/src/rig.ts +2941 -0
  201. package/src/slots.ts +892 -0
  202. package/src/spine_side.ts +138 -0
  203. package/src/timelines.ts +837 -0
  204. package/src/trackgen.ts +364 -0
  205. package/src/transform.ts +310 -0
  206. package/src/types.ts +1797 -0
  207. package/src/validate.ts +3875 -0
  208. package/tools/contact.ts +126 -0
  209. package/tools/editor_roundtrip.ts +1641 -0
  210. package/tools/font5x7.ts +101 -0
  211. package/tools/measure_contact_depth.ts +105 -0
  212. package/tools/plate.ts +508 -0
  213. package/tools/png_probe.mjs +72 -0
@@ -0,0 +1,100 @@
1
+ /**
2
+ * The mesh attachments, as every body that reads a mesh sees them (issue
3
+ * #1025, step 4c of #380) — the census's F03, F05, F07 (vertex data), F08
4
+ * (mesh geometry) and F10 (the linked-mesh join), for A04, A13, A14, A15, A20,
5
+ * A21, A22, A28 and the mesh half of A23.
6
+ *
7
+ * ⭐ **One family** (issue #1054). Cut 4c-1 stated the meshes for A13, A14,
8
+ * A15 and A22 as a family of their own (`SkinMeshFacts`) and cut 4c-2 stated
9
+ * them again here; the two walked the same entries in the same order and
10
+ * agreed on every field they shared, and two families of one fact are two
11
+ * places for a supplier to disagree with itself. The size the budget and
12
+ * canvas rules read joined this one, and the bones a mesh's weights name are
13
+ * derived from `weights` (`weightBonesOf`) rather than stated beside them.
14
+ *
15
+ * ⭐ **The order is the file's**, as `./skin_entries.ts` states it: every
16
+ * skin in the file's order, and within a skin the entries slot by slot in the
17
+ * skeleton's slot order — the walk spine-core's `getAttachments()` makes and
18
+ * the model side reproduces by calling the emitter's own order.
19
+ *
20
+ * 🔸 **What a vertex's binding names is the bone's INDEX in the roster**,
21
+ * because two bodies print it (`A20`'s weight-0 clause and `A28`'s row
22
+ * shapes) and the index is what the file holds. The model document names a
23
+ * binding's bone by name; its supplier turns the name into the index the
24
+ * emitter writes (`boneIndexOf` in `src/emit_spine.ts`), called, and a weight
25
+ * into the float32 the runtime stores it as (`Math.fround`).
26
+ *
27
+ * 🔒 **`encoding` is the round trip's, and only the round trip's.** A clause
28
+ * whose subject is the Spine encoding — the flat vertex run's own coherence,
29
+ * a binding's index into the bone array — has no model-side subject: the
30
+ * document names bones and states the weighted form outright, and the run is
31
+ * written by the emitter (the card's point 2). Those clauses stay in
32
+ * `src/validate.ts`, which hands their findings to the body here, at the
33
+ * place in the walk the body used to print them, so the moved body and the
34
+ * kept clause print the lines the one body printed, in the same order. The
35
+ * model side supplies none, because it has no encoding to be wrong.
36
+ *
37
+ * Links nothing from the runtime: the shapes are plain values.
38
+ */
39
+
40
+ /** One influence of a weighted vertex: the bone's index in the roster and the weight the runtime holds. */
41
+ export interface MeshBinding {
42
+ readonly bone: number;
43
+ readonly weight: number;
44
+ /** The kept clause's finding about this binding's index (`A20`'s range rule), where it has one; never on the model side. */
45
+ readonly encoding?: string;
46
+ }
47
+
48
+ /** One mesh attachment of one skin, a linked mesh included (it loads as a mesh drawing its source's geometry). */
49
+ export interface MeshEntry {
50
+ /** The attachment's own name: the entry's `name`, else its placeholder. */
51
+ readonly name: string;
52
+ readonly skin: string;
53
+ /** The slot it is filed under, and that slot's bone. */
54
+ readonly slot: string;
55
+ readonly slotBone: string;
56
+ readonly placeholder: string;
57
+ /** The file's link, when this entry takes its geometry from another mesh, or `null`. */
58
+ readonly link: { readonly source: string } | null;
59
+ /** The triangles it draws, as indices into its vertices — a link's are its source's. */
60
+ readonly triangles: readonly number[];
61
+ /** `worldVerticesLength`: two numbers per vertex. */
62
+ readonly worldVerticesLength: number;
63
+ /** Its `uvs`, as the runtime reads them (doubles). */
64
+ readonly regionUVs: readonly number[];
65
+ /** `hullLength`: two numbers per hull vertex. */
66
+ readonly hullLength: number;
67
+ /** Its `width` and `height` — a link's are its source's, which the runtime's `setSourceMesh` writes over the link's own. */
68
+ readonly width: number;
69
+ readonly height: number;
70
+ /** Per vertex its influences, in order — or `null` for an unweighted mesh. */
71
+ readonly weights: ReadonlyArray<readonly MeshBinding[]> | null;
72
+ /** The kept clauses' findings about this mesh's vertex run (`A04`'s encoding rules), in order; never on the model side. */
73
+ readonly encoding: readonly string[];
74
+ }
75
+
76
+ /** What A04, A20, A21, A28 and A23 read of the meshes. */
77
+ export interface MeshFacts {
78
+ /** The bone roster's names, by index. */
79
+ readonly bones: readonly string[];
80
+ /** Every mesh attachment of every skin, in the file's walk order. */
81
+ readonly meshes: readonly MeshEntry[];
82
+ }
83
+
84
+ /**
85
+ * Every bone a mesh's weights name, in the weight run's order (repeats kept),
86
+ * by name — empty for an unweighted mesh. A binding whose index the roster
87
+ * does not hold names nothing here: that index is the encoding's fault, which
88
+ * `A20`'s kept clause names (`MeshBinding.encoding`), and no bone drives the
89
+ * mesh through it.
90
+ */
91
+ export function weightBonesOf(facts: Pick<MeshFacts, 'bones'>, mesh: Pick<MeshEntry, 'weights'>): string[] {
92
+ const names: string[] = [];
93
+ for (const vertex of mesh.weights ?? []) {
94
+ for (const binding of vertex) {
95
+ const name = facts.bones[binding.bone];
96
+ if (name !== undefined) names.push(name);
97
+ }
98
+ }
99
+ return names;
100
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The join from an attachment to an atlas region, before anything loads it
3
+ * (issue #1025, step 4c of #380) — the census's F21 names plus the skin
4
+ * entries' region paths, as A08 reads them: every region name the atlas
5
+ * declares, and every lookup a skin entry will make.
6
+ *
7
+ * 🚨 **Both halves are read before the round trip, on purpose** (issue #589):
8
+ * A08 exists to name a miss the loader would refuse without naming the
9
+ * placeholder or the skin, so it cannot read what the loader produced. On the
10
+ * model side the same holds one step over — A08 runs behind the reader alone,
11
+ * not behind the region rule that stands in A00's place, so a miss is named by
12
+ * A08's sentence on both sides and the parse beside it refuses the same file.
13
+ *
14
+ * ⭐ **The order is the file's.** A08 prints one line per lookup that misses,
15
+ * in the order the skins, a skin's slot keys and a slot's placeholders stand in
16
+ * the file — the emitter's `editorSkinOrder` and `editorSlotKeyOrder`, called
17
+ * on the model side — and then one per padded region name, in the atlas's
18
+ * order.
19
+ *
20
+ * Links nothing from the runtime: `validate()` reads the region names off a
21
+ * `TextureAtlas` it builds for this alone and the lookups off the skeleton
22
+ * JSON; the model side reads both off the document (`../model/region_joins.ts`).
23
+ */
24
+ import type { AttachmentRegionJoin } from '../region_lookups.ts';
25
+
26
+ export type { AttachmentRegionJoin };
27
+
28
+ /** What A08 reads. Each half is `null` when its file did not parse, and the body says which. */
29
+ export interface RegionJoinFacts {
30
+ /** Every region the atlas declares, by its name as spelled (untrimmed), in the atlas's order. */
31
+ readonly regionNames: readonly string[] | null;
32
+ /** Every skin entry that resolves through a region, with the names it will look up, in the file's order. */
33
+ readonly joins: readonly AttachmentRegionJoin[] | null;
34
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Numbered series and the frame a slot shows (issue #1025, cut 4c-3 of step
3
+ * 4c of #380) — the census's F02, F03, F18 and R4 as A46 reads them: every
4
+ * skin entry that draws a region, as the file states it and whether the
5
+ * runtime loaded it; every sequence timeline, as the file states it; an
6
+ * animation's duration; and what a slot shows at a time.
7
+ *
8
+ * ⭐ **Attachments by address, never by object.** A46 used to key what it knew
9
+ * by the loaded attachment object and to ask whether the slot shows "the keyed
10
+ * attachment or one playing its timelines" by identity. An object is the
11
+ * runtime's; an address — `skin`, `slot`, `placeholder`, the triple the file
12
+ * files an entry under and a timeline names it by — is the file's, and on the
13
+ * runtime's side each loaded entry is exactly one object (one per skin, slot
14
+ * and placeholder, which `Skin.getAttachment` is keyed by). So `posedFrame`
15
+ * answers with addresses: the entry the slot shows, and the entry whose
16
+ * timelines it plays (itself, or a linked mesh's source when the link plays
17
+ * its source's timelines).
18
+ *
19
+ * ⭐ **The file's order and spelling where A46 walks and prints**: the skins in
20
+ * the file's order, a skin's slot keys and a slot's placeholders in it; every
21
+ * `sequence` block and key as the file spells it, since A46 parses them itself
22
+ * and prints what it found.
23
+ *
24
+ * Links nothing from the runtime: `validate()` reads it off the skeleton JSON
25
+ * and the loaded skeleton (`spineSequenceFacts`), the model side off the
26
+ * document and the core (`../model/sequences.ts`).
27
+ */
28
+
29
+ /** A skin entry's address: `skin`, `slot`, `placeholder`, joined by NULs. */
30
+ export type EntryAddress = string;
31
+
32
+ /** The address of one skin entry. */
33
+ export function entryAddress(skin: string, slot: string, placeholder: string): EntryAddress {
34
+ return `${skin}\u0000${slot}\u0000${placeholder}`;
35
+ }
36
+
37
+ /** One skin entry that draws a region — a region, a mesh or a linked mesh. */
38
+ export interface SequenceSkinEntry {
39
+ readonly skin: string;
40
+ readonly slot: string;
41
+ readonly placeholder: string;
42
+ /** The entry's `name`, `path` and `sequence` as the file spells them (`undefined` where it states none). */
43
+ readonly name: unknown;
44
+ readonly path: unknown;
45
+ readonly sequence: unknown;
46
+ /** Whether the runtime loaded an attachment for the entry: its slot exists and the skin holds it. */
47
+ readonly loaded: boolean;
48
+ }
49
+
50
+ /** One sequence timeline — an attachment's `sequence` that the file states as a list — the address it keys, and its keys as the file spells them. */
51
+ export interface SequenceTimeline {
52
+ readonly animation: string;
53
+ readonly skin: string;
54
+ readonly slot: string;
55
+ readonly placeholder: string;
56
+ readonly keys: readonly unknown[];
57
+ }
58
+
59
+ /** What a slot shows at one pose. */
60
+ export interface PosedSequence {
61
+ /** The entry the slot shows. */
62
+ readonly shown: EntryAddress;
63
+ /** The entry whose timelines it plays: itself, or the source of a linked mesh that plays its source's. */
64
+ readonly playsAs: EntryAddress;
65
+ /** The atlas region the shown entry's series resolves to at this pose, or `null` for none. */
66
+ readonly region: string | null;
67
+ }
68
+
69
+ /** What A46 reads. */
70
+ export interface SequenceFacts {
71
+ /** Every skin entry of a region, mesh or linked mesh, in the file's order: skins, then each skin's slot keys, then a slot's placeholders. */
72
+ readonly entries: readonly SequenceSkinEntry[];
73
+ /** Every animation's sequence timelines, in the file's order: animations, then skins, slots and placeholders as the animation keys them. */
74
+ readonly timelines: readonly SequenceTimeline[];
75
+ /** Whether the skeleton has a slot of this name. */
76
+ hasSlot(slot: string): boolean;
77
+ /** The runtime's duration of an animation, or `null` for no animation of that name. */
78
+ duration(animation: string): number | null;
79
+ /**
80
+ * What the slot shows with the animation applied at `time` on a fresh,
81
+ * non-looping track from the setup pose, no skin set — `null` when it
82
+ * shows nothing.
83
+ */
84
+ posedFrame(animation: string, slot: string, time: number): PosedSequence | null;
85
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The skeleton's bones and slots as the file lists them (issue #1025, cut 4c-4
3
+ * of #380) — the census's F01 and F02, the halves of them that A12, A25 and
4
+ * A26 read: each bone's name and its parent's, and each slot's name and
5
+ * whether it declares a dark colour, in the file's order.
6
+ *
7
+ * ⭐ **The order is a value.** The slots array IS the draw order, and A26
8
+ * holds it to the rig's table index for index; A12 prints one line per dark
9
+ * slot in that order. The emitter writes both arrays in the model's own order
10
+ * and never re-sorts them (`emitBones`, `emitSlots` in `src/emit_spine.ts`), so
11
+ * the document's lists are the file's.
12
+ *
13
+ * ⚠️ **Read as the bodies always read the raw JSON.** A slot is any object in
14
+ * the array, its name `String(name)` (a slot with no string name reads
15
+ * `"undefined"`, as it always printed) and `dark` whether the key is present at
16
+ * all; a bone is an object whose name is a string, its parent the string the
17
+ * file states or `null`. `validate()` reads them off the skeleton JSON
18
+ * (`rawSkeletonRoster`), which it parses before the round trip, so a file the
19
+ * loader refuses is still read; the model side reads them off the document
20
+ * (`../model/skeleton_roster.ts`).
21
+ *
22
+ * Links nothing from the runtime.
23
+ */
24
+
25
+ /** A bone as the rules over parentage read it. */
26
+ export interface RosterBone {
27
+ readonly name: string;
28
+ /** The parent's name, or `null` for a root (or a parent the file does not spell as a string). */
29
+ readonly parent: string | null;
30
+ }
31
+
32
+ /** A slot as the rules over the draw order and the dark colour read it. */
33
+ export interface RosterSlot {
34
+ readonly name: string;
35
+ /** Whether the slot declares a dark colour — the key's presence, which is all A12 asks. */
36
+ readonly dark: boolean;
37
+ }
38
+
39
+ /** What A12, A25 and A26 read of the skeleton's arrays. */
40
+ export interface SkeletonRosterFacts {
41
+ /** The bones, in the file's order. */
42
+ readonly bones: readonly RosterBone[];
43
+ /** The slots, in the file's order — the draw order. */
44
+ readonly slots: readonly RosterSlot[];
45
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The skin entries, as the bodies that walk them read them (issue #1025, step
3
+ * 4c of #380) — the census's F03, F05 and F06: every skin's attachments, of
4
+ * which kind each is, and a region's name and size.
5
+ *
6
+ * ⭐ **The order is a fact, and it is the file's.** A body that prints one
7
+ * line per offending entry prints them in the order this list holds them, so a
8
+ * supplier that walked another order would print the same findings in another
9
+ * order — a different report about the same rig. The order is the one
10
+ * spine-core's loaded skins list their entries in: the skins in the file's
11
+ * order (`default` first, the rest in the editor's order the emitter writes —
12
+ * `editorSkinOrder` in `src/compile.ts`), and within a skin the entries slot by
13
+ * slot in the skeleton's slot order, each slot's in the order its table states
14
+ * them. The model side produces it by calling the emitter's own order, never
15
+ * by restating it (`../model/skin_entries.ts`); the selftest measures the two
16
+ * walks equal on every multi-skin build it makes.
17
+ *
18
+ * Links nothing from the runtime: a spine-core `RegionAttachment` satisfies
19
+ * the entry shape structurally, which is how `validate()` supplies it.
20
+ */
21
+
22
+ /** One region attachment: the name it loaded under (its `name`, else its placeholder), the region path it resolves through (its `path`, else that name) and its size. */
23
+ export interface RegionEntry {
24
+ readonly name: string;
25
+ readonly width: number;
26
+ readonly height: number;
27
+ /** Read by A19 (issue #1025, cut 4c-1), which exempts a base plate by the region it draws; the runtime types it as possibly unset, and reads it with the name as fallback. */
28
+ readonly path?: string;
29
+ }
30
+
31
+ /** What the skins hold, for A03, A11 and A19. */
32
+ export interface SkinEntryFacts {
33
+ /** Every region attachment of every skin, in the file's walk order (the header's ⭐). */
34
+ readonly regionAttachments: readonly RegionEntry[];
35
+ /** How many clipping attachments the skins hold, every skin counted. */
36
+ readonly clippingCount: number;
37
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * What a skin activates, and what asks to be activated (issue #1025, step 4c
3
+ * of #380) — the census's F01, F04 and F12 as A38 reads them: every bone with
4
+ * its parent and its `skinRequired` flag, every constraint in update order with
5
+ * its flag, and each skin's own `bones` and constraint lists.
6
+ *
7
+ * 🔑 **A constraint is an object, not a name.** A skin lists constraint
8
+ * OBJECTS, and two constraints of one name under two kinds are two objects a
9
+ * skin may list separately (issue #692) — so a skin's `constraints` hold the
10
+ * very entries `constraints` holds, and a body asks whether one is listed by
11
+ * identity. A bone's `parent` is the bone entry itself, so the ancestor chain is
12
+ * walked by reference too.
13
+ *
14
+ * ⭐ **The order is the file's.** A38 prints one line per offending member:
15
+ * skins in the file's order (the emitter's, `editorSkinOrder`), a skin's bones
16
+ * as it lists them and its constraints kind by kind in the order the file keys
17
+ * them (`ik`, `transform`, `path`, `physics`, `slider` — `RIG_SKIN_CONSTRAINT_KEYS`,
18
+ * the emitter's), then the bones in the skeleton's order and the constraints in
19
+ * update order.
20
+ *
21
+ * Links nothing from the runtime: spine-core's loaded `SkeletonData` satisfies
22
+ * the shape structurally, which is how `validate()` supplies it, and the model
23
+ * side builds it from the document (`../model/skin_members.ts`).
24
+ */
25
+
26
+ /** One bone: its name, whether it is skin-required, and its parent entry. */
27
+ export interface MemberBone {
28
+ readonly name: string;
29
+ readonly skinRequired: boolean;
30
+ readonly parent: MemberBone | null;
31
+ }
32
+
33
+ /** One constraint: its name and whether it is skin-required. */
34
+ export interface MemberConstraint {
35
+ readonly name: string;
36
+ readonly skinRequired: boolean;
37
+ }
38
+
39
+ /** One skin: its name and the bones and constraint entries it lists. */
40
+ export interface MemberSkin {
41
+ readonly name: string;
42
+ readonly bones: readonly MemberBone[];
43
+ readonly constraints: readonly MemberConstraint[];
44
+ }
45
+
46
+ /** What A38 reads. */
47
+ export interface SkinMemberFacts {
48
+ readonly skins: readonly MemberSkin[];
49
+ /** Every bone, in the skeleton's order. */
50
+ readonly bones: readonly MemberBone[];
51
+ /** Every constraint, in update order. */
52
+ readonly constraints: readonly MemberConstraint[];
53
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The sliders and the timelines their animations key, as A40 reads them
3
+ * (issue #1025, cut 4c-5 of step 4c of #380) — the census's F01–F04, F12,
4
+ * F15, F18, F19 and R3.
5
+ *
6
+ * ⭐ **The order is the runtime's.** The sliders in the `constraints` array's
7
+ * order, which is the update order and the order A40 calls "earlier" and
8
+ * "later" in; each animation's timelines in the order the runtime builds
9
+ * them — the slot timelines, the bone timelines, then ik, transform, path,
10
+ * physics, slider, the attachments' deform and sequence, the draw order and
11
+ * the events, each group's targets in the order the file keys them [measured:
12
+ * an animation keying `events`, `drawOrder`, `attachments`, `slider`,
13
+ * `physics`, `path`, `transform`, `ik`, `slots`, `bones` in that key order
14
+ * loads them slots, bones, ik, transform, path, physics, slider, deform,
15
+ * sequence, draw order, events]; each timeline's properties in the order it
16
+ * registers them. A40 groups the timelines by property in that order and
17
+ * prints one line per property shared, so the order is a fact both suppliers
18
+ * state, not a sort either applies.
19
+ *
20
+ * 🔑 **A property is named by an id both suppliers spell the same way**: the
21
+ * property's name, then the index of the bone, slot or constraint it
22
+ * addresses in the skeleton's order (`-1` for a physics timeline naming no
23
+ * constraint), then — for a deform or sequence timeline — the attachment it
24
+ * is keyed on as `skin/slot/placeholder`. The runtime spells the last as an
25
+ * object's serial number, which is the runtime's and not the rig's, so its
26
+ * supplier maps each attachment object to the address it is filed under; a
27
+ * physics `reset` and the draw-order and event timelines carry no index at
28
+ * all (measured: a named `reset` reads `physicsConstraintReset` alone).
29
+ *
30
+ * 🔸 **What applying a timeline additively does is a question, not a value.**
31
+ * It is posed — twice, with `add`, from two start states, under every skin —
32
+ * so a body asks for it (`behaviour`), and only for the timelines it needs:
33
+ * the validator answers with the runtime's probe, the model side with the
34
+ * core's (`src/core/additive.ts`), and the selftest puts every question a
35
+ * body asks to both.
36
+ *
37
+ * Links nothing from the runtime.
38
+ */
39
+
40
+ /** What applying a timeline twice with `add` does (`src/core/additive.ts`' header). */
41
+ export type AddBehaviour = 'accumulates' | 'overwrites' | 'inert';
42
+
43
+ /** One property a timeline registers: the id it is shared by, the property's name, and the target and property as A40's sentence names them. */
44
+ export interface SliderTimelineProperty {
45
+ readonly id: string;
46
+ readonly property: string;
47
+ readonly names: string;
48
+ }
49
+
50
+ /** One timeline of a slider's animation. */
51
+ export interface SliderTimelineFact {
52
+ /** The runtime class it loads as — the word A40's sentence names `apply` on. */
53
+ readonly runtimeClass: string;
54
+ readonly properties: readonly SliderTimelineProperty[];
55
+ }
56
+
57
+ /** One slider constraint. */
58
+ export interface SliderFact {
59
+ readonly name: string;
60
+ /** Its position in the skeleton's `constraints` array. */
61
+ readonly index: number;
62
+ /** Its setup `mix`. */
63
+ readonly mix: number;
64
+ readonly additive: boolean;
65
+ readonly skinRequired: boolean;
66
+ /** The skins whose `slider` list names it, in the skeleton's skin order. */
67
+ readonly skins: readonly string[];
68
+ /** The animation it applies, with its timelines in the runtime's order — or `null` where it applies none. */
69
+ readonly animation: { readonly name: string; readonly timelines: readonly SliderTimelineFact[] } | null;
70
+ }
71
+
72
+ /** What A40 reads beside the constraint facts. */
73
+ export interface SliderCompositionFacts {
74
+ /** Every slider, in the `constraints` array's order. */
75
+ readonly sliders: readonly SliderFact[];
76
+ /** What the `timeline`-th timeline of `animation` does when it is applied twice with `add` — posed. */
77
+ behaviour(animation: string, timeline: number): AddBehaviour;
78
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Slot colour timelines and the colour a slot poses at (issue #1025, step 4c
3
+ * of #380) — the census's F18 and R4: the animations and the slot timelines
4
+ * they key, and one slot's light colour posed by the runtime's rule.
5
+ *
6
+ * ⭐ **The file's order, and the file's spelling.** A45's first clause names
7
+ * the timeline "which the file states last" as the one that wins, so the order
8
+ * of a slot's timelines is a value and not a presentation; and its findings
9
+ * print a key's `time`, `color` and `value` as the file states them. So the
10
+ * list holds, for every animation in the order the file keys them and every
11
+ * slot in the order the animation keys them, that slot's timelines in the
12
+ * file's order, each key as the file spells it. `validate()` reads it off the
13
+ * skeleton JSON; the model side produces it from the document by calling the
14
+ * emitter's own order and its own parser-default and key-order passes
15
+ * (`../model/slot_colour.ts`), so a key the emitter would write without a field
16
+ * reads without it here too.
17
+ */
18
+
19
+ /** One animation's timelines on one slot: timeline name -> keys, as the file states them. */
20
+ export interface SlotTimelines {
21
+ readonly animation: string;
22
+ readonly slot: string;
23
+ readonly timelines: Readonly<Record<string, unknown>>;
24
+ }
25
+
26
+ /** A slot's light colour as posed: four channels, NaN where the pose read no number. */
27
+ export interface PosedSlotColour {
28
+ readonly color: { readonly r: number; readonly g: number; readonly b: number; readonly a: number };
29
+ }
30
+
31
+ /** What A45 reads. */
32
+ export interface SlotColourFacts {
33
+ /** Every (animation, slot) pair whose timelines the file keys, in the header's order. */
34
+ readonly slotTimelines: readonly SlotTimelines[];
35
+ /** Whether the skeleton holds an animation of this name. */
36
+ hasAnimation(name: string): boolean;
37
+ /**
38
+ * The slot's colour with the animation applied at `time` on a fresh,
39
+ * non-looping track from the setup pose, no skin set — or `undefined` for a
40
+ * slot the skeleton does not have.
41
+ */
42
+ posedSlot(animation: string, slot: string, time: number): PosedSlotColour | undefined;
43
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The stage the skeleton states (issue #1025, step 4c of #380) — the census's
3
+ * F11: the setup-pose box's width and height, which A14 measures a mesh against
4
+ * and A19 measures an attachment against.
5
+ *
6
+ * ⚠️ **`undefined` is a value here, and it is the runtime's.** A skeleton that
7
+ * declares no stage loads with `width` and `height` undefined (measured through
8
+ * spine-core 4.3.13: a header with neither key reads both as `undefined`, not
9
+ * 0), and the two rules read that absence differently on purpose — A14 skips,
10
+ * A19 names the base plate it cannot decide. So the fact carries the absence
11
+ * rather than a number standing in for it, and each body reads it as it always
12
+ * did.
13
+ *
14
+ * A `rigc-compiled/3` document states it (`stage`, issue #1026), and since
15
+ * issue #907 that is the only place a rigc build states it: the Spine header
16
+ * carries the setup-pose bounding box. So both suppliers read a rigc build's
17
+ * stage off its document (`spineStage` in `../../validate.ts`,
18
+ * `../model/stage.ts`); an export, which has no document, is read off its
19
+ * header.
20
+ * Links nothing from the runtime.
21
+ */
22
+
23
+ /** The stage's two extents, each `undefined` where the skeleton states none. */
24
+ export interface StageFacts {
25
+ readonly width: number | undefined;
26
+ readonly height: number | undefined;
27
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The stage box a rig asked for and what the skeleton holds there (issue
3
+ * #1168) — what `A50_STAGE_BOX_IS_THE_STAGE` reads.
4
+ *
5
+ * ⭐ **The question is asked by the model document and answered by the
6
+ * skeleton.** The document states which slot and attachment carry the stage
7
+ * (`stage.box`, `ModelStage.box`) and the stage they were written from; a Spine
8
+ * file carries no such statement, so an export, a bare directory and a
9
+ * document that states no box all ask nothing and the body SKIPs, naming which.
10
+ * What answers is read off the skeleton: through spine-core's loaded
11
+ * `SkeletonData` and a skeleton posed at setup (`spineStageBox` in
12
+ * `../../validate.ts`), or through the document's records and rigc's core
13
+ * poser (`../model/stage_box.ts`).
14
+ *
15
+ * Links nothing from the runtime.
16
+ */
17
+
18
+ /** The box the document says the rig asked for, and the stage it was written from. */
19
+ export interface StageBoxAsked {
20
+ readonly slot: string;
21
+ readonly attachment: string;
22
+ readonly stage: { readonly x: number; readonly y: number; readonly width: number; readonly height: number };
23
+ }
24
+
25
+ /** The attachment the slot carries under the asked name, in the `default` skin. */
26
+ export interface StageBoxHeld {
27
+ /**
28
+ * The attachment's type in the format's words — `boundingbox`, `region`,
29
+ * `mesh`, `clipping`, `path`, `point` — as the runtime loads it: a linked
30
+ * mesh loads as a `mesh`, so both suppliers spell it so.
31
+ */
32
+ readonly type: string;
33
+ /** Whether its vertices are bound to bones (a weighted run) rather than stated in the slot bone's space. */
34
+ readonly weighted: boolean;
35
+ /** The vertex numbers it holds as loaded — `x, y` per vertex for an unweighted box. Empty for a type that holds none. */
36
+ readonly stored: readonly number[];
37
+ /**
38
+ * Its world vertices at the setup pose — constraints applied, no physics,
39
+ * no skin set — `x, y` per vertex; or why there are none (its bone is
40
+ * inactive, the setup pose cannot be posed).
41
+ */
42
+ readonly world: readonly number[] | string;
43
+ }
44
+
45
+ /** What A50 reads. */
46
+ export interface StageBoxFacts {
47
+ /** The box the rig asked for, or `null` where nothing asks — and then `why` says what asked nothing. */
48
+ readonly asked: StageBoxAsked | null;
49
+ /** The SKIP's reason where `asked` is `null`; empty otherwise. */
50
+ readonly why: string;
51
+ /** Whether the skeleton has a slot of the asked name. */
52
+ readonly slot: boolean;
53
+ /** The `default` skin's attachment of the asked name on that slot, or `null` for none (no default skin, nothing under that name). */
54
+ readonly held: StageBoxHeld | null;
55
+ }
56
+
57
+ /**
58
+ * The SKIP wherever nothing asks: a `/3` document whose stage states no box, a
59
+ * document that declares no stage, a `/2` or `/1` document, or none at all (an
60
+ * export, a bare directory). One sentence for all of them, because the rule
61
+ * reads one fact — that no box was asked for — and two suppliers that differ
62
+ * only in whether a caller handed the document over must print one line.
63
+ */
64
+ export const SKIP_NO_STAGE_BOX =
65
+ 'nothing asks for a stage box: no rigc-compiled/3 model document beside this skeleton states one (stage.box, from the rig spec\'s skeleton.stageBox) — a rig that does not ask, or an export, carries no stage in its Spine files to measure';
@@ -0,0 +1,74 @@
1
+ /**
2
+ * The stepped poses (issue #1025, cut 4c-5a of step 4c of #380) — the census's
3
+ * F01, F18, R4 (the posed `inherit`) and R5 as A10 reads them: the skeleton's
4
+ * setup pose with every physics state reset, every animation walked on a
5
+ * LOOPING track from that pose in equal steps, and a bone's inheritance mode
6
+ * posed at one time on a fresh, non-looping track.
7
+ *
8
+ * ⭐ **A pose is handed over whole, non-finite values in place.** A10's
9
+ * subject is the first number of a pose that is not finite, so a supplier
10
+ * that refused such a pose, or wrote it as something else, would answer a
11
+ * different question. The runtime's supplier reads what spine-core posed; the
12
+ * model side's is the core's looping walk (`src/core/walk.ts`), which returns
13
+ * the value rather than refusing it.
14
+ *
15
+ * 🔸 **The inheritance mode is `null` where the pose holds a mode**, and the
16
+ * value it holds, as `String` spells it, where it holds none — the one bone
17
+ * reading that can be wrong with every number finite (#733): the runtime's
18
+ * lookup leaves a spelling it does not resolve as no mode at all.
19
+ *
20
+ * The bone timelines A10 walks for its `inherit` keys are `BoneTimelineFacts`
21
+ * (`./bone_timelines.ts`), the family A24, A29 and A30 read.
22
+ *
23
+ * Links nothing from the runtime: `validate()` supplies it from spine-core
24
+ * (`spineSteppedPoses`), the model side from the document and the core
25
+ * (`../model/stepped_poses.ts`).
26
+ */
27
+ import type { PosedVertices, WorldTransform } from '../../nonfinite.ts';
28
+
29
+ /** One bone of a pose: its world transform as computed, and its inheritance mode — `null` for a mode, else the value held. */
30
+ export interface SteppedBone extends WorldTransform {
31
+ readonly inherit: string | null;
32
+ }
33
+
34
+ /** One slot of a pose: its light colour and its dark colour (`null` for a slot holding none), as computed. */
35
+ export interface SteppedSlot {
36
+ readonly name: string;
37
+ readonly colour: readonly [number, number, number, number];
38
+ readonly dark: readonly [number, number, number] | null;
39
+ }
40
+
41
+ /** One pose: every bone in skeleton order, every region and mesh shown in draw order, every slot in setup order. */
42
+ export interface SteppedFrame {
43
+ readonly bones: readonly SteppedBone[];
44
+ readonly drawn: readonly PosedVertices[];
45
+ readonly slots: readonly SteppedSlot[];
46
+ }
47
+
48
+ /** What A10 reads. */
49
+ export interface SteppedPoseFacts {
50
+ /** The skeleton's bone count. */
51
+ readonly boneCount: number;
52
+ /** The animations, in the file's order, each with the runtime's duration (the last key of every timeline, as float32). */
53
+ readonly steppedAnimations: ReadonlyArray<{ readonly name: string; readonly duration: number }>;
54
+ /** Whether the skeleton holds an animation of this name. */
55
+ hasAnimation(name: string): boolean;
56
+ /** Whether the skeleton holds a bone of this name. */
57
+ hasBone(name: string): boolean;
58
+ /**
59
+ * The bone's inheritance mode with the animation applied at `time` on a
60
+ * fresh, non-looping track from the setup pose, every physics state reset
61
+ * before it — `null` where the pose holds a mode, else that value spelled by
62
+ * `String`, and `undefined` for a bone the skeleton does not have.
63
+ */
64
+ posedInherit(animation: string, bone: string, time: number): string | null | undefined;
65
+ /** How the file spells a bone's setup `inherit`: `JSON.stringify` of the stated value (`"undefined"` for none). */
66
+ statedInherit(bone: string): string;
67
+ /** The setup pose, every physics state reset, before any animation is set. */
68
+ setup(): SteppedFrame;
69
+ /**
70
+ * The animation set on a LOOPING track over that setup pose, then `frames`
71
+ * steps of `step` each — the poses after steps 1 to `frames`, in order.
72
+ */
73
+ walk(animation: string, step: number, frames: number): SteppedFrame[];
74
+ }