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:
| Validator | Purpose |
|---|---|
| SchemaValidator | Validates scene/prefab schema versions and required fields |
| GraphValidator | Checks references resolve, detects forbidden cycles |
| BuildValidator | Verifies project structure integrity |
| HeadlessRunValidator | Runs 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.