skip-silence

Skip Silence — Technical Documentation

How the extension works under the hood. For the general overview, see README.md.

Architecture

There are three moving parts — content script, popup, and a background script that only exists for the keyboard shortcut. Settings flow through chrome.storage; live data flows through a runtime Port. There is no server, no offscreen document, and no page-world script injection.

Audio graph & silence detection

MediaElementSource → VolumeProcessor (worklet) → DelayNode → GainNode → destination
                          │
                          └─ RMS per ~21ms window → threshold logic → controller

Playback policy

Why element capture (and not tabCapture)

The original Skip Silence used chrome.tabCapture on Chrome; that API is unavailable to MV3 extensions. Element capture is the only viable MV3 path, and it comes with known constraints handled in content.ts:

Settings & state

Misc hard-won details

Development

bun i
bun run dev            # Chrome with the extension loaded
bun run build          # .output/chrome-mv3
bun run build:firefox  # .output/firefox-mv2
bun run compile        # typecheck

Manual smoke test: serve test/media-test.html same-origin, hit “Generate & play” — the rate readout should jump to the silence speed during the 3s silence gaps and snap back for each tone.

Manual test matrix: YouTube lecture (skips in pauses, snaps back on speech, survives YouTube’s own rate handling), Twitch VOD, plain <audio> podcast page, cross-origin <video> (audio stays intact, popup shows “can’t analyze”), Netflix (untouched, DRM status), disable mid-silence (rate and volume restore), Firefox spot-check.