Gabriel Kaszewski c5c1436bc7 Fix WebGL2 for web build (raylib 5 requires VAOs)
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>
2026-03-07 00:39:03 +01:00

Endless Runner

A 2D side-scrolling endless runner built with Rust and raylib.

Rust

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 one PickupDef entry and one ActiveEffect impl.

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
No description provided
Readme 79 KiB
Languages
Rust 95.6%
HTML 2.9%
Shell 1.5%