{/* The FigSrc* tags come from the site-wide mdxComponents map in
    site.config.ts — no import needed. */}

# Visualize a source

  A **source** is DreamLake's connection to your data — an S3 bucket or a
  Hugging Face repo linked into your namespace. Drop one `.dreamrc` file at a
  dataset's root and the app renders every episode in it: cameras, time
  series, timelines, 3D. Nothing is imported or converted — the app reads
  your storage in place.

## Connect your data

Linking happens in the dashboard: open **Sources** in your namespace
(`/source/<namespace>`) and connect the storage. Credentials stay
server-side, encrypted — never in files or URLs.

| Storage | Connect with | Get bytes in today |
| --- | --- | --- |
| S3 bucket | bucket credentials | `aws s3 cp --recursive ./my-dataset s3://bucket/prefix` |
| Hugging Face repo | OAuth | `hf upload you/dataset ./my-dataset --repo-type dataset` |

Then verify from a shell that the source holds what you think:

```bash
dreamlake source list                                # sources you can reach
dreamlake source browse [path] --source <name>       # list a directory
dreamlake source download <path> --source <name> -o ./out # spot-check a file
```

## Shape the dataset

Most robot-learning exports work **as-is** — a published dataset renders
unmodified, with one file added:

| Your dataset root holds | `format` | Anything to do first? |
| --- | --- | --- |
| `meta/info.json` (LeRobot v2.x / v3.0) | `lerobot` | no |
| `*.zarr.zip` or a `.zarr/` directory (UMI) | `umi` | no |
| `*.mcap` files — Foxglove schemas or plain ROS&nbsp;1 / ROS&nbsp;2 bags | `mcap` | no |
| `model/` + `episodes/*/frames.parquet` + `episode.json` | `folder` | no — a DreamLake sim-playback dataset renders as-is |
| anything else — videos, images, CSV, parquet | `folder` | one folder per episode |

Layout details and shape rules:
[prepare your data](https://viz.dreamlake.ai/dataset-viz/requirements).

## Make it render

The `.dreamrc` names which fields feed which **views** — that's the whole
job. Open the source in the app and the dataset renders:

```yaml file=".dreamrc"
version: 1
dataset:
  format: lerobot # lerobot | umi | mcap | folder
  episodes: auto
views:
  - view: videoStack
    cameras: ['observation.images.*']
  - view: lineChart
    series: [{ field: [action, '*'] }]
```

The full authoring workflow — reading the field inventory, every view and
its options, a live gallery of finished files —
[starts here](https://viz.dreamlake.ai/dataset-viz/start).

## Single MCAP files

Selecting one `.mcap` file in the browser renders it as a one-episode
dataset. Which config drives the render is a fixed chain — the first hit
wins:

1. **`<filename>.dreamrc`** beside the file — `test.mcap` looks for
   `test.mcap.dreamrc`. A config written *for this file*: its views render
   with the selected file as the one episode.
2. **The folder's `.dreamrc`**, when its `dataset.format` is `mcap` — the
   unified config for a folder of recordings, applied to just this file.
3. **The source root's `.dreamrc`**, same condition.
4. **No config at all** — the file still renders: a default view generated
   from its [Foxglove or ROS well-known schemas](https://viz.dreamlake.ai/dataset-viz/reference#the-default-mcap-view).
   Camera topics become a frame stack, point clouds a 3D pane, tf a moving
   robot or skeleton (below), numeric channels charts. The header marks it
   as generated, and **copy .dreamrc** hands you the exact YAML — save it
   as `<filename>.dreamrc` (step 1) and the layout is yours to edit.

The more standard the recording, the more the no-config default shows;
channels outside the Foxglove / JSON / ROS schema set fall back to the
metadata table with the reason stated.

## ROS bags and robots

Plain ROS bags need no conversion — ROS&nbsp;2 (rosbag2's own MCAP
output) and ROS&nbsp;1 alike. Images, point clouds and poses land in the
same views as their Foxglove twins, and the `/tf` tree renders in 3D with
Foxglove semantics: transforms compose down the declared parent chain, so
a tf-only recording plays as a **moving skeleton** — joints, bones, no
model required.

When the names a recording publishes — tf frame ids, or the joint names on a
`/joint_states` topic — carry a known robot's own naming, the default view
goes further and renders **the robot itself**: a Unitree&nbsp;G1 recording
opens as the G1, a DROID episode as a Franka Panda with its Robotiq gripper,
meshes streamed from the
[robot preset registry](https://huggingface.co/datasets/live9080/dreamlake-robots).
Unknown structures keep the honest skeleton — nothing is guessed. To put a
robot on a recording yourself, name its URDF in the 3D view:

```yaml file="<filename>.dreamrc"
- view: recon3d
  up: z
  tracks: [{ field: '/tf::*', as: transform3d }]
  models:
    - https://huggingface.co/datasets/live9080/dreamlake-robots/resolve/main/g1/g1_29dof.urdf
```

The viewer reads URDF directly — meshes resolve relative to the file (or
through a `packages:` map for `package://` references), each link drives from
its `/tf::<link>` track by name, and links the recording never publishes ride
their nearest tracked parent.

A bag that logs only **joint angles** and no per-link poses — very common,
since the angles are the state and the poses are derivable — is 3D too: bind
the topic with `joints:` beside a URDF and the viewer runs the forward
kinematics itself, gripper linkages included. Full detail:
[ROS bags & robot models](https://viz.dreamlake.ai/dataset-viz/robots).

## Sim recordings (MuJoCo & URDF)

A teleop recorder that runs MuJoCo can write a DreamLake **sim-playback
dataset** directly — one folder per episode, plus the exact model the
session ran snapshotted into `model/`. Each `frames.parquet` stores **named
channels** — one column per joint, seven per free body, keyed to MJCF names
by `episode.json` — so the data survives model recompilation and outlives
any single scene version. The `mujoco` view loads the snapshot and plays the
channels back **kinematically**: qpos in, forward kinematics out, never
stepping physics — scrubbing the shared timeline is random access,
frame-exact in either direction. Because channels are name-keyed, an `env:`
override plays the same data on a scene-only [env](/envs.md): hand channels
with no match there are skipped and listed, while objects and fixtures
replay on their own. `ctrl.*` columns carry the action stream for a
`lineChart`. The recorder drops this `.dreamrc` at the root:

```yaml file=".dreamrc"
version: 1
name: sharpa-teleop
dataset:
  format: folder
  episodes: "episodes/*/"
views:
  - view: mujoco
    qpos: [frames]          # named channel columns
    meta: [episode]         # episode.json — channels map + model ref
    height: 420
    # env: ns/laundry       # optional: play on a scene-only env
  - view: timeline           # shared clock + playback bar
  - view: lineChart
    series: [{ field: [frames, 'ctrl.*'] }]
```

The same contract has a **URDF flavor** for motion that isn't an MJCF scene —
a retargeted mocap clip, a policy rollout, anything that is "a robot
description plus per-frame joint values". `episode.json` says `sim: "urdf"`,
`model.path` names the dataset's URDF (with `model.files` listing every
mesh), and channels bind **URDF joints by name** — one column per
revolute/continuous/prismatic joint — plus one `freejoint` channel naming
the **root link** with seven columns (x, y, z, qw, qx, qy, qz — quaternion
**w-first**, meters, Z-up world) for the floating base. The `urdf` view
drives `setJointValue` and the base pose directly; joints the robot lacks
are listed, not fatal, and the same `env:` override plays the data on a
pushed URDF env:

```yaml file=".dreamrc"
version: 1
name: g1-dance
dataset:
  format: folder
  episodes: "episodes/*/"
views:
  - view: urdf
    joints: [frames]        # URDF joint columns, keyed by joint name
    meta: [episode]         # episode.json — sim "urdf", model + channels
    height: 480
  - view: timeline
  - view: lineChart
    series: [{ field: [frames, left_knee_joint] }]
```

Playback lives here, in sources; the envs you curate stay untouched —
pushing and versioning scenes is the [envs guide](/envs.md).

## Let Claude do it

Add the two [source skills](https://github.com/dreamlake-ai/dreamlake-skills),
point at a folder, and say *"visualize this dataset in DreamLake"*:

| Skill | Does |
| --- | --- |
| `dreamlake-source` | inspects the data, preps the layout, gets it linked, verifies the source |
| `dreamlake-dataset-viz` | writes and debugs the `.dreamrc` — bindings, validation, iteration |

```bash
git clone https://github.com/dreamlake-ai/dreamlake-skills
mkdir -p ~/.claude/skills
cp -r dreamlake-skills/{dreamlake-source,dreamlake-dataset-viz} ~/.claude/skills/
```

Install both — source gets the bytes connected, dataset-viz makes them render.

## Next steps

    The five-step authoring workflow, every view, and the .dreamrc gallery.

    The DreamLake-hosted flavor — collections with schemas you push to from
    the terminal.
