From 6471c446dfde0fcbbc10613305153725f776602a Mon Sep 17 00:00:00 2001
From: th
Date: Mon, 20 Apr 2026 21:52:12 +0200
Subject: [PATCH] docs: testing walkthrough for the macro-clips feature set
Covers the end-to-end flows per slice: markers (m shortcut + scrub-
ruler interactions), script tracks/frames (open dialog, action types,
forward-only firing rules), button clip creation and drag-to-track,
ButtonInstance dialog (label, onClick, disabled, transitions), canvas
runtime (pointer state machine, drag-out cancel behavior, scripted
state flips), transitions (matched layer blend vs crossfade, easing),
the DSL language reference with examples, a quick sanity pass for the
HTML export runtime, and which in-app test suites to look for.
Also documents the two known limitations (no in-app button state
authoring, scripts not baked into the server PNG/MP4 render) and a
small devtools cheat sheet for poking the pinia store directly.
Co-Authored-By: Claude Opus 4.7 (1M context)
---
docs/macro-clips-testing.md | 244 ++++++++++++++++++++++++++++++++++++
1 file changed, 244 insertions(+)
create mode 100644 docs/macro-clips-testing.md
diff --git a/docs/macro-clips-testing.md b/docs/macro-clips-testing.md
new file mode 100644
index 0000000..4ad9274
--- /dev/null
+++ b/docs/macro-clips-testing.md
@@ -0,0 +1,244 @@
+# Macro Clips & Scripts — Testing Guide
+
+Eine Walkthrough für die Features aus `docs/macro-clips-and-scripts.md`.
+Start: App mit `npm run dev`, leeres Projekt öffnen („New Project" im
+Welcome-Dialog).
+
+---
+
+## 1. Marker
+
+**Ziel:** Sprungziele auf der Haupt-Timeline setzen und benennen.
+
+1. Playhead an eine beliebige Stelle ziehen (z. B. t = 2 s).
+2. `m` drücken → ein Marker wird an der Playhead-Position angelegt und ein
+ Rename-Prompt öffnet sich. Namen eingeben (z. B. `intro`), `Enter`.
+3. Marker erscheint als kleine Fahne oben auf der Scrub-Ruler.
+4. **Interaktionen am Marker:**
+ - Einfacher Klick → Playhead springt dort hin.
+ - Drag → Marker zeitlich verschieben.
+ - Doppelklick → Rename.
+ - Marker anwählen, `Backspace`/`Delete` → löscht ihn. `Esc` → entauswählt.
+
+**Erwartung:**
+- Mehrere Marker bleiben zeitlich sortiert.
+- Zweiter Marker mit gleichem Namen bekommt automatisch Suffix (`intro 2`).
+- Namen müssen Scene-weit unique sein (Rename zeigt Fehler-Dialog bei
+ Kollision und öffnet den Prompt erneut).
+
+---
+
+## 2. Script-Tracks & Action-Frames
+
+**Ziel:** Zeit-gebundene Aktionen definieren, die bei Playback feuern.
+
+1. Im Timeline-Header die **Code-Taste** (`>`-Icon) klicken → ein neuer
+ Script-Track wird angelegt (kleinere Zeile als Clip-Tracks).
+2. Auf der leeren Script-Lane an beliebiger Zeitposition klicken → ein
+ neuer Action-Frame wird erstellt und der **ScriptFrameDialog** öffnet
+ sich.
+3. Im Dialog **Add action** drücken → ein Dropdown zeigt alle Action-Typen.
+ - Beispiel: `Pause` auswählen → nur Typ, keine Params nötig.
+ - Weitere Action hinzufügen: `Jump to marker` → Marker-Name aus dem
+ Dropdown wählen (dafür muss aus Schritt 1 ein Marker existieren).
+4. Dialog schließen mit **Done**.
+5. Mehrere Actions pro Frame sind erlaubt — die Zahl rechts neben dem
+ Frame-Dot zeigt deren Anzahl.
+
+**Testen:**
+- Playhead VOR den Action-Frame ziehen, dann `Space` (Play).
+- Playback läuft, und **genau wenn der Playhead über den Frame hinausgeht**,
+ feuern die Actions in Listen-Reihenfolge.
+- Beispiel `pause + jumpToMarker intro` → Playback pausiert und
+ Playhead springt zum `intro`-Marker.
+
+**Erwartung:**
+- Beim Scrubben (Ziehen des Playheads oder Marker-Klick) feuern
+ **keine** Actions.
+- Beim Loop-Wrap (von `playbackOut` zurück nach `playbackIn`) feuern
+ ebenfalls keine Actions.
+- Rückwärtsbewegen der Zeit feuert nichts.
+
+---
+
+## 3. Button-Clips erzeugen und platzieren
+
+**Ziel:** Einen klickbaren Button definieren, auf die Stage bringen und
+onClick-Actions hinterlegen.
+
+1. In der Asset-Sidebar den Abschnitt **Buttons** → `+` klicken. Namen
+ eingeben (z. B. `PlayButton`), `Enter`.
+2. Der Button erscheint in der Liste mit einem Cursor-Icon. Die 4 States
+ sind automatisch als bunte Rects vorausgefüllt
+ (blau / hellblau / dunkelblau / grau).
+3. Button-Clip aus der Sidebar auf eine Clip-Track ziehen (Drag-and-Drop).
+ - Wenn keine Clip-Track existiert, in den Timeline-Bereich unter den
+ Tracks droppen → neue Clip-Track entsteht automatisch.
+4. Auf der Clip-Track erscheint ein 4-Zellen-Block (`N H P D`) an der
+ Drop-Position.
+5. Auf dem Canvas erscheint der Button (standardmäßig in der Stage-Mitte)
+ — wenn der Playhead ≥ Instanz-Startzeit.
+
+**Button editieren:**
+1. Auf den 4-Zellen-Block klicken → **ButtonInstanceDialog** öffnet sich.
+2. **Label** vergeben (z. B. `play`) — wichtig, weil:
+ - Im DSL über `btn:play` referenzierbar.
+ - Im Dropdown von `Set button state`-Actions sichtbar.
+3. **On click** → Actions definieren (z. B. `Play` und `Jump to marker intro`).
+4. **Start disabled** aktivieren → Button startet grau/schraffiert,
+ reagiert nicht auf Klicks.
+5. **Done**.
+
+---
+
+## 4. Button-Runtime auf der Stage testen
+
+**Voraussetzung:** Ein Button ist platziert und der Playhead ist auf
+oder nach dessen Startzeit.
+
+1. Maus über den Button bewegen → Farbe wechselt zu *hellblau* (`hover`).
+2. Maus-Down → Farbe wird *dunkelblau* (`pressed`).
+3. Maus-Up (immer noch im Button) → `onClick`-Actions feuern; State geht
+ zurück zu `hover`.
+4. Maus-Down und **rausziehen** vor dem Maus-Up → kein `onClick`,
+ State kehrt zu `normal` zurück (Standard-Browser-Button-Verhalten).
+5. Disabled-Button hat keine Hover-/Press-Reaktion, ignoriert Klicks.
+
+**Skript-getriggert:**
+- In einem ScriptFrame eine `Set button state`-Action mit Target = Button-Label
+ und state = `pressed` anlegen.
+- Beim Playback überqueren → der Button schaltet visuell in `pressed`,
+ ohne dass der User hovert.
+- `Set button disabled` / `Enable` toggelt den Disabled-Flag zur Laufzeit.
+
+---
+
+## 5. Transitions zwischen States
+
+**Ziel:** Glatter visueller Übergang zwischen States statt hartem Wechsel.
+
+1. ButtonInstance-Dialog öffnen (4-Zellen-Block klicken).
+2. Unter **Transitions** → `+ Add transition`.
+3. Zeile: `normal → hover`, Duration `0.15`, Easing `easeOut`.
+4. Weitere Zeile: `hover → normal`, Duration `0.2`, Easing `easeOut`.
+5. Done.
+6. Auf dem Canvas Maus über den Button → die Farbe **fade**t zwischen
+ Blau und Hellblau über 150 ms, statt instant zu wechseln.
+
+**Hinweise:**
+- Transitions sind Clip-scoped, d. h. sie gelten für **alle** Instanzen
+ des Buttons.
+- Layer werden zwischen den beiden States per `name` gematcht (beim
+ Default-Seed heißen alle Face-Layer schlicht `Face` → werden immer
+ interpoliert). Unmatched Layer faden nur rein/raus (Crossfade).
+- Ohne Transition: State-Wechsel ist sofort (Verhalten wie vor Slice 7).
+
+---
+
+## 6. Script-DSL testen
+
+**Ziel:** Komplexere Logik in einer kompakten Textform statt manuellem
+Zusammenklicken mehrerer Actions.
+
+1. ScriptFrameDialog öffnen (oder ButtonInstanceDialog).
+2. **Add action** → Typ `Run script` wählen.
+3. Im Textarea:
+ ```
+ // setzt Pause und springt an den intro-Marker
+ pause
+ jump @intro
+ state btn:play pressed
+ disable btn:play
+ ```
+4. Done.
+
+**Testen:**
+- Frame überqueren → alle parsed Aktionen feuern in Reihenfolge.
+- Falsche Syntax → Warnung erscheint in der Devtools-Konsole
+ (`[animatr] Script line N: ...`). Die fehlerhafte Zeile wird
+ übersprungen; valide Zeilen feuern trotzdem.
+
+**DSL-Referenz (aktueller Sprachumfang):**
+```
+// Kommentar (bis Zeilenende)
+
+play // Playback starten
+pause // Playback pausieren
+rewind // Playhead → playbackIn (in-point)
+
+jump 2.5 // Zeit in Sekunden
+jump #135 // Frame-Nummer (durch fps geteilt)
+jump @markerName // benannter Marker
+
+state btn:label // ∈ normal|hover|pressed|disabled
+enable btn:label
+disable btn:label
+```
+
+---
+
+## 7. Export-Runtime prüfen
+
+**Ziel:** Sicherstellen dass Buttons, Scripts, Marker im exportierten
+Projekt genauso funktionieren wie im Editor.
+
+1. Menü → Export (oder beliebiger Export-Trigger je nach UI).
+2. `AnimatrPlayer`-HTML-Export wählen → Datei öffnen im Browser.
+3. **Erwartet:**
+ - Buttons rendern an ihren Positionen, mit Pointer-Reaktion.
+ - onClick feuert die hinterlegten Aktionen (z. B. `jump @intro` springt
+ im exportierten Player-Playhead zum Marker).
+ - Transitions animieren sauber.
+ - Script-Frames feuern bei natürlichem Playback.
+4. Devtools-Konsole im Export-Tab → `window.AnimatrPlayer.__v` sollte
+ `'6'` ergeben. Cache-Probleme? Hard-Reload mit Shift+Cmd+R / Ctrl+F5.
+
+---
+
+## 8. Runtime-Tests (in-app)
+
+`Ctrl+Shift+Alt+T` öffnet den Test-Runner. Relevante Suiten:
+- `scene store — markers` / `script tracks & frames` / `button clips & instances`
+- `actions — evalAction with mock runtime`
+- `actions — script type expands via evalAction`
+- `scriptDsl — parser`
+- `button runtime — state machine + action wiring`
+- `scene store — tick fires script frames forward-only`
+
+Alle sollten grün laufen.
+
+---
+
+## Bekannte Einschränkungen
+
+- **Kein Button-State-Editor in der UI:** Die 4 States sind beim Seed mit
+ farbigen Rects vorausgefüllt. Um die Optik anzupassen müsste man
+ aktuell `scene.buttonClips[i].states[…]` direkt im gespeicherten
+ Projekt-JSON editieren. Ein eigener Edit-Modus ist geplant, aber
+ nicht implementiert.
+- **Server-Render (PNG-Sequence / MP4)** bakt Script-Actions und
+ Button-Interaktionen bewusst nicht ein — das wäre keine deterministische
+ Animation mehr. Scripts wirken nur in der interaktiven
+ Browser-Laufzeit (Editor + `AnimatrPlayer`-HTML-Export).
+
+---
+
+## Devtools-Cheat-Sheet
+
+Für Tests ohne UI:
+```js
+// Pinia store im Devtools:
+const s = __pinia.state.value.scene
+const store = useSceneStore() // im Vue-Devtools verfügbar
+
+// Button-Instanz direkt einen bestimmten State geben:
+const rt = useButtonRuntime()
+rt.setState(instanceId, 'pressed')
+rt.reset()
+
+// Alle Marker sehen:
+console.table(store.scene.markers)
+
+// Alle Button-Instanzen:
+console.table(store.scene.buttonInstances)
+```
|