Data
Dtypes
A dtype (data type) describes what kind of data a track carries — joint angles, IMU readings, video segments, action annotations. It's the contract between the track producer (usually dreamlake-py) and the track consumer (a vuer-m3u view or lane).
vuer-m3u ships 13 built-in dtypes and a small registry API for app-defined dtypes. dtype is convention, not enforcement — the server stores opaque bytes; if your chunks don't match the documented schema, the view breaks, that's on the author.
Data vs presentation
This is the point of the dtype registry:
| Layer | Carries | Lives in |
|---|---|---|
| Data — what the data IS | dtype + chunk schema | Server Track record + m3u8 + chunks (convention-only) |
| Presentation — how to draw it | lane/view component | App code — <TimelineContainer views={...}> or direct imports |
A single joint_angles track can be rendered as a chart (LineChartLane), a 3D stick figure (JointAngleView), or a URDF-driven 3D robot (UrdfRobot with useJointAnglesForUrdf). The data is the same; only the presentation changes — and that choice lives in the app, not in the track.
The 13 built-ins
| Dtype | Chunk format | Shape | Default lane | Standalone view |
|---|---|---|---|---|
video | HLS TS / fMP4 | opaque | VideoLane | VideoPlayer |
audio | HLS AAC | opaque | — | — |
subtitle | WebVTT | opaque | PillLane | SubtitleView |
scalar | JSONL | {ts, data: number} | LineChartLane | BarTrackView |
vector | JSONL | {ts, data: number[]} | LineChartLane | BarTrackView |
imu_6dof | JSONL | {ts, data: [ax,ay,az, gx,gy,gz]} | LineChartLane | ImuChartView, ImuGizmoView |
joint_angles | JSONL | {ts, data: number[]} | LineChartLane | JointAngleView, UrdfRobot |
pose_6dof | JSONL | {ts, data: [x,y,z, qx,qy,qz,qw]} | LineChartLane | PoseView |
image | JSONL | {ts, data: number[], shape: [H,W,C]} | — | — |
action_label | JSONL | {ts, te, label} | PillLane | ActionLabelView |
marker_event | JSONL | {ts, label} | MarkerLane | — |
detection_2d | JSONL | {ts, te, label, bbox: [x,y,w,h]} | MarkerLane | DetectionBoxView |
ribbon_state | JSONL | {ts, te, state} | PillLane | — |
Using dtypes
In a Timeline config
import { TimelineContainer, defaultTimelineViews, type TimelineConfig } from '@vuer-ai/vuer-m3u'
const config: TimelineConfig = {
container: { id: 'ep1', duration: 30 },
tracks: [
{ id: 'cam', path: 'cams/wrist', dtype: 'video', src: '/cam.m3u8' },
{ id: 'qpos', path: 'robot/arm', dtype: 'joint_angles', src: '/qpos.m3u8' },
{ id: 'ops', path: 'narr/ops', dtype: 'action_label', src: '/ops.m3u8' },
],
}
<TimelineContainer config={config} views={defaultTimelineViews} />The views map is what decides which lane draws each dtype. defaultTimelineViews wires the built-ins; apps can override a subset:
<TimelineContainer
config={config}
views={{ ...defaultTimelineViews, joint_angles: { lane: MyCustomQposLane } }}
/>With a standalone view
Standalone views (one-per-pane visualizations) are chosen by direct import — there's no dispatch layer. The dtype contract just tells you which views can consume the track:
import { JointAngleView } from '@vuer-ai/vuer-m3u'
<JointAngleView src="/qpos.m3u8" />See the "Compatible standalone views" row on each dtype page for the options.
Registering custom dtypes
If your team invents a new data shape not covered by the built-ins, register it at app bootstrap:
import { registerDtype } from '@vuer-ai/vuer-m3u'
registerDtype({
id: 'gripper_force',
name: 'Gripper force',
description: 'Single-axis force reading from a grasping end-effector.',
defaults: { range: [-50, 50], unit: 'N' },
})Then author tracks with dtype: 'gripper_force'. Supply a lane component in your <TimelineContainer views> map to render it — or alias it to an existing generic lane:
<TimelineContainer
config={config}
views={{
...defaultTimelineViews,
gripper_force: { lane: LineChartLane, icon: 'waves', defaultHeight: 84 },
}}
/>dtype vs chunkFormat
Easy to conflate — they're different:
- dtype identifies data semantics (
joint_angles,imu_6dof) and feeds defaults into lane props. - chunkFormat identifies the byte encoding (
jsonl,vtt,ts) and picks the decoder. Inferred from chunk file extension.
imu_6dof and joint_angles both use jsonl. video and audio use different chunk formats but neither loads decoded samples in vuer-m3u. You'll usually think about dtype; chunkFormat is transport plumbing.
API reference
| Symbol | Purpose |
|---|---|
DtypeSpec | { id, name, description?, defaults? } |
registerDtype(spec) | Add a spec to the registry (overwrites on duplicate id) |
getDtype(id) | Lookup a registered spec |
listDtypes() | All registered specs |
hasDtype(id) | Check registration |
BUILTIN_DTYPES | The 13 stock specs (frozen list) |
defaultTimelineViews | Stock TimelineViews wiring for built-ins |