Block World
Build and explore an endless 3D world of blocks, Minecraft-style
- Token useHigh
- Estimatemore than 250k
- Category🎲 Fun & Games
- Version1.0.0
About
A 3D sandbox game in the spirit of Minecraft. Walk or fly across an endless world of hills, forests, beaches, deserts and snowy peaks, break blocks and build anything you like with sixteen kinds of block. It runs in your web browser, saves your worlds on your computer, and needs no account or download.
What you get
A 3D building game that runs in your web browser. One file, works offline, no account, no ads.
What you need
- An AI coding agent that can create and run files (Claude Code, Codex, Cursor or similar)
- A computer with a keyboard and mouse, and a modern browser (Chrome, Edge, Firefox or Safari)
Token use
High: more than 250k tokens.
Tokens are how AI assistants measure work. More tokens means a longer build and more of your plan's usage limit, or a higher bill if you pay per use.
Version history
- 1.0.0Current 20 Oct 2026 First release
See the recipe This is what your AI reads. You don't need to.
Goal
Build Block World, a first-person 3D block-building sandbox (creative mode) in the spirit of Minecraft, as a single web page that opens by double-clicking. The world is made of 1×1×1 blocks, goes on forever in every direction, and is generated from a seed, so the same seed always gives the same world. The player walks, jumps, flies, breaks blocks and places them. Every change is saved.
It must look good and run smoothly (60 fps on an ordinary laptop) without any libraries. Use raw WebGL2. The rendering approach below is the standard, proven one; follow it.
Before you start, ask the person
- Who is it for? A child (gentler defaults: slower mouse, flying allowed from the start) or a grown-up. (Default: anyone, normal defaults.)
- A name for the game shown on the title screen. (Default: “Block World”.)
- Should the day turn into night? (Default: yes, a 20-minute day–night cycle that can be turned off in settings.)
Features
- Title screen: a list of saved worlds (name, last played) with Play and Delete (delete asks for confirmation), plus Create world: name, optional seed (text or number; blank picks a random one) and world type Normal or Flat (bedrock, 3 dirt, grass on top at height 4, no trees, no water).
- Endless terrain (Normal worlds), generated per chunk from the seed with these rules:
- Seed: hash the seed text to a 32-bit integer (for example cyrb53 or FNV-1a), and use it to seed a small PRNG (mulberry32) that builds the permutation tables for 2D simplex or gradient noise. Write the noise yourself. Use no
Math.random()anywhere in world generation. - Height:
h = 30 + 10·fbm(x/200, z/200, 4 octaves). Mountains:m = fbm(x/400, z/400); wherem > 0.3, add(m − 0.3)·60. Round to an integer and clamp to 4–60. Sea level is 28. - Biomes from temperature
t = noise(x/600, z/600)and moistureu = noise((x+5000)/500, (z+5000)/500): desert wheret > 0.45, snowy wheret < −0.45or the surface is above 48, forest whereu > 0.2, otherwise plains. - Columns: y = 0 bedrock; stone up to
h − 4; dirt up toh − 1; top block grass (sand in deserts and whereverh ≤ 29; snow in snowy areas). Fill air with water fromh + 1up to 28. - Trees: decide per world column with a hash of
(x, z, seed): forest 4 %, plains 0.5 %, only on grass. A tree is a 4–6 block log trunk with a leaf blob of radius 2 around the top. Deserts get 1–3 block cacti (0.6 %) on sand. To keep trees whole across chunk borders, also evaluate tree columns up to 2 blocks outside the chunk and write only the blocks that fall inside it.
- Seed: hash the seed text to a 32-bit integer (for example cyrb53 or FNV-1a), and use it to seed a small PRNG (mulberry32) that builds the permutation tables for 2D simplex or gradient noise. Write the noise yourself. Use no
- Blocks (ids in brackets): air [0], bedrock [1], stone [2], dirt [3], grass [4], sand [5], water [6], log [7], leaves [8], planks [9], cobblestone [10], glass [11], bricks [12], snow [13], cactus [14], white cloth [15], red cloth [16], yellow cloth [17], blue cloth [18]. Grass, logs and cactus have different top, side and bottom faces.
- Textures: draw every 16×16 texture in code on a canvas at startup (no image files). Give them a pixel-art look with seeded per-pixel noise: green speckled grass top; grass side as dirt with a ragged green fringe on the top 3–4 rows; grey stone; blobby cobblestone; planks with horizontal seams; bricks; glass as a light frame with a clear centre; leaves with about 20 % fully transparent pixels; water blue with alpha about 0.7.
- Controls: click to lock the mouse (Pointer Lock). Mouse looks around; W A S D move; Space jumps; double-tap Space (within 300 ms) toggles flying; while flying Space rises and Shift sinks; Ctrl or double-tap W sprints. Left click breaks, right click places, middle click picks the block you are looking at into the hotbar. 1–9 and the mouse wheel choose a hotbar slot. E opens the block picker (all blocks except air and bedrock; click one to put it in the selected slot). F3 toggles a debug overlay. Esc pauses.
- Player physics: box 0.6 wide and 1.8 tall, eyes at 1.62. Gravity 32 blocks/s², jump speed 9 blocks/s (jumps just over 1 block high, never 2), walk 4.3 blocks/s, sprint 5.6, fly 10.9. Resolve collisions one axis at a time (Y first, then X, then Z) against solid blocks; water, air and anything above the world top are not solid. In water, fall slowly (max 2 blocks/s down) and Space swims up at 3 blocks/s. No auto step-up. If the player falls below y = −10, put them back at spawn.
- Breaking and placing: a voxel ray cast (Amanatides & Woo DDA) from the eye, reach 5 blocks, that ignores air and water. Draw a thin dark outline around the targeted block. Breaking removes the block instantly, except bedrock, which can’t be broken. Placing puts the selected block against the hit face. Refuse a placement that would overlap the player’s box, or that is outside y 0–63. Placing into water replaces the water.
- Look:
- Light each face by direction (top 1.0, north and south 0.8, east and west 0.65, bottom 0.5).
- Add per-vertex ambient occlusion (the classic “side1, side2, corner” method with 4 brightness levels 0.5 / 0.7 / 0.85 / 1.0), and flip the quad’s triangle diagonal when
ao0 + ao2 < ao1 + ao3so the shading has no seams. - Add distance fog that fades into the sky colour at the edge of the render distance.
- Underwater, tint the view blue and pull the fog in close.
- With the day–night cycle on, the sky colour and a light multiplier (night 0.25, day 1.0) change smoothly over 20 minutes, starting at morning.
- HUD: crosshair, hotbar with block icons (render each icon as a little isometric cube from its textures), and the selected block’s name shown briefly when it changes. The debug overlay shows fps, position, chunk, facing direction, targeted block and the number of loaded chunks.
- Pause menu: Resume, Settings, Save and quit to title. Settings: render distance 3–10 chunks (default 6), mouse sensitivity, invert Y, field of view 60–100 (default 75), day–night cycle on/off, sound on/off. Settings are saved.
- Sounds: short soft sounds for break, place and footsteps, made with the Web Audio API from filtered noise. No audio files.
- Saving: worlds are saved automatically every 10 seconds, when pausing, and when the page closes. Save only what differs from the generated world (see Constraints), plus the player position and look direction, flying state, hotbar and time of day. Reopening a world puts you exactly where you left.
Constraints
- One self-contained
index.htmlwith inline CSS and JavaScript: no libraries, no CDN, no external requests, no build step. It works offline when opened from the file system. - Use original names, textures and sounds. Don’t copy textures, sounds or names from Minecraft or any other game.
- Rendering (WebGL2):
- Chunks are 16 × 16 × 64 blocks, stored as a
Uint8Arraywith indexx + z*16 + y*256. - Mesh each chunk by emitting only faces next to air or to a transparent block of a different type (so water next to water and glass next to glass make no faces).
- Put the textures in a
TEXTURE_2D_ARRAY(one 16×16 layer per texture,NEARESTmagnification, mipmaps withNEAREST_MIPMAP_LINEAR). An array texture avoids the bleeding lines a texture atlas gives. - Draw in two passes. Opaque pass: all solid blocks plus leaves and glass, with alpha-tested pixels discarded in the shader. Then water in a translucent pass with depth writes off and blending on, with chunks drawn far to near.
- Use one vertex array per chunk per pass. Skip chunks outside the view frustum.
- Chunks are 16 × 16 × 64 blocks, stored as a
- Loading:
- A chunk’s block data is generated before it is meshed, and a chunk is only meshed once all four of its neighbours have block data, so there are no holes or extra faces along chunk borders.
- Generate and mesh nearest-first within a time budget of about 4 ms per frame, so walking never stutters.
- Unload chunks more than render distance + 2 away (their edits stay in the save).
- When a block on a chunk edge changes, remesh the neighbouring chunk too.
- Spawn: at x = 0, z = 0, standing on the top block. If that column is water, search outward in a spiral for the nearest land column.
- Save data in
localStorageunderblock-world-v1, with aschemaVersion. Edits are stored per chunk as{"cx,cz": {index: blockId}}, with the last write winning. If saving hits the storage limit, show a friendly message instead of failing silently. - Cap the canvas pixel ratio at 2. Pause when the mouse lock is lost (Esc or switching windows).
- Put world generation, noise, the ray cast and the collision code in a
<script id="core">block that uses no DOM, so they can be tested withnode. - Expose
window.gamefor testing:getBlock(x, y, z),setBlock(x, y, z, id),teleport(x, y, z),player(position, velocity, onGround, flying) andfps.
Build steps
- Core in node: seeded noise,
generateChunk(seed, cx, cz), the DDA ray cast and the AABB collision step. Test them before writing any graphics. - WebGL2 setup, the texture array from code-drawn textures, and one meshed chunk on screen with a free-fly camera.
- The chunk manager: nearest-first loading within the frame budget, neighbour-gated meshing, unloading, and frustum culling.
- Player physics, Pointer Lock controls and flying.
- Ray cast, outline, break, place and pick, with neighbour remeshing.
- Ambient occlusion, face lighting, fog, water pass, underwater tint and the day–night cycle.
- HUD, hotbar icons, block picker, debug overlay, pause menu and settings.
- Saving, the world list, Flat worlds, sounds and polish.
Acceptance checks
- Determinism (node): generating chunk (0, 0) and chunk (−3, 7) twice with the same seed gives identical arrays; a different seed gives a different chunk (0, 0).
- Terrain (node): across the 21 × 21 chunks around the origin, every column has bedrock at y = 0, no column is taller than 63, every water block sits at or below y = 28 with nothing but water or air above it up to sea level, and no tree is cut off at a chunk border (compare blocks across borders).
- Ray cast (node): in a test world with a stone column at x = 0, z = 0 whose top is y = 40, looking straight down from (0.5, 70.5, 0.5) finds nothing (out of reach), and from (0.5, 42.1, 0.5) it hits (0, 40, 0) on the top face. A ray through water hits the block under the water.
- Physics (node): standing on flat ground and jumping, the highest point of the feet is between 1.1 and 1.4 blocks up. Walking into a 1-block wall stops the player, jumping onto it works, and a 2-block wall can’t be climbed. The player never ends up inside a solid block, even at 15 blocks/s falling speed.
- In the browser: no console errors, and no cracks, missing faces or flickering lines along chunk borders. Leaves and glass show the blocks behind them, and water is see-through.
- Break a block, place a different one, reload the page: both changes are still there. Placing a block where the player stands is refused.
- Teleport 2,000 blocks away: new terrain streams in nearest-first, and over 30 seconds of flying in one direction no frame takes longer than 100 ms. With render distance 6, the fps shown in the overlay stays at or near the display’s refresh rate on a normal laptop.
- The day–night cycle changes the sky, fog and light together, and turning it off in settings stops it.
Hand-off to the person
Tell them where index.html is and to double-click it (Chrome or Edge works best). Give them the controls in a short table, including double-tapping Space to fly and E for the block picker. Explain that worlds are saved in this browser on this computer only: clearing browser data deletes them, and a different browser won’t see them. Tell them that typing the same seed when creating a world makes the same landscape, so they can share good seeds with friends. If it runs slowly, lower the render distance in Settings.