A polished, browser-playable remake of a MIPS Assembly Columns game
originally written for the MARS simulator (CSC258 final project). The original
columns.asm is the source of truth for gameplay, controls, timing, colors,
music, and game states. This project recreates all of it natively in
TypeScript. It is not a MARS emulator; the assembly was read and
re-implemented as idiomatic web code.
A 3-block column falls down a 6×17 well. Move it, soft-drop it, and cycle its colors to line up 3 or more of the same color horizontally, vertically, or diagonally. Matches clear, blocks above fall (gravity), and new matches can cascade. The drop speed ramps up over time. The game ends when the stack reaches the top row.
- Falling 3-block columns with a 5-deep next preview
- Left / right movement and soft drop
- Color cycling within the column (
[top, mid, bot] → [mid, bot, top]) - Collision detection, locking, and match detection in all four directions
- Match clearing → gravity → cascade resolution
- Speed progression (
interval = 20000 / speed_m10, +0.1× every 10 s, cap 3.0×) - Pause / resume and a Game Over → retry flow
- Looping background music + sound effects
- Score (a web-remake addition; the original assembly had no score system)
| Action | Keys |
|---|---|
| Move left | ← / A |
| Move right | → / D |
| Soft drop | ↓ / S (hold to keep dropping) |
| Cycle colors | ↑ / W / Space |
| Pause | P |
| Restart | R |
The original debounced every key (one action per press). Movement and rotation preserve that feel; soft drop additionally supports holding for a smoother game.
npm install
npm run dev # start the dev server (http://localhost:5173)npm run build # type-check + production build into dist/
npm run preview # preview the production build locallyRequires Node 18+.
The build emits relative asset URLs (base: "./" in vite.config.ts), so the
contents of dist/ can be hosted anywhere static.
- Vercel - import the repo; framework preset Vite. Build command
npm run build, output directorydist. - Netlify - build command
npm run build, publish directorydist. - GitHub Pages - run
npm run buildand publishdist/(e.g. via thepeaceiris/actions-gh-pagesaction orgh-pagespackage). Relative paths mean it works from a project subpath without further config.
| MARS / MIPS feature | Browser implementation |
|---|---|
Bitmap display @ 0x10008000 |
HTML Canvas grid (CanvasRenderer); each 8×8 VRAM block → one cell |
Keyboard mapping @ 0xffff0000 |
keydown / keyup events (InputManager) |
| Syscall 30 (time) | performance.now() |
| Syscall 32 (sleep ~16 ms) | requestAnimationFrame game loop |
| Syscall 42 (random) | Math.random() for piece/color generation |
| Syscall 31 (MIDI note) | Tone.js synths (AudioManager + music.ts) |
Audio only initializes after the first user interaction (Start button / key / mute), satisfying browser autoplay policies.
src/
main.ts # wiring, game loop, DOM/overlay sync
game/
Game.ts # state machine, timing, scoring
Board.ts # grid, collisions, match resolution
Piece.ts # piece + 5-deep preview queue, color cycling
matching.ts # 4-direction run scanning + gravity
constants.ts # geometry, colors, timing (from columns.asm)
types.ts # shared types
rendering/
CanvasRenderer.ts # board + preview drawing
input/
InputManager.ts # keyboard → actions
audio/
AudioManager.ts # Tone.js BGM + SFX
music.ts # BGM note/duration tables (from columns.asm)
styles.css
index.html
vite.config.ts- Geometry matches the original: 6 columns × 17 match rows, plus one spawn buffer row; columns spawn in the middle column with the top block just inside the top border.
- Colors are the exact
COLOR_TABLEvalues (red, orange, yellow, green, blue, purple) and theGREYframe color. - The background melody is the exact
BGM_PITCHES/BGM_DURStable (32 notes, 375 ms each), converted from MIDI note numbers to frequencies. - Scoring and held-soft-drop are clearly-marked additions; everything else follows the assembly behavior.