Case Study
Espil.Online is a live, interactive 3D world of real cities, designed, built, and operated by one person. This case is not about any single screen in it. It is about the decision that lets one person ship a product this size without it falling apart: treating the design as a system first.
The product kept growing new kinds of surface: a globe entry, city interfaces, a heads-up display, loading states, and a portfolio site beside it. Built screen by screen, each new surface would drift a little further from the others, and a solo builder has no team to catch the drift. I needed the consistency a team provides, without the team.
I stopped treating the design system as a style guide and rewrote it as documented laws: palette, typography, and interaction rules, written down and binding. Design tokens were implemented as CSS custom properties in the production code, so a design decision and its implementation are the same object. Interfaces are composed from a reusable component family before anything new is invented, and a new pattern joins the family, documented, before it is used.
The workflow is AI-assisted end to end. Exploration happens in Figma. Prototyping, implementation, and refactoring run through AI agents, primarily Claude Code, working against the written laws and token set. That constraint is deliberate: it is what makes generated work converge on one product. QA passes judge new surfaces against the same laws, so the system is also the review process.
The fence scales further than one product's screens. The build is run as a studio of specialized AI departments, each with a defined scope and a written brief: world and map production, 3D assets, character skills and motion, music, quality assurance, architecture, marketing, and a coordination office that keeps every department's state identical. Work is divided between them the way a studio divides it - by discipline, not by whoever is free - and each department produces inside its own brief, to the same documented laws.
Direction sits with one person. I set the product canon, the priorities, and the order of work, and every consequential decision is mine: when the game's maps had to come first, I mobilized every department behind the map pipeline until maps flowed from the editor into the engine. Departments do not whisper to each other in pairs - decisions, blockers, and completions are broadcast to all departments in identical form, and open questions travel to a single reporting channel and return as one decision everyone applies. Nothing quietly diverges, because nothing is allowed to travel in secret.
The professionalism is in the gates. No department's word makes its work done: output is verified against the live build before anyone reports it, production deployments pass an architecture and security review before they ship - vulnerabilities are hunted as a standing routine, code review is continuous, and my own screen is the final quality check on anything a user will see. Claims are traced to their source before they are repeated - a count, a link, a fix, a file. What this buys is the thing a one-person practice is not supposed to have: parallel production with a studio's accountability - many hands, one direction, and a record of everything.
When the loading experience needed standardizing, the system faced its clearest test. One glass-loader implementation was built once, against the laws, and became the single standard for every loading screen. The same implementation was then transplanted across two production sites, espil.online and han.espil.online, with no per-site redesign. A decision made once held everywhere the system reaches.

A social world can run on a page. A game with an economy cannot - so before the game build, the architecture was designed as a written package: an overview, the architecture itself, the UI and UX flows, and a build order. It was then reviewed against four fixed points, and the build follows them: identity is one, sessions are one, game data attaches to the same database, and everything runs on one platform behind one host.
There is a single account system for the web, the app, and the PC program: Google sign-in on a multi-provider identity table, and sessions issued by the backend itself - an opaque token, stored hashed in the database, carried as an httpOnly cookie on the web and as a Bearer token in the app, sliding for 30 days with a 90-day cap. Visitors who never sign in browse as ghosts. The clients split by weight: the web stays light on Mapbox, social at the centre, with a simple male or female social avatar; the app - the same web build in a Capacitor shell - and the PC program are the real game on 3D assets. The game character is a server record on the shared account, created and selected only in the app and on PC, never in the web's avatar choice.
The API lives at api.espil.online on Cloudflare's serverless platform - there is no operating VM. Workers run the API split into per-domain services: auth, characters, travel, inventory, economy, stalls, social, and housing; D1 holds the accounts, sessions, and game data. Anything that changes money or items travels as a transactional request. Realtime presence runs on Durable Objects, one per place instance, and carries only what is ephemeral - presence, position relay inside a place, chat, and stall beacons - and it stores nothing. Movement is client-reported with server sanity checks; the economy never is.
Leo Coin runs on a double-entry ledger. Every coin movement is a single balanced transaction - debit and credit entries against ledger accounts - carrying an idempotency key, so a retried request cannot duplicate value, and an audit trail that can be replayed. No endpoint accepts a client-stated balance. New coin is minted only by the system account against recorded knowledge-sharing events: the supply grows through knowledge, by mechanism and not just by slogan. A stall purchase settles atomically in the same pattern - item to the buyer, coins to the seller - and there is no fee by construction: the schema holds no fee account and no fee field, so a fee cannot be charged by accident or added silently later.
The world is places, not one open map. A server-side registry is the single source of truth for every place - its pin on the continent, its unlock rule, its asset manifest - and travel is an instant hop between unlocked places: the server validates, issues a short-lived join token, and records where the character stands. The heavy bytes never ride the server: each place's crafted GLB bundle is published to R2 object storage with a manifest of files, hashes, and sizes; the client downloads it on first entry, verifies the hashes, and caches it under a size cap. Art fixes ship by repointing a manifest - no app release, no server load. Distribution is client-carried on purpose: the backend stays thin, and the whole system runs inside Cloudflare's free allowances. Zero recurring cost is a design constraint of this architecture, not an accident of it.
Shared tables - users, identities, sessions - and everything game-side keyed to the same user: characters and their state, place unlocks, item definitions and inventory, ledger accounts and entries, knowledge-share events, stalls and their listings, trade records, pickup requests, and houses. One database of record, so a person, their character, their stall, and their coins are never four different stories.
Espil.Online began in 2015 at Bieclipse Design, my own practice, and everything I have accumulated feeds it: design, code, and the music I compose as Espil Ceil. The system is what lets all of that arrive as one product instead of a pile of parts.
One person, team-level consistency, sustained for years. That is what the system buys.