Python
3.9 โ 3.13. NumPy-native: pass arrays straight through, zero copies where the dtype allows.
pip install dalaran-sdk
One schema, four bindings, no build step. Add it to a script you already have and the viewer opens itself.
3.9 โ 3.13. NumPy-native: pass arrays straight through, zero copies where the dtype allows.
pip install dalaran-sdk
The reference implementation. Everything else binds to this crate; no FFI overhead on the hot path.
cargo add dalaran
C++17, header-first with a prebuilt static core. CMake and Bazel targets, or vendor the amalgamation.
FetchContent_Declare(dalaran ...)
gRPC + Arrow IPC, fully specified. Write a binding for any language in an afternoon.
dalaran.proto ยท v3
import dalaran as dl
import numpy as np
dl.init("hello-world", spawn=True) # spawns the viewer if it isn't running
pts = np.random.normal(size=(50_000, 3))
rgb = ((pts - pts.min()) / pts.ptp() * 255).astype(np.uint8)
dl.log("world/cloud", dl.Points3D(pts, colors=rgb, radii=0.01))
use dalaran::{Points3D, RecordingStreamBuilder};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let rec = RecordingStreamBuilder::new("hello-world").spawn()?;
let points: Vec<[f32; 3]> = (0..50_000).map(|_| random_xyz()).collect();
rec.log("world/cloud", &Points3D::new(points).with_radii([0.01]))?;
Ok(())
}
#include <dalaran.hpp>
int main() {
const auto rec = dalaran::RecordingStream("hello-world");
rec.spawn().exit_on_failure();
std::vector<dalaran::Position3D> points = random_xyz(50000);
rec.log("world/cloud", dalaran::Points3D(points).with_radii(0.01f));
}
Log the intrinsics once and every 3D entity under that path is drawn in the image with the right perspective.
dl.log("world/cam", dl.Pinhole(focal=725.0, width=1920, height=1080), static=True)
dl.log("world/cam", dl.Transform3D(translation=t, rotation=q))
dl.log("world/cam/rgb", dl.Image(frame))
dl.log("world/cam/rgb/dets", dl.Boxes2D(
array=boxes, array_format="XYWH",
labels=names, class_ids=ids,
))
Each joint logs only its own local transform. The viewer composes the chain, so a fix at the base propagates everywhere.
dl.log("world/base", dl.Transform3D(translation=odom))
dl.log("world/base/arm/j0", dl.Transform3D(rotation=dl.RotationAxisAngle([0,0,1], q0)))
dl.log("world/base/arm/j0/j1", dl.Transform3D(rotation=dl.RotationAxisAngle([0,1,0], q1)))
dl.log("world/base/arm/j0/j1/tool", dl.Transform3D(translation=[0, 0, 0.19]))
# Anything logged under .../tool now moves with the gripper
dl.log("world/base/arm/j0/j1/tool/grasp", dl.Points3D(contact_pts))
Scalars land on the same timeline as your point clouds, so a spike in error and the frame that caused it are one click apart.
dl.log("metrics/loss", dl.Scalar(loss))
dl.log("metrics/grad_norm", dl.Scalar(gn))
dl.log("metrics/lr", dl.Scalar(sched.get_last_lr()[0]))
dl.log("debug/activations", dl.Tensor(feat.detach().cpu().numpy(),
dim_names=["batch", "ch", "h", "w"]))
dl.log("logs/train", dl.TextLog(f"step {step}: {loss:.4f}", level=dl.TextLogLevel.INFO))
A bridge node subscribes to your topics and maps standard message types onto archetypes automatically. TF becomes a transform tree; PointCloud2 becomes a cloud.
Log tensors without leaving the training loop. Detach, stride and colormap handling are built in.
Pass geometry objects directly; the SDK reads vertices, normals and texture coordinates off the object.
Stream simulator state each step and compare a rollout against the physical run on a shared clock.
dl.notebook_show() embeds the real viewer in an output cell โ interactive, not a static image.
Write .dlr artifacts from your test suite and attach them to the run. Failures arrive as recordings.
| Command | What it does |
|---|---|
| dalaran <file.dlr> | Open a recording in the native viewer |
| dalaran --serve-web | Serve the WebAssembly viewer on localhost |
| dalaran ls run.dlr | List entities, components and timeline ranges |
| dalaran filter --entity 'world/cam/**' | Extract a subtree into a smaller recording |
| dalaran merge a.dlr b.dlr -o both.dlr | Combine recordings onto one timeline |
| dalaran compare base.dlr new.dlr | Open two runs in a synced side-by-side layout |
| dalaran analytics disable | Turn off usage telemetry permanently |