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 @@
-