6

Made a Canabalt-style one-button endless runner and the procedural obstacle spawner kept generating impossible sequences: two gaps back to back with no room to land, or a wall the instant you couldn't react.

The issue was that "randomly spawn obstacles" has no notion of whether the previous obstacle is even survivable at the current speed. I rewrote the prompt to make the spawner reason about reachability: compute the minimum safe gap from jump physics and current speed, and never place something the player can't clear.

Mostly happy with it now. Dropping the prompt, no big question, just sharing what worked.

THE PROMPT
Build a one-button endless runner in a single HTML canvas file, vanilla JS, 60fps. Auto-run to the right, Space/click to jump (variable height), procedurally generated ground gaps and obstacles, distance-based score.

Difficulty and fairness (the core requirement):
1. Speed starts at 320px/s and increases 6px/s per second, capped at 720px/s.
2. Derive jump physics constants (impulse, gravity) so a full jump clears a gap of width G_max at the CURRENT speed; compute G_max every spawn from those constants.
3. Never spawn a gap wider than 0.85*G_max or an obstacle that arrives sooner than the player's reaction budget (250ms) after the previous landing.
4. Guarantee a flat 'recovery' stretch of at least 1.5x player width after any gap so back-to-back gaps are always survivable.
5. Weighted obstacle mix (gap, low block to jump, tall block near a gap) whose difficulty weights scale with speed, but clamp so the game stays 'hard but fair', never impossible.

Game feel: parallax background (3 layers), speed lines that intensify with velocity, camera shake on near-misses, a stumble animation if you clip a low block (lose speed, not instant death), and a screen-freeze + zoom on death. Framerate-independent. Print the reachability formula (how G_max is derived from jump physics) as a comment before the code.
1the stumble-instead-of-die on low blocks is a great fairness touch. losing speed stings enough without a hard reset.canvas_carl 1 month ago
1deriving max gap from the actual jump physics instead of a magic number is the whole ballgame. this is why my runner felt unfair, i was hand-picking gap widths.vibecoder 1 month ago
add a comment

0 Answers

Your Answer