I'm very interested in trying Roc for gamedev, but this obviously needs a platform for each game engine. I know @Luke Boswell is working on a graphical platform, but I suspect that's still pretty for from being ready to handle everything a game platform requires.
I recently remembered WASM4, it's a fantasy console similar to PICO-8, but instead of using Lua, it uses any language that can target WASM. I think this would be a great way to try Roc for small game projects because the engine can handle all the input, graphics and sound, and it has an intentionally small scope which will keep the Roc API simple.
I've started working on a platform in Zig based on the existing WASM platform, but I have pretty much no Zig experience, so I'm going to need a lot of help!
First thing I need help with: running the WASM platform from the Roc repo!
I'm getting this error when I try to build the app:
❱ roc build --target=wasm32 examples/platform-switching/rocLovesWebAssembly.roc
🔨 Rebuilding platform...
An internal compiler expectation was broken.
This is definitely a compiler bug.
Please file an issue here: https://github.com/roc-lang/roc/issues/new/choose
thread '<unnamed>' panicked at 'cannot find `glue.zig`. Check the source code in find_zig_glue_path() to show all the paths I tried.', crates/compiler/build/src/link.rs:123:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at 'Failed to (re)build platform.: Any { .. }', crates/compiler/build/src/program.rs:1021:46
Yeah, that is a bug. If you run it with cargo run -- build --target=wasm32 ...
I think that is a workaround. The issue is that the roc cli is hardcoded to look for a glue.zig file and it is located relative to the executable. This definitely isnt needed, its just an interim workaround that is ready to be removed from roc cli.
For building a wasm platform I highly reccomend using zig and a build.zig similar to my https://github.com/lukewilliamboswell/basic-graphics platform. That will be a much nicer experience.
I'm definitely keen to help out with this project, sounds like fun!!
Also I have a super simple WASM platform which may be helpful to look at as it https://github.com/lukewilliamboswell/roc-serverless
Thanks Luke, I suspected this was something that had a workaround, those links will definitely be super helpful :thumbs_up:
That's a really fun idea. Also, yeah, the wasm build target is currently very hobbled together. Like roc has great wasm code gen (including dev backend) , but the wasm linking and platform generation is basically hard coded to some zig stuff that just happened to be convenient at the time
Depending on how wasm4 works, it may be worth starting by just compiling roc to a wasm library and then loading it from a wasm4 application. That may be easier than full platform setup at the current moment.
Aside, maybe this could be a good project for us to look at for cleaning up wasm linking and making it work more generically.
Brendan Hansknecht said:
compiling roc to a wasm library and then loading it from a wasm4 application
Sorry for my ignorance about wasm, I haven't heard of wasm libraries. It sounds like it could be possible to compile all the Roc code into a wasm library, then import that into a Zig program that is compiled to a .wasm
file, is that right?
So my understanding is we would compile all roc code to a .wasm
file then make zig generate a .wasm
that links to and includes the roc .wasm
file. So give zig control of the final build process to get around all of the hacky stuff we do when roc controls the build process.
Not sure how much time I'll have, but I'll look at making a really basic wrapper to show what I mean. That should at least be a base that could be built off of.
The platform build stuff is really easy I thknk using build.zig. The part of this project that I think will be a challenge to get started is the interface between roc and Zig. We dont have a zig-glue.roc spec yet, so you have to roll these by hand. @Brendan Hansknecht was potentially going to look at implementing a basic init, update, render for the roc-graphics-mach experiment. Maybe this would be a better place to do that. This looks like a more mature game engine to target. I'm not confident I can build the zig-roc interface, but once we have that it should be pretty easy to add more capability. I could make a bare bones platform pretty quickly, with the build process etc just copying what I already have elsewhere. But without the integration we'd have to bundle a full json implementation from zig in wasm and use json between roc and zig which is less than ideal. It might be OK to get us started though.
yeah, I think it would be cool to make this work. I do agree that zig glue would help a lot. I may be one of the few peoples that will happily write glue code by hand and who has the knowledge to generally do so correctly-ish.
Working on this or working on zig glue would both probably be good things for me to do/to stream.
I just noticed that wasm4 supports rust first class. I assumed that it would just be a c project, but it has wrappers for tons of languages. If we want this platform to build robust and working soon, I would advise just making it with rust. Given rust glue already exists, it would be much more seamless to make a really nice platform. That said, pushing zig stuff is also important. So that could be the focus instead. Just depends on goals.
I spent an hour or so this afternoon looking at it with zig, and what I thought would be really straightforward isnt. I think this is a good project to sort out the roc build process, wasm32 makes this interesting. But totally agree, if we can use rust it would be much quicker to flesh out a working platform for actual gamedev.
I made a start on this, got something basic that doesn't work. https://github.com/lukewilliamboswell/roc-wasm4-games
So the issue I'm facing is that Roc expects things like roc_malloc to be provided by the wasm runtime, however this isn't provided by the default w4 run myCartridge.wasm
So, I'm not sure it will be possible to make a platform for this without forking the wasm4 runtime and providing the functions that Roc requires to be provided.
This will be the same issue with Rust too
Why is that a problem? I'm sure that zig has access to some chunk of memory that it can expose to roc. Wasm4 shouldn't need to expose it to roc.
Specifically, zig will have to expose a memory allocator that give some of the available program memory lifted here to roc: https://wasm4.org/docs/reference/memory/
Probably the simplest solution. Would be for the actual model to be stored in separate memory but for each frame to just use a clean arena allocator. Though given zig dowsnt know the exact size of the model, that may not be easy.
In the worst case, a simple impl of malloc and free needs to be added on top of that available memory.
Screenshot-2023-11-21-at-10.11.10AM.png
wrote a very messy and primitive allocator that uses the program memory space labeled by wasm4.
So yeah, everything should be doable.
Also, I don't fully understand our wasm build pipeline and how to make zig build something that we can have roc build on top of. So in my current testing, I am just having zig control the full build (which may always be needed for this platform due to the memory restrictions and such, but not fully sure.
Fork here of luke's work as a reference: https://github.com/bhansconnect/roc-wasm4-games
So good :+1:
@Hannes take a look and let us know what you think. With Brendan's modifications this works and we have a functional platform for Wasm4.
All you can do with it right now is pass a string back and forth, but I have used just that functionality within the platform to still expose a nice API for apps in roc-graphics-mach so there looks to be nothing stopping us from building a much more featureful platform for developing wasm4 games.
We can also potentially look at making a nicer Zig-Roc interface than just passing a Str
.
Also, there is probably a smarter way to do malloc and free. I just use a bit set and a list of used locations. Originally wanted to just use the bitset but forgot that roc_dealloc
doesn't get passed a size currently. If that gets fixed, this can be made a lot slimmer.
4.3K
isn't small enough? :sweat_smile:
That is with a limit of 200 allocations. At the max possible number of allocations, it is 33k.
If roc gives us the size info, it can be 4k with the max possible number of allocations being allowed.
Is there plans for roc_dealloc
to get passed a size? Sounds useful
Its been discussed before and on my long list of eventually want to implement. Biggest change will be to seamless slices, but overall still feels quite worth it. Does cost an extra usize on the heap per list/large string.
That said, the usize just exists in the allocator is not in the list/large string. So depending on the allocator, it has little cost.
Oh yeah, I can do that manually in this zig platform, let me fix that.
Ok, now it is 3.8k and it avoids the extra overhead of a side table for tracking allocations. instead it just stores the size before the allocation. So can have lots of allocations without statically wasting tons of binary space. Does waste more memory though cause every allocation has 1 chunk of overhead. But I think it is a better tradeoff.
Thanks Luke and Brendan, sorry for not responding earlier, I've been bust this week with starting a new job. That's great news that you've been able to get a proof-of-concept working! I'll find some time to get my head around how it works and how to build a proper API around it, probably just by passing a string to the platform for now like Luke suggested.
Last updated: Jul 05 2025 at 12:14 UTC