Live Reloading GUI From Scratch

Very cool!

I believe the killer feature is the REPL interpreted mode which lets you run the code without linking, which is often the slowest part of a live reload workflow. For example, even with all the tweaks prescribed in the Bevy Rust engine compile optimizations doc, including using the new mold linker, I couldn’t make my toy moonracer game reload in less than a few seconds.

I 100% agree. ghci is a top reason why I continue to use Haskell for gamedev and consider languages such as Rust to be insufficient.

Speaking from gamedev experience, you can probably take the hot reloading even further. For instance:

  1. You can re-use the existing window handle by storing it with foreign-store.
  2. Dunno if imgui could do this, but you can spin up your app in an OS thread and have it listen on an MVar for an entire app loop. Stuff that MVar in a foreign-store and then on reload, pass in the newly-loaded app loop. Depending on how your state & loop is managed, you can have new code operate on pre-existing state. No need to bounce main! I’ve done this with games and apecs and it’s pretty cool.
  3. You can also use the MVar approach to make ghci your development console - have your app loop listen to an MVar that has effects in it and execute them. You can even have it pass results back with some Dynamic magic - [example code]. I banged my head against the wall trying to add a “dev console” using a hand-rolled interpreter for a while. And then I tried hint. But then it dawned on me that ghci was all you need.

Here’s an example Main.hs using these techniques.

9 Likes