---
title: "Rendering"
type: docs
---

# Rendering

Prosperon's rendering is **data-driven**. You create sprites and other drawables, set their properties, and the engine handles drawing them. You never touch the GPU directly.

## The Model

Think of it like programming sprites on a classic console:

1. **Create** a sprite (or text, shape, tilemap, particle emitter)
2. **Set** its position, image, layer, and visual properties
3. The engine **draws** everything each frame, sorted and batched automatically

```javascript
var sprite = use('sprite')

var player = sprite({
  image: "player.png",
  pos: {x: 100, y: 200},
  layer: 5
})

// Move it later
player.pos.x = 150
player.pos.y = 250
```

That's it. The sprite is registered with the engine when created and drawn every frame until destroyed.

## Coordinate System

There are two coordinate spaces:

**World space** is the game world. The camera's position determines what's visible. If the camera is at `[100, 100]`, that world coordinate is at the center of the screen. X+ goes right, Y+ goes up.

**HUD space** is the screen itself. `[0, 0]` is the bottom-left corner, `[camera.width, camera.height]` is the top-right. HUD elements don't move with the camera.

## Layers

Every drawable has a `layer` — an integer that determines draw order. Lower layers draw first (behind), higher layers draw last (in front).

Within a layer, objects can be sorted by different criteria:

- **explicit** (default) — engine may reorder for performance
- **y-sort** — sort by Y position, useful for top-down games where "lower" objects appear in front

## Planes

Drawables are organized into **planes**. A plane is a named group that can have its own resolution, camera, and effects. By default, everything goes into the `'default'` plane.

Planes render independently and composite onto the screen. This lets you have a game world at 320x240 pixel-art resolution and a HUD at native resolution, for example.

## Effects

Planes and groups of sprites can have effects applied:

- **Bloom** — threshold + multi-pass Gaussian blur
- **Mask** — stencil masking using other sprites as the mask shape

Effects are declared in the compositor config and applied automatically. You tag sprites with groups, then apply effects to those groups.

## Presentation Modes

The final composited frame is presented to the window in one of three modes:

| Mode | Behavior |
|------|----------|
| `stretch` | Fill the window, may distort |
| `letterbox` | Fit inside window, preserve aspect ratio, black bars |
| `integer_scale` | Scale by whole numbers only, nearest-neighbor, pixel-perfect |

## Camera

A camera defines the viewport into the world:

```javascript
var camera = use('camera')
var cam = camera.make({
  pos: {x: 0, y: 0},
  width: 320,
  height: 240
})
```

The camera's `width` and `height` set the game's internal resolution. The `pos` determines what world coordinate is at the center of the screen.

## Drawable Types

| Type | Module | Description |
|------|--------|-------------|
| Sprite | `sprite` | Textured quad with transform, tint, UV mapping |
| Text | `text2d` | Rendered text with font, size, wrapping |
| Shape | `shape2d` | SDF-rendered rectangles, circles, ellipses, pills |
| Tilemap | `tilemap2d` | Grid of tiles on a single layer |
| Particles | `particles2d` | Particle emitter producing sprite-like particles |
| Line | `line2d` | Polylines and line segments as triangle meshes |

All drawable types share common properties: `pos`, `layer`, `plane`, `groups`, `visible`, `opacity`, `tint`.

## How It Works Internally

For those curious about the pipeline (you don't need to know this to use Prosperon):

1. Drawables register with `film2d` — the internal sprite registry
2. Each frame, the **compositor** queries film2d for all visible drawables
3. Drawables are sorted by layer, batched by texture/material
4. Effect groups are rendered to intermediate targets, effects applied
5. Planes composite to the screen via the **SDL GPU backend**
6. The backend uses Metal, Vulkan, or DirectX depending on platform
