Raylib

Using Chasm with the Raylib game engine, setup, API, and running your first game.

Raylib is a simple, open-source C game library. Chasm ships with a complete Raylib binding, compile with --engine raylib and the full Raylib API is available in your script.

Setup

1

Install Raylib

On macOS:

brew install raylib

On Linux:

sudo apt install libraylib-dev
2

Run with the Raylib engine

chasm run --engine raylib game.chasm

The CLI compiles your script and links it against Raylib automatically.

3

Watch mode (hot reload)

chasm watch --engine raylib game.chasm

Save the file → the engine reloads your script instantly without restarting.

Script Structure

A Raylib Chasm script uses on_init, on_tick, and on_draw:

@player_x  = 400.0
@player_y  = 300.0
@speed  = 200.0

def on_init() do
  # Called once at startup
end

def on_tick(dt :: float) do
  if key_down(key_code(:right)) do @player_x = @player_x + @speed * dt end
  if key_down(key_code(:left))  do @player_x = @player_x - @speed * dt end
  if key_down(key_code(:down))  do @player_y = @player_y + @speed * dt end
  if key_down(key_code(:up))    do @player_y = @player_y - @speed * dt end
end

def on_draw() do
  clear_background(0x181820ff)
  draw_rectangle(@player_x - 16.0, @player_y - 16.0, 32.0, 32.0, 0x4488ffff)
  draw_text("Move with arrow keys", 10.0, 10.0, 20, 0xffffffff)
end

Drawing

FunctionDescription
clear_background(color)Fill the screen with a solid color
draw_rectangle(x, y, w, h, color)Filled rectangle
draw_rectangle_lines(x, y, w, h, color)Outlined rectangle
draw_rect_rounded(x, y, w, h, r, seg, color)Filled rectangle with rounded corners
draw_circle(x, y, r, color)Filled circle
draw_circle_lines(x, y, r, color)Circle outline
draw_line(x1, y1, x2, y2, color)Line segment
draw_line_ex(x1, y1, x2, y2, thick, color)Line segment with thickness
draw_triangle(x1, y1, x2, y2, x3, y3, color)Filled triangle
draw_ellipse(cx, cy, rx, ry, color)Filled ellipse
draw_poly(cx, cy, sides, radius, rot, color)Filled regular polygon
draw_text(text, x, y, size, color)Text with built-in font
measure_text(text, size)Returns rendered width of text in pixels
draw_fps(x, y)Draw current FPS counter

Colors are 0xRRGGBBAA packed integers. Common values:

white             = 0xffffffff
black             = 0x000000ff
red               = 0xff0000ff
transparent_white = 0xffffff80   # 50% alpha

Input

Keyboard

FunctionReturnsDescription
key_down(key)boolTrue every frame the key is held
key_pressed(key)boolTrue only on the first frame the key is pressed
key_released(key)boolTrue only on the frame the key is released
key_up(key)boolTrue every frame the key is not held
key_last()intKeycode of the most recently pressed key
key_code(name)intConvert a key name atom to a keycode

Use key_code to convert atom names to integer keycodes:

# Move while held
if key_down(key_code(:right)) do @x = @x + @speed * dt end

# Fire once per press
if key_pressed(key_code(:space)) do fire_bullet() end

Key name atoms supported by key_code:

AtomKey
:right, :left, :up, :downArrow keys
:spaceSpace bar
:enterEnter / Return
:escapeEscape
:backspaceBackspace
:tabTab
:shift, :left_shift, :right_shiftShift
:ctrl, :left_ctrl, :right_ctrlControl
:alt, :left_alt, :right_altAlt
:a:zLetter keys
:0:9Digit keys
:f1:f12Function keys

You can also pass raw integer keycodes directly (e.g. key_down(262) for right arrow).

Mouse

FunctionReturnsDescription
mouse_x()floatCurrent mouse X position
mouse_y()floatCurrent mouse Y position
mouse_dx()floatMouse X delta since last frame
mouse_dy()floatMouse Y delta since last frame
mouse_down(button)boolTrue while button is held
mouse_pressed(button)boolTrue on the first frame button is pressed
mouse_released(button)boolTrue on the frame button is released
mouse_wheel()floatMouse wheel scroll delta

Mouse button indices: 0 = left, 1 = right, 2 = middle.

Screen

FunctionReturnsDescription
screen_width()intCurrent window width in pixels
screen_height()intCurrent window height in pixels
fps()intCurrent frames per second
dt()floatSeconds elapsed since last frame
time()floatSeconds elapsed since startup
set_fps(fps)Set target frame rate
set_title(text)Set window title
set_window_size(w, h)Resize the window
toggle_fullscreen()Toggle fullscreen mode

Textures and Fonts

@player_tex :: persistent = 0
@font       :: persistent = 0

def on_init() do
  @player_tex = load_texture("assets/player.png")
  @font       = load_font("assets/mono.ttf")
end

def on_draw() do
  draw_texture(@player_tex, @player_x, @player_y, 0xffffffff)
  draw_text_ex(@font, "Score: #{@score}", 10.0, 10.0, 24.0, 1.0, 0xffffffff)
end

Load textures and fonts in on_init into persistent attrs so they survive hot-reload.

FunctionReturnsDescription
load_texture(path)intLoad a texture, returns handle
unload_texture(handle)Free a texture
draw_texture(handle, x, y, tint)Draw texture at position
draw_texture_ex(handle, x, y, rot, scale, tint)Draw with rotation and scale
draw_texture_rect(handle, sx, sy, sw, sh, dx, dy, tint)Draw a sub-region
texture_w(handle)intTexture width in pixels
texture_h(handle)intTexture height in pixels
load_font(path)intLoad a font, returns handle
draw_text_ex(font, text, x, y, size, spacing, color)Draw with custom font

Audio

@shoot_sfx :: persistent = 0

def on_init() do
  init_audio()
  @shoot_sfx = load_sound("assets/shoot.wav")
end

def on_tick(dt :: float) do
  if key_pressed(key_code(:space)) do
    play_sound(@shoot_sfx)
  end
end
FunctionReturnsDescription
init_audio()Initialize the audio device
load_sound(path)intLoad a sound, returns handle
play_sound(handle)Play a sound
stop_sound(handle)Stop a sound
sound_playing(handle)boolTrue if the sound is currently playing
sound_volume(handle, vol)Set volume (0.0–1.0)
load_music(path)intLoad streaming music, returns handle
play_music(handle)Start playing music
update_music(handle)Call each frame to stream music
stop_music(handle)Stop music
music_playing(handle)boolTrue if music is playing
music_length(handle)floatTotal duration in seconds
music_played(handle)floatCurrent playback position in seconds

Collision

FunctionReturnsDescription
collide_rects(x1, y1, w1, h1, x2, y2, w2, h2)boolRectangle vs rectangle
collide_circles(x1, y1, r1, x2, y2, r2)boolCircle vs circle
point_in_rect(px, py, rx, ry, rw, rh)boolPoint inside rectangle

Camera 2D

def on_draw() do
  camera2d_begin(@cam_x, @cam_y, @target_x, @target_y, 0.0, @zoom)
  # draw world-space objects here
  camera2d_end()
end
FunctionDescription
camera2d_begin(cx, cy, tx, ty, rot, zoom)Begin camera-transformed drawing
camera2d_end()End camera drawing
world_to_screen_x(wx, wy, cx, cy, tx, ty, rot, zoom)Convert world X to screen X
world_to_screen_y(wx, wy, cx, cy, tx, ty, rot, zoom)Convert world Y to screen Y

Gamepad

FunctionReturnsDescription
gamepad_available(pad)boolTrue if gamepad is connected (pad 0 = first)
gamepad_button_down(pad, btn)boolTrue while button is held
gamepad_button_pressed(pad, btn)boolTrue on first frame button pressed
gamepad_axis(pad, axis)floatAxis value -1.0 to 1.0