raylib-starter

One C file on raylib: a fixed timestep, scenes, a CRC-checked save, and an ECS. Built for the 10 MB ceiling — the C answer to game-kit.

250assertions, both games, all passing
57 KBthe game's own code, -O2 object
882 KBreal binary, linked against raylib 6.2
0engine calls in the core
1,351 Bthe core as wasm32, -Os

Build it

make              # the game        (needs raylib)
make test         # the suite       (needs only a C compiler)
make size         # fail if over 10 MB
make web          # the game in a browser (needs emsdk + raylib for wasm)
make wasm-core CC="zig cc"   # the core alone as wasm32, needs nothing
targetneedsgives
makeraylibgk, the desktop game
make testa C compiler99 assertions, headless
make sizeraylibbuild, then fail above 10 MB
make webemsdk + raylib for wasmweb/gk.html, .js, .wasm
make wasm-corea wasm32 compilerweb/gk-core.wasm — 1,351 bytes measured
make snakeraylibsnake, a second game on the same core
make test-snakea C compiler35 assertions for snake

What is in the core

piecewhat it does
gk_loopaccumulator, a 0.25 s frame clamp, a 240-step cap, alpha out for interpolation
gk_scenesnamed scenes with enter / exit / update / render; an unknown name is refused
gk_inputdown and pressed-this-frame, driven by the host — no engine types in the core
gk_savemagic + version + CRC32, so a half-written save is caught rather than loaded
gk_ecsentities, component bags and systems over a bitmask, fixed capacity, no malloc
gk_cameraworld↔screen, follow with easing, zoom, bounds that keep the view in the level
gk_tilemap, gk_movesolid tiles and collide-and-slide, axis by axis
gk_atlas, gk_anim, gk_tiles_visibleframe rectangles, which frame is showing, and the tiles a camera can see
gk_rngmulberry32 — the same sequence as game-kit's rng(), verified to 1e-12
gk_ease, gk_spring, gk_tweenmotion-kit's 11 curves and settle-time springs, verified to 1e-9

Warning-free

Seven configurations compile with -Wall -Wextra -Werror: the real build, the headless core, the stub link, both games, both suites, the benchmark, five cross targets and the wasm module.

The closest a GPU-less machine gets

make link-check links the real main() of both games — not the GK_NO_MAIN core — against the stub and runs each for 120 frames.

gk     frames=120 draws=2533
snake  frames=120 draws=712
OK: both games ran 120 frames headless, past the title

The loop, the scene machine, the render path and the key mapping all execute. What it cannot prove is that raylib draws: that needs a GPU and a display.

Portability, measured

targetcore objectverified
aarch64-linux-musl4,024 Byes
arm-linux-musleabihf2,964 Byes
riscv64-linux-musl4,736 Byes
x86_64-windows-gnu9,986 Byes
aarch64-macos3,048 Byes
wasm32-wasi-musl1,351 Byes
*-linux-android—no — needs the NDK

Why not archetype storage

Measured with make bench. The ratio is real; the absolute numbers are not — at 256 entities a system run is 2.1 µs against 0.12 µs in a 16.6 ms frame.

entitiesscan ns/entityarchetype ns/entityratio
2568.10.4617.7×
1,02417.20.4736.6×
4,0968.92.184.1×

The first run of that benchmark showed 260 ns/entity — a linear id lookup inside every component access, so every system was O(n²). Systems now receive the entity, access is O(1), and the number fell to 8.1 ns.

Why it tests without an engine

The core has no raylib in it. main.c compiles with -DGK_NO_MAIN and then contains no engine at all, so the suite drives the real game loop, the real scene machine and the real ECS headless — no window, no display, no GPU. The stub in stub/ mirrors raylib 5.x signatures, so the same source builds both ways.

What was not verified where this was written: the real raylib link. raylib needs X11 and GL headers, so make and make size are the two things to run on a machine with raylib installed. The suite and the raylib-facing half were both compiled; the engine was not linked.

The demo game

Three scenes — title, play, over — with a player and six drifting motes, all entities in the ECS. Collection is an AABB test, the round is 30 seconds, and the best score is saved to disk. Every part of the core is exercised by the game, which is why the tests can assert on the game rather than on toy inputs.

Support the work

One person's work: no company, no ads, no tracking, no paid tier. If this saved you an afternoon, a contribution keeps the next one coming — any amount, or none.

UPI drsohilboi@ybl  ·  Ko-fi  ·  PayPal  ·  Books  ·  All projects  ·  Email