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>
5.1 KiB
title, type
| title | type |
|---|---|
| Tutorial | docs |
A Tutorial Introduction
This tutorial walks through building a simple game from scratch. By the end, you'll understand modules, programs, rendering, and input.
How Prosperon Starts
Prosperon runs a .ce program file as the root actor. This is your game's entry point. There is no config.js or main.js — everything is modules you import with use().
Step 1: A Window
Create game.ce:
var core = use('core')
core.start({
title: "My Game",
width: 1280,
height: 720
})
Run it with prosperon game.ce. You get a window. core.start() initializes the GPU backend, opens the window, and starts the main loop.
Step 2: Drawing a Sprite
Sprites are the fundamental drawable. Create one and it appears on screen — you don't issue draw calls.
var core = use('core')
var sprite = use('sprite')
var compositor = use('compositor')
var camera = use('camera')
var cam = camera.make({
pos: {x: 0, y: 0},
width: 320,
height: 240
})
var player = sprite({
image: "player.png",
pos: {x: 0, y: 0},
width: 32,
layer: 5
})
var plan = compositor.compile({
planes: [{
name: 'game',
plane: 'default',
resolution: {width: 320, height: 240},
camera: cam,
presentation: 'integer_scale'
}]
})
core.start({
title: "Sprite Test",
width: 1280,
height: 720,
render: function() {
return compositor.execute(plan)
}
})
Key ideas:
sprite()creates a sprite and registers it with the engine automatically- The compositor describes how to render the scene: which planes, at what resolution, with what camera
- Your
rendercallback returns the compositor result — the engine sends it to the GPU
Step 3: Moving the Sprite
Add an update callback to move things each frame:
core.start({
title: "Moving Sprite",
width: 1280,
height: 720,
update: function(dt) {
player.pos.x += 60 * dt
},
render: function() {
return compositor.execute(plan)
}
})
dt is the time elapsed since the last frame, in seconds. Multiply speeds by dt for frame-rate-independent movement.
Step 4: Handling Input
Use the input module to map physical keys to named actions, then route those actions to your game objects:
var input = use('input')
input.configure({
action_map: {
move_left: ['a', 'left'],
move_right: ['d', 'right'],
jump: ['space']
}
})
var player_entity = {
on_input: function(action, data) {
if (action == 'move_left' && data.pressed) {
player.pos.x -= 16
}
if (action == 'move_right' && data.pressed) {
player.pos.x += 16
}
}
}
var p1 = input.player1()
p1.possess(player_entity)
The input system handles keyboard, gamepad, and touch. You define actions once and bind them to any physical input.
Step 5: Adding Sound
var sound = use('sound')
sound.play("jump.wav")
Sounds are loaded by path. The engine caches audio data so loading the same sound twice reuses the existing data.
Step 6: Multiple Planes
Real games often need separate rendering layers — pixel art at low res, HUD at native res:
var plan = compositor.compile({
clear: {r: 0.1, g: 0.1, b: 0.2, a: 1},
planes: [
{
name: 'game',
plane: 'default',
resolution: {width: 320, height: 240},
camera: cam,
layer_sort: {'5': 'y'},
presentation: 'integer_scale'
},
{
name: 'hud',
plane: 'hud',
resolution: {width: 1280, height: 720},
camera: hud_cam,
presentation: 'stretch'
}
]
})
Sprites belong to a plane via their plane property. Each plane renders at its own resolution with its own camera, then composites onto the screen in order.
Step 7: Entities
For anything more than a few sprites, use the entity system. Define entity types as modules, create instances with overrides:
// entities/coin.cm
var sprite = use('sprite')
return {
value: 1,
image: "coin.png",
init: function() {
this.sprite = sprite({
image: this.image,
pos: this.pos,
width: 16,
layer: 3
})
},
on_destroy: function() {
this.sprite.destroy()
}
}
// In your game program
var world = use('world')
var coin_proto = use('entities/coin')
var c = world.add_entity(coin_proto, {
pos: {x: 50, y: 80},
value: 5
})
The entity's init() runs after overrides are applied. The prototype defines every valid field with a default — it is the schema.
Putting It Together
A complete minimal game has:
- A
.ceprogram that imports modules and callscore.start() - Sprite and entity modules (
.cm) that define game objects - A compositor config that describes the rendering setup
- Input configuration that maps keys to actions
The engine does the rest: batching sprites, sorting layers, managing GPU resources, polling events, scheduling frames.
Next Steps
- Graphics — Sprites, text, shapes, tilemaps
- Compositor — Planes, effects, presentation modes
- Input — Actions, players, control stacks
- Entities — The entity model and world system