chore: stage all pending work — caption styling, media server, processing modal, docs, summaries

Includes:
- Extended caption styling (font, shadow, dimmed color, bg toggle)
- Media server, subtitle downloader, VTT parser, processing modal
- Waveform tiers, thumbnail/timeline improvements, transport controls
- Hybrid download model, dependency management, clip export enhancements
- 21 chat summaries, 2 implementation plans, 2 design specs

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-22 10:48:16 -04:00
parent fd05ae19b5
commit 8ad2f1c800
57 changed files with 4929 additions and 210 deletions

View File

@@ -0,0 +1,95 @@
# Extended Caption Styling: Font, Shadow, Dimmed Color
**Date:** 2026-09-22
**Scope:** Add font selection (system font detection), drop shadow controls, dimmed/unspoken text color customization, and background toggle to the shared caption settings panel.
## Problem
Several burn-in caption style properties are hardcoded: font is always Arial, shadow is always off, and the dimmed (unspoken) text color in word-by-word mode is a hardcoded grey (`&H73CCCCCC`) that doesn't relate to the user's chosen text color. The preview uses a different approach (CSS opacity on the main color), creating a visual mismatch between preview and exported captions.
## New Settings Fields
Added to `CaptionSettings` (frontend) and `CaptionStyle` (backend):
| Field | Type | Default | Description |
|---|---|---|---|
| `fontFamily` | string | `'Arial'` | Font family name from system fonts |
| `backgroundEnabled` | boolean | `true` | Explicit toggle for the background box (replaces relying on opacity=0) |
| `shadowEnabled` | boolean | `false` | Drop shadow toggle (mutually exclusive with background) |
| `shadowDepth` | number (1-5) | `2` | Shadow offset in ASS units |
| `shadowColor` | string | `'#000000'` | Shadow color (hex) |
| `dimmedColorMode` | `'auto' \| 'custom'` | `'auto'` | How unspoken word color is derived |
| `dimmedOpacity` | number (0.1-0.9) | `0.4` | Opacity for auto-derived dimmed color |
| `dimmedColor` | string | `'#999999'` | Custom dimmed color (used in custom mode) |
## Background / Shadow Mutual Exclusivity
Background and shadow are **mutually exclusive**. Enabling one disables the other. This is required because ASS uses `BackColour` for both the background box and shadow color — they cannot be independent simultaneously.
### ASS BorderStyle Mapping
| Background | Outline | Shadow | ASS BorderStyle | ASS Outline | ASS Shadow |
|---|---|---|---|---|---|
| ON | ON | - | 4 | 2 | 0 |
| ON | OFF | - | 3 | 0 | 0 |
| - | ON | ON | 1 | 2 | depth |
| - | OFF | ON | 1 | 0 | depth |
| OFF | ON | OFF | 1 | 2 | 0 |
| OFF | OFF | OFF | 1 | 0 | 0 |
When **background is ON**: `BackColour` = `backgroundColor` + `backgroundOpacity` alpha.
When **shadow is ON**: `BackColour` = `shadowColor` (fully opaque).
When **neither**: `BackColour` = transparent (`&HFF000000`).
## Dimmed Text Color
In word-by-word (karaoke) mode, unspoken words appear in a dimmed color (ASS `SecondaryColour`).
### Auto Mode (default)
The dimmed color is derived from the main `textColor` at `dimmedOpacity`. Both preview and burn-in use the same approach:
- **Preview CSS:** `opacity: {dimmedOpacity}` on unspoken word spans (current behavior, but using the configurable value instead of hardcoded 0.4)
- **Burn-in ASS:** `SecondaryColour = hex_to_ass_color_with_alpha(textColor, (1 - dimmedOpacity) * 255)`
### Custom Mode
The user picks a specific `dimmedColor`. Both preview and burn-in use it directly:
- **Preview CSS:** `color: {dimmedColor}; opacity: 1` on unspoken word spans
- **Burn-in ASS:** `SecondaryColour = hex_to_ass_color(dimmedColor)`
## System Font Detection
A new Tauri command `list_system_fonts` runs `fc-list : family` (fontconfig, available because ffmpeg/libass depend on it). Output is parsed into a sorted, deduplicated list of font family names.
- Called once when the caption settings panel opens; result is cached in component state.
- If `fc-list` is not available, falls back to a hardcoded preset list: Arial, Helvetica, Verdana, Georgia, Times New Roman, Courier New, Impact.
- The dropdown renders each option with `font-family` set to that font's name, providing a live preview of each font.
## Panel UI Layout
The settings panel (320px wide) is organized into grouped sections:
1. **Font**: Dropdown (system fonts) + Size slider + Bold checkbox
2. **Text Color**: Color picker
3. **Dimmed Text**: Auto/Custom toggle. Auto: opacity slider. Custom: color picker.
4. **Outline**: Checkbox + color picker (disabled when unchecked)
5. **Background** (mutually exclusive with shadow): Checkbox + color picker + opacity slider
6. **Shadow** (mutually exclusive with background): Checkbox + depth slider + color picker
7. **Position**: Bottom/Top radio
8. **Word Highlight**: Checkbox (karaoke on/off)
9. **Reset to defaults** button
## Files Changed
| File | Change |
|---|---|
| `src/lib/stores/preferences.svelte.ts` | Add new fields to `CaptionSettings` interface and defaults |
| `src-tauri/src/models.rs` | Add new fields to `CaptionStyle` struct |
| `src/lib/bindings/export.ts` | Update TS `CaptionStyle` interface |
| `src/lib/components/ExportDialog.svelte` | Pass new fields through to export config |
| `src-tauri/src/services/clip_exporter.rs` | Use font, shadow, dimmed color, background toggle in ASS generation |
| `src/lib/components/CaptionSettingsPanel.svelte` | Add font dropdown, shadow controls, dimmed color controls, background toggle |
| `src/lib/components/VideoPlayer.svelte` | Use dimmed color settings + font in preview CSS |
| `src-tauri/src/commands/media_analysis.rs` (or new file) | Add `list_system_fonts` command |
| `src-tauri/src/lib.rs` | Register new command |
| `src/lib/bindings/mediaAnalysis.ts` (or new binding) | TS binding for `list_system_fonts` |