How Procedural Coin Placement Works
The difference between a random generator and a constrained one, and the arithmetic that makes an endless game fair.
The problem with random
A purely random generator will eventually produce a layout no player could survive: a gap wider than any jump, a hazard placed where there is no room to avoid it, a coin in a position that cannot be reached. In a game with a finish line that is an annoyance. In an endless game, where the score is the entire point, it destroys the meaning of the score.
Once a player suspects that a death might not have been their fault, they stop treating the number at the end as a measure of skill. Every design decision in endless generation follows from wanting to avoid that.
Computing the movement envelope
The foundation is knowing exactly what the player can do, which is derivable rather than estimated. For a jump with an initial upward velocity and a constant gravity, the maximum height reached is the velocity squared divided by twice the gravity. The time to reach that apex is velocity over gravity, and total air time is twice that.
Horizontal distance is then simply the player's horizontal speed multiplied by total air time. Where a game offers a double jump, the second jump adds another arc, typically at around eighty-eight percent of the original velocity, and both contributions are added.
The critical property of computing this rather than hard-coding it is that the numbers update automatically. If a game's gravity is retuned during development, the generator's limits move with it, and no layout silently becomes impossible.
The constraints
With the envelope known, the generator caps everything inside it. On this site, a gap is never wider than about sixty-two percent of the real jump distance, and a raised terrain step is never taller than fifty-five percent of the real jump height.
Those margins are not arbitrary. They leave room for the player not being at optimal speed, not jumping at the perfect moment, and not landing at the very edge. A gap at ninety-five percent of theoretical maximum is technically clearable and practically unfair.
Difficulty is then expressed by moving gaps closer to the cap rather than past it. A run at full difficulty has gaps near sixty-two percent; an early run has them well below. The game gets harder without ever becoming impossible.
Chunks and culling
Terrain is generated in chunks - a segment of ground with a width, a height and whatever hazards and coins belong on it - and the generator builds ahead of the player until the world extends roughly two screens past the view.
Behind the player, everything that has scrolled fully off is culled. That keeps the number of live objects roughly constant regardless of how long a run lasts, which is what stops a ten-minute run from gradually slowing down.
Object pooling handles the churn. Rather than allocating a new coin and discarding it, a pool keeps used objects and hands them back out. In a game that spawns and destroys hundreds of small objects a minute, that is the difference between smooth play and periodic stutter on a mid-range phone.
Coin placement within a chunk
Coins are placed per chunk from the pattern library, anchored to the chunk's surface height. Because the surface is known and the pattern geometry is known, reachability is guaranteed by construction rather than checked afterwards.
One placement rule is worth singling out: every gap gets an arc of coins over it, with the arc's height capped at around fifty-five percent of the real jump height. That does two jobs. It rewards the jump the gap forces, and it visually traces the path that clears the gap, which is how a player learns the timing without being told.
The opening of a run is handled specially. During the grace period the generator is instructed to emit a straight, generously spaced line and no hazards at all, so every run starts with a streak already building.
Seeds and debugging
Using a seeded pseudo-random generator rather than the built-in random function has one practical benefit: a layout can be replayed exactly. When a player reports a section that felt unfair, a seed reproduces it precisely.
This site's generator uses a small deterministic algorithm that produces the same sequence from the same starting seed. Ordinary play uses the browser's random source, but the seeded path exists so that a specific layout can be reproduced during development.
Key takeaways
- Fair generation means constrained generation, not random generation.
- Jump height is velocity squared over twice gravity; jump distance is horizontal speed times total air time. Both are exact.
- Capping gaps at roughly 62 percent of real jump distance keeps every gap clearable at any difficulty.
- Terrain is built in chunks ahead of the player and culled behind, keeping memory flat during a long run.
- A seeded generator lets a problematic layout be replayed exactly, which is how generation bugs get fixed.
Frequently asked questions
Can a generated gap be impossible?
Not in a constrained generator. Gaps are capped at a fraction of the jump distance the physics actually produce, so they get harder but never impossible.
Is every generated coin reachable?
Yes. Patterns are anchored to known surface positions with geometry sized inside the player's movement envelope, so reachability is guaranteed by construction.
Does a long run get slower?
It should not. Objects behind the player are culled and recycled through a pool, so the live object count stays roughly flat regardless of run length.
Why does every run start with an easy coin line?
The grace period is deliberate. It guarantees a run opens with collectable coins and no hazards, so the combo system is meaningful from the first second.
A note on terminology. Everything described as a coin, gem or treasure in this article is a virtual in-game collectible used for scoring. Nothing here relates to real-world currency, numismatics, collecting physical coins, or any form of financial value.