I run a small site called Joy of Tools. It has 254 tools for jobs that take about two minutes: merging a PDF, shrinking a photo, counting words, working out a loan payment.
I set one rule before I wrote any of them. Whatever you add stays on your device. There is no upload and no account. Most of the technical choices followed from that rule, so this post goes through what each kind of tool runs on and where it gets awkward.
Merging, splitting, rotating and adding page numbers use pdf-lib. Turning pages into images uses pdf.js. Both are fine on a phone for ordinary files. Large scans are the weak spot, because the whole file has to sit in memory and a phone browser gives up long before a laptop does.
Images, audio and video
Resizing and converting images is plain canvas work. HEIC photos from an iPhone are the exception, because browsers other than Safari cannot read them, so those go through libheif first. Audio and video conversion use ffmpeg compiled to WebAssembly. It is several times slower than a server would be. I decided that was an acceptable price for the file not going anywhere.
OCR and speech
Text recognition is Tesseract running in the browser. Text to speech runs a voice model through ONNX Runtime Web, and speech to text uses transformers.js. A model downloads the first time a tool is opened and is cached after that. The first run is slow and I have not found a good way around it.
Six languages
The site is built with Next.js and next-intl, and every tool has its own page in English, Japanese, Spanish, Portuguese, German and French. That comes to about 1,400 pages.
I expected translation to be the work. It was not. The work was the data behind the tools, and the last five tools I opened in the other languages showed it clearly.
A tip calculator cannot keep American percentages. In Germany service is included and people round up or leave 5 to 10 percent. In Brazil a 10 percent service charge is already on the bill. Each language needed its own currency, its own preset buttons, and a decimal comma in the input.
The periodic table shows Cobalt and Caesium in German, which is the official spelling, but people type Kobalt and Cäsium, so the search needed a list of other spellings. In Japanese several element names are written in kanji, and someone typing in hiragana would find nothing unless the search also knew the readings.
The fantasy name generator builds names from syllables. Written in katakana, some of those syllables turned into rude words, so the Japanese version needed a filter the English one never did.
What I would like to hear
If you try it, tell me which tool you looked for and did not find, and what felt slow on your phone.



