Preview
MCAP Preview
MCAP recordings (the open robotics container format from Foxglove). The previewer reads only the footer + summary — message bodies are never fetched.
Extensions: mcap
MCAP format brief
MCAP is a chunked binary format optimized for indexed access:
┌─────────────────────────┐
│ Magic │ 8 bytes
├─────────────────────────┤
│ Header │
├─────────────────────────┤
│ Schemas, channels │
├─────────────────────────┤
│ Chunks (messages) │ ← bulk of the file (GBs)
│ ... │
├─────────────────────────┤
│ Statistics │
│ Channel index │ ← Summary section
│ Schema records │
├─────────────────────────┤
│ Summary offset │
├─────────────────────────┤
│ Footer (last 28 bytes) │
│ Summary start offset │
│ Summary CRC │
│ Magic │
└─────────────────────────┘The footer points to the summary; the summary describes everything in the file (schemas, channels, message counts, time ranges) without referencing message bodies.
IReadable adapter pattern
@mcap/core exposes McapIndexedReader.Initialize, which expects an IReadable:
interface IReadable {
size(): Promise<bigint>
read(offset: bigint, length: bigint): Promise<Uint8Array>
}The previewer adapts a URL into an IReadable backed by Range requests:
const sizeResp = await fetcher(url, { method: 'HEAD' }) // or use prop-passed size
const total = BigInt(sizeResp.headers.get('Content-Length')!)
const readable: IReadable = {
size: async () => total,
read: async (offset, length) => {
const start = Number(offset)
const end = start + Number(length) - 1
const r = await fetcher(url, { headers: { Range: `bytes=${start}-${end}` } })
return new Uint8Array(await r.arrayBuffer())
},
}
const reader = await McapIndexedReader.Initialize({ readable })McapIndexedReader then issues two reads:
read 1: bytes=<size-8192>-<size-1> # footer + tail of summary
read 2: bytes=<summaryStart>-<summaryEnd> # rest of summaryTwo requests, regardless of file size. A 50 GB MCAP previews in a few hundred KB.
What's shown
After initialization, the previewer reads reader.channelsById, reader.schemasById, and reader.statistics:
| Section | Content |
|---|---|
| Header bar | Filename, size, library/profile from reader.header |
| Statistics | Total messages, message-type counts, time range (first → last) |
| Channels | Topic name, schema, message count, frequency (msgs/sec) |
| Schemas | Name, encoding (ROS, Protobuf, JSON, …), brief def preview |
What's NOT shown
Message bodies are not fetched. <FilePreview> is for triage ("does this MCAP have the topics I expect, recorded over the time range I expect?"), not for inspecting payloads. For payload inspection, download and load in Foxglove Studio or the mcap CLI.
Live demo
import { FilePreview } from '@vuer-ai/vuer-m3u/preview'
export function MyComponent() {
return (
<FilePreview url="/vuer-m3u-demo/preview/mcap/sample.mcap" />
)
}Cross-links
- Size Strategy — footer + summary
- Recipes — auth fetcher — the same
fetcheris plumbed into the IReadable adapter - @mcap/core (npm)