revert macro-clips button feature (keep markers + scripts)

The button authoring ended up too far from the intended model after
three correction passes. Pulling it out entirely so we can rebuild
from a clean spec. Markers, script tracks, script frames, the Action
editor, the Script DSL and the runtime for all of the above stay —
they work.

Removed:
- types: ButtonState, StateTransition, ButtonHitArea, ButtonClip,
  ButtonInstance, setButtonState/setButtonDisabled Action variants,
  Scene.buttonClips/buttonInstances
- store: activeButtonClip* getters, all add/remove/setButton* actions,
  seedDefaultButtonClip, enterButtonEdit/setActiveButtonState/
  exitButtonEdit, button-label resolution in actionRuntime
- useButtonRuntime composable, buttonBlend helper,
  ButtonInstanceDialog, sidebar Buttons section, Timeline button
  rendering + pointer handlers, CanvasStage button rendering +
  pointer state machine, exportPlayer button runtime + hit-testing
- DSL commands state/enable/disable and their parse errors
- 35 button-related tests + helpers; stale testing doc; stale design
  doc

Re-applied three uncommitted fixes that were unrelated to the button
work:
- clicking a marker no longer jumps the playhead (only drag / dblclick
  act on it)
- script tracks get a right-click context menu (rename + delete,
  color in the existing palette)
- onTracksPointerDown excludes .script-lane / .script-frame so
  clicks on empty lanes or on frame dots reach the frame-open path
  instead of being swallowed by box-select pointer capture

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 23:37:49 +02:00
1 parent 616973b0fa
commit 31604052ca
16 files changed
+84 -2809

No files matched your search

-86
View File
@@ -2,7 +2,6 @@
import { computed, ref, watch } from 'vue'
import {
PhCircle,
PhCursorClick,
PhFilmStrip,
PhImage,
PhImageSquare,
@@ -108,7 +107,6 @@ async function addSampleText() {
}
const clips = computed(() => store.scene.clips ?? [])
const buttonClips = computed(() => store.scene.buttonClips ?? [])
async function addClip() {
const input = await promptDialog({
@@ -149,45 +147,6 @@ function onClipDragStart(e: DragEvent, clipId: string) {
e.dataTransfer.setData('text/plain', clipId)
}
async function addButtonClip() {
const input = await promptDialog({
title: t('sidebar.newButtonDialog.title'),
message: t('sidebar.newButtonDialog.message'),
defaultValue: t('sidebar.newButtonDialog.default'),
confirmLabel: t('sidebar.newButtonDialog.confirm'),
})
if (input === null) return
store.seedDefaultButtonClip(input || t('sidebar.newButtonDialog.default'))
}
async function renameButtonClipPrompt(id: string, current: string) {
const input = await promptDialog({
title: t('sidebar.renameButtonDialog.title'),
defaultValue: current,
confirmLabel: t('sidebar.renameButtonDialog.confirm'),
})
if (input === null) return
store.setButtonClipName(id, input)
}
async function deleteButtonClip(id: string) {
const ok = await confirmDialog({
title: t('sidebar.deleteButtonDialog.title'),
message: t('sidebar.deleteButtonDialog.message'),
confirmLabel: t('sidebar.deleteButtonDialog.confirm'),
variant: 'danger',
})
if (!ok) return
store.removeButtonClip(id)
}
function onButtonClipDragStart(e: DragEvent, id: string) {
if (!e.dataTransfer) return
e.dataTransfer.effectAllowed = 'copy'
e.dataTransfer.setData('application/x-animatr-button-clip', id)
e.dataTransfer.setData('text/plain', id)
}
async function handleFileSelected(event: Event) {
uploadError.value = null
const input = event.target as HTMLInputElement
@@ -377,51 +336,6 @@ function onAssetDragStart(e: DragEvent, asset: Extract<Asset, { kind: 'image' }>
</li>
<li v-if="!clips.length" class="empty">{{ t('sidebar.noClips') }}</li>
</ul>
<div class="lib-header clips-header">
<h4>{{ t('sidebar.buttons') }}</h4>
<button
class="thumb-toggle"
:title="t('sidebar.createButtonTooltip')"
@click="addButtonClip"
>
<PhPlus :size="12" weight="bold" />
</button>
</div>
<ul class="clips">
<li
v-for="bc in buttonClips"
:key="bc.id"
class="clip button-clip"
draggable="true"
@dragstart="onButtonClipDragStart($event, bc.id)"
>
<div class="clip-icon">
<PhCursorClick :size="16" />
</div>
<div class="clip-meta">
<span class="clip-name" :title="bc.name">{{ bc.name }}</span>
<span class="clip-sub">{{ t('sidebar.buttonSubtitle') }}</span>
</div>
<div class="clip-actions">
<button
class="clip-btn"
:title="t('sidebar.renameTooltip')"
@click.stop="renameButtonClipPrompt(bc.id, bc.name)"
>
<PhPencilSimple :size="11" />
</button>
<button
class="clip-btn danger"
:title="t('sidebar.deleteTooltip')"
@click.stop="deleteButtonClip(bc.id)"
>
<PhTrash :size="11" />
</button>
</div>
</li>
<li v-if="!buttonClips.length" class="empty">{{ t('sidebar.noButtons') }}</li>
</ul>
</div>
</template>