10 KiB
v0.1.3 Polish & Tweaks — Design Spec
Date: 2026-09-22 Version: 0.1.2 → 0.1.3
Overview
Three UI polish features for v0.1.3: adjustable clip-list layout, improved timeline timestamp labels with a mouse-proximity magnification effect, and a custom right-click context menu on the timeline.
Feature 1: Adjustable Layout (Clip List Position)
Current State
The main content area is a vertical stack:
┌──────────────────────────────┐
│ Toolbar │
├──────────────────────────────┤
│ Video Preview │
├──────────────────────────────┤
│ Transport Controls │
├──────────────────────────────┤
│ Timeline / Thumbs / Waveform │
├──────────────────────────────┤
│ Clip List │
├──────────────────────────────┤
│ Status Bar │
└──────────────────────────────┘
Proposed: Two Layout Modes
A new clipListPosition preference ('bottom' | 'left') controls where the clip list appears. Default: 'bottom' (current behavior, unchanged).
When set to 'left', the layout becomes:
┌──────────────────────────────────────────┐
│ Toolbar │
├──────────┬───────────────────────────────┤
│ Clip │ Video Preview │
│ List │ │
│ │ │
│ ├───────────────────────────────┤
│ │ Transport Controls │
├──────────┴───────────────────────────────┤
│ Timeline / Thumbs / Waveform (full) │
├──────────────────────────────────────────┤
│ Status Bar │
└──────────────────────────────────────────┘
Key details:
- The clip list shares horizontal space only with the video preview and transport controls. The timeline remains full-width underneath — no horizontal space is sacrificed for timeline real estate.
- A vertical drag-to-resize handle sits between the clip list and the video area, allowing the user to adjust the sidebar width. Default width: ~220px. Min: 150px. Max: 40% of window width.
- The existing vertical resize handle between timeline and clip list only appears in
'bottom'mode. In'left'mode, the timeline height is controlled by the existingtimelineHeightstate (still resizable via a horizontal drag handle between the upper section and the timeline).
Toggle Button
A button in the toolbar (alongside ⚙ and ℹ) toggles between 'bottom' and 'left' modes. The icon visually hints at the current layout — e.g. a stacked-rows icon for bottom mode, a sidebar icon for left mode. Clicking it switches immediately and persists the preference.
Persistence
- Add
clipListPosition: 'bottom' | 'left'to thePreferencesinterface inpreferences.svelte.ts. - Add
clipListWidth: number(default 220) for the sidebar width in left mode. - Both are saved/loaded via the existing Tauri store mechanism.
Implementation Notes
App.svelteis the only component that needs structural changes.ClipList.svelte,VideoPlayer.svelte, andTimeline.svelteremain unchanged — they just get placed in different containers.- In
'left'mode, the.contentarea becomes:- A flex column with two children:
- Upper section (flex row):
[ClipList sidebar | flex column of [VideoPlayer, TransportControls]] - Lower section (same as before): timeline pane with resize handle
- Upper section (flex row):
- The vertical resize handle between the upper and lower sections works the same as the existing one.
- A flex column with two children:
- In
'bottom'mode: the current layout is preserved exactly. - The
ClipListcomponent needs no changes; it already fills its container. The only adjustment is removing theborder-topwhen in left mode (the sidebar should have aborder-rightinstead), which can be handled via a CSS class or prop.
Feature 2: Timeline Timestamp Labels
Current State
Timestamp labels are rendered at 10px font size in drawTimeTicks() in renderer.ts. They are small and hard to read.
Proposed Changes
- Increase base font size from
10pxto12px. - Mouse-proximity magnification effect: As the cursor moves along the timeline, labels near the cursor smoothly scale up. This creates an invisible "magnifying lens" effect for timestamps.
Magnification Behavior
- Radius: ~80px from cursor (in canvas pixel space).
- Peak size: ~18px directly under the cursor.
- Falloff: Smooth cosine interpolation from peak to base size. A label 80px away renders at base size; a label directly under the cursor renders at peak size.
- Vertical alignment: Labels stay bottom-aligned as they grow — the text baseline remains constant, so larger labels grow upward. This prevents layout jitter.
- Cursor leaves timeline: When the mouse leaves the canvas (
onmouseleave),mouseXis set tonulland all labels render at the base size. No magnification in this state.
Implementation Notes
Timeline.sveltealready handlesonmousemove. Add tracking of the mouse X coordinate (a simplelet mouseX = $state<number | null>(null)), updated onmousemoveand cleared onmouseleave.- Pass
mouseXintodrawTimeline()→drawTimeTicks(). drawTimeTicks()computes the per-label font size based on distance frommouseX:distance = abs(labelX - mouseX) if distance > MAGNIFY_RADIUS: scale = 0 else: scale = (1 + cos(PI * distance / MAGNIFY_RADIUS)) / 2 fontSize = BASE_FONT_SIZE + BONUS_FONT_SIZE * scale- Trigger a redraw whenever
mouseXchanges. SincerequestDraw()already coalesces viarequestAnimationFrame, this adds no extra frame overhead — it simply piggybacks on the next scheduled frame.
Feature 3: Timeline Right-Click Context Menu
Current State
Right-clicking the timeline shows the default web/Tauri context menu (Reload, Inspect Element), which is not useful.
Proposed: Custom Context Menu
A styled context menu appears on right-click anywhere on the timeline canvas. Right-clicking also moves the playhead to the clicked position.
Menu Items
| # | Label | Behavior | Availability |
|---|---|---|---|
| 1 | Mark In | Sets in-point at the right-clicked time (calls markInPoint) |
Always |
| 2 | Mark Out | Sets out-point at the right-clicked time (calls markOutPoint) |
Always |
| — | (separator) | ||
| 3 | Go to Clip Start | Seeks playhead to selectedClip.startTime |
Disabled if no clip selected |
| 4 | Go to Clip End | Seeks playhead to selectedClip.endTime |
Disabled if no clip selected |
| — | (separator) | ||
| 5 | Delete Clip | Removes the selected clip | Hidden if no clip selected |
Behavior
- Right-click on canvas:
contextmenuevent is intercepted, default is prevented. The playhead moves to the clicked time position. The context menu appears at the cursor's screen coordinates. - Selecting an item: Executes the action and closes the menu.
- Closing without action: Click anywhere outside the menu, press Escape, or scroll — the menu closes.
- Positioning: The menu is rendered as a positioned
<div>appended at theApp.sveltelevel (or uses a portal pattern) so it isn't clipped by anyoverflow: hiddencontainers. If the menu would extend beyond the window edge, it flips direction (e.g. opens leftward or upward).
Component: TimelineContextMenu.svelte
Props:
x: number— screen X positiony: number— screen Y positiontime: number— the timeline time at the right-click positionselectedClipId: string | null— to determine which items are enabled/hiddenonAction: (action: ContextMenuAction) => void— callback for menu item selectiononClose: () => void— callback to close the menu
Actions (discriminated union):
type ContextMenuAction =
| { type: 'mark-in' }
| { type: 'mark-out' }
| { type: 'go-to-clip-start' }
| { type: 'go-to-clip-end' }
| { type: 'delete-clip' };
Styling
- Dark theme matching the app's existing style (dark background, light text, hover highlights).
- Subtle border/shadow to float above the timeline.
- Disabled items: dimmed text, no hover effect, not clickable.
- Separators: thin horizontal lines using
var(--border).
Implementation Notes
Timeline.svelteadds anoncontextmenuhandler on the canvas element.- The handler computes the time from the click X coordinate (using existing
computeClickTime), seeks the playhead, and emits an event / sets state to show the context menu. - The context menu component is rendered conditionally in
Timeline.svelte(orApp.svelteif clipping is an issue). - Keyboard shortcut hints can optionally be shown in the menu items (e.g. "Mark In I") for discoverability.
Version Bump
Execute scripts/bump-version.sh after incrementing VERSION.
Confirm all locations updated from 0.1.2 → 0.1.3:
package.json—versionfieldsrc-tauri/tauri.conf.json—versionfieldsrc-tauri/Cargo.toml—versionfieldgrep/findfor remaining0.1.2references, fix any, and add toscripts/bump-version.sh
Scope Boundaries
- No changes to the backend (Rust). All three features are purely frontend.
- No changes to clip store logic — existing
markInPoint,markOutPoint,removeClip,selectClipfunctions are reused as-is. - No new dependencies.
- The context menu does NOT appear on the minimap — only on the main timeline canvas.