Simplified Chinese: API.zh.md
This document covers the complete public API of @ioai/rosview v1.2.0.
Before using this package, install peer dependencies in your host app: react, react-dom, three, @react-three/fiber, and @react-three/drei.
- RosViewer
- RosViewProvider
- TypeScript Types
- Preference Utilities
- Dataset Utilities
- Layout Utilities
- Extension API
- MessagePipeline Hook
- URL Parameters (SPA)
The main embeddable component. Renders the full viewer UI including navbar, panels, and playback controls.
import { RosViewer } from '@ioai/rosview';
import '@ioai/rosview/style.css';| Prop | Type | Default | Description |
|---|---|---|---|
url |
string |
— | Single remote file URL (HTTP/HTTPS). Supports HTTP Range requests for large files. |
urls |
string[] |
— | Multiple remote file URLs. Each becomes a selectable dataset in the sidebar. |
file |
File |
— | Single local File object (e.g. from <input type="file">). |
files |
File[] |
— | Multiple local File objects. |
fileManifest |
string | FileListItem[] |
— | Remote dataset manifest JSON URL or an array of FileListItem rows. Merged with url/urls. Fetch errors are logged and do not block other sources. Use this prop when embedding; the standalone SPA does not read manifest URLs from query parameters. |
All source props may be combined. Duplicates are deduplicated automatically. Files take priority over URLs in display order.
| Prop | Type | Default | Description |
|---|---|---|---|
theme |
'light' | 'dark' | 'system' |
'system' |
Color theme. 'system' follows the OS preference. |
language |
'en' | 'zh' | 'ja' |
'en' |
UI language (English, Simplified Chinese, Japanese). |
className |
string |
— | CSS class applied to the outermost container element. |
style |
React.CSSProperties |
— | Inline styles applied to the outermost container element. |
| Prop | Type | Default | Description |
|---|---|---|---|
preferencePersistence |
'localStorage' | 'off' |
'localStorage' |
UI preferences (theme, language, sidebar width). 'off' disables automatic localStorage writes. |
layoutPersistence |
'localStorage' | 'off' | 'inherit' |
'inherit' |
Panel layout persistence; 'inherit' follows preferencePersistence; 'off' skips ioai.rosview.layout. |
layoutStorageKey |
string |
'ioai.rosview.layout' |
localStorage key for layout JSON (multi-embed isolation). |
urlState |
'spa' | 'off' |
'off' |
'spa': sync browser ?url= with the active dataset and restore file:// / folder:// / sample:// from IndexedDB Recent or the sample manifest (standalone SPA). 'off': default for npm embedding — no history.pushState, and custom locators in url do not auto-restore. |
| Prop | Type | Default | Description |
|---|---|---|---|
mode |
'viewer' | 'tool' |
'viewer' |
'tool': workspace without MCAP (MinimalPlayer), default panels-only chrome. |
requireSource |
boolean |
mode !== 'tool' |
When false, mounts panels without url/file. |
chrome |
'full' | 'minimal' | 'panels-only' |
per mode |
Chrome preset; overridable via showNavbar / showSidebar / showPlaybackBar. |
showNavbar / showSidebar / showPlaybackBar |
boolean |
per chrome |
Explicit chrome toggles. |
hideOpenFileMenus |
boolean |
false |
Hide navbar file menus and disable recording drag-and-drop. |
initialLayout |
FoxgloveLayoutData |
— | Declarative layout applied on mount (before localStorage). |
defaultPanel |
OpenPanelInput |
— | Single-panel shorthand (ignored when initialLayout is set). |
suppressWelcomePanel |
boolean |
mode === 'tool' |
Skip Dockview Welcome placeholder. |
| Prop | Type | Description |
|---|---|---|
onFatalError |
(error: Error) => void |
Called when a file fails to load and no fallback succeeds. |
onThemeChange |
(theme: 'light' | 'dark' | 'system') => void |
Called when the user changes the theme via the navbar. |
onLanguageChange |
(language: 'en' | 'zh' | 'ja') => void |
Called when the user changes the language via the navbar. |
onPlayerReady |
({ player, hasSource }) => void |
Fired once when player presence becomes ready. |
onLayoutReady |
({ panelCount }) => void |
Fired after Dockview layout hydration. |
onSourceLoadingChange |
(loading: boolean) => void |
Notifies host while a source is initializing. |
extensions |
RosViewExtension[] |
Optional host contributions: sidebar tabs plus timeline/playback overlays. |
hostContext |
unknown |
Opaque value forwarded to every extension as context.hostContext. RosView does not interpret it (pass dataset ids, feature flags, etc.). |
<RosViewer url="https://cdn.example.com/recording.mcap" />const [theme, setTheme] = React.useState<'light' | 'dark' | 'system'>('dark');
const [lang, setLang] = React.useState<'en' | 'zh' | 'ja'>('en');
<RosViewer
url="https://cdn.example.com/recording.mcap"
theme={theme}
language={lang}
preferencePersistence="off"
onThemeChange={setTheme}
onLanguageChange={setLang}
/>import {
RosViewer,
createSinglePanelLayout,
} from '@ioai/rosview';
import '@ioai/rosview/style.css';
<RosViewer
mode="tool"
preferencePersistence="off"
layoutPersistence="off"
initialLayout={createSinglePanelLayout({ type: 'UrdfDebug', id: 'UrdfDebug!embed' })}
theme="dark"
language="zh"
/>Provides the theme context and i18n IntlProvider for applications that need to render custom UI within the ROSView theme.
import { RosViewProvider, useRosViewTheme } from '@ioai/rosview';| Prop | Type | Default | Description |
|---|---|---|---|
theme |
'light' | 'dark' | 'system' |
'system' |
Theme for child components. |
language |
'en' | 'zh' | 'ja' |
'en' |
Language for react-intl messages. |
children |
React.ReactNode |
(required) | Child components. |
const { theme, resolvedTheme } = useRosViewTheme();
// theme: 'light' | 'dark' | 'system'
// resolvedTheme: 'light' | 'dark' (system resolved to actual value)type RosViewLanguageCode = 'en' | 'zh' | 'ja';type RosViewUiTheme = 'light' | 'dark' | 'system';type RosViewPersistedTheme = 'light' | 'dark'; // 'system' is not persistedtype PreferencePersistence = 'localStorage' | 'off';Represents a single data source (file or URL) that has been normalized for use with the player.
interface DatasetItem {
id: string;
kind: 'file' | 'url';
name: string;
file?: File;
url?: string;
sizeBytes?: number;
durationSec?: number;
topicCount?: number;
}One row from a remote dataset manifest JSON.
interface FileListItem {
url: string;
name?: string;
sizeBytes?: number;
durationSec?: number;
topicCount?: number;
}ROS-compatible timestamp (nanosecond precision).
interface Time {
sec: number;
nsec: number;
}A decoded message from the player.
interface MessageEvent<T = unknown> {
topic: string;
receiveTime: Time;
message: T;
sizeInBytes: number;
schemaName?: string;
}type PlayerPresence = 'preinit' | 'initializing' | 'ready' | 'closed';For host applications that manage preferences externally (preferencePersistence="off").
import { readPreferences, writePreferences } from '@ioai/rosview';
import { ROS_VIEW_PREFERENCES_STORAGE_KEY, ROS_VIEW_LAYOUT_STORAGE_KEY } from '@ioai/rosview';Returns the stored preferences object or null if none saved.
const prefs = readPreferences();
// { theme: 'dark', language: 'zh', ... } | nullMerges a partial preferences object into the stored value.
writePreferences({ theme: 'dark', language: 'en' });| Constant | Value | Content |
|---|---|---|
ROS_VIEW_PREFERENCES_STORAGE_KEY |
'ioai.rosview.prefs' |
UI preferences JSON |
ROS_VIEW_LAYOUT_STORAGE_KEY |
'ioai.rosview.layout' |
Panel layout JSON |
import { parseRemoteDatasetListJson, datasetItemsFromListItems } from '@ioai/rosview';Parse a raw JSON value (from fetch) into a FileListItem[]. Invalid rows are skipped.
const res = await fetch('/manifest.json');
const items: FileListItem[] = parseRemoteDatasetListJson(await res.json());Convert FileListItem[] to DatasetItem[] (the format used by RosViewer).
const datasets = datasetItemsFromListItems(items);
<RosViewer files={[]} fileManifest={items} />import {
readSavedDockviewLayout,
saveDockviewLayoutToStorage,
clearSavedDockviewLayout,
} from '@ioai/rosview';| Function | Description |
|---|---|
readSavedDockviewLayout() |
Read the saved panel layout from localStorage. Returns FoxgloveLayoutData | null. |
saveDockviewLayoutToStorage(layout) |
Write a panel layout to localStorage. |
clearSavedDockviewLayout() |
Remove the saved panel layout from localStorage. |
import { importFoxgloveLayout, buildFoxgloveLayout, parseFoxgloveLayout } from '@ioai/rosview';
import { exportDockviewLayout, importDockviewLayout, openDockviewPanel } from '@ioai/rosview';| Function | Description |
|---|---|
parseFoxgloveLayout(raw) |
Parse a raw Foxglove layout JSON object into FoxgloveLayoutData. |
importFoxgloveLayout(data, options?) |
Convert a FoxgloveLayoutData into a DockView-compatible layout and apply it. Returns ImportFoxgloveLayoutResult. |
buildFoxgloveLayout(input) |
Build a FoxgloveLayoutData from a panel configuration object. |
exportDockviewLayout() |
Export the current panel layout as FoxgloveLayoutData. Returns null if no layout is active. |
importDockviewLayout(layout) |
Apply a previously exported layout to the current DockView instance. |
openDockviewPanel(input) |
Programmatically open a panel by type. Returns the new panel ID or null. |
createSinglePanelLayout(input) |
Build single-panel FoxgloveLayoutData from OpenPanelInput. |
MinimalPlayer |
Stub Player for tool mode / advanced hosts (no recording source). |
@ioai/rosview can be extended by passing extensions to RosViewer.
import type {
RosViewExtension,
RosViewExtensionContext,
SidebarTabContribution,
PlaybackOverlayContribution,
TimelineOverlayContribution,
PlaybackControlsApi,
PlaybackSnapshot,
TimelineApi,
MessageAccessApi,
} from '@ioai/rosview';| Type | Description |
|---|---|
RosViewExtension |
One extension bundle. Contains optional sidebarTabs, playbackOverlays, and timelineOverlays (merged after playbackOverlays, same contribution shape). |
SidebarTabContribution |
Registers a sidebar tab (id, title, optional icon, optional order, render(context)). |
PlaybackOverlayContribution |
Registers a region above playback track (id, optional order, optional height, render(context)). |
TimelineOverlayContribution |
Alias of PlaybackOverlayContribution for naming clarity. |
RosViewExtensionContext |
Stable context object passed into extension renderers. |
PlaybackControlsApi |
Playback controls: seek, play, pause, setSpeed, setLooping, stepBy, stepMessage, playUntil, subscribeCurrentTime, getCurrentTime, getSnapshot. |
PlaybackSnapshot |
Low-frequency playback state including currentTime, startTime, endTime, isPlaying, speed, optional progressPercent, buffering, problems. |
TimelineApi |
Helpers aligned with the scrubber: getTimeBounds, timeToPercent, percentToTime. |
MessageAccessApi |
Read-only getMessagesInTimeRange when the underlying player supports it. |
import { RosViewer } from '@ioai/rosview';
import type { RosViewExtension } from '@ioai/rosview';
const annotationExtension: RosViewExtension = {
id: 'my-annotation-tool',
sidebarTabs: [
{
id: 'annotations',
title: 'Annotations',
order: 20,
render: ({ playback }) => (
<MyAnnotationSidebar
getPlaybackSnapshot={playback.getSnapshot}
onSeek={playback.seek}
/>
),
},
],
playbackOverlays: [
{
id: 'annotation-ranges',
order: 10,
render: ({ playback, timeline }) => (
<MyAnnotationTimeline
getBounds={timeline.getTimeBounds}
timeToPercent={timeline.timeToPercent}
getPlaybackSnapshot={playback.getSnapshot}
subscribeCurrentTime={playback.subscribeCurrentTime}
onSeek={playback.seek}
/>
),
},
],
timelineOverlays: [
{
id: 'lane-markers',
order: 5,
height: 14,
render: ({ timeline }) => <MyThinLane timeline={timeline} />,
},
],
};
<RosViewer url="/demo.mcap" extensions={[annotationExtension]} hostContext={{ datasetId: 42 }} />;- Prefer
playback.subscribeCurrentTime()for high-frequency visuals (canvas/ref updates) instead of React setState on every frame. - Use
playback.getCurrentTime()for one-off real-time playhead reads. - Use
playback.getSnapshot()for low-frequency state checks likeisPlaying,startTime, andendTime; itscurrentTimeis a compatibility snapshot, not a React-driven playhead source. - Keep extension renderers resilient; runtime errors are isolated from core playback controls.
For advanced use cases — subscribing to playback state and decoded messages from within custom React components rendered inside the viewer.
useMessagePipeline is intended for slowly-changing metadata such as presence, topics, bounds, progress, speed, and decoded message availability. Do not use playerState.activeData.currentTime for live playback UI; use playback.subscribeCurrentTime() or playback.getCurrentTime() instead.
import { useMessagePipeline } from '@ioai/rosview';function MyCustomPanel() {
const presence = useMessagePipeline(s => s.playerState.presence);
const topics = useMessagePipeline(s => s.sortedTopics);
if (presence !== 'ready') return <div>Loading…</div>;
return (
<ul>
{topics.map(t => <li key={t.name}>{t.name} ({t.schemaName})</li>)}
</ul>
);
}The selector function receives MessagePipelineState and should return a stable (memoized) value to avoid unnecessary re-renders.
When using the standalone SPA at rosview.com or a self-hosted deployment, the address bar uses a single datasource parameter url (plus optional UI params). Opening or switching a source updates the URL with history.pushState so refresh restores the same item.
| Parameter | Example value | Description |
|---|---|---|
url |
https://cdn.example.com/recording.mcap |
Remote recording (HTTP(S) or same-origin path such as /examples/run.mcap). |
url |
file://test.mcap |
Local file: replay uses the most recent matching Recent entry with stored FileSystemFileHandle (same display name; ambiguous if duplicated). |
url |
folder://dataset |
Local folder: replay uses the most recent Recent directory entry whose folder name matches. |
url |
sample://franka_stack |
Built-in sample: resolve id against the JSON catalog from VITE_SAMPLE_DATASETS_MANIFEST_URL or VITE_SAMPLES_BASE_URL (see sample manifest in the repo src/services/sampleDatasets.ts). |
theme |
dark |
Initial theme (light / dark / system). |
language |
zh |
Initial language (en / zh / ja). |
file://, folder://, and sample:// are app-specific locators, not the browser’s native file: URL scheme.
For multiple remote files or a remote JSON manifest, use the React urls / fileManifest props when embedding @ioai/rosview; the standalone SPA intentionally tracks a single url in the query string.
Example deep-link:
https://rosview.com?url=https://cdn.example.com/run1.mcap&theme=dark&language=en