This walkthrough builds a small Godot application with a counter implemented in its own C++ library. Godot loads the TTX extension, the extension discovers the counter's interface, and a GDScript button calls it. The completed application carries the libraries it needs with it.

Downloading the tools

Install Godot 4.7 or later, Python 3 and Bazel. The example uses the standard Godot editor and a Linux x86-64 build. Bazel acquires the C++ compiler selected by the example's build configuration.

From the Godot extension release, download the Linux x86-64 SDK bundle. It contains the extension, public headers and matching TTX and Perimortem runtimes. The image lab is a separate source example, not part of this bundle.

Create an empty project in Godot's Project Manager and close the editor while installing native libraries. In that project's directory, extract the runtime files and notices:

unzip /path/to/godot-ttx-sdk-linux-x86_64.zip 'addons/*' 'licenses/*'

Building your library

Download the example's C++ source into your project:

curl -L https://raw.githubusercontent.com/tetrodotoxin-dev/Godot/v0.1.0/demo/counter/counter.cpp -o counter.cpp

Create MODULE.bazel with the published compiler toolchain and extension bundle:

module(name = "counter")
bazel_dep(name = "rules_cc", version = "0.2.17")
bazel_dep(name = "platforms", version = "1.0.0")
bazel_dep(name = "tetro_toolchain", version = "0.2.1")
archive_override(
    module_name = "tetro_toolchain",
    sha256 = "eea7461fb783d2b87a638c4ce1c8d9cbee73e54c90259516ca73cd7e850bdc0f",
    urls = ["https://github.com/tetrodotoxin-dev/Toolchain/releases/download/v0.2.1/tetro_toolchain-0.2.1-source.tar.gz"],
)
register_toolchains("@tetro_toolchain//:cc_toolchain_for_linux_x86_64")
http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "godot_ttx",
    urls = ["https://github.com/tetrodotoxin-dev/Godot/releases/download/v0.1.0/godot-ttx-sdk-linux-x86_64.zip"],
    # Copy the bundle's SHA256SUMS entry from the release here.
    sha256 = "SDK_SHA256",
)

Create BUILD.bazel. The counter has one SDK dependency:

load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_shared_library.bzl", "cc_shared_library")

cc_library(
    name = "implementation",
    srcs = ["counter.cpp"],
    copts = ["-fvisibility=hidden"],
    deps = ["@godot_ttx"],
)
cc_shared_library(
    name = "counter",
    shared_lib_name = "libcounter.so",
    deps = [":implementation"],
    user_link_flags = ["-Wl,-z,defs", "-Wl,-rpath,$ORIGIN"],
)

Create .bazelrc with build --symlink_prefix=.bin/ to keep generated files out of Godot's resource scan. Then build and install your provider:

bazel build //:counter -c opt
cp .bin/bin/libcounter.so addons/godot_ttx/

Bazel downloads the bundle and builds only counter.cpp. Your project needs neither Godot's C++ bindings nor the extension's implementation sources. The public field contracts describe how parameters and results project into Godot values. TTX checks the representations used to call each method.

Connecting it to Godot

Add these settings to your project's project.godot:

[ttx]
imports={
"counter": "res://addons/godot_ttx/libcounter.so"
}
classes=[{
"module": "counter",
"export": "Counter",
"name": "TtxCounter",
"base": "Node"
}]

imports assigns a project name to the library. The class entry selects its Counter route and exposes it as TtxCounter, derived from Godot's Node. Nested routes can use an array, such as "export": ["Tools", "Counter"].

Import project.godot in Godot's Project Manager and open the project. Under Project > Project Settings > Plugins, enable TTX providers. The native bridge loads through its .gdextension file; the editor plugin supplies the provider-library export step.

Create a scene with a VBoxContainer root, a Label named Value, and a Button named Advance. Set the button's text to "Advance", attach this script to the root and save the scene as main.tscn:

extends VBoxContainer

var counter = TtxCounter.new()

func _ready() -> void:
    add_child(counter)
    $Value.text = "0"
    $Advance.pressed.connect(_advance)

func _advance() -> void:
    $Value.text = str(counter.advance(1))

Run with F5 and select main.tscn as the main scene when prompted. Press Advance and the displayed count increases.

The scene owns the node after add_child. A second TtxCounter has independent state. Restart the editor after rebuilding and replacing native libraries so new instances use the new code.

Exporting the application

Open Project > Export, add a Linux preset and install the matching Godot export templates when prompted. Export the project into an empty directory outside the source tree.

The extension's manifest supplies its runtime dependencies. The TTX providers plugin copies the libraries selected by ttx/imports, preserving their paths in the exported application. The counter is handled by that configuration in the same way as another provider.

Run the exported executable and press Advance. Then copy the entire export directory to another location and run it again. Copy the SDK's licenses/ directory into the export and distribute the directory as a whole, including its shared libraries and license notices. The recipient needs a compatible Linux system, but does not need Bazel, the SDK headers or the Godot editor.

Adding another provider

Build the provider as another library, add it to ttx/imports, and select the interfaces you want to register in ttx/classes. A missing route or incompatible method produces a registration error in Godot's output. Its C++ implementation can use a different internal model while fulfilling the same published contract.

The image lab supplies a larger example with GDScript and CUDA providers. Its image operations remain application code rather than requirements of the generic extension SDK.