Razorbill

Architecture & Concepts

Overview

Razorbill is built on a principle: every mutation to a project must flow through a typed operation. This applies equally to manual edits in the editor, AI-generated changes, and CLI batch operations.

Project Graph

The project graph is the single source of truth for all authored data. It contains:

  • Nodes: Assets, Scenes, Prefabs, Scripts, Build Targets
  • Edges: Dependencies, references, overrides
  • Every node has a stable GUID for identity
  • Cooked artifacts use ContentHash for cache addressing

Project Structure

MyProject/
├── Content/           # Authored data (schema-versioned)
│   ├── Scenes/        # .scene files (JSON)
│   ├── Scripts/       # .cpp + .scriptasset files
│   ├── Prefabs/       # .prefab files
│   └── Materials/     # Material definitions
├── Library/           # Cooked cache (content-addressed)
│   ├── *.mesh         # Compiled mesh data
│   ├── *.texture      # Processed textures
│   └── Scripts/*.dylib # Compiled script libraries
└── Build/             # Player output

Typed Operations

An operation is a structured mutation with:

  • Input schema — Validated parameters
  • apply() — Executes the mutation through Project Graph APIs
  • Diff — Structured record of what changed
  • Undo — Inverse operation to revert the change

Operations never partially apply. If validation fails, nothing changes.

Example: CreateEntity Operation

{
  "op": "CreateEntity",
  "params": {
    "name": "Player",
    "parent": "00000000-0000-0000-0000-000000000001"
  }
}

This produces a diff containing the new entity node, its GUID, and the parent-child edge.

Transactions

Multiple operations can be grouped into a transaction that commits or rolls back atomically:

[
  { "op": "CreateEntity", "params": { "name": "Bullet" } },
  { "op": "AddComponent", "params": { "entity_name": "Bullet", "component_type": "Transform" } },
  { "op": "AddComponent", "params": { "entity_name": "Bullet", "component_type": "Rigidbody" } },
  { "op": "AddComponent", "params": { "entity_name": "Bullet", "component_type": "Collider" } }
]

If any operation fails, the entire transaction is rolled back.

Structured Diffs

Unlike text-based diffs, Razorbill produces graph-level diffs that describe:

  • Nodes created or deleted
  • Properties changed (with old and new values)
  • Edges added or removed

This enables precise undo/redo, conflict detection, and AI introspection.

Validators

Validators run headless (no editor required) to gate changes:

ValidatorPurpose
SchemaValidatorValidates scene/prefab schema versions and required fields
GraphValidatorChecks references resolve, detects forbidden cycles
BuildValidatorVerifies project structure integrity
HeadlessRunValidatorRuns headless playtest for N seconds
# Run validators from CLI
./build/toolchain/cli/eng_cli validate ~/MyProject

Entity-Component Architecture

Razorbill uses an entity-component system:

  • Entity — A named container with a GUID, optional parent, and child hierarchy
  • Component — Typed data attached to an entity (Transform, MeshComponent, Rigidbody, etc.)
  • System — Runtime logic that processes entities with specific component combinations

Components are pure data. All behavior comes from systems and scripts.

Scripting Model

Scripts are C++ files compiled to dynamic libraries (.dylib / .dll) and hot-reloaded at runtime. They interact with the engine through a stable C ABI via ScriptContext:

void OnUpdate(ScriptContext* ctx) {
    // All engine interaction goes through ctx->
    float pos[3];
    ctx->get_position(ctx->self, pos);
    pos[1] += ctx->get_delta_time();
    ctx->set_position(ctx->self, pos);
}

This design means scripts never link against engine internals, enabling hot-reload without restarting the editor.

Dependency Rules

The engine enforces strict dependency layers:

foundation/   → (nothing)
runtime/      → foundation
toolchain/    → foundation + runtime data formats
editor/       → foundation + runtime + toolchain
ai/           → foundation + toolchain
sdk/          → foundation public headers only

Runtime never depends on the editor. The editor is a client of the runtime and toolchain.

AI Safety

The AI agent uses the same typed operation system as the editor. This means:

  • Every AI mutation is validated before applying
  • All changes produce structured diffs and undo artifacts
  • A capability system controls which operations the AI can execute
  • Rate limiting prevents expensive operations from running unchecked

See AI Agent for details on the AI workflow.

On this page