lapis 4.8-dev7

Lapis for Crystal

Lapis for Crystal

Crystal Lapis Godot Tests Release Docs Benchmarks Slides License

Lapis for Crystal provides high-performance Crystal bindings and a bidirectional runtime integration for Godot Engine 4.8+ using LibGodot and GDExtension. It empowers developers to build Godot games with native LLVM machine speed, compile-time static type safety, and Ruby-like syntax elegance.

▢️ Watch the Video Tour: https://youtu.be/EKMw_zQjovc
πŸ“– Official Documentation: https://sol-vin.github.io/lapis/
πŸ“Š Interactive Benchmarks: https://sol-vin.github.io/lapis/benchmarks.html
πŸ“‘ Interactive Slide Deck: https://sol-vin.github.io/lapis_slides/


Why Lapis?

Dimension Lapis (Crystal) GDScript C# (.NET) C++ (GDExtension)
Execution Speed Native LLVM machine code (-O3 auto-vectorization) Interpreted bytecode / VM stack overhead JIT compilation, GC pause overhead Native C++ machine code
Type Safety Exhaustive compile-time typing & nil-safety Optional gradual typing (runtime checks) Static typing with nullable annotations Static typing, manual memory hazards
Memory Model Boehm GC + 64-bit ObjectDB dead-pointer guards Engine RefCounted / manual free CLR Garbage Collector + interop wrappers Manual allocation, dangling pointers / UB
Syntax Elegance Ruby-like expressive DSL, blocks, macros, union types Python-like concise scripting Verbose C-style OOP boilerplate Verbose header/source separation & macros
Hot Reloading Shadow DLL loading (bypasses Windows file locks on F5) Native script reload Domain reload (requires editor restart on edge cases) File-locked on Windows without custom loader
Native Debugger In-editor radare2: pseudo-C decompilation (pdc) & gutter sync Engine GDScript debugger External IDE debugger (VS Code / Rider) External native debugger (GDB / MSVC / LLDB)
Editor Automation Action Driver: DOM inspection, REPL, and Set-of-Marks AI Vision EditorScript (limited headless execution) None Custom C++ editor modules

Table of Contents


Architecture: Dual-Paradigm Integration

Lapis provides two 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 & Hot-Reloads| 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. Passes GDExtension C-API Table| EXE
        EXE -->|5. Steps Main Loop & Dispatches| WIN[Game Window & Audio]
    end
Paradigm Mode A: GDExtension In-Editor Mode B: Standalone LibGodot Host
Host Binary Godot Engine (godot.exe) Crystal Executable (bin/game.exe)
Primary Binaries bin/crystal_bridge.dll + bin/game.dll bin/libgodot.dll (or .so)
GC Bootstrapping Initialized by C++ loader bridge (GC_init()) Initialized natively by Crystal CRT
Hot Reloading Timestamped shadow DLL loading on F5 / F6 Recompilation of standalone executable required
Primary Use Case Rapid development, tool scripts, level design Production shipping, headless CI, embedded runners

Windows Shadow Loading

On Windows, dynamic libraries loaded via LoadLibraryA are locked by the OS kernel, preventing compilers from overwriting game.dll. In development mode, crystal_bridge.cpp copies game.dll to a timestamped shadow file (game_loaded_<PID>_<TIMESTAMP>.dll) and loads the shadow copy. bin/game.dll remains completely unlocked so Crystal can recompile freely while the Godot Editor stays open.


Production Gameplay DSL & Ergonomics

Showcase Quickstart Node

Here is an idiomatic Lapis character node demonstrating property exports, @onready path unrolling, signals, tweening, pattern matching, direct space physics queries, and dead-pointer safety:

require "lapis"

# Player character with physics movement, combat raycasting, and animations
node Player < CharacterBody3D do
  # Scene unique node references resolved and cached during _ready
  onready visual_mesh : MeshInstance3D = ~"%VisualMesh"
  onready collider : CollisionShape3D = ~"CollisionShape3D"

  # Inspector export system with ranges, steps, and tooltips
  @[Export(range: 1.0_f32..25.0_f32, step: 0.5_f32)]
  property move_speed : Float32 = 8.0_f32

  @[Export(range: 1.0_f32..30.0_f32, step: 0.5_f32)]
  property jump_velocity : Float32 = 9.5_f32

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

  # First-class type-safe signals
  signal health_changed(current : Int32, max_health : Int32)
  signal died

  @current_health : Int32 = 100

  def _ready : Void
    @current_health = @max_health
    Godot.print("Player initialized: #{name}")
  end

  def _physics_process(delta : Float64) : Void
    vel = velocity

    # Apply gravity when airborne
    unless is_on_floor
      vel.y -= 24.0_f32 * delta.to_f32
    end

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

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

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

    self.velocity = vel
    move_and_slide

    # Fire weapon raycast on attack action
    if Input.is_action_just_pressed("fire")
      fire_weapon
    end
  end

  # Performs a direct space physics raycast
  private def fire_weapon : Void
    start_pos = global_position + Vector3.new(0.0_f32, 1.2_f32, 0.0_f32)
    target_pos = start_pos + (-transform.basis.z * 50.0_f32)

    # One-liner direct space query returning typed PhysicsHit3D
    if hit = raycast_to(target_pos, from: start_pos)
      # Expression pattern matching with dead-pointer safe downcasting
      match hit.collider do
        is Enemy do |enemy|
          enemy.take_damage(25)
          flash_hit_marker
        end
        default do
          Godot.print("Hit scenery at #{hit.position}")
        end
      end
    end
  end

  # Statement-based tween orchestration with auto call-peeling and typed identifiers
  private def flash_hit_marker : Void
    tween(self) do
      animate(visual_mesh.scale, to: Vector3.new(1.15_f32, 1.15_f32, 1.15_f32), in: 0.08.seconds)
      trans(Trans.Back)
      ease(Ease.Out)
      chain()
      animate(visual_mesh.scale, to: Vector3.new(1.0_f32, 1.0_f32, 1.0_f32), in: 0.12.seconds)
      trans(Trans.Cubic)
      ease(Ease.In)
    end
  end

  # Inflicts damage, emits signals, and handles death
  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

Typed Scene Pipeline & Queries

Lapis introduces expressive pipeline and query operators that eliminate boilerplate typecasts:

# 1. Preload Pipeline (>): Preload PackedScene, instantiate, and cast to concrete node
enemy = "res://scenes/enemy.tscn" > Enemy do |e|
  e.position = Vector3.new(10.0, 0.0, 5.0)
end

# 2. Dynamic Load Pipeline (>>): Load dynamically at runtime without caching
boss = "res://scenes/boss.tscn" >> Boss

# 3. Symmetrical Upward Ancestor Resolution (<<): Find nearest parent in hierarchy
player = hitbox << Player     # Strict: returns Player or raises NodeNotFoundError
boss = hitbox << Boss?        # Nilable: returns Boss? or nil if not found

# 4. Wildcard Scene Glob Queries (*):
all_enemies = self * "Enemies/*"                    # Array(Node)
all_lights  = self * "**/Light*"                    # Recursive globstar
all_areas   = self * {"HitBoxes/*", Area3D}         # Typed: Array(Area3D)
regex_boxes = self * /^HitBox_\d+$/                 # Regex: Array(Node)
hitbox      = self["Enemies/*/Hitbox", Area2D]?     # Nilable: returns nil if empty!

# 5. Zero-Allocation Streaming Iteration:
each_node("Enemies/*", Enemy) do |enemy|
  enemy.take_damage(50)
end

# 6. Fluent Group Queries (group):
group(:enemies).each(as: Enemy) do |enemy|
  enemy.alert!(player.global_position)
end
group(:enemies).call("wake_up")
alive_count = group(:enemies).size

Type-Safe Tween Orchestration

The tween macro peels apart block statements into a fluent pipeline, strictly verifying typed property identifiers at compile time:

# Statement-based tween pipeline with auto call-peeling, easing curves, and typed identifiers
tw = tween(hero) do
  animate(position, to: Vector2.new(120, 80), in: 4.seconds)
  chain()
  animate(modulate, from: Color::RED, to: Color::BLUE, in: 0.3.seconds)
  parallel()
  ease(Ease.Out)
  trans(Trans.Cubic)
  animate(scale, to: Vector2.new(1.2, 1.2), in: 0.3.seconds)
  chain()
  animate(modulate.a, to: 0.0, in: 0.25.seconds)
end

# Non-blocking cooperative await on the tween's completion
await(tw.finished)

Pattern Matching (match)

Game development frequently deals with polymorphic nodes, dynamic Variant payloads, and input dictionaries. The match macro handles these with zero-allocation inlined execution:

match event do
  # Variant unboxing & dead-pointer safe downcasting
  is Player do |player|
    Godot.print("Player HP: #{player.max_health}")
  end

  # Guard clauses with if: condition
  is Enemy, if: event.level > 50 do |boss|
    trigger_boss_music(boss)
  end

  # Symbol / String equivalence
  is :action_jump, :action_vault do
    player.execute_aerial_move
  end

  # Tuple destructuring
  is {state, on_floor?} do
    is :jumping, false do apply_air_control end
    is :jumping, true  do trigger_landing_dust end
  end

  default do
    handle_unhandled_event
  end
end

Gameplay Patterns: FSM, Signal Bus & Pooling

# 1. Zero-Allocation Typed Union FSM
struct Idle; end
struct Walking; getter speed : Float32 = 6.0_f32; end
struct Attacking; getter combo : Int32 = 1; end

alias State = Idle | Walking | Attacking

node CombatUnit < CharacterBody3D do
  fsm State, initial: Idle.new do
    on_enter Walking do |w|
      Godot.print("Walking at speed #{w.speed}")
    end
    on_exit Attacking do
      reset_combo_timer
    end
  end
end

# 2. Type-Safe Decoupled Signal Bus
signal_bus GameEvents do
  signal score_changed(new_score : Int32)
  signal player_died
end

# Emitter:
GameEvents.instance.score_changed.emit(100)

# Receiver:
GameEvents.instance.score_changed.connect do |score|
  ui_label.text = "Score: #{score}"
end

# 3. High-Performance Object Pool
class Arena < Node2D
  node_pool bullets : Bullet, capacity: 64

  def fire_volley(at_pos : Vector2) : Void
    bullet = bullets.acquire do |b|
      b.position = at_pos
      b.velocity = Vector2.new(500.0, 0.0)
    end
  end
end

In-Editor Action Driver ("Selenium for Godot Editor")

Lapis includes the Action Driver, a programmatic UI inspection, automation, and testing framework for the Godot Editor. It provides DOM traversal, synthetic inputs, state preservation across reloads, and Set-of-Marks AI Vision generation:

[ Lapis Action Driver ] ──TCP:9095──> [ Godot Editor 4.8 ]
       β”‚                                     β”‚
       β”œβ”€ click "Build"                      β”œβ”€ Finds Control via DOM predicate
       β”œβ”€ type "%SearchEdit" "Player"        β”œβ”€ Synthesizes InputEventKey / Mouse
       β”œβ”€ open-scene "res://test.tscn"       β”œβ”€ EditorInterface scene dispatch
       └─ vision --output reports/ai         └─ Generates Set-of-Marks AI Manifest

CLI Commands:

# Click a button in the Godot Editor UI
lapis driver click "Build"

# Type text into a LineEdit or search filter
lapis driver type "%FilterEdit" "Player"

# Switch main editor screens (2D, 3D, Script, Crystal)
lapis driver screen 3D

# Generate Set-of-Marks AI Vision manifest & cropped widget images
lapis driver vision --output reports/ai_vision

# Dump the live Godot Editor DOM tree hierarchy
lapis driver dom 8

# Launch interactive Action Driver REPL
lapis driver repl

Native In-Editor radare2 Debugger & Decompiler

Powered by sol-vin/cradare2, Lapis embeds a native multi-threaded debugger directly inside the Godot Editor:

  • Gutter Breakpoint Sync: Set breakpoints directly in Godot's Script Editor gutter (F9). Breakpoints are synchronized with radare2 via source line matching (dbl) instantly.
  • Dedicated In-Editor Tab: Docked Crystal Debugger tab featuring Continue (F5), Step Over (F10), Step Into (F11), Step Out (Shift+F11), call stack frame navigation, and CPU register inspection (RAX, RBX, RIP, RSP).
  • Live Pseudo-C Decompiler (pdc): Built-in side-by-side view with native pseudo-C (pdc) decompilation and annotated assembly (pdf/pdca) with zero external decompiler dependencies.
  • Multiplayer Lockstep Break: When any peer hits a breakpoint, all other active instances are automatically paused via cooperative interrupt (DebugBreakProcess / SIGINT) to eliminate network heartbeat timeouts (ENet / WebRTC).
  • Dead-Pointer Forensics: Automatically inspects faulting memory addresses, classifies loaded modules, and checks 64-bit ObjectDB IDs to diagnose dead pointers.
# Launch test project under native radare2 debugger
lapis run -d

# Launch Godot Editor under native radare2 debugger
lapis editor -d

# Decompile symbol directly from terminal
lapis decompile bin/game.dll "*Player*physics_process*" --side-by-side

Interactive Opal TUI Hub (lapis cli)

Lapis includes an interactive full-screen terminal command center powered by Opal (sol-vin/opal). Launch it with lapis cli (or lapis -i):

β”Œβ”€β”€ Lapis Engine Command Hub (v0.0.264) ───────────────────────── [Godot 4.8-dev7] ──┐
β”‚                                                                                    β”‚
β”‚   [+] New Project / Addon Wizard      Interactive folder & template scaffold       β”‚
β”‚   [#] Launch Godot Editor             Persistent launcher with log watching        β”‚
β”‚   [A] Action Driver Controller        DOM automation REPL & AI vision capturer     β”‚
β”‚   [B] Packaging & Export Center       Multi-target builds & release packaging      β”‚
β”‚   [D] Radare2 Native Debugger         Registers, disassembly & hex memory view     β”‚
β”‚   [L] Diagnostic Log Viewer           Real-time log tailing & channel filters      β”‚
β”‚   [#] Benchmark Visualizer            Cartesian charts, percentiles & memory delta β”‚
β”‚   [~] Run Game (Performance Monitor)  Live FPS/memory charts with Ctrl+K stop      β”‚
β”‚   [?] Test Suites Dashboard           Multi-phase test runner with split-screen    β”‚
β”‚   [+] Toolchain Doctor                Environment & dependency health check        β”‚
β”‚   [~] Synchronize Multi-Targets       Sync bridge DLLs and manifests across targetsβ”‚
β”‚   [x] Clean Build Artifacts           Prune binaries & unlock shadow DLLs          β”‚
β”‚   [=] Generate Documentation          Build static offline HTML documentation site β”‚
β”‚                                                                                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ [↑/↓] Navigate  β”‚  [Enter] Launch  β”‚  [Ctrl+P] Command Palette  β”‚  [Q] Exit        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Press Ctrl+P from any screen to open the global floating Command Palette for instant fuzzy search across all 35+ CLI tools and actions.


Memory Safety & Dead-Pointer Defense

Embedding a garbage-collected language (Crystal Boehm GC) inside a native C++ engine (Godot ObjectDB) introduces a critical hazard: when Godot frees an object (e.g. via queue_free()), standard C-API bindings retain a raw pointer to dead memory. Dereferencing it triggers an unrecoverable segmentation fault (ACCESS_VIOLATION / SIGSEGV).

[ Crystal Runtime ]                              [ Godot Engine / GDScript ]
  enemy = get_node("Enemy")
  enemy.@pointer = 0x7FFE_1234  ────────────>     Node instance at 0x7FFE_1234
                                                      β”‚
                                                      β”‚ GDScript: enemy.queue_free()
                                                      β–Ό
                                                   ObjectDB destroys Node & frees memory!
                                                   0x7FFE_1234 is now DEAD / UNMAPPED!
  enemy.position = Vector3.new(...)
        β”‚
        β–Ό
  [ Lapis check_alive! ]
        β”‚
        β”œβ”€β”€β”€β”€β”€ Query ObjectDB for monotonic 64-bit instance ID: ID is INVALID!
        β”œβ”€β”€β”€β”€β”€ Marks wrapper dead (@pointer = null)
        └───── Raises Godot::DisposedObjectError (Clean, catchable Crystal exception!)
               [ ZERO NATIVE CRASHES ]

Safety Invariants:

  1. Monotonic 64-bit Instance ID Tracking: Every Godot::Object wrapper tracks its engine-assigned ID. Godot's ObjectDB monotonic IDs never collide with recycled heap addresses.
  2. Pre-Dispatch Liveness Check (#check_alive!): Before dispatches or reflection calls, Lapis validates liveness in O(1) time (Bridge.is_instance_valid(instance_id)).
  3. Graceful DisposedObjectError: If an object is freed, Lapis marks the pointer null and raises Godot::DisposedObjectError instead of crashing.
  4. Defensive Inspection: Check node.alive? or node.destroyed? before interacting with transient entities.
  5. Main-Thread SceneTree Affinity: Scene graph mutations (add_child, remove_child, queue_free) enforce main-thread execution (assert_main_thread!) with automatic thread-safe deferral (call_deferred / Godot.on_main_thread).
  6. Dead-Pointer Armor (try? & if_alive): Safely invoke methods on nilable or transient objects with @heal_sfx.try?(&.play) or @target.try?(&.take_damage(spell.power)). try? automatically queries Godot's ObjectDB monotonic ID table and returns nil safely if the object was freed or nil, eliminating C#'s .NET ?. ObjectDisposedException trap.

Performance & Benchmarks

Lapis features an automated 1-to-1 cross-language benchmark suite comparing native compiled Crystal (GDExtension) against GDScript (Godot 4 Bytecode):

πŸ“Š Explore the Live Dashboard: https://sol-vin.github.io/lapis/benchmarks.html

Benchmark Category Included Benchmarks Speedup vs GDScript Key Architectural Advantage
Algorithmic & Compute Matmul, Primes, Brainfuck, Base64, JSON, NBody, BinaryTrees, Mandelbrot, TransformMath 3.1x – 227.6x faster LLVM -O3 auto-vectorization, native unboxed arithmetic, zero Variant boxing.
Godot Engine Core NodeLifecycle, MaterialResources, Signals 1.1x – 307.7x faster Direct GDExtension C-API dispatch, low GC pause times, fast resource allocation.

Running Benchmarks Locally:

# Run all benchmarks and generate HTML/SVG reports
lapis benchmarks [ITERATIONS=3]

# Run specific categories or filters
crystal run benchmarks/runner.cr -- -c compute
crystal run benchmarks/runner.cr -- -c engine
crystal run benchmarks/runner.cr -- --filter=signals

Unified Multi-Tier Test Suite

Lapis enforces quality through an automated test harness covering language bindings, in-editor tool execution, and standalone runtimes:

  1. Engine Core Specs (spec/): Headless unit specs covering GC object retention, dynamic scaling, Variant type round-trips, and Vector math (spec/core_spec.cr, spec/math_spec.cr, spec/safety_spec.cr).
  2. Lapis CLI Specs (tools/lapis/spec/): CLI argument parsing, standalone execution, and packaging tests (tools/lapis/spec/cli_spec.cr).
  3. 85+ Modular Runtime Suites (spec/suites/): Comprehensive engine verification covering 2D/3D nodes, navigation, physics, multiplayer, shaders, audio servers, FSM, and memory lifecycle.
  4. Quantitative Zero-Leak Verification: Lapis::Test.assert_no_leak leverages Godot's Performance monitors (OBJECT_COUNT, OBJECT_NODE_COUNT, MEMORY_STATIC) and Crystal's GC.collect to mathematically verify zero object or memory leaks.
# Run the complete test suite (interactive TUI or streaming)
make test
lapis test

# Run headless specs only
make spec

Lapis CLI Toolchain Reference

The lapis CLI (bin/lapis / bin/lapis.exe) provides a unified developer toolchain:

Command Category Description
lapis cli (or lapis -i) Interactive Hub Launches the 14-workspace Opal TUI dashboard with floating Command Palette (Ctrl+P).
lapis driver [cmd] Editor Automation In-Editor Action Driver controller, interactive REPL, and Set-of-Marks AI Vision generation.
lapis doctor Diagnostics Diagnoses environment health (Crystal, Godot, C++ compiler, radare2, packaging dependencies).
lapis build [target] Build & Sync Compiles Crystal targets (game, plugin, tests, bench) with automatic flag resolution.
lapis sync Build & Sync Synchronizes compiled binaries, runtime DLLs (GC, iconv, PCRE2, LibGodot), and manifests across targets.
lapis editor Editor Launcher Launches Godot Editor with log monitoring, build hooks, and radare2 debugger support.
lapis run Runner Runs Godot project standalone with live FPS and memory metrics.
lapis test [options] Testing Unified multi-tier test runner with interactive TUI or non-TTY streaming logs.
lapis new <game|addon|example> [name] Scaffolding Scaffolds a new game, redistributable GDExtension addon, or showcase example from templates.
lapis init [path] Project Management Initializes Crystal/Lapis integration into an existing Godot project.
lapis bind <engine|project> Code Generation Generates typed Crystal API bindings for Godot classes or custom GDScript project nodes.
lapis package [target] Packaging Packages playable standalone game executables or distribution zip archives.
lapis decompile <bin> <sym> Debugging Decompiles functions to pseudo-C (pdc) or disassembles binary using native radare2.
lapis analyze <bin> Debugging Performs deep static and dynamic radare2 binary and security analysis.
lapis log [options] Logging Views, tails, searches, exports, and filters diagnostic logs.
lapis shard <cmd> Dependencies Manages Crystal shard dependencies in the Godot project (list, install, uninstall, prune).
lapis addon <cmd> Dependencies Installs, uninstalls, or manages Godot GDExtension addons.
lapis ide [editor] Tooling Configures VS Code, Cursor, Zed, or Neovim with Crystalline LSP and radare2 debugging.
lapis template <cmd> Templates Manages global project templates (save, list, remove, clean, export, import).
lapis clean [options] Maintenance Prunes compiled binaries, intermediate objects, and shadow DLLs.
lapis docs Documentation Generates offline HTML API documentation via crystal docs.
lapis setup Setup Downloads and configures targeted Godot engine binary and dumps GDExtension API.
lapis install System Installs Lapis CLI globally into system/user PATH.

Comprehensive In-Code Documentation (Lapis::Docs)

Lapis includes an extensive 10-track technical documentation system compiled directly into the code via Jasper (sol-vin/jasper):

Learning Track Submodule Topics Covered
1. Getting Started Docs::A_GETTING_STARTED Installation, source compilation, First Game Tutorial (Zero to Hero), Crystal syntax for Godot.
2. CLI & Toolchain Docs::B_LAPIS_CLI_AND_TOOLCHAIN CLI architecture, doctor diagnostics, scaffolding, build & sync, testing, clean, addons, shards, IDE.
3. Gameplay DSL Docs::C_GAMEPLAY_AND_DECLARATIVE_DSL Node DSL, exports, signals, input, scene tree, mixins (gmodule), multiplayer, GDScript migration.
4. Concurrency & Fibers Docs::D_CONCURRENCY_AND_FIBERS Fibers, cooperative signal awaiting, OS background threads, actor channels, main thread dispatch.
5. Memory Safety Docs::E_MEMORY_SAFETY_AND_ENGINE_INTERNALS Godot ObjectDB monotonic IDs, dead-pointer defense, Boehm GC vs Godot reference counting.
6. Scripting & Interop Docs::F_SCRIPTING_AND_INTEROPERABILITY First-class .cr script editing in Godot, GDScript bindings, compile-time doc comment harvesting.
7. Debugging & Diagnostics Docs::G_DEBUGGING_AND_DIAGNOSTICS Native radare2 debugging, gutter breakpoints, pseudo-C decompilation, crash forensics, watchpoints.
8. Testing & Benchmarks Docs::H_TESTING_AND_BENCHMARKS Testing framework, zero memory leak validation, performance profiling, benchmark architecture.
9. Architecture & Extensions Docs::I_ARCHITECTURE_AND_EXTENSIONS Dual-paradigm execution model, C++ loader bridge, multi-addon isolation, engine upgrade guide.
10. Modern CLI & TUI Docs::J_MODERN_CLI_AND_TUI Interactive terminal command center, Opal TUI hub, differential cell rendering, domain workspaces.

Build and view documentation locally:

make docs
# Open docs/index.html in your browser

Prerequisites & Installation

System Dependencies

  • Crystal Compiler: 1.20+
  • radare2: 5.8+ (native debugger, disassembler, and decompiler)
  • Godot Engine: 4.8-dev7+ (Standard build, 64-bit)
  • C++ Compiler: GCC (g++) or Clang (for compiling the GDExtension loader bridge)
  • GNU Make: Workspace build & synchronization automation
  • Git: Shards dependency resolution & version control

Quick Install by Platform

Platform One-Liner Command to Install Dependencies
Windows (Scoop) scoop install crystal radare2 make git
Windows (Winget) winget install CrystalLang.Crystal radare2.radare2 ezwinports.make Git.Git
Ubuntu / Debian sudo apt update && sudo apt install -y crystal radare2 make git g++
Arch Linux sudo pacman -S crystal radare2 make git gcc
macOS (Homebrew) brew install crystal radare2 make git

Official Installers

  • Windows Installer (lapis-setup-windows-x86_64.exe): Installs Lapis CLI, bundles crystalline.exe (LSP) and radare2.exe (native debugger), configures user PATH, and registers PowerShell completions.
  • Debian Package (lapis_amd64.deb): Installs Lapis globally with automatic package dependency resolution (Depends: crystal, radare2).

Adding to an Existing Project (shard.yml):

dependencies:
  lapis:
    github: sol-vin/lapis
    branch: 4.8-dev7

Run shards install to install dependencies.


Repository Structure

lapis/
β”œβ”€β”€ src/                          # Reusable Lapis library & root host application
β”‚   β”œβ”€β”€ libgodot.cr               # Library root entry point (require "libgodot")
β”‚   β”œβ”€β”€ lapis.cr                  # Lapis prelude & engine extensions
β”‚   β”œβ”€β”€ main.cr                   # Root host game entry point & test runner panel
β”‚   β”œβ”€β”€ bridge/crystal_bridge.cpp # C++ GDExtension loader bridge
β”‚   └── libgodot/                 # Core engine C-API, macros, and generated bindings
β”œβ”€β”€ tools/                        # Built-in CLI toolchain
β”‚   └── lapis/                    # Compiled native CLI (bin/lapis)
β”œβ”€β”€ spec/                         # Unified Crystal specifications & test suites
β”‚   β”œβ”€β”€ spec_helper.cr            # Common spec helper and test nodes
β”‚   β”œβ”€β”€ editor_driver_spec.cr     # In-editor @tool and runtime tests via EditorDriver
β”‚   β”œβ”€β”€ suites/                   # 85+ modular engine test suites
β”‚   └── fixtures/                 # Spec test targets & fixtures
β”œβ”€β”€ scenes/                       # Root Godot host project scenes (main_test_runner.tscn, etc.)
β”œβ”€β”€ scripts/                      # GDScript test fixtures and interop nodes
β”œβ”€β”€ project.godot                 # Root Godot host project configuration
β”œβ”€β”€ addons/                       # GDExtensions & Editor Plugins
β”‚   β”œβ”€β”€ crystal_integration/      # Official GDExtension manifest & editor build hook
β”‚   └── dummy_*/                  # Isolated test addons for multi-addon stress tests
β”œβ”€β”€ examples/                     # Independent consumer showcase examples
β”œβ”€β”€ template/                     # Clean starter template for new games
β”œβ”€β”€ template-addon/               # Starter template for redistributable addons
β”œβ”€β”€ bin/                          # Output binaries, bridge DLL, and dependencies
└── AGENTS.md                     # Agent development guidelines

License

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

Repository

lapis

Owner
Statistic
  • 8
  • 1
  • 0
  • 4
  • 5
  • 14 days ago
  • September 6, 2026
License

MIT License

Links
Synced at

Fri, 16 Oct 2026 20:14:54 GMT

Languages