Top Level Namespace

Included Modules

Extended Modules

Defined in:

Method Summary

Macro Summary

Instance methods inherited from module Lapis::Test

add_child_autofree(parent : Godot::Node, child : T) : T forall T
add_child_autofree(child : T) : T forall T
add_child_autofree
, assert_alive(object : Godot::Object, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_alive, assert_approx_eq(actual : Float32 | Float64, expected : Float32 | Float64, epsilon : Float64 = 0.001, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_approx_eq, assert_between(actual : Number, min : Number, max : Number, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_between, assert_bytes_per_iteration(max_rate : Float64 | Number, name : String = "Operation", iterations : Int32 = 1000, warmup : Int32 = 10, file : String = __FILE__, line : Int32 = __LINE__, &) : Lapis::Profiler::AllocationReport assert_bytes_per_iteration, assert_child_count(node : Godot::Node, expected : Int32, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) : Void assert_child_count, assert_connected(emitter : Godot::Object, signal_name : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_connected, assert_disposed(object : Godot::Object, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_disposed, assert_emits(emitter : Godot::Object, signal_name : String, timeout_sec : Float64 = 2.0, file : String = __FILE__, line : Int32 = __LINE__, &) : Array(Variant) assert_emits, assert_empty(collection, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_empty, assert_eq(actual, expected, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_eq, assert_false(cond : Bool | Nil, msg : String = "Expected false, got true", file : String = __FILE__, line : Int32 = __LINE__) assert_false, assert_file_does_not_exist(path : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_file_does_not_exist, assert_file_empty(path : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_file_empty, assert_file_exists(path : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_file_exists, assert_file_not_empty(path : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_file_not_empty, assert_freed(object : Godot::Object, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_freed, assert_gt(actual : Comparable, expected : Comparable, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_gt, assert_gte(actual : Comparable, expected : Comparable, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_gte, assert_has_child(node : Godot::Node, name : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) : Void assert_has_child, assert_has_method(obj : Godot::Object, method_name : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_has_method, assert_has_node(parent : Godot::Node, path : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_has_node, assert_has_signal(emitter : Godot::Object, signal_name : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_has_signal, assert_in_delta(actual : Number, expected : Number, delta : Number, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_in_delta, assert_includes(collection, item, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_includes, assert_invalid_id(instance_id : UInt64 | Int64, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_invalid_id, assert_is_a(obj, klass : T.class, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) forall T assert_is_a, assert_lt(actual : Comparable, expected : Comparable, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_lt, assert_lte(actual : Comparable, expected : Comparable, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_lte, assert_max_allocations(max_bytes : Int64 | Int32, name : String = "Operation", iterations : Int32 = 1000, warmup : Int32 = 10, file : String = __FILE__, line : Int32 = __LINE__, &) : Lapis::Profiler::AllocationReport assert_max_allocations, assert_memory_stable(cycles : Int32 = 1, max_delta : Int32 = 2, name : String = "Memory Stability", file : String = __FILE__, line : Int32 = __LINE__, &block) assert_memory_stable, assert_ne(actual, expected, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_ne, assert_nil(val, msg : String = "Expected nil value", file : String = __FILE__, line : Int32 = __LINE__) assert_nil, assert_no_emit(emitter : Godot::Object, signal_name : String, duration_sec : Float64 = 0.5, file : String = __FILE__, line : Int32 = __LINE__, &) : Void assert_no_emit, assert_no_leak(max_delta_objects : Int32 = 0, name : String = "Operation", file : String = __FILE__, line : Int32 = __LINE__, &) assert_no_leak, assert_no_new_orphans(msg : String = "", file : String = __FILE__, line : Int32 = __LINE__, &) assert_no_new_orphans, assert_no_signal(target : Godot::Object, signal_name : String, during_frames : Int32 = 10, file : String = __FILE__, line : Int32 = __LINE__) : Void
assert_no_signal(target : Godot::Object, signal_name : String, file : String = __FILE__, line : Int32 = __LINE__, &block : -> Void) : Void
assert_no_signal
, assert_node_path_exists(root : Godot::Node, path : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) : Void assert_node_path_exists, assert_not_between(actual : Number, min : Number, max : Number, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_not_between, assert_not_connected(emitter : Godot::Object, signal_name : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_not_connected, assert_not_empty(collection, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_not_empty, assert_not_freed(object : Godot::Object, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_not_freed, assert_not_nil(val, msg : String = "Expected non-nil value", file : String = __FILE__, line : Int32 = __LINE__) assert_not_nil, assert_not_same(actual : Reference, expected : Reference, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_not_same, assert_raises(klass : T.class, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__, &) forall T assert_raises, assert_refcount(refcounted : Godot::RefCounted, expected : Int32, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_refcount, assert_same(actual : Reference, expected : Reference, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_same, assert_settled(body : Godot::Object, max_frames : Int32 = 60, linear_epsilon : Float64 = 0.05, angular_epsilon : Float64 = 0.05, file : String = __FILE__, line : Int32 = __LINE__) : Void assert_settled, assert_signal_count(spy : SignalSpy, count : Int32, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_signal_count, assert_signal_emit_count(spy : SignalSpy, count : Int32, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_signal_emit_count, assert_signal_emitted(spy : SignalSpy, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_signal_emitted, assert_signal_not_emitted(spy : SignalSpy, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_signal_not_emitted, assert_string_contains(str : String, substr : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_string_contains, assert_string_ends_with(str : String, suffix : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_string_ends_with, assert_string_starts_with(str : String, prefix : String, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_string_starts_with, assert_true(cond : Bool | Nil, msg : String = "Expected true, got false", file : String = __FILE__, line : Int32 = __LINE__) assert_true, assert_valid_id(instance_id : UInt64 | Int64, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__) assert_valid_id, assert_vector_approx(actual : Godot::Vector2, expected : Godot::Vector2, epsilon : Float64 = 0.001, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__)
assert_vector_approx(actual : Godot::Vector3, expected : Godot::Vector3, epsilon : Float64 = 0.001, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__)
assert_vector_approx(actual : Godot::Color, expected : Godot::Color, epsilon : Float64 = 0.001, msg : String = "", file : String = __FILE__, line : Int32 = __LINE__)
assert_vector_approx
, assert_zero_allocation(name : String = "Hot Loop", iterations : Int32 = 1000, warmup : Int32 = 10, file : String = __FILE__, line : Int32 = __LINE__, &) : Lapis::Profiler::AllocationReport assert_zero_allocation, autofree(obj : T) : T forall T autofree, autofree_all : Void autofree_all, autoqfree(node : T) : T forall T autoqfree, await_signal(emitter : Godot::Object, signal_name : String, timeout_sec : Float64 = 2.0, file : String = __FILE__, line : Int32 = __LINE__) : Array(Variant) await_signal, cleanup_autofree : Void cleanup_autofree, cleanup_tracked_nodes : Void cleanup_tracked_nodes, input_sender : InputSender input_sender, pending(reason : String = "Test pending implementation") : Nil pending, profile_allocations(name : String = "Operation", iterations : Int32 = 1000, warmup : Int32 = 10, &) : Lapis::Profiler::AllocationReport profile_allocations, scenario(root : Godot::Node, name : String, &block : ScenarioStepContext -> Void) : Void
scenario(name : String, &block : ScenarioStepContext -> Void) : Void
scenario
, simulate(node : Godot::Node, frames : Int32 = 1, delta : Float64 = 0.016666666666666666, physics : Bool = false) : Void simulate, skip_frames(count : Int32 = 1) : Void skip_frames, skip_if(condition : Bool, reason : String = "Test skipped") : Nil skip_if, skip_physics_frames(count : Int32 = 1) : Void skip_physics_frames, suppress_errors(&) suppress_errors, track_node(node : Godot::Node) : Godot::Node track_node, with_node(klass : T.class, parent : Godot::Node | Nil = nil, &block : T -> Void) forall T with_node, with_timeout(timeout_sec : Float64 = 5.0, operation_name : String = "Operation", file : String = __FILE__, line : Int32 = __LINE__, &) with_timeout

Class methods inherited from module Lapis::Test

autofree_objects autofree_objects, autoqfree_nodes autoqfree_nodes, tracked_nodes tracked_nodes

Method Detail

def after(delay : Time::Span | Number, node : Godot::Node | Nil = nil, &block : Godot::TimerHandle -> Void) : Godot::TimerHandle #

def crystal_godot_init(api : Pointer(Godot::LibBridge::BridgeAPI)) : Void #

C ABI Entry point called by crystal_bridge when game library is loaded


def every(interval : Time::Span | Number, node : Godot::Node | Nil = nil, &block : Godot::TimerHandle -> Void) : Godot::TimerHandle #

Top-level gameplay convenience methods


def group(name : String | Symbol) : Godot::GroupQuery #

Global fluent group query helper


def load(path : String, type_hint : String = "", cache_mode : Int64 = 0_i64) : Godot::Resource #

Global convenience helper to load resources from Godot VFS


def nodes(regex : Regex) : Array(Godot::Node) #

Global query helper returning all nodes matching the regex under the active node context.

Example:

nodes(~/coin_\d+/).each(&.queue_free)

def on_main_thread(&block : -> Void) : Void #

Dispatches block to execute safely on the Godot Main Thread. Executes immediately if already on the main thread; queues if on a worker thread.


def preload(path : String) : Godot::Resource #

Global convenience helper to preload resources from Godot VFS


def vec2(x : Number, y : Number) : Godot::Vector2 #

Top-level math constructors


def vec3(x : Number, y : Number, z : Number) : Godot::Vector3 #

def vec4(x : Number, y : Number, z : Number, w : Number) : Godot::Vector4 #

Macro Detail

macro __define_node_ref_property(name_or_decl, type = nil, path = nil, is_unique = false, is_nilable = false) #

Declares a lazy-cached node property matching Godot's @onready pattern.

Unlike eager onready var = path properties which initialize strictly during _ready, this macro defines a lazy getter that resolves the node on first access, caches the pointer, and verifies #check_alive! on every subsequent access to protect against dead-pointer dereferencing.

Supported Styles:

  1. Auto-inferred name and type: onready sprite_2d, Sprite2D (fetches child "Sprite2D")
  2. Scene Unique Node: onready camera, Camera2D, "%MainCamera"
  3. Explicit path: onready sprite, Sprite2D, "Visuals/Sprite2D"

Example:

node Enemy < CharacterBody2D do
  onready sprite, Sprite2D, "Visuals/Sprite2D"
  onready health_bar, ProgressBar, "%HealthBar"

  def hit : Void
    sprite.modulate = Godot::Color.new(1.0, 0.0, 0.0) # Resolves and caches sprite
  end
end

Internal generator synthesizing dead-pointer safe, lazy-cached node property accessors.


macro abstract_class #

Convenience macro to designate a class as abstract in Godot.


macro await(target, signal_name = nil, timeout_sec = nil) #

Cooperatively awaits a signal, timer, or duration without blocking the engine main thread.

Rationale & Execution Model:

In Godot, asynchronous gameplay events (animations, dialogue timers, death signals) must not block the engine's main loop (_process / _physics_process). Standard Crystal sleep suspends the entire OS thread and hangs the engine.

await suspends only the calling Crystal fiber, polling Godot cooperatively across frame steps while ensuring:

  1. Zero main thread stalling.
  2. Immediate dead-pointer protection: if the emitting node is freed (destroy/free/queue_free) while waiting, await unblocks immediately with status.freed? == true (while await! raises Godot::DisposedObjectError and await? returns nil).
  3. Optional timeout support with automated timeout cancellation.

Supported Calling Forms:

# 1. First-class bound signal:
await(enemy.died)
await(enemy.died, timeout_sec: 5.0)

# 2. Dynamic target and string signal name:
await(boss, "phase_transition")
await(boss, "phase_transition", timeout_sec: 10.0)

# 3. SceneTree timer:
await(get_tree.create_timer(1.5).timeout)

# 4. Numeric delay in seconds:
await(1.5)
await(2.seconds)

macro await!(target, signal_name = nil, timeout_sec = nil) #

Cooperatively awaits a signal, timer, or duration, raising Godot::DisposedObjectError if the target is freed or Godot::TimeoutError if timeout expires.


macro await?(target, signal_name = nil, timeout_sec = nil) #

Cooperatively awaits a signal, timer, or duration, returning nil if the target is freed, or nil (or false) if timeout expires.


macro await_until(condition, timeout_sec, &block) #

Cooperatively yields the calling fiber until condition evaluates to truthy.

Uses Fiber.yield between evaluation cycles. Supports an optional timeout_sec parameter which raises Godot::TimeoutError if exceeded.

Example:

await_until(character.on_floor?, timeout_sec: 5.0)

macro await_while(condition, timeout_sec, &block) #

Cooperatively yields the calling fiber while condition evaluates to truthy.

Uses Fiber.yield between evaluation cycles. Supports an optional timeout_sec parameter which raises Godot::TimeoutError if exceeded.

Example:

await_while(tween.is_running, timeout_sec: 3.0)

macro build(type, **kwargs, &block) #

Idiomatic alias for create


macro cold_boot_test(category, name, &block) #

Dedicated declarative cold boot test macro


macro create(type, **kwargs, &block) #

Instantiates a Godot object or custom node and configures its properties and methods in a block or kwargs.

Supports:

  1. Keyword properties: create Sprite2D, position: Vector2.new(10, 20), centered: true
  2. Block property setters: create Sprite2D do position = Vector2.new(10, 20); centered = true end
  3. Method dispatches: create Sprite2D do add_to_group("sprites"); rotate(0.5) end
  4. Mixed kwargs and block: create Sprite2D, centered: true do position = Vector2.new(10, 20) end

macro create_child(type, under = nil, **kwargs, &block) #

Declarative alias for spawn_node


macro define_log_filter(name, **opts) #

macro define_log_filters(&block) #

macro define_string_enum_export(macro_name, hint_string, default_fallback = "") #

Defines a custom export macro macro_name that declares an exported String property with PROPERTY_HINT_ENUM (2_u32) and hint_string in the Godot Inspector.


macro delegate_property_to_instance(*prop_names) #

Forwards class-level properties to the class singleton instance


macro delegate_to_instance(*method_names) #

Forwards class-level methods to the class singleton instance (e.g. Input, AudioServer)


macro emit(signal_expr, *args) #

Type-safe signal emitter macro.

Emits signals directly via TypedSignal#emit or emit_signal.

Examples:

emit(player.health_changed, 50, 100) # Expands to player.health_changed.emit(50, 100)
emit(player.renamed)                  # Expands to player.renamed.emit
emit(health_changed, 50, 100)         # Inside Player: expands to health_changed.emit(50, 100)
emit(sig, 50, 100)                    # Signal variable: expands to sig.emit(50, 100)

macro ensure_lapis #

The primary node macro: Usage: node MyNode node MyNode do # defaults to Godot::Node end

node Player < CharacterBody3D node Player < CharacterBody3D do # inherits Godot::CharacterBody3D end Expressive loader macro to ensure Lapis engine bindings are loaded without duplicate require cycles or missing dependency errors


macro export_category(name, &block) #

Categorizes top-level inspector sections in Godot.

May be used standalone or as a block scoping exported properties.

Example:

node Boss < CharacterBody3D do
  export_category "Combat Stats" do
    @[Export]
    property health : Int32 = 1000

    @[Export]
    property defense : Int32 = 50
  end
end

macro export_group(name, prefix = "", &block) #

Groups exported properties under a common folding group in the Godot inspector.

May be used standalone or as a block scoping exported properties.

Example:

node Vehicle < CharacterBody3D do
  export_group "Engine", prefix: "engine_" do
    @[Export]
    property engine_power : Float32 = 250.0_f32

    @[Export]
    property engine_torque : Float32 = 400.0_f32
  end
end

macro export_subgroup(name, prefix = "", &block) #

Subgroups exported properties under the current inspector group.

May be used standalone or as a block scoping exported properties.

Example:

node Character < CharacterBody3D do
  export_group "Movement" do
    export_subgroup "Advanced", prefix: "adv_" do
      @[Export]
      property adv_friction : Float32 = 0.1_f32
    end
  end
end

macro gdclass(decl, &block) #

Declares a custom RefCounted or generic Godot engine class registered with ClassDB. Defaults to inheriting RefCounted when no parent is specified. Can be called with or without a block (e.g. gdclass MyState).

gdclass StateMachine < RefCounted do
  @[Export]
  property current_state : String = "idle"
end

gdclass SimpleState

macro gmodule(decl, &block) #

Declares a reusable Godot module or mixin registered with ClassDB metadata. Can declare properties (with @[Export]), signals, lifecycle hooks, and interface methods. When included into a node, gdclass, or resource via include, its properties and signals are automatically registered with ClassDB and dispatched via the GDExtension bridge.

Examples:

gmodule Damageable do
  signal health_changed(current : Int32, max : Int32)
  signal died

  @[Export(range: 0..100)]
  property health : Int32 = 100

  @[Export]
  property max_health : Int32 = 100

  def take_damage(amount : Int32) : Void
    self.health = Math.max(0, self.health - amount)
    emit(health_changed, self.health, self.max_health)
    emit(died) if self.health == 0
  end
end

node Player < CharacterBody2D do
  include Damageable
end

macro godot_bind(var_name, class_name, method_name, hash) #

Lazily retrieves and caches a GDExtension method bind handle from ClassDB


macro godot_call_str(method_name, *args) #

Dynamically calls an instance method and returns the result as a Crystal String


macro godot_collider_query(cls_name, indexed = false) #

Synthesizes null-safe #get_collider? query on raycasts and shapecasts


macro godot_marshal_enum(name, idx) #

Marshals an enum or integer argument into a typed 64-bit pointer for ptrcall


macro godot_marshal_nodepath(name, idx) #

Marshals a NodePath or String argument into an unmanaged Godot NodePath pointer


macro godot_marshal_obj(name, idx) #

Marshals a Godot Object wrapper into an unmanaged pointer-to-pointer for ptrcall


macro godot_marshal_str(name, idx) #

Marshals a String argument into an unmanaged Godot String pointer


macro godot_marshal_string_name(name, idx) #

Marshals a String or StringName argument into an interned StringName pointer


macro godot_marshal_val(name, idx) #

Marshals a primitive scalar (Float, Int, Bool, Vector2/3, Color) for ptrcall


macro godot_module(decl) #

macro godot_prop(prop_name, getter_name, setter_name = nil) #

Synthesizes an ergonomic getter and setter pair


macro godot_ptrcall(mb, target_ptr, args_slice, ret_ptr) #

Executes a low-overhead GDExtension ptrcall


macro godot_ptrcall_bool(mb, target_ptr, args_slice) #

Executes a ptrcall returning a boolean


macro godot_ptrcall_enum(mb, target_ptr, args_slice, enum_type) #

Executes a ptrcall returning a strongly-typed enum


macro godot_ptrcall_float(mb, target_ptr, args_slice) #

Executes a ptrcall returning a float (Float64 / Float32)


macro godot_ptrcall_float32(mb, target_ptr, args_slice) #

macro godot_ptrcall_float64(mb, target_ptr, args_slice) #

macro godot_ptrcall_int(mb, target_ptr, args_slice) #

Executes a ptrcall returning an integer (Int64)


macro godot_ptrcall_obj(mb, target_ptr, args_slice, class_type) #

Executes a ptrcall returning a typed object wrapper, reusing alive instance if present


macro godot_ptrcall_obj_or_nil(mb, target_ptr, args_slice, class_type) #

Executes a ptrcall returning a typed object wrapper, or nil if Godot returned nullptr


macro godot_ptrcall_val(mb, target_ptr, args_slice, type_name) #

Executes a ptrcall returning a value type with default constructor (e.g. Vector2, Vector3, Color, Transform3D)


macro godot_ptrcall_void(mb, target_ptr, args_slice) #

Executes a void ptrcall with no return buffer


macro godot_return_enum(enum_type, ret_var) #

Instantiates a strongly-typed enum from a 64-bit ptrcall return buffer


macro godot_return_obj(class_type, ret_ptr) #

Wraps a returned native object pointer into its typed Crystal wrapper


macro godot_signal(name, *types) #

Synthesizes a first-class typed signal accessor, StaticSignalSlot view, and direct emission helper


macro godot_singleton(cls_name, godot_name, parent_type = Godot::Object) #

Defines a Godot singleton accessor and pointer caching


macro godot_singleton_accessor(method_name, cls_name) #

Emits top-level Godot module singleton helper


macro godot_static_call_str(method_name, *args) #

Dynamically calls a static engine method and returns the result as a Crystal String


macro group(*group_names) #

Declaratively assigns the node to one or more scene tree groups upon _ready.

The node macro extracts all group statements and registers them automatically in Godot's SceneTree when the node enters the tree.

Example:

node Player < CharacterBody3D do
  group "players", "damageable", "interactable"
end

macro icon(path) #

Convenience macro to set a custom icon path in the editor.


macro instantiate(path, as type = Godot::Node, **kwargs, &block) #

Loads a PackedScene (.tscn) and instantiates it as wrapper type T with configuration


macro instantiate_child(path, under = nil, as type = Godot::Node, **kwargs, &block) #

Loads a PackedScene (.tscn), instantiates it as wrapper type T, and attaches it as a child to the parent


macro load(path) #

Loads a resource dynamically from the Godot virtual filesystem with compile-time type inference.

Supported extensions:

For custom types, chain .as(Type):

config = load("res://data.tres").as(CustomConfig)

macro load?(path) #

Safe, nil-returning variant of load(path).

Returns nil if the resource fails to load or does not exist on disk.

Example:

if scene = load?("res://dlc/bonus_level.tscn")
  # ...
end

macro log_filter(name, **opts) #

Re-export at top-level for maximum ergonomics


macro match(target, &block) #

Expression-oriented pattern matching macro designed for concise, expressive gameplay scripting.

Returns the evaluated result of the first matching branch, or nil if no branch matched.

Rationale & Architectural Design:

While Crystal's native case / when statement is powerful, game development in Godot requires specialized pattern matching capabilities that native case cannot express:

  1. Variant Unboxing: Automatically extracting typed values from dynamically typed Godot::Variant.
  2. Dead-Pointer Safe Node Downcasting: Verifying #alive? during downcasting so freed nodes never match.
  3. Implicit Variable Binding: Allowing match i do is Int64 do "Value: #{i * 2}" end without repetitive |i| closures.
  4. String & Symbol Equivalence: Matching :action against "action" seamlessly for input and state machines.
  5. Structural Destructuring: Extracting elements from Tuples, Arrays with rest ranges ([first, .., last]), and Dictionaries.

Supported Syntax Patterns:

1. Implicit Variable Binding (Variable is narrowed to branch type):

value_text = match i do
  is Int64          do "Integer: #{i * 2}" end
  is String         do "Text: #{i.upcase}" end
  is Godot::Vector2 do "Vector: (#{i.x}, #{i.y})" end
  default           do "Unsupported Variant" end
end

2. Explicit Parameter Binding:

description = match hit.collider do
  is Player do |player| "Player with #{player.health} HP" end
  is Enemy  do |enemy|  "Enemy of level #{enemy.level}" end
  default   do "Non-entity obstacle" end
end

3. Guard Clauses (if: named argument):

label = match score do
  is Int64, if: score > 1000 do "High Score: #{score}" end
  is Int64                   do "Normal Score: #{score}" end
  default                    do "Invalid" end
end

4. Multi-Pattern Splats:

match state do
  is :idle, :standing do play_animation("idle") end
  is :run, :sprint    do play_animation("run") end
end

5. Tuple Destructuring:

match {state, on_floor?} do
  is :jumping, false do apply_air_control end
  is :jumping, true  do land! end
end

6. Array Rest Matching:

match inventory do
  is [first, .., last] do |f, l| "First: #{f}, Last: #{l}" end
  default do "Empty or small" end
end

7. Dictionary Matching:

match packet do
  is dict(type: "chat", body: msg) do |_, text| display_message(text) end
  default do handle_unknown_packet end
end

macro multiplayer_test(name, clients = 2, &block) #

Dedicated declarative multiplayer simulation test macro


macro n!(path, type = nil) #

Ultra-short alias for node!(path, type).


macro n?(path, type = nil) #

Ultra-short alias for node?(path, type).


macro node(decl, &block) #

macro node!(path, type = nil) #

Immediately retrieves a child node from the current node's scene hierarchy.

Provides GDScript $ parity with static type casting.

Supported Patterns:

  1. Type-inferred: node!(Sprite2D) -> looks up "Sprite2D" and casts to Sprite2D
  2. Path with Type: node!("Visuals/Sprite2D", Sprite2D) -> resolves path and casts to Sprite2D
  3. Path string: node!("Visuals/Sprite2D") -> resolves path as untyped Godot::Node

Raises Godot::NodeNotFoundError if the node is not found or fails type casting.

Example:

def _ready : Void
  sprite = node!(Sprite2D)
  camera = node!("Pivot/Camera3D", Camera3D)
end

macro node2d(decl, &block) #

Expressive convenience macro for 2D scene nodes defaulting to Godot::Node2D


macro node3d(decl, &block) #

Expressive convenience macro for 3D spatial nodes defaulting to Godot::Node3D


macro node?(path, type = nil) #

Safely retrieves a child node from the current node's scene hierarchy, returning nil if not found.

Supported Patterns:

  1. Type-inferred: node?(Sprite2D) -> looks up "Sprite2D", returns Sprite2D?
  2. Path with Type: node?("Visuals/Sprite2D", Sprite2D) -> returns Sprite2D?
  3. Path string: node?("Visuals/Sprite2D") -> returns Godot::Node?

macro node_path!(path) #

Creates a compile-time verified Godot::NodePath


macro node_ref(name_or_decl, type = nil, path = nil) #

Declares a dead-pointer safe, lazy-cached node property matching Godot's @onready pattern.

Supports:

  1. Macro signature: node_ref player, Player, "Player"
  2. Type declaration: node_ref player : Player = "Player"
  3. Auto-inferred: node_ref sprite_2d : Sprite2D

macro node_ref?(name_or_decl, type = nil, path = nil) #

Declares a safe, lazy-cached node property that returns nil if missing or type mismatch.

Examples:

node_ref? player, PlayerController, "Player"
node_ref? hud : GameHUD = "HUD"

macro on(sig_or_target, *args, once = false, &block) #

Expressive signal connection macro

Supports:

  1. First-class signal: on button.pressed { do_something }
  2. Positional type filter: on body_entered, Player { |p| p.collect }
  3. Multi-argument type filters: on item_equipped, Player, Sword { |p, s| ... }
  4. Any wildcard filter: on damage_received, Player, Any { |p, info| ... }
  5. One-shot execution: on boss.died, Player, once: true { |p| ... }
  6. Target and signal string: on enemy, "died" { |bounty| add_score(bounty) }

macro on_signal(sig_or_target, *args, once = false, &block) #

Zero-allocation static signal connection macro binding compile-time typed procs or blocks directly to StaticSignalTable slots.

Can be used both:

  1. Declaratively at class body scope inside node or gmodule:
    node Player < CharacterBody3D do
      signal health_changed(new_health : Int32, max_health : Int32)
      signal died
    
      on_signal health_changed, ->on_health_changed(Int32, Int32)
      on_signal :died, ->on_died, once: true
    
      def on_health_changed(hp : Int32, max : Int32) : Void
      end
    
      def on_died : Void
      end
    end
  2. Imperatively inside methods or scripts:
    on_signal player.health_changed, ->(hp : Int32, max : Int32) { ... }
    on_signal player.health_changed_slot, handler_proc
    on_signal player, :health_changed, handler_proc, once: true
    on_signal player.health_changed do |hp, max|
      ...
    end

macro onready(name_or_decl, type = nil, path = nil) #

macro onready?(name_or_decl, type = nil, path = nil) #

Declares a safe, lazy-cached node property that returns nil if missing or type mismatch.

Examples:

onready? player, PlayerController, "Player"
onready? hud, GameHUD, "HUD"

macro play_sound(stream, at = nil, under = nil, **kwargs, &block) #

Context-aware one-shot audio playback macro:

  • Inspects @type at compile-time:
    • @type <= Godot::Node2D -> emits AudioStreamPlayer2D with global_position
    • @type <= Godot::Node3D -> emits AudioStreamPlayer3D with global_position
    • Otherwise -> emits non-spatial AudioStreamPlayer
  • If explicit at: coordinate is passed (Vector2 or Vector3), spatializes appropriately
  • Automatically preloads or loads the AudioStream
  • Sets kwargs properties (e.g. pitch_scale: 1.2, volume_db: -5.0, bus: "SFX")
  • Executes inline configuration block (e.g. do pitch_scale = 1.2 end)
  • Attaches to active scene root (current_scene || root) so audio survives caller deletion!
  • Connects finished.once { queue_free } for automatic memory cleanup
  • Returns the strongly-typed audio player

macro preload(path) #

Preloads and caches a resource from the Godot virtual filesystem with compile-time type inference.

Supported extensions:

For custom types, chain .as(Type):

const CONFIG = preload("res://data.tres").as(CustomConfig)

macro preload?(path) #

Safe, nil-returning variant of preload(path).

Returns nil if the resource fails to load or does not exist on disk.

Example:

if icon = preload?("res://custom_icon.png")
  # ...
end

macro resource(decl, &block) #

Declares a custom Godot Resource class registered with ClassDB and EditorHelp. Supports @[Export] properties, custom signals, and serialization to .tres.

resource ItemData < Resource do
  @[Export]
  property item_name : String = "Health Potion"

Declares a custom Resource subclass registered with ClassDB.
Defaults to inheriting `Resource` when no parent is specified.
Can be called with or without a block (e.g. `resource MyItem`).

resource CustomPotion do @[Export] property item_name : String = "Health Potion"

@[Export] property value : Int32 = 50 end

resource ShortItem


macro resource_card(decl, &block) #

Declares a custom Resource strategy card.

Custom Resources inheriting from Godot::Resource act as pluggable strategy objects and data containers (e.g. inventory items, ability cards, weapon stats).

Example:

resource_card WeaponCard < Resource do
  @[Export]
  property damage : Int32 = 50
  @[Export]
  property cooldown : Float32 = 1.0_f32

  def use(target : CharacterBody2D) : Void
    # strategy implementation
  end
end

macro signal(name_or_decl, *extra_types) #

Declares a custom Godot signal with first-class typed signal accessors.

class Player < Godot::CharacterBody3D
  signal health_changed(new_health : Int32, max_health : Int32)
  signal died

  def take_damage(amount : Int32)
    health_changed.emit(50, 100)
    died.emit if amount >= 100
  end
end

macro spawn_child(type, under = nil, **kwargs, &block) #

Contextual alias for spawn_node


macro spawn_node(type, under = nil, **kwargs, &block) #

Instantiates a node, configures it, and attaches it as a child to the specified parent (defaults to self if inside a Node method, or current scene / root).


macro static_unload #

Convenience macro to mark extension library unloading behavior.


macro test_case(category, name, cold_boot = false, &block) #

Base test_case macro


macro test_suite(category, &block) #

Declarative suite macro allowing grouped tests, parameterized tests, and suite/case lifecycle hooks


macro tween(target, &block) #

Block-based tween DSL targeting specified node with compile-time type verification (e.g. tween(player) do animate(...) end)


macro tween(&block) #

Block-based tween DSL targeting self (e.g. tween do animate(...) end)


macro tween(property_expr, to value, in in_duration = 0.2.seconds, from from_val = nil, trans = Godot::Tween::TransitionType::TransLinear, ease = Godot::Tween::EaseType::EaseInOut) #

Compile-time type-safe tween macro supporting dot-navigation (e.g. tween(boss.position.y, to: 150.0))


macro u!(name, type = nil) #

Ultra-short alias for unique!(name, type).


macro u?(name, type = nil) #

Ultra-short alias for unique?(name, type).


macro unique!(name, type = nil) #

Immediately retrieves a Scene Unique Node (Godot 4 %Node syntax).

Automatically prepends % to the identifier if not already present.

Supported Patterns:

  1. Type-inferred: unique!(ProgressBar) -> looks up "%ProgressBar" as ProgressBar
  2. Name with Type: unique!("HealthBar", ProgressBar) -> looks up "%HealthBar" as ProgressBar
  3. Name string: unique!("HealthBar") -> looks up "%HealthBar" as Godot::Node

Raises Godot::NodeNotFoundError if the unique node does not exist.


macro unique?(name, type = nil) #

Safely retrieves a Scene Unique Node (Godot 4 %Node syntax), returning nil if not found.


macro unique_node(name_or_decl, type = nil, unique_name = nil) #

Declares a lazy-cached Scene Unique Node property (Godot 4 %Node syntax).

Examples:

unique_node health_bar, ProgressBar      # fetches "%HealthBar"
unique_node main_hud, CanvasLayer, "HUD" # fetches "%HUD"

macro unique_node?(name_or_decl, type = nil, unique_name = nil) #

Declares a safe, lazy-cached Scene Unique Node property that returns nil if missing.

Examples:

unique_node? health_bar, ProgressBar, "HealthBar"

macro unique_node_ref(name_or_decl, type = nil, unique_name = nil) #

Declares a dead-pointer safe, lazy-cached Scene Unique Node property (Godot 4 %Node syntax).

Supports:

  1. Macro signature: unique_node_ref camera, Camera2D, "MainCamera"
  2. Type declaration: unique_node_ref camera : Camera2D = "MainCamera"
  3. Auto-inferred: unique_node_ref main_hud : CanvasLayer

macro unique_node_ref?(name_or_decl, type = nil, unique_name = nil) #

Declares a safe, lazy-cached Scene Unique Node property that returns nil if missing.

Examples:

unique_node_ref? camera, Camera2D, "MainCamera"
unique_node_ref? hud : CanvasLayer

macro warning_ignore(name) #

Convenience macro to suppress compiler warnings.


macro warning_ignore_restore(name) #

macro warning_ignore_start(name) #