package

github.com/sol-vin/libgodot

latest / published Sep 16, 2026 / repository

High-performance Crystal bindings and 2-way host integration for Godot Engine 4.8+ using LibGodot and GDExtension.

LibGodot for Crystal

Crystal Godot Docs License

LibGodot for Crystal provides high-performance Crystal bindings and a bidirectional runtime integration for Godot Engine 4.8+. It empowers game developers to write Godot games with native machine speed, complete compile-time type safety, and Ruby-like elegance.


Architecture: Dual-Paradigm Integration

LibGodot supports two distinct execution paradigms designed for both rapid in-editor iteration and lean standalone production shipping:

graph TD
    subgraph Mode A: GDExtension In-Editor Workflow
        GE[Godot Editor 4.8] -->|Loads| GDX[addons/crystal_integration/crystal.gdextension]
        GDX -->|Loads| CB[bin/crystal_bridge.dll]
        CB -->|1. Initializes Boehm GC| CRT[Crystal Runtime]
        CB -->|2. Shadow loads| GDL[bin/game_loaded_pid_ts.dll]
        GDL -->|3. crystal_godot_init| REG[ClassDB & EditorHelp]
        REG -->|4. Exposes Nodes & Inspector| GE
        GE -->|F5 / Build Hook| EB[EditorPlugin._build]
        EB -->|Recompiles| GDL
    end

    subgraph Mode B: Standalone LibGodot Host Paradigm
        EXE[bin/game.exe] -->|1. Owns main Entry Point| CRTM[Crystal Boehm GC]
        EXE -->|2. In-Memory Boot| LGD[bin/libgodot.dll]
        LGD -->|3. libgodot_create_godot_instance| GINST[Godot Engine Instance]
        GINST -->|4. Pass GDExtension C-API Table| EXE
        EXE -->|5. Step Main Loop & Dispatch| WIN[Game Window & Audio]
    end
  • Mode A: GDExtension In-Editor Workflow (game.dll + crystal_bridge.dll): Develop inside the Godot Editor (make editor). The native C++ bridge boots the Boehm GC and shadow-copies game.dll to prevent Windows file locking. Pressing F5 in the editor triggers live compilation and reload.
  • Mode B: Standalone LibGodot Host Paradigm (game.exe + libgodot.dll): Crystal owns main(), initializes its runtime natively, boots Godot in-memory, and controls the main loop for standalone shipping builds (make game_exe).

Detailed architectural deep-dive is available in Docs::A_ARCHITECTURE and Docs::B_COMPILATION_AND_BUILD.


Features

  • Intuitive Node DSL: Define Godot nodes with concise node ClassName < ParentNode do ... end syntax.
  • Inspector Export System: Complete support for @[Export], numeric ranges, enums, file pickers, bitmask flags, groups, categories, and tool buttons.
  • Automated Doc Comment Harvesting: Standard Crystal # comments above classes, properties, signals, and methods are extracted at compile time and registered into Godot's EditorHelp XML database for in-editor tooltips and offline F1 Help.
  • Type-Safe Signals: Declare signals via signal health_changed(new_health : Int32) with generated emit_<signal> helpers.
  • GDScript Interoperability: Automatic compile-time generation of typed Crystal wrappers for project GDScript nodes and scenes (make project_bindings).
  • Engine Reflection & Global Singletons: First-class access to singletons like Godot.input, Godot.engine, Godot.audio_server, and generated Godot classes.
  • Native In-Editor Debugging with LLDB: Breakpoints in Godot's Script Editor gutter seamlessly synchronize with LLDB. Includes an interactive in-editor console, call stack navigation, and Multiplayer Lockstep Break coordination to eliminate peer timeout disconnects.
  • Strict Decoupling: Clean separation between reusable library (src/), test suite (test/), and examples (examples/).

Prerequisites & Installation

Required Tooling

  • Crystal Compiler: 1.14+ (or preview builds)
  • Godot Engine: 4.3+ or 4.4+ (Standard build, 64-bit)
  • C++ Compiler: GCC (g++) or Clang (for compiling the GDExtension loader bridge)
  • Make: GNU Make
  • Powershell: Used for support scripts and make process

Native In-Editor Debugging Prerequisite (LLDB)

For native in-editor debugging, breakpoint synchronization, and multiplayer lockstep inspection, install LLDB:

  • Windows: scoop install llvm or winget install LLVM.LLVM
  • Ubuntu / Debian: sudo apt install lldb
  • Arch Linux: sudo pacman -S lldb
  • macOS: brew install llvm or xcode-select --install

Documentation

  • Official Online Documentation Site: https://sol-vin.github.io/libgodot/
  • Architecture & Guides in Docs Module: Complete guides covering architecture, build toolchains, memory management, and concurrency are contained in Docs (such as Docs::I_CONCURRENCY_FIBERS_AND_THREAD_SAFETY).
  • Offline HTML API Documentation: Generate complete API documentation locally with make docs (output at docs/index.html).
  • In-Editor Help: Class and method descriptions are harvested at compile time and accessible directly inside Godot via F1 or Inspector tooltips.

Quickstart

require "libgodot"

# Player character with physics movement, health tracking, and signals
node Player < CharacterBody3D do
  # Movement speed in meters per second
  @[Export(range: 1.0_f32..20.0_f32, step: 0.5_f32)]
  property speed : Float32 = 7.0_f32

  # Jump velocity impulse
  @[Export(range: 1.0_f32..25.0_f32, step: 0.5_f32)]
  property jump_velocity : Float32 = 8.0_f32

  # Gravitational acceleration
  @[Export(range: 1.0_f32..50.0_f32, step: 1.0_f32)]
  property gravity : Float32 = 18.0_f32

  # Maximum hit points
  @[Export(range: 10..500, step: 10)]
  property max_health : Int32 = 100

  # Emitted when the player's health changes
  signal health_changed(current : Int32, max_health : Int32)

  # Emitted when the player dies
  signal died

  # Called when node enters the active scene tree
  def _ready : Void
    @current_health = @max_health
    Godot.print("Player initialized at #{position}")
  end

  # Called every fixed physics step
  def _physics_process(delta : Float64) : Void
    vel = velocity

    unless is_on_floor
      vel.y -= @gravity * delta.to_f32
    end

    if Input.is_action_just_pressed("jump") && is_on_floor
      vel.y = @jump_velocity
    end

    input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
    direction = (transform.basis * Vector3.new(input_dir.x, 0.0_f32, input_dir.y)).normalized

    if direction.length > 0.001_f32
      vel.x = direction.x * @speed
      vel.z = direction.z * @speed
    else
      vel.x = Math.move_toward(vel.x, 0.0_f32, @speed * delta.to_f32)
      vel.z = Math.move_toward(vel.z, 0.0_f32, @speed * delta.to_f32)
    end

    self.velocity = vel
    move_and_slide
  end

  # Inflicts damage on the player
  def take_damage(amount : Int32) : Void
    return if @current_health <= 0
    @current_health = Math.max(0, @current_health - amount)
    emit_health_changed(@current_health, @max_health)
    if @current_health <= 0
      emit_died
      queue_free
    end
  end
end

Comprehensive In-Code Documentation (Docs Module)

LibGodot features an extensive in-code documentation suite under the Docs module. Each submodule details internal mechanics, macro pipelines, export options, and engine caveats:

Submodule Topic
Docs::A_ARCHITECTURE Dual-paradigm model, GDExtension Mode A vs Standalone LibGodot Mode B.
Docs::B_COMPILATION_AND_BUILD Bridge compilation, Windows shadow DLL file-locking bypass, F5 editor hook, and Makefile orchestration.
Docs::C_EXPORTS_AND_INSPECTOR All @[Export*] annotations, PropertyInfo mapping, ranges, enums, flags, categories, and buttons.
Docs::D_NODE_DSL_AND_SIGNALS Node macro DSL, lifecycle callbacks (_ready, _physics_process), signal registration, and scene APIs.
Docs::E_DOC_COMMENTS_AND_HELP Compile-time doc comment harvesting, DocData XML generation, and Godot offline F1 Help integration.
Docs::F_GDSCRIPT_INTEROP Automated compile-time GDScript bindings and Variant marshaling.
Docs::G_CAVEATS_AND_INTERNALS Boehm GC vs Godot memory lifecycles, threading rules, method bind caching, and Windows toolchains.
Docs::H_LIFECYCLE_MEMORY_AND_DEAD_POINTER_SAFETY Dead-pointer prevention, monotonic 64-bit instance IDs, O(1) liveness checks, and zero-crash DisposedObjectError.
Docs::I_CONCURRENCY_FIBERS_AND_THREAD_SAFETY Crystal fibers, background OS threads, actor channel message passing, mutexes, and main-thread SceneTree affinity.

To generate and browse the complete HTML documentation locally:

make docs

Then open docs/index.html in your browser.


Build System & Commands

Build operations are orchestrated through the root Makefile.

Command Description
make all Default Build: Compiles loader bridge, test project, examples, template, and synchronizes all DLLs.
make run Launches the test suite project directly in the Godot engine.
make editor Opens the test project in the Godot Editor (godot.exe --editor --path test).
make test Runs the multi-tier automated test suite: Crystal specs, headless in-editor tool tests, runtime test project, standalone test runner (--autorun), and smoke tests.
make test_standalone Packages and executes the standalone test runner executable (tests.exe --autorun) in debug or release mode.
make docs Generates offline HTML documentation into docs/.
make bridge Compiles src/bridge/crystal_bridge.cpp into bin/crystal_bridge.dll.
make test_project Compiles the test suite project (test/bin/game.dll).
make examples Compiles all showcase projects in examples/.
make template Compiles the starter template (template/bin/game.dll).
make game_exe Compiles standalone host executable bin/game.exe (Mode B).
make sync Synchronizes binaries, runtime DLLs, and addons across all consumer directories.
make clean Removes compiled binaries and intermediate build artifacts while preserving runtime DLLs.

Build Options

  • RELEASE=1: Compiles Crystal code with release optimizations (--release -O3) and defines LIBGODOT_RELEASE=1 / NDEBUG.
  • ENTRY=<path>: Customizes the Crystal entry file (default: test/src/main.cr).
  • CXX=<compiler>: Specifies C++ compiler for the bridge (default: g++).

Support & Toolchain Scripts (scripts/)

LibGodot provides specialized automation scripts under scripts/ to orchestrate builds, cross-compilation, asset synchronization, testing, code generation, and deployment:

Build & Compilation Scripts

Script Description & Role
scripts/build_crystal.ps1 Primary Crystal compilation driver. Sets up CRYSTAL_PATH, configures platform-specific linker flags (/DLL on Windows, -shared on Linux, -dynamiclib on macOS), and automatically injects symbol localization wrappers on Linux to prevent symbol collisions.
scripts/build_android.ps1 Cross-compiles LibGodot shared libraries (libcrystal_bridge.so and libgame.so) for Android architectures (arm64-v8a), resolving Android NDK paths, sysroots, and clang toolchains.
scripts/build_examples.ps1 Iterates through all showcase demo projects in examples/ (e.g. basic_demo), invoking their local Makefiles to build game shared libraries or standalone game executables (-Exe).
scripts/build_dummy_addons.ps1 Compiles lightweight mock GDExtension addons (dummy_audio, dummy_dialogue, dummy_inventory) in test/addons/ to verify multi-addon isolation, independent ClassDB registrations, and compiler hooks.
scripts/cc_wrapper.sh POSIX compiler wrapper script. Filters out -rdynamic on Linux shared library builds and invokes ld -r and objcopy --keep-global-symbol=crystal_godot_init to localize internal Crystal runtime symbols, preventing GNU ld/LLD version node link errors.

Packaging & Distribution Scripts

Script Description & Role
scripts/package_game.ps1 Packages a project (such as test or an example) into a playable standalone executable (e.g. tests.exe, game.exe). Automatically discovers all .gdextension manifests, generates .godot/extension_list.cfg, synchronizes runtime dependencies, and sets up self-contained binaries for production shipping.
scripts/package_android.ps1 Builds and packages complete installable Android APK bundles for Godot + Crystal games, configuring Gradle project templates, export manifests, and native .so packaging.
scripts/manage_keystore.ps1 Manages Android signing keystores and certificates for debug and release builds, including generation, inspection, and base64 environment variable decoding for CI pipelines.
scripts/ensure_export_templates.ps1 Verifies that the appropriate Godot 4 export templates are installed on the host system for desktop and mobile targets, reporting readiness for standalone release exports.

Synchronization & Dependency Scripts

Script Description & Role
scripts/sync_bins.ps1 Synchronizes compiled binaries (crystal_bridge.dll, game.dll, plugin.dll) and Crystal runtime libraries (gc.dll, iconv-2.dll, pcre2-8.dll, libgodot.dll) across bin/, test/bin/, template/bin/, examples/*/bin/, and all addon directories.
scripts/sync_addons.ps1 Maintains strict file parity for addons/crystal_integration across root, test, template, and showcase projects, updating GDExtension manifests and editor build hooks.
scripts/ensure_deps.ps1 Locates and copies required Crystal runtime dynamic libraries (Boehm GC, iconv, PCRE2, and LibGodot engine shared libraries) into target binary output folders.
scripts/ensure_dirs.ps1 Ensures all required build, output, and staging directories exist across the repository workspace.

Testing & Verification Scripts

Script Description & Role
scripts/run_tests.ps1 The master multi-tier test suite runner. Executes Phase 1 Crystal specs, Phase 2 in-editor @tool tests, Phase 3 runtime project suites, Phase 3b standalone compiled runner (tests.exe --autorun in debug and release modes), and Phase 4 smoke tests. Generates test_report.md and JSON summaries for GitHub Actions CI.
scripts/run_ci_local.ps1 Runs a complete local simulation of the GitHub Actions CI pipeline, executing builds, format checks, multi-tier tests, and packaging steps within a clean staging environment.
scripts/report_android.ps1 Audits Android APK bundles (generated by package_android.ps1), verifying ELF architecture ABI compatibility, dynamic symbol tables, permissions, and manifest integrity.

Binding Generation & Documentation Scripts

Script Description & Role
scripts/generate_bindings.cr Automated code generator that parses Godot's extension_api.json and synthesizes strongly typed Crystal classes, global enums, singletons, and method bindings into src/libgodot/generated/.
scripts/overrides.yml Type mapping and signature override definitions consumed by generate_bindings.cr to handle engine C-API quirks, method rename rules, and custom Variant marshalers.
scripts/patch_docs.ps1 Post-processes offline HTML documentation produced by crystal docs, injecting modern CSS themes, navigation enhancements, and repository links into docs/.

Memory Safety, Object Lifecycle & Dead-Pointer Protection

Developing with a garbage-collected language like Crystal embedded inside a native C++ engine like Godot introduces a dual memory model hazard:

  • Crystal Boehm GC: Manages Crystal heap objects and node wrappers (Godot::Object).
  • Godot ObjectDB & Reference Counting: Manages native C++ engine nodes and refcounted resources.

The Dangling Pointer Hazard in Cross-Language Bindings

When an object is freed on the Godot engine side or via GDScript (e.g. queue_free() or target.free()), standard C-API bindings retain a raw C++ pointer to dead memory. Subsequent operations (e.g. target.position = new_pos) dereference the unmapped address, triggering an immediate, fatal segmentation fault (ACCESS_VIOLATION / SIGSEGV) that crashes the game process with no traceback.

[ Crystal Runtime ]                          [ Godot Engine / GDScript ]
  enemy = get_node("Enemy")
  enemy.@pointer = 0x7FFE_1234  -------->     Node instance at 0x7FFE_1234
                                                  |
                                                  | GDScript: enemy.queue_free()
                                                  v
                                               ObjectDB destroys Node & frees memory!
                                               0x7FFE_1234 is now DEAD / UNMAPPED!
  enemy.position = Vector2.new(...)
        |
        v
  [ LibGodot check_alive! ]
        |
        +---> Query ObjectDB for 64-bit instance ID: ID is INVALID!
        |
        +---> Marks wrapper dead (@pointer = null)
        |
        +---> Raises Godot::DisposedObjectError (Clean, catchable Crystal exception!)
              [ ZERO NATIVE CRASHES! ]

How LibGodot Guarantees Dead-Pointer Safety

  1. Monotonic 64-bit Instance ID Tracking: Every Godot::Object wrapper tracks its engine-assigned instance_id. Because Godot's ObjectDB generates monotonic 64-bit IDs, newly allocated heap objects will never collide with previously freed IDs.
  2. Pre-Dispatch Liveness Check (#check_alive!): Before executing method dispatches or reflection calls, LibGodot queries Godot's ObjectDB in O(1) time (Bridge.is_instance_valid(instance_id)).
  3. Graceful DisposedObjectError Exception: If an object was destroyed by GDScript, the engine, or Crystal, LibGodot marks the pointer null and immediately raises Godot::DisposedObjectError:
    begin
      enemy.position = Vector2.new(10.0, 20.0)
    rescue ex : Godot::DisposedObjectError
      Godot.print_warn "Attempted operation on dead node (ID: #{ex.instance_id})"
    end
  4. Defensive Inspection with #alive? and #destroyed?: Game logic can check entity liveness before issuing operations:
    if target.alive?
      target.apply_damage(50)
    else
      active_targets.delete(target)
    end

Quantitative Zero-Leak Verification

LibGodot's test suite integrates Godot's Performance singleton monitors (OBJECT_COUNT, OBJECT_NODE_COUNT, MEMORY_STATIC) and Crystal's GC.collect to mathematically verify that creating, reparenting, and destroying nodes across hundreds of iterations leaves zero memory leaks in both Godot's ObjectDB and Crystal's heap.


Native In-Editor Debugging with LLDB

LibGodot features first-class native debugging directly inside the Godot Editor using LLDB:

  • Gutter Breakpoint Sync: Set red breakpoints directly in Godot's Script Editor gutter; breakpoints are translated and dispatched to LLDB instantly.
  • Interactive In-Editor Panel: Dedicated Crystal LLDB tab docked in the Godot Debugger panel featuring Continue (F5), Step Over (F10), Step Into (F11), Step Out (Shift+F11), call stack frame navigation, and live variable inspection.
  • Multiplayer Multi-Session Support: Distinct session tabs with automatic role identification ([SERVER], [CLIENT 1], etc.) for multiple instances launched from the editor.
  • Multiplayer Lockstep Break Mode: When any peer hits a breakpoint, all other active instances are automatically paused via cooperative interrupt to prevent network heartbeat timeouts (ENet/WebSocket/WebRTC).

Debugging Tool Scripts (@[Tool])

Execution Context Will Breakpoint Trigger in Editor Tab? Reason & Workflow
Running Game Instance (F5 / F6) YES The tool script runs in the child game process attached to the in-editor LLDB session.
Live In-Editor Viewport / Inspector NO Code executes inside the parent Godot Editor process (godot.exe), not a child game process.
Host Deadlock Paradox: An OS-level native breakpoint (SIGTRAP) in the editor process freezes the editor GUI thread, making it impossible to click "Continue" or "Step" in the debugger tab.
Solution: Attach an external debugger (e.g. VS Code CodeLLDB or terminal lldb -- godot.exe --editor --path <project>) to debug live tool scripts without freezing the debugger UI.

Detailed architectural breakdown and VS Code .vscode/launch.json templates are documented in Docs::M_LLDB_NATIVE_DEBUGGING_GUIDE.


Repository Structure

libgodot/
├── src/                          # Reusable LibGodot library (STRICTLY decoupled)
│   ├── libgodot.cr               # Library entry point
│   ├── bridge/crystal_bridge.cpp # C++ GDExtension loader bridge
│   └── libgodot/
│       ├── docs.cr               # Comprehensive Docs module (A-G guides)
│       ├── macros.cr             # Node DSL, signal, export, and doc harvesting macros
│       ├── bridge.cr             # C-API bindings & GDExtension interface table
│       ├── core.cr               # Object, ClassDB, PropertyInfo, SignalInfo
│       ├── doc_macro.cr          # EditorDocRegistry & XML loader
│       ├── gdscript.cr           # GDScript interop bindings
│       └── generated/            # Complete generated Godot engine class bindings
├── test/                         # Dedicated verification and test project
├── examples/                     # Independent consumer showcase examples
├── template/                     # Clean starter template for new games
├── addons/crystal_integration/   # Godot editor extension manifest & build hook
├── bin/                          # Output binaries, bridge DLL, and dependencies
├── spec/                         # Automated unit specifications
└── AGENTS.md                     # Agent development guidelines

License

Distributed under the MIT License. Copyright (c) 2026 Ian and contributors.

API