Draw

Immediate-mode 2D drawing, text, textures, cameras, and render effects.

render! is handed a Frame, and everything drawn is drawn through it:

render! = |model, frame| {
    frame.clear!(Color.from_hex_rgb(0x0d1425))
    frame.rectangle!({ x: 40, y: 40, width: 200, height: 90, style: Draw.filled(Color.white) })
    frame.circle!({ center: model.pointer, radius: 18, style: Draw.outlined(Color.red, 3) })
    Ok({})
}

The Frame is a capability rather than a value: the host opens the frame scope around render! and closes it afterwards, so nothing can draw before the frame begins or after it ends, and the nested scopes -- with_camera!, with_shader!, with_scissor!, with_render_texture!, with_blend_mode! -- restore what they changed however their callback ends. Do not keep a Frame in the model; pass the callback's own frame down through helpers.

Every effect that takes a Frame -- every shape, every texture, every scope, and every uniform set! -- is legal in render! only. The loaders in this module are the other half. default_font!, font_from_bytes!, load_render_texture!, Shader.from_source! and the Shader.uniform_*! resolvers allocate host resources from what the app already has, so they are legal in init!, update!, and tasks, and refused in render!. The two that read files out of an asset store, load_store_font! and Shader.from_store!, wait instead: each is legal in init!, where it blocks startup, and in tasks, where it parks the task, and refused in update! and render!. Create them in init!, keep them in the model, and hand the values to render!; per-frame drawing and uniform updates then allocate nothing. To load a font or a shader after startup, read the file on a task -- with Files.read_bytes!, then font_from_bytes! or Shader.from_source! from update! when the message arrives, or by calling the store loader inside the task itself.

Most shapes come in two spellings: frame.circle!(cfg) and Draw.circle!(frame, cfg) are the same call. Prefer the receiver; the free function is kept because it composes in a pipeline where the frame is not the value at hand.

Text has a fuller home in Text, which measures, wraps, aligns and prepares it. Draw.text! and the Draw.align_* constants are the older, simpler set: they draw a string with no layout pass. Reach for Text when the position depends on the size of what is drawn.

from_rgba : { r : U8, g : U8, b : U8, a : U8 } -> Rgba

Convert a structural RGBA value at an adapter boundary into roc-ray's color.

alpha_blend : BlendMode

Conventional source-alpha compositing.

additive_blend : BlendMode

Add source and destination colors, useful for light and glow effects.

filled : Rgba -> ShapeStyle

Create a fill-only shape style.

stroke : Rgba, F32 -> Stroke

Create a stroke with color and thickness in logical pixels.

outlined : Rgba, F32 -> ShapeStyle

Create a stroke-only shape style.

default_font! : () => Font

Snapshot raylib's built-in font, metrics included.

Legal in init!, update!, and tasks; refused in render!.

align_top_left : TextAlign

Top-left text anchor.

These nine constants and align_offset are the older alignment set, for Draw.text_at!. Text.align_top_left and its siblings are the ones to reach for: they are the same nine anchors, and they are what Text.Prepared.draw! takes.

align_offset : TextSize, TextAlign -> Vector2

Convert a measured size and alignment into an anchor offset.

origin_for : Vector2, TextSize, TextAlign -> Vector2

Find the top-left text origin for an anchored position.

align_factor : TextAlign -> Vector2

Convert text alignment into horizontal and vertical factors from 0 to 1.

center_in_rect : Rectangle, TextSize -> Vector2

Find the top-left position that centers measured text in a rectangle.

clear! : Frame, Rgba => {  }

Clear the active drawing target to a solid color.

Legal in render! only.

rectangle_gradient_v! : Frame, RectangleGradientV => {  }

Draw a vertical rectangle gradient.

Legal in render! only.

rectangle_gradient_h! : Frame, RectangleGradientH => {  }

Draw a horizontal rectangle gradient.

Legal in render! only.

circle_gradient! : Frame, CircleGradient => {  }

Draw a radial circle gradient.

Legal in render! only.

fps! : Frame, Fps => {  }

Draw raylib's current frames-per-second counter.

Legal in render! only.

rectangle! : Frame, Rectangle => {  }

Draw a filled and/or outlined axis-aligned rectangle.

Legal in render! only.

rounded_rectangle! : Frame, RoundedRectangle => {  }

Draw a filled and/or outlined rounded rectangle.

Legal in render! only.

circle! : Frame, Circle => {  }

Draw a filled and/or outlined circle.

Legal in render! only.

line! : Frame, Line => {  }

Draw a stroked line segment. NoStroke performs no drawing.

Legal in render! only.

triangle! : Frame, Triangle => {  }

Draw a filled and/or outlined triangle.

Legal in render! only.

polygon! : Frame, Polygon => {  }

Deprecated: use convex_polygon!.

Legal in render! only.

convex_polygon! : Frame, ConvexPolygon => {  }

Draw a convex filled polygon and/or an ordered polygon outline. The host triangulates the fill without allocating; fewer than three points do not fill.

Legal in render! only.

load_store_font! : Store, LoadFont => Try(Font, [PathInvalid, NotFound, ReadFailed, FontLoadFailed, ResourceLimit, ..])

Load a font relative to an explicit asset store.

Legal in init!, where it blocks startup, and in tasks, where it parks the task; refused in update! and render!. The file is read off the frame thread and rasterized when the bytes are back. To load a font from update!, use font_from_bytes! with bytes the app already holds.

font_from_bytes! : FontBytes => Try(Font, [FontLoadFailed, ResourceLimit, ..])

Decode an authored, compile-time embedded font.

The bytes are borrowed while raylib copies and decodes them, so no extra Roc payload-sized buffer is created. Legal in init!, update!, and tasks; refused in render!.

texture_draw : Texture -> TextureDraw

Create a draw configuration covering the whole texture at the origin.

texture_at : Texture, Vec2 -> TextureDraw

Create a draw configuration covering the whole texture at pos.

texture_view_draw : Texture -> TextureDraw

Create a draw configuration covering a read-only sampled view.

texture_view_at : Texture, Vec2 -> TextureDraw

Create a sampled-view draw configuration at pos.

texture! : Frame, TextureDraw => {  }

Draw a texture with explicit source, destination, origin, rotation, and tint.

Legal in render! only.

draw_texture! : Frame, TextureDraw => {  }

Deprecated: use texture!.

Legal in render! only.

texture_instances! : Frame, Texture, List(TextureInstance) => {  }

Draw many instances of one texture, in list order, with a single hosted call.

texture! crosses the Roc/host boundary once per sprite, and that crossing is what caps how many sprites a frame can afford. This crosses once for the whole batch and lets the host loop over it, so the cost per instance is the DrawTexturePro call alone. Build the list from application state and pass it straight through; an empty list does not cross at all.

Legal in render! only.

projective_texture! : Frame, ProjectiveTexture => {  }

Project a texture onto a validated planar quad with exact homogeneous UV interpolation. This remains one hosted call and preserves active shaders.

Legal in render! only.

projective_texture_view! : Frame, ProjectiveTextureView => {  }

Project a sampled texture view onto a validated planar quad.

Legal in render! only.

load_render_texture! : RenderTextureSize => Try(RenderTexture, [RenderTextureLoadFailed, ResourceLimit, ..])

Allocate an offscreen framebuffer.

Creation allocates GPU resources and one fixed host-heap slot, so do it in init! rather than per frame. Legal in init!, update!, and tasks; refused in render!.

render_texture : RenderTexture -> Texture

View the color attachment as a sampled texture without allocating or copying. The returned reference keeps the owning framebuffer alive.

render_texture_source : RenderTexture -> Rect

The source rectangle that samples a render target's colour attachment.

Its height is negative. Render textures use OpenGL framebuffer coordinates, so the attachment is vertically inverted when sampled on screen, and a negative-height source is how a draw flips it back.

load_shader_source! : LoadShaderSource => Try(Shader, [ShaderLoadFailed, ResourceLimit, ..])

Compile shader stages from source strings. Empty strings select the default stage, which is useful for fragment-only 2D post-processing.

Legal in init!, update!, and tasks; refused in render!.

with_render_texture! : Frame, RenderTexture, (Frame => Try(result, [ScopeLimit, ScopeUnavailable, ..errors])) => Try(result, [ScopeLimit, ScopeUnavailable, ..errors])

Scope offscreen rendering so BeginTextureMode/EndTextureMode stay paired. Callback errors are returned only after the native target has been restored.

Legal in render! only.

with_shader! : Frame, Shader, (Frame => Try(result, [ScopeLimit, ScopeUnavailable, ..errors])) => Try(result, [ScopeLimit, ScopeUnavailable, ..errors])

Scope shader application so the default shader is always restored. Callback errors are returned only after the previous shader has been restored.

Legal in render! only.

with_blend_mode! : Frame, BlendMode, (Frame => Try(result, [ScopeLimit, ..errors])) => Try(result, [ScopeLimit, ..errors])

Scope one of raylib's built-in blend equations. Custom blend factors are deliberately excluded until they can be represented without global state.

Legal in render! only.

with_camera! : Frame, CameraMode, (Frame => Try(result, [ScopeLimit, ..errors])) => Try(result, [ScopeLimit, ..errors])

Draw the callback in world space using this camera.

Legal in render! only.

with_mode_2d! : Frame, CameraMode, (Frame => Try(result, [ScopeLimit, ..errors])) => Try(result, [ScopeLimit, ..errors])

Deprecated: use with_camera!.

Legal in render! only.

with_scissor! : Frame, Rect, (Frame => Try(result, [ScopeLimit, ..errors])) => Try(result, [ScopeLimit, ..errors])

Restrict callback drawing to screen-space bounds, and close the scissor however the callback ends, error included.

bounds is in the same logical coordinates as every other drawing call, so it is a rectangle on the surface rather than in framebuffer pixels.

Legal in render! only.

text! : Frame, Text => {  }

Draw text using explicit font, spacing, color, and anchor alignment.

Legal in render! only.

debug_text! : Frame, DebugText => {  }

Draw top-left aligned text with the built-in font and default spacing.

Legal in render! only.

text_at! : Frame, SimpleText => {  }

Draw simple top-left aligned text with the built-in font.

Legal in render! only.

text_centered! : Frame, SimpleText => {  }

Draw simple text centered on its position.

Legal in render! only.

Frame

Draw.Frame :: # (opaque)

Opaque, zero-sized authority the host supplies only while it runs render!.

Holding one is what makes a draw call expressible, so drawing cannot reach init! or update!. Roc does not enforce affine use or encode a frame epoch, so do not retain a Frame in the model: pass the callback's own frame down through helpers.

size! : Frame => FrameSize

How big the surface being drawn to right now is.

Normally this is the window's logical drawing size -- the same value Window.Snapshot.size reports, in the same coordinate space as mouse input and every drawing call. Inside with_render_texture! it is the render target's size instead, because that is what the callback's coordinates are relative to.

This is the size of the drawing surface, so it is F32 where Window.Snapshot.size is I32: it feeds rectangles, text anchors and centre points directly, and a render target's dimensions are already F32 on Texture. Window.Snapshot.size stays I32 because it is also the thing Window.suggest_size sets.

Reach for this when laying something out against the surface -- a HUD in a corner, a title centred across the top. Layout decisions that update! also has to make, such as which arrangement to use or what the pointer is over, belong on input.window where the rest of application logic can see them.

Legal in render! only.

FrameSize : {
    width : F32,
    height : F32,
}

Dimensions of the surface render! is currently drawing to.

Texture : Texture

Host-owned GPU texture, the same type Assets loads and generates.

Named here as well so drawing code can keep a texture in its model without importing Assets; Draw.Texture, Assets.Texture and the companion package's Texture are one type, not three.

Vector2 : Vec2

Two-dimensional vector used by drawing records.

Rect : Rect

Axis-aligned rectangle used by drawing records.

Camera2D : Camera2D

Pure 2D camera settings.

Fill : [NoFill, Fill(Rgba)]

Optional shape fill.

Stroke : [NoStroke, Stroke({ color : Rgba, thickness : F32 })]

Optional shape outline with color and thickness.

ShapeStyle : {
    fill : Fill,
    stroke : Stroke,
}

Combined fill and outline applied by shape helpers.

Rectangle : {
    x : F32,
    y : F32,
    width : F32,
    height : F32,
    style : ShapeStyle,
}

Axis-aligned rectangle and its style.

RoundedRectangle : {
    x : F32,
    y : F32,
    width : F32,
    height : F32,
    radius : F32,
    segments : I32,
    style : ShapeStyle,
}

Rounded rectangle; radius and segment count control corner tessellation.

RectangleGradientV : {
    x : F32,
    y : F32,
    width : F32,
    height : F32,
    color_top : Rgba,
    color_bottom : Rgba,
}

Vertical rectangle gradient from top to bottom.

RectangleGradientH : {
    x : F32,
    y : F32,
    width : F32,
    height : F32,
    color_left : Rgba,
    color_right : Rgba,
}

Horizontal rectangle gradient from left to right.

Circle : {
    center : Vector2,
    radius : F32,
    style : ShapeStyle,
}

Circle and its style.

CircleGradient : {
    center : Vector2,
    radius : F32,
    color_inner : Rgba,
    color_outer : Rgba,
}

Radial gradient from inner to outer color.

Line : {
    start : Vector2,
    end : Vector2,
    stroke : Stroke,
}

Line segment and stroke.

Triangle : {
    a : Vector2,
    b : Vector2,
    c : Vector2,
    style : ShapeStyle,
}

Triangle vertices and style.

ConvexPolygon : {
    points : List(Vector2),
    style : ShapeStyle,
}

A simple convex polygon. Points must be ordered around the boundary (clockwise or counter-clockwise). Filled concave or self-intersecting polygons are not supported; outlines accept any ordered point path.

Polygon : ConvexPolygon

Deprecated: use ConvexPolygon.

The same type under its older name. ConvexPolygon says the constraint the host relies on, so it is visible at the call site.

Fps : {
    pos : Vector2,
    size : F32,
    color : Rgba,
}

Position, size, and color for the FPS counter.

GlyphMetrics : GlyphMetrics

Scalar metrics for one glyph, shared with platform-independent packages.

TextSize : Size

Text measurement result.

Font : Font

A native font handle paired with an immutable scalar metric snapshot. Loading constructs the snapshot once; every receiver on it is pure.

Declared in the roc-ray-types package's Font and re-exported here, which is also where base_size, line_spacing, glyphs, get_glyph_index, measure and stub are documented. A layout package can therefore measure text against a real font without depending on this platform. Loading one is an effect and stays here: Draw.default_font!, Draw.load_store_font!, and Draw.font_from_bytes!.

HAlign : [Left, Center, Right]

Horizontal text anchor.

VAlign : [Top, Middle, Bottom]

Vertical text anchor.

TextAlign : {
    horizontal : HAlign,
    vertical : VAlign,
}

Horizontal and vertical text anchor.

Text : {
    pos : Vector2,
    text : Str,
    size : F32,
    spacing : F32,
    color : Rgba,
    font : Font,
    align : TextAlign,
}

Fully configured text draw.

DebugText : {
    pos : Vector2,
    text : Str,
    size : F32,
    color : Rgba,
}

Built-in-font text intended for quick diagnostics.

SimpleText : {
    pos : Vector2,
    text : Str,
    size : F32,
    color : Rgba,
}

Built-in-font text with default spacing.

LoadFont : {
    path : Str,
    size : I32,
}

Font path and base pixel size.

TextureDraw : TextureDrawConfig

Resolved texture draw configuration: which texture, which part of it, where it goes, and how it is rotated and tinted.

TextureDrawConfig in the signature is the module-private record this aliases; Draw.TextureDraw is the name to write. Build one with texture_draw, texture_at, or the TextureDrawBuilder combinators.

TextureInstance : TextureInstanceConfig

One instance of a batched texture draw. These are the fields of TextureDraw minus the texture, which the batch supplies once.

TextureInstanceConfig in the signature is the module-private record this aliases; Draw.TextureInstance is the name to write.

ProjectiveQuadCorners : {
    top_left : Vec2,
    bottom_left : Vec2,
    bottom_right : Vec2,
    top_right : Vec2,
}

Four ordered corners of a projected planar surface.

ProjectiveQuad

Draw.ProjectiveQuad :: # (opaque)

A finite, convex planar projection with a bounded homography. Construct it with ProjectiveQuad.from_corners; the opaque representation carries the homogeneous weights needed for exact perspective-correct interpolation.

from_corners : ProjectiveQuadCorners -> Try(ProjectiveQuad, [NonFiniteQuad, DegenerateQuad, NonConvexQuad, ProjectiveHorizon, ..])

Validate four boundary-ordered corners and solve their projective weights. A single homography cannot represent a concave, self-intersecting, or horizon-crossing destination, so those states are rejected here.

project : ProjectiveQuad, Vec2 -> Vec2

Project a unit-square coordinate onto the destination surface. This uses the same homography as rendering and is useful for aligned overlays.

ProjectiveTexture : {
    texture : Texture,
    source : Rect,
    quad : ProjectiveQuad,
    tint : Rgba,
}

Texture and source region projected exactly onto a validated planar quad.

ProjectiveTextureView : {
    texture : Texture,
    source : Rect,
    quad : ProjectiveQuad,
    tint : Rgba,
}

Sampled texture view projected exactly onto a validated planar quad.

CameraMode : Camera2D

Camera accepted by scoped 2D drawing.

RenderTexture

Draw.RenderTexture :: # (opaque)

Host-owned framebuffer. Its texture-shaped box has a distinct host kind; the host rejects ordinary textures before entering an offscreen scope. Releasing the final reference unloads the framebuffer and both attachments.

load! : RenderTextureSize => Try(RenderTexture, [RenderTextureLoadFailed, ResourceLimit, ..])

Allocate an offscreen framebuffer.

Legal in init!, update!, and tasks; refused in render!.

texture : RenderTexture -> Texture

Read-only view of this render target's color attachment.

source : RenderTexture -> Rect

Vertically inverted full-source rectangle for drawing the color attachment.

stub : RenderTexture

Resource-free render target for pure tests.

The handle never resolves to a host resource, so entering a scope with it is refused the way a released target is. Its color attachment is the package's Texture.stub with zero dimensions; copy it with the dimensions the test needs. Do not use it to test drawing, offscreen scopes, or resource lifetime.

Shader

Draw.Shader :: # (opaque)

Host-owned GPU shader. Empty vertex/fragment strings select raylib's default stage. Keep this value alive for every cached Uniform derived from it.

from_source! : LoadShaderSource => Try(Shader, [ShaderLoadFailed, ResourceLimit, ..])

Compile shader stages from source strings.

Legal in init!, update!, and tasks; refused in render!.

from_store! : Store, LoadShader => Try(Shader, [PathInvalid, NotFound, ReadFailed, ShaderLoadFailed, ResourceLimit, ..])

Compile shader stage files resolved through an explicit asset store.

Legal in init!, where it blocks startup, and in tasks, where it parks the task; refused in update! and render!. The sources are read off the frame thread and compiled when the bytes are back. To compile from update!, use from_source! with strings the app already holds.

uniform_f32! : Shader, Str => Try(F32Uniform, [UniformNotFound, ..])

Resolve a scalar floating-point uniform once.

Legal in init!, update!, and tasks; refused in render!. Resolving a uniform is a lookup against the compiled program, so it belongs beside the load. Setting one is the opposite: set! on the resolved handle is legal in render! only.

uniform_i32! : Shader, Str => Try(I32Uniform, [UniformNotFound, ..])

Resolve a scalar integer uniform once. Same phases as uniform_f32!.

Legal in init!, update!, and tasks; refused in render!.

uniform_vec2! : Shader, Str => Try(Vec2Uniform, [UniformNotFound, ..])

Resolve a two-component vector uniform once. Same phases as uniform_f32!.

Legal in init!, update!, and tasks; refused in render!.

uniform_vec3! : Shader, Str => Try(Vec3Uniform, [UniformNotFound, ..])

Resolve a three-component vector uniform once. Same phases as uniform_f32!.

Legal in init!, update!, and tasks; refused in render!.

uniform_vec4! : Shader, Str => Try(Vec4Uniform, [UniformNotFound, ..])

Resolve a four-component vector uniform once. Same phases as uniform_f32!.

Legal in init!, update!, and tasks; refused in render!.

uniform_color! : Shader, Str => Try(ColorUniform, [UniformNotFound, ..])

Resolve a color-valued vec4 uniform once. Same phases as uniform_f32!.

Legal in init!, update!, and tasks; refused in render!.

uniform_texture! : Shader, Str => Try(TextureUniform, [UniformNotFound, ..])

Resolve a sampled-texture uniform once. Same phases as uniform_f32!.

Legal in init!, update!, and tasks; refused in render!.

stub : Shader

Resource-free shader value for pure tests.

The handle never resolves to a host resource, so entering a scope with it is refused the way a released shader is, and setting a uniform derived from it does nothing. Put it in a model to reach the app's real update! from an expect. Do not use it to test compilation, uniforms, or resource lifetime.

LoadShader : {
    vertex_path : Str,
    fragment_path : Str,
}

Store-relative shader stage names. An empty path selects raylib's default stage; non-empty paths are resolved only through Shader.from_store!.

LoadShaderSource : {
    vertex_source : Str,
    fragment_source : Str,
}

Shader stages as GLSL source strings rather than store paths, for Shader.from_source!. An empty string selects raylib's default stage, which is what a fragment-only 2D post-processing effect wants.

FontFormat

:= [Ttf, Otf]

Which font file format FontBytes carries. The bytes are decoded by format rather than by sniffing them, so a mislabelled file fails to load instead of loading as something else.

FontBytes : { format : FontFormat, bytes : List(U8), size : I32 }

An authored font embedded with a compile-time file import, plus the pixel size to rasterize its glyph atlas at. size is baked into the atlas, so drawing at a much larger size scales that atlas up rather than re-rasterizing; load the font again at the size you need instead.

F32Uniform

Draw.F32Uniform :: # (opaque)

A resolved F32 uniform location, from Shader.uniform_f32!.

The typed uniform handles are zero-cost nominal wrappers over the cached host location plus its owning shader. Their distinct types prevent using the wrong setter without adding a tag, allocation, or host lookup.

set! : F32Uniform, F32 => {  }

Send a scalar float to this uniform for the draws that follow.

Legal in render! only.

I32Uniform

Draw.I32Uniform :: # (opaque)

A resolved I32 uniform location, from Shader.uniform_i32!.

set! : I32Uniform, I32 => {  }

Send a scalar integer to this uniform for the draws that follow.

Legal in render! only.

Vec2Uniform

Draw.Vec2Uniform :: # (opaque)

A resolved two-component uniform location, from Shader.uniform_vec2!.

set! : Vec2Uniform, Vector2 => {  }

Send a two-component vector to this uniform for the draws that follow.

Legal in render! only.

Vec3Uniform

Draw.Vec3Uniform :: # (opaque)

A resolved Vec3 uniform location, from Shader.uniform_vec3!.

set! : Vec3Uniform, Vec3 => {  }

Send a three-component vector to this uniform for the draws that follow.

Legal in render! only.

Vec4Uniform

Draw.Vec4Uniform :: # (opaque)

A resolved Vec4 uniform location, from Shader.uniform_vec4!.

set! : Vec4Uniform, Vec4 => {  }

Send a four-component vector to this uniform for the draws that follow.

Legal in render! only.

ColorUniform

Draw.ColorUniform :: # (opaque)

A resolved color uniform location, from Shader.uniform_color!. GLSL has no color type, so this is a vec4 whose components the setter normalizes from the 0-to-255 bytes of an Rgba to the 0-to-1 floats a shader reads.

set! : ColorUniform, Rgba => {  }

Send a color to this uniform for the draws that follow, normalized to the 0-to-1 range GLSL uses.

Legal in render! only.

TextureUniform

Draw.TextureUniform :: # (opaque)
set! : TextureUniform, Texture => {  }

Bind any sampled texture view, including a render-target attachment.

Legal in render! only.

This is the one to reach for. set_texture! is the same call named for the ordinary case, and exists only because binding a plain texture is what most shaders want and set! does not say so.

set_texture! : TextureUniform, Texture => {  }

Bind an ordinary texture, as set! does. Prefer set!, which also accepts a render-target attachment; this spelling reads better when the value at hand is plainly a texture.

Legal in render! only.

Vec3 : { x : F32, y : F32, z : F32 }

Three-component shader uniform value.

Vec4 : { x : F32, y : F32, z : F32, w : F32 }

Four-component shader uniform value.

BlendMode : [
    Alpha,
    Additive,
    Multiplied,
    AddColors,
    SubtractColors,
    AlphaPremultiply,
]

Built-in blend equations with scoped application through with_blend_mode!.

ScopeError : [ScopeLimit, ScopeUnavailable]

A scoped renderer could not be opened because its bounded native stack is full or a transferred host resource no longer resolves.