Video clip support#4
Merged
Merged
Conversation
Add browser-native video/gif/webp clip support: probe + frame extraction (<video> seek / ImageDecoder), an MJPEG-AVI muxer, trim/budget math, and an encode orchestrator in src/lib/video/ (zero UI imports). Extend EditorSession with media/clip state, playback, size estimate and send; share the editor transform for per-frame rendering; carry clip params in history; thread an upload extension through the badge client. Unit tests for the muxer (incl. strict RIFF size-walk + buffer-size hint), clip math, detection, and session. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Filmstrip trim timeline with drag handles + scrub tab, playback bar, fps chips, frame-budget meter, and a media-type pill. The round preview becomes a canvas painted from the source video or decoded gif/webp frames through the editor transform. Auto-detect on pick/drop/paste; paste prefers an animated representation over a static one. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drive the clip flow against FakeBadge: upload a clip and assert an .avi file appears, the preview canvas paints real pixels, playback advances, an animated gif auto-detects as a clip, and a pasted animated webp does too. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
46e6d05 to
369498c
Compare
- Extract the interactive editor stage into Preview.svelte (canvas/video/gif rendering + rAF loop + input handling), leaving Composer as layout. - Add multi-touch pinch-to-zoom and twist-to-rotate (plus two-finger pan) alongside the existing drag / wheel / keyboard controls; e2e covers a pinch. - Reduce editor card padding and let the controls span the full card width. - Keep the timeline trim handles inside the strip so they no longer clip off the edge at the start and end. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Clips autoplay when loaded. - Frame rate and speed are now continuous sliders that snap to their preset stops (5/10/15/24 fps; 0.5/1/2x), with ticks positioned at each stop. - Speed now changes the uploaded clip's playback rate on the badge (same sampled frames, AVI declares a scaled fps via playbackFps) - not just preview. - Keep the first encoded frame as a snapshot: shown on the upload-success screen, and stored on history items so the Recent list renders a still (with a video badge) instead of the video blob, which broke for some formats. Video drafts get a first-frame snapshot too. - Move Fit inline into the Size row; put a small Reset next to Send to badge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ine + flow fixes - Show video snapshots (not the broken video blob) for clips on the badge file list, with a Clip chip; same snapshot reuse as the recent list. - Recent list: label rows by relative time (most have no filename) and mark videos with a Clip chip instead of the clipped corner play badge. - After Send, the Done button keeps the edit loaded instead of clearing it. - Preview simulates the chosen frame rate: repaint only on frame steps so a low fps visibly stutters like the badge (always live while editing). - Timeline: in/out handles now sit just outside the window edges with side gutters, so they can't cross each other on a tiny window and never clip at the ends. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Draft autosave was re-serializing the full original to IndexedDB on every edit, and prune() read every stored blob into memory just to drop the oldest. Now: video originals live in a write-once 'blobs' object store (loaded on demand via getBlob), metadata autosaves stay small, and prune walks the updatedAt index keys-only. Images keep their (small) blob inline. Restore loads the original from the blob store when needed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Correctness: - frames: frameAt() resolved immediately when no seek is needed (assigning currentTime its current value fires no 'seeked' event) - fixes a silent hang + leaked <video> when grabbing a frame at time 0. - editor-session: guard the debounced size estimate with a generation counter so a slow stale estimate can't overwrite a newer one; restore() only marks the blob dirty when the original came inline (not from the blob store). Cleanup: - reuse isAnimatedImageType in openFrameSource and Preview (was duplicated 3x). - export OUT from editor.ts and delete the duplicate video/dims.ts. - probeAnimatedImage counts frames without allocating every bitmap. - gate the playback playhead sync to frame steps, not every rAF. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds video clips (incl. animated GIF/WebP) as a second media type to Badgey, plus the editor/UX work and fixes that came out of iterating on it.
Core feature
Pipeline (browser-native, no ffmpeg.wasm)
New
src/lib/video/(zero UI imports):probe·frames(<video>seek +ImageDecoderfor GIF/WebP) ·clip(trim/budget/playback math) ·avi(MJPEG-AVI muxer) ·encode(orchestrator, the seam to add ffmpeg.wasm later). The badge receives the clip exactly like an image, with an.avidisplay name. Covers MP4/MOV/WebM/GIF/WebP; MKV/AVI/exotic codecs are out of native reach. The interactive stage was extracted intoPreview.svelte, leavingComposer.svelteas layout.Notable fixes
LISTsize must include its 4-byte type — ours were 4 bytes short, which desktop ffmpeg tolerates but the badge's strict parser faults on (the "AVI crashes the badge" bug). Also setdwSuggestedBufferSize.blobsobject store (loaded on demand); per-edit metadata autosaves stay small, andprunewalks the index keys-only instead of reading every stored blob.Verification
.avion the badge, preview paints, autoplay advances, success/recent snapshots, animated GIF + pasted WebP detection, and a two-finger pinch resize.bun run check0/0, build clean. A review round (multi-angle) was run and its findings applied.Design/spec/process docs are intentionally kept out of this repo (engineering notes live in ClickUp).
🤖 Generated with Claude Code