quake-rb

A port of the Quake (1996) engine to Ruby. Reads original .pak/.bsp/.mdl assets and renders them via OpenGL + SDL2.

quake-rb running e1m1

Why

Mostly as a counterpart to doom — to see how far you can take id Software's classic engines in plain Ruby, and to learn the BSP/PVS/lightmap pipeline by writing it from the spec rather than reading the C.

Quick start

bundle install
bundle exec bin/quake

On first run, with no data/id1/pak0.pak present, you'll be asked to download the freely-redistributable shareware Quake (Episode 1, ~17 MB). It's pulled from archive.org/quakeshareware/QUAKE_SW.zip and extracted into ./data/id1/pak0.pak. You can also drop your own registered pak0.pak (and pak1.pak) in there manually.

System requirements:

  • Ruby 3.1+
  • SDL2 (brew install sdl2 / apt install libsdl2-dev)
  • OpenGL 2.1
  • unzip (used by the shareware fetcher)

Controls

Key Action
WASD Move
Mouse Look
Space Jump
C Crouch
1–8 / scroll Weapon select
N Toggle noclip
L Dump player pose + save a screenshot to debug/shots/ (debug aid)
Esc Quit

What works

  • BSP loading + face extraction with texture coordinates
  • Texture mapping with the original 256-colour palette
  • Static lightmaps from the lighting lump
  • PVS culling, including:
    - leaf 0 fallback (treat solid leaf as all-visible, 
  • Sky rendering: two-layer scrolling cloud + back layer, PVS-culled
  • Water/slime/lava: turbsin-warped texture, alpha-blended translucency, backface culling for the duplicate front/back face pairs Quake's BSP compiler emits
  • Brush entities (doors, plats, buttons, triggers) with their own transforms
  • MDL alias models with frame interpolation
  • Particle effects + viewmodel + HUD
  • Player physics: walk, crouch, jump, friction, water levels, platform riding
  • Item pickups, weapon switching, Quake-style player weapon firing, shareware audio mixer
  • Common QuakeC trigger behavior at engine level, including target firing, killtarget, counters, hurt/push/teleport triggers, and changelevel requests

What doesn't (yet)

  • Multiplayer / netcode
  • QuakeC server program — game logic is faked at engine level
  • Full savegame/spawn parameter preservation across episode/level transitions
  • Mirrors, particle warp, dynamic lights
  • Sky cube / skybox replacement
  • Demo playback

Maps

The shareware PAK ships:

start, e1m1, e1m2, e1m3, e1m4, e1m5, e1m6, e1m7, e1m8

Pass -map maps/e1m3.bsp to load a different one.

Architecture

lib/quake/
  bsp/             reader, types, face vertices, PVS / FatPVS / vis-through-water
  pak/             pak0.pak reader
  mdl/             alias model reader
  wad/             gfx.wad (HUD/menu graphics) reader
  palette.rb       256-colour palette 

The headless runner is genuinely useful for working on the engine without a window — see debug/scripts/* for examples (water visibility traces, leaf inspection, BSP dumps).

Development

# Run the tests
bundle exec ruby -Itest -Ilib -e 'Dir["test/**/*_test.rb"].each { |f| require File.expand_path(f) }'

# Run a headless debug script (renders to a hidden window)
bundle exec bin/quake-debug debug/scripts/water_real.rb

# Run the game with YJIT
bundle exec bin/quake --yjit

Status

This is a hobby project. It can comfortably walk you through e1m1, fire Quake-style player weapons, pick up items, and use a growing subset of QuakeC brush/trigger behavior. The QuakeC server program is still not implemented, so game logic is ported incrementally at engine level and monsters don't fight back yet.

License

GPL-2.0-only, matching the original Quake source release.

The shareware Quake data is © 1996 id Software, freely redistributable. The registered Quake data (if you supply your own pak0.pak + pak1.pak) is not redistributable; you must own a copy.