Files
prosperon/docs/graphics.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

4.1 KiB

title, type
title type
Graphics docs

Graphics Concepts

This page covers the fundamental graphics concepts in Prosperon.

Textures and Images

A texture is a set of bytes on the GPU — not directly accessible from script code.

An image is a texture combined with a UV rect that specifies which region to draw:

image = {
  texture: GPU texture handle,
  rect: {x, y, width, height}  // UV coordinates
}

This means multiple images can share one texture (a sprite sheet or atlas), each referencing a different region.

Supported Image Formats

Format Notes
PNG Standard, lossless
QOI Fast decode, lossless
GIF Animated frames supported
JPG/JPEG Lossy
Aseprite (.ase) Frames, tags, slices, durations, pivots

Aseprite files are fully parsed — named animation tags, per-frame durations, pivot points, and slice data are all available.

Sprites

A sprite is the fundamental drawable. Create one with the sprite module:

var sprite = use('sprite')

var s = sprite({
  image: "player.png",
  pos: {x: 100, y: 200},
  width: 32,
  height: null,   // derived from aspect ratio
  anchor_x: 0.5,  // center horizontally
  anchor_y: 0,    // bottom edge
  layer: 5,
  rotation: 0,
  flip: {x: false, y: false},
  color: {r: 1, g: 1, b: 1, a: 1},
  opacity: 1,
  tint: {r: 1, g: 1, b: 1, a: 1},
  filter: 'nearest',
  plane: 'default',
  groups: [],
  visible: true
})

Fit Modes

When both width and height are specified, the fit property controls how the texture maps into the rectangle:

Fit Behavior
none Use the texture's native pixel size
fill Stretch to exactly fill the rectangle (may distort)
contain Fit inside the rectangle, preserving aspect ratio
cover Fill the rectangle, preserving aspect ratio (crops via UV)

If only one dimension is given (e.g. width: 32, height: null), the other is derived from the texture's aspect ratio.

Anchors

The anchor determines which point of the sprite sits at pos:

  • anchor_x: 0, anchor_y: 0 — top-left at pos
  • anchor_x: 0.5, anchor_y: 0.5 — center at pos
  • anchor_x: 0.5, anchor_y: 0 — bottom-center at pos (good for characters)

UV Mapping

For sprite sheets, control which region of the texture is drawn:

sprite({
  image: spritesheet_texture,
  uv: {offset: {x: 0.25, y: 0}, scale: {x: 0.25, y: 0.5}}
})

Text

Create text with the text2d module:

var text2d = use('text2d')

var label = text2d({
  text: "Hello World",
  font: "myfont.ttf",
  size: 24,
  pos: {x: 100, y: 100},
  layer: 10
})

Shapes

SDF-rendered shapes via the shape2d module:

var shape2d = use('shape2d')

var box = shape2d.rect({
  pos: {x: 50, y: 50},
  width: 100,
  height: 80,
  color: {r: 1, g: 0, b: 0, a: 1},
  layer: 3
})

var ball = shape2d.circle({
  pos: {x: 200, y: 200},
  radius: 25,
  color: {r: 0, g: 1, b: 0, a: 1}
})

Available shapes: rect, circle, ellipse, pill.

Tilemaps

Grid-based tile rendering:

var tilemap2d = use('tilemap2d')

var map = tilemap2d({
  tiles: tiles_2d_array,
  tile_width: 16,
  tile_height: 16,
  layer: 0
})

Tiles can be flipped, and the entire tilemap can have an affine transform applied. Camera culling for large maps is planned.

Particles

Particle emitters produce sprite-like particles:

var particles2d = use('particles2d')

var emitter = particles2d({
  texture: "spark.png",
  pos: {x: 100, y: 100},
  layer: 8
})

Coordinate System

Prosperon uses a Y-up coordinate system:

  • X+ goes right
  • Y+ goes up
  • [0, 0] in world space is where the camera starts
  • [0, 0] in HUD space is the bottom-left of the screen

Camera

A camera defines the viewport into the world. Its width and height set the game's internal resolution. Its pos determines what world coordinate is at the center of the screen.

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

Everything in world space is drawn relative to the camera's position. HUD space is always screen-relative.