Skip to content
mohaneddzPublic

About

๐ ๐‘๐ฎ๐ง๐ง๐ž๐ซ is a deterministic browser auto runner with cube, ship and ball modes, a level editor, endless mode and in browser reinforcement learning (Q-learning and DQN). Next.js + TypeScript, no game engine; every level is solver verified in the build.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Latest commit

ย 

History

134 Commits

Folders and files

Repository files navigation

Q-Runner

Q-Runner

A deterministic browser auto-runner with cube, ship and ball modes, a level editor, an endless mode and in-browser reinforcement learning (tabular Q-learning and a DQN). No backend, no physics engine, no game framework โ€” the simulation is hand-rolled and runs entirely client-side.

Play it at q-runner.vercel.app.

Built with Next.js (App Router) + TypeScript, Zod for the level schema, Zustand for editor state, localForage for persistence, and a plain 2D canvas for rendering.

The idea

A fixed 120Hz simulation lives in one pure step function. The game loop, the training environment and a reachability solver all call that same function, which is what makes the central claim hold: a level cannot ship unless the solver has proved it clearable.

The solver is allowed to change its input only once every six ticks โ€” a 50ms grid. So "solvable" means solvable with roughly human timing slack, not frame-perfectly. pnpm build runs it over all ten built-in levels and fails the build on any rejection.

What's here

  • /levels โ€” the ten built-in levels plus anything you have built, with best progress and clear state per level.
  • /play โ€” the game. Hold to jump, fly or flip depending on the mode. You can also watch a scripted baseline bot, or watch the solver's own winning route replayed.
  • /editor โ€” pan/zoom canvas, place, erase, marquee multi-select, drag, snapping, undo/redo, an inspector for object and level settings, JSON import/export, and a Check button that runs the level through the same solver the built-in levels pass.
  • /endless โ€” stages generated on the fly and rejected unless the solver can still cross them. Difficulty and speed climb per stage. The next stage is built while you play the current one, and a run is reproducible from its seed (?seed=โ€ฆ).
  • /training โ€” an agent training against the same engine, with a learning curve, throughput and state-coverage metrics, and a viewer that runs the greedy policy. Pick tabular Q-learning over a discretised state, or a DQN (a small hand-written MLP with experience replay and a target network, no ML library). Agents are saved per level.

Game objects

Platforms (tile, span, block, floating, ceiling), spikes (single, double, triple, tall, mini, inverted), yellow and pink pads and orbs, cube/ship/ball portals, gravity portals, and a finish gate. Hazards use a hitbox smaller than the drawn spike so clipping a corner is survivable.

Setup

pnpm install
pnpm dev

Deploying

The live site is a Vercel project connected to this repo, so pushes to master deploy. Set NEXT_PUBLIC_SITE_URL to the deployment's origin (see .env.example): it is read at build time for canonical URLs, the sitemap, robots.txt and the social card, and falls back to http://localhost:3000 when unset.

Scripts

Command What it does
pnpm dev Dev server
pnpm build Validates every built-in level, then builds
pnpm check Typecheck, lint, tests, level validation
pnpm test 95 tests via node:test
pnpm validate:levels Solve every built-in level end to end
pnpm generate:levels Regenerate the ten built-in levels (deterministic per seed)
pnpm generate:icons Redraw favicons and the social card
pnpm preview [level] [ticksโ€ฆ] Render frames of a level to PNG via a headless canvas
pnpm benchmark:agents Train both agents on every built-in level and report how far each gets

pnpm preview replays a solved route and writes frames to previews/. It is a visual smoke test for the renderer that does not need a browser.

Level format

Levels are version-1 JSON validated by a Zod schema (src/game/level/levelSchema.ts), in world units rather than pixels โ€” the same unit the editor grid, the renderer and the solver all use. The ten built-in levels live in src/data/builtinLevels/ and are generated, not hand-placed: chunks are appended only if a beam of surviving states can still cross them.

Regenerating is deterministic. Object ids are positional and the authoring timestamp is pinned, so pnpm generate:levels twice produces byte-identical files.

Tests

pnpm test covers the simulation, the solver, generation, the editor store and the renderer. The one that matters most replays the solver's own winning route through the real GameEngine for each shipped level and asserts it finishes โ€” if the engine and the solver ever drift apart, "validated" quietly stops meaning anything.

How well the agents learn

pnpm benchmark:agents trains each agent from scratch on every built-in level, then runs its greedy policy (no exploration) once. Each agent gets the budget its epsilon schedule is tuned for: 1M steps for the Q-table, 200k for the DQN, whose exploration bottoms out near 100k. Exploration is random, so each pair ran three times; progress columns are medians.

Level Q-learning: best in training Q-learning: greedy Q-learning clears DQN: best in training DQN: greedy DQN clears
01 First Light 100% 100% 3/3 100% 18% 0/3
02 Static Drift 100% 45% 0/3 85% 33% 0/3
03 Overpass 100% 72% 1/3 10% 10% 0/3
04 Ion Wake 44% 18% 0/3 13% 9% 0/3
05 Crosswire 100% 77% 1/3 20% 19% 0/3
06 Nightfall 64% 16% 0/3 64% 17% 0/3
07 Rollcage 22% 20% 0/3 21% 19% 0/3
08 Inversion 87% 11% 0/3 47% 11% 0/3
09 Redline 99% 10% 0/3 33% 7% 0/3
10 Terminal Velocity 100% 100% 2/3 34% 8% 0/3

Run on 2026-10-23, about 30โ€“50s per training run on one CPU core.

  • The Q-table is the stronger agent here. Its greedy policy clears four of the ten levels at least once, including the last one. "Best in training" is often far above "greedy" because an exploring run can stumble through a section that the learned policy then fails.
  • The DQN never clears a level at these settings. Its network is tiny (16 hidden units), trains on a fifth of the steps, and was not tuned beyond keeping it stable. Read this as "the defaults are not enough", not as a ceiling for the method.
  • Clearing is not repeatable. The same agent and budget clear level 03 in one run out of three.

Known limitations

  • Progress and levels are per-browser. Everything is in IndexedDB via localForage. There is no account, no sync, and clearing site data loses saved levels.
  • Landscape only on mobile. The game is a 16:9 canvas and reads badly in portrait.
  • The trained agents are a demo, not a solver. Neither clears every level reliably (see How well the agents learn). The reachability solver is the thing that actually proves a level clearable.
  • Rotation is presentation-only. Objects can be rotated for looks; collision stays axis-aligned, which is what the solver assumes.
  • No music. There are sound effects for jump, death, orbs and portals; musicBpm is carried in the level format but nothing reads it yet.

About

๐ ๐‘๐ฎ๐ง๐ง๐ž๐ซ is a deterministic browser auto runner with cube, ship and ball modes, a level editor, endless mode and in browser reinforcement learning (Q-learning and DQN). Next.js + TypeScript, no game engine; every level is solver verified in the build.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages