Brief for assistants
Give this page to any AI model before you ask it for help with an AR Clip project. Paste it into the chat, or give the model this page's address.
No model has been trained on AR Clip. Without this page, models borrow from other engines they know and give answers that look right but are wrong.
AI tools that look for machine-readable context find it on their own at
/llms.txt. The whole documentation in one file is at
/llms-full.txt.
How a project is built
Everything in a project is an entity. An entity is a name plus a set of components. The components decide what the entity is. There are no classes and no object types to choose from.
Project
└── Space shared background, lighting, grid, units
└── Scene an entity carrying an Anchor — the trigger that makes it appear
└── Entity
└── Entity entities nest
Do not mix up these two relationships:
- Composition — an entity has components, at most one of each kind. Components are not children.
- Containment — an entity contains other entities. Moving a parent moves its children.
A scene is an entity with an Anchor and no Transform. Logic for the whole space is an entity with a Script or Patch and no parent.
You do not write the code that makes components work. Your job is to decide which components exist and what values they hold.
Four ways to add behaviour
| Layer | Where it lives | Use it for |
|---|---|---|
| Events | an Events component | a trigger and a list of steps; most interactivity |
| Patches | a patch graph or resource | logic with values and conditions, built visually |
| Scripts | a script resource | anything that really needs code |
| UI | a UI card | all 2D interface |
All four change the same components. If two of them handle the same trigger, it fires twice. This is a very common bug in generated answers.
Names
- Triggers are kebab-case:
on-click,on-launch,on-collide. - Steps are snake_case:
play_animation,set_visibility,scene_transit_action. - Key and mouse triggers have other names in scripts. An event uses
on-keyandon-mousewith branches. A script listens foron-keydown/on-keyupandon-mousedown/on-mouseup/on-click. - Names must match exactly. A mistyped name gives no error — it just never matches.
- The editor shows readable labels, like "Show / hide object". Code uses the ids above.
Look names up, do not guess
If you are connected over MCP, these calls show exactly what exists:
| Call | Returns |
|---|---|
list_component_schemas | every component and its fields |
list_event_types | every trigger and step, with parameters |
list_patch_nodes | every patch node, with its ports |
describe_*_api | written guidance for each area |
Call them before you write anything that names a component, trigger, step or node. Inventing a name that sounds right is the most common mistake on this platform.
Without MCP, use the reference: components · triggers · steps · patch nodes · shader nodes.
Mistakes that look right
update({ position: { y: 2 } }) sets x and z to zero. Always spread the old value:
t.update({ position: { ...t.$data.position, y: 2 } });
material.update({ color }) does nothing, because color lives inside a slot:
material.update({
materials: [{ ...material.$data.materials[0], color: '#ff0000' }],
});
$dataIt seems to work, but the change is lost. Only update() and updateAt() write data.
Physics controls its position and overwrites it on the next step. Use ctx.physics.teleport to
place it, and applyImpulse / applyForce to move it.
A GLB is not solid until you give it a collider. A dynamic one falls through the world.
More rules that catch models out:
- Rotation is in radians in scripts, and in degrees everywhere a person looks — the editor, patch node ports, MCP tools.
- Multiply by
dtinctx.tick, or motion speed depends on the device's frame rate. - Import component classes in scripts from
@was/engine:TransformComponent,MetaComponentand the rest. OnlyinitanddefinePropsare globals. - There is no "animation finished" event, in any mechanism. Time it yourself.
- Scripts have no DOM, no
fetch, no timers and no rendering library. Usectx.tick,ctx.audio,ctx.store, and a UI card for interface. - The editor does not run logic. Scripts, patches, physics and timers run only in preview or in a published project. Never tell a user their script "should run in the editor".
- While a state is active, edits to that object are saved into the state, not into the object.
- Use the timeline tools to change a timeline. If you edit the timeline component directly, the animation may not play.
- One object, one way to animate it. The timeline overwrites a transition.
Use a built-in step instead of rewriting it
ctx.step(name, params, { targets }) runs any step the editor offers: animation, state switching,
scene transitions, transitions. Check the step reference before you write the same thing by hand.
Check a patch before you say it works
Look at it as code and read the result. A graph with a problem reports a data cycle or broken
JavaScript. Over MCP, use preview_patch_code.
Units
| Quantity | In data | What a person sees |
|---|---|---|
| Position | metres | project units |
| Rotation | radians | degrees |
| Animation time | seconds | seconds (milliseconds on state switches) |
| Opacity | 0–1 | 0–100 in keyframes and in the opacity step |
| Font size | pixels, 1000 px = 1 m | pixels |
| Clip frames | 30 fps | frames |
How to answer the user
- Ask which layer they want. "Without code" and "in a script" lead to very different answers to the same question.
- Choose the simplest layer that works. An event is better than a patch; a patch is better than a script.
- Say where to click. For someone in the editor, panel names matter more than concepts.
- Remind them to preview. Most "it does not work" reports happen because the editor does not run logic.
- Do not invent names. If you are not sure, say so and point to the reference.