How we build nopa, part 2

In part one I promised to go under the hood. Here it is: why nopa has no backend, how heavy work fits into a browser tab, where your work lives — and how to check every word of this yourself in about a minute.

There is nowhere to upload to

Most tool sites are a page in front of a server: your file goes up, the server does the work, the result comes back. nopa turns that around. The site is static files — HTML, JavaScript, fonts — and the code comes to you instead of your file going to it. When you merge two PDFs, the merge runs in your tab, and the PDF never leaves it.

That is also why there is no account. An account exists to keep something of yours on a server, and there is no server keeping anything — so there is nothing to sign in to.

Heavy work, in a tab

The browser has become a serious machine, and each tool uses the part of it that fits the job:

  • PDFs: pdf-lib builds and rewrites the file, PDF.js draws the pages you see. Compress a PDF and both run on your device.
  • Photos and audio: neural networks run in WebAssembly on ONNX Runtime. The background remover and the transcriber download their model once and keep it; your photo goes to the model, never the other way round.
  • Scans: tesseract.js reads the text of a scanned page in a worker. The first time it downloads a reading model of 4–5 MB, and after that it is already there.
  • Word files: mammoth reads a .docx and docx writes one back, so the Word editor can open the contract you were sent and hand it back as a real Word file.
  • Games: jsnes runs a whole NES in JavaScript. The NES page ships two homebrew games whose authors allow it, and plays your own .nes file without uploading it.

The cost: the code has to come to you

There is a flip side. A server-side tool sends you a light page and does the heavy lifting where you cannot see it; we have to send the heavy part to you. So we count it: a script in our repo opens every page in a real browser and adds up the JavaScript it downloads before you press anything. The first run found pages pulling 1.4 MB for nothing — the whole story, with numbers, is in an earlier post.

The rule since then: an engine loads when its button is pressed. The PDF engine arrives when you open a PDF, the reading model when you ask for a scan to be read. This week the rule caught one more: the board was downloading a 170 KB PDF library every time it opened, for a single menu item.

Where your work lives

What you save — a board, a task list, a document, the files the tools produce — goes into IndexedDB, the browser’s own database, on your device. The apps save as you work: close the tab, and it is where you left it.

The honest part: that storage belongs to this browser. Clear the site’s data and it is gone; pick up your phone and it is not there. So a backup is one click away — the whole desktop as a single file, in Settings → Data — and the same screen can ask the browser not to clear nopa when the disk runs low.

Offline, after the first visit

A service worker keeps a copy of the app on your device, so once you have opened nopa, the tools open without a connection. Not everything is stored up front: neural-network models and the reading model download only when a tool needs them, because a phone should not hold a hundred megabytes of models on the off chance.

Check it yourself

Open your browser’s DevTools, switch to the Network tab and use any tool. You will see two kinds of requests: our own code arriving from nopa.space, and visit statistics going to Yandex Metrica and PostHog — which page was opened, which tool was used. You will not see your file going anywhere, because it does not. A content blocker turns the statistics off, and every tool works the same.

We got this wrong once ourselves. The panel on our product pages used to promise “not one POST” — measured on a build without the statistics, while in production the counter sends POSTs of its own. A reader would have caught it in ten seconds; we caught it this week and rewrote the panel to say exactly what you will see.

What this design cannot do

A server does some things a tab cannot, and we would rather say so:

  • No sync. Your phone and your laptop each keep their own copy; a backup file moves it, a live link does not exist.
  • No live collaboration. Two people editing one board need a server between them.
  • The first run of an AI tool waits for its model to download.
  • A phone is slower than a data centre. Most jobs take a moment; an hour of audio takes a while.

What’s next

If something breaks on your device, or you need a tool we do not have, write to hello@nopa.space — a real person reads it. Or start from the catalog; part one, on why nopa exists at all, is here.