Files
prosperon/docs/ops.md
John Alanbrook 83b798e365 Add Hugo website and rewrite docs to match current engine
New Hugo site in website/ with prosperon.dev theme (blue/gold/castle
aesthetic), docs sidebar navigation, and content pages. Rewrote all
doc files to align with the actual codebase: compositor+film2d
rendering, use() modules (no global prosperon object), Pit language,
script+JSON entity model. Added entities.md, front matter to all
70+ API docs, and updated API index for current module architecture.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:09:55 -06:00

171 lines
4.7 KiB
Markdown

---
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.