Skip to content

scene

stable

A hierarchical 3D scene graph with named nodes, parent-child relationships, transforms (position/rotation/scale), and depth-first traversal.

use plugin scene::{SceneNode.new, add_child, remove_child, …}
18 functions Graphics
/ filter jk navigate Esc clear
Functions (18)
  1. SceneNode.new Create a named scene node
  2. add_child Attach a child node to a parent
  3. remove_child Detach a child node from a parent
  4. set_position Set the node's 3D position
  5. get_position Get the node's 3D position
  6. set_rotation Set the node's Euler rotation
  7. get_rotation Get the node's Euler rotation
  8. set_scale Set the node's 3D scale
  9. get_scale Get the node's 3D scale
  10. set_visible Show or hide the node
  11. is_visible Check if the node is visible
  12. get_name Get the node's name
  13. set_name Rename the node
  14. get_parent Get the parent node handle
  15. children List direct child handles
  16. child_count Count direct children
  17. find_by_name Search descendants by name
  18. traverse Return all descendants depth-first

Overview

scene is a hierarchical 3D scene graph: a tree of named nodes, each carrying a local transform (position, rotation, and scale) and a visibility flag. Nodes are opaque SceneNode handles created with SceneNode.new and wired together with add_child / remove_child, so the graph models parent-child relationships the way a game engine or 3D editor would. Transforms are stored per node as plain x/y/z triples (rotation in radians, scale defaulting to 1.0 on every axis).

Use it when you need to organize objects spatially and walk that structure: attach a weapon to a player, a camera to a rig, or props to a room, then query the tree with children, child_count, get_parent, find_by_name, and traverse. The mental model is simple: build nodes, parent them, set transforms, then read the hierarchy back by handle.

Common patterns

Build a small hierarchy and position the nodes within it:

use plugin scene::{SceneNode}

let world = SceneNode.new("world")
let player = SceneNode.new("player")
let weapon = SceneNode.new("weapon")

world.add_child(player)
player.add_child(weapon)

player.set_position(0.0, 0.0, 0.0)
weapon.set_position(0.5, 1.0, 0.0)
print("player has {player.child_count()} child")

Walk an entire subtree depth-first and print every node's name:

use plugin scene::{SceneNode}

let root = SceneNode.new("root")
let a = SceneNode.new("a")
let b = SceneNode.new("b")
root.add_child(a)
root.add_child(b)

let all = root.traverse()
print("nodes in subtree: {all[1].get_name()}, {all[2].get_name()}, {all[3].get_name()}")

Locate a deep descendant by name, then hide it:

use plugin scene::{SceneNode}

let level = SceneNode.new("level")
let arm = SceneNode.new("arm")
let hand = SceneNode.new("hand")
level.add_child(arm)
arm.add_child(hand)

let found = level.find_by_name("hand")
found.set_visible(false)
print("{found.get_name()} visible: {found.is_visible()}")

Create a named scene node

Creates a new scene node with the given name. The node starts at the origin with no parent and default scale of 1.0 on all axes.

use plugin scene::{SceneNode}

let root = SceneNode.new("root")
let camera = SceneNode.new("camera")
let light = SceneNode.new("sun")

root.add_child(camera)
root.add_child(light)
camera.set_position(0.0, 5.0, -10.0)

Attach a child node to a parent

Attaches child as a direct child of this node. Sets the child's parent reference automatically. Adding the same child twice is a no-op.

use plugin scene::{SceneNode}

let world = SceneNode.new("world")
let player = SceneNode.new("player")
let weapon = SceneNode.new("weapon")

world.add_child(player)
player.add_child(weapon)
print(world.child_count())   // 1
print(player.child_count())  // 1

Detach a child node from a parent

Detaches child from this node and clears the child's parent reference.

use plugin scene::{SceneNode}

let parent = SceneNode.new("parent")
let child = SceneNode.new("child")
parent.add_child(child)
parent.remove_child(child)
print(parent.child_count())  // 0

Set the node's 3D position

Sets the local 3D position of the node.

use plugin scene::{SceneNode}

let node = SceneNode.new("cube")
node.set_position(10.0, 0.0, -5.0)
let pos = node.get_position()
print("{pos["x"]}, {pos["y"]}, {pos["z"]}")  // 10, 0, -5

Get the node's 3D position

Returns the node's local position as a table with x, y, z float fields.

use plugin scene::{SceneNode}

let node = SceneNode.new("obj")
node.set_position(1.0, 2.0, 3.0)
let p = node.get_position()
print(p["x"])  // 1
print(p["y"])  // 2
print(p["z"])  // 3

Set the node's Euler rotation

Sets the node's local Euler rotation in radians (x=pitch, y=yaw, z=roll).

use plugin scene::{SceneNode}

let node = SceneNode.new("turret")
node.set_rotation(0.0, 1.5708, 0.0)  // 90 degrees yaw
let rot = node.get_rotation()
print(rot["y"])  // 1.5708

Get the node's Euler rotation

Returns the node's Euler rotation as a table with x, y, z float fields.

Set the node's 3D scale

Sets the node's local scale on each axis. Default is 1.0 on all axes.

use plugin scene::{SceneNode}

let node = SceneNode.new("sprite")
node.set_scale(2.0, 2.0, 1.0)
let s = node.get_scale()
print(s["x"])  // 2

Get the node's 3D scale

Returns the node's local scale as a table with x, y, z float fields.

Show or hide the node

Shows or hides the node. Visibility is a flag on the node only; child visibility is not affected by this call.

use plugin scene::{SceneNode}

let node = SceneNode.new("hud")
node.set_visible(false)
print(node.is_visible())  // false
node.set_visible(true)
print(node.is_visible())  // true

Check if the node is visible

Returns true if the node's visibility flag is set.

Get the node's name

Returns the node's current name.

use plugin scene::{SceneNode}

let node = SceneNode.new("enemy")
print(node.get_name())  // enemy

Rename the node

Renames the node. Useful when dynamically creating nodes that may later be searched by name.

use plugin scene::{SceneNode}

let node = SceneNode.new("temp")
node.set_name("boss_1")
print(node.get_name())  // boss_1

Get the parent node handle

Returns the parent node handle, or nil if the node has no parent.

use plugin scene::{SceneNode}

let root = SceneNode.new("root")
let child = SceneNode.new("child")
root.add_child(child)
let p = child.get_parent()
// p is the root handle

Re-parenting follows the chain: detach a node and its parent becomes nil again.

use plugin scene::{SceneNode}

let room = SceneNode.new("room")
let lamp = SceneNode.new("lamp")
room.add_child(lamp)
room.remove_child(lamp)
let p = lamp.get_parent()
print("orphaned: {p == nil}")  // true

List direct child handles

Returns a 1-indexed table of direct child node handles.

use plugin scene::{SceneNode}

let parent = SceneNode.new("parent")
let a = SceneNode.new("a")
let b = SceneNode.new("b")
parent.add_child(a)
parent.add_child(b)
let kids = parent.children()
print(parent.child_count())  // 2

Iterate the direct children to read each one's name:

use plugin scene::{SceneNode}

let group = SceneNode.new("group")
group.add_child(SceneNode.new("first"))
group.add_child(SceneNode.new("second"))

let kids = group.children()
print(kids[1].get_name())  // first
print(kids[2].get_name())  // second

Count direct children

Returns the number of direct children attached to this node.

Search descendants by name

Searches the subtree rooted at this node (excluding the node itself) for a descendant with the given name. Uses depth-first search. Returns the first match or nil.

use plugin scene::{SceneNode}

let root = SceneNode.new("root")
let a = SceneNode.new("arm")
let b = SceneNode.new("hand")
root.add_child(a)
a.add_child(b)

let found = root.find_by_name("hand")
print(found.get_name())  // hand

A search that matches nothing returns nil, which you can guard against:

use plugin scene::{SceneNode}

let root = SceneNode.new("root")
root.add_child(SceneNode.new("torso"))

let leg = root.find_by_name("leg")
print("found: {leg == nil}")  // true

Return all descendants depth-first

Returns a flat 1-indexed table of all node handles in the subtree rooted at this node, in depth-first order (including the node itself).

use plugin scene::{SceneNode}

let root = SceneNode.new("root")
let a = SceneNode.new("a")
let b = SceneNode.new("b")
root.add_child(a)
root.add_child(b)

let all = root.traverse()
print(all[1].get_name())  // root
print(all[2].get_name())  // a
print(all[3].get_name())  // b

Because the result includes the node itself, traverse is handy for bulk operations over a whole subtree, like hiding everything beneath a node:

use plugin scene::{SceneNode}

let menu = SceneNode.new("menu")
menu.add_child(SceneNode.new("button_a"))
menu.add_child(SceneNode.new("button_b"))

let nodes = menu.traverse()
for node in nodes {
  node.set_visible(false)
}
print("hidden subtree rooted at {nodes[1].get_name()}")
enespt-br