loop. clip. navigate by scene.
clipper is a tiny, client-only web app for working closely with video (and audio): scrub a file, set A / B points, save replayable clips, and jump around a long video using a 2D visual seek grid of thumbnails instead of blind scrubbing.
Everything runs in your browser. Your media never leaves the device, nothing is uploaded, and there is no backend.
Finding the right moment in a multi-hour video by dragging a 1D timeline is guesswork. clipper shows the whole video as a grid of scene thumbnails, so you navigate visually, then mark and loop the exact range you care about (practising a passage, studying a clip, transcribing, etc.).
- 2D seek grid - thumbnails laid out in a grid; tap/click a cell to jump there.
- A-B clips - set A and B, then save named, replayable clips per file.
- Loop playback - loop the current A-B range with one button.
- Local history - recently opened files and their clips are remembered (localStorage); import/export your data as JSON.
- Video and audio, playback speed (0.5x - 2x), custom fullscreen, drag and drop.
- Open by URL -
app/?src=<video-url>loads a video directly (handy for sharing a demo link or pointing at a file on a local server). - PWA - installable, works offline once loaded.
- Open the app.
- Drop a video/audio file onto the player, or click to pick one. Or open
app/?src=<url>to load one by URL. - Expand Video Thumbnails to build the seek grid; tap a cell to seek.
- Set A and B, hit 💾 Save Clip, and 🔁 Loop to loop the range.
| Key | Action |
|---|---|
Space |
play / pause |
← / → |
seek -5s / +5s (Shift = 10s) |
A / B |
set point A / B |
S |
save clip |
L |
toggle loop |
F |
fullscreen |
Esc |
clear A-B (or exit fullscreen) |
In the seek grid: tap a cell to seek, drag horizontally to scrub, drag vertically to scroll, arrow keys move the marker.
The grid is powered by vam-seek by unhaya,
vendored into vendor/vam-seek.js. clipper ships a patched copy that fixes the
behaviour on mobile Safari (changes are tagged clipper: in the file):
- Tap-to-seek now works. iOS Safari does not repaint a paused video when you
only set
currentTime, so tapping a cell looked like it did nothing. clipper forces the seeked frame to present with a brief play/pause tick. - The grid scrolls again. Touch handling was rewritten around
touch-action: pan-y: a tap seeks, a horizontal drag scrubs, and a vertical drag scrolls the list natively (the old code blanket-blocked scrolling). - Long videos stay responsive. Frames are now extracted lazily as cells scroll into view (IntersectionObserver) instead of decoding every cell up front, which matters a lot for multi-hour files.
- Lower idle cost. The marker follow loop is a play/pause-gated rAF instead of a permanent 16ms timer.
It is plain HTML/CSS/JS with no build step. Any static server works:
cd clipper
python3 -m http.server 8080
# open http://localhost:8080/ (landing)
# open http://localhost:8080/app/ (app)For testing large videos by URL you want HTTP range support; see test/ for a
small range-capable server and the iOS-simulator / WebKit test harness used to
verify the mobile fixes.
Hosted from the main branch root (Settings -> Pages -> Source: "Deploy from a
branch" -> main / / (root)). It is a static site; .nojekyll disables Jekyll
processing. All links are relative so it works under the /clipper/ project path.
Vanilla HTML + CSS + JS. No framework, no bundler, no dependencies to install. The
only third-party code is the vendored, patched vendor/vam-seek.js.
- Seek grid: VAM Seek by Susumu Takahashi (unhaya), used under its CC BY-NC based license.
- clipper is a personal, non-commercial project. See LICENSE and vendor/VAM-SEEK-LICENSE.