Skip to main content

author-tutorial

Author an interactive tutorial, guided lesson, onboarding flow, coach-mark tour, or objectives checklist in LunCoSim. Use for work under `assets/tutorials/` and for requests involving `mission`, `objective`, `coach_step`, `hint`, or `spotlight`.

Informations de source

Dépôt
LunCoSim/lunco-sim
Dernière activité de la source
29 octobre 2026 à 21:32
Langue détectée de SKILL.md
anglais
Étoiles
106
Forks
21

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
author-tutorial
description
Author an interactive tutorial, guided lesson, onboarding flow, coach-mark tour, or objectives checklist in LunCoSim. Use for work under `assets/tutorials/` and for requests involving `mission`, `objective`, `coach_step`, `hint`, or `spotlight`.
# Author an authored lesson A lesson is a file-backed Rhai scenario with optional standard USD scene content. The application Rhai policy reads generic JSON asset snapshots, selects the tutorial catalog, and builds the workbench menu. The shared Rust asset and UI layers know only text assets, JSON values, and generic menu trees. The lesson does not need a Rust type, registry, lifecycle owner, or custom USD schema. Read [`author-scenario`](../author-scenario/SKILL.md) first, then use [`assets/tutorials/README.md`](../../assets/tutorials/README.md) and the examples under `assets/tutorials/`. ## Add a lesson 1. Add `assets/tutorials/<track>/<name>.rhai`. 2. If it needs a world, reuse or add an authored scene under `assets/`. 3. Add an entry to `assets/tutorials/catalog.json`: ```json { "track": "Sandbox", "title": "First Drive", "blurb": "Take control of a rover and drive it to a lunar flag.", "difficulty": "beginner", "lesson_type": "exercise", "duration_minutes": 5, "source_asset": "lunco://tutorials/sandbox/first_drive.rhai", "scene_asset": "lunco://tutorials/sandbox/first_drive.usda" } ``` The `track` value determines the submenu containing the lesson. Reuse an existing track when the lesson belongs to that learning path. The Rhai policy at `assets/scripting/policy/application_asset_lifecycle.rhai` discovers the unique marked catalog from generic asset-scope events and uses the shared `parse_json` function; do not add tutorial-specific Rust loading or menu code. The reserved experiment-results namespace is classified by the asset owner and excluded by the menu policy before parsing. Keep catalogs in authored source directories. The `application_json_catalogs` production gate covers catalog selection, result exclusion, similar directory names and malformed authored entries. For classroom onboarding, use the maintained [Lunar Rover Lab curriculum](../../docs/tutorials/06-classroom-onboarding.md). `lesson_type` distinguishes a guidance tour from an assessed exercise or an independent challenge; `duration_minutes` is an estimate, not a measured result. Both fields are optional for catalogs that do not publish that metadata. An optional `next_source_asset` links to another entry in the same catalog. The policy validates targets and cycles and passes a typed `lesson_path` to the scenario; do not duplicate a curriculum registry in Rust or a second tool. A project-authoring lesson may name `twin_asset` with an exact registered `twin.toml` URI. Its manifest selects the scene and the scene embeds its guide. The launcher submits `OpenTwinAsset`; the asset adapter resolves it off-thread and Workspace owns admission. Do not also specify `scene_asset` for that entry. Resolve a live prim's owning document once with `assembly_edit::document_for_entity`, and retain that explicit id across panel changes. A detached library demonstration stage has no editable document owner. The menu submits the generic `RunScenarioAsset` command. It uses `ScenarioReloadPolicy::Restart` for a predictable fresh start and lets the command resolve an omitted host target to the active `WorldRoot`. Other apps can reuse the command without importing tutorial code. ## Rhai contract Use the shared prelude: - `hint(...)`, `spotlight(anchor, caption)`, and `notify_kind(...)` for presentation; - `coach_step(steps, index)` with `tutorials::tour_event` for a guided tour; - `mission(me, ctx)` and `objective(...)` for an objective-driven exercise; - `input_binding(...)`/`input_hint(...)` for the controller-owned semantic labels. LunCoSim defaults complete HUD cards to View. A lesson that guides work across perspectives declares `hud_perspectives([])` in its initialization; a lesson limited to particular layouts declares their registered ids instead. The declaration applies only to that script's card, including objectives and input. Use ordinary `hint(...)` and mission helpers afterward. Spotlights and coach steps use their existing layout anchors. Do not inspect lesson names or special case tutorial assets in Rust to choose visibility. Use `panel.center` for the viewport or central work area, a generic `panel.side_browser`, `panel.right_inspector`, or `panel.bottom` anchor for a whole dock, and `panel.<id>` for a specific panel. Choose an anchor published by the active layout; `coach_step` focuses a named panel before drawing its spotlight. Progression must observe semantic commands or authoritative state. Never gate a lesson on a physical key name or a timer. A lesson must not open a USD layer directly; if it needs a world, the catalog's `scene_asset` is the request. Never branch on the Rust build profile (`is_debug()` or `debug_assertions`). The authored `lint.rhai` policy rejects that coupling; use `is_unattended()` when attended and automated execution need different behavior. Tours may advance on Next because they review guidance. Their completion must not claim that unobserved editing or engineering actions occurred. Use the shared cursor and navigation policy: ```rhai fn on_event(me, evt, ctx) { if tutorials::navigation(evt, ctx) { return; } this = tutorials::tour_event(this, evt, steps(), ctx); } ``` Initialize `this.i = 0` and show the opening coach in `on_start`. The helper makes Skip terminal and emits `TUTORIAL_SKIPPED`, without emitting `MISSION_COMPLETE`. An exercise instead calls `tutorials::finish(ctx, message)` after its own verified result, and handles `tutorials::navigation` in its event hook. A standalone launch without catalog context has no next-lesson action; its copy should direct the learner to Tutorials rather than promise a dialog. `tutorials::start_path` relaunches a guide with its exact calling Twin owner; Restart uses this same path and preserves scene edits. Do not use `RestartScene` as a guide restart: a scene-free tour has no scene to reload. An explicit document-reset action must still state that it discards edits. For a saved report, resolve the current application lesson with `tutorials::application_path(source_asset)` in the interactive presentation path. It reads enabled typed actions from `InspectScriptedMenus`, whose reader and renderer share the installed immutable trees. Use the returned titles and path for continuation instead of duplicating catalog destinations. Unknown or ambiguous lessons reject visibly. Keep headless report assessment independent of windowed menu presentation. The focused acceptance is `scripts/api/test_tutorial_navigation.py`. Use existing guided action buttons for direct control/help and the generic `RecoverVessel` command for explicit righting. Never treat command admission, a zero trace, a file picker, or a save request as a successful result. For a saved project, verify the owning document's saved state and Twin admission. `QueryUsdPrim` includes disposable live-stage state. For persistent authoring assessments, inspect document-layer ownership too and verify save/reopen; an ECS move alone must not count as a saved edit. Store measurements as typed authored values with their assumptions; do not silently substitute zero when a measurement is unavailable. For physical waypoint arrival, author an Avian sensor in USD and map its generic `SENSOR_ENTER` event to a lesson event in Rhai. Match `evt.source` to the exact sensor with `sensor_entered(evt, sensor_id)`, then validate that `evt.value` identifies the intended subject or one of its colliders before emitting the lesson event. Use `SensorOccupants` in `on_start` to handle an existing contact. Objectives and task waits consume the lesson event; distance thresholds do not define arrival. Do not add a tutorial-specific `TriggerZone` label to a shared sensor asset. Example objective: ```rhai fn mission(me, ctx) { [ objective("take_control", #{ text: "Take control of the training rover", done: |m| { let role = controller(find_path("/Training/Rover")); role != () && role != "AiAgent" }, }), objective("reach_flag", #{ text: "Drive to the glowing flag", requires: ["take_control"], requires_event: "flag_reached", }), ] } ``` ## USD scene contract Scene ownership stays in the USD scene command layer. `RunScenarioAsset` submits a `SceneTransitionIntent`; the USD owner resolves and composes it, and the generic scenario driver waits for the completion/readiness edge. Use standard USD composition and schemas: `subLayers`, `references`, `payloads`, `UsdPhysics`, and `UsdLux`. For a repeatable celestial lesson, author a non-zero epoch on the scene root with the celestial payload. Otherwise the startup-installed scene-time policy selects current computer UTC converted to TDB after the scene and its queued projections settle. Time-dependent consumers wait for that result. Missing time with celestial sources is reported by runtime warning and lint. For a basic or UI lesson, author a fixed `DistantLight` or omit the world. Do not add tutorial-specific API schemas. ## Test without a Rust rebuild Put behavior assertions in `assets/scenarios/tests/<name>.rhai` and use the production scene-test binary. Keep Rust tests limited to generic scripting, asset, USD, and lifecycle seams. For a navigation-only lesson, omit the world payload and use `// @timing presentation`. Launch it with the exact `owner_twin_id`; Twin ownership does not require scene ownership. Check `InspectGuidedHud.tour` for the owner, step and anchor, advance Next/Back while no scene is admitted, then replace the Twin and verify the tour cannot return. The production acceptance is `python3 scripts/api/test_workbench_perspectives.py --scene-free --port PORT`; it launches its own windowed session and requires the authored verdict. ```bash "$LUNCOSIM_BIN" test \ --scene scenes/tests/tutorial_first_drive.usda --max-ticks 6000 ``` `--validate` proves preflight only. Inspect the authored verdict and process exit code for runtime evidence. Rhai, catalog, and authored USD edits should be replayed through the already-built production binary whenever possible.
Voir sur GitHub