Utility
ROOMFUL
If your place burned down tomorrow, could you tell your insurer what was in it? Almost nobody can.
Click to preview · 2× speed
Stack/Tools
What it does
Walk around the house with your phone. Photograph a thing, name it, put a value on it, and the camera reopens for the next one. About eight seconds an item, because if it takes twenty nobody finishes a house.
Later, at a laptop, fix the values you guessed at, add serial numbers off the receipts, and export a dated PDF with photos and totals for your insurer.
It installs to a home screen and opens with no signal, which matters because the place you actually use it is a garage with no reception. Nothing is ever uploaded. No account, no server, no analytics.
The hard part
Fitting a whole house of photographs into a browser storage quota, with no server to offload to.
A phone photo is three to five megabytes. Forty of them is more than most browsers will store. So every image is decoded off the main thread, downscaled to 1200px on its long edge and re-encoded as WebP, landing around 200 KB. That's still enough resolution to read a serial number off a label.
Compression here isn't about bandwidth, which is the usual reason. There's nothing to upload. It's purely about fitting inside a quota that can't be raised.
A decision I'd defend
IndexedDB over localStorage. localStorage caps at roughly 5 MB and stores strings only, so photos would have needed base64 encoding, a third larger and blocking the main thread. About ten items would have exhausted it. IndexedDB stores binary directly and gets a quota measured in hundreds of megabytes.
The cost is that everything becomes asynchronous, which is why the app loads all its text records into memory once at startup and treats memory as the read path. Photos deliberately stay out and are fetched only when something renders them.
Selected screens



Where it stands
Shipped and live. Installs to a home screen, opens in airplane mode, and produces a document you could attach to a claim.
23 tests covering the money helpers and the total calculations, including the property that the grand total always equals the sum of the room totals.
What's still missing
Devices can't see each other's data. That's the direct cost of having no backend rather than an oversight, so moving an inventory between a phone and a laptop is a file you export and carry.
Object URLs are held for the whole session, so memory grows with the number of photos viewed. Fine at a few hundred items.
And a value above JavaScript's safe integer range breaks totals. It needs an input cap and a test, and it's documented rather than fixed.
Full reasoning for all three is in the README.
I wrote up the whole build: why no backend, what that bought and what it cost, and the bug I spent two hours on when the stack trace had already named it.