scene
stableA 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, …} Functions (18)
- SceneNode.new Create a named scene node
- add_child Attach a child node to a parent
- remove_child Detach a child node from a parent
- set_position Set the node's 3D position
- get_position Get the node's 3D position
- set_rotation Set the node's Euler rotation
- get_rotation Get the node's Euler rotation
- set_scale Set the node's 3D scale
- get_scale Get the node's 3D scale
- set_visible Show or hide the node
- is_visible Check if the node is visible
- get_name Get the node's name
- set_name Rename the node
- get_parent Get the parent node handle
- children List direct child handles
- child_count Count direct children
- find_by_name Search descendants by name
- 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()}")