Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Engine/apps/agent-backend/src/editor_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub fn tools() -> Vec<Value> {
),
(
"scene_create",
"Create an empty persisted scene; does not switch or overwrite. Path is relative to the scenes folder.",
"Create an empty persisted scene for an independent screen/map or lifetime boundary; read authoring_guide for menu/loading/map decisions. Inspect scene_list first. Does not switch or overwrite. Path is relative to the scenes folder, e.g. maps/map1.scene.",
json!({"type":"object","required":["path","name"],"properties":{"path":{"type":"string"},"name":{"type":"string"}}}),
),
(
Expand All @@ -42,7 +42,7 @@ pub fn tools() -> Vec<Value> {
),
(
"object_create",
"Create an authored folder, empty object, camera or light, optionally inside parent (null means scene root). Folders organize the scene explorer. For finished meshes use model_create; primitives are for deliberate blockouts/colliders.",
"Create an authored folder, empty object, camera or light, optionally inside parent (null means scene root). Use folders and nested subfolders to organize growing scenes by purpose/area; parent is the immediate live UUID, not a path. Folders do not create separate scenes or transform children. For finished meshes use model_create; primitives are for deliberate blockouts/colliders.",
json!({"type":"object","required":["name"],"properties":{"name":{"type":"string"},"kind":{"type":"string","enum":["empty","folder","camera","light","blockout"]},"parent":{"type":["string","null"],"description":"Existing destination object/folder UUID, or null for scene root; defaults to root."}}}),
),
(
Expand Down
4 changes: 2 additions & 2 deletions Engine/apps/agent-backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ fn handle(session: &mut WorkspaceSession, request: &Value) -> Option<Value> {
"protocolVersion": "2025-06-18",
"capabilities": {"tools": {"listChanged": false}},
"serverInfo": {"name": "rustic-workspace", "version": env!("CARGO_PKG_VERSION")},
"instructions": "Call workspace_info first. If no game is selected, supply its absolute directory in project_root. Read project instructions with read_agent_file and read the bundled authoring_guide before editing game content. Prefer custom models and persist complete scenes before playtesting. Read scene_explorer_guide for hierarchy organization and folder/object creation, duplication and deletion. Use editor tools for properties, scenes, script scopes, model previews and playtest input."
"instructions": "Call workspace_info first. If no game is selected, supply its absolute directory in project_root. Read project instructions with read_agent_file and read the bundled authoring_guide before editing game content. Prefer custom models and persist complete scenes before playtesting. Organize growing scenes with meaningful folders and nested subfolders. Read scene_explorer_guide for safe hierarchy edits and authoring_guide to choose separate menu, loading and map scenes and verify transitions. Use editor tools for properties, scenes, script scopes, model previews and playtest input."
}),
"tools/list" => json!({"tools": tools()}),
"tools/call" => {
Expand Down Expand Up @@ -156,7 +156,7 @@ fn tools() -> Value {
tools.as_array_mut().expect("tools array").push(json!({"name":"authoring_guide","description":"Read the bundled, current Rustic game design, modeling, scene, scope and playtest guidance. Works with existing customized integrations.","inputSchema":{"type":"object","properties":{}}}));
tools.as_array_mut().expect("tools array").push(json!({"name":"texture_guide","description":"Read current HDR/PBR map, Texture child and sky guidance, including slot names, channel conventions, examples and renderer limits. Available even when installed skills were customized.","inputSchema":{"type":"object","properties":{},"additionalProperties":false}}));

tools.as_array_mut().expect("tools array").push(json!({"name":"scene_explorer_guide","description":"Read the current rustic-scene-explorer skill: organize hierarchy folders, add objects, duplicate/delete subtrees, reparent safely, undo and save. Available with preserved custom instructions.","inputSchema":{"type":"object","properties":{}}}));
tools.as_array_mut().expect("tools array").push(json!({"name":"scene_explorer_guide","description":"Read the current rustic-scene-explorer skill: organize folders and nested subfolders while authoring; distinguish folders from separate scenes; add objects, duplicate/delete subtrees, reparent safely, undo and save. Available with preserved custom instructions.","inputSchema":{"type":"object","properties":{}}}));
tools
.as_array_mut()
.expect("tools array")
Expand Down
50 changes: 49 additions & 1 deletion Engine/crates/engine-scripting/src/agent_authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,57 @@ Use `scene_list` to discover active/start scenes and nested paths. Scene-managem

Call `texture_guide` and use the `rustic-textures` skill before assigning surface maps. `texture_inspect` reads direct and resolved maps; `texture_update` patches named slots and UV/intensity controls; `texture_create_child` attaches a Texture child as one undoable edit. Existing project-relative images are decoded before assignment. All 17 slots are optional. Do not invent a runtime material scripting API or treat a sky panorama as a complete PBR material. Inspect `viewport_capture`, save with `scene_save`, and verify the material in Play.

## Decide when to create a new scene

Use this workflow whenever a request adds a screen, level, map, mode or major world area. Inspect `scene_list`, `editor_status`, project instructions and existing transition scripts before deciding. Reuse a suitable existing scene instead of creating duplicates. State a brief decision and the intended entry/exit flow; do not expose private chain-of-thought or turn routine scene choices into approval requests. Follow the user's requested scope and existing project conventions.

A scene is a separately saved world with its own authored objects and scene/object script lifetime. A hierarchy folder groups objects inside one world. Choose a new scene when content needs an independent entry point, camera/UI composition, rules, reset boundary or load/unload lifetime. Choose folders when content belongs to the same active world and should remain available together. A large object count alone is not a reason to split a scene.

| Content | Default decision | Reason and exceptions |
| --- | --- | --- |
| Main menu/title screen | Separate scene when the game needs a front end | Own menu camera/UI and navigation; avoid running level actors behind a menu unless intentionally designed that way. |
| Map1 and Map2, campaign stages or distinct arenas | Separate scene per independently entered map | Allows each map to own its geometry, spawns, rules and reset flow. Connected areas that must remain visible and interactive together may belong in one scene. |
| Loading screen | Separate scene when a transition needs a dedicated visible screen | Give it a defined destination, failure behavior and transition owner. A lightweight loading overlay may remain in the current scene. A separate scene does not itself provide asynchronous loading or progress reporting. |
| Pause, inventory, settings or a confirmation dialog | Usually UI within the current scene | These commonly preserve live gameplay state. Use a separate scene only when a deliberate full-screen flow and its state restoration justify it. |
| Win/loss/results screen | UI in the map or a separate results scene | Use an overlay for a quick retry; a separate scene suits a distinct post-match flow that receives session results. |
| Buildings, rooms, vegetation, enemies and triggers in one map | Nested hierarchy folders | Organize by area and responsibility without inventing scene transitions. |

Do not create every example scene for every task. A single-map prototype can have one organized playable scene. A request for a menu and two maps normally calls for MainMenu, Map1 and Map2, with Loading only if useful or requested. Do not create empty placeholder scenes and report a complete game flow.

### Plan paths, ownership and transitions

Before authoring a multi-scene flow, record a compact scene inventory in the task notes or an existing project design document: saved path, unique document name, purpose, entry trigger, destination/exit trigger and state that must survive. For example:

```text
menus/main_menu.scene MainMenu -> Play chooses Map1
loading/loading.scene Loading -> selected destination, if a loading screen is needed
maps/map1.scene Map1 -> completion chooses Map2; exit returns to MainMenu
maps/map2.scene Map2 -> results/retry or MainMenu
```

These are `scene_create` paths relative to the configured scenes directory. Runtime file paths are relative to the project root: with a scenes directory of `scene`, Map1's runtime path is `scene/maps/map1.scene`. Query the project configuration; do not assume `scene` or prepend the scenes directory twice. Disk subdirectories organize saved scene files; they do not create Hierarchy folders. Use unique document names, meaningful filenames and the project's existing casing/extension convention.

Keep progression, settings, selected map and transition destination in an appropriate global/session service when they must survive a switch. Keep map rules in scene scope and actor behavior in object scope. Do not preserve stale entity UUIDs or scene-owned object references across unload; reacquire destination objects after activation. Avoid attaching the same transition controller globally and to each scene, which can trigger duplicate transitions.

Use Rustic's documented runtime behavior: `game.scene.load` explicitly retains a scene but does not activate it; `switchTo` selects it and can load a saved destination automatically. Automatically loaded scenes unload when switched away from; explicitly loaded scenes and the initial Play scene remain loaded until explicitly unloaded. Inactive retained scenes do not tick or render. Do not promise simultaneous gameplay/rendering of several loaded worlds or assume a persistent UI scene renders over a map. Choose intentional retention or reset behavior and release scenes that no longer need their state. Unloading the active scene clears selection, so arrange a valid destination rather than leaving a blank view. Switching to the same scene preserves its state; it is not a restart API. Consult the scene-lifecycle guide for the supported unload/reload sequence when a fresh restart is required.

A loading screen must have time to become visible before requesting expensive destination work. Activation happens at runtime boundaries; switching twice in one callback is not evidence that the intermediate screen rendered. Verify an actual frame of Loading and then the destination. Do not invent an asynchronous loader, percentage API, background streaming or progress values. If the current loading API blocks, report that limitation and use truthful loading feedback; do not claim smooth animation or measured progress without evidence. Keep a recoverable menu/retry route for failed destinations instead of an endless spinner.

### Create, author and verify each scene

1. List existing scenes; reuse matching content. Stop Play and resolve pending runtime-change review. Check the active scene and unsaved state before any switch, since `scene_switch` saves current edits.
2. Create only missing scenes using `scene_create`, for example `{"path":"maps/map1.scene","name":"Map1"}`. It persists an empty scene, refuses overwrite and leaves the active scene unchanged. Inspect failures rather than retrying with random filenames.
3. Open the intended destination using `scene_switch` with its returned/listed path, then refresh `editor_status`. All following object tools target that active scene. Never parent an object to a UUID from another scene or mistake creation for switching.
4. Author meaningful folders and subfolders, camera, lighting, models, collision, UI and correctly scoped scripts. Build the actual screen/map, including usable entry/exit interactions. Save with `scene_save` before moving on.
5. Use `scene_set_start` only when the requested flow needs a different launch scene, commonly MainMenu. Verify active and start paths independently with `scene_list`; the active editor scene is not necessarily the game's launch scene.
6. Test each scene directly and then start from the intended launch scene. Starting Play uses the open editor scene, so open the launch scene to test the complete path. Exercise menu -> optional loading -> Map1 -> Map2, return to menu, failure/retry and a second traversal as applicable. Confirm fresh versus preserved state matches the design.
7. Inspect `viewport_capture`, console messages, active/loaded scene state through documented APIs, and script attachments. Check that the correct camera/UI appears, controls work, scene-owned callbacks end when unloaded, and transitions do not loop or duplicate. Stop Play before fixes and resolve runtime-change review.

Report the scenes created/reused, their paths and launch scene, the hierarchy organization, the transitions actually tested, and any remaining limitations. A successful tool response establishes only that operation; a saved scene alone does not establish a working player flow.

## Organize the scene explorer

Read the bundled `rustic-scene-explorer` skill through `scene_explorer_guide` for hierarchy layout, folder creation, duplication and deletion. Start from `editor_status`, which reports each object's UUID, `folder` flag and `parent`. Use a small, meaningful hierarchy (for example World/Buildings, Gameplay, Lighting and UI) that matches the game; use folders for organization and ordinary empty root objects for group movement. Folder transforms do not affect their descendants. Create real explorer folders with `object_create`, `kind:"folder"`, and optional `parent`; filesystem directories do not create scene folders. Rename/reparent through `object_update`. Reparenting keeps local transforms and can change world placement when non-folder ancestors change, so inspect the ancestor chain before regrouping.
Read the bundled `rustic-scene-explorer` skill through `scene_explorer_guide` for hierarchy layout, folder creation, duplication and deletion. Start from `editor_status`, which reports each object's UUID, `folder` flag and `parent`. Actively organize authored content into meaningful folders and nested subfolders as it grows (for example World/Town/Buildings, World/Forest/Vegetation, Gameplay/Actors, Gameplay/Triggers and UI/HUD). Reuse suitable existing groups and avoid a flat root full of unrelated objects. Keep a tiny scene simple and create only groups that hold or will immediately receive relevant content; use folders for organization and ordinary empty root objects for group movement. Folder transforms do not affect their descendants. Create real explorer folders with `object_create`, `kind:"folder"`, and optional `parent`; filesystem directories do not create scene folders. Rename/reparent through `object_update`. Reparenting keeps local transforms and can change world placement when non-folder ancestors change, so inspect the ancestor chain before regrouping.

Use `object_duplicate` to copy an object/folder and its whole subtree with fresh IDs, retaining folder flags, local transforms, assets and script attachments. The default destination is the original parent; supply `parent:null` for scene root or another parent UUID, and optional `name` for the copied root. Use the returned new IDs when editing the copy. Use `object_delete` to remove an object/folder and ALL descendants after inspecting the subtree; move children out first if they must survive. Assets and script sources remain on disk. Creation, duplication, deletion and reparenting use scene undo/redo; verify the hierarchy/viewport and persist with `scene_save`. These tools work directly through the plugin without computer use. Stop play and resolve any runtime-change review before editing.

Expand Down
Loading
Loading