macro-clips slice 7: button state transitions
- ButtonClip transitions are now editable in ButtonInstanceDialog (from/to/duration/easing) and persisted on the clip via the new store.setButtonClipTransitions action; transitions are shared by every instance of the button (clip-scoped, not instance-scoped). - lerpProps exported from interpolate.ts so callers outside the sampler can blend two poses. - useButtonRuntime tracks an active transition per instance plus a reactive transitionTick that pokes Vue computeds each frame. A self-driving RAF loop runs only while some transition is active (idles when none), so animations work paused or playing. - applyButtonStateChange(id, to, transitions, persistedDisabled) is the one entry point for state changes — it looks up a matching from→to transition and starts it, or flips state instantly. Pointer handlers in CanvasStage and store.actionRuntime.setButtonState both go through it. - CanvasStage blends the two state stacks via sampleStateLayers + blendStates: layers matched by name interpolate their sampled props with lerpProps; unmatched layers fade in/out. Renderer uses the blended layer list in place of the pure state stack during transit. - Export runtime mirrors the same flow: applyButtonChange starts transitions, sampleButtonTransition drives per-frame progress, and drawButtonStatesBlended composites via drawLayer(layer, 0, override). drawLayer gained an optional propsOverride param for this. RUNTIME_VERSION bumped to 6. - Tests cover applyButtonStateChange matching logic and sampleTransition's time → u mapping plus done flag. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
f61f90d613
commit
68ea8576b6
8 files changed
+515
-32
No files matched your search
+18
-2
@@ -27,7 +27,10 @@ import {
|
||||
scriptFramesInRange,
|
||||
type ActionRuntime,
|
||||
} from '@/lib/actions'
|
||||
import { useButtonRuntime } from '@/composables/useButtonRuntime'
|
||||
import {
|
||||
applyButtonStateChange,
|
||||
useButtonRuntime,
|
||||
} from '@/composables/useButtonRuntime'
|
||||
|
||||
const uid = () => Math.random().toString(36).slice(2, 10)
|
||||
|
||||
@@ -1204,6 +1207,15 @@ export const useSceneStore = defineStore('scene', {
|
||||
const clip = this.scene.buttonClips?.find((c) => c.id === id)
|
||||
if (clip) clip.name = name.trim() || clip.name
|
||||
},
|
||||
setButtonClipTransitions(
|
||||
id: string,
|
||||
transitions: NonNullable<ButtonClip['transitions']>,
|
||||
) {
|
||||
const clip = this.scene.buttonClips?.find((c) => c.id === id)
|
||||
if (!clip) return
|
||||
if (transitions.length) clip.transitions = [...transitions]
|
||||
else delete clip.transitions
|
||||
},
|
||||
addButtonInstance(
|
||||
buttonClipId: string,
|
||||
clipTrackId: string,
|
||||
@@ -1577,7 +1589,11 @@ export const useSceneStore = defineStore('scene', {
|
||||
console.warn('[animatr] unknown button ref:', ref)
|
||||
return
|
||||
}
|
||||
btnRt.setState(id, state)
|
||||
const inst = instances.find((x) => x.id === id)
|
||||
const clip = self.scene.buttonClips?.find(
|
||||
(c) => c.id === inst?.buttonClipId,
|
||||
)
|
||||
applyButtonStateChange(id, state, clip?.transitions, inst?.disabled)
|
||||
},
|
||||
setButtonDisabled(ref, disabled) {
|
||||
const id = resolve(ref)
|
||||
|
||||
Reference in new issue
Block a user