Files
gui-video-clipper/docs/superpowers/specs/2026-09-23-v021-polish-and-cut-clip-design.md

160 lines
5.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# v0.2.1 — Polish, Icons, Cut Clip & Shortcuts Reference
## Overview
Incremental polish release building on v0.2.0 Player mode. Six changes: controls position tweak, Lucide icon migration, blur animation fix, mode toggle shortcuts, cut-clip feature, and keyboard shortcuts reference in the About dialog.
---
## 1. Floating Controls Position & Blur Fix
### Position
Raise `.player-controls-overlay` from `bottom: 48px` to `bottom: 64px` (+16px).
### Blur Pop-in Fix
**Problem:** `backdrop-filter: blur(8px)` is on `.player-controls-panel` while the parent `.player-controls-overlay` transitions `opacity: 0 → 1`. WebKit doesn't smoothly composite `backdrop-filter` through an ancestor `opacity` transition — the blur snaps on once opacity crosses a rendering threshold.
**Fix:** Move the blur background into a `::before` pseudo-element on `.player-controls-panel`. The pseudo-element handles `background` + `backdrop-filter` and has its own `opacity` transition driven by the `.visible` class on the overlay ancestor. The panel itself becomes `position: relative` with no background/backdrop-filter of its own.
```css
.player-controls-panel {
position: relative;
/* background and backdrop-filter removed */
}
.player-controls-panel::before {
content: '';
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.75);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 12px;
z-index: -1;
opacity: 0;
transition: opacity 0.25s ease;
}
.player-controls-overlay.visible .player-controls-panel::before {
opacity: 1;
}
```
---
## 2. Lucide Icon Migration
Install `lucide-svelte` as a dependency. Replace all emoji and text-glyph icons with Lucide SVG components across `PlayerControls.svelte`, `TransportControls.svelte`, and the `App.svelte` toolbar.
### Icon Mapping
| Current | Lucide Component | Location |
|---|---|---|
| 🔇 / 🔉 / 🔊 | `VolumeX` / `Volume1` / `Volume2` | PlayerControls, TransportControls |
| ⏪ | `SkipBack` | PlayerControls |
| ❚❚ / ▶ | `Pause` / `Play` | PlayerControls, TransportControls |
| ⏩ | `SkipForward` | PlayerControls |
| CC (text) | `Captions` | PlayerControls |
| ⧉ | `PictureInPicture2` | PlayerControls |
| ⛶ / ⤓ | `Maximize` / `Minimize` | PlayerControls |
| ⚙ | `Settings` | App toolbar |
| ℹ | `Info` | App toolbar |
| ⬒ / ⬓ | `PanelLeft` / `PanelBottom` | App toolbar |
| ✂️ (new) | `Scissors` | PlayerControls (cut clip button) |
| ◄K / K► | `ChevronFirst` / `ChevronLast` | TransportControls |
| ◄\| / \|► | `StepBack` / `StepForward` | TransportControls |
Icons render inline as SVGs. Size: 16–18px to match existing button dimensions.
---
## 3. Mode Toggle Shortcuts
Both `C` and `P` keys become bidirectional toggles. Pressing either key switches from the current mode to the other mode.
Implementation: both the `'c'/'C'` and `'p'/'P'` cases in `handleGlobalKeydown` call `toggleMode()` instead of hard-coding a target mode via `setAppMode()`.
---
## 4. Cut Clip Feature
### Button
A scissors icon (`Scissors` from Lucide) in the `PlayerControls` right control group, positioned between the speed selector and the CC button.
### Behavior
- **Left-click / `X` key:** Create a 10-second clip starting at the current playhead position (`currentTime` → `currentTime + 10`). Clamp end to `session.duration`. Switch to Clipper mode. Playhead stays at its current position.
- **Right-click / `Z` key:** Create a 10-second clip ending at the current playhead position (`currentTime - 10` → `currentTime`). Clamp start to `0`. Switch to Clipper mode. Playhead stays at its current position.
### Implementation
- Add a `cutClip(position: 'at' | 'before')` helper. It calls `addClip(start, end)` from the clips store, then `setAppMode('clipper')`.
- Pass an `onCutClip` callback prop to `PlayerControls`. The button's `onclick` calls `onCutClip('at')`, `oncontextmenu` prevents default and calls `onCutClip('before')`.
- In `handleGlobalKeydown`: `X`/`x` → `cutClip('at')`, `Z`/`z` → `cutClip('before')`. Only active in Player mode.
- **Tooltip:** "Cut clip at playhead (X) · Right-click: 10s before (Z)"
### Edge Cases
- No video loaded (`session.duration === 0`): no-op.
- Playhead < 10s from start: `Z`/right-click clamps start to 0.
- Playhead < 10s from end: `X`/left-click clamps end to duration.
---
## 5. Tabbed About Dialog with Keyboard Shortcuts
### Tab Structure
Two tabs: **About** (default) and **Shortcuts**.
### About Tab
Identical to current content (icon, app name, version, author, license, repo link, close button). Dialog stays at ~360px wide.
### Shortcuts Tab
Two-column layout (key on left, description on right) grouped by section headers. Dialog expands to ~520px wide with `max-height: 70vh` and vertical scroll. Width change transitions smoothly (`transition: max-width 0.2s ease`).
Tab switcher: text tabs at the top of the dialog, active tab gets accent-color underline.
### Complete Shortcut Reference
**Global (both modes):**
| Key | Action |
|---|---|
| `Space` | Play / Pause |
| `K` | Play / Pause |
| `J` | Shuttle slower (−0.25×) |
| `L` | Shuttle faster (+0.25×) |
| `←` | Seek back 5s |
| `→` | Seek forward 5s |
| `Shift+←` | Seek back 1s |
| `Shift+→` | Seek forward 1s |
| `,` | Previous frame |
| `.` | Next frame |
| `<` (Shift+,) | Previous keyframe |
| `>` (Shift+.) | Next keyframe |
| `C` / `P` | Toggle mode |
| `Cmd+/` | About |
**Player mode:**
| Key | Action |
|---|---|
| `F` | Toggle fullscreen |
| `X` | Cut clip at playhead → Clipper |
| `Z` | Cut clip 10s before playhead → Clipper |
**Clipper mode:**
| Key | Action |
|---|---|
| `I` | Set in-point |
| `O` | Set out-point |
| `Delete` / `Backspace` | Remove selected clip |
| `Cmd+E` | Export |