Skip to content

Add ShadowClip Web: browser-based clip editing, no install required#22

Open
samyost wants to merge 1 commit into
dkuc:masterfrom
samyost:claude/browser-video-editing-clips-ae9no4
Open

Add ShadowClip Web: browser-based clip editing, no install required#22
samyost wants to merge 1 commit into
dkuc:masterfrom
samyost:claude/browser-video-editing-clips-ae9no4

Conversation

@samyost

@samyost samyost commented Jul 9, 2026

Copy link
Copy Markdown

A fully client-side editor under web/ — drop ShadowPlay recordings into the page and trim/export clips without installing anything. Files never leave the machine.

  • Frame-by-frame scrubbing forwards AND backwards: exact frame rate is parsed from the MP4 sample table (stts/mdhd) and steps are anchored to the presentation timestamp of the on-screen frame via requestVideoFrameCallback, so rapid stepping stays frame-exact.
  • Drag-on-video fine scrubbing (~1 ms/px, Shift for coarse), click to play/pause, keyboard shortcuts matching the desktop app.
  • Segments with per-segment speed (0.25x-4x) and center zoom (1x/2x/4x), timeline with thumbnail filmstrip and draggable segment edges; segments are concatenated on export like the desktop app.
  • In-browser export via ffmpeg.wasm using the same filter graph as the desktop FfmpegEncoder (trim/setpts, scale+crop zoom, setpts/atempo speed, concat, optional setdar 16:9), with stream-copy fast path under the same restrictions. Output is normalized to the source frame rate when speeds change, fixing timestamp mangling the CFR default causes.
  • Screenshot to clipboard (Safari-compatible promise ClipboardItem), audio presence probing for non-MP4 containers, HEVC/undecodable sources still exportable via parsed metadata, Infinity-duration WebM handling, and single-threaded ffmpeg core so no COOP/COEP headers are needed (hostable on GitHub Pages).
  • vendor/ffmpeg-worker.js: self-contained @ffmpeg/ffmpeg 0.12.10 module worker (MIT) so the engine loads from a CDN cross-origin.

Verified end-to-end in headless Chromium with pixel-level frame checks (33 assertions: fps parsing incl. 59.94/moov-at-end, bidirectional and rapid stepping, segment ops, copy/re-encode/video-only/WebM exports decoded and checked with native ffmpeg).

Claude-Session: https://claude.ai/code/session_01NiZVridAzJ92rnDPXWh3PK

A fully client-side editor under web/ — drop ShadowPlay recordings into
the page and trim/export clips without installing anything. Files never
leave the machine.

- Frame-by-frame scrubbing forwards AND backwards: exact frame rate is
  parsed from the MP4 sample table (stts/mdhd) and steps are anchored to
  the presentation timestamp of the on-screen frame via
  requestVideoFrameCallback, so rapid stepping stays frame-exact.
- Drag-on-video fine scrubbing (~1 ms/px, Shift for coarse), click to
  play/pause, keyboard shortcuts matching the desktop app.
- Segments with per-segment speed (0.25x-4x) and center zoom (1x/2x/4x),
  timeline with thumbnail filmstrip and draggable segment edges;
  segments are concatenated on export like the desktop app.
- In-browser export via ffmpeg.wasm using the same filter graph as the
  desktop FfmpegEncoder (trim/setpts, scale+crop zoom, setpts/atempo
  speed, concat, optional setdar 16:9), with stream-copy fast path under
  the same restrictions. Output is normalized to the source frame rate
  when speeds change, fixing timestamp mangling the CFR default causes.
- Screenshot to clipboard (Safari-compatible promise ClipboardItem),
  audio presence probing for non-MP4 containers, HEVC/undecodable
  sources still exportable via parsed metadata, Infinity-duration WebM
  handling, and single-threaded ffmpeg core so no COOP/COEP headers are
  needed (hostable on GitHub Pages).
- vendor/ffmpeg-worker.js: self-contained @ffmpeg/ffmpeg 0.12.10 module
  worker (MIT) so the engine loads from a CDN cross-origin.

Verified end-to-end in headless Chromium with pixel-level frame checks
(33 assertions: fps parsing incl. 59.94/moov-at-end, bidirectional and
rapid stepping, segment ops, copy/re-encode/video-only/WebM exports
decoded and checked with native ffmpeg).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NiZVridAzJ92rnDPXWh3PK
Copilot AI review requested due to automatic review settings July 9, 2026 22:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new ShadowClip Web client-side editor under web/ that enables trimming and exporting gameplay clips in the browser (including frame stepping and segment-based edits) using ffmpeg.wasm, plus documentation and a vendored ffmpeg worker to support module-worker loading.

Changes:

  • Introduces the web UI (HTML/CSS) and main editor logic (file list, playback/stepping, segments, timeline, screenshot, export flow).
  • Adds an MP4 metadata parser to derive exact FPS / frame count / audio presence for accurate stepping and export decisions.
  • Implements in-browser export via ffmpeg.wasm, including stream-copy vs re-encode modes, and a vendored module worker for ffmpeg core loading.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
web/vendor/ffmpeg-worker.js Vendored/inlined ffmpeg worker to support module-worker loading and CDN core usage.
web/README.md Documents running the static site, features, shortcuts, and limitations/self-hosting notes.
web/js/mp4.js Minimal MP4 parser to extract exact FPS and track/audio metadata.
web/js/exporter.js ffmpeg.wasm engine loader and export pipeline (filter graph + copy/encode modes).
web/js/app.js Main web app: UX, playback, frame stepping, segments/timeline, screenshot, export wiring.
web/index.html Static page layout and controls for the web editor.
web/css/style.css Styling for the web editor UI.
README.md Root README updated to link to the new web app.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread web/js/exporter.js
throw new Error(`ffmpeg exited with code ${rc}\n${logTail.slice(-8).join('\n')}`);
const out = await ff.readFile(outputName);
if (!out || out.length === 0) throw new Error('ffmpeg produced an empty file');
return new Blob([out.buffer], { type: 'video/mp4' });

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot no u

Comment thread web/js/app.js
Comment on lines +695 to +698
function xToTime(clientX) {
const rect = timelineEl.getBoundingClientRect();
return clamp(((clientX - rect.left) / rect.width) * state.duration, 0, state.duration);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants