Video tools

Extract video frames

Pull out one frame every N seconds as a sequence of PNGs, in the browser only, like pdf-to-image (src/tools/pdf-to-image.ts), because decoding frames needs WebCodecs, which Node has no equivalent of. Nothing is uploaded.

Runs on your device. The file is never uploaded.

Extract video frames samples one PNG every intervalSec seconds of a clip, one second apart by default, stopping at maxFrames, which is 60. Files are named after the video with a three-digit counter, such as clip-001.png, so they sort in time order. Decoding frames calls WebCodecs, which Node lacks, so the CLI and MCP surfaces refuse this one.

Input

Options

Questions

How many frames will I get?

One every intervalSec seconds, which defaults to 1, stopping at maxFrames, which defaults to 60. So the default settings give you at most a minute of one frame per second. Raise maxFrames if you need more, but remember every frame is a separate PNG held in memory until you download it.

What are the files called?

Your video name with a three digit counter and a .png ending, for example clip-001.png, clip-002.png and so on, in time order, so they sort correctly in any file manager. PNG is the only output format here. For a single frame in PNG or JPEG, use Video thumbnail instead.

Why is there a maxFrames cap at all?

So a long video cannot silently produce thousands of files. Sampling an hour long recording once a second would mean 3600 PNGs built in your browser memory at the same time. The cap stops early instead, and you can raise it deliberately when you know what you are asking for.

Why did it say my video is shorter than the interval?

Because no sample time fell inside the file. The tool builds the list of timestamps by stepping from zero to the video duration by intervalSec, and if that list is empty it refuses with the duration and the interval both named. Lower intervalSec so that at least one sample lands inside the clip.

Why will it not run on the command line?

Because decoding frames needs WebCodecs, which Node does not implement. The CLI and MCP surfaces refuse it with "video-extract-frames needs a browser (OffscreenCanvas). Use it at /video/video-extract-frames instead." The web page runs the same code in a Web Worker. Everything still stays on your device, since that worker runs inside the page you have open.

Is my video uploaded?

No. The file is decoded in your own tab and the PNGs are built there too. Nothing reaches a server. Both the source video and every extracted frame are held in memory at once, so a long video with a high maxFrames is the case most likely to run a tab out of room.

Related Video tools

n→nVideo thumbnailGrab a single frame from a video as a PNG or JPEG, in the browser only, like pdf-to-image (src/tools/pdf-to-image.ts), because decoding a frame needs WebCodecs, which Node has no equivalent of.Runs on each file you dropn→nVideo to GIFConvert a video clip to an animated GIF. In the browser only, like video-extract-frames (src/tools/video-extract-frames.ts), because decoding frames needs WebCodecs, which Node has no equivalent of. WebCodecs has no GIF codec at all, so this decodes frames with mediabunny/WebCodecs and then builds the GIF89a bytes itself (src/gif.ts): one shared 256-colour palette (median-cut, sampled across every frame this tool decodes, not per-frame) so colours stay consistent frame to frame, with each pixel mapped to its nearest palette entry. No dithering.Runs on each file you dropn→nGIF to videoConvert an animated GIF into a video, in the browser only, like video-convert (src/tools/video-convert.ts), because encoding needs WebCodecs, which Node has no equivalent of. WebCodecs has no GIF codec at all, so this parses the GIF89a bytes itself (src/gif.ts), including disposal method and transparency compositing, so a GIF built from partial-frame deltas decodes to the same full frames a browser would show, not only its raw per-frame rectangles. It then feeds the composited frames to mediabunny/WebCodecs to encode. Always outputs MP4, following every other Node-native remux tool in this codebase; each frame's own GIF delay becomes its video frame duration. MP4 has no alpha channel, so any transparent GIF pixel, composited onto a canvas that starts fully transparent black, becomes opaque black in the video, not the checkerboard a GIF viewer shows; verified by executing this tool against a transparent fixture and reading the pixel back out.Runs on each file you drop