gdscript-transpiler/README.md
Claude Code 27396acf47 release(forgejo-.forgejo/): 🔖 Publish new release with updated metadata, README, and source code + tests
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-03-25 22:43:42 -07:00

3.9 KiB

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_casecamelCase
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.pyextract_functions(), check_functions()
  • transforms.pyapply_simple_transforms() and its sub-converters
  • context.pyMethodContext: tracks tile-loop state, buffer dicts, upwind/hop vars
  • postprocess.pyjoin_continuation_lines(), add_closing_braces()
  • assembler.pytransform_method_body(): the coordinate bridge (axial → flat-array idx)

The assembler handles game-engine-specific patterns:

  • Flat-array idx(col, row, w) replacing axial Dictionary lookups
  • Float32Array buffer dicts for per-tile accumulation
  • hopCol/hopRow tracking for wind-hop traversals
  • upwind_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) or key in obj (object)
  • .get(key, default)obj.get(key) ?? default or obj[key] ?? default
  • .is_empty().length === 0 or .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.