Game modules
A game module is a whole genre in one function. You call defineRaceGame, definePuzzleGame, defineShooterGame or defineKingdomGame with a config (numbers, colours, names, content tables) and get back a complete game: the rules, the scene, the controls, the HUD, the start and end screens, sounds where the module has them, and the dev self-play button. You write no game loop.
Use a module when your idea fits its genre. When it does not, build the game from the engine pieces instead (see When no module fits).
Module or engine piece
The engine is a set of pieces: a WebGPU canvas, touch controls, a character controller, a combat kit, bots, the 2D layer, saves, leaderboards and more. A game made from pieces writes its own loop in src/game/index.tsx and decides everything.
A module is built from those same pieces, with the loop already written. The difference is what you write:
| Engine pieces | A game module | |
|---|---|---|
| What you write | a React component with your own loop, rules, HUD and screens | one config object |
Size of src/game/index.tsx | hundreds of lines | 10 to 300 lines, mostly data |
| What you can change | anything | what the config exposes; more by editing the module's code |
| Where it lives | @/engine | @/engine/modules/<name> |
Modules are not re-exported from @/engine. Import each one from its own path:
import { defineRaceGame } from '@/engine/modules/racing';
The four modules
| Module | Genre | Entry function | What you supply | Example |
|---|---|---|---|---|
| Racing | 3D arcade car race on a closed track | defineRaceGame(config) | laps, a track preset or your own points, car tuning, number and pace of AI rivals, time of day and colours | Sunset Sprint, the starter game in src/game/index.tsx |
| Puzzle | 2D grid puzzle: block, merge, match or sort | definePuzzleGame(config) | the rule pack, endless or levels, a daily puzzle, board size, palette, optional tile and background painters | examples/moon-blocks/, examples/moonrise/, examples/gem-cascade/ |
| Shooter | 3D arena shooter with bots and multiplayer | defineShooterGame(config) | a mode (ffa, tdm, gun-game, ctf, koth), rules, a map preset, loadouts, seats and bots, items | examples/flag-rush/ |
| Kingdom | story-led town builder with joystick fights | defineKingdomGame(config) | resources, buildings, crops, units, hero classes, missions, the town layout and a story of chapters | examples/oath-of-ashvale/ |
Every entry function returns a GameDefinition (id, title, description, badge, accent, Component). Your src/game/index.tsx default-exports it, and the app renders its Component full screen. The rules for that file are on the game contract page.
// src/game/index.tsx
import { definePuzzleGame } from '@/engine/modules/puzzle';
export default definePuzzleGame({
id: 'moon-blocks',
title: 'Moon Blocks',
description: 'Drag blocks onto the board and clear lines under the moon.',
pack: 'block',
});
Every module fills defaults and clamps out-of-range numbers, so a config with a wrong value still plays. Stay inside the documented ranges anyway, so the game does what the config says.
How to choose
| Your idea | Pick |
|---|---|
| cars, laps, a circuit, drifting, a kart race | Racing |
| fill lines with blocks, slide and merge numbers, tap groups of a colour, swap three in a row, pour colours into tubes | Puzzle |
| guns, bots, deathmatch, teams, capture the flag, king of the hill, a weapon ladder, friends in the same match | Shooter |
| a village you build and grow, timers, crops, a hero who rides out to clear enemy camps, dialogue and chapters | Kingdom |
| anything else | the engine pieces, see below |
A few edge cases:
- A shooter rule none of the five modes covers (waves of enemies, bomb defusal, escort): use the combat kit directly, starting from
examples/pulse-arena/. - A puzzle mechanic beyond the four packs: either add a rule pack to the puzzle module (see Writing a module for the conventions) or draw the game yourself on the 2D layer.
- A town builder with no story and no fights: the kingdom module requires a story. Without one, use saves and progression with your own screens.
When no module fits
Compose the engine pieces in src/game/index.tsx. Start from the example closest to your idea and change it. The pieces you will most likely need:
| You need | Read |
|---|---|
| a 3D scene, lights and the frame loop | Canvas and rendering |
| a character that runs and jumps, cameras, levels | Character and cameras |
| weapons, health, hits | Combat |
| enemies that patrol, hear, see and chase | Bots |
| a flat game: tiles, sprites, taps, particles | 2D layer |
| turn-based board games with a computer opponent | Turns |
| dialogue, choices and objectives | Story |
| touch controls, a joystick, keys on the web | Input |
| a HUD, icons and fonts | HUD and UI |
| sounds and music | Audio |
| saved progress, currencies, unlocks | Saves |
| leaderboards, presence, multiplayer rooms | Networking |
If you find yourself building the same genre twice, it may be worth a module of its own: Writing a module.