tiramisu/debug
Debug visualization utilities for game development.
This module provides tools for visualizing game elements during development:
- Debug shapes: Boxes, spheres, lines, rays, grids, axes, points
- Physics visualization: Collider wireframes and shapes
- Performance monitoring: FPS, frame time, draw calls, memory usage
- Color constants: Common debug colors for quick visualization
Usage
Debug visualizations are added to your scene just like regular nodes:
import tiramisu/debug
import vec/vec3
pub fn view(model: Model) {
[
// Your game objects
scene.Mesh(...),
// Debug visualizations
debug.axes("axes", vec3.zero(), 5.0),
debug.grid("grid", 20.0, 20, debug.color_white),
debug.sphere("target", target_position, 0.5, debug.color_red),
]
}
Performance Stats
Monitor your game’s performance in the update loop:
pub fn update(model: Model, msg: Msg, ctx: Context) {
let stats = debug.get_performance_stats()
io.println("FPS: " <> float.to_string(stats.fps))
// ...
}
Physics Debugging
Visualize physics colliders in your view function:
pub fn view(model: Model, ctx: Context) {
// Enable collider wireframes
case ctx.physics_world, model.debug_mode {
option.Some(physics_world), True ->
debug.show_collider_wireframes(physics_world, True)
_, _ -> Nil
}
// ... return scene nodes
}
Types
Performance statistics collected from the game engine.
Contains real-time performance metrics useful for optimization and debugging.
Fields
fps: Current frames per second (smoothed average)frame_time: Time in milliseconds to render the last framedraw_calls: Number of draw calls in the last frame (lower is better)triangles: Total number of triangles rendered in the last framememory_mb: Estimated GPU memory usage in megabytes
pub type PerformanceStats {
PerformanceStats(
fps: Float,
frame_time: Float,
draw_calls: Int,
triangles: Int,
memory_mb: Float,
)
}
Constructors
-
PerformanceStats( fps: Float, frame_time: Float, draw_calls: Int, triangles: Int, memory_mb: Float, )
Values
pub fn axes(
id: id,
origin: vec3.Vec3(Float),
size: Float,
) -> scene.Node(id)
Create coordinate axes visualization at a given position.
Displays X (red), Y (green), and Z (blue) axes to help visualize object orientation and world coordinates. This is particularly useful for understanding transformations and rotations.
Parameters
id: Unique identifier for this debug nodeorigin: Position where the axes should be centeredsize: Length of each axis line
Example
import tiramisu/debug
import vec/vec3
// Show world axes at origin
debug.axes("world-axes", vec3.zero(), 5.0)
// Show object-local axes
debug.axes("player-axes", player_position, 2.0)
pub fn bounding_box(
id: id,
min: vec3.Vec3(Float),
max: vec3.Vec3(Float),
color: Int,
) -> scene.Node(id)
Create a debug wireframe box defined by minimum and maximum corners.
Useful for visualizing bounding boxes, collision volumes, or spatial regions.
Parameters
id: Unique identifier for this debug nodemin: Minimum corner position (x, y, z)max: Maximum corner position (x, y, z)color: Hex color code (e.g.,0xff0000for red)
Example
import tiramisu/debug
import vec/vec3
// Visualize a bounding box from (-1, -1, -1) to (1, 1, 1)
debug.bounding_box(
"bounds",
vec3.Vec3(-1.0, -1.0, -1.0),
vec3.Vec3(1.0, 1.0, 1.0),
debug.color_cyan,
)
pub fn box_from_transform(
id: id,
t: transform.Transform,
color: Int,
) -> scene.Node(id)
Create a debug bounding box from a transform.
Convenient helper that extracts position and scale from a transform to create a bounding box visualization. Useful for visualizing object bounds in world space.
Parameters
id: Unique identifier for this debug nodet: Transform containing position and scale informationcolor: Hex color code for the box wireframe
Example
import tiramisu/debug
import tiramisu/transform
import vec/vec3
let cube_transform = transform.new()
|> transform.with_position(vec3.Vec3(0.0, 2.0, 0.0))
|> transform.with_scale(vec3.Vec3(2.0, 2.0, 2.0))
// Visualize the cube's bounds
debug.box_from_transform("cube-bounds", cube_transform, debug.color_orange)
pub fn collider(
id: id,
shape: physics.ColliderShape,
transform: transform.Transform,
color: Int,
) -> scene.Node(id)
Visualize a physics collider shape at a given transform.
This function converts a physics collider into debug visualization nodes that can be added to your scene for debugging physics shapes.
Example
import tiramisu/debug
import tiramisu/physics
import tiramisu/transform
import vec/vec3
pub fn view(model: Model) {
let body_transform = transform.at(position: vec3.Vec3(0.0, 5.0, 0.0))
let collider = physics.Box(width: 2.0, height: 2.0, depth: 2.0)
[
// Your normal scene nodes...
// Debug visualization for the collider
debug.collider(
id: "player-collider-debug",
shape: collider,
transform: body_transform,
color: debug.color_green,
),
]
}
pub const color_black: Int
Black color (0x000000) - Rarely used for debug visualization (not visible on dark backgrounds).
pub const color_blue: Int
Blue color (0x0000ff) - Commonly used for information, water, or Z-axis visualization.
pub const color_cyan: Int
Cyan color (0x00ffff) - Commonly used for secondary information or water/ice elements.
pub const color_green: Int
Green color (0x00ff00) - Commonly used for success, active states, or Y-axis visualization.
pub const color_magenta: Int
Magenta color (0xff00ff) - Commonly used for special markers or UI highlights.
pub const color_orange: Int
Orange color (0xffa500) - Commonly used for alerts, spawn points, or intermediate states.
pub const color_purple: Int
Purple color (0x800080) - Commonly used for special objects, power-ups, or tertiary markers.
pub const color_red: Int
Red color (0xff0000) - Commonly used for errors, warnings, or X-axis visualization.
pub const color_white: Int
White color (0xffffff) - Commonly used for grids, general outlines, or default markers.
pub const color_yellow: Int
Yellow color (0xffff00) - Commonly used for caution, highlights, or important markers.
pub fn cross(
id: id,
position: vec3.Vec3(Float),
size: Float,
color: Int,
) -> List(scene.Node(id))
Create a 3D cross (three perpendicular lines) at a position.
Useful for marking points in 3D space with a distinctive visual marker that’s visible from all angles, unlike a simple point.
Parameters
id: Unique identifier for all three lines (they share the same ID)position: Center position of the crosssize: Total length of each line (extends size/2 in each direction)color: Hex color code for all three lines
Returns
A list of three line nodes (X, Y, and Z aligned).
Example
import tiramisu/debug
import vec/vec3
// Mark a target position with a visible cross
debug.cross(
"target-marker",
target_position,
1.0,
debug.color_red,
)
pub fn get_performance_stats() -> PerformanceStats
Get current performance statistics from the renderer.
Returns real-time performance metrics that can be used for optimization, profiling, or displaying debug information to the user.
Example
import tiramisu/debug
import gleam/io
import gleam/float
pub fn update(model: Model, msg: Msg, ctx: Context) {
let stats = debug.get_performance_stats()
// Log performance issues
case stats.fps <. 30.0 {
True -> io.println("Warning: Low FPS!")
False -> Nil
}
// Track draw calls for optimization
case stats.draw_calls > 100 {
True -> io.println("Too many draw calls: " <> int.to_string(stats.draw_calls))
False -> Nil
}
// ... rest of update logic
}
pub fn grid(
id: id,
size: Float,
divisions: Int,
color: Int,
) -> scene.Node(id)
Create a grid on the ground plane (XZ plane).
Useful for visualizing the ground, spatial reference, or movement areas.
Parameters
id: Unique identifier for this debug nodesize: Total size of the grid (e.g., 20.0 creates a 20×20 grid)divisions: Number of grid divisions (higher = more lines)color: Hex color code for all grid lines
Example
import tiramisu/debug
// Create a 20×20 grid with 20 divisions
debug.grid("ground-grid", 20.0, 20, debug.color_white)
pub fn line(
id: id,
from: vec3.Vec3(Float),
to: vec3.Vec3(Float),
color: Int,
) -> scene.Node(id)
Create a debug line between two points.
Useful for visualizing connections, trajectories, or directions.
Parameters
id: Unique identifier for this debug nodefrom: Starting point of the lineto: Ending point of the linecolor: Hex color code (e.g.,0xff00fffor magenta)
Example
import tiramisu/debug
import vec/vec3
// Draw a line from origin to target
debug.line(
"path-line",
vec3.Vec3(0.0, 0.0, 0.0),
target_position,
debug.color_green,
)
pub fn path(
id: fn(Int) -> id,
points: List(vec3.Vec3(Float)),
color: Int,
) -> List(scene.Node(id))
Create multiple lines forming a path through points.
Useful for visualizing paths, trajectories, AI navigation routes, or animation curves. Connects consecutive points with lines.
Parameters
id: Function that generates unique IDs for each line segment (receives index)points: List of positions to connectcolor: Hex color code for all path lines
Returns
A list of line nodes, one for each segment between consecutive points.
Example
import tiramisu/debug
import vec/vec3
let waypoints = [
vec3.Vec3(0.0, 0.0, 0.0),
vec3.Vec3(5.0, 2.0, 0.0),
vec3.Vec3(10.0, 0.0, 5.0),
vec3.Vec3(15.0, 3.0, 10.0),
]
// Visualize a patrol path
debug.path(
fn(i) { "patrol-segment-" <> int.to_string(i) },
waypoints,
debug.color_yellow,
)
pub fn point(
id: id,
position: vec3.Vec3(Float),
size: Float,
color: Int,
) -> scene.Node(id)
Create a debug point marker at a position.
Useful for marking specific coordinates, waypoints, or spawn points.
Parameters
id: Unique identifier for this debug nodeposition: World position of the pointsize: Size of the point markercolor: Hex color code (e.g.,0xffa500for orange)
Example
import tiramisu/debug
// Mark spawn points
debug.point("spawn-1", spawn_pos_1, 0.3, debug.color_green)
debug.point("spawn-2", spawn_pos_2, 0.3, debug.color_green)
pub fn ray(
id: id,
origin: vec3.Vec3(Float),
direction: vec3.Vec3(Float),
length: Float,
color: Int,
) -> scene.Node(id)
Create a debug ray from an origin point in a direction.
Useful for visualizing raycasts, shooting directions, or look-at vectors.
Parameters
id: Unique identifier for this debug nodeorigin: Starting point of the raydirection: Direction vector (should be normalized for predictable length)length: Length of the raycolor: Hex color code (e.g.,0xff0000for red)
Example
import tiramisu/debug
import vec/vec3
// Visualize a forward-facing ray
debug.ray(
"look-ray",
camera_position,
camera_forward,
10.0,
debug.color_blue,
)
pub fn show_collider_wireframes(
physics_world: physics.PhysicsWorld(id),
enabled: Bool,
) -> Nil
Enable or disable debug wireframe visualization for all physics colliders in the scene.
This function uses Rapier’s built-in collider visualization which renders wireframes for all physics bodies in the physics world. The wireframes update automatically each frame as objects move and rotate.
Note: This function requires access to the physics world, which is available
in the view function via the Context parameter.
Example
import tiramisu/debug
import gleam/option
pub fn view(model: Model, ctx: tiramisu.Context) {
// Enable/disable debug visualization based on model state
case ctx.physics_world, model.debug_mode {
option.Some(physics_world), True -> {
debug.show_collider_wireframes(physics_world, True)
}
_, _ -> Nil
}
// Return scene as normal
[
scene.Mesh(
id: "cube",
geometry: geometry,
material: material,
transform: transform,
physics: option.Some(physics_body), // Will show wireframe when enabled
),
// ... more scene nodes
]
}
pub fn sphere(
id: id,
center: vec3.Vec3(Float),
radius: Float,
color: Int,
) -> scene.Node(id)
Create a debug wireframe sphere.
Useful for visualizing positions, ranges, trigger zones, or spherical collision shapes.
Parameters
id: Unique identifier for this debug nodecenter: Center position of the sphereradius: Radius of the spherecolor: Hex color code (e.g.,0x00ff00for green)
Example
import tiramisu/debug
import vec/vec3
// Visualize a pickup range around a player
debug.sphere(
"pickup-range",
player_position,
2.5,
debug.color_yellow,
)
pub fn with_collider_wireframes(
nodes: List(scene.Node(id)),
color: Int,
) -> List(scene.Node(id))
@deprecated Use show_collider_wireframes with the physics world from context instead.
This function is kept for backwards compatibility but will be removed in a future version.