Designed by Martin Stoleru. Developed by Alinus Dumitrana

All Projects

Gengie

Date May 2026

Gengie (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.

Stack

  • OCaml as the language
  • brr for browser, DOM, and canvas bindings — OCaml-shaped, not JS-shaped

No bundler, no framework. A static index.html mounts the engine onto a single <canvas> filling the viewport.

What's In It So Far

The engine is a handful of small modules under lib/:

  • Frame — per-frame snapshot: dt, elapsed time, frame count, canvas size, smoothed FPS, input state
  • Scene — background color plus an ordered list of Object.t, rendered back-to-front
  • Object — a self-contained (init, update, render) unit with the state type hidden inside, so a single list can hold heterogeneous objects
  • Canvas — thin wrapper around Brr_canvas (clear, fill rect, fill text)
  • Input — global keyboard tracker via keydown/keyup listeners, exposed as a per-frame snapshot
  • State — typed mutable container for shared state across objects
  • Vec2, Color, Time, Fps_counter — small utility modules

The 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.

The Demo

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

Where It's Going

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.

Why OCaml

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

Other Projects

Check out more of my work.

May 2026

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 more
Jan 2025

Atlas

A personal website built with Rust and Axum — server-rendered with minimal JavaScript, and on-demand PDF generation.

Read more