lapis 4.8-dev7
Lapis for Crystal
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
- Production Gameplay DSL & Ergonomics
- In-Editor Action Driver ("Selenium for Godot Editor")
- Native In-Editor radare2 Debugger & Decompiler
- Interactive Opal TUI Hub (
lapis cli) - Memory Safety & Dead-Pointer Defense
- Performance & Benchmarks
- Unified Multi-Tier Test Suite
- Lapis CLI Toolchain Reference
- Comprehensive In-Code Documentation (
Lapis::Docs) - Prerequisites & Installation
- Repository Structure
- License
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:
- Monotonic 64-bit Instance ID Tracking: Every
Godot::Objectwrapper tracks its engine-assigned ID. Godot's ObjectDB monotonic IDs never collide with recycled heap addresses. - Pre-Dispatch Liveness Check (
#check_alive!): Before dispatches or reflection calls, Lapis validates liveness in O(1) time (Bridge.is_instance_valid(instance_id)). - Graceful
DisposedObjectError: If an object is freed, Lapis marks the pointer null and raisesGodot::DisposedObjectErrorinstead of crashing. - Defensive Inspection: Check
node.alive?ornode.destroyed?before interacting with transient entities. - 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). - 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 returnsnilsafely if the object was freed ornil, eliminating C#'s.NET ?.ObjectDisposedExceptiontrap.
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:
- 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). - Lapis CLI Specs (
tools/lapis/spec/): CLI argument parsing, standalone execution, and packaging tests (tools/lapis/spec/cli_spec.cr). - 85+ Modular Runtime Suites (
spec/suites/): Comprehensive engine verification covering 2D/3D nodes, navigation, physics, multiplayer, shaders, audio servers, FSM, and memory lifecycle. - Quantitative Zero-Leak Verification:
Lapis::Test.assert_no_leakleverages Godot'sPerformancemonitors (OBJECT_COUNT,OBJECT_NODE_COUNT,MEMORY_STATIC) and Crystal'sGC.collectto 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, bundlescrystalline.exe(LSP) andradare2.exe(native debugger), configures userPATH, 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.
lapis
- 8
- 1
- 0
- 4
- 5
- 14 days ago
- September 6, 2026
MIT License
Fri, 16 Oct 2026 20:14:54 GMT