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

@@ -1,9 +1,19 @@
import { session } from '$lib/stores/videoSession.svelte';
let _videoEl: HTMLVideoElement | null = null;
export function setVideoElement(el: HTMLVideoElement | null) {
_videoEl = el;
}
function getVideo(): HTMLVideoElement | null {
return _videoEl;
}
export function seekTo(time: number) {
const clamped = Math.max(0, Math.min(time, session.duration));
session.currentTime = clamped;
const videoEl = document.querySelector('video');
const videoEl = getVideo();
if (videoEl) {
videoEl.currentTime = clamped;
}
@@ -14,7 +24,7 @@ export function seekBy(seconds: number) {
}
export function togglePlayPause() {
const videoEl = document.querySelector('video');
const videoEl = getVideo();
if (!videoEl) return;
if (videoEl.paused) {
void videoEl.play();
@@ -24,7 +34,7 @@ export function togglePlayPause() {
}
export function stepFrame(direction: 1 | -1) {
const videoEl = document.querySelector('video');
const videoEl = getVideo();
if (videoEl && !videoEl.paused) {
videoEl.pause();
}
@@ -44,15 +54,38 @@ export function jumpKeyframe(direction: 1 | -1) {
}
}
export function setVolume(v: number) {
const videoEl = getVideo();
if (videoEl) {
videoEl.volume = v;
videoEl.muted = false;
}
}
export function setMuted(m: boolean) {
const videoEl = getVideo();
if (videoEl) {
videoEl.muted = m;
}
}
export function getVolume(): number {
return getVideo()?.volume ?? 1;
}
export function getMuted(): boolean {
return getVideo()?.muted ?? false;
}
export function resetShuttleRate() {
const videoEl = document.querySelector('video');
const videoEl = getVideo();
if (videoEl) {
videoEl.playbackRate = 1;
}
}
export function adjustShuttle(dir: 1 | -1, shuttleRate: number): number {
const videoEl = document.querySelector('video');
const videoEl = getVideo();
if (!videoEl) return shuttleRate;
const nextRate = Math.max(0.25, Math.min(4, shuttleRate + dir * 0.5));