Deep panel infrastructure knowledge: PanelExtensionAdapter, RenderState incremental building, PanelExtensionContext API, pauseFrame backpressure, panel lifecycle, and the PanelAPI internal hooks.
71%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./.github/skills/panel-extension-api/SKILL.mdThe panel infrastructure connects panels to the MessagePipeline and manages their lifecycle.
MessagePipeline (zustand store)
│
▼
PanelExtensionAdapter (per-panel bridge)
│ ├── buildRenderState() (incremental state building)
│ ├── pauseFrame() (backpressure mechanism)
│ └── PanelExtensionContext (API exposed to panel code)
▼
Panel Component (renders data)| File | Role |
|---|---|
packages/suite-base/src/components/PanelExtensionAdapter/PanelExtensionAdapter.tsx | React component, manages panel lifecycle + subscriptions |
packages/suite-base/src/components/PanelExtensionAdapter/renderState.ts | Incrementally builds RenderState from pipeline state |
packages/suite-base/src/context/PanelExtensionContext.ts | Context type panels consume |
packages/suite-base/src/PanelAPI/ | Internal hooks for built-in panels |
interface RenderState {
topics?: readonly Topic[];
currentFrame?: readonly MessageEvent[];
allFrames?: readonly MessageEvent[]; // preloaded range
currentTime?: Time;
parameters?: Map<string, unknown>;
variables?: Map<string, unknown>;
colorScheme?: "dark" | "light";
appSettings?: Map<string, unknown>;
}renderState.ts tracks which fields changed since the last rendercurrentTime changed, topics is reused)interface PanelExtensionContext {
subscribe(topics: SubscriptionConfig[]): void;
onRender(renderState: RenderState, done: () => void): void;
saveState(state: unknown): void;
seekPlayback(time: Time): void;
setParameter(key: string, value: unknown): void;
}This snippet is a core API introduction, not the full type surface. For the complete
PanelExtensionContext definition (including read-only properties, watch/subscription APIs,
publish/service methods, settings APIs, and range subscriptions), see:
packages/suite/src/index.ts.
The render callback is
onRender(renderState, done). The panel must calldone()when it has finished processing the frame — this drivespauseFramebackpressure.
const done = pauseFrame(panelId);
// ... expensive rendering (GPU upload, chart update) ...
done(); // ready for next framedone() within the timeout, the next frame is forcedinitPanel() is calledcontext.subscribe()RenderState → onRender() firescleanup() is calledpanels/MyPanel/
├── index.tsx # registration + entry point
├── MyPanel.tsx # main component
├── settings.ts # settings tree definition
├── types.ts # panel-specific types
└── MyPanel.test.tsxBuilt-in panels access data via React hooks in PanelAPI instead of the PanelExtensionContext
render-callback model:
import * as PanelAPI from "@lichtblick/suite-base/PanelAPI";useDataSourceInfo() — rarely-changing metadata (topics, datatypes, capabilities, startTime);
re-renders only when metadata changes, not during playback.RenderState minimizes object creation — only changed fields are rebuiltpauseFrame prevents data flooding slow panelsmessage-pipeline skilllichtblick-suite/lichtblick
9589f38
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.