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