Agent skill

Lunco UI

by LunCoSim in LunCoSim/lunco-sim

LunCoSim UI architecture and panel implementation patterns. An agent skill from LunCoSim/lunco-sim.

Apache-2.0Auto-check passedFrontend & Design

Install Lunco UI

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

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

GitHub CLI
$ gh skill install LunCoSim/lunco-sim lunco-ui --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/lunco-ui .claude/skills/lunco-ui && 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
lunco-ui
GitHub stars
107
Token cost
~10k tokens
SKILL.md length
5,255 words
Files
1
Skills in repo
40
Repo updated
First seen
Licence
Apache-2.0

At a glance

LunCoSim UI architecture and panel implementation patterns. An agent skill from LunCoSim/lunco-sim.

  • Works in 5 steps: UI lives in src/ui/ — domain crates have… → UI never mutates state — all… → Panels are Panel impls (the contract… → …
  • Working on any user interface for the LunCoSim solar system simulation — adding panels
  • SKILL.md covers MANDATORY: Read Architecture…, Core Principles, Runtime-authored HTML/CSS… and Adding a Panel, plus 4 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Lunco UI is an agent skill from LunCoSim/lunco-sim. LunCoSim UI architecture and panel implementation patterns. Use this skill whenever working on any user interface for the LunCoSim solar system simulation — adding panels, building dashboards, creating inspectors, spawning UI, telemetry displays, docking layouts, themes, or anything involving egui, lunco-workbench, or Panel. Also use when the user mentions typed commands, WidgetSystem, or 3D world-space UI. Even if the request seems simple (like "add a button"), use this skill because the panel registration and…

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

It sits in Frontend & Design. The repository describes itself as: Collaborative Multiphysics Cosimulator For Space Missions 🌎🚀🌚. The licence is Apache-2.0.

When your agent uses it

  • Working on any user interface for the LunCoSim solar system simulation — adding panels
  • Building dashboards
  • Creating inspectors
  • Telemetry displays

Example prompts

  • “add a button”
  • “/lunco-ui”

Requirements

  • Python 3

Workflow steps

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

  1. UI lives in src/ui/ — domain crates have src/ui/mod.rs exporting a *UiPlugin. UI code never lives outside ui/ directories.
  2. UI never mutates state — all interactions emit typed command events (the #[Command] structs, triggered via ctx.trigger(...)) that…
  3. Panels are Panel impls (the contract lives in lunco_workbench_core) — registered via lunco_workbench_core::WorkbenchPanelAppExt::register_p…
  4. Headless must work — removing UI plugins (Layers 3 and 4) leaves a functioning simulation. See AGENTS.md §4.1 for the four-layer…
  5. Typography roles are shared. ThemePlugin maps egui's built-in styles and TypographyRole styles from Theme.typography across egui surfaces…

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 and bash).

    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

Lunco UI loads about 10k tokens when it runs. Until then it costs about 149 tokens; SKILL.md has 5,255 words of instructions outside code blocks.

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

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). 5,255 words, ~10,464 tokens.

Download SKILL.mdSave it as .claude/skills/lunco-ui/SKILL.md (or your agent's skills folder).
name
lunco-ui
description
LunCoSim UI architecture and panel implementation patterns. Use this skill whenever working on any user interface for the LunCoSim solar system simulation — adding panels, building dashboards, creating inspectors, spawning UI, telemetry displays, docking layouts, themes, or anything involving egui, lunco-workbench, or Panel. Also use when the user mentions typed commands, WidgetSystem, or 3D world-space UI. Even if the request seems simple (like "add a button"), use this skill because the panel registration and command patterns are project-specific and not obvious from Bevy alone.

LunCoSim UI Architecture

MANDATORY: Read Architecture First

Before implementing ANY UI, read:

crates/lunco-ui/ARCHITECTURE.md

It explains the full architecture, step-by-step panel integration guide, and design decisions. This skill is a quick-reference summary.

Core Principles

  1. UI lives in src/ui/ — domain crates have src/ui/mod.rs exporting a *UiPlugin. UI code never lives outside ui/ directories.
  2. UI never mutates state — all interactions emit typed command events (the #[Command] structs, triggered via ctx.trigger(...)) that observers handle. This makes the UI AI-native: AI observes the same command stream as humans and can emit identical commands.
  3. Panels are Panel impls (the contract lives in lunco_workbench_core) — registered via lunco_workbench_core::WorkbenchPanelAppExt::register_panel(). The concrete shell drains that registration into its docking system.
  4. Headless must work — removing UI plugins (Layers 3 and 4) leaves a functioning simulation. See AGENTS.md §4.1 for the four-layer architecture.
  5. Typography roles are shared. ThemePlugin maps egui's built-in styles and TypographyRole styles from Theme.typography across egui surfaces in ThemeApplySet. Render systems outside the workbench should run after that set. Let ordinary widgets use the mapped Body, Button, Heading, Small, and Monospace styles. Use TypographyRole::text_style() for RichText and TypographyRole::font_id(ui.style()) for custom painter text. Guidance and status messages use Body; Caption is for secondary metadata and compact status-bar summaries. Dense data roles are for chart labels, timestamps, and similarly compact values. Authored model text and world-space labels retain their content/spatial owner.

The workbench is deliberately split into contracts, reusable presentation, optional guided presentation, and the concrete shell. lunco-workbench-core contains the stable Panel/PanelCtx, InstancePanel, PerspectiveLayoutPlan, menu registry, WorkbenchSnapshot, scheduling labels, and perspective command payloads. It is safe for domain UI crates that need panel behavior or published layout facts and does not pull the renderer or egui_dock. lunco-workbench-guided-ui owns optional Rhai-driven HUDs, spotlights, coach-mark tours, and guided-recovery surfaces; hosts add it explicitly after the shell. Its mission checklist can be restricted with GuidedObjectivesVisibility; LunCoSim shows that checklist in View while keeping tutorial hints, actions, spotlights, coach marks, and recovery surfaces available over Builder and Editor. lunco-workbench is the concrete shell: it owns docking, egui/bevy integration, persistence, source editing, and shell-only widgets such as icons and tree renderers. lunco-workbench-widgets owns the shell-independent icon, text-editor, and tree helpers. Virtualized trees use tree::branch_header for a fixed row stride; recursive trees use tree::branch for an indented body, sharing the same disclosure state and controls. lunco-workbench-browser is the optional reusable Twin/Files feature: it owns browser state, standard panels, and filesystem/library sections, including the asset-provisioning dependency. Domain crates must not read the shell's private WorkbenchLayout; use WorkbenchSnapshot for layout facts and typed workbench/browser actions for navigation.

Universal runtime inspections should read an authoritative view model produced outside egui. For ports, use PortRegistry::entity_port_infos so values, units, ranges, source, authority, and writability come from backend owners; sample at a bounded cadence when the data has no shared change marker. Writable rows emit the existing typed command and validate against the metadata contract; the panel must not infer policy from names or mutate port storage directly. If the view caches metadata, its invalidation must use the owner-provided PortBackend::topology_key and the durable owner-published PortTopologyRevision. Providers publish it from component lifecycle observers and change-filtered structural identity checks; Avian groups declare their identity key and invalidation hook beside their membership predicate. Do not use a broad scene revision or entity-count poll as a port-topology signal. Large inspection surfaces must virtualize their fixed-height browser rows and request live values only for expanded/visible bodies through the existing owner. The USD Prim tree caches open rows and uses the shared tree disclosure controls with preview-scoped identities; preserve selection reveal, offscreen scrolling, and the typed display-mode commands. The bundled-library browser consumes the asset manifest's revision, not a per-frame hash of all paths. The normal sample path reads live values through the registry rather than rerunning backend list/metadata callbacks.

For USD topology, extend the existing Connections projector in crates/lunco-luncosim-edit-ui/src/ui/connection_canvas/. Default to the active SceneMountState mount; Editor document focus is an explicit alternate source. Read composed USD, including prims without ECS projections, independently of Modelica compilation. Cache facts and consume stage deltas, never traverse in paint. Start at the loaded root with direct hierarchy children; use cached USD ancestry for drill-in and explicit descendant expansion. Preserve full property identities; causal edges have arrows, acausal/joint edges do not. Never fabricate missing interfaces. Scene selection uses mount-scoped entity targets, documents use SelectUsdPrim. Use Edit connections / OpenUsdSourceDocument to establish the document boundary without replacing the scene. The USD document owner resolves the exact registered source on a worker and reuses its file-preparation lifecycle. USD browser clicks use this source-only command too. OpenFile can open a different workspace/Twin and is not an additional-preview command. Verify source isolation through assets/scenarios/tests/usd_source_isolation.rhai, launched by scripts/api/test_usd_source_isolation.py with an exact scene, source and composed selection path in an owned production session. Successful and rejected sources preserve the active Twin and physics topology, and physics continues while a preview opens. Use the composed USD reader's runtime-provider schema contract to display exact authored interface references before runtime projection. Runtime owners validate availability and types; the diagram does not admit connections to simulation. Publish endpoint failures with exact identities in Recent events, not in the diagram toolbar. Use diagram.layout for authored Rhai layout policy over immutable graph facts, including independent view keys and typed interface roles. Run it on bounded workers with source/scope revision fencing and the Application/Visualization/Preparation context; validate complete finite placements before rendering and apply saved placements afterward. The policy may return a bounded display label and schematic accent role; consume both in the view without modifying USD identities. Breadcrumbs, Back and searchable Find system share cached USD ancestry. Double-click uses OpenConnectionNode and diagram.open.plan: systems open USD child topology, leaf Modelica programs use the existing schema editor, and Rhai/Python use source. Navigation must preserve exact source identity and reject missing cards. Modelica OpenFile resolves registered asset URIs on its worker through SchemeRegistry, preserving the document owner and read-only library state. Exercise the installed policy with assets/scripting/tests/test_diagram_layout.rhai. Use diagram.group.plan for optional Rhai grouping over immutable program-source, typed-port, topology and standard CollectionAPI facts; Rust validates and renders its disjoint partition on the existing layout worker. Expanded frames and collapsed summary cards preserve full USD topology. Resolve summary ports to their exact original endpoint before authoring or inspecting a connection. Use the typed SetConnectionGroup, SetConnectionGroupCollapsed, RemoveConnectionGroup, MoveConnectionGroup and SetConnectionGrouping commands; group movement is one journaled edit for all member placements. Manual membership, disclosure, exclusions and the grouping switch belong to each existing named view. Salvage usable groups and placements independently when an optional view file is damaged. Verify installed policies through assets/scripting/tests/test_diagram_groups.rhai as well as the layout gate; exercise collapse/expand, movement and rejection in the production API. Persist named scopes and layouts in separate .lunco-view.toml project artifacts using lunco-doc::diagram_view / DocumentHost, through typed view commands. Each view has independent placement; USD files only own topology. Save views / Load views use bounded asynchronous lunco-storage work and recover valid entries from missing/corrupted optional view files with warnings and automatic layout. Different sources or unsupported versions use the loaded USD automatic view; duplicate file owners and stale loads reject. Mouse port connections use journaled ApplyUsdOps, retain declared types and unrelated links, and Save/Undo stay source-document-owned. Layout Undo/Redo belongs to the view document. Canvas.movable_layout permits node arrangement in read-only scene views. Consume InspectConnectionDiagram for exact source, view IDs, layouts, rendered ports, and logical screen coordinates. Verify scene inspection preserves same-prim feedback as edges. Drilling into a system shows input/output/acausal interface terminals and child prims. nodes[].key is the independent placement identity; nodes[].path stays the exact USD prim for authoring and selection. nodes[].role identifies boundary terminals; never infer runtime ownership from port names. connections[] retains exact USD endpoints alongside their presentation keys. Verify input/input and output/output boundary forwarding and rejection of terminal deletion. Verify navigation, independent named layouts, file roundtrip, and mouse gestures in an owned production API session, plus pure document/projector/interpreter tests. Drag Library/Twin sources into a document diagram: USD becomes a reference; Modelica/Rhai must land on an existing host prim. Models-palette drags retain their typed authored port contract. Inspect nodes[].programs for backend, source and resolver issues, including hidden children attributed to their nearest visible ancestor. Drop naming/routing belongs to diagram.drop.plan in assets/scripting/policy/diagram_drop.rhai; Rust validates its typed plan and uses the existing journal batch. Verify terminal outcomes and placement after source success with connection_diagram_authoring.rhai, including missing-host and unsupported-source rejection. Exercise the installed policy with assets/scripting/tests/test_diagram_drop.rhai. Use connection_diagram_wiring.rhai for composed sink authoring, undo and missing-target rejection in an owned document preview. The contextual Connections inspector opens exact program facets with OpenConnectionNode.program_path; an omitted program path retains normal policy-driven double-click navigation. Show USD path/type, ports, peers and Modelica/Rhai sources together beside the graph, using a floating panel on compact widths. SelectConnectionElement validates exact cards/ports and shares source-scoped scene/document selection. Selected nodes emphasize incident links; selected ports emphasize exact endpoint matches, and unrelated wires use shared disabled opacity. Use cached graph adjacency for peer rows. Find searches prims, ports and program sources; reveal may navigate to the exact hidden prim's parent. NavigateConnectionDiagram keeps view, scope, expansion and viewport history; Back restores them after layout completes. Verify tracing, navigation restoration and invalid identities with connection_diagram_explore.rhai. Keep the header to source/mode and primary actions, then navigation. Put named views, schema options and repository files under View, variants under Details, and gestures under Help. Show USD dirty state independently from view dirty state. Port dragging, click-to-connect and the inspector Connect to picker must share endpoint/type validation; valid targets show rings and invalid targets explain rejection before release. The shared canvas validator rejects before EdgeCreated; ApplyUsdOps owns admission and journaling. Distinct same-prim ports may author valid feedback. Composed edits preserve the viewport through asynchronous layout. Verify native dragging, undo and rejected directions with connection_diagram_gestures.rhai in a visible Connections document. Supply doc_id, exact source/sink view keys, source_port/sink_port and a same-direction invalid_port on the sink; place the two cards within the focused viewport before running the gate. Show acausal connectors as hollow diamonds with explicit labels and separate counts; zero causal outputs does not mean a physical model is disconnected. Show prim type and no authored ports for geometry/cameras. Use FrameConnectionDiagram for Focus/Fit over the current view key; the render boundary consumes its request through the shared viewport. Focus preserves scope and topology and fits at most natural scale. Open uses the existing double-click command. Verify exact card centering, complete-system fit and missing-card rejection with connection_diagram_focus.rhai; inspect viewport and node dimensions through the existing diagram query.

The Editor's authoring_review panel is the shared human-facing evidence surface for authored/runtime inspection. Its target chain must keep selected, controlled, and the active camera target as separate rows; do not collapse them into a vehicle-specific status or infer control from selection. Render retained RuntimeDiagnostics with the producer, severity, exact subject, and message, and route a subject action through the canonical typed selection command when a live GlobalEntityId exists. Inspection checkboxes use the existing DiagnosticVisualStore leases for joints, frames, mass, forces, wheel forces, and collision geometry. The panel is presentation only: measurements, tolerances, provenance, candidate grouping, and preview/document navigation remain authored Rhai over typed USD queries.

default_slot() seeds layout intent only before the first perspective is active. After that, the active Perspective owns its slot declarations; late panel registration adds the renderer without changing the current presentation unless the panel declares visible_in_perspective() for the active perspective. Use that contribution when a plugin-owned panel belongs in another package's perspective, so the perspective does not need a dependency on the panel package or a copied panel id. Cached user layouts still restore as saved; contributions apply when a perspective builds its default layout.

Modelica preparation emits discrete lifecycle notices for its compilation queue, solver-cache lookup, equation lowering, cache reuse, and elapsed preparation time. The shared Modelica notice observer projects Info, Warn, and Error into Recent status. Preparation notices are session/source-fenced and never solver results; they must not release the simulation hold or change the model's time or outputs.

The workbench status history is one shared presentation surface: render Info, Warn, Error, and Attention through the same responsive level/source/message/action row. Its popup is compact, sized to roughly half the available parent window and clamped to 420–960 logical px; the message column consumes the remaining inner width rather than an arbitrary fixed fraction. A new terminal RuntimeFault opens the popup automatically, but its explanation is published as the ordinary Modelica Error event in history. Selecting that row expands the complete message. Compile failures explain why simulation did not start and include unmatched unknown names, categories, and referencing equation rows when Rumoca can diagnose them. Step failures list Modelica values not produced, their last accepted values, and sample and target times. Use one scroll area with a stable id_salt in this popup so egui keeps one history surface and does not report duplicate scroll-state IDs. Ordinary warnings and non-terminal errors remain in history without opening the popup. Diagnostic rows keep the shared column geometry, expose row activation through the cursor and tooltip, and add the complete diagnostic as an optional body under that row. Emit the existing typed action for Attention; do not create level-specific row layouts or source-specific styling. StatusBus coalesces consecutive identical discrete snapshots before this shared reader. Keep the expanded history view discrete: do not append active progress to its event list. Hide the entire event summary from the strip while that history view is open, including its fallback to the latest discrete event; preserve the strip click target so it can close the popup. Active progress shows a compact notice anchored above the strip as a non-exclusive UI_ORDER overlay, never an egui popup, so it cannot close a menu the user opens while loading. Scene progress is titled “Scene loading…” or “Scene unloading…” for a clear transition; other progress keeps its source label. The complete owner-written message wraps inside the card, and the status strip uses the same concise scene label. Do not infer phase from free-form text. Terrain tile streaming, optional terrain refinement, and post-projection scene geometry stay published for readiness consumers but drive the workbench loading notice only during an admitted or active scene transition. This prevents camera movement after scene load from reopening the loading notice. “Recent status details” opens the history popup, which stays open when work completes. The compact notice disappears on completion; do not stack it with the history view or auto-close a history view the user expanded.

Stack application surfaces through lunco-theme, top to bottom: menus and popups (egui Foreground), UI windows/dialogs/notices (UI_ORDER), the general HUD (HudTier::General: sky clock, toasts, global notices), and the specific HUD (HudTier::Specific: lesson or vehicle readouts). Create HUD areas with HudTier::area/HudTier::layer; the workbench applies stack_hud_layers once per pass. Never give a persistent overlay Foreground. Authored runtime HUI paints before egui and stays below every egui tier. Tutorial rings, coach/recovery cards, and completion prompts use lunco_workbench_guided_ui::GUIDED_OVERLAY_ORDER (UI_ORDER); the lesson HUD is a specific-HUD readout; their scrims use the shared GUIDED_SCRIM_ORDER (egui::Order::Background). Workbench menus and window controls are egui Foreground surfaces and therefore remain above both tutorial layers visually and for input. The workbench measures the live menu row and right-side control group; on compact widths it keeps File and View direct and places registered domain menus plus Edit, Settings, Help, and Time under one keyboard-reachable More entry. The direct and overflow surfaces call the same menu renderers, so command semantics and callback state have one owner. Build responsive menu measurements from the registry snapshot and group scripted contributions only when their popup opens. Keep this one shared layer contract; do not rely on system execution order or give a tutorial surface a Foreground/Tooltip order that can cover application controls. The tutorial draw systems are chained within their shared layer, so their relative paint order is deterministic as well.

Rhai-contributed workbench menus use the shared lunco_workbench::menu_popup_max_width helper with the egui content viewport, fix that width before laying out wrapped rows, and let short lists shrink vertically instead of reserving an empty scroll region. Completion state uses the shared vector UiIcon::Check and UiIcon::Pending with accessible status text; do not render status words or font-dependent glyphs as a second status system.

The workbench scopes only its private mutable layout out of the World while painting. The authoritative WorkbenchMenuRegistry remains installed and is read through an immutable frame snapshot, so layout resets do not clear menu contributions. PanelCtx and MenuCtx trigger intents, together with shell menu actions, go through DeferredWorldTriggers and are applied after the egui pass restores the layout; do not call observer events directly from a render callback when a typed context can queue the intent.

Egui developer overlays are owned by the shell's persisted WorkbenchAppearanceSettings::egui_debug_overlays, off by default. Debug builds offer the opt-in under Settings → Appearance. Do not enable diagnostics in panel-local styles; the shell applies the preference to both theme styles on all contexts before each egui pass.

Panel entries in the View menu use PanelMenuGroup for their primary workflow: Builder owns live-Twin construction panels, Editor owns authored document editing panels, and Lunica owns Modelica workbench panels. Put shared panels in their primary home once; leave Other for integrations with no workflow home and Hidden for internal panels that should not be user-toggleable.

Document-private viewport mounts retire at DocumentClosed, or when their final preview lease ends with no workspace projection owner. Mount-set changes prune their catalog entries before replacement scans; closing a preview must not unregister a shared workspace authority.

For Twin-browser work, use lunco_workbench_browser::BrowserQuery as the single transient search field. Sections filter their own authoritative view-models by human-readable names/paths, retain matching ancestors, and emit the existing typed navigation actions. Do not add a per-domain search resource or make the browser search generated ids. Shared scene-catalog choices retire closed-mount entries at TwinClosed; the catalog owner invalidates scan generations while preserving application library and surviving-mount entries. See the lifecycle contract.

Native USD Scene Files reads the published SceneFileView; never traverse or stat files during paint or its main-thread input capture. Its single bounded worker pins source owners/generations and a TwinRootsSnapshot, coalesces the latest request, and rejects stale publication after source or mount retirement. Keep valid rows during same-scope refresh, clear them on scope change, and make preparation/admission errors visible without automatic retries. Verify the active TwinClosed edge cancels the pending task, coalesced request and refresh state immediately. DocumentClosed removes published USD rows at that edge. Snapshots resolve authored logical Twin names against live mounts; publication still requires the captured scope and revision. Verify the generic browser_retirement and scene_file_ lifetime/publication seams and the asset-owner closure budget/error test; see the closure contract.

For hierarchy rows, use lunco_workbench_widgets::tree::{branch, branch_header, leaf} and tree::{label, selectable_label} for row text. The shared renderer resolves Theme.typography.tree and owns the disclosure control, full-width row geometry, left-aligned label presentation, persistent expansion identity, indentation, and the default depth-based expansion policy. Domain panels own only their view-model filtering, stable egui::Id, selection/loading state, and typed actions. Do not create a second CollapsingHeader/CollapsingState path for a tree, or duplicate selectable-row sizing and alignment at call sites. Do not move domain selection or loading policy into the shared renderer. Search may force matching branches open for the current frame; ordinary expansion remains persistent UI state.

Show full SKILL.md (2,095 more words)Show less

Selectable tree rows use tree::selectable_label, even when they support drag and drop or reserve trailing value columns. Wrap the shared label as the drag source instead of replacing it with a direct Button::selectable call.

Project-owned settings are not user-global settings: read the active Twin's manifest through the workspace resource and emit a typed event for changes. Workbench hot-exit documents, tabs, and dock windows are scoped to the active Twin. With no active Twin, use the host's startup layout and skip workspace state load/save; do not restore loose Editor or Modelica tabs from an app-global no-folder session. Workspace snapshots load, prepare file-backed documents, serialize, and save on Bevy's task pool through lunco-storage. Domain codecs restore documents through their existing registries and lifecycle events. Document-backed view tabs can remap many saved views onto one canonical document; the codec chooses whether unmatched tabs are retained or dropped, while stable singleton-instance panels keep their own IDs. For the missing-asset consent flow, the popup's unchecked negative checkbox means "show next time" and persists through twin.toml [downloads]; do not add a second global settings key for it.

The Entities panel follows SceneMountState::active_root through the shared UsdSceneRoot ancestry helper. Membership follows scene hierarchy through nested grids and remains independent of physics frames. Additive mounts and render-only previews are excluded. Membership is an application-owned scene fact, not a Twin preference. Clear the derived tree on active TwinClosed so outgoing rows cannot linger.

The native Updates submenu is content-sized by the workbench's shared menu container. Keep its identity block explicit (Version, GitHub Actions build, and Update channel), derive the run/attempt label only from the CI-stamped nightly version, and show an explicit unavailable state for local builds. Do not present a source SHA as the GitHub build number or force a feature-local minimum width.

Generated USD runtime scene edits use the same Twin-owned settings boundary: usd.runtime_persistence is one boolean opt-in for both reading and writing the .lunco/runtime cache. The Settings menu reads the USD owner's policy and emits SetTwinSetting; it must not register a global autosave section or invent a second persistence path.

Camera labels are a shared projection owned by lunco-usd-bevy::camera_switch::camera_display_labels. Reuse it in workbench camera lists, the USD/entity trees, and Inspector; keep the full USD path as the selection/tooltip identity. Unique leaves are compact, duplicate leaves gain nearest-owner context, generated ID suffixes stay out of primary text, and only an unavoidable normalized collision gets an ordinal.

Document-scoped editor panels use the existing UsdPreviewId session as their view-model key. Keep each open session's tree, canvas, authored Inspector data, joint/animation state, authored layer, and projection generation isolated; the Editor perspective opens the prim tree in the upper-left pane and keeps the Twin Browser in the separate lower-left pane, so document choice and authored hierarchy remain visible together. The prim tree consumes the full width of its pane and uses immediate structural collapse rendering; do not add a nested auto-shrinking scroll region or animated body that can paint stale outlines over neighbouring rows. All hierarchy rows use lunco_workbench_widgets::tree::{branch, leaf} and tree::{label, selectable_label}; depth-based initial expansion uses tree::default_open_at_depth. The Ports entity browser follows the same contract as the Twin, Entity, USD, Modelica, library, and telemetry trees. Raw CollapsingHeader is for non-tree sections, not a second tree implementation. The Prims rows reuse the Entities selectable-row presentation and expose preview-scoped Visible, Invisible, and Contour controls at the trailing edge. Those controls dispatch SetUsdPrimDisplayMode; the viewport projects the typed intent and the render binder owns wireframe rendering. Strip leading decorative bullet, circle, and square markers from the row's presentation label without changing the authored name. The viewport panel paints the session selected by the focused UsdPreviewViewId. Views share that session projection while keeping independent camera/render-target state. The viewport applies UsdPreviewRenderBudget to visible view targets (2048 px per axis, 4,194,304 pixels per view, and 8,388,608 visible pixels per frame by default) and leaves hidden cameras inactive. The generic ECS selection is a focused-session projection and must be restored from editor-owned session selection on focus changes. Dispatch edits with the session's explicit document, authored layer, and generation through the typed USD command surface. The full-width Prims tree owns a single vertical scroll surface; a newly selected primary row opens its ancestors and scrolls into view, while a stable selection leaves manual scrolling untouched. For path-based editor selection, use SelectUsdPrim with the focused preview; never resolve a USD path globally across live and preview projections.

The USD visual preview is an egui image over an offscreen camera, so its selection surface must publish image-local primary clicks with Shift/Ctrl modifier state. The editor selection owner maps that position through the focused camera and ray-casts only the preview's composed hierarchy, selecting the nearest non-empty UsdPrimPath ancestor. The viewport's exact image rect is also the sole geometry source for render-target sizing and gizmo handle mapping; do not use the surrounding toolbar-bearing panel rect. When a gizmo handle owns a primary drag, the preview camera's competing pan path is suppressed so the pointer remains in gizmo mode.

Scene click ownership is perspective-scoped. Read the shared lunco_interaction_core::SceneInteractionMode contract: View/simulation owns unmodified clicks for possession, while Shift/Ctrl clicks remain explicit selection or removal intents; editor-facing perspectives own unmodified clicks for selection and gizmos. Do not add a second per-crate mode flag or let global pointer observers infer ownership from the hit entity.

The workbench host is also the app-level semantic input surface. The shared contract is owned by lunco-control-core; editor actions such as Cancel must consume the shared UserIntent/InputBindingsSettings path, not a raw KeyCode or an assumption that an isolated USD preview has a local avatar. CancelIntent suppresses the action while egui owns keyboard focus, preserving text-field editing.

Avatar presentation has one wall-clock interaction cadence. Free-avatar port writes, locomotion, and camera look application belong to lunco_time::InteractionSchedule, not FixedUpdate or a direct Update pose writer. Render-frame pointer input may be buffered before that schedule, but the interaction step must consume it once alongside movement so pause and simulation rate changes cannot split orientation from translation.

For authored UI workflows, use the controller's InjectWindowInput command and the Rhai helpers in prelude/input.rhai. They enqueue typed key, pointer, and scroll events through the same Bevy aggregate WindowEvent and typed input messages produced by bevy_winit; picking, egui, focus, and semantic bindings therefore keep their normal owners. Rhai composes chords, clicks, drags, and workflow timing. Do not call a scene tool directly, synthesize a ScenePointer/intent event, or create a second UI automation command for a particular panel. Coordinates are logical primary-window pixels, and the command is local to the client window.

In View, a click on a vehicle part resolves through the enclosing authored ControlBinding/MobilityRoot before considering nested component input surfaces, so the vehicle remains the possession target. Standalone non-avatar input surfaces remain valid direct targets.

For interactive reusable-assembly authoring, follow the edit-usd-assembly runbook: the production window must remain headful and visible to the user, each coherent typed edit must be followed by a screenshot the agent inspects, and user feedback is a required checkpoint before the next material edit or save. Do not turn a panel into a direct file writer or a second session/state owner.

World-space vehicle trails are transient render presentation, not UI-owned state. Read solved wheel contacts after WheelRaycastResultsSet, retain bounded stroke history, and clear it on frame changes and SceneTeardown. A moving endpoint provides sub-spacing continuity; missing wheel support starts a new stroke, including airborne and inverted motion. Use the physical wheel's full width. DEM contacts resolve their ColliderTileOf owner and reuse streaming SurfaceCurveAnnotation segments painted on terrain fragments; ordinary static supports use the shared contact-plane ribbon builder. Do not derive tracks from root motion, visual wheel roll, controller input or authored routes. Inspect InspectVehicleTrail and exercise vehicle_trail_contact.rhai through the production API; verify the exact target scene visually. See the canonical motion trail contract for history, admission budgets and publication fencing.

Runtime-authored HTML/CSS surfaces

For a Twin-facing HUD, telemetry card, progress overlay, or simple runtime control that should change without a Rust rebuild, use the dedicated runtime-ui skill and docs/architecture/runtime-authored-ui.md.

This is a separate presentation path built on HUI/Flair. It uses the generic EngineExposures capability registry, the existing WorkbenchEguiHost camera, and the workbench's authoritative dock/pick geometry. The host is the persistent Bevy UI layer: it paints into the scene camera's shared cleared main texture, with its MSAA/HDR key synchronized to the active scene camera. This keeps UI state correct across camera replacement and perspective changes without a load-preserving accumulation target. It does not replace Panel/egui, create a second UI camera, or permit templates to mutate domain state. Use this skill for workbench panels and use runtime-ui for authored HTML/CSS surfaces; do not create a hybrid shim for one widget. The manifest controls the retained surface's outer rectangle: the runtime pins its minimum and maximum size to the resolved placement and clips overflow, while the authored CSS/profile must fit its contents inside that boundary. The lunco-ui::modal host is the canonical owner of queued modal outcomes, scrim, focus, Esc dismissal, and typed CloseModal dispatch. Base HUI does not provide those dialog semantics. The separate bevy_hui_widgets 0.6.0 crate offers primitive input, slider, and select mechanics, but it is not included in LunCoSim and does not define clipboard, validation, keyboard-navigation, accessibility, or modal semantics; do not route a rich editor through it without a new typed contract and acceptance tests.

For lander control cards, keep GNC identity and state on the existing authored USD boundary: resolve the column-zero lunco:ui:schemaNode, then read its ModelicaModel/SimComponent lifecycle and authored causal ports. Do not use the generic Autopilot actor as a lander GNC indicator, infer GNC from a prim name, or create a second status store. Add operator channels with LunCoTelemetryAPI on the guidance component so the compact card and the telemetry browser read the same SignalRegistry samples. The card must expose unavailable, compiling, ready, active, paused, handoff, and failure states; absence of an actuator sample is not permission to hide the authored surface. The runtime exposure producer must additionally scope card roots to the active SceneMountState root. Preview, additive, and outgoing scene entities are not operator HUD sources, and a repeated ECS projection of one composed (stage, prim path) must not fill a second manifest slot; report the duplicate at the projection owner and retain one active identity. Scene-derived exposure namespaces are hidden synchronously on SceneTeardown so deferred despawns cannot leave the outgoing card visible; the next active scene repopulates them, while retained application facts such as camera-status remain available.

The Modelica diagram's Show nets checkbox is the Connections legend's single workbench/egui presentation control, backed by the per-tab lunco-canvas::Canvas. It hides rendered and interactive connection edges without changing authored topology. Keep the legend and this dynamic graph control in the canvas panel; HUI/Rhai does not provide the dynamic list and graph-state contract it would require.

Canvas-owned diagram overlays must stay inside the owning leaf: direct painting uses the canvas clip rectangle, while an egui::Area uses constrain_to with the measured leaf rectangle. Non-interactive overlays do not claim pointer input, and modal dialogs use the shared lunco-ui::modal host.

Adding a Panel

rust
use lunco_workbench_core::{Panel, PanelCtx, PanelId, PanelSlot};
use lunco_workbench::WorkbenchAppExt;
use lunco_ui::prelude::*;

pub struct MyPanel;

impl Panel for MyPanel {
    fn id(&self) -> PanelId { PanelId("my_panel") }
    fn title(&self) -> String { "My Panel".into() }
    fn default_slot(&self) -> PanelSlot { PanelSlot::RightInspector }

    fn render(&mut self, ui: &mut egui::Ui, ctx: &mut PanelCtx) {
        // READ state — view-model resources / selected components via the
        // ctx, never raw `&mut World` scans, never mutate.
        if let Some(sel) = ctx.resource::<UiSelection>() {
            // ... read sel ...
        }

        // EMIT a typed command event — never mutate directly.
        if ui.button("Action").clicked() {
            ctx.trigger(MyCommand { /* ... */ });
        }

        // Other supported mutations are queued through the same context:
        // ctx.set_resource(MyResource::default());
    }
}

// Register in ui/mod.rs through the concrete shell:
// app.register_panel(MyPanel);

What NOT to Do

❌ Don't✅ Do
Mutate resources directly from UIctx.trigger(TypedCommand { .. }) (or ctx.defer), let observers handle it
Put UI code in lib.rs or outside ui/All UI in src/ui/ subdirectory
Use world.query() every frame for graphsUse WidgetSystem for O(1) cached queries
Copy a SignalRegistry history every graph paintUse the visualization-owned history fingerprint cache; copy only at the egui plot data boundary
Reproject every canvas edge every paintCache screen geometry by scene generation and viewport key; keep selection/tool state live
Walk the dock tree once per anchor groupPublish all slot anchors from one dock traversal
Build custom docking/themesUse lunco-workbench — it's already there

Discovering Existing Commands

Commands are typed structs marked #[Command], handled by observers marked #[on_command(TypeName)] (both from lunco_core). To find what commands exist:

bash
# Find all command observers
grep -rn "#\[on_command(" crates/

# Find all command struct definitions
grep -rn "#\[Command" crates/

# Find where a command is emitted from UI
grep -rn "\.trigger(" crates/

To add a new command: define a #[Command] struct + #[on_command(..)] observer in the relevant domain crate (see the test-via-api skill's "Add a command" section for the full pattern).

When to Use WidgetSystem

Use WidgetSystemUse raw queries
Queries same entities every frameReading 1-2 resources
10+ query fieldsSimple UI, minimal ECS
100+ rendered itemsInfrequent panels

File Structure

crates/lunco-ui/           ← mechanisms (WidgetSystem, typed commands, 3D UI)
crates/lunco-*/src/ui/     ← domain-specific panels

Wheel-track history uses VehicleTrailSettings.max_points_per_wheel (default 32768, about 16 km at half-metre spacing). Terrain annotations preserve retained history through adaptive spatial subdivision; they never shorten a lane because a root cell is crowded. Moving heads and retirement emit stable segment deltas; InspectVehicleTrail.annotation_edits exposes the consumed update count. Dirty-range uploads preserve the resident texture and its material bindings. Budget errors are terminal publication diagnostics. Validate long curved paths as well as live contact, and inspect actual GPU output after image capacity grows.

© 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/lunco-ui of LunCoSim/lunco-sim.

Open the folder on GitHubat commit 43f1301

Compare with similar skills

Lunco UI 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.

Lunco UI compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Lunco UI this skillLunCoSim/lunco-sim107—~10kAutomated safety check: PassApache-2.0
Web Artifacts Builderanthropics/skills180k40 repos~769Automated safety check: PassApache-2.0
React Doctormakeplane/plane61k12 repos~657Automated safety check: PassAGPL-3.0
Impeccablebestofjs/bestofjs3.1k26 repos~2.6kAutomated safety check: PassMIT
Figma Design System Builderwarpdotdev/warp65k2 repos~4.4kAutomated safety check: PassAGPL-3.0
Web Interface Guidelines Reviewervercel-labs/openreview1.7k97 repos~308Automated safety check: PassNone

Similar skills

  • Web Artifacts Builder

    anthropics/skills

    Official

    Builds multi-component claude.ai HTML artifacts as a small React, TypeScript and Tailwind project, then bundles it into one shareable HTML file.

    180k GitHub starsUsed in 40 repos~769 tokens
    Frontend & DesignAuto-check passed
  • React Doctor

    makeplane/plane

    Scans React code for lint, accessibility, bundle size and architecture issues, reports a health score and checks that changes do not lower it.

    61k GitHub starsUsed in 12 repos~657 tokens
    Frontend & DesignAuto-check passed
  • Impeccable

    bestofjs/bestofjs

    A skill your agent uses when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise improve a…

    3.1k GitHub starsUsed in 26 repos~2.6k tokens
    Frontend & DesignAuto-check passed
  • Builds or updates a design system in Figma from a codebase in ordered phases: discovery, variables and tokens, components, theming and documentation, with checkpoints.

    65k GitHub starsUsed in 2 repos~4.4k tokens
    Frontend & DesignAuto-check passed
  • Web Interface Guidelines Reviewer

    vercel-labs/openreview

    Official

    Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my…

    1.7k GitHub starsUsed in 97 repos~308 tokens
    Frontend & DesignAuto-check passed
  • Tailwindcss Development

    anonaddy/anonaddy

    Always invoke when the user's message includes 'tailwind' in any form.

    4.9k GitHub starsUsed in 10 repos~865 tokens
    Frontend & DesignAuto-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 Lunco UI

What does Lunco UI do?

LunCoSim UI architecture and panel implementation patterns. An agent skill from LunCoSim/lunco-sim. Lunco UI is an agent skill from LunCoSim/lunco-sim. LunCoSim UI architecture and panel implementation patterns.

When should I use Lunco UI?

Lunco UI fits situations like: working on any user interface for the LunCoSim solar system simulation — adding panels; building dashboards; creating inspectors; telemetry displays.

How do I install Lunco UI in Claude Code?

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

How do I install Lunco UI in Codex?

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

Can I use Lunco UI 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 lunco-ui -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/lunco-ui, .gemini/skills/lunco-ui, .github/skills/lunco-ui and .opencode/skills/lunco-ui in your project.

What does Lunco UI need to run?

SKILL.md names no scripts, command-line tools or credentials: Lunco UI is instructions for the agent only. Our summary lists: Python 3.

Does Lunco UI 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 Lunco UI 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 Lunco UI use?

Lunco UI 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 Lunco UI use?

About 10k tokens (SKILL.md is roughly 42k 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 Lunco UI?

Skills that share tags, products or a category with Lunco UI: Web Artifacts Builder (anthropics/skills, 180k stars), React Doctor (makeplane/plane, 61k stars), Impeccable (bestofjs/bestofjs, 3.1k stars) and Figma Design System Builder (warpdotdev/warp, 65k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Lunco UI?

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.