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
| target | needs | gives |
|---|---|---|
make | raylib | gk, the desktop game |
make test | a C compiler | 99 assertions, headless |
make size | raylib | build, then fail above 10 MB |
make web | emsdk + raylib for wasm | web/gk.html, .js, .wasm |
make wasm-core | a wasm32 compiler | web/gk-core.wasm — 1,351 bytes measured |
make snake | raylib | snake, a second game on the same core |
make test-snake | a C compiler | 35 assertions for snake |
What is in the core
| piece | what it does |
|---|---|
gk_loop | accumulator, a 0.25 s frame clamp, a 240-step cap, alpha out for interpolation |
gk_scenes | named scenes with enter / exit / update / render; an unknown name is refused |
gk_input | down and pressed-this-frame, driven by the host — no engine types in the core |
gk_save | magic + version + CRC32, so a half-written save is caught rather than loaded |
gk_ecs | entities, component bags and systems over a bitmask, fixed capacity, no malloc |
gk_camera | world↔screen, follow with easing, zoom, bounds that keep the view in the level |
gk_tilemap, gk_move | solid tiles and collide-and-slide, axis by axis |
gk_atlas, gk_anim, gk_tiles_visible | frame rectangles, which frame is showing, and the tiles a camera can see |
gk_rng | mulberry32 — the same sequence as game-kit's rng(), verified to 1e-12 |
gk_ease, gk_spring, gk_tween | motion-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
| target | core object | verified |
|---|---|---|
aarch64-linux-musl | 4,024 B | yes |
arm-linux-musleabihf | 2,964 B | yes |
riscv64-linux-musl | 4,736 B | yes |
x86_64-windows-gnu | 9,986 B | yes |
aarch64-macos | 3,048 B | yes |
wasm32-wasi-musl | 1,351 B | yes |
*-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.
| entities | scan ns/entity | archetype ns/entity | ratio |
|---|---|---|---|
| 256 | 8.1 | 0.46 | 17.7× |
| 1,024 | 17.2 | 0.47 | 36.6× |
| 4,096 | 8.9 | 2.18 | 4.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.
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