UI shell

AXIS chrome: topbar, watchlist, status bar, settings, plugin manager, logs, and layout chrome around the chart.

This page

UI shell

The shell is the non-canvas chrome: navigation of axes, market selection, modals, and status. It binds human gestures to store + plugins without owning calculation.

AXIS topbar groups: market, venue, engine, panels, Studio Command palette filtering theme commands

Abstract

ComponentPathRole
Topbarui/Topbar.tsxAxes pickers, Load/Run/Live, theme, modals
Watchlistui/Watchlist.tsxSymbols, quotes, click-to-load
StatusBarui/StatusBar.tsxStatus, engine/storage badges, trade snippet
StudioHostui/studio/StudioHost.tsxFull-page Runtime / Wire / Settings / Workers / Plugins
SettingsPageui/settings/SettingsPage.tsxAppearance, chart, live, keys, editor, theme
PluginsPageui/plugins/PluginsPage.tsxCatalog / install / library
WirePageui/wire/WirePage.tsxCompose-recipe wiring (source × stream × engine × storage × dataset)
SystemLogsui/SystemLogs.tsxRing buffer of store.logs
ResultsPanelui/ResultsPanel.tsxBottom drawer (see results doc)
Iconsui/icons.tsxLucide wrappers
ResizeHandleui/ResizeHandle.tsxPanel widths/heights

Conceptual model

Diagram

Rendering…

Topbar responsibilities

Grouped left→right (axis-tb-group, data-tb-group):

GroupContents
brandLogo + AXIS
marketSymbol, Interval, Type (TopbarField), Compare
dataSource (+ CSV upload), Load, Reload (icon-only)
computeEngine, Stream, Run, Live, Replay
layoutMulti-chart layouts + recipes
panelsList, Editor, Library, Data (Source Manager), Scripts, Layers, Alerts, Data window, Inputs, Results
systemStudio (Runtime / Wire / Settings / Workers / Plugins), Theme (margin-left: auto)
ControlEffect
Symbol / intervalStore + Load (Enter / blur reload)
Source / Stream / EnginesetActivePlugin + side effects
Chart typesetChartType (candles, HA, …)
CompareSecond-symbol overlay
Load / ReloadOne-shot historical fetch → chart
Data panelData Source Manager — background deep history
Scripts panelApplied indicators/strategies list
RunEditor doc → runAndApply; accent only while status === 'running'
Livemultiplex start/stop (stops Replay)

Chart themes

Settings / command palette expose ten curated presets (void dark/light, classic, mono, obsidian, graphite, pacific, dusk, porcelain, parchment). High-end soft surfaces — not neon high-contrast. See src/theme/presets.ts. | Replay | Bar replay over loaded bars | | Panel toggles | isPanelOpen / dual-write chrome | | Settings / Plugins | Modal open | | Detach editor | Bridge + popout |

Integrated labels: ui/TopbarField.tsx (.axis-tb-field*).
catalogTick forces memo re-list when plugins install/remove.

Command palette

Ctrl/Cmd+KCommandPalette + command-registry.ts: panels, theme, layouts, Run, symbol focus, editor toggles (ruler, debug, pins, profiler), jump to line, git push/pull, save library. Palette entries render any recorded shortcut chords.

Keyboard shortcuts

Global chord dispatch hub (src/ui/shortcuts/): capture-phase handling with a dialog-skip guard so shortcuts never fire while a modal is open. Wired to three scopes:

  • App-level — palette, Run, panel toggles, replay, layouts
  • Chart — keymap routed through the dispatch hub (cancel draft, layouts, replay)
  • Editorsrc/editor/cm-line-ops.ts Prec.high line ops: duplicate line, toggle comment, indent/unindent, delete line

Recorder and discovery:

  • Recorder: Settings → Keyboard → record a chord; per-user overrides persist on the app store
  • Shortcuts modal: lists default bindings with live rendering
  • Conflict flags: scope-aware (app.escape vs chart.cancel-draft layer by design — no false conflict)

Alerts panel

Dockable Alerts (src/alerts/* + AlertsPanel.tsx): local-first book for price, % change, drawing touch, indicator plots, Pine alert() / alertcondition(), and on-chain kinds. Delivery: browser Notification, optional HTTPS webhook, optional L2 webhook. Live ticks evaluate price/drawing/plot kinds; strategy/indicator runs evaluate Pine alert() events (last bar). Continuous server-side arming is not required for session use.

Workspace snapshots

storage/workspace-snapshot.ts + optional chrome menus capture layout/plugin prefs for restore (distinct from OHLCV — bars still re-fetch on Load).

Panel docks (side-by-side)

Left/right docks with 2+ open panels lay out horizontally (row), not stacked under each other:

  • Example: Indicators left of Editor on the right strip
  • Column width = sum of panel widths (capped)
  • Each panel keeps its own width (resize handle on chart-facing edge)
  • Bottom dock still stacks vertically

See ui/panels/dock-layout.ts, FloatableShell.tsx.

Mobile shell (phones / tablets)

src/ui/mobile/MobileShell.tsx + src/ui/responsive.ts — reactive phone | tablet | desktop mode from viewport + pointer: coarse (desktop ≥1024px is unchanged):

  • Phones (≤767px): compact header (brand · venue · symbol · interval) + bottom tab bar (Chart · Panels · Editor · Studio · More) replace the Topbar/StatusBar. Panels and More open as nav overlays.
  • Panel sheets: docked/floating panels render as full-viewport sheets — one at a time, dismiss via swipe-down on the title bar. Desktop panel geometry is bypassed, never overwritten, so phone↔desktop switches preserve layouts. Phones boot chart-first.
  • Force-single chart: 2H/2V/4 layouts collapse to the active slot with a slot-switcher chip row; other slots stay preserved in store.chartLayout.
  • Tablets (768–1023px): desktop shell with a horizontally scrollable topbar.
  • Dialogs become bottom sheets; safe-area insets, 100dvh root, ≥44px touch targets.

Watchlist

Watchlist rail with BTCUSDT selected and live 24h quotes
  • Default universe includes majors (BTCUSDT, …)
  • refreshSec clamped 5–120
  • Source-aware labels (e.g. CSV mode)
  • Click sets symbol and loads through active source

Status bar

Connection HUD: LIVE, tick, engine, and source/stream/storage chips

Single row:

  • Left — Connection HUD (ConnectionHud, data-testid="axis-connection-hud")
    • LIVE badge (off / connecting / live / err)
    • Tick pulse (fixed-width price + age; ping does not resize layout)
    • Engine chip (id · interpret/compile · latency)
    • Plane chips SRC / STR / ENG / STO with transport badges WS / REST / LOCAL / BROKER
    • Source↔stream pairing warning when mismatched
  • Rightstatus / statusMessage, strategy snippet, log toggle, bar/ind/pane counts

Telemetry is ephemeral (store.telemetry); HUD compact mode and live prefs persist via settings.

Live settings (Settings dialog)

SettingDefaultEffect
Enable live streamonlive.preferAfterLoad → multiplex after Load and on boot when bars exist
Indicator re-runevery-tickor bar-close only
Compact connection HUDoffhide plane chips

Logs

System Logs strip

  • appendLog(level, message, source)
  • Cap MAX_LOGS (500)
  • Not persisted
  • Boot messages, pyodide ready, live errors

Scriptlogs & Profiler

Script log.* output and editor line-timing live on a separate path — see Debugging. Controls sit on the editor header (not the topbar) and do not write into store.logs.

Theming

Settings → Theme: Void Dark preset and chart color tokens Switching chart theme presets

store.themedocument.documentElement data-theme (dark | light). Void dark is default product aesthetic. Settings → Theme picks a curated preset (void / classic / mono / boutique) and edits chart tokens live.

Accessibility / test hooks

E2E selectors use data-testid on critical controls (axis-btn-load, axis-manager, …) per TESTING.md.

Invariants

  1. Shell never calls Python.
  2. Plugin lists always come from registry facades (listSources, …).
  3. Modal settings persist only on Save (not on every keystroke of endpoint field until save).
  4. Live off leaves historical bars intact.

Failure modes

SymptomShell-side check
Pickers emptyBuiltins not registered at boot
Live ignores clickStream none or multiplex error in logs
Settings probe failsNetwork / CORS—not topbar bug

See also