Docs

Query System

Systems Map

Query is a runtime filter that returns NodeID values for nodes matching boolean expressions and name, tag, type, or base type predicates. Start with direct lookup (name/tag/type), then compose filters with gates and subtree scope. Without in_subtree, the full tree is queried.

Query itself does not cause borrow pain. Main rule stays same: collect values, then run one runtime mutation closure at a time.

Macro forms

query!(ctx, expr) -> Vec<NodeID>query!(ctx, expr, in_subtree(parent_id)) -> Vec<NodeID>query_first!(ctx, expr) -> Option<NodeID>query_first!(ctx, expr, in_subtree(parent_id)) -> Option<NodeID>

Simple lookup first

let boss = query_first!(ctx, all(name["Boss"]));let enemies = query!(ctx, all(tags["enemy"]));let cameras = query!(ctx, all(is[Camera3D]));

Composition power

Query predicates compose into high-signal runtime selectors. This is practical ECS-style targeting with node types as structure and tags as runtime grouping data.

let arena_targets = query!(    ctx,    all(        any(tags["enemy"], tags["elite"]),        base_type[Node3D],        not(tags["dead"])    ),    in_subtree(arena_root)); for id in arena_targets {    let _ = with_base_node_mut!(ctx, Node3D, id, |node| {        node.position.y += 0.1;    });}

Tags can be authored in scenes or changed at runtime with tag_set!, tag_add!, and tag_remove!.

Query + borrow-safe mutation flow

Typical pattern: query IDs first, compute helper values, then mutate each target in short closures.

// 1) find idslet ids = query!(ctx, all(tags["enemy"], base_type[Node3D])); // 2) optional: collect runtime values outside mutation closureslet dt = delta_time!(ctx); // 3) mutate in isolated closuresfor id in ids {    let _ = with_base_node_mut!(ctx, Node3D, id, |node| {        node.position.y += 0.1 * dt;    });}

Predicates

name[...]

Match one or more scene node names.

tags[...]

Match nodes carrying runtime tags.

is[...] / is_type[...]

Match exact concrete node types.

base[...] / base_type[...]

Match nodes that inherit from a base type.

Gates + scope

all(...)

Every nested condition must match.

any(...)

At least one nested condition must match.

not(...)

Inner condition must not match.

in_subtree(parent_id)

Limit query to descendants under one parent.

Exact type vs base type

is[] and is_type[] match concrete node types. base[] and base_type[] use inheritance checks and match descendants of a base type.

When a query returns mixed Node3D descendants, use with_base_node! or with_base_node_mut! to access shared base fields safely.