Big upgrades have landed in https://github.com/lukewilliamboswell/roc-ray with the 0.9 release
Here's a recording of the ScrewBot demo running buttery smooth at 120fps with hot-reloading.
Screencast from 2026-08-06 10-13-16.webm
Thanks for your work on this Luke.
For my Puri GUI framework demo, I asked my LLM to add clipboard support and it went off and did a slightly crazy hack to bring in RocRay with additions. After updating to 0.9 and moving multi-click recognition into Puri, the local adapter is down to three additions:
These are all features of raylib so I think it'd make sense to just expose them through the platform? Something feels a bit off about all of this to me somehow, but I'm trying to open my mind to it. I'm accustomed to composing things to solve problems like this. I understand the benefits of having a clear line of what a Roc program can do, but I wish platforms were more first-class and could be composed/parameterized. I feel awkward asking for particular things to be added vs just composing them on to what has been chosen to packaged up by the platform author. It probably makes a lot of sense to have the option of a platform that doesn't expose clipboard for security reasons. I don't see that as a bug or missing feature in general, but for my app I'd like to have it.
I hadn't thought of these, good ideas :thumbs_up: I'll add them later today. There was something else I wanted to add too, so if I can remember what that was I'll roll that in as well.
It's definitely an experiment to see how we go - Roc's platform abstraction is pretty unique. I'm not sure the best way to evaluate what should live in the platform and what should be something I encourage people to fork and extend for themselves.
This question may be more appropriate in a broader channel, but in my demo Todo app I have a file called RocRayInput.roc. It translates rr.Host and rr.Keys into Puri’s platform-independent events. The translation is pure and conceptually belongs in the reusable puri-rocray package, not inside the Todo application. However, an ordinary package cannot import types or modules from the application’s selected rr platform.
Would it make sense for RocRay’s public data types and pure helpers to live in a companion ordinary package that both the RocRay platform and puri-rocray could depend on? Is that a pattern platform authors should generally consider for public types that reusable packages may need to reference?
I think the answer is yes... but it's not really been tried before. The concept for cross-platform packages has been floating around but we haven't seen much beyond the http package.
I forgot to make the changes from above earlier. I could try and split the types out and see if I can publish the types in package alongside the platform.
I'm not sure where the split is or how it would feel for the downstream app/package authors. But I guess its worth a try. We might find something worth modifying in roc's design
My concern isn't cross-platform packages, but I'm building tooling to connect my backend-independent GUI model to roc-ray that then would be used in an application that chooses that backend.
No rush on the other changes. I'm just having fun. I tried going back to Rust to work on my actual project but I keep thinking about Roc :)
I'm not sure I follow... if it's not a cross-platform package you are thinking of
Puri is designed to be backend (i.e. platform) agnostic, but even if it weren't I wouldn't be able to reference rocray types from it. So imo it's not about having cross-platform packages, but packages that reference platform types even if they're only designed to assist with one platform.
I think I might need to experiment and build something to try it out...
Puri can definitely use other packages types, just like a platform package can use other packages types -- so they can both depend on and share a common generic.Keys type
yeah, that would be one solution, to make a habit of putting types and pure functions in a separate package
I finally remembered what I wanted to add... generating images and videos by recording frames and then encoding that to a file in whatever format you need.
The use case I had in mind was rendering a nice diagram or maybe a moving visualization
Claude can make sharing links for things, here is a demo of the new Capture features
https://claude.ai/code/artifact/8cdf3963-650d-478c-bded-0fb75e00ae24
Or if the above doesn't work... a capture of a moving graph exported as WebM :grinning_face_with_smiling_eyes:
Screencast from 2026-08-07 17-34-42.webm
roc-ray previously had an update! and I think I want to bring it back, I want to take all the slow things off the thread that is drawing and calls Roc and I can't think of a better way to do that.
Jake Brownson said:
This question may be more appropriate in a broader channel, but in my demo Todo app I have a file called RocRayInput.roc. It translates
rr.Hostandrr.Keysinto Puri’s platform-independent events. The translation is pure and conceptually belongs in the reusable puri-rocray package, not inside the Todo application. However, an ordinary package cannot import types or modules from the application’s selectedrrplatform.Would it make sense for RocRay’s public data types and pure helpers to live in a companion ordinary package that both the RocRay platform and
puri-rocraycould depend on? Is that a pattern platform authors should generally consider for public types that reusable packages may need to reference?
I want to echo Jake's concern.
In terrocotta I have the same problem, and it is not trying to be cross-platform. Terrocotta can't depend on roc-ray so it can only abstract over structural types/functions that will then unify with roc-ray's types/functions when the user app puts things together.
In particular, since 0.9.0 FontResource has become nominal.
FontResource :: Box(U64)
Font : [DefaultFont, LoadedFont(FontResource)]
load_font! : { path : Str, size : I32 } => { font : FontResource, err : U8 }
Since Terrocotta can't depend on nominal FontResource, it can't use it in its API.
So user can load a font = load_font!("path/to/font", 16) but can't pass it to any terrocotta API. So terrocotta can only work with default font...
So I believe, the roc-ray platform should only define structural API, and a companion roc-ray-types package can define a Nominal API on top if need be. Then Terrocotta can import and work with the nominal types.
If anyone is interested, I've been experimenting with a new API for roc-ray in this branch
https://github.com/lukewilliamboswell/roc-ray/tree/spike/elm-architecture
The core idea is introducing a pure update to the API to decouple slow tasks from the fast roc/raylib render loop which runs in a single thread. That lays a nicer architecture for adding features like reading from files and networking.
I need to sit and experiment with it more, but it's starting to feel pretty good.
That also includes a supporting types package where all the core types for roc-ray live so other packages could depend and build upon those.
This looks great.
types package it should include a frame.Drawable where alias for the effectful interfaceupdate, UI layout should go in update but it is still effectful because of Draw.measure_text!() (see https://github.com/lukewilliamboswell/roc-ray/issues/101). Ideally roc-ray Font should expose pure idx = font.get_glyph_index(codepoint) and glyph = font.glyphs[idx]. Then terrocotta can implement pure measure text using the unicode package.Unicode package is quite mature now, so we can totally do something there probably
font metrics and glyphs must happen on the roc-ray side
FontMetrics := {
base_size : F32,
glyphs : List(GlyphMetrics),
# codepoint → glyph index mapping
get_glyph_index : FontMetrics, U32 -> U32
}
GlyphMetrics : {
advance_x : F32,
offset_x : F32,
offset_y : F32,
width : F32,
height : F32,
}
then unicode package can give the codepoint. Then where does measure(font, config, text) live ? Not unicode because is has no notion of font. roc-ray only if roc-ray is okay with depending on unicode. Otherwise in user code like terrocotta
i think I may be able to cheat a little and have this be an "action" the API is still pure for the user but the platform can call the effectful host parts under the hood
idk though because I guess the next thing is the user will want to use the layout information
do you think it's an issue if UI layout stays in render?
shouldn't this metrics buildup happen on Font.load!() which is usually during init! ?
then font has a handle and the metrics/glyphs
Good ideas. I've got to head out soon but can poke at it again tomorrow
Luke Boswell said:
do you think it's an issue if UI layout stays in render?
I wonder. update is to update the Model. Model update needs layout solved to resolve user interactions (to update which element is focused, i need to know user clicked on what ?) so it feels like layout should be in update.
https://github.com/obust/terrocotta/blob/main/package/Program.roc#L144
since render! : Model, Draw.Frame => Try({}, [Exit(I64), ..]) does not modify the model, then if i do layout in render!, how do i update the model focused/hovered/drag/scroll state ?
Yeah I think the general shape is layout once per update, retain that in the model for comparing on the next update, and so we need to find a way to make that pure (by moving the font stuff around).
I'm still chipping away at this ... just waiting for bug fixes to land in a nightly release before I can update and cut a pre-release to try it out
I have a WIP branch for the font metrics we have been discussing. I feel pretty good about it all except how it works with the DefaultFont tag union. ‘Font: [DefaultFont, LoadedFont(FontResource)’. Both variants need FontMetrics but adding it to FontResource does not add it to DefaultFont. I liked it better before 0.9.0 where default font was handle Box(0). At least the interface was uniform and I did not have to match everywhere. I believe Font: { key: Box(U64), metrics: FontMetrics } works better. Then roc-ray provides a default_font which has key 0 and precomputed font metrics.
I see it already changed in the elm-architecture branch. I’ll take a closer look soon
@Luke Boswell I migrated terrocotta to spike/elm-architecture and it is looking good. init!, update, render! is clean. Mouse and Keys are clean. Text measurement is clean, Font is better but still awkward at times.
However being generic over the host's AssetsHost.Texture interface was very noisy. So I added a shared types/Texture.roc in this PR https://github.com/lukewilliamboswell/roc-ray/pull/157
I might have other smaller change requests but for now this is the only big one.
Here is the terrocotta diff for reference https://github.com/obust/terrocotta/pull/52
Thank you, do you think we can commit to this architecture? It started as a spike but I'm becoming more convinced we should go with it
I've been very distracted with PDF's lately and haven't given roc-ray much love
There is a lot of changing parts in this branch.
I think the ./types package is a must have. Currently terrocotta cannot work on 0.9.0 and that is the answer to it.
The mouse and keys are much better to work with than the bit arrays, but are they as efficient ?
The init!, update, render! split with separate render thread is a nice fit with terrocotta which is an immediate mode UI. It also sounds relevant to other raylib use cases like Games/PhysicsSimulation/? but I can't fully speak for those domains.
So overall the abstractions are nicer to work with, but are they zero cost ?
Usually other languages provide a zero cost layer first, then build abstractions on top for convenience.
For example Rust's raylib-sys for low-level/raw FFI bindings and raylib the idiomatic Rust wrapper over raylib-sys.
In that mindset, roc-ray would stick to raylib-sys and provide only the standalone effectful functions. A separate roc package would provide the idiomatic abstractions on top.
However I don't know yet if that is possible/convenient in roc given the platform-app relationship.
I found some things to tighten up, and a bug in Roc's Box which is forcing the Model to be copied each frame.
I've got an RC with some big changes, and I'm looking for anyone who is interested and able to assist me testing the new features. I'm looking for feedback from someone building something, even if it's just simple. Does it all hang together nicely etc.
Let me know if you are interested.
https://github.com/lukewilliamboswell/roc-ray/releases/tag/0.10.0-rc2
I'm tracking a few compiler bugs which I would like to resolve before cutting the full 0.10.0 release. The docs and examples need polish and I want to do more testing on macos and windows.
I have some changes to Font for you here https://github.com/lukewilliamboswell/roc-ray/pull/175
and I have a suggested change to Task.spawn!() here https://github.com/lukewilliamboswell/roc-ray/issues/176
Here are some other add-hoc feedback
I think the Task direction is great with all the new IO capabilities (Http/Files/Socket/etc.). It is a big milestone that I am happy to work with in its current form. I only have toy examples and I am sure it will fail somehow on bigger scenarios (in particular, the issue Task.spawn_with!() is trying to address). I can't project that far. Maybe more forward looking, but do we know how this will play with the roc 0.2.0 plan on concurrency ?
Text.rocIt is doing half of the job of text layout. The current half and the second half are opinionated and I don't think roc-ray should take a stance here.
So I think it is a "nice to have" to simplify the demos but roc-ray should not assume end user will use it. In particular, Draw.text!() must not make alignment mandatory https://github.com/lukewilliamboswell/roc-ray/blob/main/platform/Draw.roc#L1371. It Draw should be "alignment-free" and all text layout utilities should be scoped in Text.roc.
PR : https://github.com/lukewilliamboswell/roc-ray/pull/177
Draw.rectangle! and Draw.rounded_rectangle!Draw.rectangle! and Draw.rounded_rectangle! for background fill and Draw.border! and Draw.rounded_border! for strokeNB: I will make a PR for that
DrawHost.roc effectsThese effects do not belong to "Drawing"
default_font! : () => Font.Handle
startup_default_font! : () => FontResult
font_metrics! : Font.Handle => FontMetrics
load_font_bytes! : LoadFontBytes => FontResult
load_store_font! : LoadStoreFont => FontResult
load_render_texture! : RenderTextureSize => RenderTextureResult
load_shader_source! : LoadShaderSource => ShaderResult
load_store_shader! : LoadStoreShader => ShaderResult
font_metrics! : Font.Handle => FontMetrics
prepare_text! : PrepareText => PrepareTextResult
These effects should be renamed for consistency
draw_prepared_text! to text_prepared!
draw_texture! to texture!
draw_texture_instances! to texture_instances!
draw_texture_quad! to texture_quad!
As a comparision point, here are the drawing primitives that the Clay project found useful to expose
https://github.com/nicbarker/clay/blob/main/renderers/raylib/raylib.h#L1246
main.roc. This makes reviewing easier, hopefully making the example main logic stand out. Also it will help see if there are patterns regarding what applications abstract/organize around.Physics.roctypes/Mouse.roc/platform/Mouse.roc/platform/MouseHost.roc splits of the application/host boundaryMouseHost.roc/HostHost.roc/DrawHost.roc/etc. to MouseABI.roc/HostABI.roc/DrawABI.rocABI.roc or FFI.roc with all the flat standalone effectful functions like in this raylib header file. Then Mouse.roc/Host.roc/Draw.roc repurpose the standalone functions into public facing types with methods. We can drop all MouseABI.roc/HostABI.roc/DrawABI.roc/etc.Audio.roc synthesisTime.rocInstant and Duration/Date/Calendar should be other packages. There has been discussions around this but I have not followed closely.Romain Lepert said:
the issue
Task.spawn_with!()is trying to address
I've spent some time looking into this and I think I need more time
Romain Lepert said:
It is doing half of the job of text layout. The current half and the second half are opinionated and I don't think roc-ray should take a stance here.
I think in general we should lean towards the more minimal api surface... I am leaning towards pulling things like this and physics out into separate packages. Moving types too.
So we might have something like this maybe -- the hope is that someday people will make nicer libraries like terracotta and we can retire these.
/packages
/types
/physics
/simple-text
/simple-plotting
Romain Lepert said:
- I would rename
MouseHost.roc/HostHost.roc/DrawHost.roc/etc. toMouseABI.roc/HostABI.roc/DrawABI.roc
I agree, the current multi-file split is a holdover from the approach I took with the last two API migrations... but I think we're in a position we could put them all in a fat HostABI.roc again
Romain Lepert said:
- Maybe roc-ray can provide some mixing features
My gut feeling is we sit on any Audio changes for a little .. I suspect as we build more capable graphics applications we might find things in this space.
Romain Lepert said:
Duration/Date/Calendarshould be other packages
Agree I think these were in here for the demos/examples, but we should probably just vendor a simple Calendar.roc next to any example that uses that, or use a package. I've tried to keep things simpler while Roc is less stable and avoid too many dependencies as versions and updates can be a pain.
I've been a little distracted working on other things for roc-ray ... :smile: https://github.com/lukewilliamboswell/roc-ray/issues/178
I'm imagining a web interface or dashboard you can drop this stats file in and have interactive views of the app run... like flame graphs but way more detail
That would be super valuable !
Well Codex just hit me with another usage reset ... so I'm going to throw some tokens at this observation spike :grinning_face_with_smiling_eyes:
Here it is... and it's kind of awesome https://github.com/lukewilliamboswell/roc-ray/pull/182
@Luke Boswell
Here is the Host ABI refactoring https://github.com/lukewilliamboswell/roc-ray/pull/184
Importantly I made Host.roc ABI public.
As mentioned in the PR description:
This is for libraries (e.g. terrocotta) to be generic over a single Host effects rather than over many public Draw/Window/Mouse/etc. effects. Libraries cannot import concrete types that carry effects, so any effect a library abstracts over needs to be behind a generic interface; exposing the single structural HostABI transport lets a library be parameterized once over Host instead of threading generics over every public capability module.
this will unlock mouse_set_cursor!, read_clipboard!/set_clipboard_text!, a canvas element and more for terrocotta
Romain Lepert said:
This is for libraries (e.g. terrocotta) to be generic over a single
Hosteffects rather than over many publicDraw/Window/Mouse/etc. effects. Libraries cannot import concrete types that carry effects, so any effect a library abstracts over needs to be behind a generic interface; exposing the single structuralHostABItransport lets a library be parameterized once overHostinstead of threading generics over every public capability module.
Would you mind sharing an example or code snippet? I'm wondering if this is by design or something we should think about for Roc
We have a way to group where clauses behind an alias, and I assume you can use effectful functions just like pure ones with that -- I haven't tried it yet
Yeah, I think this something we should think about for Roc.
so we could have mouse.Mouseable, window.Windowable, frame.Drawable but we have nothing that implements all of these. So we have to pass Mouse, Window, Draw, etc.
for terrocotta, it means Model : Program.State(AppModel, Msg, Mouse, Window, Frame, etc.)
and then Program has to pass each of these down the stack to the function that needs each.
It makes everything generic and pollutes the code like the function coloring problem. Terrocotta does not want to be generic over these. I believe there is a real discussion to have around this subject for Roc.
this this old PR for mouse https://github.com/obust/terrocotta/pull/49/changes
At least with the public Host.roc then there is just one to pass around and functions pick their interfaces. Also for terrocotta many of the "convenience" build on top of Host.roc just don't work. I want the barebone ABI and rework the abstractions. For now that is the best and maybe in the future we can agree on what's best overall.
by conveniences I mean these kinds
# Draw.roc
rectangle! : Frame, Rectangle => {}
rectangle! = |_frame, cfg| {
match cfg.style.fill {
NoFill => {}
Fill(color) => Host.draw_rectangle!({ x: cfg.x, y: cfg.y, width: cfg.width, height: cfg.height, color })
}
match cfg.style.stroke {
NoStroke => {}
Stroke(stroke_cfg) => Host.draw_rectangle_lines!({ x: cfg.x, y: cfg.y, width: cfg.width, height: cfg.height, color: stroke_cfg.color, thickness: stroke_cfg.thickness })
}
}
This just is worse for terrocotta. I better have Host.draw_rectangle! and Host.draw_line! so I can provide a more flexible way to do borders per side
canvas is also a good example of why where clause are not a good fit. once i build it, it will be easier to demonstrate the UX regression if i were to use where clauses
I don't have all the details here but I am very confident that exposing Host to application authors is not the answer :sweat_smile:
there's been an extreme level of design work done to prevent application authors from needing to know what the host is unless they are doing some low-level performance optimization
so let's not undo all that by exposing it directly to them! :smile:
is the overall goal to be able to have a layout library that can be easily used by not only roc-ray but also other platforms?
Richard Feldman said:
I don't have all the details here but I am very confident that exposing
Hostto application authors is not the answer :sweat_smile:
The problem is that i am developing a library, not an application.
The library needs the Host to abstract effects.
The application needs the library.
So the intent is not to expose the Host to the app. But allowing to expose to the library opens the door for the app as well, even if it is not going to be the recommended path.
I can guess your answer: Your library should be part of the platform.
But I honestly don't find this like a compelling solution everywhere...
Richard Feldman said:
is the overall goal to be able to have a layout library that can be easily used by not only roc-ray but also other platforms?
No right now I am not trying to make it platform agnostic. I'd like to make it work for roc-ray only. Still it is an opinionated way to expose UI and layout which might be too heavy for certain use cases. So I am not convinced the answer it to pull the library into the platform.
So right now there is no real way for an ecosystem to build around a Host effectful set of function without the host just exposing its FFI and letting the libraries build the abstractions.
so all i am asking for right now is the keys to the host. Let me build the best UX i can. Then we can remove the keys and see the UX regression. Only then we see the true cost of this hard platform boundary.
gotcha! In that case, since it's coupled to roc-ray, wouldn't it be easier to just build right there in roc-ray itself instead of introducing a separate package boundary? That sounds like it would be much easier for iteration :smile:
2 messages were moved from this topic to #ideas > Platform extensibility using bundle of effects pattern by Luke Boswell.
Richard Feldman said:
gotcha! In that case, since it's coupled to roc-ray, wouldn't it be easier to just build right there in roc-ray itself instead of introducing a separate package boundary? That sounds like it would be much easier for iteration :smile:
Do you mean to pull terrocotta in roc-ray so that it is not a package but just code that is part of the platform ?
If so, yes that would make my life easier, but in general platform packages won't have the privilege to live in the platform codebase. So that would bias the development experience, wouldn't it ? And it has to be a true package eventually so it has to be able to work without platform access, right ?
@Luke Boswell
This PR fixes the Host.roc resource handle contract (cannot manufacture handles) and fixes the effects to return Try(ok, err) types instead of the hand-decoded err : U8 sentinels.
https://github.com/lukewilliamboswell/roc-ray/pull/187
I reached token limit so i can't finish the refactor (see TODOs). Feel free to pick it up if you agree with the intent and have tokens to spare.
What this means is that all Host.roc effects are safe and "ergonomic" to use publically.
The caviat is that Host.roc are not always legal to call depending on the program init!, update!, render!, Task lifecycle.
| Effect | init! |
update! |
render! |
Task |
|---|---|---|---|---|
| Supposed effect-set carrier | App.Startup |
App.Input(msg) |
Draw.Frame |
None (host-tracked task phase) |
texture_load_store! |
✓ | — | — | ✓ |
texture_load_bytes! |
✓ | ✓ | — | ✓ |
texture_generate_color! |
✓ | ✓ | — | ✓ |
texture_generate_checked! |
✓ | ✓ | — | ✓ |
texture_update! |
✓ | ✓ | — | ✓ |
texture_update_region! |
✓ | ✓ | — | ✓ |
texture_set_filter! |
✓ | ✓ | — | ✓ |
texture_set_wrap! |
✓ | ✓ | — | ✓ |
texture_load_render_target! |
✓ | ✓ | — | ✓ |
text_default_font! |
✓ | ✓ | — | ✓ |
text_startup_default_font! |
✓ | — | — | — |
text_load_font! |
✓ | ✓ | — | ✓ |
text_load_store_font! |
✓ | — | — | ✓ |
text_prepare! |
✓ | ✓ | — | ✓ |
shader_load_source! |
✓ | ✓ | — | ✓ |
shader_load_store! |
✓ | — | — | ✓ |
shader_location! |
✓ | ✓ | — | ✓ |
shader_set_float! |
— | — | ✓ | — |
shader_set_int! |
— | — | ✓ | — |
shader_set_vec2! |
— | — | ✓ | — |
shader_set_vec3! |
— | — | ✓ | — |
shader_set_vec4! |
— | — | ✓ | — |
shader_set_texture! |
— | — | ✓ | — |
store_open! |
✓ | — | — | ✓ |
mouse_set_cursor_mode! |
✓ | ✓ | — | ✓ |
mouse_set_cursor! |
✓ | ✓ | — | ✓ |
trace_mark! |
✓ | ✓ | ✓ | ✓ |
trace_begin! |
✓ | ✓ | ✓ | ✓ |
trace_end! |
✓ | ✓ | ✓ | ✓ |
trace_sample_i64! |
✓ | ✓ | ✓ | ✓ |
trace_sample_f64! |
✓ | ✓ | ✓ | ✓ |
time_now! |
✓ | ✓ | — | ✓ |
task_sleep! |
✓ | — | — | ✓ |
task_spawn! |
— | ✓ | — | ✓ |
audio_gen_tone! |
✓ | ✓ | — | ✓ |
audio_gen_sound! |
✓ | ✓ | — | ✓ |
audio_load_sound! |
✓ | — | — | ✓ |
audio_load_music! |
✓ | — | — | ✓ |
audio_play_sound! |
✓ | ✓ | — | ✓ |
audio_stop_sound! |
✓ | ✓ | — | ✓ |
audio_pause_sound! |
✓ | ✓ | — | ✓ |
audio_resume_sound! |
✓ | ✓ | — | ✓ |
audio_is_sound_playing! |
✓ | ✓ | ✓ | ✓ |
audio_set_sound_volume! |
✓ | ✓ | — | ✓ |
audio_set_sound_pitch! |
✓ | ✓ | — | ✓ |
audio_set_sound_pan! |
✓ | ✓ | — | ✓ |
audio_play_music! |
✓ | ✓ | — | ✓ |
audio_stop_music! |
✓ | ✓ | — | ✓ |
audio_pause_music! |
✓ | ✓ | — | ✓ |
audio_resume_music! |
✓ | ✓ | — | ✓ |
audio_set_music_volume! |
✓ | ✓ | — | ✓ |
audio_set_music_pitch! |
✓ | ✓ | — | ✓ |
audio_set_music_pan! |
✓ | ✓ | — | ✓ |
audio_set_music_looping! |
✓ | ✓ | — | ✓ |
audio_is_music_playing! |
✓ | ✓ | ✓ | ✓ |
audio_seek_music! |
✓ | ✓ | — | ✓ |
audio_music_length! |
✓ | ✓ | ✓ | ✓ |
audio_music_time_played! |
✓ | ✓ | ✓ | ✓ |
audio_set_master_volume! |
✓ | ✓ | — | ✓ |
files_read_text! |
✓ | — | — | ✓ |
files_metadata! |
✓ | — | — | ✓ |
files_read_bytes! |
✓ | — | — | ✓ |
files_list! |
✓ | — | — | ✓ |
files_write_text! |
✓ | — | — | ✓ |
files_write_bytes! |
✓ | — | — | ✓ |
http_send! |
✓ | — | — | ✓ |
cmd_run! |
✓ | — | — | ✓ |
stdio_write_text! |
✓ | ✓ | — | ✓ |
stdio_write_line! |
✓ | ✓ | — | ✓ |
stdio_write_bytes! |
✓ | ✓ | — | ✓ |
udp_bind! |
✓ | ✓ | — | ✓ |
udp_send! |
✓ | ✓ | — | ✓ |
udp_receive! |
✓ | — | — | ✓ |
app_exit! |
✓ | — | — | — |
app_args! |
✓ | — | — | — |
app_read_env! |
✓ | — | — | — |
app_read_text! |
✓ | — | — | — |
random_entropy! |
✓ | — | — | — |
random_i32! |
✓ | — | — | — |
keys_set_exit_key! |
✓ | ✓ | — | ✓ |
window_read_clipboard! |
✓ | ✓ | — | ✓ |
window_set_clipboard_text! |
✓ | ✓ | — | ✓ |
window_suggest_size! |
✓ | ✓ | — | ✓ |
window_set_target_fps! |
✓ | ✓ | — | ✓ |
window_suggest_min_size! |
✓ | ✓ | — | ✓ |
window_scale_dpi! |
✓ | ✓ | ✓ | ✓ |
window_monitors! |
✓ | ✓ | — | ✓ |
window_suggest_position! |
✓ | ✓ | — | ✓ |
window_suggest_monitor! |
✓ | ✓ | — | ✓ |
tilemap_load_tmx! |
✓ | — | — | ✓ |
tilemap_draw! |
— | — | ✓ | — |
sqlite_open! |
✓ | — | — | ✓ |
sqlite_close! |
✓ | — | — | ✓ |
sqlite_prepare! |
✓ | — | — | ✓ |
sqlite_run_stmt! |
✓ | — | — | ✓ |
sqlite_run_once! |
✓ | — | — | ✓ |
sqlite_exec_script! |
✓ | — | — | ✓ |
draw_begin_camera! |
— | — | ✓ | — |
draw_end_camera! |
— | — | ✓ | — |
draw_begin_blend! |
— | — | ✓ | — |
draw_end_blend! |
— | — | ✓ | — |
draw_begin_render_texture! |
— | — | ✓ | — |
draw_end_render_texture! |
— | — | ✓ | — |
draw_begin_scissor! |
— | — | ✓ | — |
draw_end_scissor! |
— | — | ✓ | — |
draw_begin_shader! |
— | — | ✓ | — |
draw_end_shader! |
— | — | ✓ | — |
draw_circle! |
— | — | ✓ | — |
draw_circle_gradient! |
— | — | ✓ | — |
draw_circle_lines! |
— | — | ✓ | — |
draw_clear! |
— | — | ✓ | — |
draw_fps! |
— | — | ✓ | — |
draw_line! |
— | — | ✓ | — |
draw_draw_prepared_text! |
— | — | ✓ | — |
draw_frame_size! |
— | — | ✓ | — |
draw_polygon! |
— | — | ✓ | — |
draw_polygon_lines! |
— | — | ✓ | — |
draw_rectangle! |
— | — | ✓ | — |
draw_rectangle_gradient_h! |
— | — | ✓ | — |
draw_rectangle_gradient_v! |
— | — | ✓ | — |
draw_rectangle_lines! |
— | — | ✓ | — |
draw_rounded_rectangle! |
— | — | ✓ | — |
draw_rounded_rectangle_lines! |
— | — | ✓ | — |
draw_text! |
— | — | ✓ | — |
draw_draw_texture! |
— | — | ✓ | — |
draw_draw_texture_instances! |
— | — | ✓ | — |
draw_draw_texture_quad! |
— | — | ✓ | — |
draw_triangle! |
— | — | ✓ | — |
draw_triangle_lines! |
— | — | ✓ | — |
capture_set_virtual_mouse! |
✓ | ✓ | — | ✓ |
capture_set_virtual_keys! |
✓ | ✓ | — | ✓ |
capture_set_virtual_text! |
✓ | ✓ | — | ✓ |
capture_start_recording! |
✓ | ✓ | — | ✓ |
capture_stop_recording! |
✓ | ✓ | — | ✓ |
capture_screenshot! |
— | — | — | ✓ |
capture_screenshot_texture! |
✓ | — | — | ✓ |
capture_pixel_at! |
✓ | ✓ | — | ✓ |
capture_read_region! |
✓ | ✓ | — | ✓ |
My believe is that the lifecycle effect carriers should carry their respective Host.roc effects AS-IS without any modification.
roc-ray/typesroc-ray/platform/Host.roc (private)App.Startup App.Input(msg) Draw.Frame (public)Then packages can build whatever abstraction their need on top of roc-ray/types and where clauses or effect bundles "Alternative package API".
However, none of these should live in core roc-ray because none of these abstractions is low level enough to meet all the roc-ray use cases (GUI, Games, Plotting, etc.)
For example, this opinionated Flexible Drawing API must not be the common denominator for drawing.
in particular you could have a simple-demo package that gives you the simple adapters you need to make the demo examples digestable. Then the demos can do simple_frame = simple_draw(frame) to get whatever API is useful for demos
Last updated: Sep 03 2026 at 15:16 UTC