Decisions (ADRs)
Every direction decision with context, choice and consequences. This wiki is the only source; the owner can veto any line.
Status key: Decided = made at the owner's request; the owner can veto it, and if they do the decision is rewritten here first. Open = needs an owner choice before the work it affects. Proposed = written by an agent and waiting for the owner's approval; work may follow it, and it changes if the owner says so. Agents never change a decided row on their own. They propose a new ADR instead. Round 1 decisions date from 2026-10-03; round 2 (owner review) from 2026-10-04.
◆ADR-001 · Zoen, and this wiki as the only source
- Decision: The game is Zoen. This wiki (docs +
packages/game-data) is the single source of truth. Earlier working documents are archived outside the repo and never cited. Accepted art was copied intozoen/art/originals/and is read-only. - Consequences: New logo needed (
ART-UI-020). Everything an agent needs must exist here; missing facts are added to data with"proposed": true.
◆ADR-002 · Web-native client: TypeScript + Babylon.js
Superseded by ADR-024 (owner approval, round 6, 2026-10-04). Kept for history. The wiki Feel Lab still uses Babylon.js as previz.
- Context: Targets are browser and mobile, with AI agents doing most of the work from a CLI.
- Decision: The client is TypeScript + Babylon.js 9 (WebGPU with a WebGL2 fallback), bundled with Vite. Mobile ships the same build as a PWA, plus Capacitor shells for the app stores.
- Why: Small download, instant start, no editor GUI dependency, text-only sources (diffable, testable headless), and the same code on every platform. iOS/iPadOS 26 Safari ships WebGPU by default.
- Trade-offs: No visual editor (we build in-game debug tools and use the Babylon Inspector). Animator-style and VFX-graph conveniences are rebuilt as small, tested systems.
- Rejected: Unity 6 Web (heavy downloads, mobile browser memory limits, needs the GUI editor), Godot web export (threading/C# limits), Unreal (no web target).
◆ADR-003 · Rust authoritative zone servers and their protocol, 1,000 players per channel
- Status: Decided (round 1, 2026-10-03). Written up in full by M0-06 (2026-10-10) from what M0 built; the write-up is proposed — awaiting owner approval (M0 gate "ADRs approved by owner"). Amended by ADR-024 (Unity client) and ADR-029 (one simulation; spike M0-11 passed on Web, macOS and Android). Also covers the wire protocol.
- Context: One map must hold a crowd (towns, world bosses), every hit must stay fair at up to 200 ms RTT, and clients run on phones and in browsers. Outcomes decided on a client can be cheated. AI agents build and test the servers from a CLI, so determinism and headless tests matter more than editor tooling.
- Decision:
- Server authority: each region map runs as a Rust zone process that owns every outcome (movement, hits, damage, loot, XP). Clients send inputs and casts only; animation and VFX never apply damage (non-negotiable rules).
- Fixed tick: 20 Hz (
sim.json → tickHz); one owner per entity; the tick budget is in Netcode for 1,000 players. - Channels: a channel holds 1,000 players plus about 4,000 monsters. When a channel is full, a new channel of the same map opens (caps and routing).
- Shared simulation: rules both sides need (movement, collision, cast phases, cooldowns, costs) are written once in
the
zoen-simcrate: integer fixed-point,no_std, no allocation per tick, an FNV-1a state hash after every tick, and golden vectors exported from the crate (contractsim.json, vectorspackages/sim-golden). - Protocol: one schema,
packages/protocol/zoen.schema.json, generates the Rust and C# message code. Messages are bit-packed binary frames over WebSocket (wss, Nagle off) on every target; WebTransport or UDP only if they measure better later.protocolVersionis bumped on every breaking change and the gateway turns mismatched clients away with an update prompt; servers refuse to start whendataVersion(hash of the game data) differs (versioning, transport and prediction). - Around the zone: the gateway (axum + sqlx) owns accounts and durable transactions in PostgreSQL 17; Rust bots
load-test the zone (
stack.json).
- Why: predictable CPU and no GC pauses at a fixed tick; data-oriented systems parallelise per spatial cell; one Cargo workspace lets the server and the client plugin share the sim crate (ADR-029).
- Built in M0 (M0-03, M0-11 part A): the root Cargo workspace (
Cargo.toml, memberscrates/*, no external crates, clippy deniesunwrap/expect);crates/zoen-sim(step(&mut SimState, &[Input], &mut Events), per-actor input sequence numbers, on-foot movement, region clamp, FNV-1a 64 hash);crates/zoen-sim-tools(readssim.json,attributes.jsonandworld.json;export-golden,bench-step); 4 golden scenarios inpackages/sim-golden/vectors.jsonwith a schema;crates/zoen-sim-ffi(C ABI v1,include/zoen_sim.h).pnpm sim:test|sim:golden|sim:bench;tools/verify.mjsand CI runpnpm sim:test. Built in M1-03 (part A):services/zone(cratezoen-zone: pure tick aroundzoen-sim, fixed-rate scheduler, spatial hash, AOI interest sets,pnpm zone:bench) andcrates/zoen-data(game-data reader); the zone's numbers are innetcode.json. Built in M1-03B: per-client delta snapshots (zoen-zonesnapshot.rs),packages/protocol/zoen.schema.jsonand its reference codeccrates/zoen-protocol(hand-written; codegen with the C# client). Built in M1-03C: thezonebinary's WebSocket endpoint (services/zone/src/net, RFC 6455 onstd,pnpm zone:run). Not built yet:services/bots(M1-04),services/gateway(M6). - Consequences:
- A rule that touches movement or combat lands in
zoen-simfirst; its golden vectors are regenerated and every side checks them, so drift fails the tests. - Server code keeps the Rust rules in
CLAUDE.md: nounwrap()in server paths; fixed-tick systems are pure functions of state and inputs. - Prediction never shows damage; presentation follows server events. How the client runs the shared rules is ADR-029's spike (plugin) with the C# subset of ADR-024 as the fallback.
- The M1 and M6 load gates measure the tick and bandwidth budgets with 1,000 bots. Those budgets, the grid, the interest
numbers and the channel caps are game data in
netcode.json(M1-03);NETCODE_1000.mdexplains them. - Hosting stays local until OPEN-4 is answered.
- A rule that touches movement or combat lands in
◆ADR-004 · Monorepo
- Status: Decided (round 1, 2026-10-03). Amended by ADR-024 (Unity project), ADR-025 (site and admin) and ADR-029 (engine-free C# core). Written up in full by M0-06 (2026-10-10); the write-up is proposed — awaiting owner approval (M0 gate).
- Context: One source of truth (ADR-001) is read by the wiki, the client, the public site, the admin and the servers. Agents work from one checkout, so a change must show up everywhere and be checked by one command.
- Decision:
zoen/is one git repository with three toolchains side by side:- pnpm workspace (
pnpm-workspace.yaml:apps/*,packages/*):apps/wiki,apps/site,apps/admin;packages/game-data(canonical JSON and its tests),packages/ui,packages/db,packages/config,packages/analytics; laterpackages/protocol. - Cargo workspace at the root (
Cargo.toml, memberscrates/*):zoen-sim,zoen-sim-tools,zoen-sim-ffi. The servers join asservices/*from M1-03. - Unity and .NET:
apps/client-unity(the Unity project; not a pnpm package),packages/core-cs(engine-free C# core, loaded by Unity as the local packagecom.zoen.core) andpackages/sim-golden(vectors read by the Rust, C# and JS tests). - Data flows one way:
packages/game-data/data/*.json→ generators (pnpm data:build) and readers (wiki, site export, UnityProjectSetup,zoen-sim-tools). Generated files are never edited by hand. - One check command:
node tools/verify.mjs(data tests,sim:test,core:test, docs lint, wiki typecheck and build); CI (.github/workflows/ci.yml) runs the same checks and the web-tool checks.
- pnpm workspace (
- Why: game data is imported by every part, and a change shows up everywhere in one commit.
- Built in M0: the Cargo workspace (M0-03),
packages/sim-golden(M0-03),packages/core-cs(M0-09),apps/client-unity(M0-04) next to the existing pnpm apps and packages. Layout: repository layout. - Consequences:
- Cross-language contracts are files in the repo (game data,
sim.json, golden vectors, later the protocol schema), and each is checked by tests on every side that reads it. - Per-machine outputs stay out of git (Unity
Library/and builds,packages/core-cs/.artifacts/, Cargotarget/). - Merging to
mainand pushing stay the owner's call (ADR-029).
- Cross-language contracts are files in the repo (game data,
◆ADR-005 · Skill system: Atlas + Codex + 8 picks + facets + finishers
- Status: Decided (round 1, 2026-10-03), revised in round 2 (owner review, 2026-10-04: three weapons per path ADR-006, finishers ADR-015, self and team buffs ADR-016). Written up in full by M0-06 (2026-10-10); the write-up is proposed — awaiting owner approval (M0 gate).
- Context: 8 usable skills at level 40, many builds, PoE-style paths, combos and flashy spam.
- Decision: A Passive Atlas (six 60° sectors, three weapon lanes each) sets stats and Weapon Masteries.
Each Mastery unlocks a Codex of 7 skills (6 + 1 finisher). The player gets 8 skill picks
(
builds.json → skillPickLevels: levels 1, 3, 6, 10, 15, 20, 27, 34). Each pick learns a skill or ranks one up (skills.json → rankRule: max rank 3); ranks 2 and 3 each add a facet choice.- Combos use states (stun, knockdown, launch, chill, burn…) and payoffs; a single 60% conditional direct-hit cap applies.
- Consequences:
- The skill list is data:
skills.jsonholds 18 weapon codices × 7 skills plus 3 pole codices × 6 buffs (144 skills); the Atlas is generated (atlas.json); states and reactions are incombat-states.json. - Skill timings are authoritative server phases (windup → active → recovery, ADR-003); clients only predict the windup presentation.
- The 60% cap is written in Skills & builds only; it gets a data field when payoffs are built.
- Each skill is built to the polish standard (ADR-028); a skill factory follows the first polished skill (ADR-029).
- The skill list is data:
- Details: Skills & builds.
◆ADR-006 · 18 builds: 3 weapons on every path
- Decision (round 2): Every one of the six Atlas paths carries three weapon families, one build each:
| Path | Builds (weapon) |
|---|---|
| Iron · STR | Ravager (greataxe), Warblade (greatsword), Earthshaker (warhammer) |
| Steel · STR+AGI | Twinblade (dual blades), Vanguard (sword & shield), Boltwright (heavy crossbow) |
| Wind · AGI | Nightblade (daggers), Talon (claws), Windarcher (bow) |
| Storm · AGI+INT | Songweaver (pipa, buffer), Windmender (war fan, support healer), Ringdancer (chakram, ricochet DPS) |
| Lantern · INT | Pyromancer (wand, fire), Stormcaller (storm staff, lightning), Frostweaver (rime tome, chill) |
| Jade · INT+STR | Lanternbinder (lantern scepter, summoner), Ashwarden (censer, damaging auras), Oathkeeper (glaive, protector support) |
- The owner's "INT+AGI" and "AGI+INT" lists are the same Atlas path (Storm) and were consolidated into one row.
- Moved: Boltwright → Steel (a heavy crossbow is cranked with strength); Songweaver → Storm; Lanternbinder → Jade. Replaced: Spellslinger split into Pyromancer/Frostweaver/Stormcaller; Stormsage became Stormcaller (pure INT); Moonglaive became Oathkeeper. Retired skills: Glacier Reap, Dragon Coil.
- Rule: Equipping a weapon needs its Mastery on the Atlas and the item's stat requirement (pure: 18 + 2.3×ilvl; hybrid: 12 + 1.45×ilvl in each stat). Origins never lock anything; they only change distances.
- Suggested later builds (region 2, not in data): Hexbinder (bone bell, curses, INT), Sandseer (earth sigils, INT+STR), Dunestalker (javelin, AGI+STR).
◆ADR-007 · Controls: console-style ARPG with a Mouse1 chain
- Decision (round 2): WASD to move. Mouse1 spam runs the chain list: up to 8 chain slots, and only attack skills may be placed there (a build with 8 attack skills can chain all 8). Each press performs the next ready chain skill, or a basic hit if none is ready. Mouse2 is always the movement skill from the belt gem. Q E Z X C are quick skill slots that take any learned skill or buff. 1–8 / F1–F8 hold potions, scrolls, food and buffs. Shift+Mouse1 attacks in place (round 4: was Space+Mouse1; the modifier is rebindable), and Mouse1 on empty ground walks there. Everything is remappable, with gamepad and mobile layouts.
- Why: The owner's spec. One chain list serves both manual spam and Auto-Hunt.
◆ADR-008 · Hit reactions by impact vs weight
- Decision: Every hit has an impact class (light/medium/heavy/massive) and every target a weight class. The server picks the reaction. Normal monsters can be knocked back, knocked down, launched and pulled. Elites take half of that, bosses take break pressure only, and players are never displaced by players outside the arena.
◆ADR-009 · World scale 4.096 km, four monster mounts
- Decision: Amber Basin is 4.096 km square with waypoints at every area. Mounts are permanent per character,
bought from the Stablemaster with gold and gated by level: Reedback Strider (10), Duneplate Carrier (20),
Emberhorn Aurochs (30), Mirage Drake (40) — desert beasts, not plain animals. Data:
mounts.json. - Why permanent: consumable mounts add bag clutter and a gold drain that hurts new players; the gold sink moves to the purchase price, mount feed is cosmetic-free, and skins are sold for Zoe.
◆ADR-010 · Leveling pace: a 24/7 player needs at least 7 days
- Decision (round 2): 175 effective hours to reach 40. The fastest humanly sustainable schedule (14 h party play
- 10 h online Auto-Hunt every day) takes about 8.3 days; a character left on Auto-Hunt 24/7 about 11 days; a typical player about a month (34 days). A rolling-24 h soft cap halves kill XP past 18 effective hours, so even perfect round-the-clock play stays above 7 days (7.3).
- Tuning: one table in
scripts/gen-progression.mjs; the tests enforce the 7-day floor. Alpha uses its own ruleset instead (ADR-019). See Leveling.
◆ADR-011 · Economy and online contracts live in data
- Decision: Refinement +15 bands with Caravan Ward, 12 orbs + 11 shards, sockets 1–3 by tier, a 4×(12×10) stash plus
a 64-slot bank, four equal companions, the Lantern Convoy (16 players), the Kharuun world-boss schedule, boss reward
caps, the 8 h dungeon chest, stalls in gold or whole orbs, build inspection off by default, and offline Auto-Hunt as a
visible actor for 4 h. Canonical numbers:
items.json,consumables.json,materials.json,mounts.json. Summaries: Items & economy, Online.
◆ADR-012 · HUD and in-game UI as one sprite kit
- Decision: No flattened HUD images. HUD pieces (
ART-HUD-*) plus 9-slice sprites cut bytools/build-ui-sprites.pyfrom the accepted UI originals (window frame, leather header, popup headers per type/rarity, glass popup body with bronze bottom corners, 34 px button art in a 44 px target, item wells, sockets, dropdown). The wiki's Components page is the single visual reference for the client.
◆ADR-013 · AI development process with logged tests and tokens
- Decision: Every task is started, tested and finished through
tools/task-log.mjs. Tokens come from Claude Code transcripts (tools/token-ledger.mjs). No task is "done" without a passing logged test and evidence.
◆ADR-014 · Three support roles, no dedicated "healer lock"
- Decision: Songweaver buffs (songs), Windmender heals and cleanses, Oathkeeper protects (taunt, party barriers). All three deal real damage and can solo; party roles are volunteer jobs, never queue locks.
◆ADR-015 · Finisher skills (conditional ultimates)
- Status: Accepted by the owner (round 7, 2026-10-04): "all good, let's proceed".
- Decision: Every codex has one finisher: very high damage, a long cooldown, and a condition on the target (stunned, knocked down, launched, frozen, sleeping, or below 30% life). It costs a pick, so a finisher build gives up a skill.
- In the Mouse1 chain a finisher is checked before every chain step: if the condition is true and it is ready, it fires on that step; otherwise it is skipped silently. Pressed manually while the condition is false, it shows "No opening".
- Why: Rewards building around a state (stun builds feed stun finishers) and gives every weapon a headline moment.
◆ADR-016 · Self buffs vs team buffs, scenario loadouts
- Status: Accepted by the owner (round 7, 2026-10-04): "all good, let's proceed".
- Decision: Each pole codex (Iron, Wind, Lantern) has 3 self buffs (solo farming, duels) and 3 team buffs
(party, team arena). Every skill carries scenario tags (
farm,boss,party,duel,arena), and every build lists suggested swaps per scenario. Respec items make swapping cheap.
◆ADR-017 · Consumables, materials and vendors
- Decision: Potions, elixirs, cleanses, foods and scrolls (return, teleport to waypoint, speed, XP, drop, resurrection,
reset) in
consumables.json. Every monster drops 2 materials (materials.json) sold to vendors for gold; blacksmiths sell white (normal) bases and alchemists sell potions. Stack limits: orbs and shards 999, materials 999, consumables 200. - Amended (round 7, owner): drop quantities are random, never fixed. A monster's material drop is 1–5 (not exactly
2 of anything), and every stackable drop (shards, orbs, consumables, gold) rolls its own range. Ranges:
drop-quantity.json(proposed). The ruleset multiplier (alpha ×10) applies after the roll.
◆ADR-018 · Zoe, the top-up currency
- Decision: Zoe is bought with real money (live only) and spent on cosmetics, mount skins, extra stash tabs and character slots, and convenience that gives no power. Zoe never buys orbs, gear, XP, or refinement. Earned Zoe from bosses stays capped (9 per occurrence, 20/day, 60/week).
- Amended (round 7, owner): a Caravan Market with daily and weekly capped stock where Zoe (and, for a gold sink,
gold) can buy progression helpers: refinement implements, orb shards and boss trophy materials. Everything bought is
account-bound; gear, XP, drop rate, +refinement levels, Reweaving/Crowning/Oathseal and boss-only quest items are never
sold. Catalogue, caps and prices (proposed):
market.json, Items & economy.
◆ADR-019 · Rulesets (alpha / beta / live) and one-time access keys
- Status: Accepted by the owner (round 7, 2026-10-04): "all good, let's proceed".
- Decision (round 4, owner): every test phase is the live game × multipliers (
rulesets.json: XP per source, drop chance, drop quantity, gold, respec cost; live = all ×1). Alpha: XP ×140 quests / ×70 kills (≈ 1.6 h to 40, under 2 h), drops ×10 chance and ×10 stack size, gold ×10, free respec. No custom starting kit: setting the multipliers back to 1 gives the live game unchanged. Testers get the big test kit (orbs, bases, levels, bosses, preset builds) in the GM room. Switching phase is one config value. (Round 2 had a custom alpha stash: 10M gold, 999 of every orb. The owner replaced it in round 4.) - Access keys: single-use keys (stored hashed, burned on redeem, bound to the new account). Agents never mint keys or create accounts; the owner runs the mint command.
◆ADR-020 · Jewelry and 11 equipment slots
- Status: Accepted by the owner (round 7, 2026-10-04): "all good, let's proceed".
- Decision: helmet, main hand, off hand, gloves, boots, armour, belt, necklace, earring, ring ×2. Jewelry rolls affixes like gear but has no sockets.
◆ADR-021 · PvP: duels and the Sand Arena only
- Status: Accepted by the owner (round 7, 2026-10-04): "all good, let's proceed".
- Decision: No open-world PvP in the MVP. Consensual duels (1v1, anywhere outside towns) and a rated Sand Arena (2v2 and 4v4 instances). Arena damage uses a PvP coefficient so PvE balance stays separate.
◆ADR-022 · Public website
- Status: Accepted by the owner (round 7, 2026-10-04): "all good, let's proceed".
- Decision: A separate public app (
apps/site) built from public data only: game guide, builds, rankings, armory (opt-in), events, patch notes, alpha key redemption. No admin, art-request, token, task or roadmap data ships there. Plan: Public website. - Amended by ADR-025 (2026-10-04): the site is a Next.js server app (not a static export), and a public roadmap built
only from allow-listed
publicfields of the roadmap data is allowed.
◆ADR-023 · Atlas playground
- Status: Accepted by the owner (round 7, 2026-10-04): "all good, let's proceed".
- Decision: The Atlas page is a playground: click to allocate along the cheapest path, click an allocated node to remove it and every node that loses its connection, undo/redo, share codes, build presets. In game the same rules apply, with respec costs.
◆ADR-024 · Engine for native + web: Unity 6 LTS client, Rust servers
- Status: Accepted by the owner (round 6, 2026-10-04): "from the game coverage and scope I will go with your recommendation". Supersedes ADR-002; closes OPEN-9. Analysis: Engine & platforms; tooling: Unity development toolkit. The M0-06 write-up below (what M0 built, consequences; 2026-10-10) is proposed — awaiting owner approval (M0 gate).
- Context (decided by the owner, round 4): Zoen ships on Windows, Android, iOS and the browser. The browser is capped at Low–Mid; the full High/Ultra experience is in the downloaded apps.
- Decision:
- One Unity 6 LTS + URP (C#) client project for all four targets. The Web build carries only the Low/Mid profiles.
- Rust authoritative servers stay (ADR-003).
- Client prediction subset in C#, checked against the same golden vectors as the Rust sim.
- The wiki Feel Lab stays Babylon.js previz.
- Trade-offs: larger web download; needs the Unity editor and a Unity ID (owner); C# and Rust share rules via test vectors instead of one crate.
- Amended by ADR-029 (2026-10-06): the client side of the shared simulation is decided by a spike. If the Rust crate runs as a plugin on every target, the C# prediction subset is not written; otherwise it stands. The pin is Unity 6.3 LTS. Amended by ADR-032 (2026-10-08, 2026-10-11): test builds are Web, an Android APK and a Windows player tested on the owner's Windows PC; macOS and iOS are paused (until 2026-10-11 the third test build was a native macOS app). The release targets above are unchanged.
- Built in M0 (M0-04 to M0-12):
apps/client-unity: Unity 6000.3.25f1 (ProjectSettings/ProjectVersion.txt; version and changeset instack.json), URP 17.3, four quality tiers generated fromfeel-quality.jsonbyZoen.ProjectSetup.Run(Web Low–Mid; tier defaults and caps fromfeel-quality.json → tierSelection, proposed), FPS overlay, the capability probe (M0-05) and day/night and weather (M0-12, ADR-030).- Builds and smokes pass on Web (Chrome on the Mac and the phone), macOS and the Android APK on the owner's phone.
- Engine-free rules in
packages/core-cs(Zoen.Core, netstandard2.1, xunit,pnpm core:test), loaded by Unity as the local packagecom.zoen.corewith no engine references (M0-09). - Headless runner
tools/unity-run.mjs(EditMode, PlayMode,build web|macos|android, one Unity at a time; M0-10); Test Framework 1.6.0 and Performance Testing 3.5.0 pinned, no MCP (M0-07). - One-simulation spike, part A (M0-11):
crates/zoen-sim-ffiruns inside the macOS app through theZoenSimNativeP/Invoke bridge and matches the golden vectors on every tick. Android, Web, Windows and iOS (M0-11B–D) wait for the owner's approval of the Rust targets; the spike result is pending and is recorded in ADR-029. No C# prediction code exists.
- Consequences:
- The owner holds the Unity ID and the Unity Personal licence (active since 2026-10-08); the plan terms are checked
before release (
stack.json). Editor and package upgrades go through the toolchain gate in Unity development toolkit. - Agents drive Unity from the command line only: scenes are built from code, tests and builds run through the runner, and gameplay rules that stay in C# live in the engine-free core.
- The client's prediction path follows the M0-11 result: the
zoen-simplugin on every target, or this ADR's C# subset. The protocol code generator emits C# for the client (ADR-003). - The Web build is capped at Low–Mid and its download and memory are measured, not assumed. The Windows player is built on this Mac (Mono) and tested on the owner's Windows PC; the Windows sim DLL is built on that PC; iOS is paused (ADR-032).
- The owner holds the Unity ID and the Unity Personal licence (active since 2026-10-08); the plan terms are checked
before release (
◆ADR-025 · Web platform: public site + admin on local Supabase
- Status: Accepted by the owner with the web-platform plan (2026-10-04); details are refined during the build
(tasks
WEB-*). Amends ADR-022 (static export, roadmap) without changing ADR-001/003/019. - Context: the owner asked for the player site and a game admin now, in this monorepo, with a local database in Docker and a real AI bug-fix flow. The docs give player accounts, characters, items, receipts and rankings to the Rust gateway (M6), so nothing yet stores web content, staff accounts or operations data.
- Decision:
apps/site(player site, a Next.js server app — not a static export) andapps/admin(staff console) joinapps/wikiin the pnpm monorepo. Shared code lives inpackages/ui,packages/db,packages/ai-ops,packages/analyticsandpackages/config. The wiki is not refactored.- Supabase (Postgres 17 + Auth + Storage, local in Docker,
packages/db/supabase) is the web platform's store: news/FAQ/status/site settings, pre-registrations and newsletter, staff accounts with roles and an append-only audit log, bugs, live-ops config (flags, ruleset overrides, switches), AI jobs and first-party site analytics. - Supabase Auth is for staff only, always with 2-step sign-in. Player accounts, characters, items, receipts, rankings and access keys stay with the gateway and its own database (Accounts and sign-in, ADR-019); the admin reaches them through a GameOps adapter that shows labelled demo data until M6. Agents never mint keys or create player accounts.
- Game content stays canonical JSON in git (ADR-001). The admin reads it and stores change proposals only. The site reads an allow-listed export; proposed records and tuning numbers are not exported (owner, 2026-10-04).
- A public roadmap is allowed, built only from allow-listed
publicfields of the roadmap data (no dates, no budgets). - AI bug fixes: an owner-approved job runs Claude Code on the owner's Mac when its worker is online, otherwise in GitHub Actions; both push a branch and open a pull request, and never merge.
- Built (2026-10-05, tasks
WEB-*): both apps run end to end on the local stack — the site (direction A) and the console with 15 modules (Players, Security and World on labelled demo data). Every rule is enforced in the database as well as the console (tested per role), publishing reaches the site at once through a signed webhook, and the AI fix pipeline works up to the keys the owner adds. Details: Web platform, Staff console. - Trade-offs: a second Postgres (web) next to the future gateway database; the site needs a Node host when it goes online (OPEN-4); Docker memory is shared with other local stacks.
◆ADR-026 · Town/GM music, special boss themes and outdoor environment sound
- Status: Accepted by the owner (2026-10-05) in chat: music for each town and the GM arena, made classic; outside towns "instead of background music we can generate a background environment effect". Replaces the per-zone theme plan in the Audio pipeline; advances OPEN-3.
- Context: the hunting areas are combat spaces. Hit layers, telegraph cues and boss warnings must stay readable (telegraphs are never culled), and a 1,000-player crowd already competes for the voice budget. Ten extra long zone themes would also be the slowest assets to generate and loop-test locally. Towns and the GM room are where the owner stands still or tests for long sessions, so music fits there.
- Decision:
- Towns each play one looping classic theme (orchestral fantasy; the Amber Basin has one town, Amber Gate), with the crowd bed and a forge emitter underneath. A future town adds one theme of its own.
- The GM room (Caravan Proving Ground) plays its own calm classic loop with steady dynamics, so hit sounds stay audible in long manual tests.
- Ordinary outdoor travel/combat (the ten hunting areas and Caravan Crown Arena) has no ambient zone music: a 20 s environment bed per area plus one spot emitter on its landmark (Environment, stage 11). Each bed is written for its area; "no music, no voices" travels in the negative prompt.
- Music is generated locally with the Stable Audio 3 Small Music bundle; beds and emitters stay on Small SFX.
- Amended (owner, 2026-10-05, round 9): audio must not be annoying. As in most games: a calm town theme, and outdoors a quiet bed plus random sparse ambient accents instead of a constant loop; music rests between plays (Audio).
- Agent's reading (owner can veto): "classic" = classic orchestral fantasy (strings, woodwinds, harp, horn, timpani), with the oud and frame drum already named for Amber Gate. Instrumental, no choir.
- Amended (owner, 2026-10-05, battle preparation follow-up): special boss music is allowed for named engaged boss encounters, including the Regent and Kharuun. Encounter start/end/reset/leash/leave/death/reconnect governs playback; warnings duck music and remain audible. Outside an encounter, outdoor environment sound resumes. Town/GM rest scheduling does not impose gaps on an active boss theme. New boss briefs are planned assets, not delivered audio.
- Not decided: the Sand Arena colosseum outside named boss encounters, day/night variants of the beds.
- Amended by ADR-030 (owner, 2026-10-06): a day/night cycle and weather are accepted, so each area bed gets a night variant and weather adds a wind or rain layer.
- Trade-offs: areas have no theme of their own, so identity comes from sound design; local AI music can only be judged by listening (every take is playable on the Audio generation page; loop seams are checked numerically).
◆ADR-027 · Movement-first battle preparation and quality gates
- Status: Owner direction recorded (2026-10-05) from the request to prepare the wiki before game development. Runtime implementation remains future work; owner follow-up accepted the foundations below. Numeric targets remain proposed until profiled, even where the owner suggested or accepted a starting value.
- Context: animation lockouts, incompatible bodies and unreviewed skill/environment assets undermine the console action experience the owner wants. The old Combat active-phase lock conflicted with the requested immediate escape.
- Decision: a valid movement gem cancels an own attack in windup, active and recovery, including signatures and finishers. Normal resource, cooldown, hard-control and destination validation remains. Resolved hits stay authoritative; future cast-owned hits stop; already released independent entities keep their lifetime. Animation/hitstop cannot delay valid movement. Action skills come next; WASD uses an explicitly authored per-skill locomotion policy.
- Quality direction: establish a versioned mannequin; perform multi-angle agent self-review, chain/control/movement
tests, rich readable VFX review and complete environment checks before content expansion. Mandatory guide:
Game development guide; preparation data:
development-standards.json. - Owner follow-up accepted (2026-10-05):
- Every movement gem needs mana. Starting reuse targets: Cairn Vault jump 1 s, Reed Rush dash 0.3 s; other gems are individually tuned. Cooldown is not input/startup latency. Exact per-gem mana/travel values precede implementation.
- Stun/sleep/knockdown block movement; roots block unless a gem explicitly escapes them.
- Researched per-skill locomotion: mobile buffs/compatible aimed casts, brief planted contacts, directed travel.
- Combo resumes at the next eligible slot after movement (starting memory 1 s); expiry restarts. Before attack commit, no attack mana charge and starting 50% attack cooldown refund; no attack refund after commit. Movement pays its own cost.
- Optional close-view boss lock-on, role/difficulty enemy engagement coordination, foundation work and a small optional cosmetic KO/combo display in the first slice. Perfect-dodge rewards, hit-confirm cancels, hazards/destruction deferred.
- Close third-person and zoomed-out tactical views; R3 toggles views only. Silk Roll is blue.
- Entry-level hardware is the floor; delegated reference selection is recorded in
reference-devices.jsonand Performance. Physical validation is pending. Special boss music is permitted under the ADR-026 amendment.
- Consequences: supersedes Combat §3's unconditional active-phase lock for movement gems. Extend server replay, input, animation cleanup and collision tests before production. No new invulnerability, perfect-dodge reward, console release or game mode is inferred. Suggested locomotion defaults and numeric limits require playtest validation.
◆ADR-028 · AAA detail catalog and feel defaults
- Status: Accepted by the owner (2026-10-06) in chat: "yes" to adopting the catalog stage by stage; camera shake "70% but we should have settings for this"; "yes" to no blood and to hiding other players' damage numbers by default. Closes OPEN-12 and part of OPEN-14.
- Context: the wiki defined the big systems (hit-feel stack, effect layers, 4-layer hit sound, budgets) but not the small details that make them feel finished. Three of its techniques also do not exist on every platform: telegraphs as pooled decals, and mixer snapshots and dynamic resolution in the Web build.
- Decision:
polish-standards.jsonis the polish standard: 127 details in three stages.coreis due with the first polished skill (G2),slicewith the battle slice (G3) andpolishin M10. The skill gate gains row 14. Page: AAA detail catalog.- Its numbers stay starting values to tune, like every proposed value under ADR-027. The catalog never overrides
combat-states.json,feel-quality.jsonor the performance budgets. - Feel defaults are settings. Camera shake defaults to 70% in both data files. Other players' damage numbers are hidden by default. There is no blood. Rules: development guide → player settings.
- Consequences: telegraphs get a renderer and pool of their own (VFX-04); every mix decision must work as bus-gain changes (SFX-03); every technique names its fallback per platform (OPT-01). Nothing is implemented or measured yet.
◆ADR-029 · Token rules, agent self-review and development order
- Status: Accepted by the owner (2026-10-06): "lets proceed with all of your suggestions". The one-simulation question (OPEN-11) was delegated: "proceed whats best ill let you decide". Closes OPEN-11 and OPEN-13; amends ADR-013 and ADR-024.
- Context: measured on 2026-10-06, 69% of the Claude cost was re-reading conversation context (median 465k tokens per turn) and the Ledger's task rows were double-counted. The roadmap waited on one install although half of M0–M2 needs no Unity, and it planned 5–7 hand-built tasks for each of 144 skills. Details: Speed and token efficiency.
- Decision:
- Token rules bind every agent (
CLAUDE.md): one task per fresh session, context packs instead of whole data files, checks batched into one command, loops as scripts, numbers before pictures. - Agent self-review of animation is metrics over every frame, one contact sheet and the flagged frames. The owner reviews motion.
- Order of work: the server and content lanes start before Unity is installed. Gameplay rules that stay in C# live
in an engine-free core tested with
dotnet test. Scenes are built from code. A Unity runner summarises logs. A skill factory is built after the first polished skill and before the 18 skills of M4. Tasks M0-09 to M0-11 and M2-11, and theneedsandearlyStartfields, are inroadmap.json. - One simulation (the agent's decision by delegation; the owner can veto it): the target is the Rust
zoen-simcrate running inside the client as a plugin, so every rule is written once. A spike (M0-11) must pass on Windows, Android, iOS, macOS and the Web build. Until it does, no C# prediction code is written, andzoen-simkeeps a plain, allocation-free step interface and still exports golden vectors. If the spike fails on any shipping target, the C# prediction subset of ADR-024 stands. - Spike result (M0-11, 2026-10-11; report
logs/evidence/M0-11D/spike-report.md): golden hashbb46012ea5aaaebfmatches every tick through the plugin on macOS (dylib 406 KB; 108 ns/tick for 1 mover, 0.33 ms for 5,000), Android APK on the nubia phone (.so 317 KB; 54.5 ns, 0.15–0.16 ms) and the Web build in Chrome (static archive, build +38 KB; 70–100 ns, 0.16–0.21 ms; 0 console errors). iOS is built and recorded not tested (ADR-032): staticlib 2.3 MB at iOS 15.0, the C smoke links with Xcode 26.6. Windows: the staticlib builds; the DLL needs the MSVC CRT and Windows SDK libraries (Microsoft licence, owner item). Decision: confirmed with a qualification:zoen-simis the one simulation for client prediction and the server, and the C# prediction subset is not written. Open risks: Windows (licence, no test machine), iOS not run, the bundled Emscripten 3.1.39 (LLVM 17) needs a feature-name rewrite of rustc's objects on every upgrade, and the Web floor is Chrome 95, Firefox 100, Safari 15.2. If Windows or iOS fails once tested, the fallback is decided then for that target only. - Toolchain: agents installed Rust and the .NET SDK on 2026-10-06. Unity may be installed by command line; the owner still signs in. The pin is Unity 6.3 LTS (supported until December 2027; 6.0 LTS support ends in October 2026).
- Git: the working tree was committed on the branch
sync/working-tree-20261006. Merging tomainand pushing stay the owner's call.
- Token rules bind every agent (
- Consequences: the read-first set shrinks (
CONTINUE_HERE.mdwithout history); per-task token numbers are attributed per session from now on. Nothing changes for players.
◆ADR-030 · Day/night and weather from day one
- Status: Accepted by the owner (2026-10-06): "lets add it in day one so we optimize game development, we can put a toggle button in gm's arena". Closes the rest of OPEN-14; amends ADR-026.
- Context: lighting, effects, sound and budgets all depend on the time of day and the weather. Adding them late would mean re-authoring and re-testing every area, effect and telegraph.
- Decision:
- A world clock and a weather state per area exist from the first client scene (M0-12). Contract and starting values:
time-weather.json(four phases, five weather states, the weather each area allows, budgets). - The GM arena has Time and Weather buttons and the commands
/gm time,/gm cycleand/gm weather. - Every look, readability and performance check runs across a small review matrix: day, night, a hazy dusk and the area's heaviest weather.
- A world clock and a weather state per area exist from the first client scene (M0-12). Contract and starting values:
- Agent's reading (owner can veto): look and sound only, with no gameplay effect in the first release. The server owns the clock, so everyone in a channel sees the same sky. Each area keeps its mood as a grade over every phase.
- Consequences: each area bed gets a night variant and weather adds a wind or rain layer (the audio requests are not written yet). The environment pipeline's lighting stage produces four keyframes per area. Weather particles live inside the tier totals. The cycle length and weather odds are proposed, not final.
◆ADR-031 · Round-2 review decisions
- Status: Accepted by the owner (2026-10-07), answering the round-2 review: "1. c 2. a 3. yes 4. all 5. later, for the action ensure it is aaa and ill adjust or give feedback later". Closes OPEN-15 to OPEN-19; amends ADR-028 (catalog) and ADR-029 (token rules).
- Context: the confirmed hit layer arrives one round trip plus up to one 50 ms tick after the local contact frame (80–130 ms at an 80 ms round trip). Accepted details already need voices. The token rules were written but not enforced, and the catalog had no online, input, look or session details.
- Decision:
- Hits online (OPEN-15, C): build both impact modes behind a Combat Lab switch: strict confirmed layers (HIT-04) and predicted contact (attacker freeze, spark and first impact transient on the client's own hit test; numbers, health, reactions, status and kill confirm on the server event). The owner judges both at a simulated 80 ms round trip (NET-01) with the measured delay (NET-02) and picks one at G2.
- Voices (OPEN-16, a): non-verbal efforts, hurt sounds, barks and creature voices from the local audio generator; no spoken lines.
- Enforcement (OPEN-17, yes): a read guard, a context meter, lane agents with a model each, and a next-session chip at every finish (review E2, E3, E5, E7), built in a task of their own.
- Catalog round 2 (OPEN-18, all): the 90 details, the NET, INP, LOOK and FLOW areas and the
alphastage are part of the polish standard; 44coredetails gate G2. - Video-to-motion (OPEN-19, later): not now. The agents make the action AAA with the existing pipeline (mannequin, Mixamo base motion, polish and the catalog); the owner reviews it and gives feedback later.
- Consequences: M2-01 runs at a simulated 80 ms by default, M2-07 builds both impact modes and M2-08 judges them. The predicted mode needs the shared simulation in the client (M0-11) or a client hit test that matches the server's. Effort sets per lineage and gender become audio requests, judged by listening.
◆ADR-032 · Test platforms the owner can run now
- Status: Accepted by the owner (2026-10-08): "i only have nubia 7s pro, i can test here in browser" · "for mac os meaning it will have native app? if yes then lets do it" · "yes i have android phone, if possible we can also pass on this device so i can test" · review feel in the browser and the macOS build: "yes". Amends ADR-024 (test builds only) and the M0-05, M0-11, M2-08 and M2-10 cards; OPEN-1 stays decided.
- Amended 2026-10-11 (owner): "can we skip macos and ios for now, we focus browser, android, windows to make the development faster, lets update the guide document" · where the Windows build is tested: "I have a Windows PC" · may agents download Microsoft's Windows SDK and CRT with xwin on this Mac: "No, build it on a Windows PC". Development focus only: the release targets of ADR-024 are unchanged.
- Context: the owner tests on an Apple M3 Mac and one Android phone (nubia, "7s pro"; exact model, chip and RAM are recorded by the M0-05 probe). The owner has none of the selected Low references, no gamepad was named, and Xcode is not installed. The Unity Personal licence was activated on 2026-10-08. Since 2026-10-11 the owner also tests on a Windows PC (hardware not yet probed) that agents can't reach.
- Decision (as amended 2026-10-11; from 2026-10-08 the test builds were Web, a native macOS app for High/Ultra and
the Android APK, and M0-04 to M0-12 were tested that way):
- Test builds: every client milestone produces a Web build (Chrome on the Mac and on the phone), an Android APK sideloaded to the owner's nubia NX709S (no store account) and a Windows build: the Unity Windows x86_64 player with the Mono backend, built on this Mac, copied to the owner's Windows PC and tested there by the owner (agents can't reach that PC; WIN-01 gives him a smoke kit).
- Paused: macOS and iOS. Neither is built or tested in milestone work. Existing macOS/iOS code, plugins and scripts stay, unmaintained; resuming either is a new owner decision. macOS was never a release target.
- One-simulation spike (M0-11): passed on Web, macOS and Android; iOS was built, not tested. The Windows sim
DLL is built on the owner's Windows PC (Rust and Visual Studio Build Tools, installed by the owner;
node tools/sim/build-plugin.mjs windows); agents don't download the Microsoft SDK or CRT. Until the DLL exists, the Windows player runs without the native sim (the boot check reports it absent; that is not an error). If a target later fails, the C# subset of ADR-024 stays the fallback. - Owner's devices: the phone and the Windows PC are test devices, not Low references
(
reference-devices.json → ownerTestDevices: the PC is unprobed until WIN-01; the Mac's measured probes stay as history). Their results are labelled with their probe; they do not validate the Galaxy A07 or Intel N150 baselines. - Low references: physical validation stays pending. Agents record Windows PC, Chrome and phone numbers plus Chrome CPU-throttle runs as "not verified on Low"; the M4 performance gate stays open until reference units exist.
- Feel review (M2-08): the owner judges both impact modes in Chrome (Low–Mid) and on the Windows PC (High), which takes over the macOS app's High/Ultra view.
- Controls (M2-10): keyboard/mouse on the Windows PC and in Chrome on the Mac, touch on the owner's phone; gamepad stays unverified until one is connected.
- Consequences: the M0-04 builds added Android; M0-05 probed the owner's phone; M0-11 needed the Rust targets
wasm32-unknown-emscriptenandaarch64-linux-android. WIN-01 adds the Windows build, the owner's smoke kit and the Windows probe. No purchase is needed.
◆ADR-033 · 3D: Blender and the mannequin first, Tripo by hand from a request log
- Status: Accepted by the owner (2026-10-08): "use blender for now and use the mannequin" · "i have tripo ai subscription but i think its different so the only thing i can do is to manual create each 3d model" · "create a todo logs in wiki like the sound effects and image" · "armors should be different". Amends OPEN-2 and the Tripo pipeline; ADR-024 and the character pipeline stay.
- Context: the owner's Tripo plan is a web subscription; API credits are not confirmed and no API key exists on this Mac. The hands-free API path therefore cannot run. Rigging armour into a character mesh makes clipping, weights and modular gear hard to fix.
- Decision:
- Blender first. Agents build with Blender headless scripts and the versioned mannequin (M2-09): bodies from MPFB2, weapons and simple props hard-surface in Blender, VFX flipbooks in Blender. Skill and battle work uses the mannequin until M3 bodies pass its contract.
- Tripo by hand. Agents never call the Tripo API or automate its website. A generated model request log
(a generated data file and the wiki page Model requests, like the art and audio requests) lists each model the owner may
make in the Tripo website: id, use, reference views, prompt, settings, polygon budget and the file name. The
owner drops the exported
.glbintoart/3d/inbox/. Agents check the inbox at the start of each art or content task, validate and polish the file in Blender, and record it as delivered. Until a model arrives, its Blender placeholder is used. This costs nothing new (no API credits). - No Tripo auto-rig. Tripo exports are unrigged. Agents rig in Blender: humanoids and armour onto the Zoen game skeleton of the mannequin contract (Rigify → bake, Animation), monsters onto their family rigs (NPCs & monsters). One skeleton keeps animation, sockets and retargeting shared.
- Base body plus separate armour. Player bodies are modelled and rigged in a thin, close-fitting undersuit. Armour, robes and outer clothes are separate meshes per slot, fitted and weight-transferred in Blender, and the covered body regions are hidden by masks. New 2D requests add undersuit turnarounds per lineage and gender and armour-piece sheets per set and slot. The armoured turnarounds ART-CHR-050/051 stay as design reference only.
- Consequences: a new task (MODEL-01) builds the request generator, the wiki page, the inbox checker and the new 2D requests. The Tripo API sections stay documented for a later decision but are not used.
◆Open decisions (owner)
| ID | Question | Default until answered |
|---|---|---|
| OPEN-1 | Decided (owner, 2026-10-05): entry-level floor; selection delegated. Galaxy A07 4G / 4 GB, iPhone SE (2020) / A13, Intel N150 / 8 GB integrated-GPU Windows laptop. Exact probes and physical benchmarks pending; Performance. | |
| OPEN-2 | Decided (round 7): Tripo (owner bought a plan) + Blender polishing. Tripo → Blender pipeline | |
| OPEN-3 | Decided (round 7): local AI generation (Stable Audio 3, Local SFX); SFX and ambience work now; music needs the extra Small Music bundle (owner choice). 2026-10-05: the owner chose town/GM music, later permitting special boss themes (ADR-026); the owner approved the Small Music download (919 MB) the same day and it is installed | |
| OPEN-4 | Hosting for the alpha (VPS) | Skipped by the owner (round 7): local only; decide when the alpha testers come |
| OPEN-5 | App store accounts (Apple $99/yr, Google $25) | Skipped by the owner (round 7): Web build + local native test builds only |
| OPEN-6 | Final balance formula (damage/mitigation/crit) beyond proposed tuning | Skipped by the owner (round 7): test the game first; proposed formulas in COMBAT.md stay |
| OPEN-10 | Windows code signing (see the explanation in Updates) | Unsigned local test builds only |
| OPEN-7 | Zoe price table (PHP per Zoe pack) | Not sold until beta; alpha grants only |
| OPEN-8 | Which team position events ship first (proposals) | Lantern Rush + Last Light for the first release; Caravan Run next |
| OPEN-11 | Decided by delegation (2026-10-06, ADR-029): target the Rust simulation as a client plugin; spike M0-11 decides; the C# subset of ADR-024 is the fallback | |
| OPEN-12 | Decided (owner, 2026-10-06, ADR-028): accepted, stage by stage | |
| OPEN-13 | Decided (owner, 2026-10-06, ADR-029): accepted; they are in CLAUDE.md and the kickoff prompt | |
| OPEN-14 | Decided (owner, 2026-10-06): camera shake 70% with a setting, no blood, other players' numbers hidden (ADR-028); day/night and weather in from day one (ADR-030) | |
| OPEN-15 | Decided (owner, 2026-10-07, ADR-031): C. Strict and predicted-contact impact modes behind a Combat Lab switch, judged at 80 ms; the owner picks one at G2 | |
| OPEN-16 | Decided (owner, 2026-10-07, ADR-031): (a). Non-verbal efforts and creature voices from the local generator; no spoken lines | |
| OPEN-17 | Decided (owner, 2026-10-07, ADR-031): yes. Read guard, context meter, lane agents and next-session chips, built in a task of their own | |
| OPEN-18 | Decided (owner, 2026-10-07, ADR-031): all. 90 details, four areas and the alpha stage accepted | |
| OPEN-19 | Decided (owner, 2026-10-07, ADR-031): later. Mixamo base motion and agent polish; the owner gives feedback on the action later |
Source: zoen/docs/vision/DECISIONS.md · 8,157 words · edit the Markdown, not this page.
