zig-raylib-5.5
Zig raylib 5.5 Bindings Reference
Idiomatic Zig bindings for raylib 5.5, wrapping the C API with Zig patterns: error unions, optionals, slices, and defer-based resource management.
Version: raylib 5.5+ (raylib-zig bindings) Minimum Zig: 0.15.1
Critical: Build Configuration
build.zig.zon Dependency
.dependencies = .{
.raylib_zig = .{
.url = "git+https://github.com/raylib-zig/raylib-zig#main",
.hash = "...", // Get from build error on first run
},
},
build.zig Setup
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Get raylib-zig dependency
const raylib_dep = b.dependency("raylib_zig", .{
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = "my-game",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
// Add raylib module and link library
exe.root_module.addImport("raylib", raylib_dep.module("raylib"));
exe.root_module.linkLibrary(raylib_dep.artifact("raylib"));
// Optional: add raygui for GUI widgets
exe.root_module.addImport("raygui", raylib_dep.module("raygui"));
b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run", "Run the game");
run_step.dependOn(&run_cmd.step);
}
Import in Code
const rl = @import("raylib");
Critical: Basic Game Loop
const rl = @import("raylib");
pub fn main() !void {
// Initialize window
rl.initWindow(800, 450, "My Game");
defer rl.closeWindow();
rl.setTargetFPS(60);
// Main game loop
while (!rl.windowShouldClose()) {
// Update game state here
// Draw
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawText("Hello, raylib!", 190, 200, 20, .dark_gray);
}
}
Critical: Error Handling Pattern
All loading functions return RaylibError!T:
pub const RaylibError = error{
LoadFileData, LoadImage, LoadTexture, LoadRenderTexture,
LoadFont, LoadFontData, LoadShader, LoadModel,
LoadModelAnimations, LoadMaterial, LoadMaterials,
LoadWave, LoadSound, LoadMusic, LoadAudioStream,
// ... and more
};
Use try for loading resources:
const texture = try rl.loadTexture("assets/sprite.png");
defer rl.unloadTexture(texture);
const model = try rl.loadModel("assets/character.glb");
defer rl.unloadModel(model);
const shader = try rl.loadShader(null, "shaders/effect.fs");
defer rl.unloadShader(shader);
Critical: Common Mistakes (WRONG vs CORRECT)
// WRONG: Importing raymath as a separate module
const raymath = @import("raymath");
// CORRECT: Access raymath through the raylib module
const rl = @import("raylib");
// then use: rl.math.clamp(), rl.math.lerp(), rl.math.matrixMultiply(), etc.
// WRONG: Importing rlgl as a separate module
const rlgl = @import("rlgl");
// CORRECT: Access rlgl through the raylib module
const rlgl = rl.gl; // or use rl.gl.* directly
// WRONG: Calling play as a method on sound
sound.play();
// CORRECT: Use free function for sound playback
rl.playSound(sound);
// WRONG: Calling crossProduct as a method on Vector2
const cross = v1.crossProduct(v2);
// CORRECT: Vector2 crossProduct is a FREE FUNCTION only
const cross = rl.math.vector2CrossProduct(v1, v2);
// NOTE: Vector3 DOES have crossProduct as a method: v1.crossProduct(v2)
// WRONG: Using try on functions that don't return error unions
const s = try rl.loadSoundFromWave(wave);
const a = try rl.loadSoundAlias(sound);
const img = try rl.getClipboardImage();
// CORRECT: These return their types directly (no error union)
const s = rl.loadSoundFromWave(wave);
const a = rl.loadSoundAlias(sound);
const img = rl.getClipboardImage();
// WRONG: Expecting raygui button() to return i32
const result: i32 = rg.button(bounds, "Click");
// CORRECT: raygui button() returns bool
if (rg.button(bounds, "Click")) { ... }
// WRONG: Passing const slice to raygui textBox
rg.textBox(bounds, "text", 64, editMode);
// CORRECT: textBox requires a mutable [:0]u8 slice
var buf: [64:0]u8 = .{0} ** 64;
_ = rg.textBox(bounds, &buf, 64, editMode);
Critical: Resource Management with Defer
Always pair load with unload using defer:
pub fn main() !void {
rl.initWindow(800, 600, "Game");
defer rl.closeWindow();
rl.initAudioDevice();
defer rl.closeAudioDevice();
const texture = try rl.loadTexture("sprite.png");
defer rl.unloadTexture(texture);
const sound = try rl.loadSound("jump.wav");
defer rl.unloadSound(sound);
const font = try rl.loadFont("font.ttf");
defer rl.unloadFont(font);
// Game loop...
}
Critical: Type Initialization Patterns
Vector2, Vector3, Vector4
// Named init function
const pos = rl.Vector2.init(100, 200);
const pos3d = rl.Vector3.init(1, 2, 3);
// Static constructors
const zero = rl.Vector2.zero();
const one = rl.Vector3.one();
// Anonymous struct literal (type inferred from context)
rl.drawCircleV(.{ .x = 100, .y = 200 }, 50, .red);
rl.drawCube(.{ .x = 0, .y = 0, .z = 0 }, 2, 2, 2, .blue);
// When assigning to a typed variable
var target: rl.Vector2 = .{ .x = 400, .y = 300 };
Color
// Named colors (use directly)
rl.clearBackground(.ray_white);
rl.drawRectangle(10, 10, 100, 50, .red);
// Custom color
const custom = rl.Color.init(128, 64, 255, 255);
// Color utilities
const faded = rl.fade(.blue, 0.5); // 50% transparent blue
const tinted = color.tint(.red); // Apply tint
Rectangle
// Full struct literal
var rect = rl.Rectangle{ .x = 10, .y = 10, .width = 100, .height = 50 };
// Init function
const rect2 = rl.Rectangle.init(10, 10, 100, 50);
// Collision check method
if (rect.checkCollision(rect2)) {
// Collision detected
}
Critical: Drawing Context Pattern
All drawing must occur between beginDrawing/endDrawing:
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
// 2D shapes
rl.drawRectangle(10, 10, 100, 50, .red);
rl.drawCircle(200, 200, 50, .blue);
rl.drawLine(0, 0, 800, 450, .black);
// Text
rl.drawText("Score: 100", 10, 10, 20, .dark_gray);
// Textures
texture.draw(100, 100, .white);
Camera2D Pattern
var camera = rl.Camera2D{
.target = .init(player.x, player.y),
.offset = .init(screenWidth / 2, screenHeight / 2),
.rotation = 0,
.zoom = 1,
};
// In game loop:
camera.target = .init(player.x, player.y); // Follow player
camera.zoom += rl.getMouseWheelMove() * 0.1;
// Drawing with camera
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
{
camera.begin();
defer camera.end();
// Draw world objects (affected by camera)
rl.drawRectangleRec(player, .red);
for (enemies) |enemy| {
rl.drawCircleV(enemy.pos, enemy.radius, .blue);
}
}
// Draw UI (not affected by camera)
rl.drawText("Score: 100", 10, 10, 20, .black);
Camera3D Pattern
var camera = rl.Camera3D{
.position = .init(10, 10, 10),
.target = .init(0, 0, 0),
.up = .init(0, 1, 0),
.fovy = 45,
.projection = .perspective,
};
// Update camera with built-in modes
camera.update(.orbital); // Orbit around target
// camera.update(.free); // Free movement
// camera.update(.first_person);
// camera.update(.third_person);
// Drawing 3D
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
{
camera.begin(); // or: rl.beginMode3D(camera);
defer camera.end();
// Draw 3D objects
rl.drawGrid(10, 1);
rl.drawCube(.init(0, 1, 0), 2, 2, 2, .red);
model.draw(.init(0, 0, 0), 1.0, .white);
}
// Draw 2D UI
rl.drawFPS(10, 10);
Input Handling
Keyboard
// Check if key was just pressed (single frame)
if (rl.isKeyPressed(.space)) {
player.jump();
}
// Check if key is being held down (continuous)
if (rl.isKeyDown(.right)) {
player.x += speed * dt;
} else if (rl.isKeyDown(.left)) {
player.x -= speed * dt;
}
// Check if key was just released
if (rl.isKeyReleased(.escape)) {
showMenu();
}
Mouse
// Mouse buttons
if (rl.isMouseButtonPressed(.left)) {
shoot();
}
if (rl.isMouseButtonDown(.right)) {
aim();
}
// Mouse position
const mousePos = rl.getMousePosition();
const worldPos = rl.getScreenToWorld2D(mousePos, camera);
// Mouse wheel
const wheelMove = rl.getMouseWheelMove();
camera.zoom += wheelMove * 0.1;
Gamepad
if (rl.isGamepadAvailable(0)) {
if (rl.isGamepadButtonPressed(0, .right_face_down)) { // A button
player.jump();
}
const axisX = rl.getGamepadAxisMovement(0, .left_x);
if (@abs(axisX) > 0.2) { // Dead zone
player.x += axisX * speed * dt;
}
}
Collision Detection
2D Collisions
// Rectangle vs Rectangle
if (rl.checkCollisionRecs(rect1, rect2)) {
// Handle collision
}
// Circle vs Circle
if (rl.checkCollisionCircles(center1, radius1, center2, radius2)) {
// Handle collision
}
// Circle vs Rectangle
if (rl.checkCollisionCircleRec(circleCenter, radius, rect)) {
// Handle collision
}
// Point vs Rectangle
if (rl.checkCollisionPointRec(point, rect)) {
// Point inside rectangle
}
// Point vs Circle
if (rl.checkCollisionPointCircle(point, center, radius)) {
// Point inside circle
}
// Line vs Line (returns collision point)
var collisionPoint: rl.Vector2 = undefined;
if (rl.checkCollisionLines(start1, end1, start2, end2, &collisionPoint)) {
// Lines intersect at collisionPoint
}
3D Collisions
// Sphere vs Sphere
if (rl.checkCollisionSpheres(center1, radius1, center2, radius2)) {
// Collision
}
// Box vs Box
if (rl.checkCollisionBoxes(box1, box2)) {
// Collision
}
// Box vs Sphere
if (rl.checkCollisionBoxSphere(box, sphereCenter, sphereRadius)) {
// Collision
}
Quick Reference
Named Colors: .white, .black, .ray_white, .blank, .red, .green, .blue, .yellow, .orange, .pink, .purple, .gray, .dark_gray, .light_gray, .gold, .lime, .sky_blue, .maroon, .violet, .beige, .brown, .dark_brown, .dark_green, .dark_purple, .magenta — or rl.Color.init(r, g, b, a) for custom.
Key Codes: .a-.z, .zero-.nine, .f1-.f12, .space, .enter, .escape, .tab, .backspace, .delete, .up/.down/.left/.right, .left_shift, .left_control, .left_alt
Mouse Buttons: .left, .right, .middle, .side, .extra, .forward, .back
Module Reference
Core
- Core API - Window, input, timing, Camera2D
- Drawing API - 2D shapes, textures, text, collision
- 3D API - Camera3D, models, animation, shaders, PBR
- Math & GL API - raymath (
rl.math.*), rlgl (rl.gl.*)
GUI
- Raygui API - GUI widgets, styling, dialogs
Resources
- Resources API - Loading/unloading patterns
Audio
- Audio API - Sound, music, streaming
Examples
- Code Examples - Complete example patterns