Tutorial: Create a World
v1.0.111 · docs-public.v0This is a learning-oriented walkthrough. By the end you will have built a first spatial world — a persistent, stateful environment with a camera, a light, a floor, and a couple of interactable props — and you will understand how each edit flows through canonical actions to backend authority.
You can follow these steps through the workbench UI or through an MCP client. The page names the canonical action for each step plus the matching MCP tool, because both surfaces funnel into the same backend authority.
This tutorial is verified against the current generated component, action, and MCP references. It teaches world authoring and renderability; playability has a separate proof path in the next tutorial.
Media placeholder: add a short side-by-side capture of the workbench hierarchy, viewport, and generated component reference while the floor/camera/light are created.
What you will build
A small world you can later turn into a game:
- a camera the runtime drives,
- a light so the scene is lit,
- a floor props can rest on,
- two interactable props standing on the floor.
Before you start
Read The Project Graph and Backend Authority first if you are new to the model. The one idea to hold onto: you never edit "the world" directly. You submit a canonical action; the backend validates and applies it; the workbench shows you a rendered projection of the new authoritative state.
Every step uses a project.* action or a semantic operation. Do not bypass them with raw model mutations — those skip authority and validation. The privileged raw-write tools exist for internal paths; normal authoring uses what is named below.
Step 1 — Discover the component contract
Before authoring entities, ask the engine which components exist and what fields they carry. Do not invent fields.
- List the 24 built-in ECS component types with
engine_list_component_typesengine_list_component_types. - Fetch one component's schema with
engine_get_component_schemaengine_get_component_schema.
The canonical inventory is the generated ECS component reference. For this tutorial you will use TransformComponent TransformComponent (spatial placement), CameraComponent CameraComponent (viewpoint), LightComponent LightComponent (lighting), RenderableComponent RenderableComponent (visible geometry), and ColliderComponent ColliderComponent (a solid surface and physics contacts).
The contract behind this step: the built-in components are atomic engine components with versioned field contracts; the inventory pins a contract hash per component, and the engine validates every payload against ComponentSchema. That is why discovery comes before authoring — the field set is fixed by code, not by you.
Step 2 — Create the project and the world
A project (a game in the control plane) is the container; a world is persistent state inside it.
- Create the workspace and project with
workspace.createworkspace.createandgame.creategame.create(MCP:project_create_gameproject_create_game). Keep the returned project id; it is thegame_idon every later call. - Create the world with
project.world.createproject.world.create(MCP:project_create_worldproject_create_world). Give it a stable key likeworld.mainso later calls can reference it by key.
Expected result: an empty world exists as authoritative state. Nothing renders yet — there is no camera, no light, and no geometry.
The contract behind this step: worlds are Project Graph resources created through governed actions, so the world has an identity, a version, and an audit trail (CreateProjectWorld) from the moment it exists.
Step 3 — Add a camera
The runtime renders through the highest-priority active CameraComponent. Create a camera entity with project.entity.create project.entity.create (MCP: project_create_entity project_create_entity), attaching components by their default keys at creation. Components are supplied as a keyed object — the key is the component's default key (for example component.camera), and the value is its field payload:
<!-- example:conceptual -->
{
"request": {
"key": "camera.main",
"name": "Main Camera",
"worldId": "world.main",
"components": {
"component.transform": { "position": { "x": 0, "y": 6, "z": 10 } },
"component.camera": { "active": true, "priority": 10, "fov": 60 }
}
}
}
The snippet is illustrative — read the exact CameraComponent and TransformComponent field contracts and defaults from the generated reference before you set values. CameraComponent defaults active to true, priority to 10, and projection to perspective; you can leave a field out to take the canonical default.
Expected result: the world now has a viewpoint. If you open Play it will draw from this camera, though the scene is still empty.
Step 4 — Add a light
Create a second entity with component.transform plus component.light. Read the LightComponent contract from the generated reference for the light type, color, and intensity fields, then set them through the same project.entity.create project.entity.create call.
Expected result: surfaces in the scene are now lit. With no geometry yet there is still nothing to see, but the lighting rig is in place.
Step 5 — Add a floor
A floor is geometry that is also solid. Create a floor entity carrying three components:
component.transform— place and scale it into a wide, flat surface.component.renderable— make it visible (aRenderableComponentreferences the mesh/material to draw).component.collider— make it solid so props and, later, a player can rest on it. TheColliderComponentshapedefaults tosphere; for a floor set it toboxand give itsizeandsolid: true. Read the exact shape enum (box,sphere,disc,capsule,mesh) and field contract from the generated reference.
Expected result: open Play and you should see a lit surface from the camera's viewpoint. That proves renderability — it does not yet prove playability.
The contract behind this step: ColliderComponent is consumed by the runtime physics and collision systems (runtime.physicsSystem, runtime.collisionSystem), whereas RenderableComponent is a presentation component projected to the renderer. The floor is solid because of the collider, not because it is drawn — rendering and collision are separate contracts.
Step 6 — Add interactable props
Add two prop entities standing on the floor. Each prop carries component.transform, component.renderable, and component.collider. Position them above the floor so they rest on it.
"Interactable" is behavior, and behavior is authored as a script, not as a component field. In v1 there is no InteractableComponent — interaction is expressed through Script Semantic Patch. To make a prop respond when something enters its collider, attach a script and add a trigger handler:
- Create a script shell with
project.script.createproject.script.create(MCP:project_create_scriptproject_create_script) and attach it via the entity'scomponent.script. - Apply behavior with
project.script.patch.applyproject.script.patch.apply(MCP:project_apply_script_semantic_patchproject_apply_script_semantic_patch), using theaddTriggerHandleroperation from themcp_safepack.
The compiler lowers semantic operations to canonical Script IR; you never hand-author node ids on this path. See the Script Semantic Patch reference and How-To: Write GessaScript.
Canonical reference: Script Semantic Patch operationsExpected result: two props stand on the floor, each able to react to a trigger. There is still no player — that comes in the next tutorial.
Step 7 — (Optional) Generate an asset
To replace a placeholder mesh or texture with generated content, quote and create a generation job with generation.job.quote generation.job.quote and generation.job.create generation.job.create (MCP: generation_quote_job generation_quote_job, generation_create_job generation_create_job). Generation is asynchronous; when the asset lands, reference it from a prop's RenderableComponent.
Step 8 — Inspect and confirm
Reload the workbench. The world, its entities, and their components are still there because they are authoritative state, not view state. What you see rendered is a projection of that state — change the camera priority or a light's intensity through project.entity.component.set project.entity.component.set and the view follows.
Expected result: a persistent first world — camera, light, floor, two props — that survives reload and renders from a runtime-driven camera.
What you proved and what you did not
You demonstrated that the world persists and renders. You did not demonstrate that it is playable: no player has spawned, no input is bound, and no entity is possessed. Those are separate properties with separate proof, and that is exactly what the next tutorial builds toward.
Where to go next
- Make the world a game and reach a Play proof: Tutorial: Create a Playable Game.
- Understand the model underneath: Explanation: The Project Graph.
- Edit components after creation: How-To: Edit Components.
Status
This tutorial describes the canonical hand-build flow for a v1 world. Every action, component, and tool named here is verified against the generated Tier-2 reference. Runtime claims still need runtime receipts; this tutorial intentionally stops at a persistent, renderable world.