An experimental game engine using MIR as a JIT-compiled C scripting runtime, with a custom transpiler that adds classes, operators, and inheritance to C.
The core idea: write game scripts in a C-like language with classes and operator overloading, transpile them to plain C, and JIT-compile them at startup via MIR. Scripts get near-native performance with instant iteration - no separate compilation step, no interpreter overhead.
The engine provides an ECS (Entity Component System), an ImGui layer over a Vulkan backend, a math library, threading primitives, and coroutines - all exposed to scripts as plain C function calls.
.cc script files (C with classes)
|
CCLang Transpiler
|
plain C output
|
MIR JIT compiler
|
native machine code <---> Engine (C++ / Vulkan / ImGui)
CCLang Transpiler converts .cc files with class syntax into standard C that MIR can consume. It handles:
- Classes with fields, methods, and operator overloading
- Single inheritance with struct field flattening (layout-compatible upcasting)
- Interface contracts (compile-time method validation, no vtables)
this.field/ implicit member access inside method bodies- Operator precedence parsing with temporary linearization for chained expressions like
a + b * c - Derived-to-base pointer casts for inherited method/operator calls
- Value argument slicing when passing derived types to base-typed parameters
Engine Host provides the runtime API to scripts:
- ECS - component registration, entity lifecycle, chunk-based query iteration, system callbacks
- ImGui - windows, widgets, sliders, tables, trees, draw lists, keyboard/mouse input
- Math - Vec2/Vec3/Vec4 with operators, common math functions
- Threading - work-stealing
parallel_foracross all cores,atomic_add_int/atomic_add_float/atomic_cas_intfor lock-free accumulation, background tasks, cooperative coroutines - Rendering - Vulkan backend (ImGui integration, draw list rendering)
- Hot Reload - scripts call
script_rebuild()to recompile from disk without restarting the engine
The project includes several complete games and simulations built entirely in the scripted C-with-classes language:
| Script | Description |
|---|---|
| Chess | Full chess game with negamax AI (alpha-beta, TT, null-move pruning, LMR, killer/history heuristics), configurable search depth, ImGui board with piece rendering via draw lists |
| Tetront | Classic Tetris with rotation, line clearing, scoring, and ghost piece |
| Minesweeper | Minesweeper with flood-fill reveal, flagging, and mine generation |
| Go | Go board with stone placement, capture logic, and territory scoring |
| N-Body | 100k+ particle gravitational simulation with grid-based force approximation, cutoff-radius optimization, leapfrog integration, and parallel grid binning via atomics. Substeppable |
| Wildlife | Predator-prey ecosystem with steering behaviors, energy/reproduction systems, toroidal world, and real-time population/energy/behavior graphs |
Each script is a single .cc file (plus a small .h header) that compiles and runs via MIR JIT at engine startup.
CCLang is a two-pass transpiler that converts C-with-classes to plain C.
class Vec2
{
float x;
float y;
Vec2 operator+(Vec2 other) { Vec2 r; r.x = x + other.x; r.y = y + other.y; return r; }
Vec2 operator*(float s) { Vec2 r; r.x = x * s; r.y = y * s; return r; }
float Length() { return sqrtf(x * x + y * y); }
Vec2 Normalize()
{
float l = Length();
Vec2 r;
if (l > 0.0001f) { r.x = x / l; r.y = y / l; }
else { r.x = 0.0f; r.y = 0.0f; }
return r;
}
}Transpiles to:
typedef struct { float x; float y; } Vec2;
static Vec2 Vec2_op_add(Vec2* self, Vec2 other);
static Vec2 Vec2_op_mul(Vec2* self, float s);
static float Vec2_Length(Vec2* self);
static Vec2 Vec2_Normalize(Vec2* self);
// ... method definitions with self-> substitutionUsage in scripts is natural:
Vec2 a, b;
a.x = 3.0f; a.y = 4.0f;
b.x = 1.0f; b.y = 0.0f;
Vec2 c = a + b; // -> Vec2_op_add(&a, b)
Vec2 d = a * 2.0f; // -> Vec2_op_mul(&a, 2.0f)
float len = c.Length(); // -> Vec2_Length(&c)
Vec2 n = a.Normalize() * 5; // temp + chained opclass Shape
{
float x, y, scale;
float Area() { return 0.0f; }
void SetPos(float px, float py) { x = px; y = py; }
}
class Circle : Shape
{
float radius;
float Area() { return 3.14159f * radius * radius; }
}
class Ellipse : Circle
{
float radius_y;
float Area() { return 3.14159f * radius * radius_y; }
}The transpiler flattens base fields into derived structs (Circle gets x, y, scale, radius), resolves method calls up the inheritance chain, and emits pointer casts for cross-class calls (Shape_SetPos((Shape*)&myCircle, ...)).
The expression parser handles precedence correctly and linearizes chained class operators into temporaries:
Vec2 result = a + b * 2.0f - c;Becomes:
Vec2 __tmp0 = Vec2_op_mul(&b, 2.0f);
Vec2 __tmp1 = Vec2_op_add(&a, __tmp0);
Vec2 __tmp2 = Vec2_op_sub(&__tmp1, c);
Vec2 result = __tmp2;Requires CMake 3.16+, a C++17 compiler, and the Vulkan SDK. All other dependencies are cloned automatically on first build.
git clone https://github.com/yourname/mir-engine.git
cd mir-engine
cmake -B build
cmake --build buildCMake will pull MIR, Dear ImGui, and GLFW on first configure if they aren't already present. The working directory is the repo root so the scripts/ folder is found automatically.
| Library | Purpose | Acquired |
|---|---|---|
| MIR | Lightweight JIT compiler for C | Auto-cloned by CMake |
| Dear ImGui | Immediate mode GUI | Auto-cloned by CMake |
| GLFW | Windowing and input | Auto-cloned by CMake |
| Vulkan SDK | Graphics backend | Must be installed separately |
TODO