# Jump Cutter fast-forwards silence in browser video without touching the file

> Jump Cutter is an AGPL-3.0 browser extension that skips the quiet parts of a video as it plays, using the Web Audio API to measure loudness in real time. The web platform will not let an extension look ahead in the audio, so the project ships two algorithms, a stretching one that is on by default and a cloning one that stays behind an experimental checkbox.

**WofWca/jumpcutter** — ⏩ Fast-forwards long pauses between sentences — watch lectures ~1.5x faster (browser extension)

- Repository: https://github.com/WofWca/jumpcutter
- Website: https://chrome.google.com/webstore/detail/jump-cutter/lmppdpldfpfdlipofacekcfleacbbncp
- Stars: 677 · Forks: 28
- Language: TypeScript
- License: AGPL-3.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/wofwca-jumpcutter

## Silence skipping for unedited video, in the browser

Jump Cutter is a browser extension that skips the silent parts of videos in real time. The intended uses are stated plainly in the project documentation: watching lectures, stream recordings, webinars, podcasts and other unedited video.

That word, unedited, is the key to the whole idea. A recorded lecture has pauses where the speaker thinks, a webinar has dead air while a slide loads, and a podcast has the gap between a question and an answer. None of that silence is worth the time it takes to watch, and none of it can be removed by an ordinary video player without re-encoding the file.

The extension is distributed through the Chrome Web Store, the Firefox Browser Add-ons site and the Microsoft Edge Add-ons site, and the project also publishes the packaged extensions directly on its releases page, a Chromium crx file and a Gecko xpi file. The project describes the result as watching lectures roughly 1.5 times faster, which is a claim about the effect on that kind of content rather than a guarantee for every video.

The project is written in TypeScript, published under the AGPL-3.0, and the author of the package is WofWca. The idea was inspired by a video by carykh, and the project still points at the analogous desktop software it grew out of, including the jump-cutter program by jfkthame and carykh's own jumpcutter.

## The web platform will not let you inspect audio ahead of the playhead

The reason the project is not simple is a platform limitation, and the project documentation is unusually candid about it.

With the current state of the web APIs, there is no direct way to inspect the audio samples of a media file or stream anywhere other than at the current playback position of the media element. To look ahead at the audio, you would need to decode it yourself, which means fetching and processing the media outside the element.

That constraint rules out the obvious implementation. The analogous software the documentation lists can all inspect audio freely: jump-cutter, the carykh jumpcutter project, the SilenceSkippingAudioProcessor in ExoPlayer, and the silenceremove filter in ffmpeg. Each of them can decide in advance exactly which spans are silent and remove precisely those, because a desktop tool or a native library is not limited to the playhead.

A browser extension is. It has to work with what the media element has already produced, which is why Jump Cutter ships two different algorithms rather than one good one. The two algorithms are separate code paths, each with its own controller, and the documentation notes that they have their own pros and cons even when the margin before a cut is set to zero.

The result is a compromise: a browser extension can save most of the dead air in a video, but it does not achieve the precision of a tool that edits the file.

## The stretching algorithm watches loudness and slows the buffer to save quiet onsets

The default algorithm looks at the output audio of the media element, determines its current loudness and, when the sound is not loud, increases the playbackRate. The implementation uses the Web Audio API createMediaElementSource to tap the element's audio and an AudioWorkletProcessor, the SilenceDetectorProcessor, to do the loudness analysis on the audio thread.

The subtlety is the part the project documentation spends most of its words on. This algorithm cannot look ahead. It only sees the current loudness, at the sample already sent to the audio output device.

That is a problem for speech, because some sounds that begin a word are quiet. Skip them and the speech becomes harder to follow: the documentation uses the example that throb would turn into rob. Context saves you, but it costs mental effort.

The stretching exists to fix that. The audio is always delayed, or buffered, by roughly 200 milliseconds before being output. Those 200 milliseconds were recorded while the video was playing at a high speed during silence, but they may contain the start of a quiet sound. So the buffered audio is slowed down, stretched and pitch-shifted, so that it plays back as though it had been recorded at normal speed. Only then does it go to the output device.

That is why the algorithm is called stretching. It trades a small, constant delay for the ability to preserve quiet onsets that would otherwise be fast-forwarded away, and it does so by re-timing audio that was already captured at the wrong speed.

## The cloning algorithm plays a hidden copy ahead and seeks past the gaps

The second algorithm takes the opposite approach to the same problem. Instead of reacting to the loudness of the audio as it arrives, it creates a hidden clone of the target media element and plays that clone ahead of the original. The clone is allowed to run forward, and when it hits a silent part, the position of that silence is written down.

When the visible element reaches a recorded silent part, the extension either increases its playbackRate or seeks past the silence entirely. Unlike the stretching algorithm, this one has advance knowledge, so it can skip a gap cleanly rather than speeding through it.

The cost is resource use. A second media element playing the same stream means a second decode and a second playback path, and the silent regions have to be detected and remembered before the main element reaches them. If the clone and the original drift out of sync, the recorded positions are wrong, and the skip lands in the wrong place.

This algorithm is not the default. The documentation says it can be enabled by checking the Use the experimental algorithm checkbox in the options, and its name in the source tree is ElementPlaybackControllerCloning, while the default one is ElementPlaybackControllerStretching. The two live side by side in the source under src/entry-points/content, which makes it possible to compare them on the same content.

## Finding video elements on pages that are still loading

The extension works on whatever video element it can find, and the mechanism for that is worth describing because it explains the scope of the tool.

Video elements are located by injecting a script into all pages, configured through the manifest file, and then simply asking the document for video elements with document.getElementsByTagName. That covers the video already on the page when the extension's content script runs.

The problem is that new video elements can be inserted after the page has loaded, which is the normal case on a site that builds its player dynamically. For those, the project uses a MutationObserver to watch for new elements as they appear. The observation code lives in the watchAllElements module, and the same file handles the initial sweep.

The consequence for a user is that the extension is element based, not site based. It does not need a list of supported video hosting sites, and it works on any page with a video element, including a local file played in the browser. It also means the extension inherits the page's media element and cannot act on video that is not in the DOM at all, such as some canvas or WebGL based players.

The source tree also contains a local file player entry point, which is consistent with that element based approach: the same detection and speed up logic can be applied to a file opened locally rather than streamed from a site.

## Building the extension for Gecko and Chromium from one webpack config

The build is a yarn and webpack setup that produces a different bundle per browser, and the scripts section of the package metadata shows the whole shape of it:

```json
  "scripts": {
    "_abstract-build": "yarn lint && NODE_ENV=production webpack --mode=production",
    "build:gecko": "yarn run _abstract-build --env browser=gecko",
    "build:chromium": "yarn run _abstract-build --env browser=chromium",
    "_abstract-build-and-package": "yarn run build:$BROWSER -- --env noreport && cd dist-$BROWSER && rm -f ../dist-$BROWSER.zip && zip -r ../dist-$BROWSER.zip .",
    "build-and-package:gecko": "BROWSER=gecko yarn run _abstract-build-and-package",
    "build-and-package:chromium": "BROWSER=chromium yarn run _abstract-build-and-package",
    "build-and-package:all": "rm -f dist-*.zip && yarn run build-and-package:gecko & yarn run build-and-package:chromium",
    "_abstract-serve": "webpack --mode=development --watch",
    "serve:gecko": "yarn run _abstract-serve --env browser=gecko",
    "serve:chromium": "yarn run _abstract-serve --env browser=chromium",
    "lint": "eslint ./src/",
    "format": "prettier --write .",
  },
```

The browser is a build parameter rather than two separate projects. A single webpack configuration is invoked with an environment flag for gecko or chromium, the lint step runs as part of the abstract build, and the packaging step zips the output directory into a distributable archive. A watch mode serves the development build for either browser.

The runtime dependencies are small and tell you what the extension actually uses:

```json
  "dependencies": {
    "@wofwca/smoothie": "^1.36.2-rc0",
    "hh-mm-ss": "^1.2.0",
    "lodash": "^4.17.21",
    "tippy.js": "^6.3.7",
    "tone": "~14.7.77"
  },
```

The bundle also declares which modules have side effects, so that a bundler can tree-shake the rest:

```json
  "sideEffects": [
    "./src/{content,popup,background,options,local-file-player}/main.ts",
    "./src/content/SilenceDetector/SilenceDetectorProcessor.ts",
    "./src/content/VolumeFilter/VolumeFilterProcessor.ts"
  ],
```

Those entries are the entry points of the extension itself, the popup, the background worker, the options page and the local file player, plus the two audio worklets that carry the silence detection and the volume filter.

## An AGPL extension with a store release and a moving repository

The licence is the AGPL-3.0, and that choice matters for an extension more than for a library. A browser extension runs on the user's machine, and the AGPL is designed to cover that case, so a modified build distributed to users carries an obligation to publish the corresponding source.

The practical guidance is simple. Installing the published extension from a store is unproblematic. Forking the code to change how the detection works, and handing that modified build to other people, is the situation the licence was written for, and the corresponding source has to travel with it.

The distribution channels are the Chrome Web Store, the Firefox Browser Add-ons site and the Microsoft Edge Add-ons site, plus the packaged crx and xpi files attached to the repository's releases. The project is translated through Weblate, and the community links in the documentation point at a Matrix room and a Discord server.

On maintenance, the repository is not archived and the last push was on 2026-10-02. The tagged releases are older than that: v1.32.2 from 2026-01-29, v1.31.0 from 2025-10-05 and v1.29.0 from 2025-02-23. So the extension in your browser may well be several months behind the source, and the store listing, not the repository, is what tells you which build you are running.

The repository is also structured for contributors rather than just for releases. There is a CONTRIBUTING.md, a CODE_OF_CONDUCT.md, a .gitlab-ci.yml alongside the .github directory, a chores/ directory and a docs/ directory, and the pull request rules ask that you open an issue first for anything larger than a fix.

## Conclusion

Jump Cutter suits anyone watching unedited lectures, recorded streams, webinars or podcasts in a browser, and it is the wrong tool for offline editing, for files you need to keep fast-forwarded, and for anyone who wants to strip silence from a video permanently, since it changes playback only. Before installing it, try the default algorithm first and leave the experimental cloning algorithm off until you understand the difference, then check the extension listing in the Chrome Web Store, the Firefox Browser Add-ons site or the Microsoft Edge Add-ons site for the current version, since the newest tag in the repository is v1.32.2 from 2026-01-29 while the last push was on 2026-10-02.

## FAQ

### What does Jump Cutter do?

It is a browser extension that skips the silent parts of videos in real time, so unedited content such as lectures, recorded streams, webinars and podcasts play back faster. The silence is skipped during playback only, and the original file is not changed.

### How does Jump Cutter detect silence?

The default stretching algorithm uses the Web Audio API createMediaElementSource together with an AudioWorkletProcessor to measure the loudness of the element's output audio and raise the playbackRate when it is quiet, buffering about 200 milliseconds so that quiet onsets can be slowed back down before they are output.

### What is the experimental algorithm in Jump Cutter?

It is the cloning algorithm, which creates a hidden clone of the media element, plays it ahead of the original to locate silent parts, and then speeds up or seeks past them. It is turned on with the Use the experimental algorithm checkbox rather than being the default.

### Where can I install Jump Cutter?

It is published on the Chrome Web Store, the Firefox Browser Add-ons site and the Microsoft Edge Add-ons site, and the packaged Chromium crx and Gecko xpi files are also attached to the project's releases page.

### Does Jump Cutter work on any website?

It works on any page with a video element. Video elements are found with document.getElementsByTagName and a MutationObserver catches elements added after the page loads, so there is no list of supported sites.

## Sources

- [License: AGPL-3.0](https://github.com/WofWca/jumpcutter/blob/master/LICENSE)
- [Project website](https://chrome.google.com/webstore/detail/jump-cutter/lmppdpldfpfdlipofacekcfleacbbncp)
- [README](https://github.com/WofWca/jumpcutter/blob/master/README.md)
- [Releases](https://github.com/WofWca/jumpcutter/releases)
- [WofWca/jumpcutter on GitHub](https://github.com/WofWca/jumpcutter)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/wofwca-jumpcutter
