Web Artifacts Builder
anthropics/skills
Builds multi-component claude.ai HTML artifacts as a small React, TypeScript and Tailwind project, then bundles it into one shareable HTML file.
LunCoSim UI architecture and panel implementation patterns. An agent skill from LunCoSim/lunco-sim.
$ npx skills add LunCoSim/lunco-sim --skill lunco-ui -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install LunCoSim/lunco-sim lunco-ui --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ 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-srcUse ~/.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/
Install the "lunco-ui" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/lunco-ui into .claude/skills/lunco-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "lunco-ui", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/LunCoSim/lunco-sim/tree/main/skills/lunco-uiType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add LunCoSim/lunco-sim --skill lunco-ui -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install LunCoSim/lunco-sim lunco-ui --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/lunco-ui .agents/skills/lunco-ui && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "lunco-ui" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/lunco-ui into .agents/skills/lunco-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "lunco-ui", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add LunCoSim/lunco-sim --skill lunco-ui -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install LunCoSim/lunco-sim lunco-ui --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/lunco-ui .cursor/skills/lunco-ui && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "lunco-ui" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/lunco-ui into .cursor/skills/lunco-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "lunco-ui", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/LunCoSim/lunco-sim.git --path skills/lunco-ui--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add LunCoSim/lunco-sim --skill lunco-ui -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install LunCoSim/lunco-sim lunco-ui --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/lunco-ui .gemini/skills/lunco-ui && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "lunco-ui" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/lunco-ui into .gemini/skills/lunco-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "lunco-ui", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install LunCoSim/lunco-sim lunco-uiInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add LunCoSim/lunco-sim --skill lunco-ui -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/lunco-ui .github/skills/lunco-ui && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "lunco-ui" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/lunco-ui into .github/skills/lunco-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "lunco-ui", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add LunCoSim/lunco-sim --skill lunco-ui -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install LunCoSim/lunco-sim lunco-ui --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/lunco-ui .opencode/skills/lunco-ui && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "lunco-ui" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/lunco-ui into .opencode/skills/lunco-ui/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "lunco-ui", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
lunco-uiLunCoSim 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. 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.
5 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 43f1301. It shows what the files ask for, not the result of running them.
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.
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.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
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.
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.
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.
The full file from LunCoSim/lunco-sim at commit 43f1301, republished under its Apache-2.0 licence (© LunCoSim). 5,255 words, ~10,464 tokens.
.claude/skills/lunco-ui/SKILL.md (or your agent's skills folder).Before implementing ANY UI, read:
crates/lunco-ui/ARCHITECTURE.mdIt explains the full architecture, step-by-step panel integration guide, and design decisions. This skill is a quick-reference summary.
src/ui/ — domain crates have src/ui/mod.rs exporting a *UiPlugin. UI code never lives outside ui/ directories.#[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.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.AGENTS.md §4.1 for the four-layer architecture.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.
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.
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.
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);| ❌ Don't | ✅ Do |
|---|---|
| Mutate resources directly from UI | ctx.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 graphs | Use WidgetSystem for O(1) cached queries |
| Copy a SignalRegistry history every graph paint | Use the visualization-owned history fingerprint cache; copy only at the egui plot data boundary |
| Reproject every canvas edge every paint | Cache screen geometry by scene generation and viewport key; keep selection/tool state live |
| Walk the dock tree once per anchor group | Publish all slot anchors from one dock traversal |
| Build custom docking/themes | Use lunco-workbench — it's already there |
Commands are typed structs marked #[Command], handled by observers
marked #[on_command(TypeName)] (both from lunco_core). To find what
commands exist:
# 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).
Use WidgetSystem | Use raw queries |
|---|---|
| Queries same entities every frame | Reading 1-2 resources |
| 10+ query fields | Simple UI, minimal ECS |
| 100+ rendered items | Infrequent panels |
crates/lunco-ui/ ← mechanisms (WidgetSystem, typed commands, 3D UI)
crates/lunco-*/src/ui/ ← domain-specific panelsWheel-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
Just SKILL.md in skills/lunco-ui of LunCoSim/lunco-sim.
Open the folder on GitHubat commit 43f1301
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.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Lunco UI this skillLunCoSim/lunco-sim | 107 | — | ~10k | Automated safety check: Pass | Apache-2.0 | |
| Web Artifacts Builderanthropics/skills | 180k | 40 repos | ~769 | Automated safety check: Pass | Apache-2.0 | |
| React Doctormakeplane/plane | 61k | 12 repos | ~657 | Automated safety check: Pass | AGPL-3.0 | |
| Impeccablebestofjs/bestofjs | 3.1k | 26 repos | ~2.6k | Automated safety check: Pass | MIT | |
| Figma Design System Builderwarpdotdev/warp | 65k | 2 repos | ~4.4k | Automated safety check: Pass | AGPL-3.0 | |
| Web Interface Guidelines Reviewervercel-labs/openreview | 1.7k | 97 repos | ~308 | Automated safety check: Pass | None |
anthropics/skills
Builds multi-component claude.ai HTML artifacts as a small React, TypeScript and Tailwind project, then bundles it into one shareable HTML file.
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.
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…
warpdotdev/warp
Builds or updates a design system in Figma from a codebase in ordered phases: discovery, variables and tokens, components, theming and documentation, with checkpoints.
vercel-labs/openreview
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my…
anonaddy/anonaddy
Always invoke when the user's message includes 'tailwind' in any form.
LunCoSim/lunco-sim
Generate concise LunCoSim nightly GitHub release notes with platform downloads, installation guidance, an AI-agent mission prompt, and a changelog link.
LunCoSim/lunco-sim
Build or repair a reusable scene component through a live LunCoSim Editor session.
LunCoSim/lunco-sim
Build or review a componentized LunCoSim USD assembly with a realistic, dimensionally checkable presentation.
LunCoSim/lunco-sim
Author and review LunCoSim behavioral, asset-backed, component, mission, visual, and requirements-verification tests.
LunCoSim/lunco-sim
Create, extend, register, or debug a reusable LunCoSim Rhai tool library for live USD authoring, component linting, inspection, or test support.
LunCoSim/lunco-sim
Author an interactive tutorial, guided lesson, onboarding flow, coach-mark tour, or objectives checklist in LunCoSim.
Categories
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.
Lunco UI fits situations like: working on any user interface for the LunCoSim solar system simulation — adding panels; building dashboards; creating inspectors; telemetry displays.
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.
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.
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.
SKILL.md names no scripts, command-line tools or credentials: Lunco UI is instructions for the agent only. Our summary lists: Python 3.
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.
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.
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.
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.
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.
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.