Zealandia - In Development

The Character Customizer

Before Zealandia can be a world, it needs people. This is the tool I am building to make them: the character customizer for the game app, where a player builds an SD character - hair, eyes, skin, outfit - in four directions, watches them idle on the creation stage, and sends them into the game as data. The customizer itself is still in development, and it runs live below: build a character right here, exactly as it runs today.

Live demo

The customizer itself, running in your browser. Choose a hairstyle and eyes, turn the character, watch the idle - the same build the game account creation uses.

Open the customizer full-screen

Design capability

This page is here as design work, not only as a game tool. The customizer is a small design system for people:

Run the live build: Character Customizer - live demo

A character before a world

The web side of Espil.Online keeps a simple social avatar. The game character is a different record, created in the app - and a character starts here. I built the customizer as a paper-doll system: a base character produced once, with hair, eyes, clothes and accessories as separate replaceable layers. Every layer is registered to the same ground line and the same centre point, so changing a hairstyle never moves the feet, and a new item only has to be drawn once to exist in every direction.

The customizer stage with a male character, the hair tab open
The creation stage: a male character in the default look, hair tab open - four hairstyles and twelve dyes, and a dye applies to every direction at once.

Four directions, one character

The characters are drawn the EverPlanet way, in four directions. Front, side and back are three unique drawings; the fourth direction is the side mirrored, so nothing is drawn twice that does not need to be. A strip under the stage always shows all four at once, and the character can be turned with the direction buttons, the arrow keys, or an auto-rotate. The back view is honest: it shows the back of the head, not a face pasted onto it.

The same character seen from behind, with the four-direction strip below the stage
From behind: the same character, with the four-direction strip below the stage - front, side, back, side.

Paper dolls, honestly labelled

The slots: gender; three skin tones; hairstyles with twelve named dyes; eye styles with seven colours; cosmetics such as flushed cheeks, a heart tattoo, a scar and a bandage; and top, bottom and shoes as separate slots that can also be taken off, with outfit sets that recolour together. The interface labels every slot with what actually exists - four directions, front only, or in production - because a customizer that lies about its own catalogue wastes the player's time.

A female character with the face tab open, showing eye styles and eye colours
The face tab on the female base: five eye styles and seven eye colours. The eye style rides the front animation; the colour applies to the front and the side.

Alive on the stage

The front view idles as a 24-frame loop at twelve frames a second, its seam closed with a short crossfade, so the character breathes gently with the feet planted instead of jumping between poses. A name tag floats overhead - the name the character will carry into the world. The creation stage stands before the Auckland Time Stone, where the game begins, and its backdrop can be swapped - checker, dark, sky, meadow, sunset - for checking a sprite against different light.

Out as data, not just pictures

Under the panel sit random and reset, and the way out: a PNG of the current direction, a four-direction sheet PNG, and a JSON export written in the game engine's own compositing format. That last one is the point of the tool. The game client reads the same manifest to rebuild the character from its layers, so what a player designs on this stage is exactly what walks into Waitemata.

The outfit tab with four outfit sets, the name field, and the export buttons
The outfit tab and the way out: four outfit sets, the name field, and the export row.

Still growing

The catalogue is young. More hairstyles are being separated into layers, walk cycles are in production, and every slot the tool marks as in production is exactly that. Zealandia is coming to the app and the PC; this customizer is where its people will come from.

← Back to the Full Index

han.espil.online Case Study - Espil.Online Espil.Online

Case Study

Espil.Online: Designing the System, Not the Screens

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.

Screens drift. Systems hold.

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.

Write laws, not a style guide.

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.

AI builds inside the fence.

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.

One director, a studio of departments.

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, 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.

One loader. Two sites. Zero redesigns.

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.

The standard glass loader runs over the Espil Universe render

The architecture underneath.

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.

One identity, one session, three clients

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.

A backend split by domain

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.

Money that cannot leak: the Leo Coin ledger

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.

Places, travel, and assets that ride with the client

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.

The data model, in one breath

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.

The outcome

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.

← Back to Selected Works