Vimazing is a browser game where you move a hero through a maze using pure vim motions. It supports numeric counts (e.g. 10j), line anchors (^, $), relative line/column numbers, and a score system tuned for both step-optimal routes and raw speed.
- Vim motions:
h j k l(+ uppercase) with counts:12j,3k, etc. - Hard “all-or-nothing” moves: counted/anchor moves must be fully traversable or they fail (no partial).
- Anchors:
^— jump to the start of the current corridor only if the path to the left border is clear.$— jump to the end (right border) only if the path is clear.
- Relative numbering: vim-style row/column numbers around the board; current line/column highlighted.
- Fast multi-step animation (visual only; scoring uses logic-time).
- Scoring built for speedruns:
- 100/100 at par time → 10,000
- Faster 100/100 → asymptotes to 50,000
- Fewer-than-optimal steps + speed → asymptotes to 100,000
See the full math in SCORING.MD.
- Online status (WebSocket ping + user count).
- Deterministic maze internals; consistent DOM mapping with
data-r/data-cattributes. - Accessible defaults: rem-based sizing and high-contrast theme.
- Press
ito start a new run. - Move with
h j k l. - Use numeric counts:
10j,3l, etc. If any tile in the path is blocked, the move is invalid (hero doesn’t move). - Anchors:
^to the left border,$to the right border — only if the corridor is clear end-to-end. - Press
Escto leave a run. - Numbers around the maze are relative to your hero’s position; the active row/column is highlighted.
- Par time =
optimalSteps × 250ms. - 10,000 for 100/100 at par.
- Up to 50,000 for 100/100 faster-than-par (saturating curve).
- Up to 100,000 (asymptotic) for routes that use fewer steps than optimal and are fast.
- Scoring uses logic time (timestamps on accepted moves), not animation duration.
Full details & formulas: SCORING.MD
Prereqs: Bun (v1+). Install from https://bun.sh
# install deps
bun install
# dev server (vimaze)
bun run dev:vimaze
# dev server (API)
bun run dev:api
# build
bun run build:vimazeOpen the dev server URL that Vite prints (usually http://localhost:5173).
Note: This is now a monorepo. See WORKSPACES.md for architecture details.
- Maze size: URL query params (user-facing counts, not internal grid):
?cols=64&rows=48→ renders the same maze as the old 32×24 internal grid, with vim-style numbering around.
- Cell & font size:
src/App.css:root { --cell-size: 24px; /* maze cell & number cell size */ --number-font-size: 10px; /* digits around the maze */ }
- WebSocket server: set
VITE_WS_URL(defaults tows://localhost:9000).
This is a monorepo with multiple apps and servers:
- apps/vimaze – The maze game (React + Vite)
- servers/api – WebSocket multiplayer server (Bun + Hono)
- workspaces/types – Shared TypeScript types
apps/vimaze/src/lib/MazeBuilder.ts– maze generation, DOM rendering, shortest paths, helpers.apps/vimaze/src/hooks/useGame/*– orchestration (maze, player, status, hero render, keybindings).apps/vimaze/src/hooks/useKeyBindings.ts– vim motions, numeric counts, and key logging.apps/vimaze/src/hooks/useGame/usePlayer.ts– movement logic, all-or-nothing counted moves, anchors (^,$), fast RAF animation, DOM effects (trail).apps/vimaze/src/hooks/useScore/*– timer, optimal distances, logic-time, player step counting, final score.apps/vimaze/src/App.tsx– UI composition (scoreboard, multiplayer status, overlay).
See WORKSPACES.md for full architecture documentation.
- Invalid move feedback: a red “mist” class is applied around the hero for failed moves.
- Logic time: emitted via a
maze-logic-tickCustomEvent; all scoring uses these timestamps. - Player steps: counted from position deltas, so counted motions & animations are measured correctly.
- DOM mapping: cells are addressable via
.maze-row > div[data-r="{row}"][data-c="{col}"].
- More vim motions (e.g. word-wise,
gg/G,[{/}]style corridor jumps). - Seeded mazes & weekly challenges.
- Ghost replays & leaderboards.
- Audio ticks / haptic feedback (optional).
- Accessibility & mobile touch helpers.
- The Art of Web and their Random maze generator
MIT © You can do whatever the heck you want with this.
PRs and ideas are welcome!
File an issue, or open a discussion with suggestions for motions, scoring, or UI.
- make a pull request with a screenrecording (GIF) of your best run and we'll feature it here
