From 3c912be1dc2705c03b4c6340626aaeacdced9e84 Mon Sep 17 00:00:00 2001
From: Antoine Beyeler <49431240+abey79@users.noreply.github.com>
Date: Tue, 17 Oct 2023 09:18:52 +0200
Subject: [PATCH] Add basic support for in-app "Quick Start" guides (#3813)
### What
This PR lays the basis for in-app "Quick Start" guides.
After a failed attempt to use `re_sdk` from `re_viewer` (can't target
wasm), this PR builds on recent `StoreDb` API improvements to create
"quick start" recordings from scratch.
This involves:
- adding a nice `StoreDb::from_info_and_rows()` helper function
- adding `SystemCommand::LoadStoreDb(StoreDb)`
- adding `StoreSource::Viewer` (for recordings generated from the viewer
itself)
- some helper functions in `welcome_page.rs`
This PR also introduces a draft for the (native-only) Python and Rust
Quick Starts, and placeholder for the other languages.
To address (in follow-up PR):
- markdown formatting issue where H1 appears smaller than H2 (current
work around: skip on using H1)
- #3612
- specialise Quick Start for non-server Viewers
- #3871
- write Quick Start for C++:
- #3870
- markdown formatting issue:
- https://github.com/lampsitter/egui_commonmark/issues/19
* Fixes #3095
### Checklist
* [x] I have read and agree to [Contributor
Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and
the [Code of
Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md)
* [x] I've included a screenshot or gif (if applicable)
* [x] I have tested [demo.rerun.io](https://demo.rerun.io/pr/3813) (if
applicable)
* [x] The PR title and labels are set such as to maximize their
usefulness for the next release's CHANGELOG
- [PR Build Summary](https://build.rerun.io/pr/3813)
- [Docs
preview](https://rerun.io/preview/9c7ebbf37a890b5d09941102a4d7c3a35f53f277/docs)
- [Examples
preview](https://rerun.io/preview/9c7ebbf37a890b5d09941102a4d7c3a35f53f277/examples)
- [Recent benchmark results](https://ref.rerun.io/dev/bench/)
- [Wasm size tracking](https://ref.rerun.io/dev/sizes/)
---------
Co-authored-by: Emil Ernerfeldt
---
crates/re_data_store/src/store_db.rs | 23 +++-
crates/re_log_types/src/lib.rs | 4 +
.../data/quick_start_guides/cpp_native.md | 3 +
.../quick_start_guides/how_does_it_work.md | 9 ++
.../data/quick_start_guides/python_native.md | 33 ++++++
.../quick_start_connect.cpp | 1 +
.../quick_start_guides/quick_start_connect.py | 1 +
.../quick_start_guides/quick_start_connect.rs | 1 +
.../data/quick_start_guides/rust_native.md | 31 +++++
crates/re_viewer/src/app.rs | 6 +
crates/re_viewer/src/lib.rs | 5 +-
crates/re_viewer/src/store_hub.rs | 8 ++
.../src/ui/welcome_screen/welcome_page.rs | 111 ++++++++++++++++--
crates/re_viewer/src/viewer_analytics.rs | 3 +-
.../re_viewer_context/src/command_sender.rs | 4 +
docs/code-examples/Cargo.toml | 8 +-
docs/code-examples/quick_start_connect.cpp | 5 +
docs/code-examples/quick_start_connect.py | 28 +++++
docs/code-examples/quick_start_connect.rs | 24 ++++
docs/code-examples/roundtrips.py | 2 +
20 files changed, 296 insertions(+), 14 deletions(-)
create mode 100644 crates/re_viewer/data/quick_start_guides/cpp_native.md
create mode 100644 crates/re_viewer/data/quick_start_guides/how_does_it_work.md
create mode 100644 crates/re_viewer/data/quick_start_guides/python_native.md
create mode 120000 crates/re_viewer/data/quick_start_guides/quick_start_connect.cpp
create mode 120000 crates/re_viewer/data/quick_start_guides/quick_start_connect.py
create mode 120000 crates/re_viewer/data/quick_start_guides/quick_start_connect.rs
create mode 100644 crates/re_viewer/data/quick_start_guides/rust_native.md
create mode 100644 docs/code-examples/quick_start_connect.cpp
create mode 100644 docs/code-examples/quick_start_connect.py
create mode 100644 docs/code-examples/quick_start_connect.rs
diff --git a/crates/re_data_store/src/store_db.rs b/crates/re_data_store/src/store_db.rs
index a54d1242b400..55c4d9ca0738 100644
--- a/crates/re_data_store/src/store_db.rs
+++ b/crates/re_data_store/src/store_db.rs
@@ -211,7 +211,7 @@ impl EntityDb {
// ----------------------------------------------------------------------------
-/// A in-memory database built from a stream of [`LogMsg`]es.
+/// An in-memory database built from a stream of [`LogMsg`]es.
///
/// NOTE: all mutation is to be done via public functions!
pub struct StoreDb {
@@ -238,6 +238,27 @@ impl StoreDb {
}
}
+ /// Helper function to create a recording from a [`StoreInfo`] and a some [`DataRow`]s.
+ ///
+ /// This is useful to programmatically create recordings from within the viewer, which cannot
+ /// use the `re_sdk`, which is not Wasm-compatible.
+ pub fn from_info_and_rows(
+ store_info: StoreInfo,
+ rows: impl IntoIterator- ,
+ ) -> Result {
+ let mut store_db = StoreDb::new(store_info.store_id.clone());
+
+ store_db.set_store_info(SetStoreInfo {
+ row_id: RowId::random(),
+ info: store_info,
+ });
+ for row in rows {
+ store_db.add_data_row(&row)?;
+ }
+
+ Ok(store_db)
+ }
+
#[inline]
pub fn entity_db(&self) -> &EntityDb {
&self.entity_db
diff --git a/crates/re_log_types/src/lib.rs b/crates/re_log_types/src/lib.rs
index 58dcc6011698..9bbea82d704a 100644
--- a/crates/re_log_types/src/lib.rs
+++ b/crates/re_log_types/src/lib.rs
@@ -344,6 +344,9 @@ pub enum StoreSource {
file_source: FileSource,
},
+ /// Generated from the viewer itself.
+ Viewer,
+
/// Perhaps from some manual data ingestion?
Other(String),
}
@@ -360,6 +363,7 @@ impl std::fmt::Display for StoreSource {
FileSource::DragAndDrop => write!(f, "File via drag-and-drop"),
FileSource::FileDialog => write!(f, "File via file dialog"),
},
+ Self::Viewer => write!(f, "Viewer-generated"),
Self::Other(string) => format!("{string:?}").fmt(f), // put it in quotes
}
}
diff --git a/crates/re_viewer/data/quick_start_guides/cpp_native.md b/crates/re_viewer/data/quick_start_guides/cpp_native.md
new file mode 100644
index 000000000000..6e96eb5cd031
--- /dev/null
+++ b/crates/re_viewer/data/quick_start_guides/cpp_native.md
@@ -0,0 +1,3 @@
+## C++ Quick Start
+
+TODO(ab): https://github.com/rerun-io/rerun/issues/3870
diff --git a/crates/re_viewer/data/quick_start_guides/how_does_it_work.md b/crates/re_viewer/data/quick_start_guides/how_does_it_work.md
new file mode 100644
index 000000000000..b252be0d1640
--- /dev/null
+++ b/crates/re_viewer/data/quick_start_guides/how_does_it_work.md
@@ -0,0 +1,9 @@
+### How does it work?
+
+Rerun's goal is to make handling and visualizing multimodal data streams easy and performant.
+
+Rerun is made of two main building blocks: the SDK and the Viewer. The data provided by the user code is serialised by the SDK and transferred (via a log file, a TCP socket, a WebSocket, etc.) to the Viewer process for visualization. You can learn more about Rerun's operating modes [here](https://www.rerun.io/docs/reference/sdk-operating-modes).
+
+In the example above, the SDK connects via a TCP socket to the present viewer.
+
+The `log()` function logs _entities_ represented by the "entity path" provided as first argument. Entities are a collection of _components_, which hold the actual data such as position, color, or pixel data. _Archetypes_ such as `Points3D` are builder objects which help creating entities with a consistent set of components that are recognized by the Viewer (they can be entirely bypassed when required by advanced use-cases). You can learn more about Rerun's data model [here](https://www.rerun.io/docs/concepts/entity-component).
diff --git a/crates/re_viewer/data/quick_start_guides/python_native.md b/crates/re_viewer/data/quick_start_guides/python_native.md
new file mode 100644
index 000000000000..6c33bde8ba82
--- /dev/null
+++ b/crates/re_viewer/data/quick_start_guides/python_native.md
@@ -0,0 +1,33 @@
+## Python Quick Start
+
+### Installing the Rerun SDK
+
+The Rerun SDK is available on [PyPI](https://pypi.org/) under the
+[`rerun-sdk`](https://pypi.org/project/rerun-sdk/) name. It can be installed like any other
+Python package:
+
+```sh
+pip install rerun-sdk
+```
+
+### Try out the viewer
+
+The Rerun SDK comes with a demo that can be used to try the viewer. You can send a demo recording
+to this viewer using the following command:
+
+```sh
+python -m rerun_sdk.demo --connect
+```
+
+This will open a new recording that looks like this:
+
+![Demo recording](https://static.rerun.io/quickstart2_simple_cube/632a8f1c79f70a2355fad294fe085291fcf3a8ae/768w.png)
+
+
+### Logging your own data
+
+Instead of a pre-packaged demo, you can log your own data. Copy and paste the following snippet in a new Python file and execute it to create a new recording in this viewer:
+
+```python
+${EXAMPLE_CODE}
+```
diff --git a/crates/re_viewer/data/quick_start_guides/quick_start_connect.cpp b/crates/re_viewer/data/quick_start_guides/quick_start_connect.cpp
new file mode 120000
index 000000000000..2b9e140cfbfc
--- /dev/null
+++ b/crates/re_viewer/data/quick_start_guides/quick_start_connect.cpp
@@ -0,0 +1 @@
+../../../../docs/code-examples/quick_start_connect.cpp
\ No newline at end of file
diff --git a/crates/re_viewer/data/quick_start_guides/quick_start_connect.py b/crates/re_viewer/data/quick_start_guides/quick_start_connect.py
new file mode 120000
index 000000000000..b64a5733fea1
--- /dev/null
+++ b/crates/re_viewer/data/quick_start_guides/quick_start_connect.py
@@ -0,0 +1 @@
+../../../../docs/code-examples/quick_start_connect.py
\ No newline at end of file
diff --git a/crates/re_viewer/data/quick_start_guides/quick_start_connect.rs b/crates/re_viewer/data/quick_start_guides/quick_start_connect.rs
new file mode 120000
index 000000000000..8458ae676f31
--- /dev/null
+++ b/crates/re_viewer/data/quick_start_guides/quick_start_connect.rs
@@ -0,0 +1 @@
+../../../../docs/code-examples/quick_start_connect.rs
\ No newline at end of file
diff --git a/crates/re_viewer/data/quick_start_guides/rust_native.md b/crates/re_viewer/data/quick_start_guides/rust_native.md
new file mode 100644
index 000000000000..6fc3b86d96a3
--- /dev/null
+++ b/crates/re_viewer/data/quick_start_guides/rust_native.md
@@ -0,0 +1,31 @@
+## Rust Quick Start
+
+### Installing Rerun
+
+To use the Rerun SDK in your project, you need the [rerun crate](https://crates.io/crates/rerun) which you can add with `cargo add rerun`.
+
+Let's try it out in a brand-new Rust project:
+
+```sh
+cargo init cube && cd cube && cargo add rerun --features native_viewer
+```
+
+Note that the Rerun SDK requires a working installation of Rust 1.72+.
+
+### Logging your own data
+
+Add the following code to your `main.rs` file:
+
+```rust
+${EXAMPLE_CODE}
+```
+
+You can now run your application:
+
+```shell
+cargo run
+```
+
+Once everything finishes compiling, you will see the points in this viewer:
+
+![Demo recording](https://static.rerun.io/intro_rust_result/cc780eb9bf014d8b1a68fac174b654931f92e14f/768w.png)
diff --git a/crates/re_viewer/src/app.rs b/crates/re_viewer/src/app.rs
index 05812cd1a194..597fd545ba3a 100644
--- a/crates/re_viewer/src/app.rs
+++ b/crates/re_viewer/src/app.rs
@@ -349,6 +349,12 @@ impl App {
}
}
+ SystemCommand::LoadStoreDb(store_db) => {
+ let store_id = store_db.store_id().clone();
+ store_hub.insert_recording(store_db);
+ store_hub.set_recording_id(store_id);
+ }
+
SystemCommand::ResetViewer => self.reset(store_hub, egui_ctx),
SystemCommand::UpdateBlueprint(blueprint_id, updates) => {
let blueprint_db = store_hub.store_db_mut(&blueprint_id);
diff --git a/crates/re_viewer/src/lib.rs b/crates/re_viewer/src/lib.rs
index b2ebcb8d255f..948a0d3151c0 100644
--- a/crates/re_viewer/src/lib.rs
+++ b/crates/re_viewer/src/lib.rs
@@ -102,7 +102,10 @@ impl AppEnvironment {
llvm_version: llvm_version.clone(),
},
- StoreSource::File { .. } | StoreSource::Unknown | StoreSource::Other(_) => {
+ StoreSource::File { .. }
+ | StoreSource::Unknown
+ | StoreSource::Viewer
+ | StoreSource::Other(_) => {
// We should not really get here
#[cfg(debug_assertions)]
diff --git a/crates/re_viewer/src/store_hub.rs b/crates/re_viewer/src/store_hub.rs
index 7479886fd67c..ea376ad5d578 100644
--- a/crates/re_viewer/src/store_hub.rs
+++ b/crates/re_viewer/src/store_hub.rs
@@ -192,6 +192,14 @@ impl StoreHub {
}
}
+ /// Insert a new recording into the [`StoreHub`].
+ ///
+ /// Note that the recording is not automatically made active. Use [`StoreHub::set_recording_id`]
+ /// if needed.
+ pub fn insert_recording(&mut self, store_db: StoreDb) {
+ self.store_dbs.insert_recording(store_db);
+ }
+
/// Mutable access to a [`StoreDb`] by id
pub fn store_db_mut(&mut self, store_id: &StoreId) -> &mut StoreDb {
self.store_dbs.store_db_entry(store_id)
diff --git a/crates/re_viewer/src/ui/welcome_screen/welcome_page.rs b/crates/re_viewer/src/ui/welcome_screen/welcome_page.rs
index 8b5920b61962..cdab927e19a1 100644
--- a/crates/re_viewer/src/ui/welcome_screen/welcome_page.rs
+++ b/crates/re_viewer/src/ui/welcome_screen/welcome_page.rs
@@ -1,12 +1,14 @@
use super::{large_text_button, status_strings, url_large_text_button, WelcomeScreenResponse};
use egui::{NumExt, Ui};
-use re_log_types::LogMsg;
+use itertools::Itertools;
+use re_data_store::StoreDb;
+use re_log_types::{
+ DataRow, EntityPath, LogMsg, RowId, StoreId, StoreInfo, StoreKind, StoreSource, Time, TimePoint,
+};
use re_smart_channel::ReceiveSet;
use re_ui::UICommandSender;
+use re_viewer_context::{SystemCommand, SystemCommandSender};
-//const CPP_QUICKSTART: &str = "https://www.rerun.io/docs/getting-started/cpp";
-const PYTHON_QUICKSTART: &str = "https://www.rerun.io/docs/getting-started/python";
-const RUST_QUICKSTART: &str = "https://www.rerun.io/docs/getting-started/rust";
const SPACE_VIEWS_HELP: &str = "https://www.rerun.io/docs/getting-started/viewer-walkthrough";
/// Show the welcome page.
@@ -58,10 +60,50 @@ fn onboarding_content_ui(
Visualize synchronized data from multiple processes, locally or over a network.",
image: &re_ui::icons::WELCOME_SCREEN_LIVE_DATA,
add_buttons: Box::new(|ui: &mut egui::Ui| {
- // TODO(ab): activate when C++ is ready!
- // url_large_text_button(ui, "C++", CPP_QUICKSTART);
- url_large_text_button(ui, "Python", PYTHON_QUICKSTART);
- url_large_text_button(ui, "Rust", RUST_QUICKSTART);
+ //TODO(#3870): enable with C++ guides are completed
+ #[allow(clippy::collapsible_if)]
+ if false {
+ if large_text_button(ui, "C++").clicked() {
+ open_quick_start(
+ command_sender,
+ [
+ include_str!("../../../data/quick_start_guides/cpp_native.md"),
+ include_str!(
+ "../../../data/quick_start_guides/how_does_it_work.md"
+ ),
+ ],
+ include_str!(
+ "../../../data/quick_start_guides/quick_start_connect.cpp"
+ ),
+ "C++ Quick Start",
+ "cpp_quick_start",
+ );
+ }
+ }
+ if large_text_button(ui, "Python").clicked() {
+ open_quick_start(
+ command_sender,
+ [
+ include_str!("../../../data/quick_start_guides/python_native.md"),
+ include_str!("../../../data/quick_start_guides/how_does_it_work.md"),
+ ],
+ include_str!("../../../data/quick_start_guides/quick_start_connect.py"),
+ "Python Quick Start",
+ "python_quick_start",
+ );
+ }
+ if large_text_button(ui, "Rust").clicked() {
+ open_quick_start(
+ command_sender,
+ [
+ include_str!("../../../data/quick_start_guides/rust_native.md"),
+ include_str!("../../../data/quick_start_guides/how_does_it_work.md"),
+ ],
+ include_str!("../../../data/quick_start_guides/quick_start_connect.rs"),
+ "Rust Quick Start",
+ "rust_quick_start",
+ );
+ }
false
}),
@@ -102,7 +144,7 @@ fn onboarding_content_ui(
},
];
- // Shrink images if needed so user can see all of the content buttons
+ // Shrink images if needed so user can see all the content buttons
let max_image_height = ui.available_height() - 300.0;
let centering_vspace = (ui.available_height() - 650.0) / 2.0;
@@ -231,3 +273,54 @@ fn image_banner(ui: &mut egui::Ui, icon: &re_ui::Icon, column_width: f32, max_im
);
});
}
+
+/// Open a Quick Start recording
+///
+/// The `parts` are joined with newlines to form the markdown, and the spacial tag
+/// `"${EXAMPLE_CODE}"` is replaced with the content of th `example_code` variable.
+fn open_quick_start<'a>(
+ command_sender: &re_viewer_context::CommandSender,
+ parts: impl IntoIterator
- ,
+ example_code: &str,
+ app_id: &str,
+ entity_path: &str,
+) {
+ let mut markdown = parts.into_iter().join("\n");
+ markdown = markdown.replace("${EXAMPLE_CODE}", example_code);
+
+ let res = open_markdown_recording(command_sender, markdown.as_str(), app_id, entity_path);
+ if let Err(err) = res {
+ re_log::error!("Failed to load quick start: {}", err);
+ }
+}
+
+fn open_markdown_recording(
+ command_sender: &re_viewer_context::CommandSender,
+ markdown: &str,
+ app_id: &str,
+ entity_path: &str,
+) -> anyhow::Result<()> {
+ let text_doc = re_types::archetypes::TextDocument::new(markdown)
+ .with_media_type(re_types::components::MediaType::markdown());
+
+ let row = DataRow::from_archetype(
+ RowId::random(),
+ TimePoint::timeless(),
+ EntityPath::from(entity_path),
+ &text_doc,
+ )?;
+
+ let store_info = StoreInfo {
+ application_id: app_id.into(),
+ store_id: StoreId::random(StoreKind::Recording),
+ is_official_example: true,
+ started: Time::now(),
+ store_source: StoreSource::Viewer,
+ store_kind: StoreKind::Recording,
+ };
+
+ let store_db = StoreDb::from_info_and_rows(store_info, [row])?;
+ command_sender.send_system(SystemCommand::LoadStoreDb(store_db));
+
+ Ok(())
+}
diff --git a/crates/re_viewer/src/viewer_analytics.rs b/crates/re_viewer/src/viewer_analytics.rs
index 4a8a280afba9..9317318e7ae0 100644
--- a/crates/re_viewer/src/viewer_analytics.rs
+++ b/crates/re_viewer/src/viewer_analytics.rs
@@ -181,6 +181,7 @@ impl ViewerAnalytics {
re_log_types::FileSource::DragAndDrop => "file_drag_and_drop".to_owned(),
re_log_types::FileSource::FileDialog => "file_dialog".to_owned(),
},
+ StoreSource::Viewer => "viewer".to_owned(),
StoreSource::Other(other) => other.clone(),
};
@@ -210,7 +211,7 @@ impl ViewerAnalytics {
self.deregister("llvm_version"); // can't be both!
}
StoreSource::CSdk => {} // TODO(andreas): Send version and set it.
- StoreSource::Unknown | StoreSource::Other(_) => {}
+ StoreSource::Unknown | StoreSource::Viewer | StoreSource::Other(_) => {}
}
self.register("store_source", store_source);
diff --git a/crates/re_viewer_context/src/command_sender.rs b/crates/re_viewer_context/src/command_sender.rs
index c3923a6f3b4d..4de6ac5ed72a 100644
--- a/crates/re_viewer_context/src/command_sender.rs
+++ b/crates/re_viewer_context/src/command_sender.rs
@@ -1,4 +1,5 @@
use re_data_source::DataSource;
+use re_data_store::StoreDb;
use re_log_types::{DataRow, StoreId};
use re_ui::{UICommand, UICommandSender};
@@ -10,6 +11,9 @@ pub enum SystemCommand {
/// Load some data.
LoadDataSource(DataSource),
+ /// Load some log messages.
+ LoadStoreDb(StoreDb),
+
/// Reset the `Viewer` to the default state
ResetViewer,
diff --git a/docs/code-examples/Cargo.toml b/docs/code-examples/Cargo.toml
index a96c166ab052..33a3f2c7b139 100644
--- a/docs/code-examples/Cargo.toml
+++ b/docs/code-examples/Cargo.toml
@@ -35,6 +35,10 @@ path = "asset3d_simple.rs"
name = "asset3d_out_of_tree"
path = "asset3d_out_of_tree.rs"
+[[bin]]
+name = "box2d_simple"
+path = "box2d_simple.rs"
+
[[bin]]
name = "box3d_simple"
path = "box3d_simple.rs"
@@ -132,8 +136,8 @@ name = "point3d_simple"
path = "point3d_simple.rs"
[[bin]]
-name = "box2d_simple"
-path = "box2d_simple.rs"
+name = "quick_start_connect"
+path = "quick_start_connect.rs"
[[bin]]
name = "scalar_simple"
diff --git a/docs/code-examples/quick_start_connect.cpp b/docs/code-examples/quick_start_connect.cpp
new file mode 100644
index 000000000000..e8c7c8edccd5
--- /dev/null
+++ b/docs/code-examples/quick_start_connect.cpp
@@ -0,0 +1,5 @@
+// TODO(ab): https://github.com/rerun-io/rerun/issues/3870
+
+int main() {
+ return 0;
+}
diff --git a/docs/code-examples/quick_start_connect.py b/docs/code-examples/quick_start_connect.py
new file mode 100644
index 000000000000..543fbc4fe813
--- /dev/null
+++ b/docs/code-examples/quick_start_connect.py
@@ -0,0 +1,28 @@
+"""Connect to the viewer and log some data."""
+
+import numpy as np
+import rerun as rr
+
+# Initialize the SDK and give our recording a unique name
+rr.init("rerun_example_demo")
+
+# Connect to a local viewer using the default port
+rr.connect()
+
+
+# Create some data
+SIZE = 10
+
+pos_grid = np.meshgrid(*[np.linspace(-10, 10, SIZE)] * 3)
+positions = np.vstack([d.reshape(-1) for d in pos_grid]).T
+
+col_grid = np.meshgrid(*[np.linspace(0, 255, SIZE)] * 3)
+colors = np.vstack([c.reshape(-1) for c in col_grid]).astype(np.uint8).T
+
+# Log the data
+rr.log(
+ # name under which this entity is logged (known as "entity path")
+ "my_points",
+ # log data as a 3D point cloud archetype
+ rr.Points3D(positions, colors=colors, radii=0.5),
+)
diff --git a/docs/code-examples/quick_start_connect.rs b/docs/code-examples/quick_start_connect.rs
new file mode 100644
index 000000000000..e5f4665a6609
--- /dev/null
+++ b/docs/code-examples/quick_start_connect.rs
@@ -0,0 +1,24 @@
+//! Connect to the viewer and log some data.
+
+use rerun::{demo_util::grid, external::glam};
+
+fn main() -> Result<(), Box> {
+ // Create a new `RecordingStream` which sends data over TCP to the viewer process.
+ let rec = rerun::RecordingStreamBuilder::new("rerun_example_demo")
+ .connect("127.0.0.1:9876".parse()?, None)?;
+
+ // Create some data using the `grid` utility function.
+ let points = grid(glam::Vec3::splat(-10.0), glam::Vec3::splat(10.0), 10);
+ let colors = grid(glam::Vec3::ZERO, glam::Vec3::splat(255.0), 10)
+ .map(|v| rerun::Color::from_rgb(v.x as u8, v.y as u8, v.z as u8));
+
+ // Log the "my_points" entity with our data, using the `Points3D` archetype.
+ rec.log(
+ "my_points",
+ &rerun::Points3D::new(points)
+ .with_colors(colors)
+ .with_radii([0.5]),
+ )?;
+
+ Ok(())
+}
diff --git a/docs/code-examples/roundtrips.py b/docs/code-examples/roundtrips.py
index 13328bb0ad3c..4d74c1fc769c 100755
--- a/docs/code-examples/roundtrips.py
+++ b/docs/code-examples/roundtrips.py
@@ -33,6 +33,7 @@
"image_simple": ["cpp"], # TODO(#2919): Not yet implemented in C++
"log_line": ["cpp", "rust", "py"], # Not a complete example -- just a single log line
"pinhole_simple": ["cpp"], # TODO(#2919): Seg-faults in C++
+ "quick_start_connect": ["cpp"], # TODO(#3870): Not yet implemented in C++
"scalar_multiple_plots": ["cpp"], # TODO(#2919): Not yet implemented in C++
"segmentation_image_simple": ["cpp"], # TODO(#2919): Not yet implemented in C++
"tensor_simple": ["cpp"], # TODO(#2919): Not yet implemented in C++
@@ -53,6 +54,7 @@
"pinhole_simple": ["cpp", "py", "rust"], # TODO(#3206): examples use different RNGs
"point2d_random": ["cpp", "py", "rust"], # TODO(#3206): examples use different RNGs
"point3d_random": ["cpp", "py", "rust"], # TODO(#3206): examples use different RNGs
+ "quick_start_connect": ["cpp", "py", "rust"], # These example don't have exactly the same implementation.
"tensor_simple": ["cpp", "py", "rust"], # TODO(#3206): examples use different RNGs
"transform3d_simple": ["cpp"], # TODO(#2919): Something broken in the C++ SDK
}