agentleFS
elodin-syselodin-sys/elodin/.cursor/skills/elodin-editor-dev/SKILL.md

elodin-editor-dev

Skill553 starsChanged 5 months agoApache-2.0View on GitHub

Contribute to the Elodin Editor, the 3D viewer and graphing tool. Use when editing files in libs/elodin-editor/ or apps/elodin/, working on the Bevy/Egui UI, modifying viewport rendering, telemetry graphs, video streaming, KDL schematics, or the command palette.

  • Deletes or force-pushes

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use cargo watch for fast iteration on UI changes

    line 172
  2. Very specific:

    Test with examples/three-body/main.py for a lightweight simulation

    line 174
  3. Distinctive:

    Prefer Bevy's native window screenshot path over OS screen capture.

    line 180

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Elodin Editor Development

The Elodin Editor is a 3D visualization and telemetry graphing tool built with Bevy (ECS game engine) and Egui (immediate-mode UI). It connects to Elodin-DB via Impeller for real-time data.

Running

# Standard
cargo run --bin elodin editor examples/three-body/main.py

# With hot-reload on editor code changes (requires cargo-watch)
cargo watch --watch libs/elodin-editor \
    -x 'run --bin elodin editor examples/three-body/main.py'

# Connect to a running database instead of a simulation
cargo run --bin elodin editor 127.0.0.1:2240

Environment Variables

VariableDefaultPurpose
ELODIN_ASSETS./assetsDirectory for meshes, images, GLB files
ELODIN_KDL_DIR. (cwd)Directory for .kdl schematic files
ELODIN_GPUautoNix shell GPU path (nvidia / mesa / nvk). Set before nix develop.
ELODIN_GPU_PANICunsetSet to true to force the GPU-not-found panic and print the ELODIN_GPU=… nix develop help.
ELODIN_H264_ENCODERautoLive sensor_camera format="h264": auto tries NVENC / VideoToolbox then OpenH264; cpu forces OpenH264; any other value is an FFmpeg encoder name (h264_nvenc, …). h264_vaapi is not supported.

Cargo features

Optional features declared in libs/elodin-editor/Cargo.toml (re-exported by apps/elodin/Cargo.toml):

  • inspector: adds the bevy-inspector-egui runtime entity inspector.
  • debug: enables BigSpace debug diagnostics.
  • tracy: enables Tracy profiling (see .cursor/skills/elodin-tracy/SKILL.md).

Enable with cargo run -p elodin --features "<list>" -- editor .... BigSpace is always enabled; the editor has no fallback spatial mode.

Source Layout

The editor is split across two crates:

libs/elodin-editor/ — Core library

src/
├── lib.rs              # Plugin registration, app setup
├── run.rs              # Main run loop and Bevy app builder
├── object_3d.rs        # 3D object spawning from KDL schematics
├── vector_arrow.rs     # Vector visualization (force/velocity arrows)
├── offset_parse.rs     # EQL viewport formula parsing
├── icon_rasterizer.rs  # Icon rendering
├── iter.rs             # Iterator utilities
├── ui/                 # Egui UI layer
│   ├── mod.rs          # Top-level UI orchestration
│   ├── tiles.rs        # Tiled panel layout system
│   ├── tiles/sidebar.rs
│   ├── inspector/      # Component inspector panels
│   │   ├── mod.rs
│   │   ├── entity.rs   # Entity property inspector
│   │   ├── viewport.rs # Viewport panel
│   │   ├── graph.rs    # Graph panel configuration
│   │   ├── dashboard.rs
│   │   ├── monitor.rs
│   │   ├── object3d.rs # 3D object inspector
│   │   └── ...
│   ├── plot/           # Telemetry graph rendering
│   │   ├── mod.rs
│   │   ├── data.rs     # Data fetching and buffering
│   │   ├── gpu.rs      # GPU-accelerated plot rendering
│   │   ├── widget.rs   # Egui plot widget
│   │   └── state.rs    # Plot state management
│   ├── plot_3d/        # 3D plot visualization
│   ├── schematic/      # KDL schematic loading and rendering
│   │   ├── mod.rs
│   │   ├── load.rs     # KDL file parsing
│   │   └── tree.rs     # Schematic tree view
│   ├── timeline/       # Playback timeline
│   │   ├── mod.rs
│   │   ├── timeline_controls.rs
│   │   └── timeline_slider.rs
│   ├── command_palette/ # Command palette (Ctrl+P)
│   ├── video_stream.rs  # Live video rendering
│   ├── theme.rs         # Color theme
│   ├── colors/          # Color system and presets
│   └── ...
└── plugins/            # Bevy plugins
    ├── mod.rs
    ├── view_cube/      # 3D orientation cube
    ├── camera_anchor/  # Camera tracking and anchoring
    ├── gizmos/         # Transform gizmos
    ├── navigation_gizmo/
    ├── editor_cam_touch/ # Touch input for camera
    ├── asset_cache/    # Asset caching
    ├── env_asset_source/ # ELODIN_ASSETS integration
    ├── web_asset/      # Web asset loading
    └── logical_key/    # Keyboard input handling

apps/elodin/ — CLI binary

The main entry point that ties together the editor with nox-py, s10, and Impeller. Handles CLI argument parsing (elodin editor, elodin run, etc.).

Key Subsystems

Bevy Plugin Architecture

The editor registers as a set of Bevy plugins. Each feature area (view cube, camera, gizmos) is a self-contained plugin with its own components, systems, and resources. New features should follow this pattern.

Egui UI Layer

The ui/ module contains all immediate-mode UI rendering. Egui runs inside Bevy via bevy_egui. The tile-based layout system (ui/tiles.rs) manages panel arrangement (viewports, graphs, inspectors).

Telemetry cache (SeriesStore)

Strategy: cache only what the UI uses. Full history per subscribed ID (no time-based SeriesStore GC). Menus use metadata/EqlContext, not store keys. Playback/scrub never wait on backfill — project whatever is already in RAM.

DB ──► allowlisted GetTimeSeries backfill + live ──► TelemetryCache (SeriesStore)
                                                      ├─► project SelectedTimeRange → LineTree → GPU
                                                      └─► apply_cached_data @ playhead → 3D / inspectors
Metadata ──► EqlContext ──► ADD COMPONENT / palettes (full list)
PieceWhere
Allowlist + reclaimui/plot/data.rs → update_series_fetch_priority
Backfill / live filterimpeller_bevy → backfill_cache, SeriesFetchPriority
Scheduleeditor + headless: priority then backfill_cache (lib.rs, headless.rs)

Allowlist (SeriesFetchPriority.high): enabled graph lines; Line3d / object_3d EQL (including thruster intensity EQL for particle plumes); monitors; viewport pos/look_at/up EQL; vector_arrow EQL; path-registry adapter pairs (*.world_pos, …); sensor-camera {entity}.world_pos. Empty ⇒ no SeriesStore I/O. Leaving an ID drops it from RAM. Any new live consumer must extend this allowlist or it will be blank/stale. Adapter leaf match is case-sensitive (WORLD_POS ≠ world_pos).

Plots: LineTree is a visible-window projection only (sliding GC here ≠ SeriesStore). Tip/LAST_* fetches quantized (~100 ms) + prefetch margin; also immediate visible-window prefetch so tip fills before begin→end backfill. Do not clear a LineTree when the store has zero samples in-window (unless camera range moved). ≤30 s (SHORT_WINDOW_ACCURACY_MICROS): GPU step = 1, skip Hamann–Chen (INDEX_BUFFER_LEN = 131072 in ui/plot/gpu.rs, sized for ~4 kHz × 30 s). Longer windows: GPU stride on clip; CPU project stride only for >10 min.

Headless: separate process, separate store — same priority + backfill or sensor_view poses freeze while effects still animate.

Do not: gate menus on SeriesStore keys; wait on SeriesStoreLoadState.complete for scrub; reintroduce full-metadata backfill; time-GC SeriesStore without fixing jump-to-start/scrub holes first.

KDL Schematics

KDL files define 3D objects and viewport configurations. The loading pipeline:

  1. ui/schematic/load.rs — Parses .kdl files
  2. object_3d.rs — Spawns Bevy entities (meshes, GLB models, shapes)
  3. offset_parse.rs — Evaluates EQL viewport formulas (rotate, translate)

Video Streaming

ui/video_stream.rs handles live H.264/AV1 video decoding and rendering as textures in the 3D viewport. Uses the video-toolbox crate on macOS for hardware acceleration.

Dependencies

Key crates used in the editor:

CratePurpose
bevyECS game engine, 3D rendering, windowing
bevy_eguiEgui integration for Bevy
eguiImmediate-mode UI framework
impeller-bevyBevy plugin for Impeller telemetry
arrowArrow data format for time-series
eqlElodin Query Language parser
noxSpatial math types

Development Tips

  • Use cargo watch for fast iteration on UI changes
  • The editor hot-reloads KDL schematics on file change
  • Test with examples/three-body/main.py for a lightweight simulation
  • GPU plot rendering is in ui/plot/gpu.rs — changes here affect all telemetry graphs
  • The command palette (ui/command_palette/) is the entry point for user actions

Screenshot-driven design, build, and test

Prefer Bevy's native window screenshot path over OS screen capture. It captures the full editor window (3D viewports and egui chrome) without macOS Screen Recording permissions, and works the same in local iteration and CI-style scripts.

Harness

PiecePath / env
Pluginlibs/elodin-editor/src/plugins/screenshot.rs (EnvScreenshotPlugin)
Batch scriptscripts/ci/screenshot_examples.sh <out-dir> [example …]
ActivateELODIN_SCREENSHOT=/abs/path/out.png
Delay before captureELODIN_SCREENSHOT_DELAY (seconds; default 8; use 12–20 for heavy examples)
Exit after writeELODIN_SCREENSHOT_EXIT=1 (required for bounded runs)
Sim timeELODIN_SCREENSHOT_TIME (seconds after the recording's first sample; holds the playhead there, paused; the delay is then settle time)
TabELODIN_SCREENSHOT_TAB (a named split's title; warns at capture when no tab has it)

The plugin queues Screenshot::primary_window(), waits until the PNG is non-empty on disk (async GPU readback), then sends AppExit::Success when exit is requested. Do not kill the process on a timer alone — that tears down the render thread mid-readback and yields a missing/empty PNG.

Streamed terrain has no timeout during interactive editor startup. Fixed-path automation is deliberately stricter: set ELODIN_CESIUM_CAPTURE_TIMEOUT to bound terrain warm-up; load errors and timeouts exit without a screenshot.

One-shot capture (design / verify a change)

# Release binary is much faster for visual loops
cargo build -p elodin --release

rm -f /tmp/editor-shot.png
ELODIN_SCREENSHOT=/tmp/editor-shot.png \
ELODIN_SCREENSHOT_DELAY=12 \
ELODIN_SCREENSHOT_EXIT=1 \
  ./target/release/elodin editor examples/ball/main.py

Then Read the PNG in the agent (vision) and check concrete UI/scene facts — e.g. status-bar RAM Usage: X.Y GB (not N/A / not stuck at 0.0), trajectory line present, view cube visible, graph panels populated. OCR (tesseract) is optional backup for status-bar text.

Batch regression (examples gallery)

# Default set: ball three-body drone rc-jet apollo-lander video-stream
#             sensor-camera cube-sat voyager geo-frames
scripts/ci/screenshot_examples.sh /tmp/elodin-shots ball three-body drone

Env overrides: ELODIN_BIN, ELODIN_SCREENSHOT_DELAY (script default 20), SCREENSHOT_WATCHDOG (default 180). One editor at a time; each run has a watchdog so a hung capture cannot block forever.

Workflow for UI / rendering changes

  1. Baseline — screenshot the affected example(s) before the change into /tmp/elodin-shots-baseline/.
  2. Implement — keep the change scoped; rebuild elodin (release for visual checks).
  3. Compare — re-screenshot into /tmp/elodin-shots-after/ and Read both PNGs. Assert the intended delta and that unrelated chrome (timeline, status bar, view cube) still looks healthy.
  4. Stress the failure mode — if the bug was GPU/render-path specific (e.g. FPV + HDR + plot_3d), pick the example that exercises that path (rc-jet, sensor-camera, …), not only ball.
  5. Stale DBs — if an example refuses to start with DB/time-travel errors, delete its on-disk DB (e.g. rm -rf examples/voyager/dbs/voyager, rm -rf video-stream-db) and retry. Do not dig into GStreamer until a clean DB still fails.

Gotchas

  • Port 2240 — live elodin editor / elodin run binds the sim DB; do not parallelize with monte-carlo or another editor. Group-kill leftovers before the next case.
  • RAM gauge — status-bar RSS is read via platform APIs in ui/status_bar.rs (not Bevy SystemInformationDiagnosticsPlugin). On macOS Bevy's sysinfo is built with apple-app-store and always reports 0 GiB for the current process.
  • video-stream — clear ./video-stream-db if the editor hangs or video never appears. elodinsink / x264enc / srtsrc come from nix develop or nix develop .#run (GST_PLUGIN_PATH). Do not prepend cargo target/release (libelodin makes gst-plugin-scanner abort the scan on GStreamer 1.26).
  • voyager — needs SPICE kernels under examples/voyager/nasa_spice_data/ and a clean DB dir after interrupted runs.
  • nix develop — prefer it for CI-parity builds; for a tight screenshot loop, a warm cargo build -p elodin --release outside a full env rebuild is fine once the toolchain is already installed.

When to use which example

GoalExample
Lightest viewport + trail + vector labelball
Multi-body + graph panelsthree-body
GLB + joint animationdrone
FPV / plot_3d / aerorc-jet
SITL + thrusters / descentapollo-lander
H.264 tile in UIvideo-stream
GPU sensor cameras / frustasensor-camera
Terrain / geo framesgeo-frames
Spacecraft + MEKF graphscube-sat

Key References

  • Bevy Tips (ECS): ../bevy/SKILL.md
  • Editor QA plan: ../qa-test-plan/elodin-editor/test-plan.md
  • Editor README: apps/elodin/README.md
  • KDL schematic syntax: docs/public/content/reference/schematic.md
  • Command palette reference: docs/public/content/reference/command-palette.md

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.