--- name: unity-rql description: |- How to read and change anything in the Unity Editor with RQL (rql-query / rql-mutate / rql-schema): the query language, operators, sources (scene objects, assets, scenes, prefabs, console logs, Editor state), Editor operations (create, add components, scenes, prefabs, assets, selection, Play Mode) and what installed extensions add. metadata: generated-by: mcp-plugin-dotnet --- # RQL — query and change the Unity Editor RQL is one pipeline language for the whole Editor: find objects, read members, filter, aggregate, and change them in one call. Prefer one precise query over many exploratory calls. - `rql-query` — read-only queries, compact table results. - `rql-mutate` — queries ending with `set` / `call`; all-or-nothing, undoable (Ctrl+Z), `dry_run: true` previews. - `rql-schema` — sources and component types in the scene; `rql-schema(type)` lists one type's members and methods. ```bash unity-mcp-cli run-tool rql-query --input '{"query": "objects | where name contains \"Enemy\" | select $ref name"}' unity-mcp-cli run-tool rql-mutate --input '{"query": "objects | where name == \"Player\" | set active = false"}' ``` ## Language ``` RQL: source | stage | stage ... Sources: objects (every GameObject in the loaded scenes, inactive included), roots, scenes, selection, prefab (the prefab open in prefab editing mode), console (Editor log entries), shaders, componentTypes, profiler (memory / rendering / frame snapshots; call Start / Stop / Save), tests (test methods; run a selection with tests-run query), testResults (last run), editor (Editor state and operations). Assets: unity.assets("t:Material") or unity.assets("t:Prefab", "Assets/Enemies"), unity.asset("Assets/Mats/Red.mat"). ref("Light#1234") resolves a $ref; unity.find("Player") or unity.find("Level/Pillar_1") a GameObject by unique name or path. Stages: where filter select a b.c alias=(expr) project columns (wrap computed expressions in parentheses) sort [desc], ... stable sort first N | skip N | count get replace each item by a member (lists are flattened) recurse children [max-depth=N] [include-self=false] walk the hierarchy (input items included by default) distinct [expr] | group-by expr | sum expr | min expr | max expr | avg expr Expressions: == != < <= > >= and or not + - * / %; contains, starts-with, ends-with (case-insensitive); matches "regex"; x in [a, b]; x is null; x is not null; $ is Light (includes subclasses); has(member). Literals: numbers, "strings", true/false/null, lists [a, b], objects {x: 1, y: 2}. Paths: a.b.c, list[0], map["key"]; .member on a list maps over its elements. List methods: .any(pred) .all(pred) .count([pred]) .sum(e) .min(e) .max(e) .first([pred]); inside them bare names refer to the element, falling back to the outer item. Meta: $ (current item), $ref (stable id such as Light#1234), $type, $path, $index, $depth. Enums compare to strings (type == "Spot"); == on strings is case-sensitive. Unity: GameObject has components (list), children (list), active, name, tag, layer, transform (position, localPosition, eulerAngles, localScale, parent). Component members are the C# members (public + [SerializeField]); find them via objects | get components | where $ is Light. Vectors/colors print as (x, y, z); write "(1, 2, 3)", [1, 2, 3] or {x: 1, y: 2, z: 3}; colors also "#ff8800". Material shader properties: properties["_Color"]. Destroyed objects read as null (missing references: where target == null). Navigate with paths or get; select only projects output columns. Results come back as compact rows (header line, then col|col). Long results are truncated — refine with where/first or use count. Unknown members produce warnings with suggestions; rql-schema(type) lists a type's members. ``` ## Changing things (rql-mutate) ``` set path = expr, ... assign members (paths may go through structs: set transform.position.y = transform.position.y + 1) call Method(args) invoke a method the tools expose Examples: objects | where name == "Player" | set transform.position = "(0, 1, 0)" objects | get components | where $ is Light | set intensity = intensity * 2, color = "#ffcc88" objects | where tag == "Enemy" | set active = false unity.asset("Assets/Mats/Red.mat") | set properties["_Color"] = "(1, 0, 0, 1)" objects | where name == "Spawner" | set targets = append(targets, ref("GameObject#1234")) Create / add / remove (call; the receipt's result column holds the new object's $ref for follow-up queries): editor | call CreateGameObject("Props") new root GameObject editor | call CreateGameObject("Crate", ref("GameObject#1234"), "Cube") child of a parent, optional primitive objects | where name == "Crate" | call AddComponent("Rigidbody") add a component by type name objects | where name == "Old" | call Destroy() remove a GameObject (components: get components | where $ is X | call Destroy()) objects | where name == "Lamp" | set transform.parent = ref("GameObject#1234") reparent (keeps the world position) objects | where name == "Crate" | call Duplicate() copy next to it (returns the copy) Scenes, prefabs, assets, Editor state: editor | call OpenScene("Assets/Scenes/Level.unity") editor | call NewScene("Assets/Scenes/New.unity") scenes | where path == "" | call SaveAs("Assets/Scenes/New.unity") scenes | where name == "Level" | call SetActive() editor | call InstantiatePrefab("Assets/Prefabs/Enemy.prefab", ref("GameObject#1234"), "(0, 0, 5)") objects | where name == "Crate" | call SaveAsPrefab("Assets/Prefabs/Crate.prefab") editor | call OpenPrefab("Assets/Prefabs/Enemy.prefab") then prefab | recurse children | … then editor | call ClosePrefab() editor | call CreateMaterial("Assets/Mats/Glow.mat") editor | call MoveAsset("Assets/A.mat", "Assets/Mats/A.mat") editor | set selection = [ref("GameObject#1234")] editor | set isPlaying = true profiler | call Start() profiler | call Save("Logs/profile.json") (read: profiler | select memory frame) ``` ## Sources | Source | What | |---|---| | `animation` | animation: animators (every Animator in the loaded scenes), CreateClip(path, frameRate, loop), CreateController(path, motion) | | `cinemachine` | Cinemachine: cameras, brains, noiseProfiles, bodyTypes / aimTypes / extensionTypes; CreateCamera(name, follow, lookAt, position, eulerAngles, priority), EnsureBrain(camera) | | `componentTypes` | component types that can be added (name fullName namespace) | | `console` | captured Editor log entries, oldest first (last 1000): logType message timestamp stackTrace sequence | | `editor` | Editor state (isPlaying, isPaused, selection …) and operations: CreateGameObject, OpenScene, NewScene, SaveScenes, InstantiatePrefab, OpenPrefab / SavePrefab / ClosePrefab, CopyAsset / MoveAsset / DeleteAsset / CreateFolder, CreateMaterial, SaveAssets, RefreshAssets, ClearConsole, ExecuteMenuItem (rql-schema "editor" for signatures) | | `input` | Input System: assets (.inputactions), layouts, interactions, processors; CreateAsset(path, map?) | | `navigation` | AI Navigation project settings and operations: agentTypes (bake settings, writable), areas (name, cost), BakeAll(), ClearAll() | | `objects` | every GameObject in the loaded scenes, depth-first, inactive ones included | | `prefab` | root GameObject of the prefab open in prefab editing mode (none otherwise) | | `probuilder` | ProBuilder: meshes (every ProBuilderMesh in the loaded scenes), CreateShape(type, name, size, position, rotation, parent), CreatePolyShape(points, height, name, position, flipNormals, parent), Merge(meshes, deleteSources) | | `profiler` | Unity profiler: enabled supported memory rendering script frame modules (live snapshots, MB / ms); calls Start, Stop, ClearFrames, EnableModule, Save, Load (rql-schema "profiler" for signatures) | | `roots` | root GameObjects of the loaded scenes | | `scenes` | loaded scenes | | `selection` | objects selected in the Editor | | `shaders` | every shader the Editor knows (built-in and project): name supported hasErrors | | `splines` | spline containers of the loaded scenes (containers) and CreateContainer(name, position, eulerAngles, closed, parent) | | `terrain` | terrain operations without an owner: Create (Terrain GameObject + TerrainData asset), CreateLayer (TerrainLayer asset) | | `testResults` | results of the last tests-run: name status durationMs message stackTrace | | `tests` | test methods (fullName name fixture namespace assembly mode categories parameterized explicit ignored); run a selection with tests-run query, e.g. tests \| where fixture == "PlayerTests" | | `tilemap` | tilemap operations without an owner: CreateTilemap (Grid + Tilemap GameObject), CreateTile, CreateRuleTile (tile assets) | | `timeline` | timeline operations without an owner: Create (TimelineAsset .playable), CreateSignal (SignalAsset .signal) | | `probuilder.edges(…)` | probuilder.edges(mesh, faces?): distinct edges [[a, b], …] of the faces (index list; default every face), for Bevel / SubdivideEdges / ConnectEdges | | `probuilder.facing(…)` | probuilder.facing(mesh, direction): indices of the faces pointing Up, Down, Left, Right, Forward, Back or Other (local space, within 45°) | | `probuilder.openEdges(…)` | probuilder.openEdges(mesh): border edges [[a, b], …] (a face on one side only: around holes, plane borders), for Bridge | | `probuilder.vertices(…)` | probuilder.vertices(mesh, start?, count?): [{index, position}] local vertex positions (at most 20 per call; default 0, 20) | | `terrain.heightAt(…)` | terrain.heightAt(terrain, worldX, worldZ): world-space surface height (Y) at a world X / Z position | | `terrain.heightStats(…)` | terrain.heightStats(terrain, x?, y?, w?, h?): {min, max, average, cells} of a heightmap region (default: the whole heightmap) | | `terrain.heights(…)` | terrain.heights(terrain, x, y, w?, h?): normalized heights 0 … 1 of a heightmap region as rows (at most 20 × 20 cells) | | `tilemap.cell(…)` | tilemap.cell(tilemap, cell): {cell, tile, path, sprite, color, colliderType, flags, transform} of one cell (tile null when empty) | | `tilemap.cellToWorld(…)` | tilemap.cellToWorld(tilemap, cell): the world position of a cell's center | | `tilemap.cells(…)` | tilemap.cells(tilemap, tile?): the first 20 occupied cells (optionally of one tile asset, path or name), bottom-left first | | `tilemap.count(…)` | tilemap.count(tilemap, tile?, minX?, minY?, maxX?, maxY?, z?): occupied cells, optionally of one tile (asset, path or name) and inside a region | | `tilemap.tileAt(…)` | tilemap.tileAt(tilemap, cell): the tile asset at a cell "(x, y, z)", or null | | `tilemap.tiles(…)` | tilemap.tiles(tilemap, minX, minY, maxX, maxY, z?): tile names of a region as rows, top row (maxY) first, null = empty (at most 20 × 20) | | `tilemap.worldToCell(…)` | tilemap.worldToCell(tilemap, "(x, y, z)"): the cell containing a world position | | `unity.asset(…)` | unity.asset(path): the main asset at a path, e.g. "Assets/Mats/Red.mat" | | `unity.assets(…)` | unity.assets(filter, folder?): AssetDatabase search, e.g. "t:Material", "t:Prefab Enemy" (at most 200, loaded as needed) | | `unity.find(…)` | unity.find(name): the GameObject with that unique name or hierarchy path ("Level/Pillar_1"), e.g. set Follow = unity.find("Player") | ## Animation Clips and controllers are assets: `unity.assets("t:AnimationClip")`, `unity.asset("Assets/…/Walk.anim")`, `unity.asset("Assets/…/Player.controller")`. An AnimationClip has `curves` (path type property keyCount timeRange keys, keys with writable time value inTangent outTangent …), `objectCurves` (sprite swaps), `events` and `settings` (loopTime loopBlend mirror …), all writable views, plus ordinary members (frameRate wrapMode legacy length isLooping). An AnimatorController has `layers` (name defaultWeight blendingMode defaultState `states` anyStateTransitions) and `parameters` (name type defaultFloat defaultInt defaultBool); states and transitions are assets whose members (speed motion tag … / hasExitTime exitTime duration conditions …) are set directly. Writes and calls are undoable; creating an asset is not. `rql-schema "AnimationClip"` / `"AnimatorController"` list the methods. Clips (curve `path` is the child path under the Animator, "" = its own GameObject; `type` the animated component): ``` animation | call CreateClip("Assets/Animations/Walk.anim") empty clip, 60 fps animation | call CreateClip("Assets/Animations/Idle.anim", 30, true) path, frameRate, loop unity.assets("t:AnimationClip") | select name length frameRate isLooping n=(curves.count()) e=(events.count()) unity.asset("Assets/Animations/Walk.anim") | call SetCurve("", "Transform", "localPosition.y", [[0, 0], [0.5, 1], [1, 0]]) path, type, property, keys [time, value(, inTangent, outTangent)] unity.asset("Assets/Animations/Walk.anim") | call SetCurve("Body", "SpriteRenderer", "m_Color.a", [{time: 0, value: 1}, {time: 1, value: 0, inTangent: -1}]) unity.asset("Assets/Animations/Walk.anim") | get curves | select path type property keyCount timeRange unity.asset("Assets/Animations/Walk.anim") | get curves | where property == "localPosition.y" | get keys | select index time value inTangent outTangent unity.asset("Assets/Animations/Walk.anim") | get curves | where property == "localPosition.y" | set keys[1].value = 2, keys[1].outTangent = 0 unity.asset("Assets/Animations/Walk.anim") | get curves | where property == "localPosition.y" | call AddKey(1.5, 0.5) returns the key index; RemoveKey(index), SetKeys([[t, v], …]), Evaluate(t) unity.asset("Assets/Animations/Walk.anim") | get curves | where path == "Body" | set postWrapMode = "Loop" unity.asset("Assets/Animations/Walk.anim") | call RemoveCurve("Body", "SpriteRenderer", "m_Color.a") or … | get curves | where … | call Remove() unity.asset("Assets/Animations/Walk.anim") | set frameRate = 30, settings.loopTime = true unity.asset("Assets/Animations/Walk.anim") | call AddEvent(0.5, "Footstep", "left") time, functionName, stringParameter?, floatParameter?, intParameter? unity.asset("Assets/Animations/Walk.anim") | get events | select index time functionName stringParameter unity.asset("Assets/Animations/Walk.anim") | set events[0].time = 0.25, events[0].intParameter = 1 unity.asset("Assets/Animations/Walk.anim") | call RemoveEvent(0) ClearEvents() / ClearCurves() remove all ``` Animator controllers (states by name; a trailing `layer` argument is a layer name or index, default 0): ``` animation | call CreateController("Assets/Animations/Player.controller") Base Layer, empty state machine (CreateController(path, motion) adds a state) unity.asset("Assets/Animations/Player.controller") | call AddParameter("Speed", "Float") Float, Int, Bool or Trigger unity.asset("Assets/Animations/Player.controller") | call AddParameter("Grounded", "Bool", true) optional default value unity.asset("Assets/Animations/Player.controller") | call AddParameter("Jump", "Trigger") unity.asset("Assets/Animations/Player.controller") | call AddState("Idle", unity.asset("Assets/Animations/Idle.anim")) name, motion?, layer?; the first state becomes the default unity.asset("Assets/Animations/Player.controller") | call AddState("Walk", unity.asset("Assets/Animations/Walk.anim")) unity.asset("Assets/Animations/Player.controller") | call AddTransition("Idle", "Walk", "Speed", "Greater", 0.1) from, to ("Exit" = exit), parameter?, mode?, threshold?, layer? unity.asset("Assets/Animations/Player.controller") | call AddTransition("Walk", "Idle", "Speed", "Less", 0.1) unity.asset("Assets/Animations/Player.controller") | call AddAnyStateTransition("Idle", "Jump") mode defaults by parameter type: Bool / Trigger If, Float Greater, Int Equals unity.asset("Assets/Animations/Player.controller") | call SetDefaultState("Idle") unity.asset("Assets/Animations/Player.controller") | get layers | select index name defaultWeight defaultState.name states.name unity.asset("Assets/Animations/Player.controller") | get layers | get states | select name speed motion.name transitions.destinationState.name unity.asset("Assets/Animations/Player.controller") | get layers | get states | where name == "Walk" | set speed = 1.5 unity.asset("Assets/Animations/Player.controller") | get layers | get states | where name == "Idle" | get transitions | set hasExitTime = true, exitTime = 0.9, duration = 0.25 unity.asset("Assets/Animations/Player.controller") | get layers | get states | where name == "Idle" | get transitions | call AddCondition("Grounded", "If") RemoveCondition(index), ClearConditions() unity.asset("Assets/Animations/Player.controller") | get layers | get states | get transitions | select destinationState.name hasExitTime conditions unity.asset("Assets/Animations/Player.controller") | get parameters | select name type defaultFloat defaultBool unity.asset("Assets/Animations/Player.controller") | get parameters | where name == "Speed" | set defaultFloat = 0.5 unity.asset("Assets/Animations/Player.controller") | call AddLayer("Upper Body") returns the layer index unity.asset("Assets/Animations/Player.controller") | set layers[1].defaultWeight = 0.5, layers[1].blendingMode = "Additive" unity.asset("Assets/Animations/Player.controller") | call AddState("Wave", null, "Upper Body") unity.asset("Assets/Animations/Player.controller") | call RemoveTransition("Walk", "Idle") from "AnyState" / to "Exit" for those transitions unity.asset("Assets/Animations/Player.controller") | call RemoveState("Wave", "Upper Body") unity.asset("Assets/Animations/Player.controller") | call RemoveLayer("Upper Body") unity.asset("Assets/Animations/Player.controller") | call RemoveTransition("AnyState", "Idle") unity.asset("Assets/Animations/Player.controller") | call RemoveParameter("Jump") conditions using it are removed too ``` Animator components (`animation | get animators` = every Animator in the loaded scenes): ``` editor | call CreateGameObject("Player") objects | where name == "Player" | call AddComponent("Animator") animation | get animators | set runtimeAnimatorController = unity.asset("Assets/Animations/Player.controller"), applyRootMotion = false animation | get animators | select gameObject.name runtimeAnimatorController.name isHuman cullingMode ``` Parameter names and types are read-only (conditions refer to them): rename by RemoveParameter + AddParameter. New transitions have no exit time and no blend duration; set them on the transition. Only the Animator's configuration members are readable (its playback state is not meaningful in Edit Mode); in Play Mode `call SetParameter("Speed", 2)` / `call Play("Walk")` drive it. Other components' AnimationCurve fields take keyframe lists too: `set curve = [[0, 0], [1, 1]]`. ## Cinemachine Cinemachine 3: a `CinemachineCamera` (virtual camera) on its own GameObject; the `CinemachineBrain` on the Unity Camera shows the live one (highest `Priority.Value`) and blends between them. A camera's pipeline is a Body component (position: Follow, OrbitalFollow, ThirdPersonFollow, PositionComposer …), an Aim component (rotation: RotationComposer, HardLookAt, PanTilt …), an optional noise component and extensions, all on the camera's GameObject. Follow / LookAt targets take a GameObject name or ref. Writes and calls are undoable. ``` editor | call CreateGameObject("Player", null, "Capsule") (a target for the examples) cinemachine | call CreateCamera("FollowCam", "Player", null, "(0, 3, -6)", "(20, 0, 0)", 10) name, follow?, lookAt?, position?, eulerAngles?, priority? (adds a CinemachineBrain to the main Camera) cinemachine | call CreateCamera("Overview") cinemachine | get cameras | select name Priority.Value IsLive Follow.name LookAt.name body.$type aim.$type noise.$type cinemachine | get cameras | where name == "FollowCam" | call SetBody("Follow") Body by name; cinemachine | get bodyTypes lists them ("None" removes) cinemachine | get cameras | where name == "FollowCam" | call SetAim("RotationComposer") Aim by name; cinemachine | get aimTypes cinemachine | get cameras | where name == "FollowCam" | set body.FollowOffset = "(0, 2, -8)", body.TrackerSettings.PositionDamping = "(1, 1, 1)" cinemachine | get cameras | where name == "FollowCam" | set aim.Composition.ScreenPosition = "(0.1, 0)", aim.Damping = "(0.5, 0.5)" cinemachine | get cameras | where name == "FollowCam" | set Lens.FieldOfView = 50, Lens.NearClipPlane = 0.3, Lens.Dutch = 5 cinemachine | get cameras | where name == "Overview" | set Lens.ModeOverride = "Orthographic", Lens.OrthographicSize = 12 cinemachine | get cameras | where name == "FollowCam" | set Priority.Value = 20 cinemachine | get cameras | where name == "Overview" | call SetTargets("Player") follow (and look at) Player; SetTargets(follow, lookAt) for both, null clears cinemachine | get cameras | where name == "Overview" | set LookAt = null cinemachine | get cameras | where name == "FollowCam" | call SetNoise("Handheld_normal_mild", 1.5, 1) profile, amplitudeGain?, frequencyGain?; cinemachine | get noiseProfiles | select name cinemachine | get cameras | where name == "FollowCam" | set noise.AmplitudeGain = 0.5 cinemachine | get cameras | where name == "FollowCam" | call SetBody("OrbitalFollow") replace the Body cinemachine | get cameras | where name == "FollowCam" | set body.Radius = 6, body.OrbitStyle = "Sphere" objects | where name == "FollowCam" | call AddComponent("CinemachineDeoccluder") extensions are components (cinemachine | get extensionTypes) cinemachine | get cameras | select name extensions.$type cinemachine | call EnsureBrain() brain on the main Camera (EnsureBrain("Camera name") for another) cinemachine | get brains | set DefaultBlend.Style = "EaseInOut", DefaultBlend.Time = 1.5 cinemachine | get brains | select gameObject.name DefaultBlend.Style DefaultBlend.Time UpdateMethod activeCamera cinemachine | get cameras | where name == "Overview" | call SetNoise("None") cinemachine | get cameras | where name == "Overview" | call Destroy() remove the CinemachineCamera component (objects | … | call Destroy() removes the GameObject) ``` `body` / `aim` / `noise` are the pipeline components themselves, so their members are written directly (`rql-schema "CinemachineFollow"` lists them). LensSettings is a struct written in place (`set Lens.FieldOfView = …`); `Lens.ModeOverride` (None, Orthographic, Perspective, Physical) overrides the Unity Camera's projection. Blend styles: Cut, EaseInOut, EaseIn, EaseOut, HardIn, HardOut, Linear, Custom. Brains update the live camera in Play Mode; `IsLive` reports it. ## Input System An InputActionAsset (`.inputactions` file) has `maps` → `actions` → `bindings` and `controlSchemes`; `actions` also lists every action of every map. Every `set` and `call` is validated (control paths need a known device layout, interactions / processors / composites must be registered, groups must be control schemes of the asset), written to the `.inputactions` file and re-imported at once, and is undoable. Paths look like `"/space"`, `"/leftStick"`, `"/leftButton"`; groups are scheme names joined by `;` (`"Keyboard&Mouse;Gamepad"`). ``` input | call CreateAsset("Assets/Input/Player.inputactions", "Player") path, map? (first action map); missing folders are created input | get assets | select $ref name path unity.asset("Assets/Input/Player.inputactions") | call AddControlScheme("Keyboard&Mouse", ["", ""]) name, requiredDevices?, optionalDevices?, bindingGroup? (default: name) unity.asset("Assets/Input/Player.inputactions") | call AddControlScheme("Gamepad", [""]) unity.asset("Assets/Input/Player.inputactions") | call AddMap("UI") unity.asset("Assets/Input/Player.inputactions") | get maps | where name == "Player" | call AddAction("Jump") name, type? (Button, Value, PassThrough), expectedControlType?, binding? unity.asset("Assets/Input/Player.inputactions") | get maps | where name == "Player" | call AddAction("Move", "Value", "Vector2") unity.asset("Assets/Input/Player.inputactions") | get actions | where name == "Jump" | call AddBinding("/space", "Keyboard&Mouse") path, groups?, interactions?, processors? unity.asset("Assets/Input/Player.inputactions") | get actions | where name == "Jump" | call AddBinding("/buttonSouth", "Gamepad", "hold(duration=0.4)") unity.asset("Assets/Input/Player.inputactions") | get actions | where name == "Move" | call AddComposite("2DVector", {up: "/w", down: "/s", left: "/a", right: "/d"}, "Keyboard&Mouse") composite, {part: path}, groups?, interactions?, processors? unity.asset("Assets/Input/Player.inputactions") | get actions | where name == "Move" | call AddBinding("/leftStick", "Gamepad", null, "stickDeadzone") unity.asset("Assets/Input/Player.inputactions") | get maps | select name actionCount unity.asset("Assets/Input/Player.inputactions") | get actions | select map name type expectedControlType interactions bindingCount unity.asset("Assets/Input/Player.inputactions") | get actions | get bindings | select action index path name groups interactions processors isComposite isPartOfComposite unity.asset("Assets/Input/Player.inputactions") | get controlSchemes | select name bindingGroup requiredDevices optionalDevices unity.asset("Assets/Input/Player.inputactions") | get actions | get bindings | where path == "/buttonSouth" | set path = "/buttonEast", interactions = "tap" unity.asset("Assets/Input/Player.inputactions") | get actions | get bindings | where isPartOfComposite and name == "up" | set path = "/upArrow" unity.asset("Assets/Input/Player.inputactions") | get actions | where name == "Jump" | set name = "Leap", type = "PassThrough", interactions = "press" unity.asset("Assets/Input/Player.inputactions") | get actions | where name == "Move" | set processors = "invertVector2", initialStateCheck = true unity.asset("Assets/Input/Player.inputactions") | get controlSchemes | where name == "Keyboard&Mouse" | set requiredDevices = [""], optionalDevices = [""] unity.asset("Assets/Input/Player.inputactions") | get controlSchemes | where name == "Gamepad" | set name = "Controller" also renames the group of its bindings unity.asset("Assets/Input/Player.inputactions") | get maps | where name == "Player" | set name = "Gameplay" unity.asset("Assets/Input/Player.inputactions") | get actions | get bindings | where groups == "Controller" | call Remove() a composite root removes its parts unity.asset("Assets/Input/Player.inputactions") | get actions | where name == "Leap" | call Remove() unity.asset("Assets/Input/Player.inputactions") | get controlSchemes | where name == "Controller" | call Remove() unity.asset("Assets/Input/Player.inputactions") | get maps | where name == "UI" | call Remove() input | select interactions processors registered names; input | get layouts lists device and control layouts ``` Assets referenced by a scene component work the same way: `objects | get components | where $ is PlayerInput | get actions | get maps`. Bindings are addressed by id, so removing some bindings in one query does not shift the others. `call` needs rql-mutate. Created assets are not removed by Undo; undoing an edit rewrites the file. ## Navigation AI Navigation components are components: `objects | get components | where $ is NavMeshSurface` (also NavMeshModifier, NavMeshModifierVolume, NavMeshLink, NavMeshAgent). Add them with AddComponent, then set members (all undoable): ``` objects | where name == "Ground" | call AddComponent("NavMeshSurface") objects | get components | where $ is NavMeshSurface | set collectObjects = "Volume", size = "(20, 5, 20)", center = "(0, 1, 0)" objects | get components | where $ is NavMeshSurface | set agentType = "Humanoid", defaultAreaName = "Walkable", layerMask = ["Default", "Water"] objects | get components | where $ is NavMeshSurface | set overrideVoxelSize = true, voxelSize = 0.1 objects | get components | where $ is NavMeshSurface | call Bake() build now (saved scene: NavMesh-.asset next to it) objects | get components | where $ is NavMeshSurface | call Clear() remove the baked data objects | get components | where $ is NavMeshSurface | select gameObject.name agentType navMeshData buildSettings.agentRadius navigation | call BakeAll() every active surface (also ClearAll()) ``` Modifiers, volumes, links: ``` objects | where name == "Water" | call AddComponent("NavMeshModifier") objects | get components | where $ is NavMeshModifier | set overrideArea = true, areaName = "Not Walkable" objects | get components | where $ is NavMeshModifier | set ignoreFromBuild = true, applyToChildren = false, affectedAgents = ["All"] objects | where name == "Mud" | call AddComponent("NavMeshModifierVolume") objects | get components | where $ is NavMeshModifierVolume | set size = "(4, 2, 4)", center = "(0, 1, 0)", areaName = "Jump" objects | where name == "Gap" | call AddComponent("NavMeshLink") objects | get components | where $ is NavMeshLink | set startPoint = "(0, 0, -2)", endPoint = "(0, 1, 3)", width = 1, bidirectional = false, costModifier = 2, areaName = "Jump" ``` Agents (`SetDestination` / `Warp` / `ResetPath` act only on an agent on a baked NavMesh, i.e. in Play Mode; they return false otherwise): ``` objects | where name == "Enemy" | call AddComponent("NavMeshAgent") objects | get components | where $ is NavMeshAgent | set speed = 5, acceleration = 12, angularSpeed = 240, stoppingDistance = 0.5 objects | get components | where $ is NavMeshAgent | set agentType = "Humanoid", areaNames = ["Walkable", "Jump"] area mask; ["All"] = every area objects | get components | where $ is NavMeshAgent | call SetDestination("(10, 0, 5)") objects | get components | where $ is NavMeshAgent | select gameObject.name isOnNavMesh hasPath remainingDistance ``` Bake settings live on the agent type (shared by every surface baking for it; rebake afterwards); areas name the area indices: ``` navigation | get agentTypes | select agentTypeID name agentRadius agentHeight agentSlope agentClimb navigation | get agentTypes | where name == "Humanoid" | set agentRadius = 0.4, agentHeight = 1.8, agentSlope = 40, agentClimb = 0.5 navigation | get areas | where name != "" | select index name cost navigation | get areas | where index == 3 | set name = "Water", cost = 4 ``` `agentType`, `areaName` / `defaultAreaName`, `areaNames` and `affectedAgents` are the name views of agentTypeID, area / defaultArea, areaMask and the agent-type list; the numeric members stay writable. A LayerMask reads as its int mask and takes an int (-1 = Everything), a layer name or a list of layer names. ## Particle systems Particle systems are components: `objects | get components | where $ is ParticleSystem`. Module structs (`main`, `emission`, `shape` …) are written through, even though they are get-only properties: ``` objects | get components | where $ is ParticleSystem | set main.startLifetime = 3, main.loop = false objects | get components | where $ is ParticleSystem | set emission.rateOverTime = [5, 25] random between two objects | get components | where $ is ParticleSystem | set main.startColor = "#ff8800" objects | get components | where $ is ParticleSystem | set main.startColor = [["#ff0000", 0], ["#0000ff", 1]] gradient ``` `MinMaxCurve` takes a number or `[min, max]`; `MinMaxGradient` a color, `[color, color]` or gradient keys. Playback in the Editor: `objects | get components | where $ is ParticleSystem | call Play()` (also Pause, Stop, Clear, Simulate(seconds)). ## ProBuilder ProBuilder meshes are components: `probuilder | get meshes` (= `objects | get components | where $ is ProBuilderMesh`). A mesh reads as faceCount vertexCount edgeCount triangleCount, `bounds` (local) / `worldBounds`, `directions` (face indices per local direction), `materials` (slots: index material faceCount) and `faces` (read-only views: index direction center normal submeshIndex material vertices edges); the raw vertex arrays are not members. Edit with `call` (rql-mutate): faces are index lists `[0, 1]`, edges vertex index pairs `[[0, 1], [1, 2]]`. `probuilder.facing($, "Up")`, `probuilder.edges($, faces?)`, `probuilder.openEdges($)` and `probuilder.vertices($, start?, count?)` compute selections (also as call arguments). The receipt's result column holds the created mesh's $ref: `ref("ProBuilderMesh#…") | call Extrude([0], 1)`. Create and inspect: ``` probuilder | call CreateShape("Cube", "Crate", "(2, 1, 2)", "(0, 0.5, 0)") type, name?, size?, position?, rotation?, parent? probuilder | call CreateShape("Cube", "Box", null, "(3, 0.5, 0)") types: Cube Stair CurvedStair Prism Cylinder Plane Door Pipe Cone Sprite Arch Sphere Torus probuilder | call CreateShape("Cylinder", "Block", "(1, 2, 1)", "(6, 1, 0)") probuilder | call CreatePolyShape(["(0, 0)", "(4, 0)", "(4, 3)", "(0, 3)"], 0.5, "Floor", "(-6, 0, 0)") points (x, z), height, name?, position?, flipNormals?, parent? probuilder | get meshes | select $ref gameObject.name faceCount vertexCount edgeCount triangleCount bounds.size probuilder | get meshes | where gameObject.name == "Crate" | select directions materials worldBounds.center probuilder | get meshes | where gameObject.name == "Crate" | get faces | select index direction center normal vertexCount submeshIndex material.name probuilder | get meshes | where gameObject.name == "Crate" | get faces | where direction == "Up" | select index center edges probuilder | get meshes | where gameObject.name == "Crate" | select up=(probuilder.facing($, "Up")) edges=(probuilder.edges($, [0])) v=(probuilder.vertices($, 0, 4)) ``` Faces (indices shift after DeleteFaces; Extrude appends the new side faces and returns their indices): ``` editor | call CreateMaterial("Assets/Materials/Grass.mat") probuilder | get meshes | where gameObject.name == "Crate" | call SetFaceMaterial(probuilder.facing($, "Up"), "Assets/Materials/Grass.mat") faces, material (path, unity.asset(…) or ref); returns the submesh index probuilder | get meshes | where gameObject.name == "Crate" | get materials | select index material.name faceCount probuilder | get meshes | where gameObject.name == "Crate" | call Extrude(probuilder.facing($, "Up"), 0.5) faces, distance (negative = inward), method? FaceNormal | IndividualFaces | VertexNormal probuilder | get meshes | where gameObject.name == "Crate" | call Extrude(probuilder.facing($, "Forward"), 0.25, "IndividualFaces") probuilder | get meshes | where gameObject.name == "Crate" | call FlipNormals([0]) faces? (every face when omitted) probuilder | get meshes | where gameObject.name == "Box" | call DeleteFaces(probuilder.facing($, "Up")) at least one face must remain probuilder | get meshes | where gameObject.name == "Box" | select open=(probuilder.openEdges($)) probuilder | get meshes | where gameObject.name == "Box" | call Bridge(probuilder.openEdges($)[0], probuilder.openEdges($)[2]) two open edges [a, b], allowNonManifold?; returns the new face index ``` Edges, pivot, merge: ``` probuilder | get meshes | where gameObject.name == "Block" | call Bevel(probuilder.edges($, probuilder.facing($, "Down")), 0.1) edges, amount 0 … 1 (exclusive); returns the new face indices probuilder | get meshes | where gameObject.name == "Block" | call SubdivideEdges(probuilder.edges($, [0]), 1) edges, subdivisions (1 = split in half); returns the vertices added probuilder | get meshes | where gameObject.name == "Block" | call ConnectEdges(probuilder.edges($, [1])) at least 2 edges sharing faces; returns the new face indices probuilder | get meshes | where gameObject.name == "Floor" | call SetPivot("Center") "Center" (bounds) or "FirstVertex"; the geometry stays in place probuilder | get meshes | where gameObject.name == "Floor" | call SetPivotAt("(-6, 0, 0)") a world position probuilder | call Merge([meshes.first(gameObject.name == "Crate"), meshes.first(gameObject.name == "Box")]) refs to meshes or GameObjects (first = target), deleteSources? (default true) ``` Directions are in the mesh's local space (normal within 45° of the axis; the rest is Other). Invalid indices, edges that are not edges of the mesh, amounts outside the range and deleting every face fail without changing anything. Every call is undoable (the mesh is rebuilt after Undo / Redo); a created material asset stays. ## Splines A `SplineContainer` component holds splines; `splines[i]` has `closed`, `knotCount`, `length` (world units) and `knots[j]` with writable `position` (container-local), `worldPosition`, `tangentIn`, `tangentOut`, `eulerAngles`, `tangentMode` (AutoSmooth, Linear, Mirrored, Continuous, Broken) and `tension`. The `splines` source lists every container (`splines | get containers`) and creates new ones. Writes and calls are undoable. `rql-schema "SplineContainer"` lists the methods; `… | get splines | get knots | first 1 | describe` lists the knot members. ``` splines | call CreateContainer("Road") new GameObject + SplineContainer (one empty spline) splines | call CreateContainer("Loop", "(0, 0, 5)", "(0, 90, 0)", true) name, position, eulerAngles, closed splines | get containers | select gameObject.name n=(splines.count()) splines.knotCount objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | call AddKnots(["(0, 0, 0)", "(5, 0, 2)", "(10, 0, 0)"]) append several knots to spline 0 objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | call AddKnot("(15, 0, 3)") append one knot to spline 0 objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | call AddSpline() returns the new spline index objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | call AddKnot(1, "(0, 2, 0)") append to spline 1 objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | call InsertKnot(1, "(2, 0, 1)") insert at knot index 1 (InsertKnot(spline, knot, position) for others) objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | call RemoveKnot(0) RemoveKnot(spline, knot) for other splines objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | call Evaluate(0.5) point at t: position (world) localPosition tangent up objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | get splines | get knots | select index position tangentMode objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | set splines[0].knots[2].position = "(10, 1, 0)" move a knot (container-local) objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | set splines[0].knots[0].tangentMode = "Linear" objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | get splines | get knots | set tangentMode = "AutoSmooth" every knot of every spline objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | set splines[0].closed = true objects | get components | where $ is SplineContainer | where gameObject.name == "Road" | call RemoveSpline(1) ``` Knot methods take an optional leading spline index (`AddKnot(position)` = spline 0, `AddKnot(1, position)` = spline 1); new knots are AutoSmooth. Writing a tangent of an AutoSmooth / Linear knot switches it to Broken so the value sticks. Evaluate needs rql-mutate (it is a call); its result column holds the sample. Unity.Mathematics `float2` / `float3` / `float4` / `quaternion` values print and are written like vectors: `"(1, 2, 3)"`; a quaternion also accepts euler degrees `"(0, 90, 0)"`. ## Terrain Terrains are components: `objects | get components | where $ is Terrain`. Settings are members of the Terrain, the data (size, resolutions, layers, prototypes) lives in its `terrainData`. Heights are normalized 0 … 1 (fraction of `terrainData.size.y`); heightmap / alphamap cells are `x` along world X and `y` along world Z. ``` objects | get components | where $ is Terrain | select $ref gameObject.name terrainData.size terrainData.heightmapResolution terrainData.terrainLayers.name terrain | call Create("Island", "Assets/Terrain/Island.asset", 257, "(500, 120, 500)", "(0, 0, 0)") name, dataPath, heightmapResolution, size, position objects | get components | where $ is Terrain | set terrainData.size = "(800, 200, 800)" objects | get components | where $ is Terrain | set terrainData.heightmapResolution = 513, terrainData.alphamapResolution = 512 objects | get components | where $ is Terrain | set heightmapPixelError = 2, drawTreesAndFoliage = false, materialTemplate = unity.asset("Assets/Mats/Terrain.mat") ``` Heights (`call` needs rql-mutate; sampling functions work in rql-query): ``` objects | get components | where $ is Terrain | call SetHeights(0.25) flatten everything to 25 % objects | get components | where $ is Terrain | call SetHeights(0.6, 100, 100, 32, 32) height, x, y, w, h (w / h 0 = to the edge) objects | get components | where $ is Terrain | call SetHeightGrid([[0.1, 0.2], [0.3, 0.4]], 10, 20) explicit rows (row = y) starting at cell (10, 20) objects | get components | where $ is Terrain | select h=(terrain.heights($, 10, 20, 2, 2)) normalized rows, at most 20 × 20 objects | get components | where $ is Terrain | select s=(terrain.heightStats($)) {min, max, average, cells}; region: ($, x, y, w, h) objects | get components | where $ is Terrain | select y=(terrain.heightAt($, 250, 250)) world surface Y at world X / Z ``` Layers (textures), trees and details: ``` terrain | call CreateLayer("Assets/Terrain/Grass.terrainlayer", unity.asset("Assets/Textures/grass.png"), "(10, 10)") objects | get components | where $ is Terrain | call AddLayer(unity.asset("Assets/Terrain/Grass.terrainlayer")) returns the layer index objects | get components | where $ is Terrain | call PaintLayer(1, 1.0, 0, 0, 64, 64) layer, strength, x, y, w, h on the alphamap objects | get components | where $ is Terrain | call RemoveLayer(0) objects | get components | where $ is Terrain | set terrainData.terrainLayers[0].tileSize = "(20, 20)" objects | get components | where $ is Terrain | call AddTreePrototype(unity.asset("Assets/Trees/Oak.prefab")) returns the prototype index objects | get components | where $ is Terrain | call PlaceTrees(0, 200, 0.1, 0.1, 0.5, 0.5) prototype, count, minX, minZ, maxX, maxZ (normalized), heightScale?, widthScale? objects | get components | where $ is Terrain | call PlaceTreesAt(["(0.5, 0.5)", "(0.25, 0.75)"], 0) normalized (x, z) positions, prototype objects | get components | where $ is Terrain | call ClearTrees() objects | get components | where $ is Terrain | select terrainData.treeInstanceCount terrainData.treePrototypes.prefab objects | get components | where $ is Terrain | set terrainData.treePrototypes[0] = {prefab: unity.asset("Assets/Trees/Oak.prefab"), bendFactor: 0.3} prototypes are replaced whole objects | get components | where $ is Terrain | set terrainData.treeInstances[0].heightScale = 2 objects | get components | where $ is Terrain | call AddDetailPrototype(unity.asset("Assets/Textures/grass_blade.png")) texture = grass billboard, prefab = detail mesh objects | get components | where $ is Terrain | get terrainData | call SetDetailResolution(1024, 32) objects | get components | where $ is Terrain | where gameObject.name == "Center" | call SetNeighbors(ref("Terrain#…"), null, ref("Terrain#…"), null) left, top, right, bottom ``` `terrainData.treeInstances` is read only when named (`select terrainData.treeInstances[0]`). Tree / detail prototype members are read-only (TerrainData returns copies): replace the element with an object literal. Invalid resolutions, regions outside the map and out-of-range indices fail without changing anything. Heights, paint, layers and trees are undoable; created assets (TerrainData, TerrainLayer) are not removed by Undo. Neighbors are not saved with the scene (Unity reconnects terrains with `allowAutoConnect` and the same `groupingID`). ## Tilemap Tilemaps are components on children of a `Grid`: `objects | get components | where $ is Tilemap`. Cells are `"(x, y, z)"` (z = 0 for 2D); tile arguments take an asset path (`"Assets/Tiles/Grass.asset"`), a ref or `unity.asset(…)`; sprite arguments also take the texture (`unity.asset("Assets/Art/grass.png")`), its path or `"Assets/Art/sheet.png#grass_3"` (one sprite of a sheet). ``` objects | get components | where $ is Tilemap | select $ref gameObject.name tileCount usedTiles cellBounds orientation tilemap | call CreateTilemap("Ground") name, parent?, cellSize?, gridName? (new Grid + Tilemap) tilemap | call CreateTilemap("Walls", ref("GameObject#…")) parent with a Grid: another layer of that Grid tilemap | call CreateTile("Assets/Tiles/Grass.asset", "Assets/Art/grass.png", "#FFFFFF", "Grid") path, sprite?, color?, colliderType? tilemap | call CreateRuleTile("Assets/Tiles/Ground.asset", "Assets/Art/ground.png#ground_4") path, defaultSprite?, colliderType? ``` Painting (`call` needs rql-mutate; undoable): ``` objects | get components | where $ is Tilemap | where gameObject.name == "Ground" | call SetTile("(0, 0, 0)", "Assets/Tiles/Grass.asset") objects | get components | where $ is Tilemap | call SetTile("(3, 1, 0)", null) erase one cell objects | get components | where $ is Tilemap | call SetTiles(["(0, 0, 0)", "(1, 0, 0)", "(2, 0, 0)"], "Assets/Tiles/Grass.asset") objects | get components | where $ is Tilemap | call BoxFill("Assets/Tiles/Grass.asset", -5, -3, 5, 3) tile, minX, minY, maxX, maxY, z? (corners inclusive) objects | get components | where $ is Tilemap | call ClearBox(0, 0, 2, 2) returns how many tiles were removed objects | get components | where $ is Tilemap | call FloodFill("(1, 1, 0)", "Assets/Tiles/Water.asset") objects | get components | where $ is Tilemap | call ClearAllTiles() objects | get components | where $ is Tilemap | call SetColor("(0, 0, 0)", "#FF8080") tint one painted cell objects | get components | where $ is Tilemap | call SetTransform("(0, 0, 0)", 90, "(1, 1, 1)", true, false) rotation°, scale?, flipX?, flipY? objects | get components | where $ is Tilemap | call SetColliderType("(0, 0, 0)", "None") None / Sprite / Grid objects | get components | where $ is Tilemap | set orientation = "XZ", tileAnchor = "(0.5, 0.5, 0)", color = "(1, 1, 1, 0.5)" objects | get components | where $ is Tilemap | call CompressBounds() shrink cellBounds to the painted cells objects | get components | where $ is Grid | set cellSize = "(1, 0.5, 0)", cellLayout = "Isometric" objects | get components | where $ is TilemapRenderer | set sortingOrder = 2, mode = "Individual" ``` Reading cells (functions work in rql-query): ``` objects | get components | where $ is Tilemap | select t=(tilemap.tileAt($, "(0, 0, 0)")) the tile asset or null objects | get components | where $ is Tilemap | select c=(tilemap.cell($, "(0, 0, 0)")) {cell, tile, path, sprite, color, colliderType, flags, transform} objects | get components | where $ is Tilemap | select rows=(tilemap.tiles($, 0, 0, 9, 9)) tile names, top row (maxY) first, at most 20 × 20 objects | get components | where $ is Tilemap | select n=(tilemap.count($, "Grass")) occupied cells of a tile (name, path or asset); region: ($, tile, minX, minY, maxX, maxY) objects | get components | where $ is Tilemap | select cells=(tilemap.cells($, "Assets/Tiles/Grass.asset")) first 20 cells holding that tile objects | get components | where $ is Tilemap | select c=(tilemap.worldToCell($, "(2.5, 1.2, 0)")) w=(tilemap.cellToWorld($, "(2, 1, 0)")) ``` Tile assets are ordinary objects: `unity.assets("t:TileBase") | select $ref name`, `unity.asset("Assets/Tiles/Grass.asset") | set sprite = "Assets/Art/grass2.png", colliderType = "Grid"`. RuleTile rules: ``` unity.asset("Assets/Tiles/Ground.asset") | call AddRule("Assets/Art/ground.png#ground_1", "NNN/T.T/TTT") sprite, pattern, colliderType? unity.asset("Assets/Tiles/Ground.asset") | call ClearRules() objects | get components | where $ is Tilemap | call RefreshAllTiles() repaint after editing rules ``` A pattern lists the 8 neighbors in rows top to bottom (center ignored): `T` = this tile, `N` = not this tile, `.` = any; rules are checked in order and the first match wins (`"..."` = always). Methods on empty cells (SetColor, SetTransform, SetColliderType), regions over 1 048 576 cells and bad paths fail without changing anything. `cellBounds.max` is exclusive. Created assets are not removed by Undo. ## Timeline A TimelineAsset (`.playable`) holds tracks; tracks hold clips and markers; a scene `PlayableDirector` plays it and binds each track to a scene object. Times are seconds. Find timelines with `unity.assets("t:TimelineAsset")`. ``` unity.assets("t:TimelineAsset") | select $ref name duration frameRate tracks.name unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | select $ref name $type bindingType muted clips.count() markers.count() unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | recurse children | select $depth name $type groups and their sub-tracks unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | get clips | select track.name displayName start duration end asset.name timeline | call Create("Assets/Cutscenes/Intro.playable", 30) path, frameRate?, fixedDuration? (> 0 = FixedLength) unity.asset("Assets/Cutscenes/Intro.playable") | set frameRate = 24, durationMode = "FixedLength", fixedDuration = 12 ``` Tracks (type: Animation, Activation, Audio, Signal, Control, Playable, Group or a TrackAsset type name): ``` unity.asset("Assets/Cutscenes/Intro.playable") | call AddTrack("Animation", "Hero") type, name?, group? — returns the track unity.asset("Assets/Cutscenes/Intro.playable") | call AddTrack("Group", "Crowd") unity.asset("Assets/Cutscenes/Intro.playable") | call AddTrack("Activation", "Door", "Crowd") nested in the GroupTrack named Crowd unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | where name == "Hero" | set muted = true, locked = false, name = "Hero Anim" unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | where name == "Door" | call Delete() with its clips, markers and sub-tracks ``` Clips (AnimationTrack: an AnimationClip, AudioTrack: an AudioClip, other tracks: a default clip with asset null): ``` unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | where name == "Hero" | call AddClip(unity.asset("Assets/Anim/Walk.anim"), 2, 3, "Walk") asset?, start?, duration?, name? unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | where name == "Door" | call AddClip(null, 0, 1.5) unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | get clips | where displayName == "Walk" | set start = start + 0.5 move (duration kept) unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | get clips | where displayName == "Walk" | set duration = 4, clipIn = 0.25, timeScale = 1.5, easeInDuration = 0.5, easeOutDuration = 0.3 unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | get clips | where displayName == "Walk" | set asset.removeStartOffset = false the clip's PlayableAsset unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | get clips | where end > 10 | call Delete() ``` Markers and signals: ``` timeline | call CreateSignal("Assets/Cutscenes/Boom.signal") unity.asset("Assets/Cutscenes/Intro.playable") | call AddMarker(3.5) SignalEmitter on the timeline marker track unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | where $type == "SignalTrack" | call AddMarker(1, "Signal") unity.asset("Assets/Cutscenes/Intro.playable") | get markers | set asset = unity.asset("Assets/Cutscenes/Boom.signal"), time = 4 unity.asset("Assets/Cutscenes/Intro.playable") | get tracks | get markers | where time > 8 | call Delete() ``` Director and bindings (a GameObject is narrowed to the component the track drives, e.g. its Animator): ``` objects | where name == "Cutscene" | call AddComponent("PlayableDirector") objects | get components | where $ is PlayableDirector | where gameObject.name == "Cutscene" | set playableAsset = unity.asset("Assets/Cutscenes/Intro.playable"), playOnAwake = false objects | get components | where $ is PlayableDirector | select gameObject.name playableAsset.name bindings objects | get components | where $ is PlayableDirector | set bindings["Hero"] = ref("GameObject#…"), bindings["Door"] = null ``` Crossfades (blendInDuration / blendOutDuration, read-only) come from overlapping clips: move a clip's start into its neighbour. Invalid values (negative times, eases longer than the clip, a time scale on clips that cannot change speed, a clip asset that does not fit the track, unknown track names) fail without changing anything; Timeline does not clamp them silently here. Creating, deleting and editing tracks, clips, markers and bindings is undoable; created asset files stay. rql-mutate saves the edited .playable. Clips have no $ref: address them through their timeline (`… | get tracks | get clips | where …`). ## Installed RQL modules - `com.IvanMurzak.Unity.MCP.Editor.Rql.Modules.UnityCoreModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.ToolTypesModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.Mathematics.MathematicsModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.Animation.AnimationModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.Cinemachine.CinemachineModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.InputSystem.InputSystemModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.Navigation.NavigationModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.Particles.ParticleSystemModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.Physics3D.PhysicsModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.ProBuilder.ProBuilderModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.Splines.SplinesModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.Terrains.TerrainModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.Tilemaps.TilemapModule` - `com.IvanMurzak.Unity.MCP.Editor.Rql.Timelines.TimelineModule`