DEV Community

Misha Mitiev
Misha Mitiev

Posted on

Why I Built a High-Performance 2D/2.5D Engine in TypeScript (and Why I Ditched OOP)

Hi everyone! ๐Ÿ‘‹

Iโ€™m Misha Mitiev, a solo developer. Iโ€™ve spent the last several months in the trenches of browser performance, and I joined this community to share the progress of Loom Engine (v1.7.6).

Loom is a 2D/2.5D game engine built from scratch in TypeScript. It was born out of a specific need: I needed a deterministic, browser-first simulation engine to power TheWorldTable.ai.

I quickly realized that traditional Object-Oriented Programming (OOP) in JavaScript wasn't going to cut it for the scale I wanted. Here is a look at the architecture choices that make Loom Engine tick.

The Architecture: ECS + SoA
Most engines use "Game Objects." Loom uses an Entity Component System (ECS) with a Structure-of-Arrays (SoA) memory layout.

If you aren't familiar with the term, instead of having an array of "Player" objects, Loom stores data in flat TypedArrays.

The Problem: Traditional objects are scattered across the heap, making the CPU work harder to find them (Cache Misses).

The Loom Solution: By using SoA, I keep all "Position" data in one contiguous block of memory and all "Velocity" data in another. This makes iteration lightning-fast and extremely friendly to the browser's V8 engine.

Why Determinism Matters
Because Loom powers AI-driven simulations, I needed the engine to be 100% deterministic. This means that given the same input, the simulation must play out exactly the same way on every browser, every time. Achieving this in TypeScript required a strict SSE (Server-Sent Events) networking layer and a core loop that doesn't rely on variable frame rates.

What Iโ€™m Solving Right Now:
Zero-Allocation Loops: I'm currently hunting down every new keyword in my update loops to ensure the Garbage Collector never has a reason to pause the simulation.

Custom WebGL2 Batching: I'm building a renderer that reads directly from the ECS buffers to draw thousands of entities in a single draw call.

Why I'm Here
Iโ€™m looking to connect with other engineers interested in Data-Oriented Design, low-level TypeScript optimizations, and the future of browser-based simulations.

Building an engine from scratch is a massive undertaking, but seeing 100,000 entities move at a locked 60 FPS makes the "coordinate system nightmares" worth it. ๐Ÿ˜…

The Mainframe UI runs on just 28 entities, but
 when the simulation kicks in, Loom scales to 100k without breaking a sweat.

I'd love to hear from you: Have you ever experimented with ECS in the browser? What are your biggest hurdles when it comes to JS/TS performance?

Top comments (0)