Scene Detector
Drop in a video. Get every cut, with a thumbnail and a timecode for each shot β found on your own machine, with nothing uploaded.
What a cut looks like to a machine
Within a single shot, consecutive frames resemble each other: the camera moves, people move, light shifts, but the change is gradual. At a cut, everything changes at once β the colour of the picture, its brightness, its structure, all in the space of one frame.
So shot detection is the search for discontinuities in an otherwise continuous signal. The hard part is not spotting the jump; it is not mistaking a whip-pan, a flash or a fast dissolve for one. That is why the boundaries here come with thumbnails: the fastest way to check a shot list is to look at it.
Why it runs on your machine
Video is heavy. Uploading a gigabyte to answer a question about where the cuts are means waiting on the upload, paying for the transcode and handing the footage over β for an analysis that reads a few hundred small frames.
The engine behind Life2Film was built to run on a phone, so it is small enough to run in a tab. The browser already has a video decoder; this page uses it, hands the pixels to the same Rust the app uses, compiled to WebAssembly, and never opens a socket.
The BPM detector is the same engine looking at sound instead of pictures.
Your file is read and re-encoded by your own browser. No request carries it anywhere β this page has no upload endpoint to send it to.
Questions
Does the video get uploaded?
No. The browser decodes it locally, a canvas reads the pixels, and WebAssembly compares them. Nothing is sent anywhere β the page has no endpoint to send it to. That is also why there is no file-size limit and no queue.
How does it find the cuts?
It samples frames across the video and watches how much the picture changes from one sample to the next. A cut is a discontinuity β colour and luminance jump in a single step, rather than drifting the way they do during a pan or a fade. The detector looks for those steps and reports the boundaries between them.
Will it catch dissolves and fades?
Partly. A hard cut is unambiguous and gets found reliably. A slow dissolve is, by construction, a gradual change β the same shape as a camera move β so it may be reported a little early, a little late, or merged with its neighbour. Fast whip-pans can also read as cuts. Treat the result as a shot list to check, not a verdict.
What is the quality score next to each shot?
The same per-frame scoring the Life2Film app uses when deciding what to keep: sharpness, exposure, contrast, colourfulness and entropy, combined into one number. It is a rough ranking of which shots are worth a second look, not a judgement of what is interesting.
Which files work?
Anything the browser can play β MP4 and MOV with H.264, and WebM. Formats a browser cannot decode, such as most ProRes or raw camera files, will not open here; transcode a proxy first.
How long does it take?
It steps through the video seeking to each sample point, which costs tens of milliseconds each time. A one-minute clip takes a few seconds. Long videos are sampled more coarsely so the wait stays reasonable β the shot list stays accurate to roughly half a second either way.
The other tools
Build this into your own project
Finding every cut in a video β the same way this page does it, on the user's machine, with no server. Take the code, or hand the prompt to a coding agent.
const engine = await import('https://life2film.com/wasm/va_wasm.js');
await engine.default({ module_or_path: 'https://life2film.com/wasm/va_wasm_bg.wasm' });
// 31 features per frame, from RGB24 pixels
const scored = JSON.parse(engine.score_frame(width, height, rgb24, timestamp, null)); Add shot-boundary detection to my project, running in the browser without uploading the video.
Requirements:
- Use the "life2film-engine" npm package (WebAssembly) for detection and the browser's own decoder for
frames: <video> plus a canvas works everywhere and needs no WebCodecs.
- Sample frames at ~64 px wide, take the mean RGB of the centre column, and pass pixels + timestamps
to detect_scenes_slick.
- Sampling rate decides accuracy far more than the algorithm does. Measured against a video with cuts
at known times: 2 samples/second put boundaries 1-3 seconds out and all sixteen algorithms failed
the same way; 10/second put them on the frame. Do a coarse pass, then refine around each candidate
at ten times the resolution and take the largest frame-to-frame change.
- Show a thumbnail per shot. The fastest way to check a shot list is to look at it, and a boundary
that is wrong is obvious in a picture and invisible in a number.
- Score each shot with score_frame and take the median, not the mean.
- Export as EDL, OTIO, FCPXML, Audacity labels, CSV or JSON, at a frame rate the user chooses.
- Cap the input length: each sample is a seek costing tens of milliseconds.
Reference implementation: https://life2film.com/tools/scene-detector/
The engine is documented for agents, and every tool page is available as
markdown by adding .md to its address.