Files
dusk/.claude/scene.md
T
2026-06-16 10:15:59 -05:00

3.2 KiB

Scene System

Source: src/dusk/scene/

Overview

The scene system is the top-level coordinator for a running game state. It manages one active scene at a time. Scenes are JS scripts -- each scene is a .js asset file that exports an object with lifecycle hooks. The scene system loads, ticks, and tears down these scripts, while the C side runs the ECS and render pipeline on each tick.

Scene lifecycle (C side)

extern scene_t SCENE;

errorret_t sceneInit(void);     // initialise the scene manager
errorret_t sceneUpdate(void);   // process pending transition, tick active scene
errorret_t sceneRender(void);   // render entities + render pipeline + UI
errorret_t sceneDispose(void);  // dispose the active scene immediately

sceneUpdate each tick:

  1. Checks for a pending scene transition and performs it (dispose old, load and init new).
  2. Calls the JS scene's update() hook.
  3. Calls entityManagerUpdate() to fire all entity update callbacks.

sceneRender each tick:

  1. Binds the screen.
  2. Calls sceneRenderPipeline() -- renders all entities with a COMPONENT_TYPE_RENDERABLE in priority order.
  3. Renders UI.
  4. Calls the JS scene's render() hook (for any custom drawing).
  5. Unbinds the screen.

Scene lifecycle (JS side)

A scene file exports a plain object with these optional hooks:

var scene = {};

scene.init = async function() {
  // Load assets, create entities, set up state.
  // May be async -- await asset loads here.
};

scene.update = function() {
  // Called each fixed-timestep tick.
};

scene.render = function() {
  // Called each render tick, after ECS renderables.
};

scene.dispose = function() {
  // Clean up entities and state.
};

module.exports = scene;

See CLAUDE.md -- "JavaScript (asset scripts)" for JS style rules.

Render pipeline (scenerenderpipeline.h)

sceneRenderPipeline(cameraEntityId) gathers all active COMPONENT_TYPE_RENDERABLE components, sorts them by effective priority, and draws each one using its shader.

Priority rules:

  • renderable.priority != 0 -- use that value directly.
  • renderable.priority == 0 -- auto-derive: opaque geometry sorts before transparent geometry; sprite batches sort before shader materials; etc.
  • Lower priority number = drawn first (behind); higher = drawn last (on top).

The shader used for each renderable:

  • ENTITY_RENDERABLE_TYPE_SPRITEBATCH and CUSTOM default to SHADER_LIST_SHADER_UNLIT.
  • ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL uses the shader indexed by renderable.data.material.shaderType in SHADER_LIST_DEFS.

Transitioning between scenes

To move to a new scene from JS, call the scene module's transition function (exact API in the scene JS module). The C side defers the actual switch to the start of the next sceneUpdate call so the current tick completes cleanly before any dispose runs.

Relationship to the engine loop

engineUpdate()
  timeUpdate()
  inputUpdate()
  physicsManagerUpdate()
  scriptUpdate()       <- runs JS microjobs
  sceneUpdate()        <- JS update + ECS entity updates

engineUpdate() -> sceneRender()
  screenBind()
  sceneRenderPipeline()  <- ECS renderables sorted by priority
  uiRender()
  sceneRender (JS hook)
  screenUnbind / screenRender