A multi-game arcade platform with 52 playable games built with TypeScript and HTML5 Canvas (Vite).
Follow the step-by-step tutorial series to build all 50 games from scratch โ ordered from beginner to advanced. Perfect for YouTube content creators and learners.
Browse the concept reference for standalone explainers on every math, algorithm, physics, and design pattern concept used.
pnpm install
pnpm dev # http://localhost:3000
pnpm build # production build| Game | Description | Tutorial | Key Concepts |
|---|---|---|---|
| Tower Defense | Place towers, survive enemy waves | Tutorial (8 steps) | Economy, Wave System |
| Platformer | Jump, collect coins, stomp enemies | Tutorial (7 steps) | Camera, Gravity |
| Top-Down Shooter | WASD + mouse aim, wave survival | Tutorial (6 steps) | Trigonometry, Particles |
| Zombie Survival | Day/night cycle, barricades, ammo | Tutorial (7 steps) | Day/Night, Fog of War |
| Racing | Top-down track with AI opponents | Tutorial (7 steps) | Friction, Momentum |
| Fruit Ninja | Slice flying fruit, avoid bombs | Tutorial (5 steps) | Line Intersection, Quadratic |
| Lava Floor | Platforms sink into lava | Tutorial (5 steps) | One-Way Platforms |
| Basketball | Drag to aim, physics arc shooting | Tutorial (5 steps) | Projectile Motion, Parametric Equations |
| Golf | Top-down mini golf, 9 holes | Tutorial (6 steps) | Friction, Reflection |
| Game | Description | Tutorial | Key Concepts |
|---|---|---|---|
| City Builder | Manage population, food, power, happiness | Tutorial (6 steps) | Economy, Registry |
| Card Battle | Draw cards, defeat AI enemies | Tutorial (6 steps) | State Pattern |
| Ant Colony | Emergent ant simulation | Tutorial (6 steps) | Pheromones, Cellular Automata |
| Tic-Tac-Toe | Unbeatable minimax AI | Tutorial (5 steps) | Minimax |
| Connect Four | Drop discs, connect 4 vs AI | Tutorial (5 steps) | Minimax, Transparency |
| Chess | Full rules, castling, en passant, promotion UI | โ | Minimax, State Machines |
| Checkers | Forced captures, multi-jump chains, king promotion | โ | Minimax, Stack (Undo) |
| Game | Description | Tutorial | Key Concepts |
|---|---|---|---|
| Fishing | Cast, hook timing, reel tension | Tutorial (5 steps) | Weighted Random, Sine Wave |
| Idle Clicker | Click + buy upgrades, persistent | Tutorial (5 steps) | Exponential Growth, localStorage |
| Particle Sand | Sand/water/fire cellular automata | Tutorial (5 steps) | Cellular Automata, Image Data |
| Brick Builder | LEGO-like creative stacking | Tutorial (4 steps) | Responsive Canvas |
| Pixel Art | Draw pixel art with palette | Tutorial (4 steps) | Flood Fill, Coordinate Systems |
Learn the foundations behind every game. Each page has plain-English explanation, formulas, TypeScript code, and links to games where it's used.
| Category | Pages | Topics |
|---|---|---|
| Canvas API | 15 | Setup, Shapes, Arcs, Colors, Text, Transforms, Transparency, Glow, Clipping, Pixels, Rounded Rects, Animation, Coords, Layers, Responsive |
| Mathematics | 12 | Trig, Vectors, Distance, Lerp, Parametric, Reflection, Modular, Quadratic, Probability, Matrix Rotation, Exponential, Sine Wave |
| Algorithms | 15 | Flood Fill, Minimax, Backtracking, Maze Gen, Shuffle, AABB, Circle-Rect, Circle-Circle, Line-Segment, Pathfinding, Cellular Automata, State Machines, Delta Time, Weighted Random, Stack/Queue |
| Design Patterns | 9 | SOLID, Adapter, Observer, State, Factory, Strategy, ECS, Registry, Template Method |
| Physics | 9 | Gravity, Velocity, Friction, Momentum, Bounce, Terminal Velocity, Screen Wrap, One-Way Platforms, Projectile Motion |
| Game Systems | 10 | Waves, Economy, Combos, Levels, Camera, Particles, Day/Night, Fog of War, Pheromones, DAS |
| Engineering | 6 | Event Lifecycle, RAF Loop, localStorage, Path Aliases, Vite, Canvas API |
src/
โโโ main.ts # Platform entry point
โโโ platform/
โ โโโ GameRegistry.ts # Record<GameCategory, GameDefinition[]>
โ โโโ GameLauncher.ts # Create/destroy game instances
โ โโโ PlatformMenu.ts # Game selector with category tabs
โโโ shared/
โ โโโ GameInterface.ts # GameDefinition + GameInstance + GameHelp
โ โโโ HelpOverlay.ts # Shared in-game help renderer
โ โโโ Updatable.ts # System interface
โ โโโ Renderable.ts # Renderer interface
โ โโโ InputHandler.ts # Input handler interface
โโโ games/
โโโ <game-name>/ # Each game is self-contained
โโโ index.ts # GameDefinition export
โโโ types.ts # Game-specific types + constants
โโโ <Game>Engine.ts # Game loop orchestrator
โโโ adapters/
โ โโโ PlatformAdapter.ts
โโโ systems/ # Game logic (Updatable)
โโโ renderers/ # Drawing (Renderable)
โโโ data/ # Static data (levels, words, etc.)
mkdir -p src/games/my-game/{systems,renderers,adapters,data}// src/games/my-game/types.ts
export interface MyGameState {
score: number;
// ... your game state
}Each system implements Updatable<MyGameState>:
// src/games/my-game/systems/PhysicsSystem.ts
import type { Updatable } from '@shared/Updatable';
import type { MyGameState } from '../types';
export class PhysicsSystem implements Updatable<MyGameState> {
update(state: MyGameState, dt: number): void {
// game logic here
}
}Each renderer implements Renderable<MyGameState>:
// src/games/my-game/renderers/GameRenderer.ts
import type { Renderable } from '@shared/Renderable';
import type { MyGameState } from '../types';
export class GameRenderer implements Renderable<MyGameState> {
render(ctx: CanvasRenderingContext2D, state: MyGameState): void {
// draw here
}
}// src/games/my-game/systems/InputSystem.ts
import type { InputHandler } from '@shared/InputHandler';
export class InputSystem implements InputHandler {
attach(): void { /* add event listeners */ }
detach(): void { /* remove event listeners */ }
}Wire systems + renderers in a requestAnimationFrame loop.
// src/games/my-game/adapters/PlatformAdapter.ts
import type { GameInstance } from '@shared/GameInterface';
import { MyGameEngine } from '../MyGameEngine';
export class PlatformAdapter implements GameInstance {
private engine: MyGameEngine;
constructor(canvas: HTMLCanvasElement, onExit: () => void) {
this.engine = new MyGameEngine(canvas, onExit);
}
start(): void { this.engine.start(); }
destroy(): void { this.engine.destroy(); }
}// src/games/my-game/index.ts
import type { GameDefinition } from '@shared/GameInterface';
import { PlatformAdapter } from './adapters/PlatformAdapter';
export const MyGame: GameDefinition = {
id: 'my-game',
name: 'My Game',
description: 'Short description',
icon: '๐ฎ',
color: '#ff5722',
category: 'arcade', // arcade | action | puzzle | strategy | chill
help: {
goal: 'What the player needs to do.',
controls: [
{ key: 'Arrow Keys', action: 'Move' },
{ key: 'Space', action: 'Action' },
{ key: 'ESC', action: 'Exit to menu' },
],
tips: [
'Helpful tip for new players',
],
},
create(canvas, onExit) {
const inst = new PlatformAdapter(canvas, onExit);
inst.start();
return inst;
},
};// src/platform/GameRegistry.ts
import { MyGame } from '@games/my-game';
// Add to the appropriate category array:
export const GAME_REGISTRY: Record<GameCategory, GameDefinition[]> = {
arcade: [
// ...existing games
MyGame,
],
};- All event listeners removed in
destroy()/detach() - Uses
@shared/...path aliases (not relative../../shared/) - No constructor parameter properties (
erasableSyntaxOnly) -
helpfield with goal, controls, and tips -
categoryfield set -
ESCkey exits to platform menu -
npx tsc --noEmitpasses with zero errors
| Alias | Maps to |
|---|---|
@shared/* |
src/shared/* |
@platform/* |
src/platform/* |
@games/* |
src/games/* |
| Principle | Application |
|---|---|
| Single Responsibility | Each system/renderer does one thing |
| Open/Closed | New mechanics = new system files |
| Liskov Substitution | All games implement GameInstance |
| Interface Segregation | Updatable, Renderable, InputHandler |
| Dependency Inversion | Systems depend on state interfaces, not engine |
- Fork the repo
- Create a feature branch:
git checkout -b feat/my-new-game - Add your game following the steps above
- Ensure
npx tsc --noEmitandpnpm buildpass - Commit following the Commit Convention below
- Open a pull request
- One game per PR for clean review
- SOLID architecture โ separate systems, renderers, adapters
- Clean up listeners โ all event handlers must be removed on
destroy() - Help data required โ every game needs
goal,controls, andtips - No external dependencies โ pure TypeScript + Canvas API only
- Test locally โ run
pnpm dev, verify the game launches, plays, and exits cleanly
We use Conventional Commits. The release script auto-generates changelogs from these prefixes:
| Prefix | Category | When to use | Example |
|---|---|---|---|
feat: |
New Games & Features | New game, new platform feature, new tutorial | feat: add Chess game (#51) โ full rules, minimax AI |
fix: |
Bug Fixes | Bug fix, rule correction, UX fix | fix: first-row game cards not clickable |
perf: |
Performance | Optimization, code splitting, caching | perf: code-split all 52 games via dynamic import() |
docs: |
Documentation | Tutorials, README, concept pages | docs: write Tetris tutorial (Game 24) โ 7 steps |
refactor: |
Refactoring | Code restructure without behavior change | refactor: use Record for game registry |
chore: |
Other Changes | Config, tooling, CI, dependencies | chore: setup eslint, prettier, husky |
Format:
<prefix>: <short description> (under 72 chars)
Optional longer body explaining the "why" after a blank line.
Co-Authored-By: Name <email>
Branch naming:
feat/game-name # new game
fix/bug-description # bug fix
docs/tutorial-name # documentation
perf/optimization # performance
chore/config-change # tooling
See RELEASE.md for the full release workflow. Quick reference:
pnpm release:patch # 1.0.0 โ 1.0.1 (bug fixes)
pnpm release:minor # 1.0.0 โ 1.1.0 (new games/features)
pnpm release:major # 1.0.0 โ 2.0.0 (breaking changes)The release script auto-generates CHANGELOG.md with clickable commit hashes and author attribution from your commit messages.
- TypeScript โ strict mode, zero errors
- Vite โ dev server + production build
- HTML5 Canvas โ all rendering
- No frameworks โ pure vanilla TS
MIT