Why?

An experiment gone wild

I’m a Linux fanatic, and I write JavaScript a lot. Not because it’s a beautiful language, but because it runs everywhere. Websites, obviously. Apps, with React Native. Server-side and scripting with Node.js. Just about everywhere.

I’d been working on a fun website for a while, and was considering turning it into a product. But it was really more suitable as a native application. A native desktop application, with a GUI.

Now what?

I liked React, and I had worked with React Native before. It’s pretty awesome - you scaffold an application, write some JavaScript and JSX, and then you just run it on your phone using a development app. Native. The whole process of getting an application from scratch running on your phone takes minutes. React Native has Android and iOS support, and unofficially Windows and macOS. But no Linux. No go.

Then there’s Electron. Everybody seems to be using Electron nowadays. But come on, including a full browser just to get to use JavaScript in a GUI? It’s not even simple - you cannot just run things in the browser and call the OS when you need to. You have a browser environment, a Node.js environment, and communication between them.

Then there are various options which use webviews. Webviews, really? Webviews really are browsers, only these are provided by the OS you are running on - which means you cannot rely on what you get. Good luck debugging that. In the mobile world, the whole reason React Native became interesting was that you could use JavaScript without building your UI out of webviews. And now we’re back to building desktop applications with… webviews? Oh please.

Nothing came close to what I wanted.

This wasn’t the first time I was thinking about this, but something had changed. I had switched from Node.js to Bun. It supported JSX directly and could produce single file executables. I remembered seeing that Bun could also use SDL via node-sdl - it stood out to me not because of Bun, but because I hadn’t realized before that SDL could be used together with JavaScript. SDL was something I’d used myself way back, and it was widely used for building cross-platform games. I guess that got the ball rolling. I was thinking executables, built with Bun, with a GUI on top of SDL, and using Skia for rendering. Every browser I knew of was using Skia, so it seemed like the obvious choice. A GUI that would be managed with React via its universal renderer, just like React Native.

I decided to do an experiment.

First I got Bun talking to SDL, then added Skia to write to an SDL buffer shown in a window and put universal React in front. It worked. But I was a bit intimidated by React’s universal renderer - it was pretty complex and documentation was scarce. I recalled having read about SolidJS somewhere, which also had a universal renderer, but worked without a virtual DOM - that virtual DOM which gets in the way when you’re doing high-frequency animations. And I wanted animations. So I gave SolidJS a chance - and it worked. And how!

From that moment on, I was hooked. I started a project, gave it a name: Electrosol. I added React Native’s layout engine, which got quickly replaced, because grids. It started to feel a lot like React Native - but different. It felt better somehow - but this was more of a gut feeling. After all I only had a prototype, which was cute, but hardly groundbreaking. But I felt its potential.

Around Christmas 2025 I made up my mind how to continue with the project. I decided to go all in. This was just too good to let die.

I changed the name to Solid-RT: the Solid Runtime. The engine would be written in Rust, the render tree would be in Rust; the SolidJS part was meant to stay as lean as possible. As it turned out, Flutter had run into issues with Skia and was replacing it with a more modern renderer called Impeller. This seemed like the right direction to follow - so Skia was out, Impeller was in. I had ideas where to take this, most of them long term. I estimated that by February 2026 I would have a first decent version.

But then I got a new friend named Claude. And things started moving fast.

QuickJS came in to replace Bun as a JavaScript runtime. It could be embedded directly into Solid-RT, which unlocked Android and iOS - mobile was in. I also wanted the development experience I liked about React Native. So a development app came to life, connecting devices to a dev server. But that wouldn’t be restricted to mobile - any device could connect, including Windows or macOS. Seeing my code update live across all my hardware, well - I got euphoric.

It felt like everything was coming together naturally. One thing led to another. The pieces just fit.

There were roadblocks, too - at least, that’s how they appeared at first. Flutter supports custom fragment shaders. I had adopted Flutter’s renderer. Surely I’d get that too? No. Impeller’s API did not give access to them.

Fragment shaders are where you get to tell the GPU what to do with every pixel. They open the door to effects and graphics that aren’t possible with the renderer’s built-in primitives alone.

But Flutter had a different approach to shaders. That door appeared to be locked - I would have needed more from the Flutter project than Impeller alone. But there turned out to be another door. Impeller had an OpenGL backend. I could simply make a fragment shader in GL, and then feed the result into Impeller. Fragment shaders were in.

March 2026, I decided to open source at least a part of the project.

I started a fresh project, copying over the parts I wanted to publish. Solid-RT became SolidRT. The architecture kept evolving. I moved SolidRT to SolidJS 2. And I came to realize that what appeared to be a roadblock at first actually opened the door to much more than fragment shaders on the GPU.

A lot more.

Vertex shaders entered the picture. That meant I could start moving much more of the rendering work onto the GPU, instead of being limited to what Impeller exposed. And I realized I was getting into territory where I could have a real advantage over Electron, React Native and Flutter. The stakes went up, and the February estimate had gone out the window.

July 2026. “AI native” had become a thing and I came to my own conclusion about what that meant.

To me, it wasn’t about adding an AI assistant to the development workflow. If agents were going to be a first-class part of building applications, they needed to be able to interact with the applications themselves. Not just write code, but run it, inspect it, measure it, understand what was happening, then change it.

And I could do that because SolidRT owned the full flow - from JavaScript all the way down to the GPU, while running live on any device. There wasn’t a browser, a webview, or any other layer in between. It controls everything.

I added MCP support. And things got wild.

I let agents build stuff, let them report on their findings, and took that feedback back to the core, or used it to extend the MCP server.

That gave me a huge amount of insight in a very short time, and the process accelerated again. By this time, agents were able to build full applications without intervention - they could control the mouse, keyboard, gamepads and even time. I would just sit back and watch them build, step through, try things, play.

What also surprised me was how quickly they started working around the limitations of interpreted JavaScript. When something was too heavy, they found another way. Shaders were already there and easy to use, so they simply started using the GPU. When I introduced workers, they simply started offloading work from the main thread.

And as the applications got more ambitious, I started working on a 3D extension. That’s when I started hitting the limits of interpreted JavaScript hard, and this time there were no easy workarounds.

The answer was to add a spatial core in Rust to take over the heavy computations. I tried to keep it generic enough to be useful beyond 3D, which led to a 2D extension using the same core.

I was no longer comparing with Flutter and React Native - I was comparing with Three.js, Unity and Godot: the world of graphics and games.

And it all made sense.

— Antoine van Wel