An interactive, gamified résumé. Roll a cube across a 3D tile grid (Three.js); a static HTML résumé generated from JSON serves as the no-JavaScript fallback.
Demo — Game · Static résumé
| Stack | Entry | Purpose |
|---|---|---|
| Game (primary) | index.html + src/ |
Three.js + TypeScript puzzle résumé, built with Vite. |
| Static fallback | assets/resume.html (generated) |
Generated from assets/resume.json by the Python builder; what recruiters land on without WebGL/JS. |
assets/resume.json is the single source of truth: the game's src/game/levels.json
references it with JSONPath ($…) strings, resolved at build time by the
resume-refs Vite plugin in vite.config.ts.
All static assets live in assets/ — the models (assets/models/), the avatar
(assets/harishankar.jpeg), and resume.json. It is Vite's publicDir, so it is served
in dev and copied into dist/ on build (no manual copy step in the workflow).
npm install
npm run dev # Vite dev server at http://localhost:5173
npm run build # tsc --noEmit + vite build → dist/ (game only)
npm run build:site # python3 build.py + npm run build → dist/ (game + static résumé)Deployment is manual: run npm run build:site to produce dist/ (the game
index.html and resume.html side by side, with models/, the avatar, and
resume.json alongside), then publish dist/ to your host. CI
(.github/workflows/ci.yml) runs the quality checks only; it does not deploy.
Source layout under src/:
core.ts— shared primitives: theDirectionandTileKindtypes,DIRECTION_DELTA, thenoise()hash, and thePALETTEcolour map.engine/— Three.js infrastructure:scene.ts(camera/lighting/renderer) andmodels.ts(OBJ/MTL loading).game/— gameplay:layout.ts(Three.js-free board parsing/validation),grid.ts(level + tile rules),player.ts(rolling cube),tile.ts,contact.ts,decoration.ts(animated tile overlays),effects.ts(projectiles/swirls).
pip3 install -r requirements.txt
python3 build.py # assets/resume.json + template.html → assets/resume.html- Content: edit
assets/resume.json(JSON Resume schema). - Design/layout: edit
template.html(Jinja2 template, CSS inlined). assets/resume.htmlis generated — do not edit by hand; regenerate withpython3 build.py.
The puzzle ladder is produced offline by the level-gen/ crate (solver + campaign +
curator) and wired into the game with level-gen/wire_ladder.py. See
level-gen/README.md for the workflow and
levels/README.md for the candidate → curated → wired lifecycle.
Quick reference for the three stacks:
# TypeScript game
npm run typecheck && npm test && npm run build
# Python builder
pip3 install -r requirements-dev.txt
ruff check . && ruff format --check . && pytest
# Rust level generator
cd level-gen && cargo fmt --check && cargo clippy --lib --bins --tests -- -D warnings && cargo testCI (.github/workflows/ci.yml) runs the same checks on every PR and push to master.