Commit Graph
38 Commits
Author SHA1 Message Date
thandClaude Opus 4.7 c5b1dd566a 0.10.1: audio clip push-cascade + track-swap ghost, Media drawer rename
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 12:52:47 +02:00
thandClaude Opus 4.7 04f867547d 0.10.0: audio tracks — assets, per-scene lanes, editor + export playback
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 11:53:41 +02:00
thandClaude Opus 4.7 517705bf55 0.8.7: duplicate track via right-click (layer / clip / script)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 06:22:32 +02:00
thandClaude Opus 4.7 53c0410824 0.8.5: multi-select tracks, group + convert-to-clip
Multi-select
- New `selectedLayerIds: string[]` on the scene store — ordered by
  click, anchor = last entry, always equal to `selectedLayerId`.
- `toggleLayerSelection(id)` shift-click behaviour: adds or removes,
  anchor follows the last click, effectively-locked layers refuse.
- `selectLayer`, `addLayer`, and every selection-reset path keep
  the set in lock-step with the anchor.

Timeline
- Shift-click on a layer row's name toggles that layer's
  membership in the multi-selection. Every selected row highlights
  via `store.selectedLayerIds.includes(track.layerId)`.
- Right-click on a track now preserves an existing multi-selection
  if the clicked track is part of it; lands as a single-select
  otherwise.
- Track context menu adds two entries when ≥1 layer is selected:
  - "Group N selected layers" — calls the new store action and
    drops the group into the topmost selected track's stack slot
    (not at the very top as a naive `addTrackGroup` would).
  - "Convert N selected to clip" — packs the layers into a fresh
    clip with `duration = scene.duration`, deep-clones via
    `structuredClone(toRaw(l))`, drops a single `ClipInstance` on
    a new clipTrack at `startTime = 0`, and positions the
    clipTrack at the topmost selected track's slot.

Fixes
- `removeLayer` no longer unconditionally clears
  `selectedLayerIds` (bulk-replace artifact from the multi-select
  work); the anchor-matched path clears the whole set, the
  non-anchor path only splices out that one id.
- `deselectIfLocked` indentation normalised.

Regression tests
- Multi-select store API: selectLayer sync, toggleLayerSelection
  add/remove/anchor, lock-filter, empty-selection guards.
- `groupSelectedLayers`: happy-path packing, empty-select null
  return, lock-filter, stack-slot pinning.
- `convertSelectedLayersToClip`: packs layers + spawns clipTrack +
  instance (deep-clone integrity pinned via unique per-layer names
  so the cloned-layer lookup is unambiguous), drops the clipTrack
  at the topmost slot, returns null on empty selection, skips
  effectively-locked layers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 05:19:09 +02:00
thandClaude Opus 4.7 af5f99380c 0.8.4: button transitions, locked groups revoke edits, UX polish
Button-state transitions
- State flips on stage-preview buttons (normal / hover / pressed /
  disabled) now ease over 50ms instead of snapping. New
  `transitions` map + rAF ticker in useButtonRuntime drive a
  continuous sample time between BUTTON_STATE_TIMES slots;
  CanvasStage samples each button child at that interpolated time
  so keyframes at the 4 states blend smoothly. Mid-flight flips
  (hover → pressed while still in normal → hover) rebase from
  the current live sample instead of snapping.

Locked groups revoke edits
- Locking a layer directly or its enclosing group deselects the
  layer so the Properties panel can't keep editing it. Panel also
  splits into three branches — editable / locked / no-layer —
  with a dedicated locked-layer hint.
- Timeline keyframe interactions (drag, dblclick-to-remove,
  context menu, dblclick-to-create on lane, add-kf toolbar)
  now consult effective lock (direct + parent group) instead
  of just layer.locked.

Editor polish
- Inactive tracks fade as a whole row (opacity 0.5) instead of
  per-child, so keyframes, segments, and still-frame tails stay
  visually proportional to their active counterparts.
- Dragging a layer onto a group's track-name label now drops
  it INTO the group (was previously only the group-lane area).
- Button assets on the stage show a pointer cursor on hover so
  it's obvious they're interactive.
- Global CSS forces `cursor: pointer !important` on every enabled
  button / role="button" so scoped component styles can no longer
  accidentally shadow the default.
- Timeline resize handle jumped above the scrub-bar (z-index 100)
  so the full 14px grab zone is hit-testable again.

Regression tests
- setTrackLocked deselect paths: direct lock, group lock with
  selected child, group lock with unrelated selection, unlock
  doesn't re-select.
- duplicateKeyframeAt: props + easing + hold + bezier copied,
  collision refusal, unknown-id guards, separated-track routing.
- Button transition runtime: no-transition baseline, mid-flight
  bounds, mid-transition rebase, no-op setState.
- Shared composables tooltips + asset-thumbs: same ref across
  calls, localStorage round-trip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 04:31:08 +02:00
thandClaude Opus 4.7 1d84c34c15 0.8.3: custom tooltips, editor-hide, pack script, settings reshuffle
Tooltips
- New v-tooltip directive + TooltipHost floating panel replace the
  native title attribute across 95+ sites (topbar, timeline, sidebar,
  properties, stage overlays, fullscreen preview, export dialog,
  clipart drawer, modals). Styled dark card with a configurable
  label + optional help line for inline documentation; screen
  readers still get an aria-label when the panel is disabled.
- Settings → Interface toggle (`ruwio:tooltipsEnabled`) hides the
  visual panel for users who know the app. IconButton now routes
  its title prop through v-tooltip so every existing call site is
  tooltip-aware without churn.

Editor-hide + export filter
- New `Layer.editorHidden` flag, eye toggle per layer row, skipped
  by the Konva stage and the mask-preview canvas path but honoured
  by exports and fullscreen preview (runtime untouched).
- Export dialog gets a "Skip hidden tracks" switch that strips
  editor-hidden layers from every format (scene JS, runtime,
  example HTML, MP4, WebM) on opt-in. Disabled when the scene has
  no hidden layers.

Button editor
- `+` buttons appear on empty state slots in button-timeline rows
  and duplicate the nearest keyframe (prev by preference, next
  otherwise) onto that slot. New `duplicateKeyframeAt` store
  action carries props, easing, hold, and bezier handles across.

Stage / interaction
- Plain left-click on the empty content view pans the viewport,
  but only when the pointer isn't over a Konva shape — transformer
  handles, vertex dots, and selection boxes that extend past the
  canvas edge keep their drag.

Settings reshuffle
- Timeline tab merged into Document (Duration + FPS sit under a
  new "Timing" sub-heading). New Interface tab gathers three
  global prefs: Show tooltips, Show locked tracks, Asset
  thumbnails — driven by shared composables so the existing
  toolbar toggles stay in sync. Interface-tab CSS defensively
  resets the scoped label flex-column + uppercase rule that was
  making the toggle row look like an accident.

Project identity + UX polish
- Favicon wired up (moved to public/favicon.ico, linked from
  index.html); scripts/pack.sh packs the minimum Vue project
  (src, index.html, configs, public) into a tarball with the
  right version in the filename, and `npm run pack` drives it.
- About dialog now credits Torsten Hoeltge.

Test infra
- Progress bar turns red mid-run on the first failure: runAll
  gets an onResult callback that TestOverlay uses to push each
  result into the reactive array incrementally.
- mountComponent in the test harness registers v-tooltip on the
  isolated app instance so IconButton's aria-label contract
  actually fires under test.

Regression tests
- duplicateKeyframeAt: copy fidelity (props, easing, hold),
  collision refusal, unknown-id guards, separated-track targeting.
- Shared composables: useTooltipPref and useAssetThumbsPref both
  return the same ref across calls and persist to localStorage.
- Tooltip contract: IconButton ships `aria-label` (not title);
  live-DOM smoke tests match on aria-label selectors now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:57:35 +02:00
thandClaude Opus 4.7 82ee5c98d0 0.8.1: dirty-state + Cmd/Ctrl+S, fullscreen plays to OUT, UX fixes
- Unsaved-changes indicator: a small accent dot appears on the save
  button whenever the scene has changed since the last save/load.
  Save/load/new all mark the project clean on next tick.
- Cmd/Ctrl+S saves the project (reuses the same flow as the button;
  prompts for a name on first save). Tooltip now mentions the
  shortcut.
- Fullscreen preview plays to the OUT marker (or scene.duration when
  no OUT is set) instead of looping at the last keyframe. Dropped
  the runtime's effectiveEnd helper; RUNTIME_VERSION 13 → 14.
- "Still frame" keyframes no longer disable easing. A held kf's
  easing still drives the segment INTO it from the previous kf, so
  you can ease into a pause. Only the first kf disables easing
  (nothing precedes it). Dropped `timeline.holdDisabledHint`.
- Settings dialog: hint text 11px → 13px (and dropped italic) so
  the inline help is readable; section headings 10px → 13px.
- Canvas stage shadow: `shadowCfg` always emits explicit values plus
  a `shadowEnabled` flag instead of returning `{}`. Konva's default
  shadowOpacity is 1, so bailing with `{}` could leave stale shadow
  attrs on the shape. Preview and editor now gate on the same
  condition deterministically.
- Sidebar empty-state copy: "No clips" → "No clips yet" to match
  "No buttons yet".

Regression tests: runtime rangeOut fallback is scene.duration (not
last kf); sidebar empty-states both contain "yet"; the
holdDisabledHint key is gone; saveProject tooltips mention the
shortcut.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 22:00:35 +02:00
thandClaude Opus 4.7 1e89ea86e0 0.8.0: group colour cascade, still-frame past end, project rename, UX polish
Headline:

- Group colour cascades to every non-overridden child (layer or clip
  track). New `colorOverridden` flag on Layer / ClipTrack / ScriptTrack
  / TrackGroup; setTrackColor on a non-group pins the track, clearing
  re-inherits from the parent group. moveTrackIntoGroup also inherits.
  normalizeScene migrates legacy scenes (existing colour ⇒ overridden).
- Keyframes inside a button-asset timeline snap to the 4 state slots
  (normal/hover/pressed/disabled). upsertKeyframe / setKeyframeTime /
  duplicateKeyframe all enforce it; colliding drags refuse the move,
  duplicates walk to the nearest free slot.
- Backspace / Delete on a selected layer removes it (respecting the
  layer's own lock and any enclosing group lock).
- "Still frame" allowed on the last keyframe: the layer stays on stage
  past its final kf. Timeline draws a solid dim tail line from the
  last kf to the end, and single-keyframe tracks now show a full-span
  line so on-stage/off-stage reads at a glance. Height stays 3px.
- Project name moved next to the logo, turns into a rename button on
  hover (pencil fades in). Rename syncs the stored record when the
  project is already persisted.
- Shadow + blur keyframes animate in the preview and exported runtime:
  the runtime's lerpProps used to drop them, so every preview rendered
  shadow=0 between keyframes. RUNTIME_VERSION 11 → 13 (covers the
  button-mask + shadow fixes). Held-last-kf also taught to the runtime.
- Button masks render across every path: edit-mode mask-preview,
  nested buttons on the main stage, sidebar thumbnails, fullscreen
  preview + exports. drawButtonFrame new in render.ts.

Smaller fixes:

- Dragging layer A on the stage with a stale selection on layer B used
  to move B and snap A back. Now the shift-selected branch only runs
  when the dragged layer is itself in the selection.
- Clip-track row was missing its icon — PhFilmStrip was referenced but
  never imported. Added, plus dropped the bespoke `gap` on clip / script
  name rows so their icon+label spacing matches layer rows.
- Clip-art drawer pre-lays-out its 400px grid behind `overflow: hidden`
  so slide-in reveals a finished grid instead of reflowing auto-fill
  columns over 220ms.
- Timeline clip-track dropzone hides until the library has a clip; its
  "drop a clip here" hint stays centred in the visible ruler area.
- Keyframe context menu: check-mark and icons share a single 12px column
  so the ✓ on an easing option lines up with PhPauseCircle / PhCopy /
  PhTrash on the rows below. "Still frame"'s active indicator moved to
  the trailing-check slot.
- Button editor's mask-preview now shows the button's own stage instead
  of leaking through to the main scene. drawButtonFrame drives it.

Regression tests cover all of the above: group-color cascade, pin,
clear-re-inherit, migration, button-kf snap and collision rules,
backspace-deletes-selected-layer (incl. lock guards + editable-target
guard), still-frame-past-end visibility, clipart drawer rigid width,
mask rendering in drawButtonFrame / drawSceneFrame, shadow + blur
interpolation in both canvas and runtime paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 21:26:06 +02:00
thandClaude Opus 4.7 f29dc448fb fix: masks inside buttons render across all paths
Buttons used to ignore `isMask` on every render path — the mask
shape drew as normal content instead of clipping the button's
other layers. Every entry point now routes button children through
`drawMaskedGroup`:

- `drawLayers` nested-button branch
- new `drawButtonFrame` (used by the mask-preview overlay in
  button-edit mode so the preview reflects the button's own
  stage instead of the main scene)
- `renderButtonThumbnail` so sidebar previews match the stage
- exported-runtime button branch mirrors the split; bumped
  `RUNTIME_VERSION` to '11' so cached players reload

Also:

- Timeline clip-track dropzone hides until the library has at
  least one clip, and the hint stays centred in the visible
  ruler area instead of drifting with horizontal scroll.
- Regression tests pin positive/negative button masks in
  `drawButtonFrame` and verify `drawSceneFrame` applies
  button-internal masks when the button sits on the main stage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 19:43:23 +02:00
thandClaude Opus 4.7 c3764201b8 feat: 5-frame button assets + timeline/sidebar polish
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) <noreply@anthropic.com>
2026-04-21 19:19:39 +02:00
thandClaude Opus 4.7 31604052ca 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>
2026-04-20 23:37:49 +02:00
thandClaude Opus 4.7 616973b0fa feat: click-outside deselects a selected marker
Esc was already wired but nobody stumbles onto it. A capture-phase
pointerdown listener is installed while selectedMarkerId is set; any
click that doesn't land on a .timeline-marker (or on an open
dialog/menu) clears the selection. Listener is torn down automatically
when selection clears or the component unmounts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 22:20:58 +02:00
thandClaude Opus 4.7 4cb3a74dfb style: selected marker turns orange
Bold label + ring alone weren't enough to distinguish a selected
marker from the default red flags. The .selected rule now overrides
--marker-color to #f59e0b (amber) with !important so per-marker color
overrides also yield to selection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 22:18:22 +02:00
thandClaude Opus 4.7 fe1a7f9b3b fix: marker template was overriding the red default with --accent
The inline style wrote --marker-color: var(--accent) whenever
marker.color wasn't set, which shadowed the CSS default. Only emit
the inline override when a per-marker color is explicitly set so the
stylesheet's red (#ef4444) actually applies.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 22:16:29 +02:00
thandClaude Opus 4.7 28e6e5bcfc style: marker now uses pointer cursor, bold-not-underline on select, red by default
- cursor: pointer signals the click-to-jump affordance more clearly
  than ew-resize (which suggested "drag only")
- selected marker switches to font-weight 700 on the label instead of
  underlining it
- default --marker-color is now a classic red (#ef4444). User can
  still override per-marker via setMarkerColor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 22:14:56 +02:00
thandClaude Opus 4.7 06ca0b4d0e fix: marker double-click blocked by scrub handle overlap
After a single click the playhead snapped to the marker's time, which
moved the scrub handle's hit area directly on top of the marker flag.
The second click then landed on the handle (z-index 20) instead of
the marker (z-index 18), so dblclick never fired. Raised marker
z-index to 21 so marker-hits win at overlapping positions — still
below modals/popups (900+).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 22:12:36 +02:00
thandClaude Opus 4.7 024883943b macro-clips slice 4c: button creation in sidebar + drag to clip tracks
- store.seedDefaultButtonClip(name) adds a button clip with a single
  shared rect asset and four pre-populated state stacks in blue shades
  (normal/hover/pressed/disabled). Layer name 'Face' is consistent so
  transitions can later pair layers by name.
- AssetSidebar gets a Buttons section below Clips: create via prompt,
  rename, delete, drag-to-track. Drag uses a new dataTransfer type
  'application/x-animatr-button-clip' to keep it distinct from
  animation-clip drops.
- Timeline clip-lane drop accepts both types and dispatches
  addClipInstance / addButtonInstance accordingly; the new-track
  drop zone handles both too, so dragging a button to an empty area
  creates a fresh clip track + instance in one step.
- i18n for the sidebar strings and three dialogs.
- test covers seedDefaultButtonClip: four populated states, shared
  asset, consistent layer name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 21:31:41 +02:00
thandClaude Opus 4.7 94ebbac238 macro-clips slice 4b: button instance dialog
- ButtonInstanceDialog.vue edits the three instance-scope fields:
  label (with uniqueness error surface), disabled flag, onClick
  actions via the shared ActionEditor
- commit waits on a successful label set so collisions show inline
  instead of silently dropping the rename
- Timeline wires click on a button-instance block to open the dialog

Creation/placement UX (sidebar entry + drag-to-track) and the per-state
layer editor are still deferred — this slice only makes existing
instances editable once something (devtools, later slice) has put them
on a clip track.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 21:16:25 +02:00
thandClaude Opus 4.7 b9d1ca16f7 macro-clips slice 4a: script frame dialog + reusable action editor
- ActionEditor.vue — reusable list editor for Action[]: add/remove/reorder,
  per-type parameter forms (jump to time/frame/marker, set button
  state/disabled, script source). Marker and button dropdowns pull from
  the store's current scene.
- ScriptFrameDialog.vue — modal wrapping ActionEditor plus time and label
  inputs; commits on close, supports deletion.
- Timeline wires the dialog: clicking a script frame opens it for edit,
  clicking the empty script lane creates a new frame at that time and
  opens the editor.
- i18n keys for all action types, parameters, and dialog labels.

Button-authoring UI (definitions + instance placement + properties panel)
is its own slice (4b) — this commit ships script authoring only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:54:24 +02:00
thandClaude Opus 4.7 92d58937e3 macro-clips slice 3: timeline rendering for scripts and button instances
- TimelineScriptTrack added to the track union; tracks computed emits one
  per ScriptTrack in trackOrder, with the show-locked filter honoring its
  locked flag
- script track row: drag handle + PhCode name badge + lock button; lane
  renders each ScriptFrame as an orange dot with optional action-count
  badge
- button instances render inside clip-track lanes as 4 cells labeled
  N/H/P/D, colored per state, with a striped pattern on disabled and a
  fixed visual width per cell
- new scrub-bar button to add a script track (PhCode icon)
- type narrowing tightened so inGroup checks skip script/group tracks
  explicitly rather than relying on the negation

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:49:59 +02:00
thandClaude Opus 4.7 373a835576 macro-clips slice 2: marker UI on the scrub ruler
- marker flags render on the scrub ruler with color, label, and a dimmed
  vertical guideline; z-index sits below brackets and playhead
- click marker to jump the playhead, drag to retime (snaps), double-click
  to rename via prompt dialog, 'm' adds a marker at the playhead and
  opens the rename prompt
- rename collision shows a dialog and loops back into the prompt
- selectedMarkerId tracks the active marker; Delete/Backspace removes it,
  Escape clears the selection
- document keydown now gates m/Delete/Backspace on editable targets but
  keeps Escape universal

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:42:45 +02:00
thandClaude Opus 4.7 d4c4830fe2 0.6.0: background video, in/out range, top-level masks, track icons
- background video layer (document-level), syncs to playhead in editor and fullscreen
- playback in/out brackets on the scrub ruler; i/o set them, r rewinds to in-point
- togglePlay, tick, fullscreen loop, WebM + server FFmpeg export all honor [in, out]
- top-level mask layers cascade over everything below until a group boundary
- fullscreen preview slaves localTime to the bg video so it stops stuttering
- welcome "new project" now actually loads a blank scene (was a no-op)
- default canvas background hardened to white via normalizeScene
- new keyframe button (+) in the name-spacer, backspace/delete removes selected kfs
- drag-end auto-selects the created/shifted keyframe so the path is visible
- animation path updates live during drag and spans every selected keyframe
- track rows show an icon per asset kind (rect/circle/image/text/polygon/freeform)
- default mask mode is negative, buttons read − then +
- sticky track-name columns raised above playhead/brackets; orange bracket styling
- tests for playback range, blank scene, mask defaults, cascading top-level masks

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:19:34 +02:00
thandClaude Opus 4.7 69de48ea8d 0.5.6: show/hide locked tracks + group lock + crop/mask-preview split
- Timeline: new show/hide toggle next to snap; locked tracks (including
  layer, clip, and the new group lock) are filtered from the timeline
  when the toggle is off. Preference lives in localStorage and is
  shared across components via a module-level ref.
- Groups become lockable via the same inline lock toggle. A locked
  group propagates to its children: they behave as effectively locked
  in the timeline and on the stage. Collapse/expand still works on a
  locked group.
- Canvas: layers in locked+hidden tracks render as a 1px outline in
  the layer (or fill) color instead of their full fill, and are
  draggable:false / listening:false. Mask layers keep their dashed
  ghost styling; masks still apply in the preview overlay regardless
  of lock or show state.
- drawSceneFrame gains an optional `{ crop }` option; the mask-preview
  overlay passes the editor's crop toggle through, so the two controls
  are fully independent. Crop changes now also trigger a preview
  redraw via a watcher dep.
- Tests: new suites for show-locked persistence, group lock store
  action, crop option on drawSceneFrame (including mask+crop combos).
  Properties transparent-toggle tests now reset the section prefs
  localStorage so the Appearance section is guaranteed open when the
  panel mounts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:42:39 +02:00
thandClaude Opus 4.7 63042b284d 0.5.5: inline lock toggle, proper lock indentation
- Track lock becomes a small inline icon toggle sitting next to the
  track label, replacing the static badge and removing the context
  menu's lock/unlock entry.
- Locked tracks are fully inert: the lane and name have pointer-events
  disabled, only the lock button itself stays clickable. The pile of
  hover-neutralizing CSS rules is gone.
- Lock button is icon-only (no background/border box) and swaps to the
  opposite icon on hover (filled unlock when hovering a locked track,
  so the click affordance is obvious).
- Locked tracks in groups keep their indentation — the drag-handle
  switches from display:none to visibility:hidden so the reserved
  space still aligns with unlocked sibling layers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 14:37:40 +02:00
thandClaude Opus 4.7 6786ad739a 0.5.4: scrub head tapers into the playhead needle
Pentagon clip-path on the scrub handle head (flat top, straight sides
down to 55% height, triangle point at the bottom center) so the head
visually funnels into the 1px playhead needle below. box-shadow
replaced with a drop-shadow filter that respects the clip-path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 14:19:27 +02:00
thandClaude Opus 4.7 48f92015e4 0.5.3: timeline name-col resize + playhead layering
- Track-name resize strip starts below the scrub bar and sits on the
  name-column side of the boundary, so scrubbing at time=0 is no
  longer intercepted by the resize hit area.
- Playhead (lane) and scrub handle get z-index 20 so they stay on top
  of the sticky track-name column (z-index 5) and the resize strip.
  The playhead stays fully visible at time=0 and when the lane is
  scrolled under the sticky column.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 14:13:33 +02:00
thandClaude Opus 4.7 276d621d20 0.3.0: freeform drawing, stroke properties, polygon edit gestures
- Freeform drawing tool: new sidebar button enters a click-to-draw mode
  that appends points, shows a live ghost preview line, and exits via
  Enter or double-click (near the start point closes the path). Works
  end-to-end through all four render pipelines.
- Polygon authoring gestures: double-click on a path inserts a vertex on
  the nearest edge; double-click on an open polygon's endpoint resumes
  the drawing session from that end, reversing point order when needed.
- Stroke + closed-path properties: all shape types (rect, circle, text,
  polygon) expose stroke color, stroke width, and (for polygons) a
  closed toggle. Fill and stroke each support a "transparent" switch so
  shapes can render as outline-only or fill-only.
- Mask preview no longer inherits the user's stroke — the dashed ghost
  keeps its own outline regardless of stroke-width changes.
- Playhead no longer dims on inactive timeline tracks; only keyframes,
  segments and clip blocks fade.
- Properties panel point-count control for polygons, plus per-keyframe
  points animation that correctly interpolates once a baseline exists.
- Pivot drag hides the rotation handle until release.
- Transformer attach retries on a short timer to avoid races where the
  Konva node hasn't mounted yet when selection changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 09:53:01 +02:00
th 03b1147a93 bak 2026-04-20 01:05:27 +02:00
th 43933f93d1 bak 2026-04-20 00:29:12 +02:00
th 3ef5fb5a2d bak 2026-04-20 00:07:08 +02:00
th 6b6157d786 bak 2026-04-19 22:32:06 +02:00
th fcefd258eb bak 2026-04-19 21:40:09 +02:00
th e851d52aef bak 2026-04-19 21:17:07 +02:00
th b977ee35a8 bak 2026-04-19 21:13:53 +02:00
th cc6b11e61d bak 2026-04-19 20:31:53 +02:00
th e4aa0dce86 bak 2026-04-19 19:32:23 +02:00
th 94e9846c13 bak 2026-04-19 19:07:51 +02:00
th c6863f2bfc init 2026-04-19 17:53:36 +02:00