Devcontainers
A personal library of Dev Container Features and Templates published to GHCR, so every new project starts in a reproducible environment with one line of JSON.
Read moreGengie (Game + engine) is a small browser game engine I'm building in OCaml. It draws to a single 2D canvas and exists mostly as a forcing function for me to learn OCaml on a project I actually care about. The longer story is in Gengie, Part 1: Picking OCaml for a Game Engine.
No bundler, no framework. A static index.html mounts the engine onto a single <canvas> filling the viewport.
The engine is a handful of small modules under lib/:
Frame — per-frame snapshot: dt, elapsed time, frame count, canvas size, smoothed FPS, input stateScene — background color plus an ordered list of Object.t, rendered back-to-frontObject — a self-contained (init, update, render) unit with the state type hidden inside, so a single list can hold heterogeneous objectsCanvas — thin wrapper around Brr_canvas (clear, fill rect, fill text)Input — global keyboard tracker via keydown/keyup listeners, exposed as a per-frame snapshotState — typed mutable container for shared state across objectsVec2, Color, Time, Fps_counter — small utility modulesThe main loop lives in Game.run, drives requestAnimationFrame, computes a smoothed FPS with an exponential moving average, and hands a fresh Frame.t to every object each tick.
Right now it's a square on a 2D canvas. You move it with WASD or the arrow keys (Shift to sprint), it clamps to the canvas edges, and bumps a shared wall_hits counter every time it hits a wall — which a small HUD reads back. There's also an FPS overlay smoothed with an exponential moving average. Three small objects, one scene, enough to exercise the frame loop, the input snapshot, scene composition, and shared mutable state.
open Gengie let bg = Color.rgb 26 26 46 let scene = Scene.make ~background:bg [ Moving_square.obj; Stats_hud.obj; Fps_counter.make () ] let () = Game.run ~canvas_id:"game" ~scene
The engine is the means, not the end. The plan is to build a small indie game on top of it — something simple enough to actually finish, but real enough to push the engine into shapes a moving square can't. Tilemaps, sprites, audio, scenes that transition. Each new requirement is an excuse to learn a different corner of OCaml, and the game itself is what stops the engine from drifting into framework-for-its-own-sake territory.
I didn't know OCaml when I started. That's the point. The longer answer — and the one moment where the type system stopped feeling foreign — is in the Part 1 blog post.
AI is part of the workflow. Claude Code explains the idiomatic version, I retype it from scratch, then I try to break it. The retyping is what makes the patterns stick.
Built by
Alinus Dumitrana
Check out more of my work.
A personal library of Dev Container Features and Templates published to GHCR, so every new project starts in a reproducible environment with one line of JSON.
Read moreA personal website built with Rust and Axum — server-rendered with minimal JavaScript, and on-demand PDF generation.
Read more