Skip to content

AI Agent Orientation

Expanded reference for AI coding agents working in this codebase. Start here, then load the relevant skills file for your current task.

Related: Architecture Rules · Style Guide · Project Structure · Glossary


Architecture: MVT (Model-View-Ticker)

  • Models - own all state and domain logic; advance only via update(deltaMs).
  • Views - stateless renderers; read state through a bindings interface; refresh every frame via refresh().
  • Ticker - drives the loop each frame: model.update(deltaMs) then view.refresh() then renderer draws.
  • Bindings - plain object bridging view and model: get*() methods read state, on*() methods relay user input.

Full details: Architecture Overview · Architecture Rules

Critical Rules

These are non-negotiable. Violating any of these produces incorrect code.

  1. No em-dashes - use hyphens instead.
  2. Models must not use wall-clock time. No setTimeout, setInterval, requestAnimationFrame, or auto-playing GSAP tweens. All state advances through update(deltaMs) only. Time Management
  3. Views must be stateless. No domain logic, no autonomous animations. Read state from bindings (leaf views) or model properties (top-level application views), write to the presentation output, nothing else. Exception: limited presentation-only state. Views · Presentation State
  4. Never import past a barrel file. All cross-directory imports go through index.ts. Within the same directory, use direct relative paths (./foo). Project Structure
  5. No classes. Use factory functions returning plain records that satisfy an interface. Style Guide
  6. Hot-path awareness. update() and refresh() run every tick (~60fps). Avoid per-tick allocations: no array.map(), no template-string keys, no for...of on arrays, no inline closures. Use index-based for loops and pre-allocated structures. Hot Paths
  7. Model coordinates must be domain-level, not pixels. Grid-based entities expose fractional row/col/direction - not x/y in pixels. Views compute pixel positions from domain coordinates. Models

Project Structure

src/
├── main.ts              Bootstrap: init Pixi app, create cabinet, start ticker
├── cabinet/             Cabinet model & view (game selection)
├── games/               Game registry + per-game modules
│   ├── game-entry.ts    GameEntry & GameSession interfaces
│   └── <name>/          Self-contained game module
│       ├── data/        Static data and configuration constants
│       ├── models/      State & domain logic + domain types
│       └── views/       Pixi.js rendering
└── common/              Shared helpers, views, and models

Cabinet Architecture

  • GameEntry - descriptor for a game registered in the cabinet: { id, name, screenWidth, screenHeight, start(stage) -> GameSession }
  • GameSession - a running game instance: { update(deltaMs), destroy() }
  • To add a new game: create src/games/<name>/ with data/models/views, export a createXxxEntry(): GameEntry factory, register it in src/games/index.ts. Adding a Game

Key Conventions

  • Barrel imports only - never import past a directory's index.ts.
  • Factory functions, not classes - createXxxModel(options) returns an interface; implementation is a plain record with closure-scoped private state.
  • Interfaces over implementations - export the interface type, not the concrete object shape.
  • String-literal unions for enums - type TileKind = 'empty' | 'wall' | 'dot'; never use enum or const-object patterns.
  • Kind over Type in type names.
  • phase over state for lifecycle properties.
  • Bindings for reusable views - leaf views accept a get*()/on*() bindings object; top-level application views accept the model directly.
  • _ prefix for intentionally unused parameters.
  • 4-space indentation, lower-kebab-case file names, PascalCase types, camelCase everything else.
  • No null - use undefined.

Full details: Style Guide

File Organisation Within a Module

Each model/view file follows this internal ordering:

// --- Interface ---
// Public interface definition

// --- Options (if needed) ---
// Options type for the factory function

// --- Factory ---
// createXxx() factory function implementation

// --- Internals (if needed) ---
// Internal types, constants, and helpers

Commands

CommandPurpose
npm run devStart Vite dev server
npm run buildType-check + production build
npm run lintCheck lint and formatting
npm run lint:fixESLint auto-fix pass

Tech Stack

TypeScript 5.9 - Pixi.js 8 - GSAP 3 - Vite 7 - ESLint 9 - ESLint Stylistic

Skills Files

For task-specific guidance, load the relevant skills file before starting work:

TaskSkills file
Writing a new modelskill-mvt-model.md
Writing a new viewskill-mvt-view.md
Following code conventionsskill-code-style.md
Reviewing codeskill-code-review.md
Updating documentationskill-documentation.md

Each skills file is self-contained and combines both MVT architectural rules and this project's code conventions. Constraints are labelled as either MVT requirement or project convention so you know which are universally applicable and which are specific to this codebase.

Detailed Documentation

For full explanations of any topic, see the docs:

TopicPage
What is MVT?learn/what-is-mvt.md
Architecture overviewlearn/architecture-overview.md
Modelslearn/models.md
Viewslearn/views.md
The tickerlearn/ticker.md
Bindingslearn/bindings.md
Time managementguide/time-management.md
Bindings in depthguide/bindings-in-depth.md
Change detectionguide/change-detection.md
Model compositionguide/model-composition.md
View compositionguide/view-composition.md
Presentation stateguide/presentation-state.md
Hot pathsguide/hot-paths.md
Testingguide/testing.md
Adding a gameguide/adding-a-game.md
Common mistakesguide/common-mistakes.md
Architecture rulesreference/architecture-rules.md
Style guidereference/style-guide.md
Project structurereference/project-structure.md
Glossaryreference/glossary.md
Proven patternsfoundations/proven-patterns.md
Contributingcontributing.md