Hi everyone,
I wanted to share a project I’ve been working on called BAGEL (BAG ExpLoration). It’s an open-source, fully static web application designed to let you inspect, scrub, and visualize ROS 1 and ROS 2 bag files locally in your browser with zero installation, zero configuration, and no cloud uploads.
Live App: https://bagel-ros2.vercel.app
GitHub Repository: GitHub - Hussain004/BAGEL: ROS Bag Visualizer · GitHub
Demo Playlist: https://youtube.com/playlist?list=PLHZhJb0NUk4Jv26hmARxgLa_dVw6Ab5j8&si=zSZQnYMwOmESiOgq
Why build another visualizer?
While tools like RViz2 are great for live debugging, standing up a full ROS environment just to quickly sanity-check a data log on a laptop or to share results with a non-ROS collaborator can be friction-heavy.
BAGEL is built entirely on a client-side architecture. Your data never leaves your machine. It utilizes web workers and streaming chunk decoders to handle heavy robotics telemetry data directly in the browser thread.
Key Features
-
Multi-Format Ingestion: Seamless drag-and-drop or file-selection for ROS2 `.mcap` (Humble/Jazzy compatibility), ROS2 `.db3` (SQLite), and legacy ROS1 `.bag` files.
-
TF-Aware 3D Panel (Three.js): Decodes and visualizes `sensor_msgs/PointCloud2`, `sensor_msgs/LaserScan`, `geometry_msgs/PoseStamped`, `nav_msgs/OccupancyGrid` SLAM maps, and `visualization_msgs/MarkerArray`. It natively handles action semantics (`ADD`, `MODIFY`, `DELETEALL`) and lifetime fade-outs.
-
Geographical Grounding: The trajectory panel parses `sensor_msgs/NavSatFix` and projects the coordinates using an opt-in OpenStreetMap tile underlay with an in-memory LRU cache.
-
Remote URL Streaming via HTTP Range: You can paste a public URL (S3 bucket, GitHub release asset, etc.). For MCAP and ROS1 bags, the tool only streams the precise chunks you scrub through, allowing a multi-gigabyte log to open in under a second.
-
Custom Schema On-the-Fly Injection: Since `.db3` files do not embed message schemas, anything outside the standard packages usually fails to decode. BAGEL adds a runtime paste flow backed by `@foxglove/rosmsg` validation and `l@foxglovecalSto@foxgloveage` persistence, allowing you to paste your custom `.msg` definitions once and decode proprietary planner or vendor packages instantly.
-
Blazing-Fast Time-Series: Uses `uPlot` to instantly graph any numerical primitive from any message payload with zero layout lag.
Technical Stack
The frontend is built using React 19, TypeScript, and Vite. Heavy parsing workloads are offloaded to worke@mca@mcaps:
- @mcap/c@foxglov@foxglovere & @foxglove/rosbag@mcap for low-level@mc@foxglove@foxgloveparsing.
- @foxglove sql.js (WebAssembly) to@foxglovequery unindexed `.db3` tables in memory.
- seek-bzip & lz4js running in web workers to handle compressed ROS1 chunks natively without blocking UI rendering loops.
Feedback Welcome!
This is a fully open-source effort aimed at making data sharing and quick field log triage as low-friction as possible.
I would love to hear feedback from the community regarding performance benchmarks, missing primitive types you rely on, or general UX enhancements. Feel free to open issues or submit PRs on the repository!




