# Driftworld — a procedural 3D world you can share (★★★)

Build a 3D world explorer in the browser with Three.js. You type a seed, any word like `mossy-otter`, and the game grows a whole landscape from it: hills, lakes, beaches, snowy peaks and forests, going on as far as you walk. The same seed always makes the same world, so a seed is a world. The sun rises and sets. You can walk on the ground or fly. You can plant markers with short labels where you find something good. Save the world and you get a link: your friend opens it, gets the same land, your markers and a screenshot of the view you saved. As an optional extra, you can describe a world in words and a model on the server turns the description into settings for the generator.

## Done looks like

- A start screen with a seed box, a "Random seed" button and a list of saved worlds on this device.
- The terrain is made from seeded noise: same seed, same world, on any computer. A different seed is clearly a different place.
- The world is built in chunks around you, made as you move and thrown away when far behind, so you can walk for ten minutes without the frame rate dropping or memory climbing.
- Colours by height and slope: water, sand, grass, rock, snow. Trees placed by their own noise, not on steep slopes or under water.
- A day and night cycle of 10 minutes: the sun moves, light and sky colour change, fog thickens at dusk, stars come out at night. A time slider.
- Walk with WASD and mouse look on a laptop; on a phone, a left thumb joystick and drag on the right to look. F (or a button) toggles fly.
- Place a marker where you are looking, with a label up to 30 characters. Markers show as small flags with their label.
- Without any server, `?seed=mossy-otter` opens that world.
- "Save and share" stores the seed and markers in D1 and a screenshot in R2, and gives a link like `/?w=7fk2qd`. Opening it loads the same world, the markers and shows the screenshot first.
- 60 frames per second on a laptop, 30 or more on a mid-range phone.
- No console errors.

## Constraints

- Three.js from a pinned CDN address in an import map, for example `https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js` and add-ons from `https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/`. Never "latest". No other libraries, no build step.
- Seeded randomness: hash the seed string to a number, feed a small generator (for example mulberry32), and write the 2D noise function in the project. Never use `Math.random()` for anything that shapes the world.
- Chunks of 64 by 64 units. Trees as one `InstancedMesh` per chunk. Dispose geometry and materials of dropped chunks. Cap the pixel ratio at 2.
- Server only for saving: one Cloudflare Worker with static assets, a D1 binding and an R2 binding. Use wrangler. Free plan only. The game must still run with `?seed=` if the Worker is down.
- D1 table `worlds(id, seed, name, markers, created_at)` with `markers` as JSON text. R2 key `shots/<id>.jpg`.
- The Worker checks everything: seed up to 40 characters, name up to 40, at most 100 markers, labels up to 30 characters, numbers finite, screenshot JPEG and under 1 MB. World ids are 6 random characters.
- No accounts, no tracking. Phone works.
- The optional AI step (milestone 8) is clearly labelled in the game as optional. It needs Workers AI turned on in your Cloudflare account, or an API key kept as a Worker secret. The browser never calls a model directly and never holds a key.

## Milestones

1. **A scene.** `index.html` with the import map, a renderer, a camera, a sun light and a spinning cube. Resize handled.
   Check: a lit cube spins smoothly, and the browser's network panel shows Three.js loaded from the exact pinned address.
2. **Seeded terrain.** One chunk of terrain from the seed with height colours and a water plane. Print `height(10, 10)` for seed `test` in the console.
   Check: reload three times: the same number prints and the same hills appear; change the seed and the land changes.
3. **Walk and fly.** Walk on the surface with mouse look (Pointer Lock) and the phone controls. F toggles fly.
   Check: you can walk up a hill without sinking into it, fly over it, and do both on a phone.
4. **Endless land and trees.** Chunks around the player, built and dropped as you move. Trees with `InstancedMesh`.
   Check: walk in one direction for five minutes: the frame rate holds and the chunk count in a debug corner stays flat.
5. **Day and night.** Moving sun, sky colour, fog and stars, plus a time slider.
   Check: drag the slider through a full day: the light goes from dawn to noon to a dark night with stars.
6. **Markers and seed links.** Place labelled markers by raycasting the terrain. Keep them in localStorage per seed. `?seed=` opens a world.
   Check: plant three markers, reload: they are in the same places; send `?seed=` to another browser and it shows the same land.
> Up to here the world lives on your own device, and a seed link already lets a friend see the same land. Save and share puts your markers and a screenshot online too.
7. **Save and share.** The Worker, D1 table and R2 bucket. `POST /api/worlds` saves seed, name and markers and returns an id. `PUT /api/worlds/<id>/shot` takes the screenshot. `GET /api/worlds/<id>` loads it. Deploy.
   Check: save a world, open the link on your phone over mobile data: the screenshot shows, then the same land and your three markers.
8. **Optional: describe a world.** A text box, labelled "Optional, needs Workers AI or an API key". The Worker sends the text to a model and asks for JSON only: `treeDensity` 0 to 1, `waterLevel` -1 to 1, `mountainHeight` 0 to 2, `palette` from a fixed list, `landmarks` a list of up to 5 items each `tower`, `ring` or `monolith`. The Worker clamps every value and drops anything else before the game uses it.
   Check: "a flat desert with three stone rings" gives low hills, no water, sand colours and three rings; nonsense text still gives a valid world.

## Stretch

- Caves or overhangs using 3D noise for some chunks.
- Weather: rain particles and darker fog, chosen by the seed and the time.
- A photo mode that hides the controls and lets you tilt the camera.
- Footstep and wind sounds with Web Audio.
- A minimap drawn from the height function.
- A gallery page of recently saved worlds, newest first, from D1.

## Leave out

- Accounts, multiplayer, chat.
- Physics engines, model files, textures downloaded from the internet.
- Any model call from the browser, and any API key in front-end code.

Start by reading WRITING.md and the guide chapter on data if you need storage.
