Most online file converters have a dirty secret: your files get uploaded to a server you don't control, processed by someone else's machine, and sometimes stored for longer than you'd expect. For a quick GIF conversion or a PDF merge, that feels like overkill — and a genuine privacy risk if the file contains anything sensitive.
So I built utilize.internet — a collection of free file tools that run entirely in your browser using WebAssembly and the Canvas API. Your files never leave your device.
How it works
The key insight is that modern browsers are surprisingly capable of heavy computation. WebAssembly lets you run near-native code in the browser, which means tools like FFmpeg (for video) and pdf-lib (for PDF manipulation) can run client-side without any server involvement.
The architecture for every tool on the site follows the same pattern:
User selects file
↓
Browser reads file into memory (FileReader / ArrayBuffer)
↓
WebAssembly / JS library processes it locally
↓
Result is offered as a download via Blob URL
↓
File is revoked from memory when done
Nothing touches a server. No API calls for the actual processing. The only external requests are for Google Fonts (styling) and Google Analytics (visitor counting) — neither of which touches your file.
The tools
Here's what's currently live:
Image & Video
Video to GIF — powered by ffmpeg.wasm. Upload a video, drag two handles on a trim slider to select your clip, choose output width and FPS, convert. Uses the palettegen/paletteuse filter for noticeably better GIF color quality than a naive conversion.
Image to GIF — gif.js running in a Web Worker. Upload multiple images, reorder them via a filmstrip UI, set frame delay, convert.
Compress Image — Canvas API with a live quality slider. Shows before/after file size comparison in real time as you drag.
Image Converter — Canvas API again. Batch convert between JPG, PNG, and WebP. Each file gets its own download link.
PDF & Documents
Merge PDF — pdf-lib. Drag in multiple PDFs, reorder them, merge into one.
Split PDF — pdf-lib. Extract a page range, or split every page into its own PDF (delivered as a ZIP).
Shrink PDF — Two modes: "Balanced" (rebuilds the PDF structure, keeps text selectable) and "Maximum" (re-renders every page as a JPEG via pdf.js, much smaller files for scanned documents).
Images to PDF — pdf-lib. Combine JPGs/PNGs/WebPs into a PDF. Choose "fit to image" or standard page sizes (A4/Letter) with margin and auto-rotate options.
PDF to JPG/PNG — pdf.js renders each page to canvas. Per-page download links plus a "download all as ZIP" option.
Word & Excel to PDF — mammoth.js converts .docx to HTML, SheetJS converts .xlsx to an HTML table, then the browser's native print function ("Save as PDF") handles the actual PDF generation. This produces a real text-based PDF rather than a canvas image.
PDF to Word (Lite) — pdf.js extracts text from each page, groups lines into paragraphs based on position/spacing, rebuilds as a .docx via the docx library. Clearly labeled as text-extraction only (no OCR, no layout preservation).
The interesting technical challenges
ffmpeg.wasm cross-origin worker issue
This was the biggest headache. ffmpeg.wasm 0.12 internally spawns a Web Worker for its processing thread. The worker script is a separate chunk file (814.ffmpeg.js). When loaded from a CDN, browsers block the worker construction because the worker script origin doesn't match the page origin.
The fix: self-host every ffmpeg file on the same domain. The library dynamically resolves the worker chunk relative to its own src attribute, so hosting ffmpeg.js at /tools/ffmpeg/ffmpeg.js makes it automatically look for /tools/ffmpeg/814.ffmpeg.js — same origin, no CORS issue.
GIF quality
A naive video-to-GIF conversion (just specifying an output format) produces washed-out colors because GIFs are limited to 256 colors per frame and FFmpeg's default palette selection isn't great. The fix is a two-pass filter chain:
fps=15,scale=480👎flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse
palettegen analyzes the entire clip to build an optimal 256-color palette. paletteuse then applies it. The difference in output quality is significant.
ZIP generation without a library
For tools that produce multiple files (Split PDF, PDF to JPG), I needed to bundle the output into a ZIP. Rather than adding another library dependency, I wrote a minimal inline ZIP writer (~100 lines) using the "store" method (no compression, just the ZIP container structure). For PDF and image files that are already compressed, adding a second compression pass rarely saves meaningful space anyway.
Shrink PDF — honest about limitations
True PDF compression (Ghostscript-level) isn't achievable in a browser — it requires access to font subsetting, image resampling at the codec level, and other operations that need native binaries. Rather than pretend otherwise, the tool is upfront: "Balanced" mode removes structural redundancy but won't dramatically shrink a well-optimized PDF; "Maximum" mode converts to images (smaller, but text becomes unselectable). Users can make an informed choice.
Stack
Hosting: Hostinger (static files only — no server-side code)
Libraries: ffmpeg.wasm 0.12, gif.js, pdf-lib, pdf.js, mammoth.js, SheetJS, docx — all self-hosted
Analytics: Google Analytics 4
No framework: plain HTML, CSS, and vanilla JS. Each tool is a single self-contained HTML file.
The "no framework" decision was deliberate. Every tool page needs to work as a standalone file served from a static host. A build step adds complexity and deployment friction that isn't justified for this use case.
What's next
QR Code Generator — a natural fit for a client-side tool
Fill PDF Forms — pdf-lib can read and fill AcroForm fields
Sign PDF — canvas signature pad + pdf-lib stamp
If you have suggestions for tools that would fit the same pattern (free, browser-based, privacy-first), feel free to drop them in the comments.
The site is at utilizeinternet.com — everything is free, no account needed.
Built with WebAssembly, vanilla JS, and a strong preference for not storing other people's files.
#webdev #javascript #webassembly #tutorial
Top comments (0)