VideoCompressor: Building the Local-First Tool I Needed
By Raymund Zyron Abella /
How a personal utility became a private, hardware-accelerated browser workflow built with WebCodecs, WebGPU, local processing, and honest output inspection.
In this article
I built VideoCompressor because compressing a video should not require uploading a large private file to someone else's server, waiting for it to process, and downloading it again.
It is a browser-based tool I use myself. A video is selected locally, inspected, compressed on the device, previewed, and exported without leaving the browser. That practical use matters to the project: the interface is shaped by an actual recurring task rather than a feature checklist.
Starting With the Privacy Constraint
The central product decision was zero uploads. Video files can be large, personal, and slow to transfer. Keeping the entire pipeline on the device removes server storage from the trust model and avoids making network speed the main performance limit.
That constraint immediately shaped the architecture. The browser has to decode, transform, encode, mux, preview, and save the output. It also has to communicate capability differences clearly because media APIs and codecs are not equally available in every browser.
Local-first is not a badge added after implementation. It is the reason the implementation has its current form.
Designing the Shortest Useful Flow
The primary workflow is intentionally direct:
- Drop or choose a video.
- Review its size, format, duration, and resolution.
- Choose format, codec, quality, and output resolution.
- Optionally trim or denoise it.
- Start compression and monitor progress.
- Compare the result and download it.
The interface delays advanced controls until a source file exists. That keeps the first screen focused on the only action that matters at the beginning while still giving the user meaningful control before encoding starts.
WebCodecs as the Core Processing Layer
VideoCompressor uses WebCodecs for direct access to browser video decoding and encoding. Compared with routing media through a remote service, the API keeps frames near the hardware-backed media pipeline and allows progress to remain part of the local application state.
H.264 provides the compatibility-oriented path, while AV1 offers a more modern efficiency option when supported. Resolution and quality controls expose the tradeoff that compression always contains: smaller output, faster processing, and visual fidelity pull in different directions.
Mediabunny handles the container and muxing work around those encoded streams. Keeping encoding and container responsibilities separate made the pipeline easier to reason about and left room for multiple output formats.
GPU Denoising and Trimming Before Encoding
Optional WebGPU denoising addresses footage where noise consumes bitrate that could otherwise preserve useful detail. Because this work is computationally expensive, it belongs behind an explicit control rather than silently changing every video.
Trimming is an even more direct optimization. Frames that are not needed should not be encoded at all. Letting the user remove an unnecessary beginning or ending can reduce both processing time and final size before quality settings enter the equation.
These features follow the same principle: reduce waste as close to the source as possible.
Building Honest Progress and Results
Media processing takes long enough that the interface must explain what is happening. VideoCompressor reports progress during the local pipeline instead of presenting a spinner with no context. Once complete, the original and output information make the result inspectable before download.
That comparison is important because a smaller number is not automatically a better result. The user needs to preview the encoded file and decide whether the chosen quality and resolution suit its destination.
Failures also need specific language. An unsupported codec, unavailable WebGPU adapter, invalid media file, and interrupted encode are different problems. Treating them as one generic error would make a technically private tool feel unreliable.
Using My Own Product Changed the Priorities
Using VideoCompressor on my own files exposed priorities that a demo would miss. The drop zone had to recover cleanly when I changed files. Defaults had to be useful for common exports. Long videos needed progress that felt alive. Download naming had to be predictable. The result needed to be available immediately without another upload or account step.
Dogfooding also kept the scope honest. I did not need a dashboard, cloud library, or login system to solve the problem. I needed a dependable utility that opens quickly, processes locally, and gives me control over the output.
Browser Constraints Are Product Constraints
The strongest path currently depends on Chromium-based browsers with WebCodecs and WebGPU support. That is not merely a compatibility footnote. Capability detection, fallback behavior, and clear messaging are part of the product.
Client-side processing also means performance depends on the user's device. A powerful desktop can encode much faster than an older laptop or phone. The interface cannot promise one universal speed; it can avoid network transfer and use the hardware the browser makes available.
Those constraints are worthwhile because they preserve the tool's defining promise: the source video stays local.
What I Would Improve Next
Future work could add richer codec capability testing, reusable presets for common destinations, clearer estimated output size before encoding, batch compression, and more detailed frame-time diagnostics. Browser support will also continue to evolve around WebCodecs, WebGPU, and container formats.
The project already succeeds at the reason I built it. I can open a page, compress a video I actually need, and download the result without sending the original anywhere. That is a small workflow, but owning the full workflow makes the tool genuinely useful.