I'd like to make an SDL platform, where the main
function accepts & returns a "State" type that is defined by the end-user programmer, not by the platform. I'm not really sure how to define the State type though; can I list a type in the requires
part of the platform declaration?
(also is there documentation on the platform declaration syntax anywhere?)
I believe @Luke Boswell tried this somewhere. it is a bit like the elm architecture right?
roc-wasm4 and roc-ray both do this
You have to be care if you do a classic init
, update
, render
though. Your render
function if written the default way will free the model leading to future calls accessing already freed memory.
I just wrote an article on how I developed roc-ray which goes into this in some detail. https://lukewilliamboswell.github.io/roc-ray-experiment/
The way the platform is currently setup you can use tasks directly like setWindowSize etc, your not only providing a tree for things to render.
I think it should be pretty straightforward to swap out raylib for SDL if you want, though the libraries are very similar from what I can tell.
nice!
If your interested we could collaborate on roc-ray? Was there anything in particular you wanted to build with SDL?
Sure! yeah raylib seems just as good, I'd be happy to hack on it
@Luke Boswell checking out roc-ray -- the raylib
submodule is referencing a commit that doesn't exist on the public raylib.zig repo, or on your fork. Is it something you just have locally?
First time using git submodules... I thought I had pushed that commit. It's just a one liner to make something public I think. I'll have a look again and see if I can push it to my fork.
I think I figured out the issue, I has pushed to main
but the raylib repository uses master
as the default. I've just pushed the commit to both branches on my fork now, so I hope that works. Can you let me know if you have any issues?
hm the submodule is registered to the ryupold github link, not your fork
ok after fixing that, checkout is working
+ zig build
/Users/jared/clone/fork/roc-ray/build.zig:18:9: error: no field named 'force_pic' in struct 'Build.Step.Compile'
lib.force_pic = true;
^~~~~~~~~
/Users/jared/bin/zig-0.12/lib/std/Build/Step/Compile.zig:1:1: note: struct declared here
const builtin = @import("builtin");
error while building
Are you running zig 0.11.0? otherwise Im not sure
oh yeah 0.12. i just downloaded it
ok 0.11
+ zig build
/Users/jared/clone/fork/roc-ray/build.zig:21:21: error: expected error union type, found 'void'
try raylib.addTo(b, lib, target, mode, .{
~~~~~~~~~~~~^
referenced by:
runBuild__anon_6734: /Users/jared/bin/zig-11/lib/std/Build.zig:1639:37
remaining reference traces hidden; use '-freference-trace' to see all reference traces
/Users/jared/clone/fork/roc-ray/raylib/build.zig:105:21: error: expected type '*Build.Step.Compile', found '@typeInfo(@typeInfo(@TypeOf(raylib.raylib.src.build.addRaylib__anon_13150)).Fn.return_type.?).ErrorUnion.error_set!*Build.Step.Compile'
exe.linkLibrary(lib_raylib);
^~~~~~~~~~
/Users/jared/clone/fork/roc-ray/raylib/build.zig:105:21: note: cannot convert error union to payload type
/Users/jared/clone/fork/roc-ray/raylib/build.zig:105:21: note: consider using 'try', 'catch', or 'if'
/Users/jared/bin/zig-11/lib/std/Build/Step/Compile.zig:672:41: note: parameter type declared here
ah I see https://github.com/lukewilliamboswell/raylib/commit/7ca0edde71b7154f16b638a42003ea68283de4e5
working!!!! nice
now if I can get it all running on android, we'd really be cookin'
How hard is it to send collections over the bridge? I think my ideal API would be to have a single task like "renderDrawables" where you send a list of shapes / text / etc and it draws them all, instead doing a ton of chained tasks.
Without glue it will probably be quite tedious. The collection isn't the hard part. The hard part is the tagged union type that can wrap anything that is drawable.
Without glue for zig I imagine that would be cumbersome to write by hand. Definitely possible, just not ergonomic. If it's just small for a proof of concept or experiment I would. But if I wanted to change things and iterate I'd make a start on Zig glue instead.
hmmm yeah that makes sense. I could get by with just a small handful of drawables, so maybe it wouldn't be too bad?
on the other hand, I could make a layer on top of the imperative API in roc, and get the user experience I want
That probably would be much easier to do and what I would advise for now.
Yeah, should be pretty easy actually if we do it in the platform layer. So in e.g. platform/main.roc
.
pong.mp4
solitaire pong :)
That's awesome. Did you have to make many modifications to get that working?
Nope! Made a PR with the code
@Jared what do you think of this? https://github.com/lukewilliamboswell/roc-ray/pull/2
I added a Drawable
ability to see how that might feel for an API.
render : Model -> Task Model []
render = \_ ->
shapes = [
Shape2D.rect { posX: 10, posY: 50, width: 200, height: 50, color: white },
Shape2D.rectGradientV { posX: 10, posY: 150, width: 200, height: 50, top: white, bottom: blue },
Shape2D.text { text: "Hello World", posX: 10, posY: 250, size: 20, color: white },
Shape2D.circle { centerX: 300, centerY: 100, radius: 50, color: red },
Shape2D.circleGradient { centerX: 300, centerY: 200, radius: 35, inner: red, outer: blue },
]
_ <- shapes |> Task.forEach draw |> Task.await
Task.ok {}
Looks neat!
Last updated: Jul 26 2025 at 12:14 UTC