This post is the origin story behind Inglorious Web. You can read it standalone, or as a prologue to the series that followed.
This is not a post about a framework. It's a post about why I needed to build one — and why it took three years, a conference that almost nobody was supposed to attend, and the worst year of my life to get there.
Summer 2022: The Idea
I love Redux. Not in the abstract — I mean the specific intellectual pleasure of the three principles: single source of truth, immutable state, pure functions. The kind of architecture where you can look at any state transition and reason about it completely. Where testing is just calling a function.
I'd been using it professionally for years, and at some point I started wondering: what if you applied those same principles to a game engine? Games have to manage hundreds of entities updating every frame. They have to be deterministic, debuggable, and fast. Redux had proved those properties in web apps — could they survive the pressure of a game loop?
On July 30, 2022, I started finding out. The core idea was simple: model the game loop as a pure function.
const gameLoop = (state, action) => {
const nextState = reducer(state, action);
render(nextState);
return nextState;
};
This was my first attempt. It didn't last long. Redux itself turned out to be the wrong fit — slices and reducers weren't designed for entities that need independent state and behavior. So I threw it out and designed my own store: an entity-based model where each entity has a type, and each type defines its behavior as event handlers.
const types = {
player: {
move(entity, direction) {
add(entity.position, direction);
},
},
};
const entities = {
player1: { type: 'player', position: [0, 0] },
};
That felt right. By August 2022, the entity store worked. At the time I thought I was building a game engine. In hindsight, I was building a state architecture that accidentally had to do with games. And then — like most side projects — life got in the way, and I set it down.
2023: Game AI and the Canvas
A year later, a book on game AI algorithms reignited the project. I wanted to implement pathfinding, behavior trees, and decision systems in a functional style rather than the object-oriented approach most game development books assume. The entity architecture made it elegant — an enemy entity checking distance to a player entity, notifying an event, the store processing it in order. Deterministic, testable, no magic.
I added a 2D canvas rendering layer. React had been powering the visuals, but there's only so much the DOM can do at 60 frames per second. More importantly, I wanted the engine to be render-agnostic — the store shouldn't care whether it's rendering to a canvas, a DOM, or nothing at all.
By late 2023, the engine had a working canvas renderer, an AI system, and a clean separation between state, behavior, and rendering. Then I hit collision detection, and the motivation drained again. Collision detection is one of those problems that starts simple (two rectangles, check the overlap) and reveals an abyss the moment you look closely. I'd also just gotten married. The engine went back in the drawer.
2025: Coding Is Coping
Right after my wedding, things went south quickly. My mother was diagnosed with cancer. She died in March 2025.
In the same period, LLMs arrived and started threatening the thing I'd built my professional identity around. The combination — personal grief, professional anxiety, the general sense that the ground was shifting — produced a burnout I didn't fully recognize until I was already deep in it.
What pulled me out, eventually, was coding. Not productively at first. Just tinkering, reading old code, seeing if things still made sense. LLMs helped in a way I didn't expect: not by writing the code for me, but by giving me a thinking partner when I needed to reason through a design decision at 11pm with nobody else around. The engine, sitting untouched for months, started to feel interesting again.
I know this sounds like I'm romanticizing it. But there's something specific about working on a system that behaves exactly the way you tell it to — that has no opinion about your grief, no awareness of your anxiety, that just processes events in order and gives you back a new state. It was the right kind of boring.
July 2025: The Conference
My friend Savino Carlone organizes a small conference in Turin for .NET developers — Torino .NET. He needed a speaker for a mid-August online slot and asked if I could fill it. I said I had nothing to talk about. He said: "Don't worry, nobody's going to listen anyway. Everyone's on vacation."
That was enough. I said yes, pulled up the engine code, and started re-reading it to prepare slides.
What happened next surprised me. Re-reading code you wrote in a different state of mind is a strange experience. Some of it was embarrassing. Some of it was better than I remembered. And somewhere in the process of preparing examples and building a demo — a particle system, a few simple game prototypes — I realized that I'd built something genuinely interesting without fully noticing.
The attendance was better than expected. I opened with a hook for the .NET crowd: certain problems can be solved through the decorator pattern in object-oriented programming — and then I showed how, in functional programming, the decorator pattern becomes function composition. That part landed. When I moved deeper into the FP principles behind the engine, I lost most of them technically, but something still came through. They appreciated it. I left with my passion back, which was the only thing that mattered.
The Coding Spree
After the conference, I couldn't stop. And here I want to say something about LLMs that I don't see said often enough.
Nobody else cared about this project. Not in the way that matters when you're deep in a design decision at 11pm and need to think out loud. LLMs gave me something I hadn't had in a long time: a partner with encyclopedic knowledge who was genuinely willing to engage — not just say "well done," but push back, suggest alternatives, catch mistakes, and sustain a real technical conversation for as long as I needed. They also gave me the ability to move fast on the parts of the codebase I found tedious, so I could spend my energy on the parts I found interesting.
Yes, LLMs had threatened my sense of professional relevance. They also saved the project. Both things are true.
I added a scaffolding tool, sound support, touch support, an entity pool for performance-critical scenarios. I even created a JavaScript superset — IngloriousScript — that adds native vector operations to the language, because I kept writing add(position, scale(velocity, dt)) when I wanted to write position + velocity * dt.
And then, sometime in October 2025, I noticed something.
The state manager at the heart of the engine — the entity store I'd built in 2022 — was completely decoupled from the game loop and the rendering layer. It just managed state. It processed events. It was predictable and testable and deterministic.
It could power a web app.
Not Only Games
I'd spent years building React architectures for complex, data-heavy applications — config-driven dashboards at Irion, industrial HMI interfaces as lead front-end architect at Tetra Pak. I was proud of that work. But I could also see exactly where it would age. The complexity of RTK made junior developers reach for useState() when they shouldn't. Cascading renders made behavior unpredictable at times. Business logic drifted into components because that's where the framework pulled it. The kind of system that works until it doesn't, and then debugging it requires holding the entire tree in your head.
The entity store solved those problems structurally — not by being clever, but by keeping concerns separate from the start: state in the store, behavior in types, rendering as a pure function of state. A couple of years after my collaboration with Tetra Pak ended, I went back to propose migrating to Inglorious Store and Inglorious Web. The reception was warm. The migration never started. So the experiments my team and I are doing remain in-house for now — which is fine. The framework exists either way.
Then I kept pulling the thread. If all the logic lives in the store, what is React actually doing? Providing lifecycle hooks? Not needed — there are no component-level lifecycles in an entity model. Diffing the virtual DOM? Overkill when the render function is already pure and lit-html can handle surgical DOM updates at 3.24kB total.
By November 2025, React was gone. Inglorious Web was born.
What It Became
The framework now ships with a router, form handling, table, select, virtualized list, declarative SVG charts, an animation library, a design system, and SSG with HMR and file-based routing. It's Redux DevTools compatible, works with any web component, and renders to the real DOM — no virtual DOM, no compiler, no proxy-based reactivity.
The bundle is 16KB. The mental model is a one-time cost. Testing is just calling functions.
I wrote a series of posts about the architecture and the benchmarks — why I made the choices I made, where the framework fits, and where it honestly doesn't. If you want the technical argument, start there.
This post is just about how it got here: a Redux idea applied to games, a drawer it sat in for too long, a grief that made coding feel necessary, a conference in Turin that reignited everything, and a thread I kept pulling until something new came out the other end.
In May 2026 I'll be speaking about all of this at JsTek in Chicago — hoping it finds a slightly larger audience than a mid-August .NET meetup. If you're going to be there, come say hello.
Top comments (0)