{"id":52035929,"url":"https://github.com/tuanpham-dev/treasure-hunt","last_synced_at":"2026-08-01T19:30:23.169Z","repository":{"id":373089550,"uuid":"1311853330","full_name":"tuanpham-dev/treasure-hunt","owner":"tuanpham-dev","description":null,"archived":false,"fork":false,"pushed_at":"2026-07-25T09:48:53.000Z","size":247,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-25T11:08:04.732Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://tuanpham-dev.github.io/treasure-hunt/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tuanpham-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-25T09:33:18.000Z","updated_at":"2026-07-25T09:49:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tuanpham-dev/treasure-hunt","commit_stats":null,"previous_names":["tuanpham-dev/treasure-hunt"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/tuanpham-dev/treasure-hunt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuanpham-dev%2Ftreasure-hunt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuanpham-dev%2Ftreasure-hunt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuanpham-dev%2Ftreasure-hunt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuanpham-dev%2Ftreasure-hunt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tuanpham-dev","download_url":"https://codeload.github.com/tuanpham-dev/treasure-hunt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuanpham-dev%2Ftreasure-hunt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36168841,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-08-01T02:00:05.789Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-08-01T19:30:22.552Z","updated_at":"2026-08-01T19:30:23.094Z","avatar_url":"https://github.com/tuanpham-dev.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Treasure Hunt\n\nA maze game for kids learning to use a gamepad. Steer your character through the\nmaze, collect every treasure, and move on to the next of 30 levels.\n\nNo build step, no internet. Double-click `index.html` and play. (One vendored\nlibrary — Three.js, for the optional 3D mode — see \"2D and 3D\" below.)\n\n## How to play\n\n| Action | Gamepad | Keyboard | Touch |\n| --- | --- | --- | --- |\n| Move / menu navigate | D-pad or left stick | Arrow keys or WASD | On-screen D-pad |\n| Choose / confirm | A or Start | Enter or Space | Tap |\n| Back / home | B or Select | Esc | Home button |\n| Restart level | Y | (restart button) | Restart button |\n| Sound on/off | X | (sound button) | Sound button |\n\nThe whole game is fully playable with a gamepad alone — no mouse needed. The\nD-pad navigates every menu (characters, speed, 2D/3D, level select) and confirms\nwith A; in a level it moves the player, B returns home, Y restarts, X mutes.\n\nHold a direction to keep moving. Bumping into a wall is harmless — there is no\nway to lose, no timer, and no game over.\n\nOn phones and tablets an on-screen D-pad appears at the bottom of the game\nscreen. It shows only on touch devices that have **no gamepad connected** — plug\nin a controller and it disappears automatically; unplug it and it returns.\n\n## What's in the box\n\n- **6 characters**, each with its own treasure and colour scheme: Chomper (dots),\n  Cap Hero (mushrooms), Ice Princess (snowflakes), Kitty (fish), Puppy (bones),\n  Rocket (stars). Pick one on the start screen; it's remembered next time.\n- **3 movement speeds** (Slow / Normal / Fast) so the game can match a small\n  child's reaction time.\n- **30 levels**, growing from a 4×3 open yard with one treasure to a 12×9\n  labyrinth with 18. Progress, unlocked levels, chosen character, speed and the\n  mute setting are all saved in the browser.\n- All artwork is hand-drawn SVG defined in `js/sprites.js` — no image files and\n  no emoji, so it stays sharp at any size.\n- **2D or 3D**, switchable on the start screen (see below).\n\n## 2D and 3D\n\nA \"How do you want to see it?\" toggle on the start screen switches between the\nflat 2D board and a tilted-overhead 3D world; the choice is saved.\n\nBoth modes share one set of game rules. All logic — movement, wall collision,\nlevel flow — lives in `js/game.js`, which draws through a small renderer\ninterface implemented twice: `js/render2d.js` (DOM/CSS board) and\n`js/render3d.js` (Three.js scene). Because there is only one copy of the rules,\nthe two modes can't drift apart. The same six themes are reused in 3D by\nturning each character's SVG into a billboarded sprite — no extra artwork.\n\n3D uses **Three.js, vendored locally** at `js/vendor/three.min.js` (the r149 UMD\nglobal build). It's the one dependency, checked into the repo on purpose so the\ngame still runs from `file://` with no CDN and no build step. If a device has no\nWebGL, the game quietly falls back to 2D and shows a note by the toggle.\n\n## Every level is guaranteed completable\n\nLevels are built by a recursive-backtracker maze generator, which produces a\n*perfect maze*: every open tile is reachable from every other one. The optional\n\"braiding\" pass that opens up the easier levels only ever removes walls, so it\ncannot disconnect anything. Treasures are then placed only on tiles a\nbreadth-first search has already proven reachable from the player's start.\n\nThat's checked, not just claimed:\n\n```bash\nnode tools/validate-levels.js          # all 30 levels + a 1,200-maze stress sweep\nnode tools/validate-levels.js --print 7  # also draw level 7 as ASCII\n```\n\nThe script exits non-zero if any treasure is ever unreachable, sits inside a\nwall, or if any floor tile is walled off from the start.\n\nLevels are generated from a seed derived from the level number, so level 7 is\nalways the same maze for every player on every device.\n\n## Project layout\n\n```\nindex.html              page shell: start screen, level select, board, HUD\ncss/style.css           all styling, theme variables and animations\njs/sprites.js           SVG symbol sheet (+ standalone() for 3D textures)\njs/themes.js            theme + speed + render-mode data, start-screen pickers\njs/maze.js              PRNG, the 30-level table, generator, validator\njs/input.js             gamepad polling, keyboard, touch, hold-to-repeat\njs/audio.js             WebAudio sound effects (no audio files)\njs/game.js              game rules: movement, level flow, saving (renderer-agnostic)\njs/render2d.js          Renderer2D — the DOM/CSS board\njs/render3d.js          Renderer3D — the Three.js tilted-overhead board\njs/vendor/three.min.js  vendored Three.js r149 (UMD), only used by render3d.js\ntools/validate-levels.js  playability checker (Node)\n```\n\n## Adding things\n\n**A new character:** add two `\u003csymbol\u003e` drawings to the sheet in\n`js/sprites.js`, then add an entry to `THEMES` in `js/themes.js` pointing at\nthose symbol ids and giving it a palette. It appears on the start screen\nautomatically.\n\n**A new level:** append an entry to `LEVELS` in `js/maze.js` with `cols`, `rows`,\n`targets`, `braid` (0 = a tight maze, 1 = wide open) and a `name`. Run\n`node tools/validate-levels.js` afterwards; the HUD's \"/30\" count and the level\ngrid both follow the table's length.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuanpham-dev%2Ftreasure-hunt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftuanpham-dev%2Ftreasure-hunt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuanpham-dev%2Ftreasure-hunt/lists"}