Diagnostic Panel
diagnostic-panelViewersWhat the host told the plugin, what reached it and what it produced, shown in eleven tabs.
$ pnpm dlx shadcn@latest add @pluginui/core-diagnostic-panelInstall
Copies the source into your project. Anything it depends on comes with it. Run this in your React project with shadcn initialized; no registry configuration is needed.
Pulls in
Install using the registry URL
$ pnpm dlx shadcn@latest add https://pluginui.com/r/core-diagnostic-panel.jsonUsage
Connect the documented props to your application or host.
import { DiagnosticPanel } from "@/components/ui/diagnostic-panel"
import { createDiagnosticSession } from "maruaudio/ui/shared/maru/diagnostic-session"
import { createFaceApiClient } from "maruaudio/ui/shared/maru/face-api-client"
const host = createFaceApiClient()
const session = createDiagnosticSession(host)
host.ready()
session.open() // nothing streams until this is called
// Each read re-derives feed ages because silence sends no message.
// Wrap the session before useSyncExternalStore so React sees a stable
// store value across renders.
const readSnapshot = useMemo(() => createSnapshotStabilizer(session.snapshot), [session])
const snapshot = useSyncExternalStore(session.subscribe, readSnapshot, readSnapshot)
<DiagnosticPanel session={session} snapshot={snapshot} />
// Controlled tab, when the surrounding chrome owns the selection.
<DiagnosticPanel session={session} snapshot={snapshot} tab={tab} onTabChange={setTab} />About Diagnostic Panel
The developer view of a running plugin, fed by one `DiagnosticSession` snapshot: Overview, Host, Transport/Clock, MIDI, Audio, Parameters, Presets/State, Events, Stimulus, Performance and Package. The component is controlled and presentational. It owns no bridge and opens no feed, so the same view serves a drawer over a plugin face, a dev-runner pane and this docs page. Its editorial rule makes it trustworthy: every value comes from the snapshot or appears as an explicit Unreported cell. There is no `?? 0`, because an unreported latency is not zero latency and a frame that never arrived is not silence. Filling those gaps with plausible numbers is worse than leaving them blank; a developer may act on them. The stereo verdict checks per-channel RMS before correlation. A digitally silent pair correlates at exactly 1.0 by meter convention, so correlation alone would call dead air perfect mono. Audio taps use `session.readScope` inside the draw loop rather than the snapshot, keeping each 512-sample frame out of the values React diffs. Overview leads with a status strip for health, feed verdicts, build, host rate and block, latency, and connection. Its one-word verdict overrides the host's claim when a promised feed goes silent, since a dead feed is a broken host bridge regardless of DSP health. A dropped-frame count that grows with callbacks is labelled “the host is not draining” rather than shown as a number without context. Copy report puts a ten-line plain-text summary on the clipboard before the full JSON, because JSON is unreadable in the chat window where it is pasted. The closed panel costs no frames: its four Audio viewers share an animation frame scheduled only while the tab and document are visible; each tab is memoised over only the snapshot slice it reads; and tables past 200 rows render only the visible band, with spacer rows for the remaining height.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| session | DiagnosticSession | — | The SDK session the panel reads. Used for stimulus commands, `buildLocalReport()` and `readScope` in the audio tab's draw loop; the panel never opens or closes it, so visibility stays the caller's decision. |
| snapshot | DiagnosticSnapshot | — | The value to render. Read it with `useSyncExternalStore` over `createSnapshotStabilizer(session.snapshot)` rather than over `session.snapshot` directly: the session re-derives feed-health ages at read time, so its raw snapshot is not referentially stable enough for that hook. Any field left `undefined` is one this host never reported, and renders as an Unreported cell rather than a default. |
| tab | DiagnosticTabId | — | Controlled tab selection. Omit to let the panel own it. One of overview, host, transport, midi, audio, parameters, presets, events, stimulus, performance, package. |
| onTabChange | (tab: DiagnosticTabId) => void | — | Fires when the rail selection changes, in both controlled and uncontrolled modes. |
| headerActions | ReactNode | — | Rendered to the right of the header, where the overlay places its close button. |
| live | boolean | — | Defaults to true. Set false while the panel is mounted but not visible: the shared animation frame behind the Audio tab's viewers is then never scheduled at all, so a hidden panel costs nothing rather than merely idling. |
Interaction
- Drag with pointer capture, so the gesture keeps tracking past the edge of the control.
- Shift while dragging for a fine pass; release it mid-gesture and coarse tracking resumes.
- Double-click resets to
defaultValue. - Arrow keys step normally, Shift+arrow steps finely, PageUp/PageDown jump by ten, Home/End go to the extremes.
- Proper
sliderandswitchroles with livearia-valuetext, so a screen reader announces the formatted value rather than the raw number. - The scroll wheel adjusts the value while the pointer is over the control; stepped ranges move at least one declared step per notch by default.