Scrolls Buddy
A scrolling planner for the MapleRoyals community: per-slot scroll recommendations, stat progression, profit/loss, and session history, backed by a real relational data layer and product analytics, with zero servers to run.
The niche
MapleRoyals is a long-running private server for an old version of MapleStory. Its economy runs on scrolling: you apply scrolls to a piece of equipment to add stats, but every scroll has a success rate, every item has a finite number of upgrade slots, and the good outcomes are rare and expensive. Chaos scrolls randomize stats instead of adding fixed ones; white scrolls protect a slot when a scroll fails. Deciding which scroll to burn on which slot, and knowing when to stop, is a real expected-value problem that players do by feel, on spreadsheets, or not at all.
Honestly, I built it because I couldn’t work the math out in my own head. I was new to scrolling, the decisions did not come naturally, and the tool was how I learned the domain: I understood the system by building the thing that reasons about it. It turned out the rest of the community had the same gap. So Scrolls Buddy does what I wanted for myself: pick an item, and it gives you per-slot recommendations, visualizes the stat progression, and tracks the profit or loss of a scrolling session against live market prices. It sits at scrolls.itaywol.tools.
The constraint I set myself
A niche tool for a game community has an audience measured in dozens, not thousands. That number decides the architecture before anything else: I was not going to stand up, secure, and pay for a backend to serve twenty people a day. The constraint became the design brief (no servers, no database to operate, no bill that scales with traffic), and the interesting part was refusing to give up any real capability to honour it.
The result is a fully client-side application. Everything a backend would normally do happens in the browser tab.
The approach
A real database, in the browser. Session history, saved item configurations, and
scrolling outcomes are relational data with real queries behind them, the kind of thing
localStorage handles badly the moment you want to ask a question of it. So the app runs
SQLite compiled to WebAssembly, persisted into the browser via IndexedDB. It is
genuine SQL against a genuine database; the data simply lives on the user’s device and
never leaves it. No rows on a server means nothing to breach, migrate, or back up.
Game data pulled, not hosted. Item names, icons, and base stats come from public game-data APIs (maplestory.io and the MapleRoyals wiki) on demand, cached at Cloudflare’s edge. I host no assets and maintain no scraper: the canonical sources stay canonical, and the app stays a thin client over them.
Analytics without a server. I still needed to know whether anyone used the thing, and
which features earned their place. The app sends product events to PostHog, but through a
first-party /ingest path on its own domain rather than to PostHog directly, which keeps
the telemetry first-party, survives ad blockers, and still runs no infrastructure I own.
That feed is how I know it holds a steady ~20 daily active users, and which parts of
the planner they actually reach for.
Installable and offline. Because the data layer and the logic are entirely local, the app is a PWA: installable, and fully usable without a connection once the game data is cached.
The stack
React and Vite for the SPA, Radix UI primitives for accessible components, SQLite-WASM
for persistence, PostHog for analytics, and Cloudflare Pages for hosting: a static
bundle on a global edge, deployed on push, on the scrolls.itaywol.tools subdomain of a
domain I already manage. The whole thing costs nothing to keep running.
Why it worked
The tool found its users the honest way: I dropped it in the MapleRoyals community and Discord, and people who scroll gear kept it open. A steady handful come back every day, and a few thought it useful enough to leave a tip, the clearest signal a free tool can get.
The lesson I keep relearning: a sharply-scoped thing built for a real, specific need beats a general thing nobody asked for. Scoping it to twenty people is exactly what let it be serverless, free to run, and finished, rather than an ambitious platform I would still be maintaining and paying for.