Skip to main content
Extend Avala’s viewer with custom visualization panels using @avala-ai/panel-sdk. A panel is a small TypeScript project: you write lifecycle hooks, subscribe to MCAP topics, and draw. Panels run sandboxed — inside an iframe with an opaque origin and a strict Content Security Policy — and talk to the viewer over a versioned, typed protocol, so they stay stable across viewer releases.
Preview — not yet published to npm. @avala-ai/panel-sdk (0.1.x) lives in the Avala monorepo and is not on the npm registry yet, so the npx flow below does not work today — build the CLI from source instead (see Building the CLI from source). Running a panel inside Mission Control depends on the panel host, which is in active development — until it ships, build and preview against the local dev harness (avala-panel serve). Distribution (pack / install) and the marketplace are on the roadmap; see Distribution and Marketplace.

Building the CLI from source

Until the package is published, build it from the monorepo once:
Then invoke it directly (substitute this for npx avala-panel / avala-panel in the commands below):
init notices it is running from a source checkout and points the new panel’s @avala-ai/panel-sdk dependency at that checkout, so npm install and npm run build work without the package being on the registry. After publication, init emits the normal published version range instead — nothing in your panel changes.

Getting Started

Scaffold a new panel project:
This creates a panel project with the following structure:
npm run build compiles src/ into a self-contained dist/index.js. npm run serve starts the local dev harness at http://localhost:5180: it loads your built panel in a sandboxed iframe and feeds it a synthetic recording (a moving pose on /robot/pose, a draining battery on /diagnostics/battery), so you can see your panel react to real message flow with no server, no login, and no MCAP file. Run npm run watch in a second terminal to rebuild on save.

Panel Lifecycle

You pass an object implementing lifecycle hooks to definePanel. The runtime performs the handshake with the host, validates your settings, and calls your hooks — you never touch postMessage.

Lifecycle Order

When a panel is first added to the layout:
  1. onInit — set up your DOM elements and state
  2. onSettingsChange — called immediately with the initial settings
  3. onSeek — called with the current timeline position
During playback, onMessage is called for every incoming message in chronological order. When the user scrubs the timeline, onSeek is called first, followed by onMessage for messages in the new range.

Data Access

Declare the topics you want in topics, and receive typed messages through onMessage. Each MessageEvent carries topic, logTime (nanoseconds since recording start), schemaName, and the decoded data.

Basic Example

Multiple Topics

List several topics and route on message.topic:

Dynamic Subscription

Add or drop subscriptions at runtime — for example, in response to a settings change (this is exactly what the Plot example does):

Context API

The PanelContext passed to every hook exposes the panel DOM, settings, state, and viewer controls.
state is not persisted across sessions — use it for transient things like canvas references. For persistent configuration, use settings.

Panel Settings

Declare settings and the host renders a form; values are validated against your schema before your hooks see them. An invalid value falls back to the previous valid value (or the default) — your panel never receives an out-of-schema value.

Permissions

Panels are deny-by-default. A panel declares the capability scopes it needs in panel.yml; the host grants only those. Each scope carries a risk tag shown to whoever installs the panel.
Validate your manifest at any time:

Security Model

Panels run in an iframe with sandbox="allow-scripts" and no allow-same-origin, so panel code executes at an opaque origin and cannot reach the viewer’s cookies, storage, or DOM. A Content Security Policy blocks external hosts and network access (connect-src 'none'): your panel receives its data through the protocol, not over the wire. Messages are authenticated by protocol shape and frame identity, and the host↔panel protocol is semver’d — the viewer refuses to run a panel whose major protocol version it does not understand. The sandbox contains a panel from the viewer’s own surfaces, but it is not a complete data-exfiltration boundary (a panel can still leak data it was given via navigation). The viewer therefore treats permissions and panel review as the data boundary: panels are deny-by-default, are hosted on an isolated origin, and should be granted data scopes only after review. Grant annotations:write and other high-risk scopes deliberately.

Building

This produces a self-contained dist/index.js — the module the sandboxed iframe loads. Because the SDK is bundled in, there is nothing else to resolve at runtime.

Distribution

Distribution and org-scoped install are in development. The pack command below already produces the install artifact; the Mission Control install flow and marketplace are being built next.
Package your built panel for distribution:
This writes <id>-<version>.avala-panel.json — a self-contained bundle carrying the manifest and every module the build emitted: the entry plus any code-split chunks (tsup splits ESM output by default when a panel uses dynamic import()). It is the input to the (in-development) GitHub-install flow and, later, the marketplace. Panels follow semantic versioning, read from panel.yml.

Marketplace

The marketplace is on the roadmap (ROADMAP 3.1). The panel.yml manifest already carries the fields a marketplace needs — publisher, a signature slot, and declared permissions — so panels built today are forward-compatible with it.

Example: Plot Panel

The plot-panel example (shipped in the SDK repo) plots a numeric value from any topic over time. It demonstrates the topic-picker pattern and runtime subscription:
See the full plot-panel and trajectory-panel sources in the SDK repository’s examples/ directory.

Next Steps

Panel Types

Explore the built-in panel types available in the MCAP viewer.

MCAP Viewer

Learn about the multi-sensor viewer that hosts custom panels.

Fleet Dashboard

Build fleet-level dashboards that incorporate custom panel visualizations.