|
Some checks failed
Publish to PyPI / Build and Publish (push) Failing after 52s
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| src/lilith_gdscript_transpiler | ||
| tests | ||
| .gitignore | ||
| pyproject.toml | ||
| README.md | ||
lilith-gdscript-transpiler
Line-by-line GDScript → TypeScript transpiler primitives. Used to auto-generate TypeScript from Godot 4 game engine source files.
Install
pip install lilith-gdscript-transpiler --index-url https://forge.nasty.sh/api/packages/lilith/pypi/simple
Public API
High-level runner
from lilith_gdscript_transpiler import Transpiler, TranspilerConfig
from pathlib import Path
config = TranspilerConfig(
sources={"climate": Path("scripts/systems/climate.gd")},
output=Path("packages/engine-ts/src/ClimatePhysics.generated.ts"),
required_functions=[("climate", "_update_temperatures")],
assemble=lambda fns: my_assembler(fns),
)
Transpiler(config).run() # generate
Transpiler(config).check() # CI staleness check — exits 1 if stale
Primitives
| Function | Description |
|---|---|
extract_functions(source) |
Parse GDScript source → dict[str, str] of function bodies |
transform_method_body(body, name) |
Transform one GDScript method body to TypeScript |
apply_simple_transforms(line) |
Operators, math, string ops, type stripping |
to_camel(snake_name) |
snake_case → camelCase |
join_continuation_lines(body) |
Pre-process multi-line GDScript expressions |
add_closing_braces(lines) |
Post-process: insert } for dedented blocks |
Architecture
Five modules, each with a single responsibility:
extractor.py—extract_functions(),check_functions()transforms.py—apply_simple_transforms()and its sub-converterscontext.py—MethodContext: tracks tile-loop state, buffer dicts, upwind/hop varspostprocess.py—join_continuation_lines(),add_closing_braces()assembler.py—transform_method_body(): the coordinate bridge (axial → flat-array idx)
The assembler handles game-engine-specific patterns:
- Flat-array
idx(col, row, w)replacing axialDictionarylookups Float32Arraybuffer dicts for per-tile accumulationhopCol/hopRowtracking for wind-hop traversalsupwind_pos→ null-check pattern for upwind neighbor access
v1.1.0 Features
PCG32 PRNG Support
The PCG32_PREAMBLE export provides a TypeScript class that is bit-identical to
Godot 4's RandomNumberGenerator. Import it and emit it at the top of any
generated file that needs deterministic RNG:
from lilith_gdscript_transpiler import PCG32_PREAMBLE
# PCG32_PREAMBLE is a string containing a full TypeScript PCG32 class with:
# seed(initstate) — matches Godot's pcg32_srandom_r
# randi() — unsigned 32-bit integer
# randf() — float in [0, 1)
# randiRange(from, to) — integer in [from, to] inclusive
# randfRange(from, to) — float in [from, to)
Vector2i Translation
GDScript Vector2i patterns are recognized and converted to {x, y} objects
or direct field access. Vector2i(a, b) → {x: a, y: b}, v.x/v.y access
preserved as-is.
Collection Method Support
GDScript collection methods are translated to TypeScript equivalents:
.has(key)→.has(key)(Map/Set) orkey in obj(object).get(key, default)→obj.get(key) ?? defaultorobj[key] ?? default.is_empty()→.length === 0or.size === 0.append()→.push().size()→.length
Math Function Mapping
GDScript math builtins map to Math.*:
absf()/absi()→Math.abs()clampf()/clampi()→Math.min(Math.max(...))maxf()/maxi()/minf()/mini()→Math.max()/Math.min()roundi()/floori()/ceili()→Math.round()/Math.floor()/Math.ceil()sqrt()→Math.sqrt()
Extend
To add a new GDScript → TypeScript pattern, edit transforms.py for pure line
replacements or assembler.py:_do_transform_line() for context-sensitive patterns
(those that depend on being inside a tile loop, a specific method, etc.).
Always add a test in tests/test_transforms.py or tests/test_assembler.py.