Dragonbound is a single-screen survival shooter built with the Canvas API. The player rotates, moves in the direction they are facing, collects coins, and fires projectiles at incoming monsters while trying to survive long enough to improve their score.
The project began as a vanilla JavaScript bootcamp game and was later modernized incrementally into a cleaner TypeScript + Vite codebase while preserving the gameplay loop and improving maintainability.
- rotating hero with facing-direction movement
- directional shooting with rotated projectile rendering
- monsters that enter from all four canvas edges
- tuned hero/monster hitboxes for fairer collisions
- pause, restart, and game-over handling
- local high-score persistence with
localStorage - sound toggle
- runtime hitbox debug toggle
- GitHub Pages-compatible static build
| Area | Original Version | Current Version |
|---|---|---|
| Project Origin | Vanilla JavaScript bootcamp project | Incrementally modernized TypeScript project |
| Build Tooling | Legacy Webpack/bundle setup | Vite dev/build workflow |
| Source Layout | Legacy lib/-style structure |
Organized src/game, src/entities, and src/input layout |
| Typing | Untyped JavaScript | TypeScript across game logic and entities |
| Input | Scattered keyboard handling | Centralized InputController |
| Hero Movement | Simpler directional movement | Rotation + facing-direction movement |
| Shooting | Horizontal-only assumptions | Directional projectiles and muzzle-based spawn logic |
| Enemies | Horizontal-only entry paths | Multi-edge vector-based spawning |
| Collision | Full visual bounds | Tuned gameplay hitboxes |
| Persistence | None | local high-score persistence |
| Deployment | Manual/legacy setup | GitHub Pages via GitHub Actions |
- TypeScript
- Vite
- HTML5 Canvas API
- localStorage for local high-score persistence
- GitHub Actions for GitHub Pages deployment
Source code lives under src/:
src/
main.ts
game/
Game.ts
collision.ts
constants.ts
highScore.ts
hitbox.ts
vector.ts
entities/
Hero.ts
Laser.ts
Monster.ts
Coin.ts
input/
InputController.ts
High-level responsibilities:
src/main.ts: bootstraps the canvas and creates the gamesrc/game/Game.ts: orchestration, lifecycle, DOM wiring, score UI, audio, render loop, and cross-entity coordinationsrc/entities/*: entity-specific behavior such as movement, rendering, spawn helpers, and bounds cleanupsrc/game/collision.ts: hitbox resolution, overlap checks, and debug hitbox drawingsrc/game/vector.ts: shared vector math used by directional movement and aimingsrc/game/highScore.ts: local high-score persistence helperssrc/input/InputController.ts: centralized keyboard state and one-shot actions
A/Left Arrow: rotate leftD/Right Arrow: rotate rightW/Up Arrow: move forwardS/Down Arrow: move backwardSpace: shootP: pause
Install dependencies:
npm installRun the dev server:
npm run devTypecheck:
npm run typecheckPreview a production build locally:
npm run build
npm run previewProduction build:
npm run buildThe app is configured for GitHub Pages deployment and uses a production base path of /dragonbound/ in vite.config.ts.
GitHub Pages deployment is handled by:
.github/workflows/deploy-pages.yml
That workflow runs:
npm cinpm run typechecknpm run build- uploads
dist/ - deploys to GitHub Pages
To use it on GitHub:
- Push to the
masterbranch, or run the workflow manually. - In repository settings, configure Pages to deploy from GitHub Actions.
- If the repository name changes, update the base path in
vite.config.ts.
- add automated tests for pure utility modules and core gameplay regressions
- improve collision precision further with circular or rotated hitboxes
- add richer enemy wave design, spawn patterns, and difficulty balancing
- add collectible upgrades or temporary power-ups
- add a global leaderboard if a backend becomes worthwhile
- add more art/audio variety and a more polished start/game-over presentation
