Header menu logo Mibo.Raylib

2D Rendering

The 2D rendering pipeline is a deferred command system: each frame, your view function populates a RenderBuffer2D with Command2D values, and the Renderer2D<'Model> sorts them by layer and executes them in order.

What and Why

A deferred renderer means you describe what to draw without worrying about when to draw it. The renderer handles:

This is especially useful for:

When to use deferred vs immediate

Situation

Approach

Sprites, text, shapes, tiles

Use Draw.* commands (deferred)

Custom rlgl meshes, instancing

Use Draw.drawImmediate (escape hatch)

One-off GPU operations

Prefer deferred; use immediate only when raylib lacks the API

How it works

Program.mkProgram init update
|> Program.withRenderer (fun () -> Renderer2D.create myView)

Each frame, the runtime calls myView ctx model buffer. Your view adds commands, the renderer sorts and executes:

  1. buffer.Clear() — wipe previous frame's commands
  2. myView ctx model buffer — populate with this frame's draw commands
  3. buffer.Sort() — sort by layer (ascending)
  4. Execute in order, managing camera/shader state transitions

Command API layers

Two ways to add commands to the buffer:

Layer

When to use

Draw.* DSL

Everyday use — pipe-friendly, supports partial application

Command2D.* factories

When you need to store or reuse commands without a buffer

Lighting

The 2D lighting system (Mibo.Elmish.Graphics2D.Lighting) provides point lights, directional lights, ambient light, and SDF soft shadows — all GPU-driven with no extra render passes.

buffer
|> LightDraw.setAmbient lightingCtx (5<RenderLayer>, { Color = gray })
|> LightDraw.addDirectionalLight lightingCtx 6<RenderLayer> { Direction = sunDir; ... }
|> LightDraw.addPointLight lightingCtx 7<RenderLayer> { Position = torchPos; ... }
|> LightDraw.litSprite lightingCtx playerSprite
|> LightDraw.endLighting lightingCtx 999<RenderLayer>

See Lighting & Shadows for details.

Multi-camera rendering

Use Camera2DConfig for viewport-based rendering, split-screen, or overlay cameras:

// Split-screen left/right
let left = Camera2D.splitScreenLeft cam1 Color.CornflowerBlue
let right = Camera2D.splitScreenRight cam2 Color.DarkGreen

buffer
|> Draw.beginCameraWith 0<RenderLayer> left
|> // ... left viewport ...
|> Draw.endCamera 100<RenderLayer>
|> Draw.beginCameraWith 200<RenderLayer> right
|> // ... right viewport ...
|> Draw.endCamera 300<RenderLayer>

Camera2DConfig controls viewport (normalized 0–1 coordinates) and clear color. See Camera for the full API.

Next steps

Type something to start searching.