TDXGTB

A game engine built in TouchDesigner

Grand Theft
Banana

TouchDesigner components that play a game you declare in tables: stages, rules, vehicles, quests, bosses. Grand Theft Banana is the open-world game we built with them. You play Gros Michel, the banana a fungus wiped off the world's plantations in the 1950s, seventy years later and back in Panamá to face it.

How the engine works
components, one event bus
end-to-end test gates
8
jobs in the game, two endings
17
3D models, all generated locally

The game · BigMike2

One last harvest, eight jobs across Panamá.

Almirante is the hub: talk to the town, wash your boots, pick a job from one of six portals. Each job changes how you move.

Gros Michel waving a banana in the hub
Gros MichelSeventy years out of the trade
Mittens the cat on the pier
MittensTreasurer
La Marchita on the barge
La MarchitaThe fungus, up and walking

    Gallery

    The engine · TDXGTB

    Everything in the game is a component you can reuse.

    Grand Theft Banana runs on TDXGTB, a family of TouchDesigner components. Each feature below is one of them, dropped into the world and filled with rows.

    Stages and rules are table rows, with no wires between components

    Every game needs the same plumbing: a health bar, a timer, a portal that starts a level, a boss that gets angry at half health. TDXGTB has a component for each of those.

    Each component owns one job and reads one table. The Director reads stages, Vitals reads things that can be hurt, Fx reads which events should look like what. They talk over an EventBus, in one event grammar. A consequence no component owns is a row in the bus's Rules table before it is a line of code.

    This is a stage from our test world, exactly as the Director reads it:

    One table per component

    Each component is authored by one table, kept beside it so every copy keeps its own rows. A world is the components plus their rows.

    One event grammar

    kind, kind:object, kind@subject. vitals.dead@player is "the player died"; vitals.dead:player is "the player killed something". Director, Hud, Fx, Launcher and the Rules all ask the bus.

    Failures are loud

    A rule that names a missing operator or a method that is not public shows up as a red script error on the bus. Runtime state survives a reinit.

    Components

    components in three layers.

    Each card is generated from the component's own code: its docstring, its parameter declarations, its public methods and the events it publishes.

    Made here

    How the models were made

    All seventeen glTF models in the game, Gros Michel included, were generated locally with Modly from coloured blockouts we built first. Blender fits each mesh back onto its blockout, decimates it, bakes the colours into a texture and rigs it. The end-to-end test fails if a model from anywhere else ever gets back in.

    Everything else is TouchDesigner geometry: the skyline, the sea, the pier, the barge, the jungle. The town is 340 people on a sidewalk graph, 48 cars and 24 reefer trucks, 54 pelicans and nine boats, all instanced.

    The sound effects were generated locally too, with Stable Audio, and the trailer's music is our own song.

    • Blockoutcoloured primitives, rendered as the input image
    • Modlyimage to mesh, on the local GPU
    • Blenderfit, decimate, bake a texture, rig
    • TouchDesignerglTF In, animation clips declared in a table
    Grand Theft Banana key art: ten panels from the game around the GTB wordmark

    Try it in the browser

    Publish an event and see which rows answer it.

    The rows below are the real Rules, Fx Triggers and Hud Lines from our test world. The matching and the rule calls are a line-for-line port of the EventBus; the effects are the Fx component's shader.

    Publish

    What happened

      bus · Rules when | do (editable)
      fx · Triggers on | effect | amount | seconds
      hud · Lines (toasts) on | text | seconds

      Building a world

      A world is clones of the masters, each with its own tables.

      1. Clone

        Each component is a master COMP. A world holds clones of them, so a fix to a master reaches every world, and each clone keeps its own table rows.

      2. Declare

        Point the components at each other with parameters (Bus, World, Player) and fill their tables: stages, things that can be hurt, items, zones, gates, NPCs, triggers.

      3. Say the rest in Rules

        A consequence no component owns is a when | do row on the bus: vitals.below@boss:50 → npcs Set boss interval 1.6.

      4. Play it end to end

        Tests drive the real world from outside TouchDesigner: gates across the physics and the game, run with realtime off so no frame is skipped.

      Requirements

      • TouchDesigner 2025, tested on build 2025.33070.
      • Physics runs on TouchDesigner's own Bullet Solver COMP, without plugins or an external engine.
      • Python only in extensions; per-frame work stays in CHOPs and GLSL where it can.