Agent skill

Usd Projection

by LunCoSim in LunCoSim/lunco-sim

Extend or diagnose LunCoSim's USD-to-ECS projection: add a supported prim or attribute, trace an ignored field, or fix edits that fail to persist, undo, replicate, or render.

Apache-2.0Auto-check passed

Install Usd Projection

skills CLI
$ npx skills add LunCoSim/lunco-sim --skill usd-projection -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install LunCoSim/lunco-sim usd-projection --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/usd-projection .claude/skills/usd-projection && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
usd-projection
GitHub stars
107
Token cost
~8.8k tokens
SKILL.md length
4,557 words
Files
1
Skills in repo
40
Repo updated
First seen
Licence
Apache-2.0

At a glance

Extend or diagnose LunCoSim's USD-to-ECS projection: add a supported prim or attribute, trace an ignored field, or fix edits that fail to persist, undo, replicate, or render.

  • Works in 6 steps: Read it. Extractors use the UsdRead trait → Dispatch it. Prim types are a match on… → Project it. Insert components. Keep… → …
  • Lunco-usd machinery and document-owned ECS state
  • SKILL.md covers The pipeline, end to end, Law 1 — every edit goes…, Law 2 — ask the scene root,… and Law 3 — spell it the way USD…, plus 3 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Usd Projection is an agent skill from LunCoSim/lunco-sim. Extend or diagnose LunCoSim's USD-to-ECS projection: add a supported prim or attribute, trace an ignored field, or fix edits that fail to persist, undo, replicate, or render. Use for lunco-usd machinery and document-owned ECS state. Prefer this skill for projection internals; use edit-usd-assembly for live headful assembly authoring, build-usd-scene for scene authoring, and luncosim-architecture for cross-domain ownership.

Its SKILL.md is about 8.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

The repository describes itself as: Collaborative Multiphysics Cosimulator For Space Missions 🌎🚀🌚. The licence is Apache-2.0.

When your agent uses it

  • Lunco-usd machinery and document-owned ECS state

Example prompts

  • “/usd-projection”

Workflow steps

6 steps, taken from the first numbered list in SKILL.md.

  1. Read it. Extractors use the UsdRead trait
  2. Dispatch it. Prim types are a match on reader.type_name(&path) inside
  3. Project it. Insert components. Keep render-bound types out of
  4. Re-project it on edit. This is the step people forget. A structural
  5. Author it. Add a command that lowers to UsdOps (Law 1) and register it
  6. Test it. Because extractors use the shared composed-reader contract,

What it can do on your machine

Read from SKILL.md and the folder at commit 43f1301. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are rust).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Usd Projection loads about 8.8k tokens when it runs. Until then it costs about 111 tokens; SKILL.md has 4,557 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~111
When it runs · the whole SKILL.md, loaded when a task matches
~8.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from LunCoSim/lunco-sim at commit 43f1301, republished under its Apache-2.0 licence (© LunCoSim). 4,557 words, ~8,793 tokens.

Download SKILL.mdSave it as .claude/skills/usd-projection/SKILL.md (or your agent's skills folder).
name
usd-projection
description
Extend or diagnose LunCoSim's USD-to-ECS projection: add a supported prim or attribute, trace an ignored field, or fix edits that fail to persist, undo, replicate, or render. Use for `lunco-usd*` machinery and document-owned ECS state. Prefer this skill for projection internals; use edit-usd-assembly for live headful assembly authoring, build-usd-scene for scene authoring, and luncosim-architecture for cross-domain ownership.

USD → ECS projection

Before adding a field or reader branch, use luncosim-architecture and the standard-schema boundary. Prefer the OpenUSD schema that owns the concept. A migration is a clean cutover: update the authored source and all readers, delete the superseded spelling and compatibility branch, regenerate schema artifacts, and add a negative test. Never make the ECS projection a second source of truth.

USD is the source of truth. The ECS is a projection of it. Every entity you see is a rendering of a prim. Nothing is authoritative because it is in the world; it is in the world because it is in the document.

That single sentence generates every rule below.

The pipeline, end to end

UsdOp  ──►  UsdDocumentRegistry::apply   (journals + inverts)
              │
              ▼
          openusd Stage (the live CanonicalStage, NonSend)
              │  StageSink fires → RawStageChange { resynced, info_only }
              ▼
          project_stage_changes            (lunco-usd-commands/src/live_consume.rs)
              ├── resynced   → structural: spawn / despawn prims
              └── info_only  → attribute-only: translate, rotate, domes …
              │
              ▼
          UsdVisualProjectionQueued  (bounded ECS binding queue)
              │
              ▼
          UsdVisualPlugin (lunco-usd-bevy/src/lib.rs)
              └── match reader.type_name(path) → visual components
                         │
                         ▼
          UsdAnimationPlugin (lunco-usd-bevy-animation)
              └── sample authored timeSamples into visual intent

The asset loader composes the fetched layer closure and snapshots the complete default-time UsdRead surface into UsdStageProjectionPlan on its worker. The Add, UsdPrimPath observer and sync_usd_visuals both feed the same UsdVisualProjectionQueued marker. process_queued_usd_visuals drains that queue with its configured per-frame budget, but the extractor reads only the owned plan during initial materialisation; it does not parse USD, walk a live stage, or resolve composed bindings on the UI thread. CPU mesh-data geometry uses the render-free lunco-usd-geometry package, while its existing async compute path and only Bevy asset insertion remain on the main thread. After the initial asset generation, explicit live edits use the canonical StageView and the same extractor contract.

The scene transaction closes from asset and structural-projection outcomes. UsdSceneProjectionFailed on the running mount must fail and clear that transaction before a generation can commit; preview errors are separately owned. Missing default roots and nonexistent or non-prim explicit targets are visible projection failures. Verify the failure edge as well as queue drainage.

Incremental structural reconciliation resolves a live path through the UsdPrimPath lifecycle index keyed by stage asset and prim path. Insert and removal observers maintain it, including component replacement and preview duplicates; do not add a per-frame Added query or scan the full scene for each changed path. The canonical stage records a weak identity for each merged Arc<StageRecipe> so subsequent instances of that loaded revision skip cloning and comparing its full layer closure. A reloaded recipe has a new identity and must merge its current bytes before authoring the reference. Live instance handles own asset lifetime; the index and weak recipe cache are derived state. Transform edits update every indexed entity sharing that stage/path, including preview copies. Scale is applied only beneath UsdPreviewOnly; a live body's scale remains unchanged. Structural reconciliation still excludes previews. For a document-backed runtime reference spawn, the authored document keeps the reference arc. The live canonical stage receives only the instance root while an instance-scoped view over the shared immutable prepared snapshot projects the source asset's defaultPrim subtree. The view maps paths into the instance namespace and stores root pose and lunco:catalogId overrides; creating the view is constant time with respect to the source prim count. The first other authored edit composes the reference once, then shared promotion state switches every entity clone to the canonical reader. Root deletion can remove an unpromoted instance without composing its source. Keep simple QueryUsdPrim reads on the same plan; explicit geometry/topology queries use the owning document's composed stage. A failed promotion faults the mounted scene and rejects that live edit.

The stage ID committed by the document projection owner identifies the live stage; use stage_asset_for_document rather than an asset-server filename lookup. Source-text and stage assets may share a path but have different types. Changes to a document's root scene are projected by its canonical stage. Only different recipe roots that compose the changed layer are dependent refresh targets; the root scene never refreshes itself as a dependent stage.

For a bounded typed edit, the dependent owner composes the current persistent document layers directly to Sdf Data on a worker, then patches only the affected prim specs and fields in the existing canonical stage with one Stage::batch_edit. The normal sink projects those paths into ECS before an active-stage progress hold is released. Afterward, a background worker serializes the changed source and composes the immutable asset plan for a later mount. That plan refresh does not hold simulation progress or reset the live scene. Coarse composition edits and updates that span multiple changed source layers use the full-stage reset owner.

Native asset inputs follow the shared preparation gate: preserve the reader's current prepared table, retain edits/hints across superseded jobs, and release UsdNativeAssetPreparation only after that exact stage revision reaches live consumption or teardown. A queued visual or installed policy must remain deferred while native preparation holds its generation.

Doc-backed Twin admission is also asset-event driven. UsdSourceText is loaded through the shared typed load_asset_path address and registered source scheme; scene, preview, schema, reference and transitive layer readers preserve literal filename characters and attach Bevy labels separately. AssetEvent and AssetLoadFailedEvent advance or fail the pending document transaction. The default Twin path parses the exact source revision through native AsyncWorkAdmission, commits it through DocumentRegistry::open_prepared_file, restores the runtime overlay, and serializes a cloned persistent document on the worker pool. Source text and document generation are checked again before the Twin overlay is published and LoadScene is submitted. Runtime sidecar read/parse and editor-preview initial serialization remain synchronous; wasm worker transport for this path is not installed, so the owner reports that boundary visibly. The live USD stage stays with its thread-affine owner. Referenced stage closures follow the same event boundary before a reference is authored onto the live stage. Each instance retains the real source handle and one shared UsdReferenceSnapshot containing the canonical recipe, unscoped plan and actual loaded source revision. The canonical stage caches only weak snapshot identities: warm sibling reuse must validate the exact scene origin, current source recipe/plan and live mount before skipping address I/O and composition. Native file-URI references prepare confined typed addresses and StageRecipe::reanchor composition on the shared bounded reference lane, used by incremental spawns and coarse rebuilds. Preserve authored layer bytes and absolute identifiers; never inject transport aliases into the resolver. Publication rechecks exact stage lifetime/generation, source, operation, live mount and loaded source revision; worker panics become terminal completion errors. Current reference and document-projection holds remain through ordered projection, and replaced requests cannot consume outgoing completions. Each instance carries only its namespace, root identity, and root overrides; descendants reuse that view through the same queue. The entity reader invalidates that prepared source when the canonical stage generation changes, so authored overrides are always read from the live composed stage. Do not add frame-count timeouts, per-frame load polls, or direct filesystem reads to this path. After admission, DocumentChanged and stage-asset lifecycle events wake the single sync_twin_overlays owner; do not add a per-frame generation scan or a viewport-specific edit/reload path.

On first projection, the twin:// stage already contains the document's current base and runtime layers. Replay transient view edits from the document's bounded view-operation suffix since its current source baseline. Do not query the global op ring from generation zero: runtime restores are non-op generation changes, and persistent edits do not belong in the view replay. If the view suffix has expired, rebuild from the complete composed document.

For the mounted primary scene, reference fetches stay parallel but live-stage mutation and terminal failure publication follow reference operation order. A later completed reference remains prepared until every earlier active reference for that scene resolves. Keep its ready or failed outcome while deferred; never let asset completion order choose composition or fault order. Preview stages do not acquire this simulation-specific commit barrier. The production route_lifecycle Rhai scene gate covers the fixed-tick readiness contract with multiple live references; low-level owner tests cover the ready-prefix ordering seam.

The Editor is document-scoped. DocumentId from the existing DocumentRegistry<UsdDocument> identifies the file being edited; the Twin Browser opens the explicit OpenUsdPreview { preview, doc_id, edit_target } session and can later use FocusUsdPreview or CloseUsdPreview. A session owns one projected composed stage; OpenUsdPreviewView { preview, view } adds a camera/render target over that stage for another dock tab or split. FocusUsdPreviewView and CloseUsdPreviewView address the exact view. Native editor view-model resources are keyed by UsdPreviewId and derive one entry per open session; panels paint the focused view's session entry. Visible preview targets are bounded by UsdPreviewRenderBudget (2048 px per axis, 4,194,304 pixels per view, and 8,388,608 visible pixels per frame by default), while hidden view cameras stay inactive. The shared ECS selection is a focused-session projection restored from editor-owned session selection, not a document identity. Panel writes use the session's explicit DocumentId, LayerId, and projection generation.

The active Twin's asynchronous workspace restore recreates saved view tabs over the same document-scoped preview session and restores each view's camera and presentation settings. Reopening the same file reuses the registered document; use the explicit Open view action to add another perspective. A view tab without a restored session is dropped from the saved dock layout rather than shown empty.

Preview projection is a presentation scope over the same composed stage. It owns one session-local light and excludes authored scene-wide DistantLight/DomeLight prims from that render layer; authored local SphereLight/RectLight prims remain part of the assembly. A preview is ready only after its root and descendants are synced and that subtree's visual queue plus asynchronous mesh phase have settled. Consumers use the typed projection_ready state from InspectUsdViewport; they do not infer readiness from a document generation or camera state.

Each UsdPreviewView also exposes Visual and Text modes over that same session. Visual mode renders the projected stage; Text mode displays an asynchronous, generation-matched authored or composed USDA snapshot as read-only text. SetUsdPreviewViewMode and SetUsdPreviewTextLayer change only view presentation, so they preserve the document, projected stage, selection, camera, and lifecycle identity. Text snapshots are coalesced per session and discarded when the document generation or preview lease changes; they do not create a second parser, document registry, or source writer.

When an agent needs to answer “what is visible?” or edit the item a user has open, call the UI-owned InspectUsdViewport query (or assembly_edit::viewport()) and correlate its explicit preview/view handles with CaptureScreenshot. The query is presentation context, not a second document registry: use the returned doc_id, edit_target, and projection generation with document inspection and typed edit commands. Never infer identity from a tab title, filesystem basename, entity order, or the live simulation viewport.

The Files section sends a .usda, .usd, or .usdc click through the existing BrowserAction::OpenFile and async document pipeline. The emitting Twin's resolved absolute path is preserved, so an inactive Twin is not accidentally anchored on the active one. Once the document is admitted, the viewport derives its document-backed UsdPreviewId::for_document with LayerId::root(), opens the session's primary UsdPreviewView as an instance-backed dock tab, and focuses that exact tab. File reads capture FileDocumentAdmission before dispatch and validate the resolved runtime owner before publication. A retired owner cannot install a late source; repeated requests coalesce only with the same admission snapshot. Indexed Twin source requests and leases retire by exact TwinId, and stored document ownership fences deletion after a source rebind. Preview admission rejects retired document owners; private restored snapshots explicitly belong to Application. See the source lifetime contract. Browser file picks carry request-owned bytes into this same asynchronous preparation pipeline. Each successful import installs a fresh pathless Application document; the filename is display data, even when another pick has the same name. Native Save-As requests pin the exact source owner before the backend starts. Browser Save-As uses a fallible download and only publishes saved state after admission. Repeated admitted clicks reuse the same document, preview session and view tab. Explicit FocusUsdPreview and FocusUsdPreviewView commands foreground their matching instance tab as well; replacing or closing a session removes its view tabs with the presentation resources. The preview root carries UsdPreviewOnly, the USD projection ownership fence. Consumers that can create simulation side effects must use the shared bounded is_preview_only ancestry helper rather than names, stage handles, or missing physics components. Authored controls and program projection use that same ancestry fence. Cosim discovery marks preview prims examined without loading their programs, and wire derivation excludes preview descendants so duplicate USD paths cannot claim mounted-scene endpoints. Live operator entities are admitted only through their UsdSceneRoot ownership. The USD DEM bridge marks preview terrain prims examined without creating DemTerrainRequest; preview DEMs must not create collider rings, analytic query sources, or hold mission physics. Relief in an isolated Editor terrain preview still needs a separate render-only terrain realization and spatial demand. Mounted-scene live-edit reconciliation ignores preview copies when looking up an entity by stage and USD path, so a preview duplicate cannot satisfy the mounted scene's structural spawn or refresh. Procedural scene backgrounds are also excluded from previews because the skybox renderer has one scene-wide owner. Unscoped QueryUsdPrim reads select the mounted scene by ignoring UsdPreviewOnly roots; preview roots do not make live queries ambiguous. Never choose an editor stage by entity count, insertion order, or the current simulation viewport, and never use an active-viewport fallback for an entity that lacks an explicit document binding.

When an agent is creating or modifying a reusable assembly, use the dedicated interactive Assembly Editor runbook. It requires a headful production window, explicit document/preview handles, typed USD edits, a screenshot after each coherent change, and a user-feedback checkpoint. This projection skill owns the implementation boundary behind that workflow; it does not authorize direct USDA or ECS edits.

For agent or editor synchronization, call SyncUsdDocument with the explicit document generation. Use its typed delta while the cursor is covered; consume the returned base/runtime layer snapshot when a full reload or expired history window breaks the authored-operation stream. Full reloads advance the projection generation without adding a fabricated authored operation. Reject future cursors. To edit a composed path, call ResolveUsdTarget with the explicit document id, prim path, and @root@ or @runtime@ target. A referenced or payloaded path that has a local authored opinion in the current document is valid from that document layer while the existing CanonicalStage projection catches up; a composed-only path still requires the mounted canonical stage. Use the returned edit_scope and typed-operation validation rather than treating a composed read as permission to move or remove a referenced/variant prim. Do not inspect flat layer data as a replacement for OpenUSD PCP resolution or use it to invent a composed-only target.

For a transient edit target that a tool has just authored, pass authored_children: true to ResolveUsdTarget when it needs that layer's direct child paths before scene projection settles. This returns the selected layer's primChildren paths only; it does not resolve or enumerate composed children.

Agents and editor automation should use the built-in assembly_edit Rhai library. It is a thin wrapper over OpenFile, InspectUsdDocument, InspectUsdViewport, ResolveUsdTarget, SyncUsdDocument, ApplyUsdOp/ApplyUsdOps (including SetTimeSample and RemoveTimeSample for keyframes), AttachComponent, DetachComponent, UndoDocument/RedoDocument, CreateUsdProposal, InspectUsdEditSession, ReviewUsdProposal, and CommitUsdProposal; it does not create another document registry, resolver, USDA writer, or operation log. open returns the normal asynchronous command acknowledgement and callers discover the resulting id through ListOpenDocuments. Read helpers require an explicit doc_id; authored helpers require doc_id, an edit target, and a USD path. Their optional parent_gen is the existing stale-write precondition, and batch, transform, or a keyframe change land as typed journal/undo operations. A proposal requires a generation and explicit SourceAsset/Assembly/ InstanceOverride scope, validates without mutating the document, and is visible through InspectUsdEditSession. Mute/unmute and reject are review-only; commit rechecks generation, layer revision, origin, file watermark, scope, and typed validation before using the ordinary grouped journal/undo path. A conflict requires a fresh proposal; no automatic rebase or overwrite exists. Use the tool catalog and completion query to discover the source and signatures.

A scene loaded from disk and a prim authored at runtime therefore produce identical entities without one heavy deferred-command flush monopolising the window. The queue marker is the projection ownership fence: one prepared hierarchy creates one child under its USD parent, so the projector does not scan the world for duplicate stage paths. The same composed path is valid in separate scene mounts and runtime instances; hierarchy and instance identity scope those projections.

Generated Modelica domain projection follows the same ownership and change set rule: apply the shared is_domain_network_root predicate before selecting a synthesizer, then revisit only queued root entities. Live USD changes arrive as typed UsdSceneChangeBatch path sets and are routed through the canonical stage/root/member reverse index; stage-asset changes and generation gaps only requeue roots on that stage. Reserve the all-prim pass for initial discovery. Do not use the USD wiring latch as a membership signal, add a second stage scan, or use a name-based candidate list. After validation, publish the generated source and interface, link the source to its normal Modelica document, then let lifecycle compile admission dispatch it. Do not send a worker compile directly from USD projection; the standard path owns document-generation and session fencing for generated and authored models alike. Lifecycle projection is followed by stable identity admission and API/path index publication before the time spine releases simulation. Newly projected references must resolve by path on their first resumed tick through that ordered runtime path. The generated-source browser/API projection has its own source/document invalidation boundary. Do not gate it on live ModelicaModel output or clock changes; those are solver state and must stay in the Modelica runtime owner. Member class discovery is driven by ModelicaSource asset load, failure, and modification events. Do not add a time-based give-up deadline or poll pending sources on stable frames; an unavailable source remains explicitly pending until the asset owner publishes a terminal outcome.

Show full SKILL.md (1,680 more words)Show less
Scene precision boundary

The mounted UsdSceneRoot is a nested BigSpace Grid below the active site frame. Its top-level USD prims are direct Grid children and carry their own CellCoord; their visual and collision descendants remain ordinary children under the prim root and use LowPrecisionRoot. Terrain and rover/lander roots are siblings in this scene frame. Terrain is never the parent of a vehicle, because it does not own vehicle identity, physics, or lifecycle. Runtime and replicated catalog spawns must enter through the same cell/local placement boundary as authored top-level prims.

Law 1 — every edit goes through ApplyUsdOp

An authored edit that does not lower to a UsdOp is absent from save, journal, undo, and network replication. Route every authored editor/runtime mutation through the same projection boundary.

rust
commands.trigger(ApplyUsdOp { doc_id: doc, parent_gen: None, op });      // one op
apply_ops_as_change_set(world, doc, "Edit material", ops);       // N ops, ONE undo unit

Prefer apply_ops_as_change_set whenever an intent lowers to more than one op — a loop of ApplyUsdOp journals N independent entries, and undo then peels off one and leaves the object half-edited.

This law is for authored edits. A derived presentation may use the typed ApplyUsdTransientOps command after resolving its source from the composed stage when it needs a USD prim identity, schema, or picking contract. That path is generation-checked and projected through OpenUSD, but is explicitly outside save, undo/redo, and the Twin journal. Do not use it for a user edit or to refresh dense per-edit geometry. Keep high-frequency or terrain-sampled view geometry in its transient render owner; snapshot inputs, coalesce per target, bound worker admission, and commit only current results to the existing render entity. For example, route edits update their normal authored projection once, then UpdateUsdCurveView prepares sparse surface strokes without a second USD generation. Terrain fragments own the drape, so LOD/elevation changes need no route tessellation. Stable segment identities preserve unchanged legs across route edits. Inspect current publication and dirty-range work through InspectUsdCurveView. Incremental index patches keep the displayed surface texture until the current patch commits; removing the last annotation clears it immediately.

usd.document.projected includes the reconciled changed_prim_paths in its typed event data. A policy that caches composed facts should check this path set before issuing document queries; unrelated document edits are not a request to rescan the whole owned subtree. The event closes the live handoff only after referenced roots changed by that edit and their prepared instance projections have reached the ECS scene. Typed reference-add intents seed this required-root set before the asynchronous asset admission emits a stage notice; pending references elsewhere in the mounted stage do not delay this edit or retain its document-projection hold. An authoritative pending reference still owns its independent SceneReferences key until its instance projection is in ECS. Partial ancestor sink notices are accumulated into that one completion event. Each live UsdInstanceProjection retains its source asset handle with its remapped immutable plan. Sibling instances of the same asset reuse that prepared composition while any live instance still uses it.

Writing an ECS component directly is legitimate only for state that is genuinely not part of the document (a camera's current yaw, a hover highlight). If a user would expect it to survive save-and-reload, it belongs in USD.

AttachProgram { doc_id, spec } is the canonical multi-op authoring intent for a source-backed Modelica, Python, Rhai, or behaviour-tree program. It lowers the complete LunCoProgramAPI child, source asset, scalar ports, defaults, and connections through this same change-set path. A palette or script must call that command; it must not create an ECS marker or write a parallel registry. An empty contract is source-only and remains visibly distinct from a running cosim participant.

Composed asset I/O uses UsdRead::asset_identifier, the canonical identifier annotated by the maintained strongest-default OpenUSD resolver. Keep asset for raw authoring/query text. Never reanchor a child layer's asset string against the scene root. Initial/live preparation carries the same context; missing consumed context is an error. Time-sampled assets without that annotation are not admitted. Render consumers retain typed load_asset_path addresses and reuse admitted handles. Binary arc classification preserves the full logical filename; URL query/fragment semantics apply only to explicit HTTP addresses. Browser default/library readers and worker fetches encode literal filename components at the shared asset HTTP transport boundary. Keep authored logical addresses literal; do not pre-encode them or decode existing HTTP URLs. DEM directory lookup uses the existing I/O worker and asset owner's directory transport, with exact mount checks before publication. See asset provenance.

Law 2 — ask the scene root, never guess

To author a new top-level prim you need the target document and the parent path. Both come from the scene root:

rust
roots: Query<&UsdPrimPath, With<lunco_usd_bevy::UsdSceneRoot>>
let doc = lunco_usd_bevy_twin::scene_document_for(&backed, &asset_server, root.stage_handle.id())?;
let parent = &root.path;            // "/SandboxScene", "/World", …

Two failure modes this exists to prevent:

  • Counting the registry ("there's only one document") — false. The registry also holds terrain and script documents.
  • Hardcoding /World — the luncosim scene is rooted at /SandboxScene. A prim authored outside the mounted defaultPrim subtree composes into the layer and is then never mounted: it saves, it journals, and it is invisible. This failure is completely silent.

Law 3 — spell it the way USD spells it

Use the real schema. UsdLuxDomeLight for an HDRI, UsdPreviewSurface for a material, UsdPhysics* for physics. Before inventing anything, check whether USD already defines it — a scene that leaves this app must still mean what it said.

  • inputs:* is the UsdShade namespace: it lives on a Shader prim, reached by material:binding → outputs:surface. A float inputs:metallic on a Sphere is not valid USD, and no DCC will read it back. Use lunco_usd_core::material::ensure_preview_surface_ops() — it builds the Material+Shader+binding for you, and it is deliberately in lunco-usd-core so every crate authors materials the same way.
  • primvars:displayColor / displayOpacity are the only Gprim display attributes. There is no "display emissive" — emission requires a material.
  • Genuinely new concepts get the lunco: vendor namespace (lunco:dome:skybox, LunCoProceduralSkyAPI, lunco:terrain:*). That is the correct, spec-sanctioned way to extend USD. What is not correct is inventing a second spelling for something USD already has.

The procedural camera-background contract is an Xform with LunCoProceduralSkyAPI and a standard UsdShade material binding. Read that API once in lunco-usd-bevy and stamp the existing render-free ProceduralSkybox component. Do not project a UsdGeomGprim for the background, carry info:wgsl:vertexAsset, or read the API again in a downstream shader projector. UsdLuxDomeLight remains the standard path for textured environment lighting.

Never add an alias to make a file load. A tolerant reader (inputs:roughness or perceptual_roughness or bare roughness) is not robustness — it is a trap. It teaches callers the invalid spelling and hides the bug: the writer authors garbage, the reader accepts it, and the two conceal each other until the file opens in Houdini and the material is gone. If the wrong form is authored, the right behaviour is for it to visibly do nothing.

Adding support for a new prim type or attribute

  1. Read it. Extractors use the UsdRead trait (lunco-usd-bevy-stage/src/read.rs), implemented by both StageView (the live composed stage) and UsdStageProjectionPlan (the worker-produced initial snapshot). Authoring-layer reads use UsdDataExt separately; runtime extractors never switch to that source.
    • Floats: use real / real_f32, never scalar::<f64> — a float- authored value silently reads None through the f64 path.
    • Asset paths: read_token (it coerces String/Token/AssetPath), then resolve_texture_path to make it relative to the stage layer. Downloaded assets are lunco://textures/… (declared in a crate's Assets.toml).
  2. Dispatch it. Prim types are a match on reader.type_name(&path) inside instantiate_usd_prim_from_reader. There is no registry to add to.
  3. Project it. Insert components. Keep render-bound types out of lunco-usd-bevy — it is render-free by contract (cargo tree -p lunco-usd-bevy -i wgpu must be empty). bevy_light / bevy_image / bevy_camera are fine; bevy_pbr / bevy_render are not, and belong in lunco-render-bevy.
  4. Re-project it on edit. This is the step people forget. A structural change (new prim) reconciles automatically. An attribute-only edit arrives as info_only. Standard transforms and lights stay on the generic path; a domain-specific in-place refresh registers a typed UsdLiveEditOwner with lunco_usd_bevy_core::live_edit::UsdLiveEditRegistry. The owner claims only its attributes, invalidates its own projection marker when required, and refreshes from the composed stage. Owners also promote a local subtree reset to a stage reset when their runtime topology crosses that subtree. Before a full reset, each owner retires its derived state synchronously; a rejection leaves the current projection in place and faults the active simulation. Keep live_consume.rs generic: if you add an editable attribute and skip both paths, SetFoo will journal and save correctly and nothing will move on screen until reload.
  5. Author it. Add a command that lowers to UsdOps (Law 1) and register it with register_commands! — a command is only reachable from the HTTP API / MCP / rhai if its type is in the reflect registry.
  6. Test it. Because extractors use the shared composed-reader contract, unit-test the prepared UsdStageProjectionPlan for initial-load behavior and use a live StageView only for explicit authored-edit behavior — no App, no renderer. Keep pure animation topology/transform-reader tests in lunco-usd-bevy-core/src/animation.rs; runtime animation-system tests belong to lunco-usd-bevy-animation, and observable scene/policy assertions belong in Rhai. Do not create a test-only crate or import animation readers into the visual test target.

Worked example

crates/lunco-usd-bevy/src/dome.rs (HDRI environment) is the whole checklist in one file: standard schema (UsdLuxDomeLight), lunco: only for the two knobs UsdLux genuinely lacks, a shared reader used by both the load path and the live- edit path, an info_only refresh so runtime edits appear, a SetDomeLight command that lowers to ops, and pure-function tests.

Gotchas

  • bevy::init_asset::<A>() is destructive, not idempotent — it wipes Assets<A> and swaps the allocator. Guard with contains_resource.
  • The CanonicalStage is NonSend (openusd Stage is !Send). Read it under a short borrow and release it before mutating the world.
  • reconcile_structural_live does nothing for a prim that exists and already has an entity — it spawns and despawns only. Refreshing an existing entity is your job.

Active TwinClosed retires the scene mount and publishes SceneOwnerRetired before deferred teardown. Scene-time readiness closes immediately; pending admissions and scene requests are discarded, the active transaction fails, and ClearScene runs at the next lifecycle phase. Inactive Twin closure must not clear another Twin's scene. See architecture 61 for the shared owner contract.

Native path verification uses the asset owner's typed AssetPath throughout loading and handle lookup, including literal # filenames. Windows drive and UNC USD references normalize to file: at composition; they are rejected explicitly on a foreign host. Dataset output ownership uses worker-prepared lunco-storage::FilePathIdentity snapshots rather than lexical path prefixes.

© LunCoSim, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in skills/usd-projection of LunCoSim/lunco-sim.

Open the folder on GitHubat commit 43f1301

Compare with similar skills

Usd Projection next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Usd Projection compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Usd Projection this skillLunCoSim/lunco-sim107—~8.8kAutomated safety check: PassApache-2.0
Diagnose Gatewayopenclaw/openclaw392k—~670Automated safety check: PassMIT
Diagnosegithub/awesome-copilot40k1 repos~1kAutomated safety check: PassMIT
Find Project Anomaliespenpot/penpot61k—~1.2kAutomated safety check: PassMPL-2.0
Project Status Artifactanthropics/claude-plugins-official38k—~5.1kAutomated safety check: PassApache-2.0
Projects Work Managementsickn33/agentic-awesome-skills47k1 repos~4.1kAutomated safety check: PassMIT

Similar skills

  • Diagnose Gateway

    openclaw/openclaw

    Diagnose Gateway, config, secrets, channels, and port failures with read-only one-liners.

    392k GitHub stars~670 tokensUpdated today
    Auto-check passed
  • Diagnose

    github/awesome-copilot

    Official

    Perform a systematic diagnostic scan of an AI workflow across 5 quality dimensions — prompt quality, context efficiency, tool health, architecture fitness, and safety — producing a scored report…

    40k GitHub starsUsed in 1 repo~1k tokens
    Agent WorkflowsAuto-check passed
  • Check a GitHub milestone against the Main project board, report the five anomaly types to tmp/<MILESTONE-ANOMALIES.md, and fix missing milestone assignments on request.

    61k GitHub stars~1.2k tokensUpdated today
    Product & Project ManagementAuto-check passed
  • Project Status Artifact

    anthropics/claude-plugins-official

    Official

    Builds and publishes a tabbed status page for a project with several workstreams, kept current by refreshing the same private page.

    38k GitHub stars~5.1k tokensUpdated today
    Product & Project ManagementAuto-check passed
  • Projects Work Management

    sickn33/agentic-awesome-skills

    Project register: owner, team, priority, progress percentage, milestones, deliverables and budget against actual cost.

    47k GitHub starsUsed in 1 repo~4.1k tokens
    Product & Project ManagementAuto-check passed
  • Project Manager

    RightNow-AI/openfang

    Project management expert for Agile, estimation, risk management, and stakeholder communication

    18k GitHub stars~960 tokensUpdated 3 mo ago
    Product & Project ManagementAuto-check passed

More from LunCoSim/lunco-sim

All 40 skills in this repo
  • Nightly Changelog

    LunCoSim/lunco-sim

    Generate concise LunCoSim nightly GitHub release notes with platform downloads, installation guidance, an AI-agent mission prompt, and a changelog link.

    107 GitHub stars~1.1k tokensUpdated today
    Auto-check passed
  • Build or repair a reusable scene component through a live LunCoSim Editor session.

    107 GitHub stars~4.4k tokensUpdated today
    Auto-check passed
  • Assembly Quality

    LunCoSim/lunco-sim

    Build or review a componentized LunCoSim USD assembly with a realistic, dimensionally checkable presentation.

    107 GitHub stars~1.6k tokensUpdated today
    Auto-check passed
  • Author Rhai Tests

    LunCoSim/lunco-sim

    Author and review LunCoSim behavioral, asset-backed, component, mission, visual, and requirements-verification tests.

    107 GitHub stars~3.5k tokensUpdated today
    Auto-check passed
  • Author Rhai Tool

    LunCoSim/lunco-sim

    Create, extend, register, or debug a reusable LunCoSim Rhai tool library for live USD authoring, component linting, inspection, or test support.

    107 GitHub stars~5.2k tokensUpdated today
    Auto-check passed
  • Author Tutorial

    LunCoSim/lunco-sim

    Author an interactive tutorial, guided lesson, onboarding flow, coach-mark tour, or objectives checklist in LunCoSim.

    107 GitHub stars~1.4k tokensUpdated today
    Auto-check passed

Questions about Usd Projection

What does Usd Projection do?

Extend or diagnose LunCoSim's USD-to-ECS projection: add a supported prim or attribute, trace an ignored field, or fix edits that fail to persist, undo, replicate, or render. Usd Projection is an agent skill from LunCoSim/lunco-sim. Extend or diagnose LunCoSim's USD-to-ECS projection: add a supported prim or attribute, trace an ignored field, or fix edits that fail to persist, undo, replicate, or render.

When should I use Usd Projection?

Usd Projection fits situations like: lunco-usd machinery and document-owned ECS state.

How do I install Usd Projection in Claude Code?

Run `npx skills add LunCoSim/lunco-sim --skill usd-projection -a claude-code`. Or copy the skill folder (skills/usd-projection in LunCoSim/lunco-sim) into .claude/skills/usd-projection in your project. Claude Code loads it when a task matches its description.

How do I install Usd Projection in Codex?

Run `npx skills add LunCoSim/lunco-sim --skill usd-projection -a codex`. Or copy the skill folder (skills/usd-projection in LunCoSim/lunco-sim) into .agents/skills/usd-projection in your project. Codex loads it when a task matches its description.

Can I use Usd Projection in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add LunCoSim/lunco-sim --skill usd-projection -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/usd-projection, .gemini/skills/usd-projection, .github/skills/usd-projection and .opencode/skills/usd-projection in your project.

What does Usd Projection need to run?

SKILL.md names no scripts, command-line tools or credentials: Usd Projection is instructions for the agent only.

Does Usd Projection access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Usd Projection safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Usd Projection use?

Usd Projection is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Usd Projection use?

About 8.8k tokens (SKILL.md is roughly 35k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Usd Projection?

Skills that share tags, products or a category with Usd Projection: Diagnose Gateway (openclaw/openclaw, 392k stars), Diagnose (github/awesome-copilot, 40k stars), Find Project Anomalies (penpot/penpot, 61k stars) and Project Status Artifact (anthropics/claude-plugins-official, 38k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Usd Projection?

LunCoSim (a GitHub organization) maintains it in LunCoSim/lunco-sim, which has 107 GitHub stars. The repository holds 40 skills in this directory. The repository was last updated on October 10, 2026.

Source: LunCoSim/lunco-sim on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.