macro-clips slice 8: script DSL parser + runtime label resolution

- src/lib/scriptDsl.ts: small line-based parser producing Action[] plus
  a list of ParseError{line,message}. Handles: play/pause/rewind,
  jump <sec> | #<frame> | @<marker>, state btn:<label> <state>,
  enable/disable btn:<label>, // comments, skips blanks
- evalAction for type:'script' parses the source and recursively
  dispatches sub-actions; errors surface via rt.warn
- ActionRuntime.setButtonState/setButtonDisabled are documented as
  taking an instance id OR a label; the store's actionRuntime builds
  a label→id map and resolves refs before applying
- exportPlayer template gets a matching parseScriptSource plus
  resolveButtonRef; evalAction-in-engine mirrors the TS version
- RUNTIME_VERSION bumped to '4'
- tests: parser covers commands, comments, jump variants, state/enable
  errors, unknown commands; two integration tests verify that script
  actions dispatch via evalAction and that parse errors don't block
  valid actions

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.7 committed 2026-04-20 21:20:15 +02:00
1 parent 94ebbac238
commit fb58cd18f7
5 files changed
+368 -10

No files matched your search

+16 -2
View File
@@ -1493,6 +1493,14 @@ export const useSceneStore = defineStore('scene', {
},
actionRuntime(): ActionRuntime {
const self = this
const instances = self.scene.buttonInstances ?? []
const byId = new Set(instances.map((bi) => bi.id))
const byLabel = new Map<string, string>()
for (const bi of instances) if (bi.label) byLabel.set(bi.label, bi.id)
function resolve(ref: string): string | null {
if (byId.has(ref)) return ref
return byLabel.get(ref) ?? null
}
return {
fps: self.scene.fps,
playbackIn: self.playbackIn,
@@ -1512,8 +1520,14 @@ export const useSceneStore = defineStore('scene', {
// No-op in editor for now — runtime-state management lands in
// the export-runtime slice together with pointer handling.
},
setButtonDisabled(instanceId: string, disabled: boolean) {
self.setButtonInstanceDisabled(instanceId, disabled)
setButtonDisabled(ref: string, disabled: boolean) {
const id = resolve(ref)
if (!id) {
// eslint-disable-next-line no-console
console.warn('[animatr] unknown button ref:', ref)
return
}
self.setButtonInstanceDisabled(id, disabled)
},
warn(msg: string) {
// eslint-disable-next-line no-console