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>
4.7 KiB
title, type
| title | type |
|---|---|
| Compositor | 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:
- Queries all registered drawables
- Organizes them by plane and layer
- Applies effects to tagged groups
- 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:
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:
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:
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:
{type: 'bloom', threshold: 0.8, intensity: 1.0, blur_passes: 2}
Mask — uses sprites in a mask group as a stencil:
{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:
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:
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.