tiramisu/scene

Scene graph module - declarative 3D scene construction.

This module provides types and functions for building 3D scenes declaratively. Scenes are composed of SceneNode values that describe meshes, lights, cameras, and groups.

Core Concepts

Quick Example

import tiramisu/scene
import tiramisu/transform
import gleam/option
import vec/vec3

pub fn view(model: Model) {
  let assert Ok(geometry) = scene.box(width: 1.0, height: 1.0, depth: 1.0)
  let assert Ok(material) = scene.basic_material(color: 0xff0000, transparent: False, opacity: 1.0)

  [
    scene.Mesh(
      id: "player",
      geometry: geometry,
      material: material,
      transform: transform.at(vec3.Vec3(0.0, 1.0, 0.0)),
      physics: option.None,
    ),
    scene.Light(
      id: "sun",
      light: scene.DirectionalLight(color: 0xffffff, intensity: 1.0),
      transform: transform.identity,
    ),
  ]
}

Types

Level of Detail (LOD) configuration.

Defines which mesh to display based on camera distance. Use with LOD scene node for automatic detail switching to improve performance.

Example

scene.LOD(
  id: "tree",
  levels: [
    scene.lod_level(distance: 0.0, node: high_detail_mesh),   // 0-50 units
    scene.lod_level(distance: 50.0, node: medium_detail_mesh), // 50-100 units
    scene.lod_level(distance: 100.0, node: low_detail_mesh),   // 100+ units
  ],
  transform: transform.identity,
)
pub type LODLevel(id) {
  LODLevel(distance: Float, node: Node(id))
}

Constructors

  • LODLevel(distance: Float, node: Node(id))

Scene node - the core building block of your 3D scene.

Scene nodes are immutable, declarative descriptions of objects in your game. Each frame, your view() function returns a list of scene nodes, and the engine efficiently updates only what changed.

Node Types

  • Mesh: Standard 3D object (1 draw call per mesh)
  • InstancedMesh: Many identical objects (1 draw call total!)
  • Group: Container for organizing child nodes in a hierarchy
  • Light: Illuminates the scene
  • Camera: Defines viewpoint (must have at least one with active: True)
  • LOD: Switches detail levels based on distance
  • Model3D: Loaded 3D model with animations
  • Audio: Background or positional audio
  • Debug*: Visualization helpers for development

Example

pub fn view(model: Model) {
  [
    scene.Group(
      id: "player",
      transform: transform.at(model.position),
      children: [
        scene.Mesh(
          id: "player-body",
          geometry: scene.BoxGeometry(1.0, 2.0, 1.0),
          material: scene.BasicMaterial(0x00ff00, False, 1.0, option.None),
          transform: transform.identity,
          physics: option.Some(model.physics_body),
        ),
      ],
    ),
  ]
}
pub type Node(id) {
  Mesh(
    id: id,
    geometry: geometry.Geometry,
    material: material.Material,
    transform: transform.Transform,
    physics: option.Option(physics.RigidBody),
  )
  InstancedMesh(
    id: id,
    geometry: geometry.Geometry,
    material: material.Material,
    instances: List(transform.Transform),
  )
  Group(
    id: id,
    transform: transform.Transform,
    children: List(Node(id)),
  )
  Light(
    id: id,
    light: light.Light,
    transform: transform.Transform,
  )
  Camera(
    id: id,
    camera: camera.Camera,
    transform: transform.Transform,
    look_at: option.Option(vec3.Vec3(Float)),
    active: Bool,
    viewport: option.Option(#(Int, Int, Int, Int)),
  )
  LOD(
    id: id,
    levels: List(LODLevel(id)),
    transform: transform.Transform,
  )
  Model3D(
    id: id,
    object: object3d.Object3D,
    transform: transform.Transform,
    animation: option.Option(object3d.AnimationPlayback),
    physics: option.Option(physics.RigidBody),
  )
  Audio(id: id, audio: audio.Audio)
  Particles(
    id: id,
    emitter: particle_emitter.ParticleEmitter,
    transform: transform.Transform,
    active: Bool,
  )
  DebugBox(
    id: id,
    min: vec3.Vec3(Float),
    max: vec3.Vec3(Float),
    color: Int,
  )
  DebugSphere(
    id: id,
    center: vec3.Vec3(Float),
    radius: Float,
    color: Int,
  )
  DebugLine(
    id: id,
    from: vec3.Vec3(Float),
    to: vec3.Vec3(Float),
    color: Int,
  )
  DebugAxes(id: id, origin: vec3.Vec3(Float), size: Float)
  DebugGrid(id: id, size: Float, divisions: Int, color: Int)
  DebugPoint(
    id: id,
    position: vec3.Vec3(Float),
    size: Float,
    color: Int,
  )
}

Constructors

Values

pub fn lod_level(
  distance distance: Float,
  node node: Node(id),
) -> LODLevel(id)

Create an LOD level with a distance threshold and scene node.

Levels should be ordered from closest (distance: 0.0) to farthest.

Example

let high_detail = scene.lod_level(distance: 0.0, node: detailed_mesh)
let low_detail = scene.lod_level(distance: 100.0, node: simple_mesh)
Search Document