Skip to content
Plugins (190)

scene

stable

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

use plugin scene
18 functions Graphics
Runs with the native Zolo host

Plugin snippets can be edited in the Playground, but native capabilities are executed locally with the Zolo CLI.

/ 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

From import to result

  1. 01Import only what you use
  2. 02Copy the smallest example
  3. 03Run it with the Zolo CLI

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()}")

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

en