From c3764201b88c657a06988fefe1151aa0bcff3f77 Mon Sep 17 00:00:00 2001 From: th Date: Tue, 21 Apr 2026 19:19:39 +0200 Subject: [PATCH] feat: 5-frame button assets + timeline/sidebar polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Button assets - Re-introduce button-asset type with 4 content states (normal/hover/ pressed/disabled) stored as keyframes at BUTTON_STATE_TIMES, plus a separate hit-area editor mode. - useButtonRuntime composable for per-instance state/disabled flags on the main stage. - Sidebar library lists button assets with live 80×80 thumbnails; renderButtonThumbnail now accepts an images map so image-kind layers inside a button render instead of producing a fully-transparent PNG. - Compact (no-thumbnail) mode aligns button rows to the library-row height. Scope footer - Button-edit mode now uses the same sidebar scope-footer pattern as clip-edit (back button to "Main timeline" + active scope chip); removed the inline exit button from the timeline scrub-bar. Timeline - Track-name column default bumped to 260px to match the assets sidebar above it (storage key bumped to :v2 so stale values reset). - scrub-bar z-index raised above sticky track-name columns so rows scroll under it instead of over. - scrub-handle flips z-index based on horizontal scroll: above name-spacer when the playhead is in view (no half-clip at t=0), below when the playhead has scrolled off the left edge (so the toggle row cleanly covers it). - name-spacer extends ±3/1px to fully cover the obscured handle. - scrub-handle head pokes 3px above the ruler with rounded top corners via clip-path path(). Track context menu - Added missing i18n keys (renameScriptTrack / deleteScriptTrack / renameScriptTrackDialog.{title,confirm}). - Rename items show a visible pencil icon; empty .check slot removed so items line up flush-left; toggle items place their active ✓ on the right (kf-menu-trailing-check). Dev HUD - Test progress bar flips to --danger as soon as the first failure is recorded, instead of only at the end of the run. Regression tests - renderButtonThumbnail: null on empty button, renders shape layers, accepts custom images map. - i18n: renameScriptTrack / deleteScriptTrack / dialog keys resolve. - scrub-handle-obscured logic (visible at t=0, hidden when playhead is scrolled off-screen, still visible when playhead is far to the right of the scroll offset). - Updated button state-scrubber expectations to match BUTTON_STATE_TIMES (normal=1, hover=2, pressed=3, disabled=4) and that hit-mode parks at normal=1 rather than 0. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/App.vue | 11 + src/components/AssetSidebar.vue | 177 ++++++- src/components/CanvasStage.vue | 734 ++++++++++++++++++++++++++- src/components/FullscreenPreview.vue | 214 ++------ src/components/PropertiesPanel.vue | 24 +- src/components/Timeline.vue | 504 +++++++++++++++++- src/composables/useButtonRuntime.ts | 45 ++ src/devtools/TestOverlay.vue | 14 +- src/devtools/tests.ts | 525 ++++++++++++++----- src/i18n/messages.ts | 48 ++ src/lib/exportPlayer.ts | 215 +++++++- src/lib/interpolate.ts | 33 ++ src/lib/render.ts | 52 +- src/stores/scene.ts | 195 ++++++- src/types/scene.ts | 49 +- todo | 69 ++- 16 files changed, 2560 insertions(+), 349 deletions(-) create mode 100644 src/composables/useButtonRuntime.ts diff --git a/src/App.vue b/src/App.vue index af07034..5a91c74 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,6 +4,7 @@ import { PhArrowClockwise, PhArrowCounterClockwise, PhArrowLeft, + PhCursorClick, PhExport, PhFilmStrip, PhFolderOpen, @@ -439,6 +440,16 @@ onBeforeUnmount(() => { {{ store.activeClip?.name ?? '' }} +
diff --git a/src/components/AssetSidebar.vue b/src/components/AssetSidebar.vue index 3749bf7..65f74f0 100644 --- a/src/components/AssetSidebar.vue +++ b/src/components/AssetSidebar.vue @@ -1,7 +1,8 @@ @@ -347,6 +503,12 @@ function onAssetDragStart(e: DragEvent, asset: Extract gap: 10px; } +.panel.hit-disabled { + opacity: 0.4; + pointer-events: none; + filter: saturate(0.5); +} + h3 { margin: 0 0 2px; font-size: 13px; @@ -574,6 +736,17 @@ h4 { border-color: var(--border-strong); } +/* In compact (no-thumbnail) mode, buttons match library entry height + exactly by dropping the 1px border (same as .assets li). */ +.clips.compact .clip { + border: 0; + gap: 10px; +} + +.clips.compact .clip.editing { + background: var(--accent-soft); +} + .clip:active { cursor: grabbing; } diff --git a/src/components/CanvasStage.vue b/src/components/CanvasStage.vue index 2a86853..b396b6a 100644 --- a/src/components/CanvasStage.vue +++ b/src/components/CanvasStage.vue @@ -1,19 +1,36 @@