Make 2D games, visual tools, and interactive apps in Roc, powered by raylib.
RocRay is for smaller graphical programs, such as games, visualizations, and interactive tools. It is not meant to compete with large, purpose-built game engines: it has no editor, scene graph, physics engine, or asset pipeline. Your app keeps its own state and makes every decision itself; RocRay provides drawing, sound, keyboard, mouse and gamepad input, the window, recording, files, and networking. It runs on macOS (Intel and Apple silicon), Linux x86-64, and Windows x86-64.
RocRay draws in 2D today. 3D models, cameras, and lighting are planned but not yet available. RocRay is not a GUI toolkit: for desktop applications built from widgets such as buttons, text fields, and layouts, see roc-gui.
Start with Hello World, Pong, and Snake. These larger examples show what else it can do:
![]() Breakout Arcade gameplay, sounds made in code, recording |
![]() Pixel Workshop Drawing pixels and creating sounds in code |
![]() Responsive Settings Keyboard, mouse, resizing, display scaling |
![]() Postcard Studio Generative art and saving larger images |
![]() Particles Thousands of moving images at once |
![]() Capture UI Demo Automated controls and GIF recording |
![]() Live Plot Loading and drawing hundreds of thousands of lines |
![]() Spark Run Designed map, characters, music, game states |
![]() Cave Climb Designed level, jumping, camera |
- Open the latest release and install the Roc compiler its notes name, as Getting started describes.
- Download that release's
examples-<version>.zipand unzip it. - Open a terminal in the extracted directory, the one containing
examples/, and run:
roc version
roc examples/hello_world/main.rocA red circle that follows the mouse. Replace BUNDLE-URL and COMPILER with
the default bundle URL and the compiler the release notes name.
app [Model, program] { rr: platform "BUNDLE-URL", roc: "COMPILER" }
import rr.App
import rr.Color
import rr.Draw
Model : { pointer : { x : F32, y : F32 } }
Msg : []
program = { init!, update!, render! }
init! : App.Init(Model, [])
init! = App.init(App.default.with_title("Hello"), |_io| Ok({ pointer: { x: 400, y: 300 } }))
update! : Model, App.Input(Msg), App.Io => Try(Model, [Exit(I64)])
update! = |_model, input, _io| Ok({ pointer: input.devices.mouse.position() })
render! : Model, Draw.Frame => Try({}, [Exit(I64)])
render! = |model, frame| {
frame.clear!(Color.black)
frame.circle!({ center: model.pointer, radius: 40, style: Draw.filled(Color.red) })
Ok({})
}init! creates the starting state, update! uses each host cycle's input to
compute the next state, and render! draws it. Anything that waits, such as
reading a file or fetching a URL, runs as a task, and its result arrives in a
later update!. Anything the app accesses beyond its own window, such as the
network, a directory, or another program, is declared in its startup settings.
The RocRay manual is
published as a website and a PDF. Its chapters are the AsciiDoc files in
docs/, which you can also read here:
- Getting started: install, run an example, and write the smallest app
- Roc for RocRay: the Roc a small app uses
- Your first game: build a small game in six steps
- Example gallery: what each example shows, and a learning path
- Guides: the app model, input, drawing, tasks, permissions, files and assets, audio, HTTP and UDP, capture, testing, and performance
- Glossary
- API reference
- Architecture
- Contributing
- Release notes and the releases page
RocRay tracks recent nightly builds of the Roc compiler. Because Roc is still changing, RocRay's API may also change. Bug reports, documentation improvements, and focused new capabilities are welcome.








