spine-rigc 1.9.2 → 1.9.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.
- package/cli.ts +28 -4397
- package/docs/AUTHORING.md +4 -4
- package/package.json +1 -1
- package/src/assertions/bodies/a06.ts +53 -3
- package/src/assertions/bodies/a13.ts +3 -3
- package/src/assertions/bodies/a14.ts +3 -3
- package/src/assertions/bodies/a15.ts +5 -5
- package/src/assertions/bodies/a19.ts +44 -2
- package/src/assertions/bodies/a22.ts +3 -3
- package/src/assertions/facts/animated_bones.ts +4 -2
- package/src/assertions/facts/mesh_attachments.ts +33 -4
- package/src/assertions/model/animated_bones.ts +13 -5
- package/src/assertions/model/bone_timelines.ts +5 -3
- package/src/assertions/model/declared.ts +127 -0
- package/src/assertions/model/index.ts +63 -40
- package/src/assertions/model/mesh_attachments.ts +31 -2
- package/src/assertions/model/parse.ts +9 -1
- package/src/assertions/model/runtime_timelines.ts +78 -0
- package/src/assertions/model/slider_composition.ts +10 -8
- package/src/assertions/model/stepped_poses.ts +3 -2
- package/src/bonedist.ts +4 -5
- package/src/check.ts +3 -2
- package/src/checkpics.ts +1 -1
- package/src/cli/core_commands.ts +1532 -0
- package/src/cli/shared.ts +1935 -0
- package/src/cli/spine_commands.ts +1141 -0
- package/src/core/additive.ts +52 -62
- package/src/core/constraints.ts +26 -3
- package/src/core/constraints_physics.ts +11 -1
- package/src/core/constraints_slider.ts +136 -6
- package/src/core/index.ts +27 -3
- package/src/core/skins.ts +28 -3
- package/src/core/walk.ts +9 -36
- package/src/correspondence.ts +15 -0
- package/src/deformbuild.ts +60 -0
- package/src/deformmeasure.ts +20 -48
- package/src/deformreport.ts +2 -2
- package/src/framing.ts +1 -1
- package/src/pose.ts +1 -1
- package/src/preview.ts +1 -1
- package/src/region_joins.ts +54 -0
- package/src/render.ts +206 -2836
- package/src/render_core.ts +19 -36
- package/src/render_shared.ts +2887 -0
- package/src/slots.ts +1 -1
- package/src/spine_side.ts +123 -0
- package/src/validate.ts +11 -91
- package/src/assertions/facts/skin_meshes.ts +0 -49
- package/src/assertions/model/skin_meshes.ts +0 -90
|
@@ -21,11 +21,14 @@
|
|
|
21
21
|
* 🔸 **What the entry is given.** The document's text, the directory its
|
|
22
22
|
* pages resolve against, and the profile — and nothing read off a Spine file:
|
|
23
23
|
* a model-side verdict that read `skeleton.json` would be a second reading of
|
|
24
|
-
* the encoding, which is the round trip's subject and not the rig's.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* the encoding, which is the round trip's subject and not the rig's. In
|
|
25
|
+
* `given`, the two values a `rigc-compiled/2` or `/1` document does not hold —
|
|
26
|
+
* the stage and each page's `pma` (`./given.ts`); a `/3` document states both
|
|
27
|
+
* (issue #1026) and is read for them, and `given` beside one is refused by
|
|
28
|
+
* name. The rig info and the declared durations are the document's on every
|
|
29
|
+
* spec (issue #1054, `./declared.ts`): cuts 4c-1 to 4c-3 took them from the
|
|
30
|
+
* caller, as `validate()` does, and the verdict moved with what the caller
|
|
31
|
+
* handed over — now either one given beside the document is refused by name.
|
|
29
32
|
*
|
|
30
33
|
* ⛔ **Not wired into any command.** `build` keeps the round trip and its
|
|
31
34
|
* forty-nine lines; this entry is what the selftest and the instrument call
|
|
@@ -50,6 +53,7 @@ import type { AtlasPageFacts } from '../facts/atlas_pages.ts';
|
|
|
50
53
|
import type { SlotColourFacts } from '../facts/slot_colour.ts';
|
|
51
54
|
import type { RigInfo } from '../../types.ts';
|
|
52
55
|
import type { ModelGiven } from './given.ts';
|
|
56
|
+
import { modelDeclaredDurations, modelRigInfo, refuseDeclaredBeside } from './declared.ts';
|
|
53
57
|
import { a08RegionNamesMatchAttachments } from '../bodies/a08.ts';
|
|
54
58
|
import { a13MeshBudget } from '../bodies/a13.ts';
|
|
55
59
|
import { a14NoFullFrameMesh } from '../bodies/a14.ts';
|
|
@@ -59,13 +63,11 @@ import { a38SkinMembersAreSkinRequired } from '../bodies/a38.ts';
|
|
|
59
63
|
import { a06AtlasPageSizeMatchesPng } from '../bodies/a06.ts';
|
|
60
64
|
import { a19OverlayPngsHaveAlpha } from '../bodies/a19.ts';
|
|
61
65
|
import { a27RegionNameMatchesPageFilename } from '../bodies/a27.ts';
|
|
62
|
-
import { modelSkinMeshes } from './skin_meshes.ts';
|
|
63
66
|
import { modelAnimatedBones } from './animated_bones.ts';
|
|
64
67
|
import { modelSkinMembers } from './skin_members.ts';
|
|
65
68
|
import { modelRegionJoins } from './region_joins.ts';
|
|
66
69
|
import { modelAtlasRegions } from './atlas_regions.ts';
|
|
67
70
|
import { modelStage } from './stage.ts';
|
|
68
|
-
import type { SkinMeshFacts } from '../facts/skin_meshes.ts';
|
|
69
71
|
import type { AnimatedBoneFacts } from '../facts/animated_bones.ts';
|
|
70
72
|
import type { SkinMemberFacts } from '../facts/skin_members.ts';
|
|
71
73
|
import type { RegionJoinFacts } from '../facts/region_joins.ts';
|
|
@@ -134,7 +136,14 @@ export interface ModelValidateInput {
|
|
|
134
136
|
/** The directory the document's page names resolve against — the build's `--out`. */
|
|
135
137
|
atlasDir: string;
|
|
136
138
|
profile: AssertionProfile;
|
|
137
|
-
/**
|
|
139
|
+
/**
|
|
140
|
+
* Refused (issue #1054): every document states the rig info in its `rig`
|
|
141
|
+
* section, and the model side reads it there (`./declared.ts`). A caller
|
|
142
|
+
* that gives it anyway is a second source for one fact, and each rule that
|
|
143
|
+
* reads the declarations refuses the call by name rather than reading
|
|
144
|
+
* either. Kept on the type so a caller still handing it over is named, not
|
|
145
|
+
* silently ignored.
|
|
146
|
+
*/
|
|
138
147
|
rig?: RigInfo;
|
|
139
148
|
/**
|
|
140
149
|
* The stage and the pages' `pma`, for a `rigc-compiled/2` or `/1` document,
|
|
@@ -144,7 +153,7 @@ export interface ModelValidateInput {
|
|
|
144
153
|
* `given` beside it is refused by name.
|
|
145
154
|
*/
|
|
146
155
|
given?: ModelGiven;
|
|
147
|
-
/**
|
|
156
|
+
/** Refused, as `rig` is (issue #1054): every document states each animation's declared duration, and A09 reads them there. */
|
|
148
157
|
declaredDurations?: Record<string, number>;
|
|
149
158
|
}
|
|
150
159
|
|
|
@@ -164,7 +173,6 @@ export interface ModelSupply {
|
|
|
164
173
|
skinEntries: (read: ReadDocument) => SkinEntryFacts;
|
|
165
174
|
atlasPages: (read: ReadDocument) => AtlasPageFacts;
|
|
166
175
|
slotColour: (read: ReadDocument) => SlotColourFacts;
|
|
167
|
-
skinMeshes: (read: ReadDocument) => SkinMeshFacts;
|
|
168
176
|
animatedBones: (read: ReadDocument) => AnimatedBoneFacts;
|
|
169
177
|
skinMembers: (read: ReadDocument) => SkinMemberFacts;
|
|
170
178
|
regionJoins: (read: ReadDocument) => RegionJoinFacts;
|
|
@@ -184,6 +192,10 @@ export interface ModelSupply {
|
|
|
184
192
|
sliderComposition: (read: ReadDocument) => SliderCompositionFacts;
|
|
185
193
|
constraintTargets: (read: ReadDocument) => ConstraintTargetFacts;
|
|
186
194
|
steppedPoses: (read: ReadDocument) => SteppedPoseFacts;
|
|
195
|
+
/** The rig info the document declares (issue #1054, `./declared.ts`); a caller's `rig` beside it is refused by name. */
|
|
196
|
+
rigInfo: (read: ReadDocument, input: ModelValidateInput) => RigInfo;
|
|
197
|
+
/** Each animation's declared duration as the document states it (issue #1054); a caller's `declaredDurations` beside it is refused by name. */
|
|
198
|
+
declaredDurations: (read: ReadDocument, input: ModelValidateInput) => Record<string, number>;
|
|
187
199
|
}
|
|
188
200
|
|
|
189
201
|
/** The suppliers the model side runs on. */
|
|
@@ -191,7 +203,6 @@ export const MODEL_SUPPLY: ModelSupply = {
|
|
|
191
203
|
skinEntries: modelSkinEntries,
|
|
192
204
|
atlasPages: modelAtlasPages,
|
|
193
205
|
slotColour: modelSlotColour,
|
|
194
|
-
skinMeshes: modelSkinMeshes,
|
|
195
206
|
animatedBones: modelAnimatedBones,
|
|
196
207
|
skinMembers: modelSkinMembers,
|
|
197
208
|
regionJoins: modelRegionJoins,
|
|
@@ -211,12 +222,21 @@ export const MODEL_SUPPLY: ModelSupply = {
|
|
|
211
222
|
sliderComposition: modelSliderComposition,
|
|
212
223
|
constraintTargets: modelConstraintTargets,
|
|
213
224
|
steppedPoses: modelSteppedPoses,
|
|
225
|
+
rigInfo: (read, input) => {
|
|
226
|
+
refuseDeclaredBeside(read, input, 'rig');
|
|
227
|
+
return modelRigInfo(read);
|
|
228
|
+
},
|
|
229
|
+
declaredDurations: (read, input) => {
|
|
230
|
+
refuseDeclaredBeside(read, input, 'declaredDurations');
|
|
231
|
+
return modelDeclaredDurations(read);
|
|
232
|
+
},
|
|
214
233
|
};
|
|
215
234
|
|
|
216
235
|
/**
|
|
217
236
|
* One moved assertion: its code, and how the model side runs its body once the
|
|
218
|
-
* document is read. The list is the registry of what has moved —
|
|
219
|
-
*
|
|
237
|
+
* document is read. The list is the registry of what has moved — a later cut
|
|
238
|
+
* puts its rows where `validate()` runs those rules, not at the end — and the
|
|
239
|
+
* selftest reads it for the codes it compares.
|
|
220
240
|
*/
|
|
221
241
|
export interface MovedAssertion {
|
|
222
242
|
code: string;
|
|
@@ -241,53 +261,56 @@ export interface MovedAssertion {
|
|
|
241
261
|
}
|
|
242
262
|
|
|
243
263
|
/**
|
|
244
|
-
* The moved assertions, in `validate()`'s report order
|
|
245
|
-
* calls stand in
|
|
264
|
+
* The moved assertions, in `validate()`'s report order — the order its `check`
|
|
265
|
+
* calls stand in, so a model-side report lists its PASS, SKIP and FAIL lines in
|
|
266
|
+
* the order the round trip's does. The seven cuts of issue #1025 appended their
|
|
267
|
+
* rows in landing order; issue #1054 put them back, and the selftest's `VF16`
|
|
268
|
+
* names a row that stands out of that order. `SKIP_NO_ATLAS` for
|
|
246
269
|
* A17 rather than `SKIP_NO_MODEL` because that is what A17 says over a missing
|
|
247
270
|
* atlas on either side: its body reads only the pages, and on this side no
|
|
248
271
|
* document means no pages.
|
|
249
272
|
*/
|
|
250
273
|
export const MOVED_ASSERTIONS: readonly MovedAssertion[] = [
|
|
251
274
|
{ code: 'A08_REGION_NAMES_MATCH_ATTACHMENTS', run: (v, read, _input, supply) => (read.doc.pages === null ? v.skip('A08_REGION_NAMES_MATCH_ATTACHMENTS', SKIP_NO_MODEL_PAGES) : a08RegionNamesMatchAttachments(v, supply.regionJoins(read), new Set<string>())), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
275
|
+
{ code: 'A32_EVENT_KEYS_RESOLVE', run: (v, read, _input, supply) => a32EventKeysResolve(v, supply.eventKeys(read)), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
276
|
+
{ code: 'A34_CONSTRAINT_TIMELINE_TARGETS', run: (v, read, _input, supply) => a34ConstraintTimelineTargets(v, supply.constraintTargets(read)), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
277
|
+
{ code: 'A12_NO_DARK_COLOR', run: (v, read, _input, supply) => a12NoDarkColor(v, supply.skeletonRoster(read), supply.slotColour(read).slotTimelines), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
252
278
|
{ code: 'A03_REGION_WIDTH_HEIGHT_FINITE', run: (v, read, _input, supply) => a03RegionWidthHeightFinite(v, supply.skinEntries(read)), unread: SKIP_NO_MODEL },
|
|
253
279
|
{ code: 'A04_MESH_TRIANGLES_AND_ENCODING', run: (v, read, _input, supply) => a04MeshTrianglesAndEncoding(v, supply.meshes(read)), unread: SKIP_NO_MODEL },
|
|
254
280
|
{ code: 'A33_VERTEX_ATTACHMENT_GEOMETRY', run: (v, read, _input, supply) => a33VertexAttachmentGeometry(v, supply.polygons(read)), unread: SKIP_NO_MODEL },
|
|
255
281
|
{ code: 'A11_NO_CLIPPING_ATTACHMENTS', run: (v, read, _input, supply) => a11NoClippingAttachments(v, supply.skinEntries(read)), unread: SKIP_NO_MODEL },
|
|
256
|
-
{ code: 'A13_MESH_BUDGET', run: (v, read, input, supply) => a13MeshBudget(v, supply.
|
|
257
|
-
{ code: 'A14_NO_FULL_FRAME_MESH', run: (v, read, input, supply) => a14NoFullFrameMesh(v, supply.
|
|
258
|
-
{ code: 'A15_IDLE_NO_MESH_BONE_KEYS', run: (v, read, input, supply) => a15IdleNoMeshBoneKeys(v, supply.
|
|
259
|
-
{ code: 'A20_MESH_WEIGHTS_COHERENT', run: (v, read, input, supply) => a20MeshWeightsCoherent(v, supply.meshes(read), input.profile === 'spine-html', input
|
|
260
|
-
{ code: 'A21_MESH_RIM_PINNED', run: (v, read, input, supply) => a21MeshRimPinned(v, supply.meshes(read), input
|
|
261
|
-
{ code: 'A22_MESH_UVS_IN_UNIT_RANGE', run: (v, read, _input, supply) => a22MeshUvsInUnitRange(v, supply.
|
|
282
|
+
{ code: 'A13_MESH_BUDGET', run: (v, read, input, supply) => a13MeshBudget(v, supply.meshes(read), { rig: supply.rigInfo(read, input) }), unread: SKIP_NO_MODEL },
|
|
283
|
+
{ code: 'A14_NO_FULL_FRAME_MESH', run: (v, read, input, supply) => a14NoFullFrameMesh(v, supply.meshes(read), supply.stage(read, input)), unread: SKIP_NO_MODEL },
|
|
284
|
+
{ code: 'A15_IDLE_NO_MESH_BONE_KEYS', run: (v, read, input, supply) => a15IdleNoMeshBoneKeys(v, supply.meshes(read), supply.animatedBones(read), { rig: supply.rigInfo(read, input) }), unread: SKIP_NO_MODEL },
|
|
285
|
+
{ code: 'A20_MESH_WEIGHTS_COHERENT', run: (v, read, input, supply) => a20MeshWeightsCoherent(v, supply.meshes(read), input.profile === 'spine-html', supply.rigInfo(read, input)), unread: SKIP_NO_MODEL },
|
|
286
|
+
{ code: 'A21_MESH_RIM_PINNED', run: (v, read, input, supply) => a21MeshRimPinned(v, supply.meshes(read), supply.rigInfo(read, input)), unread: SKIP_NO_MODEL },
|
|
287
|
+
{ code: 'A22_MESH_UVS_IN_UNIT_RANGE', run: (v, read, _input, supply) => a22MeshUvsInUnitRange(v, supply.meshes(read)), unread: SKIP_NO_MODEL },
|
|
288
|
+
{ code: 'A39_DEFORM_KEEPS_TRIANGLE_WINDING', run: (v, read, input, supply) => a39DeformKeepsTriangleWinding(v, supply.deformSurvey(read), supply.rigInfo(read, input)), unread: SKIP_NO_MODEL },
|
|
262
289
|
{ code: 'A23_PHYSICS_CONSTRAINT_EFFECTIVE', run: (v, read, _input, supply) => a23PhysicsConstraintEffective(v, supply.constraints(read), supply.meshes(read)), unread: SKIP_NO_MODEL },
|
|
263
|
-
{ code: 'A41_PHYSICS_SURVIVES_EDITOR_ROUND_TRIP', run: (v, read, input, supply) => a41PhysicsSurvivesEditorRoundTrip(v, supply.constraints(read), input
|
|
290
|
+
{ code: 'A41_PHYSICS_SURVIVES_EDITOR_ROUND_TRIP', run: (v, read, input, supply) => a41PhysicsSurvivesEditorRoundTrip(v, supply.constraints(read), supply.rigInfo(read, input)), unread: SKIP_NO_MODEL },
|
|
264
291
|
{ code: 'A36_PATH_CONSTRAINT_EFFECTIVE', run: (v, read, _input, supply) => a36PathConstraintEffective(v, supply.constraints(read)), unread: SKIP_NO_MODEL },
|
|
265
292
|
{ code: 'A37_SLIDER_CONSTRAINT_EFFECTIVE', run: (v, read, _input, supply) => a37SliderConstraintEffective(v, supply.constraints(read)), unread: SKIP_NO_MODEL },
|
|
266
|
-
{ code: 'A47_IK_CONSTRAINT_NOT_MUTED_THROUGHOUT', run: (v, read, input, supply) => a47IkConstraintNotMutedThroughout(v, supply.constraints(read), input
|
|
267
|
-
{ code: 'A48_TRANSFORM_CONSTRAINT_NOT_MUTED_THROUGHOUT', run: (v, read, input, supply) => a48TransformConstraintNotMutedThroughout(v, supply.constraints(read), input
|
|
293
|
+
{ code: 'A47_IK_CONSTRAINT_NOT_MUTED_THROUGHOUT', run: (v, read, input, supply) => a47IkConstraintNotMutedThroughout(v, supply.constraints(read), supply.rigInfo(read, input)), unread: SKIP_NO_MODEL },
|
|
294
|
+
{ code: 'A48_TRANSFORM_CONSTRAINT_NOT_MUTED_THROUGHOUT', run: (v, read, input, supply) => a48TransformConstraintNotMutedThroughout(v, supply.constraints(read), supply.rigInfo(read, input)), unread: SKIP_NO_MODEL },
|
|
295
|
+
{ code: 'A40_SLIDERS_COMPOSE_ON_A_SHARED_TARGET', run: (v, read, _input, supply) => a40SlidersComposeOnASharedTarget(v, supply.sliderComposition(read), supply.constraints(read)), unread: SKIP_NO_MODEL },
|
|
268
296
|
{ code: 'A42_DRIVEN_CONSTRAINTS_UPDATE_AFTER_THEIR_DRIVER', run: (v, read, _input, supply) => a42DrivenConstraintsUpdateAfterTheirDriver(v, supply.constraints(read)), unread: SKIP_NO_MODEL },
|
|
269
297
|
{ code: 'A38_SKIN_MEMBERS_ARE_SKIN_REQUIRED', run: (v, read, _input, supply) => a38SkinMembersAreSkinRequired(v, supply.skinMembers(read)), unread: SKIP_NO_MODEL },
|
|
298
|
+
{ code: 'A09_ANIMATION_DURATION_MATCHES_SPEC', run: (v, read, input, supply) => a09AnimationDurationMatchesSpec(v, supply.animationDurations(read), supply.declaredDurations(read, input)), unread: SKIP_NO_MODEL },
|
|
299
|
+
{ code: 'A10_NO_NAN_AFTER_STEPPING', run: (v, read, _input, supply) => a10NoNanAfterStepping(v, supply.boneTimelines(read), supply.steppedPoses(read)), unread: SKIP_NO_MODEL },
|
|
300
|
+
{ code: 'A43_TWO_COLOR_TINT_LOADS_AND_POSES_AS_WRITTEN', run: (v, read, _input, supply) => a43TwoColorTintLoadsAndPosesAsWritten(v, supply.twoColour(read)), unread: SKIP_NO_MODEL },
|
|
270
301
|
{ code: 'A45_SEPARABLE_COLOR_TIMELINES_OWN_THEIR_CHANNELS_AND_POSE_AS_WRITTEN', run: (v, read, _input, supply) => a45SeparableColorTimelinesOwnTheirChannelsAndPoseAsWritten(v, supply.slotColour(read)), unread: SKIP_NO_MODEL },
|
|
271
302
|
{ code: 'A44_LINKED_MESH_STATES_NO_GEOMETRY_OF_ITS_OWN', run: (v, read, _input, supply) => a44LinkedMeshStatesNoGeometryOfItsOwn(v, supply.links(read)), unread: SKIP_NO_MODEL },
|
|
303
|
+
{ code: 'A46_SEQUENCE_ATTACHMENTS_SHOW_THE_FRAME_THE_FILE_STATES', run: (v, read, _input, supply) => a46SequenceAttachmentsShowTheFrameTheFileStates(v, supply.sequences(read)), unread: SKIP_NO_MODEL },
|
|
272
304
|
{ code: 'A17_ATLAS_PAGE_FILES_EXIST', run: (v, read, input, supply) => a17AtlasPageFilesExist(v, supply.atlasPages(read), input), unread: SKIP_NO_ATLAS },
|
|
273
305
|
{ code: 'A06_ATLAS_PAGE_SIZE_MATCHES_PNG', run: (v, read, input, supply) => a06AtlasPageSizeMatchesPng(v, supply.atlasRegions(read, input), input, input.profile === 'spine-html'), unread: SKIP_NO_ATLAS },
|
|
274
|
-
{ code: 'A19_OVERLAY_PNGS_HAVE_ALPHA', run: (v, read, input, supply) => a19OverlayPngsHaveAlpha(v, supply.atlasRegions(read, input), supply.stage(read, input), supply.skinEntries(read), input), unread: SKIP_NO_ATLAS },
|
|
306
|
+
{ code: 'A19_OVERLAY_PNGS_HAVE_ALPHA', run: (v, read, input, supply) => a19OverlayPngsHaveAlpha(v, supply.atlasRegions(read, input), supply.stage(read, input), supply.skinEntries(read), { atlasDir: input.atlasDir, rig: supply.rigInfo(read, input) }), unread: SKIP_NO_ATLAS },
|
|
307
|
+
{ code: 'A24_AXIS_SPACE_STROKE', run: (v, read, input, supply) => a24AxisSpaceStroke(v, supply.boneTimelines(read), { rig: supply.rigInfo(read, input) }), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
308
|
+
{ code: 'A25_DETACHED_BONE_PARENTAGE', run: (v, read, input, supply) => a25DetachedBoneParentage(v, supply.skeletonRoster(read), { rig: supply.rigInfo(read, input) }), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
309
|
+
{ code: 'A26_SLOT_DRAW_ORDER', run: (v, read, input, supply) => a26SlotDrawOrder(v, supply.skeletonRoster(read), { rig: supply.rigInfo(read, input) }), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
275
310
|
{ code: 'A27_REGION_NAME_MATCHES_PAGE_FILENAME', run: (v, read, input, supply) => a27RegionNameMatchesPageFilename(v, supply.atlasRegions(read, input)), unread: SKIP_NO_ATLAS },
|
|
276
|
-
{ code: 'A28_RIBBON_ROWS_SHARE_WEIGHTS', run: (v, read, input, supply) => a28RibbonRowsShareWeights(v, supply.meshes(read), input
|
|
277
|
-
{ code: '
|
|
278
|
-
{ code: '
|
|
279
|
-
{ code: 'A24_AXIS_SPACE_STROKE', run: (v, read, input, supply) => a24AxisSpaceStroke(v, supply.boneTimelines(read), input), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
280
|
-
{ code: 'A25_DETACHED_BONE_PARENTAGE', run: (v, read, input, supply) => a25DetachedBoneParentage(v, supply.skeletonRoster(read), input), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
281
|
-
{ code: 'A26_SLOT_DRAW_ORDER', run: (v, read, input, supply) => a26SlotDrawOrder(v, supply.skeletonRoster(read), input), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
282
|
-
{ code: 'A29_STROKE_WITHIN_CONTACT_DEPTH', run: (v, read, input, supply) => a29StrokeWithinContactDepth(v, supply.boneTimelines(read), input), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
283
|
-
{ code: 'A30_STROKE_WITHIN_CAP_CONTAINMENT', run: (v, read, input, supply) => a30StrokeWithinCapContainment(v, supply.boneTimelines(read), input), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
284
|
-
{ code: 'A39_DEFORM_KEEPS_TRIANGLE_WINDING', run: (v, read, input, supply) => a39DeformKeepsTriangleWinding(v, supply.deformSurvey(read), input.rig), unread: SKIP_NO_MODEL },
|
|
285
|
-
{ code: 'A09_ANIMATION_DURATION_MATCHES_SPEC', run: (v, read, input, supply) => a09AnimationDurationMatchesSpec(v, supply.animationDurations(read), input.declaredDurations), unread: SKIP_NO_MODEL },
|
|
286
|
-
{ code: 'A43_TWO_COLOR_TINT_LOADS_AND_POSES_AS_WRITTEN', run: (v, read, _input, supply) => a43TwoColorTintLoadsAndPosesAsWritten(v, supply.twoColour(read)), unread: SKIP_NO_MODEL },
|
|
287
|
-
{ code: 'A46_SEQUENCE_ATTACHMENTS_SHOW_THE_FRAME_THE_FILE_STATES', run: (v, read, _input, supply) => a46SequenceAttachmentsShowTheFrameTheFileStates(v, supply.sequences(read)), unread: SKIP_NO_MODEL },
|
|
288
|
-
{ code: 'A40_SLIDERS_COMPOSE_ON_A_SHARED_TARGET', run: (v, read, _input, supply) => a40SlidersComposeOnASharedTarget(v, supply.sliderComposition(read), supply.constraints(read)), unread: SKIP_NO_MODEL },
|
|
289
|
-
{ code: 'A34_CONSTRAINT_TIMELINE_TARGETS', run: (v, read, _input, supply) => a34ConstraintTimelineTargets(v, supply.constraintTargets(read)), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
290
|
-
{ code: 'A10_NO_NAN_AFTER_STEPPING', run: (v, read, _input, supply) => a10NoNanAfterStepping(v, supply.boneTimelines(read), supply.steppedPoses(read)), unread: SKIP_NO_MODEL },
|
|
311
|
+
{ code: 'A28_RIBBON_ROWS_SHARE_WEIGHTS', run: (v, read, input, supply) => a28RibbonRowsShareWeights(v, supply.meshes(read), supply.rigInfo(read, input)), unread: SKIP_NO_MODEL },
|
|
312
|
+
{ code: 'A29_STROKE_WITHIN_CONTACT_DEPTH', run: (v, read, input, supply) => a29StrokeWithinContactDepth(v, supply.boneTimelines(read), { rig: supply.rigInfo(read, input) }), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
313
|
+
{ code: 'A30_STROKE_WITHIN_CAP_CONTAINMENT', run: (v, read, input, supply) => a30StrokeWithinCapContainment(v, supply.boneTimelines(read), { rig: supply.rigInfo(read, input) }), unread: SKIP_NO_MODEL, beforeTheParse: true },
|
|
291
314
|
];
|
|
292
315
|
|
|
293
316
|
/** The codes the model side prints: its two parse rules, then the moved assertions. */
|
|
@@ -16,12 +16,21 @@
|
|
|
16
16
|
* — the two lookups the core poses a linked mesh through — and its hull
|
|
17
17
|
* the source record's, read where those two read it.
|
|
18
18
|
* - **The counts the parser derives**: `worldVerticesLength` is the length
|
|
19
|
-
* of `uvs` (the length the parser hands its vertex reader for a mesh
|
|
19
|
+
* of `uvs` (the length the parser hands its vertex reader for a mesh — the
|
|
20
|
+
* reader refuses a document whose `uvs` are not one pair per vertex, so it is
|
|
21
|
+
* also two per vertex), and
|
|
20
22
|
* `hullLength` twice the record's `hull`, which the parser reads at the
|
|
21
23
|
* mesh row's default of the parser-default table when the key is absent
|
|
22
24
|
* (`PARSER_DEFAULTS` in `src/keyorder.ts`, which the selftest holds to the
|
|
23
25
|
* parser row by row).
|
|
24
26
|
*
|
|
27
|
+
* - **`width` and `height`** are the record's, off the document's JSON — a
|
|
28
|
+
* link's its source record's, the two numbers the runtime's `setSourceMesh`
|
|
29
|
+
* writes over the link's own: the core's geometry reader keeps a mesh's
|
|
30
|
+
* vertices, UVs and triangles and not its size, which no pose reads. Since
|
|
31
|
+
* issue #1054 this is the one family of the meshes; cut 4c-1's
|
|
32
|
+
* `SkinMeshFacts` stated the same entries with these two numbers added.
|
|
33
|
+
*
|
|
25
34
|
* `encoding` is empty on every entry: the document states the weighted form
|
|
26
35
|
* outright and names bones, so the clauses about the flat run have no subject
|
|
27
36
|
* here (`../facts/mesh_attachments.ts`'s 🔒).
|
|
@@ -35,6 +44,19 @@ import type { ModelVertices } from '../../model.ts';
|
|
|
35
44
|
import type { MeshBinding, MeshEntry, MeshFacts } from '../facts/mesh_attachments.ts';
|
|
36
45
|
import { fileOrderedEntries } from './skin_entries.ts';
|
|
37
46
|
import type { ReadDocument } from './parse.ts';
|
|
47
|
+
import { isObj } from '../values.ts';
|
|
48
|
+
|
|
49
|
+
/** A record's own `width` and `height` as the document states them, found by skin (the first of that name, as a link resolves its skin), slot and placeholder. */
|
|
50
|
+
function statedSize(read: ReadDocument, skin: string, slot: string, placeholder: string): { width: number; height: number } {
|
|
51
|
+
const skins = Array.isArray(read.json.skins) ? read.json.skins : [];
|
|
52
|
+
const found = skins.find((k: unknown) => isObj(k) && k.name === skin);
|
|
53
|
+
const table = isObj(found) && isObj(found.attachments) ? found.attachments[slot] : undefined;
|
|
54
|
+
const record = isObj(table) ? table[placeholder] : undefined;
|
|
55
|
+
if (!isObj(record) || typeof record.width !== 'number' || typeof record.height !== 'number') {
|
|
56
|
+
throw new Error(`internal: skin "${skin}" slot "${slot}" placeholder "${placeholder}" is a mesh record the document states no width and height for`);
|
|
57
|
+
}
|
|
58
|
+
return { width: record.width, height: record.height };
|
|
59
|
+
}
|
|
38
60
|
|
|
39
61
|
/** The parser's reading of a mesh with no `hull` key, off the parser-default table. */
|
|
40
62
|
function hullDefault(): number {
|
|
@@ -58,8 +80,10 @@ export function modelMeshFacts(read: ReadDocument): MeshFacts {
|
|
|
58
80
|
let uvs: readonly number[];
|
|
59
81
|
let triangles: readonly number[];
|
|
60
82
|
let hull: number | undefined;
|
|
83
|
+
let size: { width: number; height: number };
|
|
61
84
|
if (g.kind === 'mesh') {
|
|
62
85
|
({ vertices, uvs, triangles, hull } = g);
|
|
86
|
+
size = statedSize(read, entry.skin, entry.slot, entry.placeholder);
|
|
63
87
|
} else {
|
|
64
88
|
// `readModel` resolves every link to a mesh or refuses the document, so a miss here is this module's defect.
|
|
65
89
|
const found = sourceVertices(g.skin, g.slot, g.source);
|
|
@@ -69,19 +93,24 @@ export function modelMeshFacts(read: ReadDocument): MeshFacts {
|
|
|
69
93
|
({ uvs, triangles } = drawn);
|
|
70
94
|
const source = doc.skins.find((k) => k.name === g.skin)?.attachments[g.slot]?.[g.source]?.geometry;
|
|
71
95
|
hull = source?.kind === 'mesh' ? source.hull : undefined;
|
|
96
|
+
size = statedSize(read, g.skin, g.slot, g.source);
|
|
72
97
|
}
|
|
98
|
+
const bone = slotBone.get(entry.slot);
|
|
99
|
+
if (bone === undefined) throw new Error(`internal: ${where} names a slot the reader accepted and the document does not hold`);
|
|
73
100
|
const weights: MeshBinding[][] | null = vertices.weighted ? vertices.bindings.map((influences) => influences.map((b) => ({ bone: indexOf(b.bone), weight: Math.fround(b.weight) }))) : null;
|
|
74
101
|
meshes.push({
|
|
75
102
|
name: shownRow(entry).name,
|
|
76
103
|
skin: entry.skin,
|
|
77
104
|
slot: entry.slot,
|
|
78
|
-
slotBone:
|
|
105
|
+
slotBone: bone,
|
|
79
106
|
placeholder: entry.placeholder,
|
|
80
107
|
link: g.kind === 'linkedmesh' ? { source: g.source } : null,
|
|
81
108
|
triangles,
|
|
82
109
|
worldVerticesLength: uvs.length,
|
|
83
110
|
regionUVs: uvs,
|
|
84
111
|
hullLength: 2 * (hull ?? hullDefault()),
|
|
112
|
+
width: size.width,
|
|
113
|
+
height: size.height,
|
|
85
114
|
weights,
|
|
86
115
|
encoding: [],
|
|
87
116
|
});
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
import { CORE_REGION_KINDS, CoreInputError, readModel, shownRow, type CompiledDocument } from '../../core/index.ts';
|
|
41
41
|
import { documentPageLookup, frameRegionName, readUvSequences } from '../../core/uvs.ts';
|
|
42
42
|
import type { AssertionKind } from '../kinds.ts';
|
|
43
|
+
import { rigSectionProblems } from './declared.ts';
|
|
43
44
|
import type { Verdicts } from '../harness.ts';
|
|
44
45
|
|
|
45
46
|
/** The reader's refusal, as a line. */
|
|
@@ -76,7 +77,14 @@ export function modelRead({ fail }: Verdicts, modelText: string): ReadDocument |
|
|
|
76
77
|
fail(A00_MODEL_READ, err.message);
|
|
77
78
|
return null;
|
|
78
79
|
}
|
|
79
|
-
|
|
80
|
+
const json = JSON.parse(modelText) as Record<string, unknown>;
|
|
81
|
+
// Issue #1054: the rig section is a source the model side reads (`./declared.ts`), so it is read here with the rest — refused by its paths, never cast.
|
|
82
|
+
const rigProblems = rigSectionProblems(json);
|
|
83
|
+
if (rigProblems.length > 0) {
|
|
84
|
+
fail(A00_MODEL_READ, `the model document: ${rigProblems.length} problem(s) in the rig section the model side reads its declarations from: ${rigProblems.join('; ')}`);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return { doc, json };
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
/**
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The runtime's words for each timeline a document's animation can hold
|
|
3
|
+
* (issue #1054): the class it loads as, the property ids it registers and what
|
|
4
|
+
* those ids carry — the values A40's sentence prints, which the document has no
|
|
5
|
+
* field for and the core has no reason to know.
|
|
6
|
+
*
|
|
7
|
+
* ⭐ **Why they live here and not beside the core's table.** Until issue #1054
|
|
8
|
+
* this table stood in `src/core/additive.ts`, beside the mode each kind's
|
|
9
|
+
* application has: 34 runtime class names and their property names as string
|
|
10
|
+
* literals in a module that otherwise speaks the document's words (#1011's
|
|
11
|
+
* second ask). The mode is the core's — it decides what the probe computes —
|
|
12
|
+
* and stays there, keyed by the document's own words (`ADDITIVE_MODE`); what
|
|
13
|
+
* the runtime calls the timeline is a fact about the validator's other
|
|
14
|
+
* supplier, and sits here with the constraint classes' names
|
|
15
|
+
* (`RUNTIME_CONSTRAINT_CLASS`, `./constraints.ts`). Both tables are keyed by
|
|
16
|
+
* the same spelling (`additiveSpelling`), and the selftest's `CO27` holds
|
|
17
|
+
* every row of both against the timeline objects spine-core loads, over a
|
|
18
|
+
* seeded population reaching every spelling.
|
|
19
|
+
*
|
|
20
|
+
* Read off the loaded timeline objects, never written from the runtime's
|
|
21
|
+
* source: the class is the object's constructor name, the properties its
|
|
22
|
+
* registered ids' names.
|
|
23
|
+
*
|
|
24
|
+
* Links nothing from the runtime.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** What a timeline's property ids are followed by: its target's index (and, for an attachment's, the attachment), or nothing. */
|
|
28
|
+
export type RuntimeTimelineAddress = 'bone' | 'slot' | 'attachment' | 'constraint' | 'none';
|
|
29
|
+
|
|
30
|
+
/** One timeline spelling, as the runtime loads it: its class, the properties it registers in order, and what its ids carry. */
|
|
31
|
+
export interface RuntimeTimelineRow {
|
|
32
|
+
runtimeClass: string;
|
|
33
|
+
properties: readonly string[];
|
|
34
|
+
address: RuntimeTimelineAddress;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const row = (runtimeClass: string, properties: readonly string[], address: RuntimeTimelineAddress): RuntimeTimelineRow => ({ runtimeClass, properties, address });
|
|
38
|
+
|
|
39
|
+
/** Every timeline spelling a document's animation can hold (`additiveSpelling`'s keys), as the runtime loads it. */
|
|
40
|
+
export const RUNTIME_TIMELINE: Readonly<Record<string, RuntimeTimelineRow>> = {
|
|
41
|
+
'bone rotate': row('RotateTimeline', ['rotate'], 'bone'),
|
|
42
|
+
'bone translate': row('TranslateTimeline', ['x', 'y'], 'bone'),
|
|
43
|
+
'bone translatex': row('TranslateXTimeline', ['x'], 'bone'),
|
|
44
|
+
'bone translatey': row('TranslateYTimeline', ['y'], 'bone'),
|
|
45
|
+
'bone scale': row('ScaleTimeline', ['scaleX', 'scaleY'], 'bone'),
|
|
46
|
+
'bone scalex': row('ScaleXTimeline', ['scaleX'], 'bone'),
|
|
47
|
+
'bone scaley': row('ScaleYTimeline', ['scaleY'], 'bone'),
|
|
48
|
+
'bone shear': row('ShearTimeline', ['shearX', 'shearY'], 'bone'),
|
|
49
|
+
'bone shearx': row('ShearXTimeline', ['shearX'], 'bone'),
|
|
50
|
+
'bone sheary': row('ShearYTimeline', ['shearY'], 'bone'),
|
|
51
|
+
'bone inherit': row('InheritTimeline', ['inherit'], 'bone'),
|
|
52
|
+
'slot attachment': row('AttachmentTimeline', ['attachment'], 'slot'),
|
|
53
|
+
'slot rgba': row('RGBATimeline', ['rgb', 'alpha'], 'slot'),
|
|
54
|
+
'slot rgb': row('RGBTimeline', ['rgb'], 'slot'),
|
|
55
|
+
'slot alpha': row('AlphaTimeline', ['alpha'], 'slot'),
|
|
56
|
+
'slot rgba2': row('RGBA2Timeline', ['rgb', 'alpha', 'rgb2'], 'slot'),
|
|
57
|
+
'slot rgb2': row('RGB2Timeline', ['rgb', 'rgb2'], 'slot'),
|
|
58
|
+
'attachment deform': row('DeformTimeline', ['deform'], 'attachment'),
|
|
59
|
+
'attachment sequence': row('SequenceTimeline', ['sequence'], 'attachment'),
|
|
60
|
+
ik: row('IkConstraintTimeline', ['ikConstraint'], 'constraint'),
|
|
61
|
+
transform: row('TransformConstraintTimeline', ['transformConstraint'], 'constraint'),
|
|
62
|
+
'path position': row('PathConstraintPositionTimeline', ['pathConstraintPosition'], 'constraint'),
|
|
63
|
+
'path spacing': row('PathConstraintSpacingTimeline', ['pathConstraintSpacing'], 'constraint'),
|
|
64
|
+
'path mix': row('PathConstraintMixTimeline', ['pathConstraintMix'], 'constraint'),
|
|
65
|
+
'physics inertia': row('PhysicsConstraintInertiaTimeline', ['physicsConstraintInertia'], 'constraint'),
|
|
66
|
+
'physics strength': row('PhysicsConstraintStrengthTimeline', ['physicsConstraintStrength'], 'constraint'),
|
|
67
|
+
'physics damping': row('PhysicsConstraintDampingTimeline', ['physicsConstraintDamping'], 'constraint'),
|
|
68
|
+
'physics mass': row('PhysicsConstraintMassTimeline', ['physicsConstraintMass'], 'constraint'),
|
|
69
|
+
'physics wind': row('PhysicsConstraintWindTimeline', ['physicsConstraintWind'], 'constraint'),
|
|
70
|
+
'physics gravity': row('PhysicsConstraintGravityTimeline', ['physicsConstraintGravity'], 'constraint'),
|
|
71
|
+
'physics mix': row('PhysicsConstraintMixTimeline', ['physicsConstraintMix'], 'constraint'),
|
|
72
|
+
// A reset registers its property with no constraint index, named or not (measured: both read `physicsConstraintReset`).
|
|
73
|
+
'physics reset': row('PhysicsConstraintResetTimeline', ['physicsConstraintReset'], 'none'),
|
|
74
|
+
'slider time': row('SliderTimeline', ['sliderTime'], 'constraint'),
|
|
75
|
+
'slider mix': row('SliderMixTimeline', ['sliderMix'], 'constraint'),
|
|
76
|
+
drawOrder: row('DrawOrderTimeline', ['drawOrder'], 'none'),
|
|
77
|
+
events: row('EventTimeline', ['event'], 'none'),
|
|
78
|
+
};
|
|
@@ -16,16 +16,17 @@
|
|
|
16
16
|
* timelines at their three levels in the order the file keys them
|
|
17
17
|
* (`keyedOrder` over the document's order, deform before sequence —
|
|
18
18
|
* `emitAttachmentTimelines`' order), then the draw order and the events.
|
|
19
|
-
* - **The words.** Each timeline's class name and properties are the
|
|
20
|
-
* table (`
|
|
21
|
-
*
|
|
19
|
+
* - **The words.** Each timeline's class name and properties are the
|
|
20
|
+
* validator's table (`RUNTIME_TIMELINE`, `./runtime_timelines.ts`; the
|
|
21
|
+
* core's until issue #1054), the one value here that is not the document's,
|
|
22
|
+
* measured off the loaded timelines; an id's index is
|
|
22
23
|
* the target's position in the document's bones, slots or constraints —
|
|
23
24
|
* which the emitter writes in that order — `-1` for a physics timeline
|
|
24
25
|
* naming none; a deform's attachment is named as the runtime names it, the
|
|
25
26
|
* record's `name`, else its placeholder.
|
|
26
27
|
* - **The behaviour** is the core's probe over the document under no skin set
|
|
27
|
-
* (`noSkinView`,
|
|
28
|
-
*
|
|
28
|
+
* (`noSkinView`, the view measured in issue #1051) and under each skin
|
|
29
|
+
* (`underSkin`): `additiveCells`, and the
|
|
29
30
|
* class `additiveBehaviour` reads off them. The core suite's `CO27` holds
|
|
30
31
|
* both to the runtime's probe; the selftest asks this supplier every
|
|
31
32
|
* question the body asks the runtime's (`VF14`).
|
|
@@ -33,7 +34,8 @@
|
|
|
33
34
|
* Links nothing from the runtime.
|
|
34
35
|
*/
|
|
35
36
|
import { fileSkinOrder, keyedOrder } from '../../compile.ts';
|
|
36
|
-
import {
|
|
37
|
+
import { additiveBehaviour, additiveCells, additiveSpelling, type AdditiveTimeline, type AdditiveView } from '../../core/additive.ts';
|
|
38
|
+
import { RUNTIME_TIMELINE } from './runtime_timelines.ts';
|
|
37
39
|
import { EVERY_GLOBAL_PHYSICS, type PhysicsTimelineKind } from '../../core/constraints_physics.ts';
|
|
38
40
|
import { underSkin, type CompiledDocument } from '../../core/index.ts';
|
|
39
41
|
import type { BoneTimelineKind, SlotTimelineKind } from '../../core/animation.ts';
|
|
@@ -57,8 +59,8 @@ const keyedFirsts = (names: readonly string[]): string[] => keyedOrder(names.fil
|
|
|
57
59
|
|
|
58
60
|
/** The words of one timeline: the table's class and properties, each id addressed by `index` (and `attachment`), and the sentence's naming. */
|
|
59
61
|
function factOf(doc: CompiledDocument, core: AdditiveTimeline): SliderTimelineFact {
|
|
60
|
-
const row =
|
|
61
|
-
if (row === undefined) throw new Error(`internal: "${additiveSpelling(core)}" is no row of the
|
|
62
|
+
const row = RUNTIME_TIMELINE[additiveSpelling(core)];
|
|
63
|
+
if (row === undefined) throw new Error(`internal: "${additiveSpelling(core)}" is no row of the runtime's timeline table`);
|
|
62
64
|
const property = (p: string, index: number | null, attachment: string | null, names: string) => ({
|
|
63
65
|
id: [p, ...(index === null ? [] : [String(index)]), ...(attachment === null ? [] : [attachment])].join('|'),
|
|
64
66
|
property: p,
|
|
@@ -21,8 +21,9 @@
|
|
|
21
21
|
* name, so on this side every bone of every pose holds one and the answer is
|
|
22
22
|
* `null` — derived from the pose rather than assumed, so a reader that
|
|
23
23
|
* started admitting such a spelling would show up here as a bone with none.
|
|
24
|
-
* - **Under no skin set**, as `validate()` poses (`noSkinView
|
|
25
|
-
*
|
|
24
|
+
* - **Under no skin set**, as `validate()` poses (`noSkinView`, the view
|
|
25
|
+
* measured in issue #1051: no skin's bones or constraints applied, a slot
|
|
26
|
+
* looked up in the default skin alone).
|
|
26
27
|
*
|
|
27
28
|
* Links nothing from the runtime.
|
|
28
29
|
*/
|
package/src/bonedist.ts
CHANGED
|
@@ -84,14 +84,13 @@ import {
|
|
|
84
84
|
type BoneSnapshot,
|
|
85
85
|
type Posable,
|
|
86
86
|
} from './render.ts';
|
|
87
|
+
import { BONEDIST_SPEC, IDENTITY_CORRESPONDENCE } from './correspondence.ts';
|
|
87
88
|
|
|
88
89
|
export class BoneDistError extends Error {}
|
|
89
90
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
/** What `--bones identity` is spelled as, where a file path would go. */
|
|
94
|
-
export const IDENTITY_CORRESPONDENCE = 'identity';
|
|
91
|
+
// `BONEDIST_SPEC` and `IDENTITY_CORRESPONDENCE` are `./correspondence.ts`'s since issue #1052: the CLI's help names
|
|
92
|
+
// both, and an entry that links nothing of the runtime prints that help. Re-exported here.
|
|
93
|
+
export { BONEDIST_SPEC, IDENTITY_CORRESPONDENCE };
|
|
95
94
|
|
|
96
95
|
/** How many bones the report's per-bone table shows before it says "and N more". */
|
|
97
96
|
export const BONE_TABLE_ROWS = 8;
|
package/src/check.ts
CHANGED
|
@@ -92,13 +92,14 @@ import {
|
|
|
92
92
|
type FramesSidecar,
|
|
93
93
|
type FrameSet,
|
|
94
94
|
type MakeCorePoser,
|
|
95
|
-
type Posable,
|
|
96
95
|
type PoseOptions,
|
|
97
96
|
type Poser,
|
|
98
97
|
type PoserName,
|
|
99
98
|
type TextureSubstitution,
|
|
100
99
|
type Viewport,
|
|
101
|
-
} from './
|
|
100
|
+
} from './render_shared.ts';
|
|
101
|
+
// The one name here that is the runtime's: a candidate's pages, read off the shape spine-core's loader returns.
|
|
102
|
+
import type { Posable } from './render.ts';
|
|
102
103
|
import {
|
|
103
104
|
applyFit,
|
|
104
105
|
boxHeight,
|
package/src/checkpics.ts
CHANGED
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
type Framing,
|
|
49
49
|
type FrameCheck,
|
|
50
50
|
} from './check.ts';
|
|
51
|
-
import { FRAMES_SIDECAR, FRAMES_SPEC } from './
|
|
51
|
+
import { FRAMES_SIDECAR, FRAMES_SPEC } from './render_shared.ts';
|
|
52
52
|
import { isContent } from './framing.ts';
|
|
53
53
|
import { isAttributable } from './slots.ts';
|
|
54
54
|
import { encodePng, Plate, type RGBA } from '../tools/plate.ts';
|