The repository’s examples/ directory holds complete apps and focused
recipes. This chapter helps you choose which to read. It assumes you have run
an example, as [run-an-example] shows.
Each example is a directory with a main.roc. Choose the one closest to
what you want to build and copy its directory. For the released examples,
download the examples zip described in [run-an-example]. The examples in
the repository name the platform in the checkout instead, and may use APIs
that have not been released yet; [development-checkout] shows how to run
them.
Run every command from the directory that contains examples/, so the paths
the examples use for their files resolve. To try an example, run it with
roc:
roc examples/snake/main.rocTo build an executable you can run again, use roc build:
roc build examples/snake/main.roc --output=snake
./snakeEvery example quits when you press Escape unless its header says otherwise.
Work through these in order. Each one adds a little to the one before it.
-
Hello World (
hello_world): the complete app loop (init!,update!, andrender!) with drawing and the pointer, and nothing else. -
Move Box (
move_box): a box moved with the arrow keys. It introduces moving by speed times elapsed time, and a pure function tested withexpect. [first-game] grows the same idea into a whole game, one step at a time; Move Box shows the finished result on one page, ready to copy. -
Sprite and Sound (
sprite_and_sound): a picture and a sound loaded from files. It introduces a permission, an asset store, and loaded resources. -
Pong (
pong): one player against a computer paddle. It combines movement, collision, input, scoring, and sounds made in code in one approachable file. -
Snake (
snake): a grid game split across a few modules, with a fixed simulation step and seeded randomness. -
Task Sleep (
task_sleep): one task that waits, and the message it sends back. Read it before adding files, networking, or any other operation that waits.
Then pick a direction:
-
A game: Breakout, then Spark Run or Cave Climb.
-
A tool or an app interface: Pixel Workshop, Responsive Settings, or Input Inspector.
-
Files, networking, or storage: the examples under Tasks that wait.
-
A particular drawing technique: the Focused recipes.
| Example | What it is | Patterns to reuse |
|---|---|---|
Hello World |
A polished minimal interactive scene |
App lifecycle, prepared text, pointer input |
Move Box |
A box you steer with the arrow keys |
Movement by elapsed time, clamping the time step, keeping an object inside the window, testing a pure function |
Sprite and Sound |
A pixel-art blob that hops and plays a sound |
Declaring a directory, opening an asset store, loading a PNG texture and a WAV sound |
Pong |
One player against a computer paddle |
Movement by elapsed time, collision, scoring, sounds made in code |
Snake |
A grid-based game with restartable state |
Fixed simulation step, keyboard control, seeded randomness in the model |
Breakout |
A complete game that can record its own demo |
Separating game logic from effects, sounds played from game events, a recording mode |
Pixel Workshop |
A tiny paint program with a texture it changes as you paint |
Textures and sounds made in code, uploading one changed cell, a pure editor returning edits |
Responsive Settings |
A resizable settings screen |
Pure layout shared by |
Postcard Studio |
A generative postcard editor that exports at twice the window size |
Drawing into an offscreen texture, exporting it from a task, output directories |
Input Inspector |
A live view of every input device, and the clipboard |
Device snapshots, the ordered event record, clipboard, window changes, reading the pixel under the pointer, an app that keeps Escape for itself |
Drop Viewer |
An image viewer whose only control is dropping a file on it |
Accepting a dropped file, reading it in a task, choosing a decoder from the bytes |
Use these when copying the Task.spawn!(input, || ...) pattern described in
[tasks]. A task’s return value arrives as one Msg on a later
input.messages.
| Example | What it is |
|---|---|
Task Sleep |
One task, one |
Async Read |
Two file reads and a |
Capture Screenshot |
A screenshot saved in a task, and the output directory refusing a path that climbs out of it |
HTTP Fetch |
An HTTP GET in a task, which you can restart while it is still running; each reply includes the id of the fetch it belongs to |
UDP Cursor |
Two instances showing each other’s pointer: a receiving task that is started again each time it returns, and sends made straight from |
SQLite Scores |
A high-score board that survives a restart: the write and the re-read share one task, so the model always gets what the database actually contains |
Use these to see several systems working together in one app.
| Example | What it demonstrates |
|---|---|
Spark Run |
A top-down game: a level made in the Tiled map editor, sprites, collision, music, sound effects, a following camera, and several game states |
Cave Climb |
A platformer with a mirror-bouncing laser and a spring grapple: tilemaps, collision, and camera tracking, split across two modules |
Live Plot |
A whole source tree listed, read, and parsed through a bounded queue of tasks, and drawn as a scrolling strip of a quarter of a million points |
Use these as focused references, not starter projects.
| Example | Use it when you need… |
|---|---|
Camera World |
World and screen coordinates, a following camera, zoom, and rotation |
Projective Texture |
A draggable perspective-correct quad and points placed with the same projection |
Post Process |
Offscreen textures, blend modes, shaders, and shader settings |
Particles |
Thousands of sprites drawn in one batch rather than one call each |
Capture Plot |
A repeatable WebM recording made in a hidden window |
Capture UI Demo |
A repeatable interface recording driven through the real pointer and keyboard |
-
Each app names its three functions' parameters the same way:
init!takesio,update!takesmodel, input, ioand reads devices throughdevices = input.devices, andrender!takesmodel, frame. -
Keep application state in
Model; compute the next model fromApp.Inputin pure helper functions thatupdate!calls. -
Load and prepare long-lived resources once in
init!, then keep them in the model instead of recreating them every host cycle. -
Derive layout and view-only values with pure helpers. Use
frame.size!()for the surface being drawn to instead of copyinginput.window.sizeinto the model. -
Move by elapsed time, and clamp it: after a pause, one host cycle can report a second or more.
-
Call host effects directly from
update!when they return immediately; useTask.spawn!(input, || ...)for anything that waits, and update the model with its result when it arrives as a message on a laterinput.messages. -
Give each kind of task its own
Msgvariant. Add an id only when several tasks of the same kind may be running at once. -
Keep game logic in pure functions so
roc testcan check them without calling effectfulupdate!. -
Let
App.defaulthandle Escape. An app that needs Escape for itself setswith_exit_key(NoExitKey)and says why, as Input Inspector does. -
Keep capture, scripted input, and headless runs out of ordinary interaction: an example never saves, records, or quits by itself during an interactive run.
Exhaustive API probes and invalid-input cases belong in the repository’s
test/ directory, where they can be explicit without making an
example harder to understand.
The animations in the repository README are recorded by the examples
themselves. Breakout, Pixel Workshop, Responsive Settings, Postcard Studio,
Particles, Spark Run, and Live Plot each take a --record-demo argument:
roc examples/breakout/main.roc -- --record-demoThe window stays hidden, a scripted demo plays through the app’s normal input
path, and the recording is written to examples/gallery/<directory>.gif. The
app exits once the file is written. Every one of these apps follows the same
shape: a demo_recording value, started in init! when the argument is
present, and a pure demo_finished that ends the run when input.capture
reports the recording Finished or Failed.
An example declares, in its startup config, anything it accesses beyond its own resources, as [permissions] describes. Nothing is passed on the command line.
| Example | Declares | Why |
|---|---|---|
|
|
Loads its picture and sound from that directory |
|
|
Loads its shader from that directory |
|
|
Loads its map, textures, music, and sounds |
|
|
Loads its map and textures |
|
|
Reads files beneath the directory it runs from |
|
|
Lists and reads the whole tree it runs from |
|
|
Copies and pastes text |
|
|
Fetches that URL, and nothing else |
|
|
Sends and receives datagrams on this machine only |
|
No permission; names itself with |
Keeps its database in its own private data directory, which needs no declaration |
Every other example declares nothing. Printing, drawing, audio, sounds and textures made in code, a dropped file, and captures written beneath the output directory all need no declaration.
The recording examples list PermissionDenied among the errors init! can
return. It comes from Capture.Writer.start!, whose result type includes it;
the io that init! receives always has permission to record, so in these
examples it does not occur.