A cheerful snowman shredding mountain snow powder in a playful Three.js animation. ⛄️🎿
snowglider_with_audio_compressed.mp4
SnowGlider is a Three.js-based skiing game featuring a snowman gliding down a procedurally generated mountain. The game includes realistic physics, terrain generation, tree obstacles, and specialized camera tracking.
- Smooth snowman skiing with realistic physics and terrain interaction
- Procedurally generated backcountry mountain terrain with natural features
- Tree and exposed-rock obstacle detection with collision physics
- Avalanche system - triggered when player travels far enough downhill, with tumbling snow boulders that can bury the player (game over)
- Snow particle effects that respond to speed and turning
- Cinematic intro fly-over of the mountain at game start (skippable)
- Tracking camera that follows the snowman's movements
- Background music (simplified native HTML5 audio; see the audio history in
CHANGELOG.md) - Timer with best time tracking
- In-game feedback form — send a feature request or bug report straight from the start screen; it opens a prefilled GitHub issue (you submit under your own account) and logs an anonymous Firebase Analytics event
- Comprehensive test suite for verifying game mechanics
ROADMAP.md tracks the feature roadmap and gap analysis — a phased P0–P3 plan mapped to the open GitHub issues. The P0 "skill & structure" layer (checkpoint gates + finish line, split timing, a result screen, ghost racing, an avalanche warning UI, and a first ski-technique pass) shipped in #56; see CHANGELOG.md for that work.
ARCHITECTURE.md— module system, load order, the per-frame game loop, and the Firebase/scoring subsystemPHYSICS.md— terrain, skiing, jumps, collisions, and the avalanche model, with a constants referenceCHANGELOG.md— notable changes, including the skill/structure layer (#56) and the full audio historytests/README.md— test types, commands, and the verification harnessTROUBLESHOOTING.md— diagnostics, debug overlays, and logging for local/production issuesROADMAP.md— feature roadmap and gap analysis (incl. the now-shipped R2/R3 refactor stages)
The TypeScript/ES-module migration and the three.js r134→0.184 upgrade are complete; the current module architecture lives in
ARCHITECTURE.md.
index.html/auth.html- Entry points (load the Vite bundlesrc/main.ts)styles/- Page-level CSS for the static site shellsrc/- Application TypeScript ES modules, bundled by Vite (game loop, terrain, snowman + physics, camera, controls, audio, auth, scores, UI). SeeARCHITECTURE.mdfor the full, maintained module map.src/boot/- Classic-script auth fallback + Firebase bootstrap + startup driverassets/- Media (audio, video) tracked with Git LFStests/,tests/verification/- Node/browser/e2e suites and headless harnessesdocs/-ARCHITECTURE.md,PHYSICS.md,CHANGELOG.md,ROADMAP.md,TROUBLESHOOTING.md(see Documentation)
- Arrow Keys / WASD: Control snowman direction
- Left Arrow / A: Turn left
- Right Arrow / D: Turn right
- Up Arrow / W: Increase speed
- Down Arrow / S: Slow down
- Space: Jump over obstacles
- V: Toggle camera view
- Reset Button: Start a new run
Steering isn't just turning — how you work the edges changes your speed (see PHYSICS.md §3 for the model):
- Parallel turn (skidded): the default steered turn — quick or abrupt steering brushes the skis sideways, scrubbing speed for a tighter turn. Your speed-control tool.
- Carve: hold a smooth, committed turn (←/→ steadily in one direction) and the skis roll onto their edges while the snowman leans hard into the arc — holding your speed through a wide line. The mastery turn above a parallel (it commits over ~0.4 s).
- Snowplow / "pizza": hold Brake (↓/S) to wedge the ski tips together (tails apart) and scrub speed or stop.
- Tuck: hold Accelerate (↑/W) with no steering to straight-line for maximum speed.
- Hop turn: Jump (Space) while steering (←/→) for a quick edge-set pivot on tight, steep terrain.
- Left Side of Screen: Turn left
- Right Side of Screen: Turn right
- Top of Screen: Increase speed
- Bottom of Screen: Slow down
- Center of Screen: Jump
- Camera Toggle Button: Switch camera view
- Audio Button: Toggle music on/off
- Reset Button: Start a new run
The game automatically detects mobile devices and enables touch controls with visual indicators for easier gameplay.
Run the Node suite with npm test; in-browser suites load via ?test=… URL parameters. See tests/README.md for the full test matrix, the browser parameters, the verification harness, and per-suite details.
Coverage is reported to Codecov against the entire src/ tree and is
intentionally non-gating in CI. It combines two passes: npm run test:coverage
measures the Node + verification suites with c8 (--all --src src), and the
browser suite collects Chromium V8 coverage that is mapped back to src/*.ts and
line-merged into the same coverage/lcov.info. Run the whole pipeline locally
with npm run test:coverage:all. Browser-only modules are therefore counted, not
shown as 0%; remaining gaps reflect untested code rather than uninstrumented
files.
Prerequisite: Node.js 22+ (matches CI). The Node test suite runs the TypeScript sources directly through Node's native type stripping, which requires Node 22 or newer.
- Clone the repository
- Install dependencies with
npm ci - Run locally using one of these options:
- Option 1:
npm run dev— Vite dev server (full features) - Option 2:
npm start— the same Vite dev server, pinned to port 8080 (full features) - Direct
file://opens are not supported after the ES-module migration.
- Option 1:
- Before pushing, run the same checks CI does:
npm run lint,npm run typecheck,npm test, andnpm run build.
-
Server mode (
npm run devornpm start):- Runs on
localhostwith HTTP protocol - Firebase Authentication works, but Firestore service is automatically disabled to prevent connection errors
- A "Local Dev Mode: Firestore disabled" indicator will be displayed in the bottom-right corner
- Best times are stored in localStorage and can be synced to Firebase when online
- Runs on
-
Direct browser mode (opening
index.htmldirectly):- Not supported. Browser module graphs and the import map do not load reliably from a
file://origin. - Use
npm run dev,npm start, ornpm run buildplus a static server.
- Not supported. Browser module graphs and the import map do not load reliably from a
- Create a Firebase project at console.firebase.google.com
- Enable the sign-in providers you want in the Firebase console. SnowGlider wires
buttons for Google, GitHub, Apple, and Anonymous ("Play as Guest"):
- Google / Anonymous — enable in Authentication → Sign-in method (no extra setup).
- GitHub — register a GitHub OAuth app and paste its client ID/secret into Firebase.
- Apple — requires a paid Apple Developer account and an Apple Service ID.
A provider button whose backend isn't enabled simply errors on click;
auth.tsskips any button absent from the DOM, so you can ship buttons incrementally. Guests are anonymous: their best time stays local and is backfilled to the leaderboard only if they later upgrade to a real provider (same uid, via account linking).
- Create a Firestore database in the Firebase console
- Register your web app in Firebase to get configuration keys
- Update the Firebase configuration in
src/boot/firebase-bootstrap.js:
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_PROJECT_ID.firebaseapp.com",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_PROJECT_ID.appspot.com",
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID",
measurementId: "YOUR_MEASUREMENT_ID"
};The application uses the following Firestore collections:
users- User profiles and best timesleaderboard- Global leaderboard entries
Firestore Security Rules are tracked in firestore.rules. Run
npm run test:firebase to validate the rules against the Firebase emulator
(requires a local Java runtime).
- Push your changes to GitHub repository
- Enable GitHub Pages in repository settings
- Make sure to add your GitHub Pages domain to the authorized domains in Firebase Authentication settings
- The CI workflow runs tests, builds the Vite static artifact with
npm run build, and deploysdist/to GitHub Pages after the test job succeeds - Your game will be accessible at
https://[your-username].github.io/[repo-name]/
Diagnostics, debug overlays (e.g. ?debug=auth), and logging guidance for
Firebase connection issues, mobile authentication, CORS, and GitHub Pages
deployment now live in docs/TROUBLESHOOTING.md.