Tenon Engine
Painted timber bracket sets (dougong) inside the Manjusri Hall

In development · Not yet released


Joinery for real-time worlds.

The whole game is a tree of entity nodes, spliced together and scripted in TenonScript. Release builds compile ahead of time through LLVM. Rendering is Vulkan path tracing, with no raster fallback.

Model
A tree
Script
.tns
Shipping
AOT · LLVM
Render
Vulkan RT

01The joint

Two parts.
No nails.

A tenon is cut to fit its mortise, and the two hold by shape. Tenon builds a game the same way: entity nodes spliced into one tree, each one seated where it belongs.

Entity

The node

The unit of the tree. Its fields are properties, and a property is not a node.

Graft

project.tproj

Binds an entity as another node's subsidiary. Declared in TML, not in a script.

Attach

At runtime

Instantiates that subsidiary onto a property.

FIG. 1 — THROUGH-TENON WITH LOCKING PIN

STATE APART

02Lineage

Held by shape alone.

Mortise-and-tenon joinery has carried Chinese timber halls for more than a thousand years. Some of the buildings below have stood since the Tang dynasty.

Foguang Temple, Mount Wutai · East Hall, 857 CE
FOGUANG TEMPLE, MOUNT WUTAI · EAST HALL, 857 CE
Nanchan Temple, Mount Wutai · 782 CE
NANCHAN TEMPLE, MOUNT WUTAI · 782 CE
Manjusri Hall · interior bracketing
MANJUSRI HALL · INTERIOR BRACKETING

03The model

One tree.
Nothing loose.

The root node is the game itself. Everything else is spliced on. The tree is how the game is controlled: it says what exists and how it behaves. Rendering, physics and audio are backends. They are not nodes, and they never appear in the tree.

Entity nodes

The unit you place, spawn and address. Data on a node lives in properties. A property is a field: it does not become a node, and it has no children.

Graft, then attach

A graft binds one entity as the subsidiary node of another. The binding is written in project.tproj, not in code. At runtime, attachment instantiates that subsidiary onto a property, so the instance sits exactly where the field says.

One block name

Every entity has a single block name, unique across the project. A script reaches it by writing $BlockName. Compilation resolves that to a NodePath. An AOT build lowers the path to a fixed index; under the VM the same lookup stays hot through an inline cache.

Logic stays out of the tree

A .tns file holds game logic and nothing structural. The shape of the game is project.tproj. Configuration is project.tconf. Scripts change behavior. They do not describe structure.

Files · all of them TML

.tns
Game logic only.
project.tproj
The tree, and every graft.
project.tconf
Configuration.
.tnm
One level per file. The filename is the level name, and the two are locked.
.tnmc
The compiled level.

How a build runs

AOT + LLVM
What ships. Scripts compile into the executable.
VM
What the editor and mods run. Hot reload, no rebuild.
TRuntime
The engine runtime.
TNSCoreRuntime
Core script runtime.
TNSModRuntime
Mod script runtime.
TDeps
The backends, packed in. None of them is a fallback.

Inside TDeps

Vulkan path tracing. No raster path underneath it.

  • Vulkan

    Path tracing only. Hardware that cannot ray trace is unsupported.

  • Light

    A physical atmosphere, volumetric clouds, ray-traced shadows.

  • OIDN

    Denoising.

  • Jolt

    Physics.

  • SDL3

    Window and input.

  • Steam Audio

    Spatial audio.

Tenon is built for AAA production. A machine without ray tracing is not a target.

04From the workshop

Latest updates.

Announcements, progress notes and design writing.

1 MIN READ

Why we named it Tenon

The name comes from a joint that holds by shape. The engine is a tree of entity nodes, spliced the same way.

  • #design
  • #essay
→

Not yet released

Still in the workshop.

Tenon Engine is under active development. Follow along on GitHub.