---
title: "Compositor"
type: docs
---

# The Compositor

The compositor is Prosperon's rendering orchestrator. You describe your scene — planes, layers, effects — and the compositor figures out what render passes are needed and executes them.

## The Basic Idea

You don't issue draw calls. You create sprites and set their properties. The compositor does the rest:

1. Queries all registered drawables
2. Organizes them by plane and layer
3. Applies effects to tagged groups
4. Composites everything to the screen

Think of it like a GBA: you declare "sprite here, sprite there," get handles back, and poke their positions. The hardware (in this case, the compositor + GPU backend) handles the actual rendering.

## Scene Configuration

A scene is described as a config object passed to the compositor:

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

var plan = compositor.compile({
  clear: {r: 0, g: 0, b: 0, a: 1},
  planes: [
    {
      name: 'background',
      plane: 'background',
      resolution: {width: 320, height: 240},
      camera: bg_camera,
      presentation: 'integer_scale'
    },
    {
      name: 'game',
      plane: 'default',
      resolution: {width: 320, height: 240},
      camera: game_camera,
      layer_sort: {'5': 'y'},
      presentation: 'integer_scale'
    },
    {
      name: 'hud',
      plane: 'hud',
      resolution: {width: 1280, height: 720},
      camera: hud_camera,
      presentation: 'stretch'
    }
  ]
})
```

Each plane renders independently at its own resolution and composites onto the screen.

## Planes

A **plane** is a named rendering group. Sprites belong to a plane via their `plane` property (default: `'default'`). Each plane in the compositor config:

- Has its own **resolution** (low-res pixel art, native UI, etc.)
- Has its own **camera**
- Has its own **layer sorting** rules
- Has a **presentation mode** (how it maps to the window)

Planes composite in order — later planes draw on top of earlier ones.

## Layer Sorting

Within a plane, drawables are sorted by `layer` (integer). Within each layer, you can choose a sorting mode:

```javascript
layer_sort: {
  '0': 'explicit',  // engine may reorder for batching efficiency
  '5': 'y'          // sort by Y position (top-down game depth)
}
```

Y-sorting is essential for top-down games where objects lower on screen should appear in front.

## Effects

Effects are applied to **groups** of sprites. Tag sprites with group names, then define effects for those groups:

```javascript
var player = sprite({
  image: "player.png",
  groups: ['glow_objects']
})

var plan = compositor.compile({
  planes: [{
    name: 'game',
    plane: 'default',
    camera: cam,
    resolution: {width: 320, height: 240}
  }],
  group_effects: {
    glow_objects: {
      effects: [
        {type: 'bloom', threshold: 0.5, intensity: 1.5, blur_passes: 2}
      ]
    }
  }
})
```

### Available Effects

**Bloom** — extracts bright areas, blurs them, composites back:
```javascript
{type: 'bloom', threshold: 0.8, intensity: 1.0, blur_passes: 2}
```

**Mask** — uses sprites in a mask group as a stencil:
```javascript
{type: 'mask', mask_group: 'mask_shapes', channel: 'alpha', invert: false}
```

Sprites in the `mask_group` are not drawn directly — they only serve as the mask shape.

## Presentation Modes

Each plane specifies how its render target maps to the window:

| Mode | Behavior |
|------|----------|
| `stretch` | Fill the window exactly (may distort aspect ratio) |
| `letterbox` | Fit inside window, preserving aspect ratio, with black bars |
| `integer_scale` | Scale by whole numbers only for pixel-perfect rendering |

`integer_scale` automatically uses nearest-neighbor filtering for crisp pixels.

## Execution

The compositor produces a **plan** — a list of render passes. The plan is executed by the GPU backend:

```javascript
var result = compositor.execute(plan)
// result.commands is sent to the GPU backend
```

In practice, `core.start({render})` handles this for you. Your render callback returns the compositor result and the engine executes it.

## Manual Drawables

You can inject drawables that aren't registered with film2d by adding them directly to a plane config:

```javascript
planes: [{
  name: 'game',
  plane: 'default',
  camera: cam,
  drawables: [
    {type: 'sprite', image: tex, pos: {x: 0, y: 0}, width: 32, height: 32, layer: 0}
  ]
}]
```

These are merged with the registered drawables for that plane.

## Render Targets

The compositor automatically manages intermediate render targets for effects. You don't need to create or manage GPU textures — the compositor allocates and reuses them as needed.

## Debug

Pass `debug: 'graph'` to `core.start` config to log the compiled render plan as JSON. Pass `debug: 'cmd'` to log the final command list sent to the GPU.
