c5c1436bc708be9f788306096aa734ee8729ba4b
Add -sUSE_WEBGL2=1 -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 to both EMCC_CFLAGS and linker flags. raylib 5.x enables VAOs by default which require WebGL2; without it glVertexAttribPointer fails on the clientside property of an undefined VAO object. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Endless Runner
A 2D side-scrolling endless runner built with Rust and raylib.
Gameplay
Run as far as you can on procedurally generated platforms. The world scrolls faster the longer you survive. Stomp enemies for bonus points, collect power-ups, and don't fall off the screen.
Controls
| Action | Keys |
|---|---|
| Jump | Space / W / ↑ |
| Restart | Space / R / Enter |
Power-ups
| Icon | Name | Effect |
|---|---|---|
| I | Invincible | Immune to side hits for 5 s |
| J | Jump Boost | 1.45× jump height for 6 s |
| 2 | 2× Score | Double score gain for 8 s |
Scoring
- Passive: 80 pts/s (multiplied by any active score effect)
- Stomp: 100 pt bonus per enemy (also multiplied)
Building
Prerequisites: Rust toolchain, raylib system library, a Wayland compositor.
# debug
cargo run
# release (LTO + stripped)
cargo run --release
Web (WebAssembly)
Prerequisites: Emscripten SDK activated in your shell.
./build_web.sh # produces web/*.js + web/*.wasm
./build_web.sh --serve # build then serve at http://localhost:8080
The web build uses ASYNCIFY so the main game loop requires no changes between native and browser targets.
Tests
cargo test
42 unit tests covering physics, collision, effects, and level generation.
Architecture
src/
main.rs — entry point, 60 fps cap, dt capped at 0.05 s
config.rs — Config struct (all tunable parameters)
player.rs — vertical physics, coyote-time jump window
platform.rs — scrolling platforms
enemy.rs — scrolling enemies with stomp detection
pickup.rs — PickupDef (data) + in-world Pickup instance
effects.rs — ActiveEffect trait + three concrete impls
level_gen.rs — procedural generation (StdRng, scrolling frontier)
world.rs — simulation loop, collision resolution, rendering
game.rs — state machine (Playing / GameOver), HUD
Key design decisions
- Player x is fixed; only the world scrolls.
- Speed follows
initial + factor × ln(1 + elapsed / time_scale)— fast early ramp, logarithmic plateau. - Landing detection uses the previous and current bottom-y crossing the platform surface, making it tunnelling-safe at high speeds.
- Coyote time: the jump window stays open for 120 ms after leaving a platform edge.
- Power-ups are fully data-driven via
Config::pickup_defs; adding a new type requires onePickupDefentry and oneActiveEffectimpl.
Tuning
All gameplay parameters live in Config::default() in src/config.rs — no recompilation of other modules needed when tweaking values.
initial_speed: 280.0, // px/s at t=0
speed_log_factor: 150.0, // how much speed grows
speed_time_scale: 30.0, // seconds before growth slows
gravity: 1900.0, // px/s²
jump_velocity: -800.0, // px/s (negative = up)
coyote_time: 0.12, // seconds
enemy_spawn_chance: 0.35, // per platform
pickup_spawn_chance: 0.28, // per platform
Description
Languages
Rust
95.6%
HTML
2.9%
Shell
1.5%