Layered architecture
The stack with enforced import direction.
Reading the stack
Top to bottom is outer to inner: the UI (HTML or React) mounts scenes, scenes hand off to the FSM, the FSM drives presenters, presenters observe stores, stores hold domain wire-types. Infrastructure (network, timing, assets) is a sibling service layer that flow and presenters can call into.
Import rules
- A layer may import from layers below it.
- A layer may NOT import from layers above or alongside it
(except
infrastructure, which is a shared service layer callable byflow/andpresenters/). domain/imports nothing but types and otherdomain/files.- Only
view/andpresenters/may importpixi-reels/pixi.js.
These are enforced by biome.json using no-restricted-imports
rules. Violating them fails lint locally and in CI.
One layer per folder
Here's what lives where:
| Folder | Content |
|---|---|
src/composition.ts | Composition root. Wires every service. |
container/ | Tiny DI container (type-keyed, lazy). |
state/ | MobX stores. Observable state + @action mutators. |
domain/ | Wire types only. SpinRequest, SpinResponse, Grid, Winline. |
infrastructure/ | I/O. Network, ticker, assets, analytics. |
flow/ | FSM + phase handlers. Owns game time. |
presenters/ | State → view. ReelsPresenter, HUDPresenter. |
view/ | Pixi scenes, symbol classes, overlays. |
config/ | Client-side config (grid dims, symbol ids). |
Data flow through the layers
Why layers, not packages
A package per layer is overkill for a single-game repo. It introduces build orchestration, version management, and workspace linking — all of which are costs. Layers as folders plus lint boundaries give you the isolation without the ceremony.
Violating the rules
If you really need to cross a boundary (and sometimes you do — Pixi math utilities, for example, are a judgement call), do it with an ADR. An architecture decision record is a committed document explaining why this case is different. Adding a rule exception via code comment is not acceptable; the justification lives in version control where future-you can find it.