A small browser arcade game built with TypeScript and Canvas 2D.
It is also a QA/SDET portfolio project focused on testable game rules, practical automation, and readable architecture.
Guide a survey craft vertically through a stream of incoming asteroids. Stay clear of collisions, let hazards pass safely, and keep the run going as the pace increases.
Astro Drift is intentionally small, frontend-only, and focused on one clear arcade loop. Its technical design keeps the gameplay rules readable and directly testable without adding unnecessary infrastructure or abstraction.
| Action | Control |
|---|---|
| Start or restart | Enter |
| Steer up | Arrow Up or W |
| Steer down | Arrow Down or S |
| Brake gameplay speed | Arrow Left or A |
| Boost gameplay speed | Arrow Right or D |
| Toggle the radio | R |
Avoid incoming asteroids and pass them safely to increase your score.
The session-local radio is enabled by default and shown by a small Canvas speaker icon. The procedural Late Library loop starts only from an eligible gameplay gesture and remains scheduled across rounds. It plays at the running level during gameplay, ducks during game over, and remains silent while idle.
- Standard and fiery asteroids create distinct hazards to dodge.
- Safely passed asteroids add to the score, while survival time is tracked separately.
- After a brief opening grace period, asteroids become faster and arrive more frequently.
- Asteroid positions are distributed more evenly across the play field to avoid repetitive patterns.
- Clear HUD, pass, collision, and game-state feedback keep the loop easy to read.
- A deterministic synthesized lo-fi track supports the loop without audio samples or assets.
- The best score is saved locally in the browser.
- Reduced-motion preferences quiet ambient star movement outside active play.
- Game, audio, and build: TypeScript, Canvas 2D, Tone.js, Vite
- Testing: Vitest,
fast-check, Playwright - Quality and automation: ESLint, GitHub Actions, GitHub Pages
Use Node.js 22 and npm.
git clone https://github.com/janmrow/astro-drift.git
cd astro-drift
npm ci
npm run devTo create and preview a production build:
npm run build
npm run preview| Command | Purpose |
|---|---|
npm run lint |
Lint the repository |
npm run typecheck:tests |
Type-check the test suite |
npm test |
Run unit and property-based tests |
npm run test:e2e |
Build the app and run Playwright browser tests |
npm run check |
Run the canonical full local quality gate |
The full gate covers ESLint, TypeScript checks for the tests and application, Vitest, a production build, and Playwright browser tests. The scripts in package.json are the executable source of truth.
On a fresh machine, install Playwright's Chromium browser before running browser tests:
npx playwright install chromiumBrowser-independent game rules and state updates live separately from Canvas rendering, procedural audio, keyboard input, storage, time, and other browser effects. src/main.ts connects that core to the browser shell and animation loop. src/audio/ owns the lazy Tone.js graph and page-lifetime music lifecycle; src/game/ has no audio dependency.
This boundary keeps important gameplay behavior directly testable without Canvas pixel assertions. The decision and its trade-offs are recorded in Architecture Decision: Separate Game Engine from Rendering.
src/game/ game rules and state updates
src/rendering/ Canvas 2D presentation
src/audio/ procedural music definition and browser-audio lifecycle
src/input/ keyboard input
src/storage/ browser persistence
src/main.ts browser shell and animation loop
tests/unit/ game rules and small boundary modules
tests/e2e/ main browser flows and contracts
docs/ architecture, testing, engineering, and visual decisions
- Unit tests cover gameplay rules, deterministic music invariants, and small boundary modules without requiring a browser.
- Property-based tests use
fast-checkto exercise meaningful invariants across generated inputs. - Playwright verifies important browser-level flows and stable DOM contracts.
- Manual browser checks cover Canvas presentation, gameplay feel, and audible music quality where pixel-, waveform-, or DSP-level automation would be brittle.
Canvas pixels and audio waveforms are not automated contracts. Rules and composition data are tested below the presentation layer, while browser tests observe stable page behavior. Late Library is synthesized at runtime with Tone.js and ships without sample files or other audio assets. See the Test Strategy for the detailed coverage boundaries and trade-offs.
- Architecture Decision: Separate Game Engine from Rendering — records the main responsibility boundary between gameplay rules and browser presentation.
- Engineering Principles — describes the code-quality and design principles used to keep the project small and readable.
- Test Strategy — documents test levels, coverage boundaries, quality gates, and deliberate trade-offs.
- Visual Style Constraints — records the technical constraints that visual changes must respect.
GitHub Actions runs the canonical npm run check gate for pull requests targeting main, pushes to main, and manual workflow runs. Deployment depends on that verification succeeding: verified main pushes and verified manual runs are built and deployed to GitHub Pages.
Astro Drift is available under the MIT License.
