Skip to content

MVT Games Documentation

Canvas and game applications tend to mix state, rendering, and timing into tangled code that is hard to test, debug, or extend. MVT (Model-View-Ticker) solves this by splitting applications into three strict layers, giving you deterministic models you can unit test, stateless views you can swap, and frame-consistent rendering across the board.

The Three Layers

  Ticker (frame loop)

    ├── 1. model.update(deltaMs)   ← Models advance state
    ├── 2. view.refresh()          ← Views read state, update presentation
    └── 3. renderer draws          ← Frame drawn to screen
LayerOwnsReceivesMust not touch
ModelState, domain logicdeltaMsViews, rendering, time
ViewPresentationBindings/modelDomain state, timers
TickerFrame loopAnimation frameDomain logic, rendering code

Choose Your Path

Learn MVT

New to the project? The learn path takes you from zero to working understanding in eight short pages:

  1. What is MVT? - The problem, the solution, the benefits
  2. Architecture Overview - The frame loop at a glance
  3. Models - State, update(deltaMs), determinism
  4. Views - Scene graph, refresh(), statelessness
  5. The Ticker - Wiring the loop
  6. Bindings - Connecting views to models
  7. Walkthrough - Annotated tour of the Asteroids module
  8. Next Steps - Where to go from here

Reference

Already familiar and need to look something up?

AI Agents

AI coding agents should start with AGENTS.md for compressed orientation.

Contributing

Adding to or maintaining these docs? See the Contributing Guide for page templates, section purposes, and style rules.

Design Philosophy

These guides are built around four principles:

  1. Separation of concerns - Models own state; views own presentation; the ticker owns time. No layer reaches into another. Public APIs are defined by interfaces, not implementation details.
  2. Testability by design - Models are deterministic (same update calls produce the same state). Views can be tested with mock bindings. Neither depends on the other.
  3. Explicit over implicit - Time flows through update(deltaMs), not hidden timers. Data flows through bindings, not global imports.
  4. Performance without obscurity - Hot-path rules exist to avoid per-tick waste, but clarity still matters. Optimise where it counts; keep everything else readable.