rig-c 2.36.0 → 2.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/animation.ts +81 -16
- package/src/core/deform.ts +11 -2
- package/src/core/entry.ts +4 -1
- package/src/core/raw.ts +92 -15
- package/src/core/track.ts +5 -0
- package/src/core/tracks.ts +1262 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rig-c",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.37.0",
|
|
4
4
|
"description": "AI-authored 2D rigging and animation, verified before it is written. rigc compiles a rig spec into skeleton data in the Spine 4.3 format, gates it with named assertions held to a spine-core round trip's verdicts, and emits nothing that fails. Ships as an agent skill.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/core/animation.ts
CHANGED
|
@@ -824,22 +824,13 @@ export function posedSlots(
|
|
|
824
824
|
/** Filled with each slot's placeholder once the sample's own timelines have moved it, before the sliders — what the attachments are posed from (`attachmentStates`). */
|
|
825
825
|
placeholders?: Map<string, string | null>,
|
|
826
826
|
): { rows: CoreSlotRow[]; conflicts: string[] } {
|
|
827
|
-
const resolve = plant.shown ?? shownAttachment;
|
|
828
827
|
const colour = plant.colour ?? readColour;
|
|
829
|
-
const blend = plant.blend ?? readBlend;
|
|
830
|
-
const round = plant.round ?? gridRound;
|
|
831
828
|
const byName = new Map(timelines.slots.map((s) => [s.name, s]));
|
|
832
|
-
|
|
833
|
-
const conflicts: string[] = [];
|
|
834
|
-
const active = activeBones(doc);
|
|
835
|
-
const gate = plant.slotTimelines ?? slotTimelinesApply;
|
|
836
|
-
for (const slot of doc.slots) {
|
|
829
|
+
return slotRowsFrom(doc, plant, sliders, placeholders, (slot, live) => {
|
|
837
830
|
let placeholder = slot.setup;
|
|
838
831
|
const light = slot.color === undefined ? [1, 1, 1, 1] : colour(slot.color);
|
|
839
832
|
const setupDark = slot.dark === undefined ? null : readColour(slot.dark);
|
|
840
833
|
const dark = setupDark === null ? null : [setupDark[0], setupDark[1], setupDark[2]];
|
|
841
|
-
// A slot on a bone the skin leaves inactive is not animated — not by the sample's timelines, not by a slider (`./skins.ts`).
|
|
842
|
-
const live = gate(doc, slot, active);
|
|
843
834
|
for (const tl of live ? (byName.get(slot.name)?.timelines ?? []) : []) {
|
|
844
835
|
if (tl.kind === 'attachment') {
|
|
845
836
|
const key = keyAt(tl.keys, t, plant);
|
|
@@ -855,6 +846,48 @@ export function posedSlots(
|
|
|
855
846
|
else if (dark !== null && setupDark !== null) dark[at - 4] = v === null ? setupDark[at - 4] : clamp01(v[i]);
|
|
856
847
|
});
|
|
857
848
|
}
|
|
849
|
+
return { placeholder, light, dark };
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* What a slot holds once the timelines have posed it and before the sliders:
|
|
855
|
+
* the placeholder it shows, its light colour and its dark one (`null` where
|
|
856
|
+
* the slot states none). `posedSlots` reads it off one animation at `t`; the
|
|
857
|
+
* live tracks off their mixed entries (`./tracks.ts`, issue #1336).
|
|
858
|
+
*/
|
|
859
|
+
export interface SlotBase {
|
|
860
|
+
placeholder: string | null;
|
|
861
|
+
light: number[];
|
|
862
|
+
dark: number[] | null;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* The slot rows from each slot's `SlotBase` — `baseOf`, called once per slot
|
|
867
|
+
* in the document's order with whether the slot is animated at all — then the
|
|
868
|
+
* sliders, the resolution and the oracle's row: `posedSlots`' body past the
|
|
869
|
+
* timelines, which the live tracks share (`./tracks.ts`).
|
|
870
|
+
*/
|
|
871
|
+
export function slotRowsFrom(
|
|
872
|
+
doc: CompiledDocument,
|
|
873
|
+
plant: TimelinePlant,
|
|
874
|
+
sliders: readonly SliderApplication[],
|
|
875
|
+
placeholders: Map<string, string | null> | undefined,
|
|
876
|
+
baseOf: (slot: ModelSlot, live: boolean) => SlotBase,
|
|
877
|
+
): { rows: CoreSlotRow[]; conflicts: string[] } {
|
|
878
|
+
const resolve = plant.shown ?? shownAttachment;
|
|
879
|
+
const blend = plant.blend ?? readBlend;
|
|
880
|
+
const round = plant.round ?? gridRound;
|
|
881
|
+
const rows: CoreSlotRow[] = [];
|
|
882
|
+
const conflicts: string[] = [];
|
|
883
|
+
const active = activeBones(doc);
|
|
884
|
+
const gate = plant.slotTimelines ?? slotTimelinesApply;
|
|
885
|
+
for (const slot of doc.slots) {
|
|
886
|
+
// A slot on a bone the skin leaves inactive is not animated — not by the sample's timelines, not by a slider (`./skins.ts`).
|
|
887
|
+
const live = gate(doc, slot, active);
|
|
888
|
+
const base = baseOf(slot, live);
|
|
889
|
+
let placeholder = base.placeholder;
|
|
890
|
+
const { light, dark } = base;
|
|
858
891
|
// The sliders, after the animation, in constraint order (`./constraints_slider.ts`).
|
|
859
892
|
// What the slot shows after the sample's own timelines: the attachments' deform and sequence timelines are matched against it (`./deform.ts`, *A switch*).
|
|
860
893
|
placeholders?.set(slot.name, placeholder);
|
|
@@ -953,16 +986,14 @@ function stepRows(posed: PosedStep): CoreBoneRow[] {
|
|
|
953
986
|
|
|
954
987
|
/** `posedBoneWorld` up to its rows, refusing a bone the evaluator gave no transform (`PosedStep`). */
|
|
955
988
|
function posedBoneStep(doc: CompiledDocument, timelines: CoreAnimationTimelines, t: number, plant: TimelinePlant, constraints: CoreConstraintTimelines | undefined, sliders: SliderApplication[] | undefined, step: PoseStep | undefined): PosedStep {
|
|
956
|
-
const active = activeBones(doc);
|
|
957
989
|
const bones = posedBones(doc, timelines, t, plant);
|
|
990
|
+
// One step of the stepped phase (issue #956, `./constraints_physics.ts`): the physics records posed by their timelines and stepped under the walk's context; the deformed curve a path walks as above.
|
|
991
|
+
if (constraints !== undefined && step !== undefined) return steppedLocals(doc, bones, plant, () => pathDeformed(doc, posedRecords(constraintRecords(doc), constraints, t), timelines, t, plant), constraints.physicsKeyed ?? [], t, sliders, step);
|
|
992
|
+
const active = activeBones(doc);
|
|
958
993
|
// The caller's adjustment, after the timelines and before anything reads the locals (`LocalAdjust`).
|
|
959
994
|
if (step?.adjust !== undefined) adjustLocals(doc, bones, step.adjust);
|
|
960
995
|
let world = (plant.evaluate ?? worldTransforms)(bones, active);
|
|
961
|
-
if (constraints !== undefined
|
|
962
|
-
// One step of the stepped phase (issue #956, `./constraints_physics.ts`): the physics records posed by their timelines and stepped under the walk's context; the deformed curve a path walks as above. No previous pass: under the step it is the previous step's, and `poseAnimations` leaves such bones out.
|
|
963
|
-
const records = stepPhysicsRecords(pathDeformed(doc, posedRecords(constraintRecords(doc), constraints, t), timelines, t, plant), constraints.physicsKeyed ?? [], t, active, step.ctx, step.before);
|
|
964
|
-
world = applyConstraints(bones, world, active, plant.constraints ? plant.constraints(records) : records, null, sliders, step.ctx, undefined, solverRules(plant.solver));
|
|
965
|
-
} else if (constraints !== undefined) {
|
|
996
|
+
if (constraints !== undefined) {
|
|
966
997
|
const setupRecords = constraintRecords(doc);
|
|
967
998
|
// A path walks the curve the sample's deform timelines left on its slot (`./deform.ts`); a slider's deform of a walked path leaves the bones out (`pathAnimationsWhy`).
|
|
968
999
|
const records = pathDeformed(doc, posedRecords(setupRecords, constraints, t), timelines, t, plant);
|
|
@@ -974,6 +1005,40 @@ function posedBoneStep(doc: CompiledDocument, timelines: CoreAnimationTimelines,
|
|
|
974
1005
|
return { bones, world, active, round: plant.round ?? gridRound };
|
|
975
1006
|
}
|
|
976
1007
|
|
|
1008
|
+
/**
|
|
1009
|
+
* One step of the stepped phase from locals already posed (issue #1336): the
|
|
1010
|
+
* caller's adjustment (`LocalAdjust`), the world transforms, the physics
|
|
1011
|
+
* records posed by `records` and stepped under the walk's context, then every
|
|
1012
|
+
* constraint. No previous pass: under the step it is the previous step's, and
|
|
1013
|
+
* `poseAnimations` leaves such bones out. A single animation's walk reaches it
|
|
1014
|
+
* through `posedBoneStep` with the locals `posedBones` posed; the live tracks
|
|
1015
|
+
* (`./tracks.ts`) with the locals their mixed entries posed — one pose path
|
|
1016
|
+
* past the timelines for both.
|
|
1017
|
+
*/
|
|
1018
|
+
function steppedLocals(doc: CompiledDocument, bones: ModelBone[], plant: TimelinePlant, records: () => CoreConstraintRecord[], physicsKeyed: NonNullable<CoreConstraintTimelines['physicsKeyed']>, t: number, sliders: SliderApplication[] | undefined, step: PoseStep): PosedStep {
|
|
1019
|
+
const active = activeBones(doc);
|
|
1020
|
+
// The caller's adjustment, after the timelines and before anything reads the locals (`LocalAdjust`).
|
|
1021
|
+
if (step.adjust !== undefined) adjustLocals(doc, bones, step.adjust);
|
|
1022
|
+
let world = (plant.evaluate ?? worldTransforms)(bones, active);
|
|
1023
|
+
const stepped = stepPhysicsRecords(records(), physicsKeyed, t, active, step.ctx, step.before);
|
|
1024
|
+
world = applyConstraints(bones, world, active, plant.constraints ? plant.constraints(stepped) : stepped, null, sliders, step.ctx, undefined, solverRules(plant.solver));
|
|
1025
|
+
for (const b of bones) if (world.get(b.name) === undefined) throw new CoreInputError(`the evaluator returned no transform for bone "${b.name}"`);
|
|
1026
|
+
return { bones, world, active, round: plant.round ?? gridRound };
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* `steppedLocals`' world transforms, the oracle's rows formed beside them when
|
|
1031
|
+
* `rows` is set (as `posedBoneWorld` forms them and `posedBoneWorldAlone` does
|
|
1032
|
+
* not): the live tracks' entry to the stepped phase (`./tracks.ts`). The
|
|
1033
|
+
* document's constraint records as they stand — the live tracks mix no
|
|
1034
|
+
* constraint timeline — and no physics timeline keyed.
|
|
1035
|
+
*/
|
|
1036
|
+
export function steppedLocalsWorld(doc: CompiledDocument, bones: ModelBone[], plant: TimelinePlant, sliders: SliderApplication[], step: PoseStep, rows: boolean): Map<string, CoreWorld> {
|
|
1037
|
+
const posed = steppedLocals(doc, bones, plant, () => constraintRecords(doc), [], 0, sliders, step);
|
|
1038
|
+
if (rows) stepRows(posed);
|
|
1039
|
+
return posed.world;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
977
1042
|
/** Each path record with the curve its slot shows deformed by the sample's own deform timelines at `t` (`./deform.ts`), or as it was. */
|
|
978
1043
|
function pathDeformed(doc: CompiledDocument, records: CoreConstraintRecord[], timelines: CoreAnimationTimelines, t: number, plant: TimelinePlant): CoreConstraintRecord[] {
|
|
979
1044
|
if (timelines.attachments.every((a) => a.deform === null)) return records;
|
package/src/core/deform.ts
CHANGED
|
@@ -536,6 +536,14 @@ export function attachmentStates(
|
|
|
536
536
|
sample: { timelines: CoreAnimationTimelines; t: number } | null,
|
|
537
537
|
sliders: readonly AttachmentApplication[],
|
|
538
538
|
plant: { deform?: DeformEvaluator; deformBlend?: DeformBlender; sequence?: SequenceEvaluator; slotTimelines?: SlotTimelineGate } = {},
|
|
539
|
+
/**
|
|
540
|
+
* The live tracks' deforms (`./tracks.ts`, issue #1336), in place of a
|
|
541
|
+
* sample's: each slot's deform array as the mixed entries left it (`null`
|
|
542
|
+
* none) and the records their deform timelines keyed on it — what the
|
|
543
|
+
* sample's own timelines would have set and seen. Absent on every other
|
|
544
|
+
* caller.
|
|
545
|
+
*/
|
|
546
|
+
mixed?: ReadonlyMap<string, { deform: number[] | null; seen: readonly string[] }>,
|
|
539
547
|
): { shown: ShownGeometry[]; why: string[] } {
|
|
540
548
|
const evalDeform = plant.deform ?? deformAt;
|
|
541
549
|
const blendOf = plant.deformBlend ?? blendDeform;
|
|
@@ -548,9 +556,10 @@ export function attachmentStates(
|
|
|
548
556
|
// A slot on a bone the skin leaves inactive is not animated: no deform, no frame, no slider switch (`./skins.ts`).
|
|
549
557
|
const live = gate(doc, slot, active);
|
|
550
558
|
let placeholder = placeholders.get(slot.name) ?? null;
|
|
551
|
-
|
|
559
|
+
const base = live ? mixed?.get(slot.name) : undefined;
|
|
560
|
+
let deform: number[] | null = base?.deform ?? null;
|
|
552
561
|
let frame: number | null = null;
|
|
553
|
-
const seen: string[] = [];
|
|
562
|
+
const seen: string[] = base === undefined ? [] : [...base.seen];
|
|
554
563
|
// What the slot shows now, the record its timelines are keyed as, and what a deform or a frame is computed on.
|
|
555
564
|
const state = (): { s: CoreShown; identity: string | null; vertices: ModelVertices | null; count: number | undefined } | null => {
|
|
556
565
|
if (placeholder === null) return null;
|
package/src/core/entry.ts
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
* browser and holds the bundle to zero `node:` strings.
|
|
17
17
|
*
|
|
18
18
|
* ⚠️ A symbol is listed here only because a dependant was seen using it,
|
|
19
|
-
* or asked for it in writing before it could be (`openTrack`, issue #1276
|
|
19
|
+
* or asked for it in writing before it could be (`openTrack`, issue #1276;
|
|
20
|
+
* `openTracks`, issue #1336).
|
|
20
21
|
* The list is `scripts/install_smoke.ts`'s `OBSERVED_SYMBOLS` rows for
|
|
21
22
|
* `./core`, and a symbol added here and not there is not promised.
|
|
22
23
|
*/
|
|
@@ -27,6 +28,8 @@ export type { RawPose, RawBone, RawDrawn, RawClip, RawClipped, RawEvent, RawRese
|
|
|
27
28
|
export { poseWalkSetup, poseLoopingWalk } from './walk.ts';
|
|
28
29
|
export { openTrack } from './track.ts';
|
|
29
30
|
export type { LiveTrack, TrackOptions, AdjustableLocals, BoneLocals, LocalAdjust } from './track.ts';
|
|
31
|
+
export { openTracks } from './tracks.ts';
|
|
32
|
+
export type { LiveTracks, TracksOptions, MixOptions, QueueOptions, TrackEntryView } from './tracks.ts';
|
|
30
33
|
export type { WalkPose } from './walk.ts';
|
|
31
34
|
export { documentPageLookup, drawnRegions, regionPageUvs, meshPageUvs, readUvSequences } from './uvs.ts';
|
|
32
35
|
export type { DrawnRegion, UvPage, UvRegion, UvSource } from './uvs.ts';
|
package/src/core/raw.ts
CHANGED
|
@@ -114,12 +114,12 @@
|
|
|
114
114
|
* missing would draw a different picture in silence.
|
|
115
115
|
*/
|
|
116
116
|
import { activeBones, CoreInputError, drawWalkOf, poseSetup, rawNumber, readColour, shownAttachment, sourceOfDoc, underNoSkin, type CompiledDocument, type CorePlant, type CoreSlotRow } from './index.ts';
|
|
117
|
-
import { posedBoneWorld, posedBoneWorldAlone, posedSlots, type LocalAdjust, type TimelinePlant } from './animation.ts';
|
|
117
|
+
import { posedBoneWorld, posedBoneWorldAlone, posedSlots, type CoreAnimationTimelines, type LocalAdjust, type TimelinePlant } from './animation.ts';
|
|
118
118
|
import { constraintsAbsentWhy, pathAnimationsWhy } from './constraints.ts';
|
|
119
119
|
import { freshStepContext, steppedPreviousPassWhy } from './constraints_physics.ts';
|
|
120
120
|
import { attachmentStates } from './deform.ts';
|
|
121
|
-
import { drawOrderAt } from './draw_order.ts';
|
|
122
|
-
import { eventsFired } from './events.ts';
|
|
121
|
+
import { drawOrderAt, type CoreDrawOrderKey } from './draw_order.ts';
|
|
122
|
+
import { eventsFired, type CoreEventRow } from './events.ts';
|
|
123
123
|
import { REGION_TRIANGLES, REGION_UVS, type CoreClippedRow, type ShapeClipper } from './clipping.ts';
|
|
124
124
|
import { poseGeometry, type CoreAttachmentRow, type CoreClipRow, type ShownGeometry } from './vertices.ts';
|
|
125
125
|
import { RUNTIME_DEG, type CoreWorld } from './world.ts';
|
|
@@ -666,28 +666,105 @@ function stepWalk<P>(track: TrackState<P>, dt: number, first = false): P {
|
|
|
666
666
|
const t = mode.loop ? (mode.time ?? loopedTime)(trackTime, duration, trackTime - dt) : trackTime < duration ? trackTime : duration;
|
|
667
667
|
const before = ctx.time;
|
|
668
668
|
ctx.time += mode.clock === undefined ? dt : mode.clock(dt, t - (first ? 0 : Math.max(last, 0)));
|
|
669
|
+
// A10's looping walk fires no event here — its one reader reads none — nor cuts its drawn attachments through a clip (`NO_CLIPPED_ROWS`), so its
|
|
670
|
+
// `clipped` rows are empty. The live track's looping mode (`live`) fires its events across the wrap by the rule `./track.ts` states as measured.
|
|
671
|
+
const fire = plant.events ?? eventsFired;
|
|
672
|
+
const keys = anim.timelines.events;
|
|
673
|
+
const pose = poseStepFrom(doc, plant, resolve, shape, mode, ctx, first, trackTime, t, {
|
|
674
|
+
world: (sliders) => (shape.rows ? posedBoneWorld(doc, anim.timelines, t, raw, anim.constraints, sliders, { ctx, before, adjust }).world : posedBoneWorldAlone(doc, anim.timelines, t, raw, anim.constraints, sliders, { ctx, before, adjust })),
|
|
675
|
+
slots: (sliders, placeholders) => posedSlots(doc, anim.timelines, t, raw, sliders, placeholders),
|
|
676
|
+
drawOrder: anim.timelines.drawOrder,
|
|
677
|
+
at: t,
|
|
678
|
+
sample: { timelines: anim.timelines, t },
|
|
679
|
+
events: () => (mode.loop && mode.live !== true ? [] : mode.loop ? fire(keys, last, t, rawNumber, t < last) : fire(keys, last, t, rawNumber)),
|
|
680
|
+
});
|
|
681
|
+
track.last = t;
|
|
682
|
+
return pose;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* What decides one step's pose before it is assembled (issue #1336): the bone
|
|
687
|
+
* world through the stepped phase, filling the sliders it applied; the slot
|
|
688
|
+
* rows, filling the placeholders the timelines left; the draw-order keys and
|
|
689
|
+
* the time they are read at; the deform and sequence timelines' sample, or the
|
|
690
|
+
* mixed deforms in its place; the events, computed when called. A walk's step
|
|
691
|
+
* reads every one off one animation at its time (`stepWalk`); the live tracks
|
|
692
|
+
* off their mixed entries (`./tracks.ts`). Everything past these is one body,
|
|
693
|
+
* `poseStepFrom`.
|
|
694
|
+
*/
|
|
695
|
+
export interface StepPosers {
|
|
696
|
+
world: (sliders: SliderApplication[]) => Map<string, CoreWorld>;
|
|
697
|
+
slots: (sliders: readonly SliderApplication[], placeholders: Map<string, string | null>) => { rows: CoreSlotRow[]; conflicts: string[] };
|
|
698
|
+
drawOrder: readonly CoreDrawOrderKey[];
|
|
699
|
+
at: number;
|
|
700
|
+
sample: { timelines: CoreAnimationTimelines; t: number } | null;
|
|
701
|
+
mixed?: ReadonlyMap<string, { deform: number[] | null; seen: readonly string[] }>;
|
|
702
|
+
events: () => CoreEventRow[];
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* One step's pose from what decided it (`StepPosers`): the bone world, the
|
|
707
|
+
* physics phase moved past the reset on `first`, the slot rows, the draw
|
|
708
|
+
* order (the keys' order, else the setup's, then each slider's key), the
|
|
709
|
+
* attachments drawn in it, and the pose assembled in `shape` — refused by name
|
|
710
|
+
* where the core leaves a block out, in that order. The one body a walk's step
|
|
711
|
+
* and a live tracks' step share.
|
|
712
|
+
*/
|
|
713
|
+
function poseStepFrom<P>(doc: CompiledDocument, plant: TimelinePlant, resolve: NonNullable<TimelinePlant['shown']>, shape: PoseShape<P>, mode: WalkMode, ctx: ReturnType<typeof freshStepContext>, first: boolean, trackTime: number, animationTime: number, posers: StepPosers): P {
|
|
669
714
|
const sliders: SliderApplication[] = [];
|
|
670
|
-
const world =
|
|
715
|
+
const world = posers.world(sliders);
|
|
671
716
|
if (first) ctx.phase = 'update';
|
|
672
717
|
const placeholders = new Map<string, string | null>();
|
|
673
|
-
const slots =
|
|
718
|
+
const slots = posers.slots(sliders, placeholders);
|
|
674
719
|
if (slots.conflicts.length > 0) throw new CoreInputError(`the raw walk leaves the slots out: ${slots.conflicts.join('; ')}`);
|
|
675
720
|
const evalOrder = plant.drawOrder ?? drawOrderAt;
|
|
676
|
-
let order = evalOrder(doc.slots.length,
|
|
721
|
+
let order = evalOrder(doc.slots.length, posers.drawOrder, posers.at) ?? doc.slots.map((_s, k) => k);
|
|
677
722
|
for (const app of sliders) order = evalOrder(doc.slots.length, app.timelines.drawOrder, app.at) ?? order;
|
|
678
723
|
const drawOrder = order.map((k) => doc.slots[k].name);
|
|
679
|
-
const states = attachmentStates(doc, resolve, placeholders,
|
|
724
|
+
const states = attachmentStates(doc, resolve, placeholders, posers.sample, sliders, plant, posers.mixed);
|
|
680
725
|
if (states.why.length > 0) throw new CoreInputError(`the raw walk leaves the attachments out: ${states.why.join('; ')}`);
|
|
681
726
|
const rank = new Map(drawOrder.map((n, r) => [n, r]));
|
|
682
727
|
const shown = [...states.shown].sort((a, b) => (rank.get(a.slot) ?? 0) - (rank.get(b.slot) ?? 0));
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
728
|
+
const events = (): RawEvent[] => posers.events().map((e): RawEvent => [e[0], finite(e[1], 'event time'), e[2], finite(e[3], 'event float'), e[4]]);
|
|
729
|
+
return shape.step(doc, { trackTime, animationTime, world, slots: slots.rows, drawOrder, shown, events }, plant, mode);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* The live tracks' side of the raw pose path (issue #1336, `./tracks.ts`):
|
|
734
|
+
* the refusals a walk makes before its first pose, a fresh physics context,
|
|
735
|
+
* the plant with the raw entry's rounding, and the two ways a pose is made —
|
|
736
|
+
* the setup pose reset (`reset: 'setup'`'s pose 0) and one step from what the
|
|
737
|
+
* mixed entries decided, assembled as the raw entry's pose (`RAW_SHAPE`,
|
|
738
|
+
* `RAW_MODE`: a non-finite value refused, every clipped row cut).
|
|
739
|
+
*/
|
|
740
|
+
export interface RawTracksPath {
|
|
741
|
+
readonly ctx: ReturnType<typeof freshStepContext>;
|
|
742
|
+
/** `plant` with the raw entry's rounding. */
|
|
743
|
+
readonly raw: TimelinePlant;
|
|
744
|
+
setupPose(): RawPose;
|
|
745
|
+
step(first: boolean, trackTime: number, animationTime: number, posers: StepPosers): RawPose;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/** `RawTracksPath` opened on `doc`, refused by name where a walk on it would be (`openWalk`). */
|
|
749
|
+
export function openRawTracksPath(doc: CompiledDocument, plant: TimelinePlant): RawTracksPath {
|
|
750
|
+
const why = constraintsAbsentWhy(doc) ?? pathAnimationsWhy(doc) ?? steppedPreviousPassWhy(doc);
|
|
751
|
+
if (why !== null) throw new CoreInputError(`the raw walk leaves the bones out: ${why}`);
|
|
752
|
+
const ctx = freshStepContext(plant.physicsStep);
|
|
753
|
+
const raw: TimelinePlant = { ...plant, ...roundPlant(RAW_MODE) };
|
|
754
|
+
const resolve = plant.shown ?? shownAttachment;
|
|
755
|
+
return {
|
|
756
|
+
ctx,
|
|
757
|
+
raw,
|
|
758
|
+
setupPose: () => {
|
|
759
|
+
const setup = poseSetup(doc, raw, ctx);
|
|
760
|
+
const absent = setup.absent.filter(([block]) => block !== 'setup.clipped');
|
|
761
|
+
if (absent.length > 0) throw new CoreInputError(`the raw walk's reset pose leaves ${absent.map(([b, w]) => `${b} out (${w})`).join('; ')}`);
|
|
762
|
+
if (setup.world === null || setup.shown === null || setup.setup.slots === null || setup.setup.drawOrder === null) throw new CoreInputError('the raw walk\'s reset pose was not posed');
|
|
763
|
+
ctx.phase = 'update';
|
|
764
|
+
return RAW_SHAPE.setup(doc, setup.world, setup.setup.slots, setup.setup.drawOrder, setup.shown, plant, RAW_MODE);
|
|
765
|
+
},
|
|
766
|
+
step: (first, trackTime, animationTime, posers) => poseStepFrom(doc, plant, resolve, RAW_SHAPE, RAW_MODE, ctx, first, trackTime, animationTime, posers),
|
|
767
|
+
};
|
|
691
768
|
}
|
|
692
769
|
|
|
693
770
|
/** `walkIn`'s walk, each pose assembled in `shape` and handed to `visit` in order as it is posed (`poseRawAnimationEach`): the walk opened, then stepped over `steps`. */
|
package/src/core/track.ts
CHANGED
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
* scan on A10's schedule and at 60 fps over three cycles — 157,771 poses, every
|
|
18
18
|
* one the same bits (the PR of issue #1276 carries the table).
|
|
19
19
|
*
|
|
20
|
+
* Several animations on several tracks, set, queued and mixed as spine-core's
|
|
21
|
+
* `AnimationState` mixes them, are `openTracks` (`./tracks.ts`, issue #1336):
|
|
22
|
+
* a second state machine over the same pose path past the timelines, which
|
|
23
|
+
* this track reaches with the locals its one animation posed.
|
|
24
|
+
*
|
|
20
25
|
* ## The walk
|
|
21
26
|
*
|
|
22
27
|
* - **Held** (`loop: false`): the raw entry's walk — the track time the
|