Status: pre-release. October 2026.
How Margo Engine is built, and how we know it works
A WebGPU engine with a 22 KB core, built by one person directing AI, with the checks that keep it honest.
Summary
Margo Engine is a 3D engine for the web. Its core is small: the entry point that every project loads is 22,781 bytes gzipped (measured 2026-10-26). Everything else is an optional package you load only if you use it: physics, glTF loading, shadows, post-processing, voxel worlds with multiplayer, a path tracer, CAD import, exporters to Unity, Unreal, Godot and Roblox, React and Next.js support, Gaussian splats, mesh editing, scientific plotting and more than seventy others. It is open source under Apache-2.0.
I built it by directing an AI (Claude) and other AI coding tools. I think that is worth saying first, plainly, because the real question is not "did a person type every line". The question is "can you trust what it does". This paper explains the design, the process that produced it, what the checks have caught, what still fails and what we do not know yet.
1. The idea: pay only for what you import
Most engines ship one large library and let a bundler remove what you do not use. Margo works the other way round. The core draws a scene and nothing else. Every other feature is a separate package with its own entry points. A package that you do not import costs your users nothing, and a package that you do import does not change how the core behaves unless you ask it to. That last point is tested: for the optional features that touch rendering, a "proof" checks that with the feature switched off, the engine produces byte-for-byte the same output as before. There are 51 such proofs.
Two limits on the size claim, because they matter:
- 22,781 bytes is the measurement of the core and its stage entry point, with the WebAssembly kernel and the WebGPU backend included. It is not the size of an application. React, controls and every package you import add to it, and per-package sizes are tracked in the repository with a stated reason for every increase.
- Most packages need WebGPU. A WebGL2 fallback exists but draws only core meshes without textures, with one directional light. A fuller fallback is planned and not built.
2. What it can do today
Rendering: physically based materials (clearcoat, sheen, transmission, subsurface, parallax and triplanar mapping), cascaded soft shadows, clustered lighting, temporal anti-aliasing, post-processing, glTF 2.0 loading, skeletal animation with retargeting, IK and a rigging package, physics through Rapier, picking and selection, text and an in-engine game UI.
Worlds and data: voxel worlds with multiplayer, lighting and a path tracer; terrain; water; sky with weather; Gaussian splats (PLY, SPZ and SOG files); scientific plotting; GPU compute (FFT, sorting, linear algebra).
Tools: mesh editing (bevels, bridges, booleans, subdivision, UV unwrap, simplification and levels of detail), a scene inspector with undo and redo, a shader node editor, a command-line asset pipeline.
Interop: CAD import (STEP and IGES) through OpenCascade; export to glTF, USDZ and engine bundles for Unity, Unreal, Godot and Roblox; React and Next.js.
We compare the engine against three.js in a 161-row feature matrix. It covers 153 rows, with 4 partial and 4 missing. The partial and missing rows are listed publicly, along with the reason for each. That table is a planning tool, not a claim of equivalence.
3. How it was built: directing AI with engineering discipline
One person set the goals and made the decisions. AI did the writing. The process was designed so that nobody has to take anyone's word for the result.
Clean room. The engine uses no code from other engines. Features are written from public specifications and published papers, and every formula in the source cites where it comes from. A separate check fails the build if the code mentions or depends on something outside an explicit, attributed list (Rapier for physics, web-ifc for BIM files, React for the React bindings).
Many helpers, one gate. Work is split into small jobs that run in parallel, each in its own copy of the repository. Only one job can land at a time, and every landing must pass the same full check first: type and API reports, about 5,700 tests, quality gates for size, duplicates, documentation and error messages, the 51 proofs, a visual regression run, every package's real-GPU test, WGSL shader validation, a no-WebGPU fallback test, and a build matrix that installs every package into clean Vite, webpack, esbuild, Rollup and Next.js projects and type-checks every README example.
Rules that grew out of mistakes. Early on, two changes were merged while one known test was failing, on the reasoning that the failure was unrelated. It was not acceptable, and the rule became: nothing lands with a failing check, and a failing check is always the author's to root-cause, related or not. Another rule: every bug gets a regression test that fails without the fix. A third: when speed work makes the engine faster than a rival because it does less, we keep the work and publish the difference instead of matching the number.
4. What the checks caught (and what they did not)
A sample of real findings from the last week, because a list of passes proves little:
- A shadow-culling optimisation lost shadows. A speed change culled shadow casters per cube face using a radius taken from the longest column of the transform matrix, which is too small for a rotated child of a non-uniformly scaled parent. A review pass that compared old and new output for 139 rendering cases found it. The fix uses a bound that holds under shear and has a test with 120 sheared casters.
- A hygiene check read error messages wrongly. It looked only up to the first quote character, so fix advice after a variable was missed and some real offenders were hidden. After the fix, 9 plain errors and 44 messages that named no fix were corrected.
- An independent test on a second GPU found four failing suites. A tester ran the GPU suites on an Intel Arc machine; all passed on our NVIDIA machine. Three of the four turned out to be tests that assumed "N frames means ready" while shaders were still compiling, and one was a real engine bug: the path tracer reported "converged" while still showing a preview frame. Three of the four fixes were confirmed on the Intel machine. Three further failures there (GPU trigonometry accuracy, one more timing assumption and a depth error that comes from the same trigonometry) are being fixed, and a rare one-pixel difference in 4x anti-aliased blending shows up on both vendors; its cause is open.
- An exporter was right and our checklist was wrong. When a texture-rotation test on an iPhone looked backwards to us, we derived the rotation from the glTF specification, compared it with the engine's own renderer, and found the checklist's expectation was the error.
- A fresh clone cannot yet run the full verification. Some proof baselines refer to commits that exist only in the author's history. We found this because a second machine tried it. A fix is in progress and is a launch condition.
5. Honest limits
- Speed. We run a 161-row performance comparison against three.js. Its first run showed Margo slower in many rows; we diagnosed the causes, fixed many and recorded the rest. Some remaining gaps are deliberate: for example Margo computes flat face normals when it loads an STL file, so the mesh lights correctly out of the box, while the three.js loader leaves them blank until you compute them yourself. We publish no speed numbers yet. Every result so far was taken on a busy shared machine and is labelled diagnostic. Numbers will appear after a quiet-machine run, with scripts anyone can rerun.
- Hardware. Results come mainly from one NVIDIA desktop GPU and one Intel integrated GPU, in Edge on Windows. Nothing has been measured on Safari, Firefox or Android, or on Apple silicon. USDZ export was checked on one iPhone.
- Coverage. Many packages are solid, some are shallow. The package list shows depth honestly. Several features were checked against specifications and not against real hardware (WebXR augmented reality, for one).
- Process. AI-directed does not mean flawless. The number of tests says nothing about what no test covers. That is why the known-bugs list is public and why independent review is part of the plan.
6. What comes next
An honest benchmark page with rerunnable scripts, a 5-minute quickstart, a website with guides, a gallery of working demos, a device compatibility table, and the first public release of the code. Until then, this paper and the waitlist are the place to follow progress.
Margo Engine, Apache-2.0. margoengine.com