build stuff

Project · ★★★ · Advanced

Tumble

A party-game obstacle race, one level long. Twelve jelly beans line up on a floating candy course. Jump the spinning bars, hop the platforms that slide over the gap, time the swinging balls on the narrow bridge, dodge what rolls down the ramp, and be one of the first six over the line. The other eleven are bots that read the course the same way you do, and some of them are bad at it. It is 3D, but the physics is a page of your own code, not an engine. Runs on a phone with a thumb stick and a Jump button, and on a desktop with the arrow keys and Space.

Play it The finished game, built from the brief below. One round takes about half a minute.

You need

What you'll learn

What this shows the agent can do

The brief

Make a new folder for the project. Copy the brief below into a file called BRIEF.md in that folder, or download BRIEF.md. Open the agent in the folder and say:

Read BRIEF.md and start with milestone 1. Stop after each milestone so I can check it.
# Tumble — a 3D obstacle race against bots (★★★)

Build a one-level obstacle race in the browser, in 3D. Twelve jelly-bean runners start together on a floating course. They run through spinning bars, hop across platforms that slide over a gap, cross a narrow bridge under swinging balls, and climb a ramp with balls rolling down it. The first six over the line qualify. You steer one bean; the other eleven are bots. It plays with a keyboard on a desktop and with a thumb stick and a Jump button on a phone.

## Done looks like

- A menu card over the live course: the name, one line on the goal, a Play button, the controls for the device in hand, and your best time.
- Play counts 3, 2, 1, GO. Nobody can move until GO.
- One course, about 170 units long, in five parts: a start pad; a wide floor with three spinning bars to jump; three platforms sliding left and right over a gap; a narrow bridge with three swinging balls; a ramp with balls rolling down five lanes, then the finish arch.
- Getting hit throws your bean and stuns it for about half a second. Falling off puts you back at the last checkpoint. There are four checkpoints, one at the start of each part.
- Eleven bots that play the same course by the same rules. They jump the bars, wait for a platform to line up, wait for a ball to pass and step out of a roller's lane. Each has a skill number, so some are good and some fall off a lot.
- Beans bump into each other.
- At the top of the screen: your place (1st to 12th), how many are through out of six, the time, and a bar showing how far along the course you are.
- The round ends when you cross the line (Qualified, with your place and time, and confetti) or when six bots cross before you (Eliminated, with your place). Then a Play again button.
- Your best qualifying time is kept in the browser.
- Works on a phone held upright and on a desktop. No console errors.

## Constraints

- Static files, no build step: `index.html`, `style.css`, `level.js`, `beans.js`, `main.js`.
- Three.js for drawing, loaded by an import map from a pinned version on a CDN. Never "latest". No physics library and no other library.
- Physics is your own and small: a bean is a point with a velocity; gravity pulls it down; floors are boxes with a top height (the ramp's top rises along its length); hazards are tested by distance. Run it on a fixed step of 1/60 second, however fast the screen draws.
- The course is data first: a list of platforms (centre, width, depth, height, and how it moves), a list of bars, a list of pendulums, a list of checkpoints. The picture, the physics and the bots all read the same lists.
- Controls: arrow keys or WASD, Space to jump. On touch: drag anywhere on the left of the screen for a stick that appears under the thumb, and a Jump button at least 96 px across on the right. Jumping forgives a little: a press up to a tenth of a second early or late still counts.
- Camera: behind and above your bean, always looking down the course. It does not turn. Pull it back and widen it when the screen is taller than it is wide.
- The level's movers keep moving behind the menu, but beans take no input until the countdown ends.
- Sounds are short oscillator beeps made in code, with a sound switch. The `AudioContext` is created on the Play tap.
- Best time and the sound switch live in localStorage under a `tumble:` prefix.
- The Play button says Loading and is disabled until the script has run.
- No lights that cast shadows: a dark circle under each bean is enough and keeps phones fast. Device pixel ratio capped at 2.
- Look: bright candy colours, striped floors, a sky-blue background with clouds and pillars far off, rounded heavy type with thick dark outlines.
- No server, no tracking, no accounts.

## Milestones

1. **A bean on a floor.** A Three.js scene with a sky, a light, the start pad and one bean you can run and jump with the keyboard. The camera follows.
   Check: run off the edge and you fall; you come back on the pad.
2. **The whole course.** All eight platforms from a list, the three sliders moving, the ramp sloping, the finish arch. Checkpoints.
   Check: you can run from start to finish with nothing in the way, riding a slider carries you with it, and falling at the bridge brings you back to the bridge.
3. **Things that hit.** Spinning bars, swinging balls, rolling balls. A hit throws and stuns.
   Check: stand in front of each hazard and get hit; jump a bar cleanly; a ball on the ramp knocks you back down the slope.
4. **Bots.** Eleven more beans driven by a function that returns the same stick-and-jump input you give. Beans push each other apart.
   Check: start a race and leave your hands off. Most bots finish in 25 to 40 seconds and a few fall along the way.
5. **A race.** Countdown, place, timer, progress bar, Qualified and Eliminated, Play again, best time.
   Check: nobody moves before GO; lose once on purpose and win once; the best time survives a reload.
> That is the whole race. The next steps make it work on a phone and feel good.
6. **Phone.** Thumb stick, Jump button, upright camera, safe areas.
   Check: play a full round on a real phone with two thumbs. The page does not scroll or zoom while you play.
7. **Juice.** Squash on jump and landing, feet that run, a spin when stunned, a screen shake on a hit, confetti, sounds.
   Check: turn the sound off and the game still reads; turn it on and every hit, jump and checkpoint has a sound.

## Stretch

- A second course, and three rounds in a row with fewer qualifying each time.
- Pick your bean's colour.
- A ghost of your best run.

## Leave out

- Real multiplayer. That is the next project, Arena.
- Grabbing and diving.
- A physics engine.

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

Milestones

The same milestones as the brief. Tick each one off when its check passes. Do one per sitting if you like. The dot in the list marks the point where you have something that works on its own. Everything after it makes it remember things or work for more than one person. Stop at the dot and use what you built before you go on.

  1. A bean on a floor. A Three.js scene with a sky, a light, the start pad and one bean you can run and jump with the keyboard. The camera follows.

    Check: run off the edge and you fall; you come back on the pad.

  2. The whole course. All eight platforms from a list, the three sliders moving, the ramp sloping, the finish arch. Checkpoints.

    Check: you can run from start to finish with nothing in the way, riding a slider carries you with it, and falling at the bridge brings you back to the bridge.

  3. Things that hit. Spinning bars, swinging balls, rolling balls. A hit throws and stuns.

    Check: stand in front of each hazard and get hit; jump a bar cleanly; a ball on the ramp knocks you back down the slope.

  4. Bots. Eleven more beans driven by a function that returns the same stick-and-jump input you give. Beans push each other apart.

    Check: start a race and leave your hands off. Most bots finish in 25 to 40 seconds and a few fall along the way.

  5. A race. Countdown, place, timer, progress bar, Qualified and Eliminated, Play again, best time.

    Check: nobody moves before GO; lose once on purpose and win once; the best time survives a reload.

  6. That is the whole race. The next steps make it work on a phone and feel good.
  7. Phone. Thumb stick, Jump button, upright camera, safe areas.

    Check: play a full round on a real phone with two thumbs. The page does not scroll or zoom while you play.

  8. Juice. Squash on jump and landing, feet that run, a spin when stunned, a screen shake on a hit, confetti, sounds.

    Check: turn the sound off and the game still reads; turn it on and every hit, jump and checkpoint has a sound.

Make it yours

Once it works, pick one of these and ask for it as a new milestone.

If it goes wrong

The bots all get stuck at the first obstacle.

They react when the bar is already touching them. A jump needs time to leave the ground. Say this to the agent:

The bots get knocked over by every spinning bar. Make them look a fifth of a second ahead: jump when the bar will be within reach then, not when it is now.

The game runs faster on one device than another.

The physics uses the time between frames, and that differs between a 60 Hz and a 120 Hz screen. Say this to the agent:

The game speed depends on the screen. Run the physics on a fixed step of 1/60 second with an accumulator, and only draw once per frame.

On a phone the page scrolls or zooms when you play.

The browser still treats drags and double taps as gestures. Say this to the agent:

Dragging the stick scrolls the page on my phone. Set touch-action to none on the page, use pointer events with setPointerCapture, and turn off text selection and the long-press menu.

You stand on a moving platform and it slides out from under you.

The bean keeps its own position while the platform moves. Say this to the agent:

I slide off the moving platforms. While a bean stands on a platform, add the platform's sideways movement to the bean each step.