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) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.7 committed 2026-04-20 21:52:12 +02:00
1 parent 1fc9eb72be
commit 6471c446df
1 file changed
+244
+244
View File
@@ -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 <state> // <state> ∈ 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)
```