A fully-featured 2D sandbox survival game — zero libraries, zero build steps, zero asset files. Just open a local server and play.
GoldCraft is a Terraria-inspired 2D tile sandbox built entirely from scratch in vanilla JavaScript and HTML Canvas. No game engine, no npm packages, no compile step — just raw browser APIs doing all the heavy lifting.
It started as a personal challenge: how much of a "real" game can you build before needing to reach for a framework? The answer turned out to be quite a lot. You get procedural terrain generation, a flood-fill lighting system, fluid physics, AI villagers, a full crafting tree, inventory with drag-and-drop armor slots, synthesized sound effects via Web Audio, and a particle system — all in a single folder you can serve with one terminal command.
The world is dark, the ores are deep, and the slimes come out at night. Good luck.
World & terrain
- Seeded procedural generation — hills, caves, ore veins, underground lava lakes, water pools, and pre-built plank villages
- 400 × 200 tile world stored in a flat
Uint8Array— fast and simple, no chunking needed at this scale - Ores: coal, iron, gold, diamond (rarer the deeper you go)
Lighting
- BFS flood-fill light map recalculated on every tile change
- Emissive sources: torches, lava, glowing ores each cast warm, coloured light
- Smooth day/night cycle — caves stay genuinely dark unless you bring a torch
Physics
- Pure AABB collision against the tile grid — no physics library
- Gravity, variable jump, acceleration-based movement, jump/land squash animation
- Liquid buoyancy and drag (water is swimmable, lava burns on contact)
- Fall damage that scales with extra height; landing in water cancels it
Crafting & progression
- You start with nothing — literally just your fists
- Full crafting tree from raw wood all the way to gold armor and diamond tools
- Station-gated recipes: some things need a workbench nearby, others need a furnace
- Smelting: ore + coal → ingots; sand → glass; wheat → bread
Inventory & items
- Drag-and-drop backpack with a 5-slot hotbar
- Dedicated armor slots (helmet, chest, greaves) that raise your
DEFstat - Dropped items fall into the world with gravity and magnetise toward you when you walk close
- Floating pickup text and damage numbers
Sound (no audio files!)
- Every sound effect is synthesized at runtime via the Web Audio API
- Mining pings, footstep thuds, splash sounds, sword swings — all procedural
Villagers
- Live in the generated houses and actually have needs
- Wander by day, return home at night, eat over time to refill their food bar
- Right-click to open their trade menu — swap your surplus ore or wood for gear, food, and torches
- They die permanently if they starve or fall into lava, so keep an eye on them
Combat & survival
- 10 hearts, health regenerates a few seconds after you stop taking damage
- Slimes spawn at night and knock you back on contact — swords hit hardest, but fists work
- Armor reduces incoming damage via the
DEFstat - Screen edges pulse red when you're low on health
Game feel
- Smoothing camera with look-ahead and screen shake on big hits
- Particle system: mining debris, landing dust, hit splatter, lava embers
- Parallax sky with drifting clouds and rolling mountains
- Equipped item rendered in the player's hand
Because the game uses ES modules, your browser will refuse to load it from a file:// URL. You need a local HTTP server — any of these one-liners will do:
# Python 3 (ships with most systems)
python -m http.server 8000
# Node.js
npx serve .
# PHP
php -S localhost:8000Then open http://localhost:8000 in a modern browser (Chrome, Firefox, Edge — anything from the last couple of years). That's it. No install, no build.
| Action | Input |
|---|---|
| Move | A / D — or ← / → |
| Jump / swim up | Space, W, or ↑ |
| Mine / attack | Hold Left Mouse |
| Place block / eat | Right Mouse |
| Trade with villager | Right Mouse on the villager |
| Select hotbar slot | 1–5 or scroll wheel |
| Inventory & crafting | E or C |
| Close any menu | E or Esc |
| Mute / unmute | M |
| Debug HUD | F3 |
| Save / Load | F5 / F9 |
The world auto-loads from your last save when you open the game. Press F5 to wipe and regenerate a fresh world if you want to start over (useful after updates that change the generator).
If you've never played this style of game before, here's the loop:
- Punch trees — yes, with your bare hands. Collect wood.
- Open inventory (
E) → craft4 Wood → Planks, then6 Planks → Workbench. - Place the workbench (right-click with it selected) and stand next to it. The crafting list will update with new recipes.
- Craft a Wood Pickaxe — now you can mine stone.
- Craft a Furnace (12 stone, at workbench) and place it.
- Mine coal and iron/gold ore underground. Smelt ore + coal → ingots at the furnace.
- Craft stone → iron → gold tools, swords, and armor. Make torches — caves are very dark.
- Dig deeper for diamond, lava lakes, and whatever the villagers want to trade.
The entire game is split into focused ES modules. There's no bundler — the browser loads them natively.
| Module | What it does |
|---|---|
config.js |
Every tunable constant: tile size, gravity, speeds, health values, damage numbers |
tiles.js |
Data-driven tile & item registries, hardness values, drop tables |
crafting.js |
Full recipe tree and craft/ingredient helpers |
trade.js |
Villager trade pool and trade execution logic |
world.js |
Tile grid storage, queries, and skylight column cache |
worldgen.js |
Seeded terrain, cave carving, ore vein placement, liquid pockets, village generation |
lighting.js |
BFS flood-fill light map with emissive source tracking |
particles.js |
Particle system and floating combat/pickup text |
sound.js |
Procedural Web Audio sound effects — no asset files |
physics.js |
Pure AABB-vs-grid collision with liquid buoyancy |
player.js |
Movement, jump, vitals, fall tracking, armor damage reduction |
inventory.js |
Backpack, hotbar, armor slots, held-stack drag logic |
drop.js |
Dropped-item entity with gravity and magnet pickup radius |
input.js |
Keyboard and mouse state, key and click edge events |
enemy.js |
Slime enemy — health, knockback, night spawning |
npc.js |
Villager AI — home-seeking, wandering, hunger, trade UI |
renderer.js |
Camera, tile culling, lighting composite, entity and UI rendering |
save.js |
Serialize/deserialize world, player, inventory, armor, and villagers to localStorage |
game.js |
Main loop and the wiring that connects every system |
The registries in tiles.js and crafting.js are intentionally data-driven so you don't have to touch the engine to add things:
- New block: add a
TILESentry (id, color, hardness, solid, optional flags likeneedsPick,emissive,ore), anITEMSentry, and aTILE_DROPSmapping. - New item / tool / weapon / armor / food: one
ITEMSentry with the rightkind, then aRECIPESline incrafting.js. - New trade good: add an entry to
TRADE_POOLintrade.js. - Tune feel or balance: all the physics and survival constants live in
config.js(MAX_HP,SAFE_FALL_TILES,LAVA_DPS,SLIME_TOUCH_DMG, …). - New entity: follow the pattern in
enemy.js— a body{x, y, vx, vy, w, h}passed tostepBody, update logic in the game loop, draw inrenderer.js.
- Liquids don't flow. Water and lava stay in the pockets the generator placed them in. It's on the list.
- Single save slot. The world is stored as JSON in
localStorage, with the tile grid base64-encoded. It's simple and it works for the scale of this project. - Save compatibility. Saves from older versions load fine, but the inventory field was added later — very old saves will start you with an empty backpack. Hit
F5to regenerate if you want a clean slate. - No mobile support. It's keyboard + mouse only right now.
This is a solo project and currently not accepting pull requests — but if you find a bug or have a clever idea, feel free to open an issue. I'd love to hear what people think.
MIT — do whatever you want with it, just don't pretend you wrote the whole thing from scratch. short term open source





