diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 36a1aa121dde..06843e5b2071 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -197,7 +197,7 @@ jobs: - [ ] Should the GH release be published for this alpha? Make a call (give extra love to alphas deployed to Rerun Cloud or when external testing is required). - If yes: - [ ] Edit and publish the GitHub release - - [ ] Stretch goal: generate a raw changelog and add it to the GH release with this disclamer: + - [ ] Stretch goal: generate a raw changelog and add it to the GH release with this disclaimer: **DISCLAIMER**: This is an unreviewed, automatically generated changelog. We only provide fully reviewed changelogs for final releases. - If no: - [ ] Delete the GH release draft @@ -378,19 +378,8 @@ jobs: git tag $version $commit git push origin $version - github-release: - name: "GitHub Release" - if: inputs.release-type == 'rc' || inputs.release-type == 'final' - needs: [tag-release] - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - token: ${{ secrets.RERUN_BOT_TOKEN }} - - name: Create GH release + if: inputs.release-type == 'rc' || inputs.release-type == 'final' env: GH_TOKEN: ${{ secrets.RERUN_BOT_TOKEN }} run: | @@ -406,6 +395,7 @@ jobs: gh release create $version --verify-tag --draft --title $version $pre_arg - name: Create comment + if: inputs.release-type == 'rc' || inputs.release-type == 'final' env: GH_TOKEN: ${{ secrets.RERUN_BOT_TOKEN }} run: | diff --git a/.github/workflows/reusable_checks.yml b/.github/workflows/reusable_checks.yml index b5c18595da7e..0eb7c1d56e81 100644 --- a/.github/workflows/reusable_checks.yml +++ b/.github/workflows/reusable_checks.yml @@ -263,19 +263,21 @@ jobs: key: cache-lychee-${{ github.sha }} restore-keys: cache-lychee- + - name: Set up pixi for PR Link Checker + if: ${{ inputs.CHANNEL == 'pr' }} + uses: prefix-dev/setup-pixi@v0.9.1 + with: + pixi-version: v0.55.0 + # For PRs: Check only links in added lines - name: PR Link Checker (added lines only) if: ${{ inputs.CHANNEL == 'pr' }} run: | - # Install lychee - curl -sSL https://github.com/lycheeverse/lychee/releases/download/lychee-v0.20.1/lychee-x86_64-unknown-linux-gnu.tar.gz | tar -xz - sudo mv lychee /usr/local/bin/ - # Fetch the base branch git fetch origin ${{ github.base_ref }}:${{ github.base_ref }} # Run our custom PR link checker - python3 scripts/ci/pr_link_checker.py --base-ref origin/${{ github.base_ref }} + pixi run link-check-pr origin/${{ github.base_ref }} # For nightly: Check all links in the entire codebase - name: Full Link Checker @@ -287,5 +289,6 @@ jobs: lycheeVersion: "v0.20.1" # When given a directory, lychee checks only markdown, html and text files, everything else we have to glob in manually. # Pass --verbose, so that all considered links are printed, making it easier to debug. + # If updating version or args update the pixi.toml to match. args: | --verbose --cache --max-cache-age 1d . --base . "**/*.md" "**/*.rs" "**/*.toml" "**/*.hpp" "**/*.cpp" "**/CMakeLists.txt" "**/*.py" "**/*.yml" diff --git a/CHANGELOG.md b/CHANGELOG.md index a29bc9fdf66a..11d5d4bb30fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,148 @@ # Rerun changelog +## [0.27.1](https://github.com/rerun-io/rerun/compare/0.27.0...0.27.1) - 2025-11-13 - Bug fixes and performance improvements -## 0.27.0 - TBD - TBD +#### πŸͺ³ Bug fixes +- Respect timepoint in URDF loader [#11866](https://github.com/rerun-io/rerun/pull/11866) +- Fix pinhole color fallback showing the wrong color [#11861](https://github.com/rerun-io/rerun/pull/11861) +- Fix broken `delete_entries` and entries table not updated [#11872](https://github.com/rerun-io/rerun/pull/11872) +- Don't smooth velocity after WASD input [#11858](https://github.com/rerun-io/rerun/pull/11858) +- URDF loader: Use global material if inline material is absent [#11869](https://github.com/rerun-io/rerun/pull/11869) + +#### πŸš€ Performance improvements +- When closing recordings (and blueprints), drop them on separate threads for UI responsiveness [#11834](https://github.com/rerun-io/rerun/pull/11834) (thanks [@kpreid](https://github.com/kpreid)!) +- Remove frame lag when creating loop region [#11862](https://github.com/rerun-io/rerun/pull/11862) +- Reverted [#11766](https://github.com/rerun-io/rerun/pull/11766) because of performance issues with the time panel. + + +## [0.27.0](https://github.com/rerun-io/rerun/compare/0.26.2...0.27.0) - 2025-11-10 - +### ✨ Overview & highlights + +#### πŸ—„οΈ OSS server upgrades +Our OSS server has server has received some attention this version. And now supports properties, layers and blueprint datasets to name a few. + +#### 🟦 more blueprint properties +The viewer is now even more configurable via blueprints. With more options for time series, bar chart, graph views, time panel, and the 3D view. With the latter now having the option to control the 3D eye position and look target. + + + time series view blueprint example + + + + + + + + 3D spatial view blueprint example + + + + + + + +#### βŒ¨πŸ–±οΈUser Interface improvements +We’ve changed the interaction of the time panel! Now the top bar is only for making selections, while the bottom panel is for moving the time cursor. Hold down shift for snap-to-grid! You can also click on events now to select them. + +https://github.com/user-attachments/assets/3cabd74c-8227-4e9d-bd42-fdff36f0466e + +You can now also use just a keyboard to navigate in panels with trees (blueprint / streams / recordings). ### ⚠️ Breaking changes +- Dropped support for python 3.9, and the minimum supported version is now 3.10. +- Dropped support for Intel (x86) macOS. +- Removed the `*_cursor` options from the time panel in the python api. + +See the +🧳 [Migration guide](https://rerun.io/docs/reference/migration/migration-0-27) for more details. + +### πŸ”Ž Details + +#### πŸͺ΅ Log API +- Functionality to `add_time_column` via lenses [#11596](https://github.com/rerun-io/rerun/pull/11596) + +#### 🌊 C++ API +- CMake: Download Arrow from Tarball URL Instead of Git [#11558](https://github.com/rerun-io/rerun/pull/11558) (thanks [@threeal](https://github.com/threeal)!) +- Fix in-repo CMake build not resolving builds of rerun_c that weren't made with pixi [#11751](https://github.com/rerun-io/rerun/pull/11751) + +#### 🐍 Python API +- Expose view container visibility in python blueprint api [#11602](https://github.com/rerun-io/rerun/pull/11602) +- Drop Python 3.9 Support [#11426](https://github.com/rerun-io/rerun/pull/11426) +- Try to avoid timestamp footguns [#11601](https://github.com/rerun-io/rerun/pull/11601) +- py-sdk: add register_prefix SDK call [#11600](https://github.com/rerun-io/rerun/pull/11600) +- [Python] Improve errors in mesh3d_ext [#11662](https://github.com/rerun-io/rerun/pull/11662) (thanks [@iwanders](https://github.com/iwanders)!) +- Return optional DebugInfo with `memory_used` as part of CreateIndexResponse [#11691](https://github.com/rerun-io/rerun/pull/11691) +- Add a new `target_partition_num_rows` API parameter to the CreateIndex API [#11686](https://github.com/rerun-io/rerun/pull/11686) +- Add Ability to Launch OSS Server From Python [#11689](https://github.com/rerun-io/rerun/pull/11689) +- Our IndexValuesLike type is overly strict. Allow np.datetime64 inputs [#11721](https://github.com/rerun-io/rerun/pull/11721) +- Add play state, loop mode and loop selection to blueprint [#11664](https://github.com/rerun-io/rerun/pull/11664) +- Index management APIs: Python bindings, types cleanup, and index statistics [#11729](https://github.com/rerun-io/rerun/pull/11729) +- Remove time from blueprint [#11823](https://github.com/rerun-io/rerun/pull/11823) + +#### πŸ¦€ Rust API +- Make `Debug` for Utf8 datatype derived component types readable [#11780](https://github.com/rerun-io/rerun/pull/11780) + +#### πŸͺ³ Bug fixes +- Fix handling of components that only vary by descriptors [#11593](https://github.com/rerun-io/rerun/pull/11593) +- Fix selection panel infinite redraw [#11623](https://github.com/rerun-io/rerun/pull/11623) +- Allow editing times in the time panel [#11774](https://github.com/rerun-io/rerun/pull/11774) +- Allow moving text cursor while holding down options/alt [#11773](https://github.com/rerun-io/rerun/pull/11773) +- Fix 3D eye speed-up modifier not working with scroll-to-zoom [#11814](https://github.com/rerun-io/rerun/pull/11814) -- Minimum supported Python is now 3.10. -- Dropped support for Intel Mac -- Removed the `*_cursor` option from the time panel in the python api. +#### 🌁 Viewer improvements +- Background of graph view is now blueprint configurable [#11522](https://github.com/rerun-io/rerun/pull/11522) +- Enable multiple instance poses for `Points3D` [#11572](https://github.com/rerun-io/rerun/pull/11572) +- Disable toast when copying component path [#11495](https://github.com/rerun-io/rerun/pull/11495) +- Add cyclic colormap [#11498](https://github.com/rerun-io/rerun/pull/11498) +- Allow eye-camera tracking arbitrary entities in 3D view [#11554](https://github.com/rerun-io/rerun/pull/11554) (thanks [@Gentlegg](https://github.com/Gentlegg)!) +- Introduce experimental `CoordinateFrame` archetype [#11674](https://github.com/rerun-io/rerun/pull/11674) +- Add experimental `child_frame` & `parent_frame` to `Transform3D` [#11730](https://github.com/rerun-io/rerun/pull/11730) +- Expose `TimeSeries` time range & zoom in the Blueprint API [#11621](https://github.com/rerun-io/rerun/pull/11621) +- Improve data density visualization by sampling dense chunks [#11766](https://github.com/rerun-io/rerun/pull/11766) +- 3D eye position and other properties in blueprint [#11788](https://github.com/rerun-io/rerun/pull/11788) +- Support arbitrary transform frame based hierarchies, fully independent of entity hierarchy [#11790](https://github.com/rerun-io/rerun/pull/11790) +- Removing time selection with context menu [#11845](https://github.com/rerun-io/rerun/pull/11845) + +#### πŸ—„οΈ OSS server +- Add support for layers in OSS server [#11532](https://github.com/rerun-io/rerun/pull/11532) +- Add support for properties in OSS server [#11630](https://github.com/rerun-io/rerun/pull/11630) +- Simplify `CreateIndexRequest` [#11636](https://github.com/rerun-io/rerun/pull/11636) +- Improve column projection specification and implement it for OSS server [#11687](https://github.com/rerun-io/rerun/pull/11687) +- Index management APIs [#11693](https://github.com/rerun-io/rerun/pull/11693) +- Add support for blueprint dataset [#11758](https://github.com/rerun-io/rerun/pull/11758) +- Add support for renaming entries [#11777](https://github.com/rerun-io/rerun/pull/11777) +#### πŸš€ Performance improvements +- Perform transform tree walk only once per frame, rather than for every View [#11470](https://github.com/rerun-io/rerun/pull/11470) +- SignificantlyΒ improve transform ingestion speed [#11655](https://github.com/rerun-io/rerun/pull/11655) +- Update mimalloc allocator from v2 to v3 [#11703](https://github.com/rerun-io/rerun/pull/11703) +- Small performance improvement for many entities [#11720](https://github.com/rerun-io/rerun/pull/11720) (thanks [@joelreymont](https://github.com/joelreymont)!) + +#### πŸ§‘β€πŸ« Examples +- Create and write tables in the Rerun server [#11694](https://github.com/rerun-io/rerun/pull/11694) + +#### πŸ“š Docs +- Clarify that 0B memory limit for grpc server only makes sense if client/server are connected from the start [#11599](https://github.com/rerun-io/rerun/pull/11599) +- Add documentation to dataframe query workflow and fix api rendering for bindings [#11650](https://github.com/rerun-io/rerun/pull/11650) +- Expose all the python apis I could find for web docs [#11709](https://github.com/rerun-io/rerun/pull/11709) +- Reorganize Docs Overview / Getting Started [#11781](https://github.com/rerun-io/rerun/pull/11781) + +#### πŸ–Ό UI improvements +- Fix blueprint / streams tree navigation ignoring focus [#11574](https://github.com/rerun-io/rerun/pull/11574) +- Keyboard navigation in tree UIs (left panel, streams panel, etc.) [#11595](https://github.com/rerun-io/rerun/pull/11595) +- Improve formatting of durations and timestamps [#11659](https://github.com/rerun-io/rerun/pull/11659) +- When scrubbing time, intelligently round to a nice value [#11658](https://github.com/rerun-io/rerun/pull/11658) +- Hold down shift for snap to grid when moving time cursor [#11757](https://github.com/rerun-io/rerun/pull/11757) +- Time panel: pick sub-second precision based on zoom level [#11761](https://github.com/rerun-io/rerun/pull/11761) +- Change how to select loop region in the time panel [#11675](https://github.com/rerun-io/rerun/pull/11675) +- Click events in the streams view [#11806](https://github.com/rerun-io/rerun/pull/11806) + +#### πŸ—£ Refactors +- Transform computations are internally now using double precision [#11756](https://github.com/rerun-io/rerun/pull/11756) + +#### πŸ€·β€ Other +- Add client object table writing functions [#11657](https://github.com/rerun-io/rerun/pull/11657) +- Drop official support for Intel Macs [#11719](https://github.com/rerun-io/rerun/pull/11719) ## [0.26.2](https://github.com/rerun-io/rerun/compare/0.26.1...0.26.2) - 2025-10-27 - More bug fixes @@ -1376,7 +1510,7 @@ https://github.com/user-attachments/assets/553b6d88-143d-4cf9-a4bc-6b620534ab95 * 🎬 Native viewer now supports H.264 video if ffmpeg is installed. * πŸ“½οΈ Videos now load a lot faster use less RAM. * πŸ“‚ Improvements to the existing `Open` (Viewer) & `log_file` (SDK) workflows, and addition of a new `Import` workflow. - * Blueprints can now easily be [re-used across different applications, recordings and SDKs](https://rerun.io/docs/howto/visualization/reuse-blueprints) + * Blueprints can now easily be [re-used across different applications, recordings and SDKs](https://rerun.io/docs/concepts/blueprints) * The new `Import` feature allows you to drag-and-drop any data into an existing recording, directly in the viewer. * ☰ Dataframe queries are now streamed, reducing memory usage. * πŸ’Š Add [capsule archetype](https://rerun.io/docs/reference/types/archetypes/capsules3d). diff --git a/Cargo.lock b/Cargo.lock index f5c9c18087ba..5111384dc4c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -270,7 +270,7 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "animated_urdf" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "clap", @@ -543,7 +543,7 @@ dependencies = [ "arrow-schema", "arrow-select", "flatbuffers", - "lz4_flex", + "lz4_flex 0.11.5", "zstd", ] @@ -1810,7 +1810,7 @@ dependencies = [ [[package]] name = "clock" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "clap", @@ -2264,7 +2264,7 @@ checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" [[package]] name = "custom_callback" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "bincode", "mimalloc", @@ -2276,7 +2276,7 @@ dependencies = [ [[package]] name = "custom_data_loader" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "re_build_tools", "rerun", @@ -2284,7 +2284,7 @@ dependencies = [ [[package]] name = "custom_store_subscriber" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "re_build_tools", "rerun", @@ -2292,7 +2292,7 @@ dependencies = [ [[package]] name = "custom_view" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "mimalloc", "rerun", @@ -2355,7 +2355,7 @@ checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" [[package]] name = "dataframe_query" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "itertools 0.14.0", "rerun", @@ -3184,7 +3184,7 @@ dependencies = [ [[package]] name = "dna" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "itertools 0.14.0", "rand 0.9.2", @@ -3728,7 +3728,7 @@ dependencies = [ [[package]] name = "extend_viewer_ui" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "mimalloc", "rerun", @@ -4366,7 +4366,7 @@ dependencies = [ [[package]] name = "graph_lattice" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "clap", @@ -4884,7 +4884,7 @@ checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" [[package]] name = "incremental_logging" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "clap", @@ -5728,7 +5728,7 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "lenses" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "arrow", @@ -5923,7 +5923,7 @@ dependencies = [ [[package]] name = "log_benchmark" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "clap", @@ -5936,7 +5936,7 @@ dependencies = [ [[package]] name = "log_file" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "clap", @@ -6042,6 +6042,15 @@ dependencies = [ "twox-hash", ] +[[package]] +name = "lz4_flex" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab6473172471198271ff72e9379150e9dfd70d8e533e0752a27e515b48dd375e" +dependencies = [ + "twox-hash", +] + [[package]] name = "lzma-sys" version = "0.1.20" @@ -6260,7 +6269,7 @@ dependencies = [ [[package]] name = "minimal" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "rerun", ] @@ -6273,7 +6282,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "minimal_options" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "clap", @@ -6283,7 +6292,7 @@ dependencies = [ [[package]] name = "minimal_serve" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "rerun", ] @@ -7074,7 +7083,7 @@ dependencies = [ [[package]] name = "objectron" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "clap", @@ -7345,7 +7354,7 @@ dependencies = [ "futures", "half", "hashbrown 0.15.5", - "lz4_flex", + "lz4_flex 0.11.5", "num", "num-bigint", "object_store", @@ -7617,7 +7626,7 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plot_dashboard_stress" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "clap", @@ -7973,7 +7982,7 @@ dependencies = [ "byteorder", "cfg-if", "itertools 0.10.5", - "lz4_flex", + "lz4_flex 0.11.5", "once_cell", "parking_lot", "serde", @@ -8302,7 +8311,7 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "raw_mesh" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "bytes", @@ -8339,7 +8348,7 @@ dependencies = [ [[package]] name = "re_analytics" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "crossbeam", "directories", @@ -8360,7 +8369,7 @@ dependencies = [ [[package]] name = "re_arrow_combinators" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "insta", @@ -8370,7 +8379,7 @@ dependencies = [ [[package]] name = "re_arrow_ui" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "egui", @@ -8387,7 +8396,7 @@ dependencies = [ [[package]] name = "re_arrow_util" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "arrow", @@ -8404,7 +8413,7 @@ dependencies = [ [[package]] name = "re_auth" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "async-trait", "base64 0.22.1", @@ -8435,7 +8444,7 @@ dependencies = [ [[package]] name = "re_blueprint_tree" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "egui", "egui_kittest", @@ -8462,7 +8471,7 @@ dependencies = [ [[package]] name = "re_build_info" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "re_byte_size", "serde", @@ -8470,7 +8479,7 @@ dependencies = [ [[package]] name = "re_build_tools" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "cargo_metadata 0.23.0", @@ -8484,7 +8493,7 @@ dependencies = [ [[package]] name = "re_byte_size" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "half", @@ -8493,7 +8502,7 @@ dependencies = [ [[package]] name = "re_capabilities" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "document-features", "egui", @@ -8502,14 +8511,14 @@ dependencies = [ [[package]] name = "re_case" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "convert_case", ] [[package]] name = "re_chunk" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -8540,7 +8549,7 @@ dependencies = [ [[package]] name = "re_chunk_store" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -8572,7 +8581,7 @@ dependencies = [ [[package]] name = "re_chunk_store_ui" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "egui", @@ -8591,7 +8600,7 @@ dependencies = [ [[package]] name = "re_component_fallbacks" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "re_log_types", "re_types", @@ -8600,7 +8609,7 @@ dependencies = [ [[package]] name = "re_component_ui" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "egui", @@ -8626,7 +8635,7 @@ dependencies = [ [[package]] name = "re_context_menu" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "egui", "egui_tiles", @@ -8647,7 +8656,7 @@ dependencies = [ [[package]] name = "re_crash_handler" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "backtrace", "econtext", @@ -8660,7 +8669,7 @@ dependencies = [ [[package]] name = "re_data_loader" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -8698,7 +8707,7 @@ dependencies = [ [[package]] name = "re_data_source" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "itertools 0.14.0", @@ -8721,7 +8730,7 @@ dependencies = [ [[package]] name = "re_data_ui" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -8755,7 +8764,7 @@ dependencies = [ [[package]] name = "re_dataframe" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "arrow", @@ -8781,7 +8790,7 @@ dependencies = [ [[package]] name = "re_dataframe_ui" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "arrow", @@ -8820,7 +8829,7 @@ dependencies = [ [[package]] name = "re_datafusion" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "arrow", @@ -8849,7 +8858,7 @@ dependencies = [ [[package]] name = "re_dev_tools" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "argh", @@ -8876,7 +8885,7 @@ dependencies = [ [[package]] name = "re_entity_db" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -8911,14 +8920,14 @@ dependencies = [ [[package]] name = "re_error" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", ] [[package]] name = "re_format" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "half", "itertools 0.14.0", @@ -8927,7 +8936,7 @@ dependencies = [ [[package]] name = "re_grpc_client" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "async-stream", "crossbeam", @@ -8951,7 +8960,7 @@ dependencies = [ [[package]] name = "re_grpc_server" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "crossbeam", @@ -8981,7 +8990,7 @@ dependencies = [ [[package]] name = "re_int_histogram" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "criterion", "insta", @@ -8992,7 +9001,7 @@ dependencies = [ [[package]] name = "re_integration_test" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "egui", "egui_kittest", @@ -9015,7 +9024,7 @@ dependencies = [ [[package]] name = "re_log" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "env_filter", "env_logger", @@ -9029,14 +9038,14 @@ dependencies = [ [[package]] name = "re_log_encoding" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "bytes", "criterion", "ehttp", "js-sys", - "lz4_flex", + "lz4_flex 0.12.0", "mimalloc", "parking_lot", "re_build_info", @@ -9061,7 +9070,7 @@ dependencies = [ [[package]] name = "re_log_types" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "arrow", @@ -9098,7 +9107,7 @@ dependencies = [ [[package]] name = "re_mcap" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -9122,7 +9131,7 @@ dependencies = [ [[package]] name = "re_memory" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "backtrace", @@ -9157,7 +9166,7 @@ dependencies = [ [[package]] name = "re_perf_telemetry" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -9187,7 +9196,7 @@ dependencies = [ [[package]] name = "re_protos" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "http", @@ -9215,7 +9224,7 @@ dependencies = [ [[package]] name = "re_protos_builder" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "camino", "re_log", @@ -9224,7 +9233,7 @@ dependencies = [ [[package]] name = "re_query" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -9279,7 +9288,7 @@ dependencies = [ [[package]] name = "re_recording_panel" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "egui", @@ -9302,7 +9311,7 @@ dependencies = [ [[package]] name = "re_redap_browser" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "datafusion", @@ -9333,7 +9342,7 @@ dependencies = [ [[package]] name = "re_redap_client" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "itertools 0.14.0", @@ -9361,7 +9370,7 @@ dependencies = [ [[package]] name = "re_redap_tests" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "arrow", @@ -9387,7 +9396,7 @@ dependencies = [ [[package]] name = "re_renderer" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -9438,7 +9447,7 @@ dependencies = [ [[package]] name = "re_renderer_examples" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -9461,7 +9470,7 @@ dependencies = [ [[package]] name = "re_ros_msg" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "serde", @@ -9470,7 +9479,7 @@ dependencies = [ [[package]] name = "re_sdk" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "arrow", @@ -9508,7 +9517,7 @@ dependencies = [ [[package]] name = "re_selection_panel" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "egui", @@ -9541,7 +9550,7 @@ dependencies = [ [[package]] name = "re_server" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -9587,7 +9596,7 @@ dependencies = [ [[package]] name = "re_smart_channel" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "crossbeam", "parking_lot", @@ -9600,7 +9609,7 @@ dependencies = [ [[package]] name = "re_sorbet" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "itertools 0.14.0", @@ -9619,14 +9628,14 @@ dependencies = [ [[package]] name = "re_span" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "num-traits", ] [[package]] name = "re_string_interner" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "nohash-hasher", @@ -9637,7 +9646,7 @@ dependencies = [ [[package]] name = "re_test_context" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -9668,7 +9677,7 @@ dependencies = [ [[package]] name = "re_test_viewport" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "egui", @@ -9684,7 +9693,7 @@ dependencies = [ [[package]] name = "re_tf" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "bitflags 2.9.4", @@ -9707,7 +9716,7 @@ dependencies = [ [[package]] name = "re_time_panel" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "criterion", @@ -9737,7 +9746,7 @@ dependencies = [ [[package]] name = "re_tracing" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "puffin", "puffin_http", @@ -9748,7 +9757,7 @@ dependencies = [ [[package]] name = "re_tuid" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "bytemuck", "criterion", @@ -9762,7 +9771,7 @@ dependencies = [ [[package]] name = "re_types" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "array-init", @@ -9804,7 +9813,7 @@ dependencies = [ [[package]] name = "re_types_builder" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "camino", @@ -9832,7 +9841,7 @@ dependencies = [ [[package]] name = "re_types_core" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "arrow", @@ -9856,7 +9865,7 @@ dependencies = [ [[package]] name = "re_ui" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -9893,7 +9902,7 @@ dependencies = [ [[package]] name = "re_uri" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "re_log_types", "re_tuid", @@ -9904,7 +9913,7 @@ dependencies = [ [[package]] name = "re_video" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "bit-vec", @@ -9940,7 +9949,7 @@ dependencies = [ [[package]] name = "re_view" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "egui", @@ -9963,7 +9972,7 @@ dependencies = [ [[package]] name = "re_view_bar_chart" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "egui", @@ -9984,7 +9993,7 @@ dependencies = [ [[package]] name = "re_view_dataframe" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "arrow", @@ -10013,7 +10022,7 @@ dependencies = [ [[package]] name = "re_view_graph" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "egui", @@ -10041,7 +10050,7 @@ dependencies = [ [[package]] name = "re_view_map" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "bytemuck", "egui", @@ -10066,7 +10075,7 @@ dependencies = [ [[package]] name = "re_view_spatial" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -10116,7 +10125,7 @@ dependencies = [ [[package]] name = "re_view_tensor" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "bytemuck", @@ -10142,7 +10151,7 @@ dependencies = [ [[package]] name = "re_view_text_document" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "egui", "egui_commonmark", @@ -10161,7 +10170,7 @@ dependencies = [ [[package]] name = "re_view_text_log" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "egui", "egui_extras", @@ -10182,7 +10191,7 @@ dependencies = [ [[package]] name = "re_view_time_series" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "egui", "egui_plot", @@ -10208,7 +10217,7 @@ dependencies = [ [[package]] name = "re_viewer" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -10304,7 +10313,7 @@ dependencies = [ [[package]] name = "re_viewer_context" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -10371,7 +10380,7 @@ dependencies = [ [[package]] name = "re_viewport" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "egui", @@ -10394,7 +10403,7 @@ dependencies = [ [[package]] name = "re_viewport_blueprint" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "arrow", @@ -10424,7 +10433,7 @@ dependencies = [ [[package]] name = "re_web_viewer_server" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "document-features", "re_analytics", @@ -10610,7 +10619,7 @@ dependencies = [ [[package]] name = "rerun" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "anyhow", @@ -10668,7 +10677,7 @@ dependencies = [ [[package]] name = "rerun-cli" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "document-features", "mimalloc", @@ -10683,7 +10692,7 @@ dependencies = [ [[package]] name = "rerun-loader-rust-file" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "argh", @@ -10692,7 +10701,7 @@ dependencies = [ [[package]] name = "rerun_c" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "ahash", "arrow", @@ -10709,7 +10718,7 @@ dependencies = [ [[package]] name = "rerun_py" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "arrow", "bytes", @@ -10873,7 +10882,7 @@ checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" [[package]] name = "run_wasm" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "cargo-run-wasm", "pico-args", @@ -11315,7 +11324,7 @@ dependencies = [ [[package]] name = "shared_recording" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "rerun", ] @@ -11520,7 +11529,7 @@ checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "snippets" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "itertools 0.14.0", "ndarray", @@ -11553,7 +11562,7 @@ dependencies = [ [[package]] name = "spawn_viewer" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "rerun", ] @@ -11639,7 +11648,7 @@ checksum = "8207e78455ffdf55661170876f88daf85356e4edd54e0a3dbc79586ca1e50cbe" [[package]] name = "stdio" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "rerun", ] @@ -11806,7 +11815,7 @@ dependencies = [ "levenshtein_automata", "log", "lru 0.12.5", - "lz4_flex", + "lz4_flex 0.11.5", "measure_time", "memmap2 0.9.8", "once_cell", @@ -11954,7 +11963,7 @@ dependencies = [ [[package]] name = "template" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "rerun", ] @@ -11970,7 +11979,7 @@ dependencies = [ [[package]] name = "test_data_density_graph" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "rand 0.9.2", @@ -11980,7 +11989,7 @@ dependencies = [ [[package]] name = "test_image_memory" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "mimalloc", "re_format", @@ -11990,7 +11999,7 @@ dependencies = [ [[package]] name = "test_out_of_order_transforms" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "clap", @@ -12001,7 +12010,7 @@ dependencies = [ [[package]] name = "test_ui_wakeup" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anyhow", "clap", @@ -12930,7 +12939,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "viewer_callbacks" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "mimalloc", "rerun", diff --git a/Cargo.toml b/Cargo.toml index 529cc5cda021..c19eb2163e5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ include = [ license = "MIT OR Apache-2.0" repository = "https://github.com/rerun-io/rerun" rust-version = "1.88" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" [workspace.metadata.cargo-shear] ignored = [ @@ -57,98 +57,98 @@ ignored = [ # re_log_types 0.3.0-alpha.0, NOT 0.3.0-alpha.4 even though it is newer and semver-compatible. # crates/build: -re_build_info = { path = "crates/build/re_build_info", version = "=0.27.0-alpha.8", default-features = false } -re_build_tools = { path = "crates/build/re_build_tools", version = "=0.27.0-alpha.8", default-features = false } -re_dev_tools = { path = "crates/build/re_dev_tools", version = "=0.27.0-alpha.8", default-features = false } -re_protos_builder = { path = "crates/build/re_protos_builder", version = "=0.27.0-alpha.8", default-features = false } -re_types_builder = { path = "crates/build/re_types_builder", version = "=0.27.0-alpha.8", default-features = false } +re_build_info = { path = "crates/build/re_build_info", version = "=0.28.0-alpha.1", default-features = false } +re_build_tools = { path = "crates/build/re_build_tools", version = "=0.28.0-alpha.1", default-features = false } +re_dev_tools = { path = "crates/build/re_dev_tools", version = "=0.28.0-alpha.1", default-features = false } +re_protos_builder = { path = "crates/build/re_protos_builder", version = "=0.28.0-alpha.1", default-features = false } +re_types_builder = { path = "crates/build/re_types_builder", version = "=0.28.0-alpha.1", default-features = false } # crates/store: -re_chunk = { path = "crates/store/re_chunk", version = "=0.27.0-alpha.8", default-features = false } -re_chunk_store = { path = "crates/store/re_chunk_store", version = "=0.27.0-alpha.8", default-features = false } -re_data_loader = { path = "crates/store/re_data_loader", version = "=0.27.0-alpha.8", default-features = false } -re_data_source = { path = "crates/store/re_data_source", version = "=0.27.0-alpha.8", default-features = false } -re_dataframe = { path = "crates/store/re_dataframe", version = "=0.27.0-alpha.8", default-features = false } -re_datafusion = { path = "crates/store/re_datafusion", version = "=0.27.0-alpha.8", default-features = false } -re_entity_db = { path = "crates/store/re_entity_db", version = "=0.27.0-alpha.8", default-features = false } -re_grpc_client = { path = "crates/store/re_grpc_client", version = "=0.27.0-alpha.8", default-features = false } -re_grpc_server = { path = "crates/store/re_grpc_server", version = "=0.27.0-alpha.8", default-features = false } -re_log_encoding = { path = "crates/store/re_log_encoding", version = "=0.27.0-alpha.8", default-features = false } -re_log_types = { path = "crates/store/re_log_types", version = "=0.27.0-alpha.8", default-features = false } -re_protos = { path = "crates/store/re_protos", version = "=0.27.0-alpha.8", default-features = false } -re_query = { path = "crates/store/re_query", version = "=0.27.0-alpha.8", default-features = false } -re_redap_client = { path = "crates/store/re_redap_client", version = "=0.27.0-alpha.8", default-features = false } -re_redap_tests = { path = "crates/store/re_redap_tests", version = "=0.27.0-alpha.8", default-features = false } -re_server = { path = "crates/store/re_server", version = "=0.27.0-alpha.8", default-features = false } -re_sorbet = { path = "crates/store/re_sorbet", version = "=0.27.0-alpha.8", default-features = false } -re_tf = { path = "crates/store/re_tf", version = "=0.27.0-alpha.8", default-features = false } -re_types = { path = "crates/store/re_types", version = "=0.27.0-alpha.8", default-features = false } -re_types_core = { path = "crates/store/re_types_core", version = "=0.27.0-alpha.8", default-features = false } +re_chunk = { path = "crates/store/re_chunk", version = "=0.28.0-alpha.1", default-features = false } +re_chunk_store = { path = "crates/store/re_chunk_store", version = "=0.28.0-alpha.1", default-features = false } +re_data_loader = { path = "crates/store/re_data_loader", version = "=0.28.0-alpha.1", default-features = false } +re_data_source = { path = "crates/store/re_data_source", version = "=0.28.0-alpha.1", default-features = false } +re_dataframe = { path = "crates/store/re_dataframe", version = "=0.28.0-alpha.1", default-features = false } +re_datafusion = { path = "crates/store/re_datafusion", version = "=0.28.0-alpha.1", default-features = false } +re_entity_db = { path = "crates/store/re_entity_db", version = "=0.28.0-alpha.1", default-features = false } +re_grpc_client = { path = "crates/store/re_grpc_client", version = "=0.28.0-alpha.1", default-features = false } +re_grpc_server = { path = "crates/store/re_grpc_server", version = "=0.28.0-alpha.1", default-features = false } +re_log_encoding = { path = "crates/store/re_log_encoding", version = "=0.28.0-alpha.1", default-features = false } +re_log_types = { path = "crates/store/re_log_types", version = "=0.28.0-alpha.1", default-features = false } +re_protos = { path = "crates/store/re_protos", version = "=0.28.0-alpha.1", default-features = false } +re_query = { path = "crates/store/re_query", version = "=0.28.0-alpha.1", default-features = false } +re_redap_client = { path = "crates/store/re_redap_client", version = "=0.28.0-alpha.1", default-features = false } +re_redap_tests = { path = "crates/store/re_redap_tests", version = "=0.28.0-alpha.1", default-features = false } +re_server = { path = "crates/store/re_server", version = "=0.28.0-alpha.1", default-features = false } +re_sorbet = { path = "crates/store/re_sorbet", version = "=0.28.0-alpha.1", default-features = false } +re_tf = { path = "crates/store/re_tf", version = "=0.28.0-alpha.1", default-features = false } +re_types = { path = "crates/store/re_types", version = "=0.28.0-alpha.1", default-features = false } +re_types_core = { path = "crates/store/re_types_core", version = "=0.28.0-alpha.1", default-features = false } # crates/top: -re_sdk = { path = "crates/top/re_sdk", version = "=0.27.0-alpha.8", default-features = false } -rerun = { path = "crates/top/rerun", version = "=0.27.0-alpha.8", default-features = false } -rerun_c = { path = "crates/top/rerun_c", version = "=0.27.0-alpha.8", default-features = false } -rerun-cli = { path = "crates/top/rerun-cli", version = "=0.27.0-alpha.8", default-features = false } +re_sdk = { path = "crates/top/re_sdk", version = "=0.28.0-alpha.1", default-features = false } +rerun = { path = "crates/top/rerun", version = "=0.28.0-alpha.1", default-features = false } +rerun_c = { path = "crates/top/rerun_c", version = "=0.28.0-alpha.1", default-features = false } +rerun-cli = { path = "crates/top/rerun-cli", version = "=0.28.0-alpha.1", default-features = false } # crates/utils: -re_analytics = { path = "crates/utils/re_analytics", version = "=0.27.0-alpha.8", default-features = false } -re_arrow_combinators = { path = "crates/utils/re_arrow_combinators", version = "=0.27.0-alpha.8", default-features = false } -re_arrow_util = { path = "crates/utils/re_arrow_util", version = "=0.27.0-alpha.8", default-features = false } -re_auth = { path = "crates/utils/re_auth", version = "=0.27.0-alpha.8", default-features = false } -re_byte_size = { path = "crates/utils/re_byte_size", version = "=0.27.0-alpha.8", default-features = false } -re_capabilities = { path = "crates/utils/re_capabilities", version = "=0.27.0-alpha.8", default-features = false } -re_case = { path = "crates/utils/re_case", version = "=0.27.0-alpha.8", default-features = false } -re_crash_handler = { path = "crates/utils/re_crash_handler", version = "=0.27.0-alpha.8", default-features = false } -re_error = { path = "crates/utils/re_error", version = "=0.27.0-alpha.8", default-features = false } -re_format = { path = "crates/utils/re_format", version = "=0.27.0-alpha.8", default-features = false } -re_int_histogram = { path = "crates/utils/re_int_histogram", version = "=0.27.0-alpha.8", default-features = false } -re_log = { path = "crates/utils/re_log", version = "=0.27.0-alpha.8", default-features = false } -re_mcap = { path = "crates/utils/re_mcap", version = "=0.27.0-alpha.8", default-features = false } -re_memory = { path = "crates/utils/re_memory", version = "=0.27.0-alpha.8", default-features = false } -re_perf_telemetry = { path = "crates/utils/re_perf_telemetry", version = "=0.27.0-alpha.8", default-features = false } -re_ros_msg = { path = "crates/utils/re_ros_msg", version = "=0.27.0-alpha.8", default-features = false } -re_smart_channel = { path = "crates/utils/re_smart_channel", version = "=0.27.0-alpha.8", default-features = false } -re_span = { path = "crates/utils/re_span", version = "=0.27.0-alpha.8", default-features = false } -re_string_interner = { path = "crates/utils/re_string_interner", version = "=0.27.0-alpha.8", default-features = false } -re_tracing = { path = "crates/utils/re_tracing", version = "=0.27.0-alpha.8", default-features = false } -re_tuid = { path = "crates/utils/re_tuid", version = "=0.27.0-alpha.8", default-features = false } -re_uri = { path = "crates/utils/re_uri", version = "=0.27.0-alpha.8", default-features = false } -re_video = { path = "crates/utils/re_video", version = "=0.27.0-alpha.8", default-features = false } +re_analytics = { path = "crates/utils/re_analytics", version = "=0.28.0-alpha.1", default-features = false } +re_arrow_combinators = { path = "crates/utils/re_arrow_combinators", version = "=0.28.0-alpha.1", default-features = false } +re_arrow_util = { path = "crates/utils/re_arrow_util", version = "=0.28.0-alpha.1", default-features = false } +re_auth = { path = "crates/utils/re_auth", version = "=0.28.0-alpha.1", default-features = false } +re_byte_size = { path = "crates/utils/re_byte_size", version = "=0.28.0-alpha.1", default-features = false } +re_capabilities = { path = "crates/utils/re_capabilities", version = "=0.28.0-alpha.1", default-features = false } +re_case = { path = "crates/utils/re_case", version = "=0.28.0-alpha.1", default-features = false } +re_crash_handler = { path = "crates/utils/re_crash_handler", version = "=0.28.0-alpha.1", default-features = false } +re_error = { path = "crates/utils/re_error", version = "=0.28.0-alpha.1", default-features = false } +re_format = { path = "crates/utils/re_format", version = "=0.28.0-alpha.1", default-features = false } +re_int_histogram = { path = "crates/utils/re_int_histogram", version = "=0.28.0-alpha.1", default-features = false } +re_log = { path = "crates/utils/re_log", version = "=0.28.0-alpha.1", default-features = false } +re_mcap = { path = "crates/utils/re_mcap", version = "=0.28.0-alpha.1", default-features = false } +re_memory = { path = "crates/utils/re_memory", version = "=0.28.0-alpha.1", default-features = false } +re_perf_telemetry = { path = "crates/utils/re_perf_telemetry", version = "=0.28.0-alpha.1", default-features = false } +re_ros_msg = { path = "crates/utils/re_ros_msg", version = "=0.28.0-alpha.1", default-features = false } +re_smart_channel = { path = "crates/utils/re_smart_channel", version = "=0.28.0-alpha.1", default-features = false } +re_span = { path = "crates/utils/re_span", version = "=0.28.0-alpha.1", default-features = false } +re_string_interner = { path = "crates/utils/re_string_interner", version = "=0.28.0-alpha.1", default-features = false } +re_tracing = { path = "crates/utils/re_tracing", version = "=0.28.0-alpha.1", default-features = false } +re_tuid = { path = "crates/utils/re_tuid", version = "=0.28.0-alpha.1", default-features = false } +re_uri = { path = "crates/utils/re_uri", version = "=0.28.0-alpha.1", default-features = false } +re_video = { path = "crates/utils/re_video", version = "=0.28.0-alpha.1", default-features = false } # crates/viewer: -re_arrow_ui = { path = "crates/viewer/re_arrow_ui", version = "=0.27.0-alpha.8", default-features = false } -re_blueprint_tree = { path = "crates/viewer/re_blueprint_tree", version = "=0.27.0-alpha.8", default-features = false } -re_redap_browser = { path = "crates/viewer/re_redap_browser", version = "=0.27.0-alpha.8", default-features = false } -re_component_fallbacks = { path = "crates/viewer/re_component_fallbacks", version = "=0.27.0-alpha.8", default-features = false } -re_component_ui = { path = "crates/viewer/re_component_ui", version = "=0.27.0-alpha.8", default-features = false } -re_context_menu = { path = "crates/viewer/re_context_menu", version = "=0.27.0-alpha.8", default-features = false } -re_chunk_store_ui = { path = "crates/viewer/re_chunk_store_ui", version = "=0.27.0-alpha.8", default-features = false } -re_dataframe_ui = { path = "crates/viewer/re_dataframe_ui", version = "=0.27.0-alpha.8", default-features = false } -re_data_ui = { path = "crates/viewer/re_data_ui", version = "=0.27.0-alpha.8", default-features = false } -re_recording_panel = { path = "crates/viewer/re_recording_panel", version = "=0.27.0-alpha.8", default-features = false } -re_renderer = { path = "crates/viewer/re_renderer", version = "=0.27.0-alpha.8", default-features = false } -re_renderer_examples = { path = "crates/viewer/re_renderer_examples", version = "=0.27.0-alpha.8", default-features = false } -re_selection_panel = { path = "crates/viewer/re_selection_panel", version = "=0.27.0-alpha.8", default-features = false } -re_test_context = { path = "crates/viewer/re_test_context", version = "=0.27.0-alpha.8", default-features = false } -re_test_viewport = { path = "crates/viewer/re_test_viewport", version = "=0.27.0-alpha.8", default-features = false } -re_time_panel = { path = "crates/viewer/re_time_panel", version = "=0.27.0-alpha.8", default-features = false } -re_ui = { path = "crates/viewer/re_ui", version = "=0.27.0-alpha.8", default-features = false } -re_view = { path = "crates/viewer/re_view", version = "=0.27.0-alpha.8", default-features = false } -re_view_bar_chart = { path = "crates/viewer/re_view_bar_chart", version = "=0.27.0-alpha.8", default-features = false } -re_view_spatial = { path = "crates/viewer/re_view_spatial", version = "=0.27.0-alpha.8", default-features = false } -re_view_dataframe = { path = "crates/viewer/re_view_dataframe", version = "=0.27.0-alpha.8", default-features = false } -re_view_graph = { path = "crates/viewer/re_view_graph", version = "=0.27.0-alpha.8", default-features = false } -re_view_map = { path = "crates/viewer/re_view_map", version = "=0.27.0-alpha.8", default-features = false } -re_view_tensor = { path = "crates/viewer/re_view_tensor", version = "=0.27.0-alpha.8", default-features = false } -re_view_text_document = { path = "crates/viewer/re_view_text_document", version = "=0.27.0-alpha.8", default-features = false } -re_view_text_log = { path = "crates/viewer/re_view_text_log", version = "=0.27.0-alpha.8", default-features = false } -re_view_time_series = { path = "crates/viewer/re_view_time_series", version = "=0.27.0-alpha.8", default-features = false } -re_viewer = { path = "crates/viewer/re_viewer", version = "=0.27.0-alpha.8", default-features = false } -re_viewer_context = { path = "crates/viewer/re_viewer_context", version = "=0.27.0-alpha.8", default-features = false } -re_viewport = { path = "crates/viewer/re_viewport", version = "=0.27.0-alpha.8", default-features = false } -re_viewport_blueprint = { path = "crates/viewer/re_viewport_blueprint", version = "=0.27.0-alpha.8", default-features = false } -re_web_viewer_server = { path = "crates/viewer/re_web_viewer_server", version = "=0.27.0-alpha.8", default-features = false } +re_arrow_ui = { path = "crates/viewer/re_arrow_ui", version = "=0.28.0-alpha.1", default-features = false } +re_blueprint_tree = { path = "crates/viewer/re_blueprint_tree", version = "=0.28.0-alpha.1", default-features = false } +re_redap_browser = { path = "crates/viewer/re_redap_browser", version = "=0.28.0-alpha.1", default-features = false } +re_component_fallbacks = { path = "crates/viewer/re_component_fallbacks", version = "=0.28.0-alpha.1", default-features = false } +re_component_ui = { path = "crates/viewer/re_component_ui", version = "=0.28.0-alpha.1", default-features = false } +re_context_menu = { path = "crates/viewer/re_context_menu", version = "=0.28.0-alpha.1", default-features = false } +re_chunk_store_ui = { path = "crates/viewer/re_chunk_store_ui", version = "=0.28.0-alpha.1", default-features = false } +re_dataframe_ui = { path = "crates/viewer/re_dataframe_ui", version = "=0.28.0-alpha.1", default-features = false } +re_data_ui = { path = "crates/viewer/re_data_ui", version = "=0.28.0-alpha.1", default-features = false } +re_recording_panel = { path = "crates/viewer/re_recording_panel", version = "=0.28.0-alpha.1", default-features = false } +re_renderer = { path = "crates/viewer/re_renderer", version = "=0.28.0-alpha.1", default-features = false } +re_renderer_examples = { path = "crates/viewer/re_renderer_examples", version = "=0.28.0-alpha.1", default-features = false } +re_selection_panel = { path = "crates/viewer/re_selection_panel", version = "=0.28.0-alpha.1", default-features = false } +re_test_context = { path = "crates/viewer/re_test_context", version = "=0.28.0-alpha.1", default-features = false } +re_test_viewport = { path = "crates/viewer/re_test_viewport", version = "=0.28.0-alpha.1", default-features = false } +re_time_panel = { path = "crates/viewer/re_time_panel", version = "=0.28.0-alpha.1", default-features = false } +re_ui = { path = "crates/viewer/re_ui", version = "=0.28.0-alpha.1", default-features = false } +re_view = { path = "crates/viewer/re_view", version = "=0.28.0-alpha.1", default-features = false } +re_view_bar_chart = { path = "crates/viewer/re_view_bar_chart", version = "=0.28.0-alpha.1", default-features = false } +re_view_spatial = { path = "crates/viewer/re_view_spatial", version = "=0.28.0-alpha.1", default-features = false } +re_view_dataframe = { path = "crates/viewer/re_view_dataframe", version = "=0.28.0-alpha.1", default-features = false } +re_view_graph = { path = "crates/viewer/re_view_graph", version = "=0.28.0-alpha.1", default-features = false } +re_view_map = { path = "crates/viewer/re_view_map", version = "=0.28.0-alpha.1", default-features = false } +re_view_tensor = { path = "crates/viewer/re_view_tensor", version = "=0.28.0-alpha.1", default-features = false } +re_view_text_document = { path = "crates/viewer/re_view_text_document", version = "=0.28.0-alpha.1", default-features = false } +re_view_text_log = { path = "crates/viewer/re_view_text_log", version = "=0.28.0-alpha.1", default-features = false } +re_view_time_series = { path = "crates/viewer/re_view_time_series", version = "=0.28.0-alpha.1", default-features = false } +re_viewer = { path = "crates/viewer/re_viewer", version = "=0.28.0-alpha.1", default-features = false } +re_viewer_context = { path = "crates/viewer/re_viewer_context", version = "=0.28.0-alpha.1", default-features = false } +re_viewport = { path = "crates/viewer/re_viewport", version = "=0.28.0-alpha.1", default-features = false } +re_viewport_blueprint = { path = "crates/viewer/re_viewport_blueprint", version = "=0.28.0-alpha.1", default-features = false } +re_web_viewer_server = { path = "crates/viewer/re_web_viewer_server", version = "=0.28.0-alpha.1", default-features = false } # Rerun crates in other repos: re_mp4 = "0.4.0" @@ -267,7 +267,7 @@ libc = "0.2.176" linked-hash-map = { version = "0.5.6", default-features = false } log = "0.4.28" log-once = "0.4.1" -lz4_flex = "0.11.5" +lz4_flex = "0.12" macaw = "0.30.0" mcap = "0.23.3" memmap2 = "0.9.8" diff --git a/crates/store/re_data_loader/src/loader_urdf.rs b/crates/store/re_data_loader/src/loader_urdf.rs index d144aaa2b9fd..991979c5bc22 100644 --- a/crates/store/re_data_loader/src/loader_urdf.rs +++ b/crates/store/re_data_loader/src/loader_urdf.rs @@ -42,6 +42,7 @@ fn send_archetype( tx: &Sender, store_id: &StoreId, entity_path: EntityPath, + timepoint: &TimePoint, archetype: &impl AsComponents, ) -> anyhow::Result<()> { send_chunk_builder( @@ -49,7 +50,7 @@ fn send_archetype( store_id, ChunkBuilder::new(ChunkId::new(), entity_path).with_archetype( RowId::new(), - TimePoint::default(), + timepoint.clone(), archetype, ), ) @@ -86,6 +87,7 @@ impl DataLoader for UrdfDataLoader { &tx, &settings.recommended_store_id(), &settings.entity_path_prefix, + &settings.timepoint.clone().unwrap_or_default(), ) .with_context(|| "Failed to load URDF file!")?; @@ -114,6 +116,7 @@ impl DataLoader for UrdfDataLoader { &tx, &settings.recommended_store_id(), &settings.entity_path_prefix, + &settings.timepoint.clone().unwrap_or_default(), ) .with_context(|| "Failed to load URDF file!")?; @@ -256,6 +259,11 @@ impl UrdfTree { pub fn get_joint_child(&self, joint: &Joint) -> &Link { &self.links[&joint.child.link] // Safe because we checked that the joint's child link exists in `new()` } + + /// Get a material by name, if it exists. + fn get_material(&self, name: &str) -> Option<&Material> { + self.materials.get(name) + } } fn log_robot( @@ -264,6 +272,7 @@ fn log_robot( tx: &Sender, store_id: &StoreId, entity_path_prefix: &Option, + timepoint: &TimePoint, ) -> anyhow::Result<()> { let urdf_dir = filepath.parent().map(|path| path.to_path_buf()); @@ -273,7 +282,14 @@ fn log_robot( .map(|prefix| prefix / EntityPath::from_single_string(urdf_tree.name.clone())) .unwrap_or_else(|| EntityPath::from_single_string(urdf_tree.name.clone())); - walk_tree(&urdf_tree, tx, store_id, &entity_path, &urdf_tree.root.name)?; + walk_tree( + &urdf_tree, + tx, + store_id, + &entity_path, + &urdf_tree.root.name, + timepoint, + )?; Ok(()) } @@ -284,6 +300,7 @@ fn walk_tree( store_id: &StoreId, parent_path: &EntityPath, link_name: &str, + timepoint: &TimePoint, ) -> anyhow::Result<()> { let link = urdf_tree .links @@ -292,7 +309,7 @@ fn walk_tree( debug_assert_eq!(link_name, link.name); let link_path = parent_path / EntityPathPart::new(link_name); - log_link(urdf_tree, tx, store_id, link, &link_path)?; + log_link(urdf_tree, tx, store_id, link, &link_path, timepoint)?; let Some(joints) = urdf_tree.children.get(link_name) else { // if there's no more joints connecting this link to anything else we've reached the end of this branch. @@ -301,10 +318,17 @@ fn walk_tree( for joint in joints { let joint_path = &link_path / EntityPathPart::new(&joint.name); - log_joint(tx, store_id, &joint_path, joint)?; + log_joint(tx, store_id, &joint_path, joint, timepoint)?; // Recurse - walk_tree(urdf_tree, tx, store_id, &joint_path, &joint.child.link)?; + walk_tree( + urdf_tree, + tx, + store_id, + &joint_path, + &joint.child.link, + timepoint, + )?; } Ok(()) @@ -315,6 +339,7 @@ fn log_joint( store_id: &StoreId, joint_path: &EntityPath, joint: &Joint, + timepoint: &TimePoint, ) -> anyhow::Result<()> { let Joint { name: _, @@ -330,19 +355,40 @@ fn log_joint( safety_controller, } = joint; - send_transform(tx, store_id, joint_path.clone(), origin)?; + send_transform(tx, store_id, joint_path.clone(), origin, timepoint)?; - log_debug_format(tx, store_id, joint_path.clone(), "joint_type", joint_type)?; - log_debug_format(tx, store_id, joint_path.clone(), "axis", axis)?; - log_debug_format(tx, store_id, joint_path.clone(), "limit", limit)?; + log_debug_format( + tx, + store_id, + joint_path.clone(), + "joint_type", + joint_type, + timepoint, + )?; + log_debug_format(tx, store_id, joint_path.clone(), "axis", axis, timepoint)?; + log_debug_format(tx, store_id, joint_path.clone(), "limit", limit, timepoint)?; if let Some(calibration) = calibration { - log_debug_format(tx, store_id, joint_path.clone(), "calibration", calibration)?; + log_debug_format( + tx, + store_id, + joint_path.clone(), + "calibration", + calibration, + timepoint, + )?; } if let Some(dynamics) = dynamics { - log_debug_format(tx, store_id, joint_path.clone(), "dynamics", dynamics)?; + log_debug_format( + tx, + store_id, + joint_path.clone(), + "dynamics", + dynamics, + timepoint, + )?; } if let Some(mimic) = mimic { - log_debug_format(tx, store_id, joint_path.clone(), "mimic", mimic)?; + log_debug_format(tx, store_id, joint_path.clone(), "mimic", mimic, timepoint)?; } if let Some(safety_controller) = safety_controller { log_debug_format( @@ -351,6 +397,7 @@ fn log_joint( joint_path.clone(), "safety_controller", &safety_controller, + timepoint, )?; } @@ -371,6 +418,7 @@ fn send_transform( store_id: &StoreId, entity_path: EntityPath, origin: &urdf_rs::Pose, + timepoint: &TimePoint, ) -> anyhow::Result<()> { let urdf_rs::Pose { xyz, rpy } = origin; let is_identity = xyz.0 == [0.0, 0.0, 0.0] && rpy.0 == [0.0, 0.0, 0.0]; @@ -378,7 +426,13 @@ fn send_transform( if is_identity { Ok(()) // avoid noise } else { - send_archetype(tx, store_id, entity_path, &transform_from_pose(origin)) + send_archetype( + tx, + store_id, + entity_path, + timepoint, + &transform_from_pose(origin), + ) } } @@ -391,13 +445,14 @@ fn log_debug_format( entity_path: EntityPath, name: &str, value: &dyn std::fmt::Debug, + timepoint: &TimePoint, ) -> anyhow::Result<()> { send_chunk_builder( tx, store_id, ChunkBuilder::new(ChunkId::new(), entity_path).with_serialized_batches( RowId::new(), - TimePoint::default(), + timepoint.clone(), vec![SerializedComponentBatch { descriptor: ComponentDescriptor::partial(name), array: Arc::new(arrow::array::StringArray::from(vec![format!("{value:#?}")])), @@ -412,6 +467,7 @@ fn log_link( store_id: &StoreId, link: &urdf_rs::Link, link_entity: &EntityPath, + timepoint: &TimePoint, ) -> anyhow::Result<()> { let urdf_rs::Link { name: _, @@ -420,7 +476,14 @@ fn log_link( collision, } = link; - log_debug_format(tx, store_id, link_entity.clone(), "inertial", &inertial)?; + log_debug_format( + tx, + store_id, + link_entity.clone(), + "inertial", + &inertial, + timepoint, + )?; for (i, visual) in visual.iter().enumerate() { let urdf_rs::Visual { @@ -432,21 +495,19 @@ fn log_link( let name = name.clone().unwrap_or_else(|| format!("visual_{i}")); let vis_entity = link_entity / EntityPathPart::new(name); - // We need to look up the material by name, because the `Visuals::Material` - // only has a name, no color or texture. - let material = material - .as_ref() - .and_then(|m| urdf_tree.materials.get(&m.name).cloned()); + // Prefer inline defined material properties if present, otherwise fall back to global material. + let material = material.as_ref().and_then(|mat| { + if mat.color.is_some() || mat.texture.is_some() { + Some(mat) + } else { + urdf_tree.get_material(&mat.name) + } + }); - send_transform(tx, store_id, vis_entity.clone(), origin)?; + send_transform(tx, store_id, vis_entity.clone(), origin, timepoint)?; log_geometry( - urdf_tree, - tx, - store_id, - vis_entity, - geometry, - material.as_ref(), + urdf_tree, tx, store_id, vis_entity, geometry, material, timepoint, )?; } @@ -459,7 +520,7 @@ fn log_link( let name = name.clone().unwrap_or_else(|| format!("collision_{i}")); let collision_entity = link_entity / EntityPathPart::new(name); - send_transform(tx, store_id, collision_entity.clone(), origin)?; + send_transform(tx, store_id, collision_entity.clone(), origin, timepoint)?; log_geometry( urdf_tree, @@ -468,6 +529,7 @@ fn log_link( collision_entity.clone(), geometry, None, + timepoint, )?; if false { @@ -477,7 +539,7 @@ fn log_link( store_id, ChunkBuilder::new(ChunkId::new(), collision_entity).with_component_batch( RowId::new(), - TimePoint::default(), + timepoint.clone(), ( ComponentDescriptor { archetype: None, @@ -534,6 +596,7 @@ fn log_geometry( entity_path: EntityPath, geometry: &Geometry, material: Option<&urdf_rs::Material>, + timepoint: &TimePoint, ) -> anyhow::Result<()> { match geometry { Geometry::Mesh { filename, scale } => { @@ -573,11 +636,12 @@ fn log_geometry( tx, store_id, entity_path.clone(), + timepoint, &Transform3D::update_fields().with_scale([x as f32, y as f32, z as f32]), )?; } - send_archetype(tx, store_id, entity_path, &asset3d)?; + send_archetype(tx, store_id, entity_path, timepoint, &asset3d)?; } Geometry::Box { size: Vec3([x, y, z]), @@ -586,6 +650,7 @@ fn log_geometry( tx, store_id, entity_path, + timepoint, &re_types::archetypes::Boxes3D::from_sizes([Vec3D::new(*x as _, *y as _, *z as _)]), )?; } @@ -595,6 +660,7 @@ fn log_geometry( tx, store_id, entity_path, + timepoint, &re_types::archetypes::Cylinders3D::from_lengths_and_radii( [*length as f32], [*radius as f32], @@ -607,6 +673,7 @@ fn log_geometry( tx, store_id, entity_path, + timepoint, &re_types::archetypes::Capsules3D::from_lengths_and_radii( [*length as f32], [*radius as f32], @@ -618,6 +685,7 @@ fn log_geometry( tx, store_id, entity_path, + timepoint, &re_types::archetypes::Ellipsoids3D::from_radii([*radius as f32]), )?; } diff --git a/crates/store/re_redap_client/src/connection_registry.rs b/crates/store/re_redap_client/src/connection_registry.rs index 9959750fbdd0..1aae8afded12 100644 --- a/crates/store/re_redap_client/src/connection_registry.rs +++ b/crates/store/re_redap_client/src/connection_registry.rs @@ -1,7 +1,9 @@ use std::collections::{HashMap, hash_map::Entry}; +use std::error::Error as _; use std::sync::Arc; use itertools::Itertools as _; +use re_auth::credentials::CredentialsProviderError; use tokio::sync::RwLock; use tonic::Code; @@ -79,6 +81,12 @@ impl ConnectionRegistry { /// Possible errors when creating a connection. #[derive(Debug, thiserror::Error)] pub enum ClientCredentialsError { + #[error("error when refreshing credentials\nDetails:{0}")] + RefreshError(TonicStatusError), + + #[error("the credentials are expired")] + SessionExpired, + #[error("the server requires an authentication token but none was provided\nDetails:{0}")] UnauthenticatedMissingToken(TonicStatusError), @@ -332,7 +340,24 @@ impl ConnectionRegistryHandle { } } - Err(err) => Err(ApiError::tonic(err, "verifying credentials")), + Err(err) => { + if let Some(cred_error) = err.source().and_then(|s| { + s.downcast_ref::() + }) { + match cred_error { + CredentialsProviderError::SessionExpired => Err(ApiError::credentials( + ClientCredentialsError::SessionExpired, + "session expired", + )), + CredentialsProviderError::Custom(_) => Err(ApiError::credentials( + ClientCredentialsError::RefreshError(err.into()), + "refreshing credentials", + )), + } + } else { + Err(ApiError::tonic(err, "verifying credentials")) + } + } Ok(_) => Ok(raw_client), } diff --git a/crates/store/re_redap_tests/Cargo.toml b/crates/store/re_redap_tests/Cargo.toml index 3bad4db13713..bc8cfd5c8f8f 100644 --- a/crates/store/re_redap_tests/Cargo.toml +++ b/crates/store/re_redap_tests/Cargo.toml @@ -39,7 +39,7 @@ anyhow.workspace = true arrow.workspace = true datafusion.workspace = true futures.workspace = true -insta.workspace = true +insta = { workspace = true, features = ["filters"] } itertools.workspace = true prost-types.workspace = true tempfile.workspace = true diff --git a/crates/store/re_redap_tests/src/tests/common.rs b/crates/store/re_redap_tests/src/tests/common.rs index 559f6f81e068..077865e50e83 100644 --- a/crates/store/re_redap_tests/src/tests/common.rs +++ b/crates/store/re_redap_tests/src/tests/common.rs @@ -9,7 +9,7 @@ use url::Url; use re_protos::{ cloud::v1alpha1::{ CreateDatasetEntryRequest, DataSource, DataSourceKind, QueryTasksOnCompletionRequest, - RegisterWithDatasetRequest, RegisterWithDatasetResponse, + RegisterWithDatasetRequest, RegisterWithDatasetResponse, ext::DatasetEntry, rerun_cloud_service_server::RerunCloudService, }, common::v1alpha1::{IfDuplicateBehavior, TaskId}, @@ -26,7 +26,7 @@ use crate::{ /// Extension trait for the most common test setup tasks. #[async_trait] pub trait RerunCloudServiceExt: RerunCloudService { - async fn create_dataset_entry_with_name(&self, dataset_name: &str); + async fn create_dataset_entry_with_name(&self, dataset_name: &str) -> DatasetEntry; async fn register_with_dataset_name( &self, @@ -40,13 +40,18 @@ pub trait RerunCloudServiceExt: RerunCloudService { #[async_trait] impl RerunCloudServiceExt for T { - async fn create_dataset_entry_with_name(&self, dataset_name: &str) { + async fn create_dataset_entry_with_name(&self, dataset_name: &str) -> DatasetEntry { self.create_dataset_entry(tonic::Request::new(CreateDatasetEntryRequest { name: Some(dataset_name.to_owned()), id: None, })) .await - .expect("create_dataset_entry should succeed"); + .expect("create_dataset_entry should succeed") + .into_inner() + .dataset + .expect("some dataset field expected") + .try_into() + .expect("conversion to ext::DatasetEntry should succeed") } async fn register_with_dataset_name( diff --git a/crates/store/re_redap_tests/src/tests/entries_table.rs b/crates/store/re_redap_tests/src/tests/entries_table.rs index 8ebeab8d38bf..ac23c4da602c 100644 --- a/crates/store/re_redap_tests/src/tests/entries_table.rs +++ b/crates/store/re_redap_tests/src/tests/entries_table.rs @@ -1,40 +1,21 @@ use futures::TryStreamExt as _; use itertools::Itertools as _; +use re_log_types::EntryId; use re_protos::cloud::v1alpha1::{ - FindEntriesRequest, GetTableSchemaRequest, ScanTableRequest, ext::EntryDetails, - rerun_cloud_service_server::RerunCloudService, + DeleteEntryRequest, FindEntriesRequest, GetTableSchemaRequest, ScanTableRequest, + ext::EntryDetails, rerun_cloud_service_server::RerunCloudService, }; +use crate::tests::common::RerunCloudServiceExt as _; use crate::{RecordBatchExt as _, SchemaExt as _}; /// We want to make sure that the "__entries" table is present and has the expected schema and data. pub async fn list_entries_table(service: impl RerunCloudService) { - let find_entries_table = FindEntriesRequest { - filter: Some(re_protos::cloud::v1alpha1::EntryFilter { - name: Some("__entries".to_owned()), - ..Default::default() - }), - }; - - let entries_resp = service - .find_entries(tonic::Request::new(find_entries_table)) - .await - .expect("Failed to find entries") - .into_inner() - .entries; - - assert!(entries_resp.len() == 1); - - let entries: EntryDetails = entries_resp[0] - .clone() - .try_into() - .expect("Failed to convert to EntryDetails"); - - assert!(entries.name == "__entries"); + let entries_table_id = entries_table_id(&service).await; let schema_request = GetTableSchemaRequest { - table_id: Some(entries.id.into()), + table_id: Some(entries_table_id.into()), }; let schema: arrow::datatypes::Schema = (&service @@ -47,10 +28,10 @@ pub async fn list_entries_table(service: impl RerunCloudService) { .try_into() .expect("Failed to convert schema"); - insta::assert_snapshot!(format!("entries_table_schema"), schema.format_snapshot()); + insta::assert_snapshot!("entries_table_schema", schema.format_snapshot()); let scan_request = ScanTableRequest { - table_id: Some(entries.id.into()), + table_id: Some(entries_table_id.into()), }; let table_resp: Vec<_> = service @@ -79,5 +60,90 @@ pub async fn list_entries_table(service: impl RerunCloudService) { let batch = batch.project_columns(&["name", "entry_kind"]); - insta::assert_snapshot!(format!("entries_table_data"), batch.format_snapshot(false)); + insta::assert_snapshot!("entries_table_data", batch.format_snapshot(false)); +} + +pub async fn entries_table_with_empty_dataset(service: impl RerunCloudService) { + let dataset_name = "empty_dataset"; + let dataset_entry = service.create_dataset_entry_with_name(dataset_name).await; + + snapshot_entries_table(&service, "entries_table_with_empty_dataset").await; + + service + .delete_entry(tonic::Request::new(DeleteEntryRequest { + id: Some(dataset_entry.details.id.into()), + })) + .await + .expect("Failed to delete entry"); + + snapshot_entries_table(&service, "entries_table_with_empty_dataset_deleted").await; +} + +async fn entries_table_id(service: &impl RerunCloudService) -> EntryId { + let find_entries_table = FindEntriesRequest { + filter: Some(re_protos::cloud::v1alpha1::EntryFilter { + name: Some("__entries".to_owned()), + ..Default::default() + }), + }; + + let entries_resp = service + .find_entries(tonic::Request::new(find_entries_table)) + .await + .expect("Failed to find entries") + .into_inner() + .entries; + + assert_eq!(entries_resp.len(), 1); + + let entries: EntryDetails = entries_resp[0] + .clone() + .try_into() + .expect("Failed to convert to EntryDetails"); + + assert_eq!(entries.name, "__entries"); + + entries.id +} + +async fn snapshot_entries_table(service: &impl RerunCloudService, snapshot_name: &str) { + let entries_table_id = entries_table_id(service).await; + + let entries_resp: Vec<_> = service + .scan_table(tonic::Request::new(ScanTableRequest { + table_id: Some(entries_table_id.into()), + })) + .await + .expect("Failed to scan table") + .into_inner() + .try_collect() + .await + .expect("Failed to collect scan results"); + + let batches = entries_resp + .into_iter() + .map(|resp| { + resp.dataframe_part + .expect("Expected dataframe part") + .try_into() + .expect("Failed to decode dataframe") + }) + .collect_vec(); + + let batch = + re_arrow_util::concat_polymorphic_batches(&batches).expect("Failed to concat batches"); + + let batch = batch + .project_columns(&["name", "entry_kind"]) + .auto_sort_rows() + .unwrap(); + + let mut settings = insta::Settings::clone_current(); + settings.add_filter( + r"__bp_[0-9a-fA-F]{32}", + "__bp_********************************", + ); + settings.bind(|| { + insta::assert_snapshot!(snapshot_name, batch.format_snapshot(false)); + }); } diff --git a/crates/store/re_redap_tests/src/tests/mod.rs b/crates/store/re_redap_tests/src/tests/mod.rs index d51c76a3f3f3..196b731ebe75 100644 --- a/crates/store/re_redap_tests/src/tests/mod.rs +++ b/crates/store/re_redap_tests/src/tests/mod.rs @@ -77,6 +77,7 @@ define_redap_tests! { create_table::create_table_entry, dataset_schema::empty_dataset_schema, dataset_schema::simple_dataset_schema, + entries_table::entries_table_with_empty_dataset, entries_table::list_entries_table, fetch_chunks::multi_dataset_fetch_chunk_completeness, fetch_chunks::simple_dataset_fetch_chunk_snapshot, diff --git a/crates/store/re_redap_tests/src/tests/snapshots/re_redap_tests__tests__entries_table__entries_table_with_empty_dataset.snap b/crates/store/re_redap_tests/src/tests/snapshots/re_redap_tests__tests__entries_table__entries_table_with_empty_dataset.snap new file mode 100644 index 000000000000..5334b1d6252e --- /dev/null +++ b/crates/store/re_redap_tests/src/tests/snapshots/re_redap_tests__tests__entries_table__entries_table_with_empty_dataset.snap @@ -0,0 +1,13 @@ +--- +source: crates/store/re_redap_tests/src/tests/entries_table.rs +expression: batch.format_snapshot(false) +--- +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ name ┆ entry_kind β”‚ +β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•ͺ════════════║ +β”‚ __bp_******************************** ┆ 5 β”‚ +β”œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ”Όβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ”€ +β”‚ __entries ┆ 3 β”‚ +β”œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ”Όβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ•Œβ”€ +β”‚ empty_dataset ┆ 1 β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ diff --git a/crates/store/re_redap_tests/src/tests/snapshots/re_redap_tests__tests__entries_table__entries_table_with_empty_dataset_deleted.snap b/crates/store/re_redap_tests/src/tests/snapshots/re_redap_tests__tests__entries_table__entries_table_with_empty_dataset_deleted.snap new file mode 100644 index 000000000000..0d3d5b8127ef --- /dev/null +++ b/crates/store/re_redap_tests/src/tests/snapshots/re_redap_tests__tests__entries_table__entries_table_with_empty_dataset_deleted.snap @@ -0,0 +1,9 @@ +--- +source: crates/store/re_redap_tests/src/tests/entries_table.rs +expression: batch.format_snapshot(false) +--- +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ name ┆ entry_kind β”‚ +β•žβ•β•β•β•β•β•β•β•β•β•β•β•ͺ════════════║ +β”‚ __entries ┆ 3 β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ diff --git a/crates/store/re_server/src/rerun_cloud.rs b/crates/store/re_server/src/rerun_cloud.rs index f4812e333b53..3e538ea9f0a7 100644 --- a/crates/store/re_server/src/rerun_cloud.rs +++ b/crates/store/re_server/src/rerun_cloud.rs @@ -562,7 +562,7 @@ impl RerunCloudService for RerunCloudHandler { { let entry_id = request.into_inner().try_into()?; - self.store.write().await.delete_dataset(entry_id)?; + self.store.write().await.delete_entry(entry_id)?; Ok(tonic::Response::new(DeleteEntryResponse {})) } diff --git a/crates/store/re_server/src/store/dataset.rs b/crates/store/re_server/src/store/dataset.rs index bdb584bf3c71..065c556c7190 100644 --- a/crates/store/re_server/src/store/dataset.rs +++ b/crates/store/re_server/src/store/dataset.rs @@ -101,6 +101,10 @@ impl Dataset { } } + pub fn dataset_details(&self) -> &DatasetDetails { + &self.details + } + pub fn set_dataset_details(&mut self, details: DatasetDetails) { self.details = details; self.updated_at = jiff::Timestamp::now(); diff --git a/crates/store/re_server/src/store/in_memory_store.rs b/crates/store/re_server/src/store/in_memory_store.rs index f209e6f5f35a..df3f93e4c17b 100644 --- a/crates/store/re_server/src/store/in_memory_store.rs +++ b/crates/store/re_server/src/store/in_memory_store.rs @@ -287,6 +287,59 @@ impl InMemoryStore { self.update_entries_table() } + pub fn create_dataset( + &mut self, + name: &str, + id: Option, + store_kind: StoreKind, + details: Option, + ) -> Result<&mut Dataset, Error> { + re_log::debug!(name, "create_dataset"); + let name = name.to_owned(); + if self.id_by_name.contains_key(&name) { + return Err(Error::DuplicateEntryNameError(name)); + } + + let entry_id = id.unwrap_or_else(EntryId::new); + if self.id_exists(&entry_id) { + return Err(Error::DuplicateEntryIdError(entry_id)); + } + + self.id_by_name.insert(name.clone(), entry_id); + + self.datasets.insert( + entry_id, + Dataset::new(entry_id, name, store_kind, details.unwrap_or_default()), + ); + + self.update_entries_table()?; + self.dataset_mut(entry_id) + } + + /// Delete the provided entry. + /// + /// For dataset, the corresponding blueprint dataset will be deleted as well. + pub fn delete_entry(&mut self, entry_id: EntryId) -> Result<(), Error> { + re_log::debug!(?entry_id, "delete_entry"); + + if let Some(table) = self.tables.remove(&entry_id) { + self.id_by_name.remove(table.name()); + self.update_entries_table()?; + Ok(()) + } else if let Some(dataset) = self.datasets.remove(&entry_id) { + self.id_by_name.remove(dataset.name()); + self.update_entries_table()?; + + if let Some(blueprint_entry_id) = dataset.dataset_details().blueprint_dataset { + self.delete_entry(blueprint_entry_id) + } else { + Ok(()) + } + } else { + Err(Error::EntryIdNotFound(entry_id)) + } + } + /// Update the table of entries. This method must be called after /// any changes to either the registered datasets or tables. We /// can remove this restriction if we change the store to be an @@ -320,41 +373,6 @@ impl InMemoryStore { Ok(()) } - pub fn create_dataset( - &mut self, - name: &str, - id: Option, - store_kind: StoreKind, - details: Option, - ) -> Result<&mut Dataset, Error> { - re_log::debug!(name, "create_dataset"); - let name = name.to_owned(); - if self.id_by_name.contains_key(&name) { - return Err(Error::DuplicateEntryNameError(name)); - } - - let entry_id = id.unwrap_or_else(EntryId::new); - if self.id_exists(&entry_id) { - return Err(Error::DuplicateEntryIdError(entry_id)); - } - - self.id_by_name.insert(name.clone(), entry_id); - - Ok(self.datasets.entry(entry_id).or_insert_with(|| { - Dataset::new(entry_id, name, store_kind, details.unwrap_or_default()) - })) - } - - pub fn delete_dataset(&mut self, entry_id: EntryId) -> Result<(), Error> { - re_log::debug!(?entry_id, "delete_dataset"); - if let Some(dataset) = self.datasets.remove(&entry_id) { - self.id_by_name.remove(dataset.name()); - Ok(()) - } else { - Err(Error::EntryIdNotFound(entry_id)) - } - } - pub fn dataset(&self, entry_id: EntryId) -> Result<&Dataset, Error> { self.datasets .get(&entry_id) diff --git a/crates/store/re_types/definitions/rerun/archetypes/coordinate_frame.fbs b/crates/store/re_types/definitions/rerun/archetypes/coordinate_frame.fbs index 3aaef845998e..4ef8880a1b40 100644 --- a/crates/store/re_types/definitions/rerun/archetypes/coordinate_frame.fbs +++ b/crates/store/re_types/definitions/rerun/archetypes/coordinate_frame.fbs @@ -12,7 +12,6 @@ namespace rerun.archetypes; /// /// \example archetypes/coordinate_frame_builtin_frames title="Change coordinate frame to different built-in frames" image="https://static.rerun.io/coordinate_frame_builtin_frame/71f941f35cf73c299c6ea7fbc4487a140db8e8f8/1200w.png" table CoordinateFrame ( - "attr.docs.unreleased", "attr.docs.category": "Spatial 3D", // TODO(RR-2699): time to introduce a doc category for transforms? "attr.docs.view_types": "Spatial3DView, Spatial2DView", "attr.rerun.state": "unstable", // TODO(RR-2777): Mark as stable when we're ready for it. diff --git a/crates/store/re_types/definitions/rerun/components/transform_frame_id.fbs b/crates/store/re_types/definitions/rerun/components/transform_frame_id.fbs index 5a427a9127a3..081d6c2fa100 100644 --- a/crates/store/re_types/definitions/rerun/components/transform_frame_id.fbs +++ b/crates/store/re_types/definitions/rerun/components/transform_frame_id.fbs @@ -12,7 +12,6 @@ namespace rerun.components; // TODO(RR-2486): Reference `CoordinateFrame` & `FrameTransform` once they exist. // TODO(RR-2698): Explain implicit transform frames in more detail. table TransformFrameId ( - "attr.docs.unreleased", "attr.rerun.state": "unstable", "attr.arrow.transparent", "attr.python.aliases": "str", diff --git a/crates/store/re_types/definitions/rerun/datatypes/time_range.fbs b/crates/store/re_types/definitions/rerun/datatypes/time_range.fbs index 7ebaab959648..4699b181c1be 100644 --- a/crates/store/re_types/definitions/rerun/datatypes/time_range.fbs +++ b/crates/store/re_types/definitions/rerun/datatypes/time_range.fbs @@ -3,8 +3,7 @@ namespace rerun.datatypes; /// Two [datatypes.TimeInt] describing a range of time. struct AbsoluteTimeRange ( "attr.rust.derive": "Copy, PartialEq, Eq, PartialOrd, Ord", - "attr.rust.override_crate": "re_types_core", - "attr.docs.unreleased" + "attr.rust.override_crate": "re_types_core" ) { /// Start of the range. min: TimeInt (order: 100); diff --git a/crates/store/re_types/src/reflection/mod.rs b/crates/store/re_types/src/reflection/mod.rs index 8f583856b1ea..a58b750a733b 100644 --- a/crates/store/re_types/src/reflection/mod.rs +++ b/crates/store/re_types/src/reflection/mod.rs @@ -3183,14 +3183,14 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { name: "child_frame", display_name: "Child frame", component_type: "rerun.components.TransformFrameId".into(), - docstring_md: "The child frame this transform transforms from.\n\nThe entity at which the transform relationship of any given child frame is specified mustn't change over time.\nE.g. if you specified the child frame `\"robot_arm\"` on an entity named `\"my_transforms\"`, you may not log transforms\nwith the child frame `\"robot_arm\"` on any other entity than `\"my_transforms\"`.\nAn exception to this rule is static time - you may first mention a child frame on one entity statically and later on\nanother one temporally.\n\n⚠ This currently also affects the child frame of [`archetypes.Pinhole`](https://rerun.io/docs/reference/types/archetypes/pinhole).\n⚠ This currently is also used as the frame id of [`archetypes.InstancePoses3D`](https://rerun.io/docs/reference/types/archetypes/instance_poses3d).\n\nIf not specified, this is set to the implicit transform frame of the current entity path.\nThis means that if a [`archetypes.Transform3D`](https://rerun.io/docs/reference/types/archetypes/transform3d) is set on an entity called `/my/entity/path` then this will default to `tf#/my/entity/path`.\n\nTo set the frame an entity is part of see [`archetypes.CoordinateFrame`](https://rerun.io/docs/reference/types/archetypes/coordinate_frame?speculative-link).\n\n⚠\u{fe0f} **This type is _unstable_ and may change significantly in a way that the data won't be backwards compatible.**", + docstring_md: "The child frame this transform transforms from.\n\nThe entity at which the transform relationship of any given child frame is specified mustn't change over time.\nE.g. if you specified the child frame `\"robot_arm\"` on an entity named `\"my_transforms\"`, you may not log transforms\nwith the child frame `\"robot_arm\"` on any other entity than `\"my_transforms\"`.\nAn exception to this rule is static time - you may first mention a child frame on one entity statically and later on\nanother one temporally.\n\n⚠ This currently also affects the child frame of [`archetypes.Pinhole`](https://rerun.io/docs/reference/types/archetypes/pinhole).\n⚠ This currently is also used as the frame id of [`archetypes.InstancePoses3D`](https://rerun.io/docs/reference/types/archetypes/instance_poses3d).\n\nIf not specified, this is set to the implicit transform frame of the current entity path.\nThis means that if a [`archetypes.Transform3D`](https://rerun.io/docs/reference/types/archetypes/transform3d) is set on an entity called `/my/entity/path` then this will default to `tf#/my/entity/path`.\n\nTo set the frame an entity is part of see [`archetypes.CoordinateFrame`](https://rerun.io/docs/reference/types/archetypes/coordinate_frame).\n\n⚠\u{fe0f} **This type is _unstable_ and may change significantly in a way that the data won't be backwards compatible.**", is_required: false, }, ArchetypeFieldReflection { name: "parent_frame", display_name: "Parent frame", component_type: "rerun.components.TransformFrameId".into(), - docstring_md: "The parent frame this transform transforms into.\n\n⚠ This currently also affects the parent frame of [`archetypes.Pinhole`](https://rerun.io/docs/reference/types/archetypes/pinhole).\n\nIf not specified, this is set to the implicit transform frame of the current entity path's parent.\nThis means that if a [`archetypes.Transform3D`](https://rerun.io/docs/reference/types/archetypes/transform3d) is set on an entity called `/my/entity/path` then this will default to `tf#/my/entity`.\n\nTo set the frame an entity is part of see [`archetypes.CoordinateFrame`](https://rerun.io/docs/reference/types/archetypes/coordinate_frame?speculative-link).\n\n⚠\u{fe0f} **This type is _unstable_ and may change significantly in a way that the data won't be backwards compatible.**", + docstring_md: "The parent frame this transform transforms into.\n\n⚠ This currently also affects the parent frame of [`archetypes.Pinhole`](https://rerun.io/docs/reference/types/archetypes/pinhole).\n\nIf not specified, this is set to the implicit transform frame of the current entity path's parent.\nThis means that if a [`archetypes.Transform3D`](https://rerun.io/docs/reference/types/archetypes/transform3d) is set on an entity called `/my/entity/path` then this will default to `tf#/my/entity`.\n\nTo set the frame an entity is part of see [`archetypes.CoordinateFrame`](https://rerun.io/docs/reference/types/archetypes/coordinate_frame).\n\n⚠\u{fe0f} **This type is _unstable_ and may change significantly in a way that the data won't be backwards compatible.**", is_required: false, }, ArchetypeFieldReflection { diff --git a/crates/utils/re_arrow_combinators/README.md b/crates/utils/re_arrow_combinators/README.md index 61777dabb577..62036dde379b 100644 --- a/crates/utils/re_arrow_combinators/README.md +++ b/crates/utils/re_arrow_combinators/README.md @@ -3,7 +3,7 @@ Part of the [`rerun`](https://github.com/rerun-io/rerun) family of crates. [![Latest version](https://img.shields.io/crates/v/re_arrow_combinators.svg)](https://crates.io/crates/re_arrow_combinators) -[![Documentation](https://docs.rs/re_arrow_combinators/badge.svg)](https://docs.rs/re_arrow_combinators?speculative-link) +[![Documentation](https://docs.rs/re_arrow_combinators/badge.svg)](https://docs.rs/re_arrow_combinators) ![MIT](https://img.shields.io/badge/license-MIT-blue.svg) ![Apache](https://img.shields.io/badge/license-Apache-blue.svg) diff --git a/crates/viewer/re_component_fallbacks/README.md b/crates/viewer/re_component_fallbacks/README.md index 8da3ef5a3231..9ba7c1dab29a 100644 --- a/crates/viewer/re_component_fallbacks/README.md +++ b/crates/viewer/re_component_fallbacks/README.md @@ -2,8 +2,8 @@ Part of the [`rerun`](https://github.com/rerun-io/rerun) family of crates. -[![Latest version](https://img.shields.io/crates/v/re_component_fallbacks.svg?speculative-link)](https://crates.io/crates/re_component_fallbacks?speculative-link) -[![Documentation](https://docs.rs/re_component_fallbacks/badge.svg?speculative-link)](https://docs.rs/re_component_fallbacks?speculative-link) +[![Latest version](https://img.shields.io/crates/v/re_component_fallbacks.svg)](https://crates.io/crates/re_component_fallbacks) +[![Documentation](https://docs.rs/re_component_fallbacks/badge.svg)](https://docs.rs/re_component_fallbacks) ![MIT](https://img.shields.io/badge/license-MIT-blue.svg) ![Apache](https://img.shields.io/badge/license-Apache-blue.svg) diff --git a/crates/viewer/re_component_fallbacks/src/component_fallbacks.rs b/crates/viewer/re_component_fallbacks/src/component_fallbacks.rs index 5ed4b7a9c235..f017b8c9caf6 100644 --- a/crates/viewer/re_component_fallbacks/src/component_fallbacks.rs +++ b/crates/viewer/re_component_fallbacks/src/component_fallbacks.rs @@ -374,6 +374,16 @@ pub fn archetype_field_fallbacks(registry: &mut FallbackProviderRegistry) { }, ); + // Pinhole + registry.register_component_fallback_provider( + archetypes::Pinhole::descriptor_color().component, + |ctx| components::Color::from(ctx.viewer_ctx().tokens().frustum_color), + ); + registry.register_component_fallback_provider( + archetypes::Pinhole::descriptor_line_width().component, + |_| components::Radius::new_ui_points(1.), + ); + // SeriesLines registry.register_component_fallback_provider( archetypes::SeriesLines::descriptor_widths().component, diff --git a/crates/viewer/re_time_panel/benches/bench_density_graph.rs b/crates/viewer/re_time_panel/benches/bench_density_graph.rs index ef6c1ddd78f0..501f187c13d4 100644 --- a/crates/viewer/re_time_panel/benches/bench_density_graph.rs +++ b/crates/viewer/re_time_panel/benches/bench_density_graph.rs @@ -215,30 +215,6 @@ fn bench_many_chunks(c: &mut Criterion) { } } -/// Benchmark that specifically tests the `uniform_sample_events` path. -/// -/// This uses large chunks that exceed the individual event rendering threshold, -/// forcing the sampling path to be taken. -fn bench_sampling(c: &mut Criterion) { - let mut group = c.benchmark_group("sampling"); - - let sizes = [5000, 10000, 20000, 50000, 100000]; - for size in sizes { - for max_sampled_events_per_chunk in [0, 4000, 8000] { - let id = format!("{size}/sample_{max_sampled_events_per_chunk}"); - - let config = DensityGraphBuilderConfig { - max_sampled_events_per_chunk, - ..Default::default() - }; - - group.bench_with_input(id, &single_chunk(size, true), |b, &entry| { - run(b, config, entry); - }); - } - } -} - fn main() { // More noisy results, but benchmark ends a lot sooner. let mut criterion = Criterion::default() @@ -250,7 +226,6 @@ fn main() { bench_single_chunks(&mut criterion); bench_many_chunks(&mut criterion); - bench_sampling(&mut criterion); criterion.final_summary(); } diff --git a/crates/viewer/re_time_panel/src/data_density_graph.rs b/crates/viewer/re_time_panel/src/data_density_graph.rs index ee9474910432..63e028bdbe83 100644 --- a/crates/viewer/re_time_panel/src/data_density_graph.rs +++ b/crates/viewer/re_time_panel/src/data_density_graph.rs @@ -563,27 +563,10 @@ pub fn build_density_graph<'a>( }; if should_render_individual_events { - // Render all individual events for (time, num_events) in chunk.num_events_cumulative_per_unique_time(timeline) { - data.add_chunk_point(time, num_events as f32); - } - } else if config.max_sampled_events_per_chunk > 0 { - let events = chunk.num_events_cumulative_per_unique_time(timeline); - - if events.len() > config.max_sampled_events_per_chunk { - // If there's more rows than the configured max, we sample events to get a fast, good enough density estimate. - data.add_uniform_sample_from_chunk( - &events, - config.max_sampled_events_per_chunk, - ); - } else { - // No need to sample, we can use all events. - for (time, num_events) in events { - data.add_chunk_point(time, num_events as f32); - } + data.add_chunk_point(time, num_events as usize); } } else { - // Fall back to uniform distribution across the entire time range data.add_chunk_range(time_range, num_events_in_chunk); } } @@ -602,10 +585,6 @@ pub struct DensityGraphBuilderConfig { /// If an unsorted chunk has fewer events than this we show its individual events. pub max_events_in_unsorted_chunk: u64, - - /// When a chunk is too large to render all events, uniformly sample this many events - /// to create a good enough density estimate instead. - pub max_sampled_events_per_chunk: usize, } impl DensityGraphBuilderConfig { @@ -614,7 +593,6 @@ impl DensityGraphBuilderConfig { max_total_chunk_events: 0, max_events_in_unsorted_chunk: 0, max_events_in_sorted_chunk: 0, - max_sampled_events_per_chunk: 0, }; /// All sorted chunks will be rendered as individual events, @@ -623,7 +601,6 @@ impl DensityGraphBuilderConfig { max_total_chunk_events: u64::MAX, max_events_in_unsorted_chunk: 0, max_events_in_sorted_chunk: u64::MAX, - max_sampled_events_per_chunk: 0, }; /// All chunks will be rendered as individual events. @@ -631,7 +608,6 @@ impl DensityGraphBuilderConfig { max_total_chunk_events: u64::MAX, max_events_in_unsorted_chunk: u64::MAX, max_events_in_sorted_chunk: u64::MAX, - max_sampled_events_per_chunk: 0, }; } @@ -654,10 +630,6 @@ impl Default for DensityGraphBuilderConfig { // Processing unsorted events is about 20% slower than sorted events. max_events_in_unsorted_chunk: 8_000, - - // When chunks are too large to render all events, sample this many events uniformly - // to create a good enough density estimate. - max_sampled_events_per_chunk: 8_000, } } } @@ -720,32 +692,12 @@ impl<'a> DensityGraphBuilder<'a> { } } - /// Uniformly sample events using the given sample size. - /// - /// Each sampled event's count is reweighted to preserve the total density. - fn add_uniform_sample_from_chunk(&mut self, events: &[(TimeInt, u64)], sample_size: usize) { - re_tracing::profile_function!(); - - let step = events.len() as f32 / sample_size as f32; - - for i in 0..sample_size { - let idx = (i as f32 * step) as usize; - // This means we might miss the last event if rounding down, but that's acceptable. - if let Some(&(time, count)) = events.get(idx) { - // Reweight the count to preserve total density - let weighted_count = count as f32 * step; - - self.add_chunk_point(time, weighted_count); - } - } - } - - fn add_chunk_point(&mut self, time: TimeInt, weight: f32) { + fn add_chunk_point(&mut self, time: TimeInt, num_events: usize) { let Some(x) = self.time_ranges_ui.x_from_time_f32(time.into()) else { return; }; - self.density_graph.add_point(x, weight); + self.density_graph.add_point(x, num_events as _); if let Some(pointer_pos) = self.pointer_pos && self.row_rect.y_range().contains(pointer_pos.y) diff --git a/crates/viewer/re_time_panel/src/time_panel.rs b/crates/viewer/re_time_panel/src/time_panel.rs index d483553cc685..a6f7cbd318d4 100644 --- a/crates/viewer/re_time_panel/src/time_panel.rs +++ b/crates/viewer/re_time_panel/src/time_panel.rs @@ -1893,65 +1893,44 @@ fn pan_and_zoom_interaction( } /// Context menu that shows up when interacting with the streams rect. -fn copy_timeline_properties_context_menu( +fn timeline_properties_context_menu( ui: &mut egui::Ui, ctx: &ViewerContext<'_>, time_ctrl: &TimeControl, hovered_time: TimeReal, ) { let mut url = ViewerOpenUrl::from_context(ctx); - if let Some(selected_time_range) = time_ctrl.active_loop_selection() - && selected_time_range.contains(hovered_time) - { - let has_time_range = url.as_mut().is_ok_and(|url| url.fragment_mut().is_some()); - let copy_command = url.and_then(|url| url.copy_url_command()); - if ui - .add_enabled( - copy_command.is_ok() && has_time_range, - egui::Button::new("Copy link to trimmed range"), - ) - .on_disabled_hover_text(if copy_command.is_err() { - "Can't share links to the current recording" - } else { - "The current recording doesn't support time range links" - }) - .clicked() - && let Ok(copy_command) = copy_command - { - ctx.command_sender().send_system(copy_command); - } - } else { - let has_fragment = url.as_mut().is_ok_and(|url| { - if let Some(fragment) = url.fragment_mut() { - fragment.when = Some(( - *time_ctrl.timeline().name(), - re_log_types::TimeCell { - typ: time_ctrl.time_type(), - value: hovered_time.floor().into(), - }, - )); - true - } else { - false - } - }); - let copy_command = url.and_then(|url| url.copy_url_command()); - - if ui - .add_enabled( - copy_command.is_ok() && has_fragment, - egui::Button::new("Copy link to timestamp"), - ) - .on_disabled_hover_text(if let Err(err) = copy_command.as_ref() { - format!("Can't share links to the current recording: {err}") - } else { - "The current recording doesn't support time stamp links".to_owned() - }) - .clicked() - && let Ok(copy_command) = copy_command - { - ctx.command_sender().send_system(copy_command); + let has_fragment = url.as_mut().is_ok_and(|url| { + url.clear_time_range(); + if let Some(fragment) = url.fragment_mut() { + fragment.when = Some(( + *time_ctrl.timeline().name(), + re_log_types::TimeCell { + typ: time_ctrl.time_type(), + value: hovered_time.floor().into(), + }, + )); + true + } else { + false } + }); + let copy_command = url.and_then(|url| url.copy_url_command()); + + if ui + .add_enabled( + copy_command.is_ok() && has_fragment, + egui::Button::new("Copy link to timestamp"), + ) + .on_disabled_hover_text(if let Err(err) = copy_command.as_ref() { + format!("Can't share links to the current recording: {err}") + } else { + "The current recording doesn't support time stamp links".to_owned() + }) + .clicked() + && let Ok(copy_command) = copy_command + { + ctx.command_sender().send_system(copy_command); } if ui.button("Copy timestamp").clicked() { @@ -2040,7 +2019,7 @@ impl TimePanel { let popup_is_open = egui::Popup::context_menu(&response) .width(300.0) .show(|ui| { - copy_timeline_properties_context_menu(ui, ctx, time_ctrl, preview_time); + timeline_properties_context_menu(ui, ctx, time_ctrl, preview_time); }) .is_some(); if popup_is_open { diff --git a/crates/viewer/re_time_panel/src/time_selection_ui.rs b/crates/viewer/re_time_panel/src/time_selection_ui.rs index 49ce918d31f4..1ad792a3a9e3 100644 --- a/crates/viewer/re_time_panel/src/time_selection_ui.rs +++ b/crates/viewer/re_time_panel/src/time_selection_ui.rs @@ -1,11 +1,14 @@ -use egui::{Color32, CursorIcon, Id, NumExt as _, Rect}; +use egui::{Color32, CursorIcon, Id, NumExt as _, Rangef, Rect}; use re_log_types::{ AbsoluteTimeRange, AbsoluteTimeRangeF, Duration, TimeInt, TimeReal, TimeType, TimestampFormat, }; use re_types::blueprint::components::LoopMode; -use re_ui::{HasDesignTokens as _, UiExt as _, list_item}; -use re_viewer_context::{TimeControl, TimeControlCommand, ViewerContext}; +use re_ui::{HasDesignTokens as _, UICommand, UICommandSender as _, UiExt as _, list_item}; +use re_viewer_context::{ + SystemCommandSender as _, TimeControl, TimeControlCommand, ViewerContext, + open_url::ViewerOpenUrl, +}; use super::time_ranges_ui::TimeRangesUi; @@ -61,8 +64,6 @@ pub fn loop_selection_ui( timeline_rect: &Rect, time_commands: &mut Vec, ) { - let tokens = ui.tokens(); - if time_ctrl.loop_selection().is_none() && time_ctrl.loop_mode() == LoopMode::Selection { // Helpfully select a time slice if let Some(selection) = initial_time_selection(time_ranges_ui, time_ctrl.time_type()) { @@ -74,15 +75,13 @@ pub fn loop_selection_ui( time_commands.push(TimeControlCommand::SetLoopMode(LoopMode::Off)); } - let is_active = time_ctrl.loop_mode() == LoopMode::Selection; - let pointer_pos = ui.input(|i| i.pointer.hover_pos()); let timeline_response = ui .interact( *timeline_rect, ui.id().with("timeline"), - egui::Sense::drag(), + egui::Sense::click_and_drag(), ) .on_hover_cursor(crate::CREATE_TIME_LOOP_CURSOR_ICON); @@ -110,34 +109,6 @@ pub fn loop_selection_ui( ); } - let full_y_range = - egui::Rangef::new(rect.top(), time_area_painter.clip_rect().bottom()); - - { - // Paint selection: - let corner_radius = tokens.normal_corner_radius(); - let corner_radius = egui::CornerRadius { - nw: corner_radius, - ne: corner_radius, - sw: 0, - se: 0, - }; - - let full_color = tokens.loop_selection_color; - let inactive_color = tokens.loop_selection_color_inactive; - - if is_active { - let full_rect = Rect::from_x_y_ranges(rect.x_range(), full_y_range); - time_area_painter.rect_filled(full_rect, corner_radius, full_color); - } else { - time_area_painter.rect_filled(rect, corner_radius, full_color); - - let bottom_rect = - Rect::from_x_y_ranges(rect.x_range(), rect.bottom()..=full_y_range.max); - time_area_painter.rect_filled(bottom_rect, 0.0, inactive_color); - } - } - // Check for interaction: { let left_edge_rect = @@ -163,6 +134,11 @@ pub fn loop_selection_ui( ); }); + middle_response.context_menu(|ui| { + let is_on_selection = true; + selection_context_menu(ui, ctx, time_commands, is_on_selection); + }); + let left_response = ui .interact(left_edge_rect, left_edge_id, egui::Sense::drag()) .on_hover_and_drag_cursor(CursorIcon::ResizeWest) @@ -208,12 +184,16 @@ pub fn loop_selection_ui( on_drag_loop_selection(ui, &middle_response, time_ranges_ui, &mut selected_range); if middle_response.clicked() { - let new_loop_mode = if time_ctrl.loop_mode() == LoopMode::Selection { - LoopMode::Off + if ui.ctx().input(|i| i.modifiers.alt) { + time_commands.push(TimeControlCommand::RemoveLoopSelection); } else { - LoopMode::Selection - }; - time_commands.push(TimeControlCommand::SetLoopMode(new_loop_mode)); + let new_loop_mode = if time_ctrl.loop_mode() == LoopMode::Selection { + LoopMode::Off + } else { + LoopMode::Selection + }; + time_commands.push(TimeControlCommand::SetLoopMode(new_loop_mode)); + } } } } @@ -230,20 +210,25 @@ pub fn loop_selection_ui( } } + timeline_response.context_menu(|ui| { + let is_on_selection = false; + selection_context_menu(ui, ctx, time_commands, is_on_selection); + }); + // Start new selection? - if let Some(pointer_pos) = pointer_pos + if !timeline_response.context_menu_opened() && timeline_response.hovered() + && let Some(pointer_pos) = pointer_pos && let Some(time) = time_ranges_ui.snapped_time_from_x(ui, pointer_pos.x) { // Show preview: - let x = time_ranges_ui - .x_from_time_f32(time) - .unwrap_or(pointer_pos.x); - ui.painter().vline( - x, - timeline_rect.y_range(), - ui.visuals().widgets.noninteractive.fg_stroke, - ); + if let Some(x) = time_ranges_ui.x_from_time_f32(time) { + ui.painter().vline( + x, + timeline_rect.y_range(), + ui.visuals().widgets.noninteractive.fg_stroke, + ); + } if timeline_response.dragged() && ui.input(|i| i.pointer.is_decidedly_dragging()) { // Start new selection @@ -254,6 +239,130 @@ pub fn loop_selection_ui( ui.ctx().set_dragged_id(right_edge_id); } } + + paint_loop_selection( + time_ctrl, + time_ranges_ui, + ui, + timeline_rect.y_range(), + Rangef::new(timeline_rect.top(), time_area_painter.clip_rect().bottom()), + time_commands, + ); +} + +fn paint_loop_selection( + time_ctrl: &TimeControl, + time_ranges_ui: &TimeRangesUi, + ui: &egui::Ui, + top_y_range: Rangef, + full_y_range: Rangef, + time_commands: &[TimeControlCommand], +) -> Option<()> { + // Use latest range to avoid frame delay + let selected_range = time_commands + .iter() + .rev() + .find_map(|c| { + if let TimeControlCommand::SetLoopSelection(range) = c { + Some(AbsoluteTimeRangeF::from(*range)) + } else { + None + } + }) + .or(time_ctrl.loop_selection())?; + + let min_x = time_ranges_ui.x_from_time_f32(selected_range.min)?; + let max_x = time_ranges_ui.x_from_time_f32(selected_range.max)?; + + let mut x_range = Rangef::new(min_x, max_x); + + if x_range.span() < 2.0 { + // Make sure it is visible: + x_range = Rangef::new(x_range.center() - 1.0, x_range.center() + 1.0); + } + + let top_rect = Rect::from_x_y_ranges(x_range, top_y_range); + let bottom_rect = Rect::from_x_y_ranges(x_range, top_rect.bottom()..=full_y_range.max); + let full_rect = Rect::from_x_y_ranges(x_range, full_y_range); + + // Paint selection: + let tokens = ui.tokens(); + let corner_radius = tokens.normal_corner_radius(); + let corner_radius = egui::CornerRadius { + nw: corner_radius, + ne: corner_radius, + sw: 0, + se: 0, + }; + + let full_color = tokens.loop_selection_color; + let inactive_color = tokens.loop_selection_color_inactive; + + let is_active = time_ctrl.loop_mode() == LoopMode::Selection; + if is_active { + ui.painter() + .rect_filled(full_rect, corner_radius, full_color); + } else { + ui.painter() + .rect_filled(top_rect, corner_radius, full_color); + + ui.painter().rect_filled(bottom_rect, 0.0, inactive_color); + } + + None +} + +fn selection_context_menu( + ui: &mut egui::Ui, + ctx: &ViewerContext<'_>, + time_commands: &mut Vec, + is_on_selection: bool, +) { + let modifier = ui.ctx().format_modifiers(egui::Modifiers::ALT); + if ui + .add_enabled( + is_on_selection, + egui::Button::new("Remove time selection").shortcut_text(format!("{modifier}+Click")), + ) + .on_disabled_hover_text("Open the context menu on selected time to remove it") + .clicked() + { + time_commands.push(TimeControlCommand::RemoveLoopSelection); + } + + let mut button = egui::Button::new("Save current time selection…"); + if let Some(shortcut) = UICommand::SaveRecordingSelection.formatted_kb_shortcut(ui.ctx()) { + button = button.shortcut_text(shortcut); + } + if ui + .add_enabled(is_on_selection, button) + .on_disabled_hover_text("Open the context menu on selected time to save it") + .clicked() + { + ctx.command_sender() + .send_ui(UICommand::SaveRecordingSelection); + } + + let mut url = ViewerOpenUrl::from_context(ctx); + let has_time_range = url.as_mut().is_ok_and(|url| url.fragment_mut().is_some()); + let copy_command = url.and_then(|url| url.copy_url_command()); + if ui + .add_enabled( + is_on_selection && copy_command.is_ok() && has_time_range, + egui::Button::new("Copy link to trimmed time range"), + ) + .on_disabled_hover_text(if let Err(err) = copy_command.as_ref() { + format!("Can't share links to the current recording: {err}") + } else if !has_time_range { + "The current recording doesn't support time range links".to_owned() + } else { + "Open the context menu on selected time to copy link".to_owned() + }) + .clicked() + && let Ok(copy_command) = copy_command + { + ctx.command_sender().send_system(copy_command); + } } /// What part of the time loop selection is the user hovering? diff --git a/crates/viewer/re_view_spatial/src/eye.rs b/crates/viewer/re_view_spatial/src/eye.rs index 531971df7fd2..d9dc7e5421e9 100644 --- a/crates/viewer/re_view_spatial/src/eye.rs +++ b/crates/viewer/re_view_spatial/src/eye.rs @@ -229,8 +229,6 @@ struct ControlEye { fov_y: Option, did_interact: bool, - - written_radius: bool, } impl ControlEye { @@ -287,14 +285,6 @@ impl ControlEye { .0, ); - let has_look_target = eye_property - .component_or_empty::(EyeControls3D::descriptor_look_target().component)? - .is_some(); - - let has_position = eye_property - .component_or_empty::(EyeControls3D::descriptor_position().component)? - .is_some(); - Ok(Self { pos, look_target, @@ -302,7 +292,6 @@ impl ControlEye { speed, eye_up, did_interact: false, - written_radius: has_position && has_look_target, fov_y, }) } @@ -544,10 +533,16 @@ impl ControlEye { let world_movement = rot * (self.speed as f32 * local_movement); - eye_state.velocity = egui::lerp( - eye_state.velocity..=world_movement, - egui::emath::exponential_smooth_factor(0.90, 0.2, dt), - ); + // If input is zero, don't continue moving with velocity. Since we're no longer interacting + // we don't want to continue writing to blueprint and creating undo points. + eye_state.velocity = if local_movement == Vec3::ZERO { + Vec3::ZERO + } else { + egui::lerp( + eye_state.velocity..=world_movement, + egui::emath::exponential_smooth_factor(0.90, 0.2, dt), + ) + }; let delta = eye_state.velocity * dt; self.pos += delta; @@ -602,7 +597,7 @@ impl ControlEye { } } -fn find_camera(space_cameras: &[SpaceCamera3D], needle: &EntityPath) -> Option { +pub fn find_camera(space_cameras: &[SpaceCamera3D], needle: &EntityPath) -> Option { let mut found_camera = None; for camera in space_cameras { @@ -618,52 +613,6 @@ fn find_camera(space_cameras: &[SpaceCamera3D], needle: &EntityPath) -> Option we don't know the bounding box of every instance (right now) - // -> tracking instances over time may not be desired - // (this can happen with entities as well, but is less likely). - // - // For future reference, it's also worth pointing out that for interactions in the view we - // already have the 3D position: - // if let Some(SelectedSpaceContext::ThreeD { - // pos: Some(clicked_point), - // .. - // }) = ctx.selection_state().hovered_space_context() - - if let Some(entity_bbox) = bounding_boxes.per_entity.get(&entity_path.hash()) { - let radius = entity_bbox.centered_bounding_sphere_radius() * 1.5; - let orbit_radius = if radius < 0.0001 { - // Handle zero-sized bounding boxes: - (bounding_boxes.current.centered_bounding_sphere_radius() * 1.5).at_least(0.01) - } else if eye.written_radius { - eye.pos.distance(eye.look_target) - } else { - radius - }; - - let fwd = eye.fwd(); - - match eye.kind { - Eye3DKind::FirstPerson => { - eye.pos = entity_bbox.center(); - eye.look_target = entity_bbox.center() + fwd; - } - Eye3DKind::Orbital => { - eye.look_target = entity_bbox.center(); - eye.pos = entity_bbox.center() - fwd * orbit_radius; - } - } - } -} - fn ease_out(t: f32) -> f32 { 1. - (1. - t) * (1. - t) } @@ -681,6 +630,10 @@ impl EyeState { } } + fn stop_interpolation(&mut self) { + self.interpolation = None; + } + /// Gets and updates the current target eye from/to the blueprint. fn control_and_sync_with_blueprint( &mut self, @@ -702,9 +655,17 @@ impl EyeState { let mut drag_threshold = 0.0; - let tracking_entity = eye_property.component_or_empty::( - EyeControls3D::descriptor_tracking_entity().component, - )?; + let tracking_entity = eye_property + .component_or_empty::( + EyeControls3D::descriptor_tracking_entity().component, + )? + .and_then(|tracking_entity| { + if tracking_entity.is_empty() { + None + } else { + Some(tracking_entity) + } + }); if let Some(tracking_entity) = &tracking_entity { let tracking_entity = EntityPath::from(tracking_entity.as_str()); @@ -717,6 +678,17 @@ impl EyeState { // to stop tracking. eye.handle_input(self, response, drag_threshold); + eye.save_to_blueprint( + ctx.viewer_ctx, + eye_property, + old_pos, + old_look_target, + old_eye_up, + ); + + // Handle spinning after saving to blueprint to not continuously write to the blueprint. + self.handle_spinning(ctx, eye_property, &mut eye)?; + if let Some(tracked_eye) = self.handle_tracking_entity( ctx, eye_property, @@ -730,17 +702,6 @@ impl EyeState { return Ok(tracked_eye); } - eye.save_to_blueprint( - ctx.viewer_ctx, - eye_property, - old_pos, - old_look_target, - old_eye_up, - ); - - // Handle spinning after saving to blueprint to not continuously write to the blueprint. - self.handle_spinning(ctx, eye_property, &mut eye)?; - self.last_look_target = Some(eye.look_target); self.last_orbit_radius = Some(eye.pos.distance(eye.look_target)); self.last_eye_up = Some(eye.up()); @@ -765,9 +726,11 @@ impl EyeState { ) -> Option { if let Some(tracking_entity) = &tracking_entity { let tracking_entity = EntityPath::from(tracking_entity.as_str()); - if self.last_tracked_entity.as_ref() == Some(&tracking_entity) { - self.last_tracked_entity = Some(tracking_entity.clone()); + + let new_tracking = self.last_tracked_entity.as_ref() != Some(&tracking_entity); + if new_tracking { self.start_interpolation(); + self.last_tracked_entity = Some(tracking_entity.clone()); } let did_eye_change = match eye.kind { @@ -790,8 +753,69 @@ impl EyeState { EyeControls3D::descriptor_tracking_entity(), ); } else { - self.start_interpolation(); - entity_target_eye(&tracking_entity, bounding_boxes, eye); + // Note that we may want to focus on an _instance_ instead in the future: + // The problem with that is that there may be **many** instances (think point cloud) + // and they may not be consistent over time. + // -> we don't know the bounding box of every instance (right now) + // -> tracking instances over time may not be desired + // (this can happen with entities as well, but is less likely). + // + // For future reference, it's also worth pointing out that for interactions in the view we + // already have the 3D position: + // if let Some(SelectedSpaceContext::ThreeD { + // pos: Some(clicked_point), + // .. + // }) = ctx.selection_state().hovered_space_context() + + if let Some(entity_bbox) = bounding_boxes.per_entity.get(&tracking_entity.hash()) { + // If we're tracking something new, set the current position & look target to the correct view. + if new_tracking { + let fwd = eye.fwd(); + let radius = entity_bbox.centered_bounding_sphere_radius() * 1.5; + let radius = if radius < 0.0001 { + // Handle zero-sized bounding boxes: + (bounding_boxes.current.centered_bounding_sphere_radius() * 1.5) + .at_least(0.02) + } else { + radius + }; + eye.pos = eye.look_target - fwd * radius; + // Force write of pos and look target to not use fallbacks for that. + eye_property.save_blueprint_component( + ctx.viewer_ctx, + &EyeControls3D::descriptor_position(), + &Position3D::from(eye.pos), + ); + + eye_property.save_blueprint_component( + ctx.viewer_ctx, + &EyeControls3D::descriptor_look_target(), + &Position3D::from(eye.look_target), + ); + } + + let orbit_radius = eye.pos.distance(eye.look_target); + + let pos = entity_bbox.center(); + + let fwd = eye.fwd(); + + match eye.kind { + Eye3DKind::FirstPerson => { + eye.pos = pos; + eye.look_target = pos + fwd; + } + Eye3DKind::Orbital => { + eye.look_target = pos; + eye.pos = pos - fwd * orbit_radius; + } + } + } + + self.last_look_target = Some(eye.look_target); + self.last_eye_up = Some(eye.eye_up); + self.last_orbit_radius = Some(eye.pos.distance(eye.look_target)); + return Some(eye.get_eye()); } } else { @@ -841,6 +865,57 @@ impl EyeState { Ok(()) } + pub fn focus_entity( + &self, + ctx: &ViewContext<'_>, + space_cameras: &[SpaceCamera3D], + bounding_boxes: &SceneBoundingBoxes, + eye_property: &ViewProperty, + focused_entity: &EntityPath, + ) -> Result<(), ViewPropertyQueryError> { + let mut eye = ControlEye::from_blueprint(ctx, eye_property, self.fov_y)?; + eye.did_interact = true; + let ControlEye { + pos: old_pos, + look_target: old_look_target, + eye_up: old_eye_up, + .. + } = eye; + // Focusing cameras is not something that happens now, since those are always tracked. + if let Some(target_eye) = find_camera(space_cameras, focused_entity) { + eye.pos = target_eye.pos_in_world(); + eye.look_target = target_eye.pos_in_world() + target_eye.forward_in_world(); + eye.eye_up = target_eye.world_from_rub_view.transform_vector3(Vec3::Y); + } else if let Some(entity_bbox) = bounding_boxes.per_entity.get(&focused_entity.hash()) { + let fwd = self + .last_eye + .map(|eye| eye.forward_in_world()) + .unwrap_or_else(|| Vec3::splat(f32::sqrt(1.0 / 3.0))); + let radius = entity_bbox.centered_bounding_sphere_radius() * 1.5; + let radius = if radius < 0.0001 { + // Handle zero-sized bounding boxes: + (bounding_boxes.current.centered_bounding_sphere_radius() * 1.5).at_least(0.02) + } else { + radius + }; + eye.look_target = entity_bbox.center(); + eye.pos = eye.look_target - fwd * radius; + } + + eye.save_to_blueprint( + ctx.viewer_ctx, + eye_property, + old_pos, + old_look_target, + old_eye_up, + ); + + eye_property + .clear_blueprint_component(ctx.viewer_ctx, EyeControls3D::descriptor_tracking_entity()); + + Ok(()) + } + pub fn update( &mut self, ctx: &ViewContext<'_>, @@ -893,13 +968,10 @@ impl EyeState { interpolation.start.lerp(&target_eye, t) } else { + self.stop_interpolation(); target_eye }; - if eye == target_eye { - self.interpolation = None; - } - self.last_eye = Some(eye); Ok(eye) diff --git a/crates/viewer/re_view_spatial/src/ui_3d.rs b/crates/viewer/re_view_spatial/src/ui_3d.rs index bbe302c02e58..0704dd2d66aa 100644 --- a/crates/viewer/re_view_spatial/src/ui_3d.rs +++ b/crates/viewer/re_view_spatial/src/ui_3d.rs @@ -27,6 +27,7 @@ use re_viewport_blueprint::ViewProperty; use crate::{ SpatialView3D, + eye::find_camera, space_camera_3d::SpaceCamera3D, ui::{SpatialViewState, create_labels}, view_kind::SpatialViewKind, @@ -313,13 +314,26 @@ impl SpatialView3D { }; if let Some(entity_path) = focused_entity { - if state.last_tracked_entity() != Some(entity_path) { - eye_property.save_blueprint_component( - ctx, - &EyeControls3D::descriptor_tracking_entity(), - &re_types::components::EntityPath::from(entity_path), - ); - state.state_3d.eye_state.last_interaction_time = Some(ui.time()); + if ui.ctx().input(|i| i.modifiers.alt) + || find_camera(space_cameras, entity_path).is_some() + { + if state.last_tracked_entity() != Some(entity_path) { + eye_property.save_blueprint_component( + ctx, + &EyeControls3D::descriptor_tracking_entity(), + &re_types::components::EntityPath::from(entity_path), + ); + state.state_3d.eye_state.last_interaction_time = Some(ui.time()); + } + } else { + state.state_3d.eye_state.start_interpolation(); + state.state_3d.eye_state.focus_entity( + &self.view_context(ctx, query.view_id, state), + space_cameras, + &state.bounding_boxes, + &eye_property, + entity_path, + )?; } } diff --git a/crates/viewer/re_view_spatial/src/visualizers/cameras.rs b/crates/viewer/re_view_spatial/src/visualizers/cameras.rs index 946c4c989949..61ceabdce867 100644 --- a/crates/viewer/re_view_spatial/src/visualizers/cameras.rs +++ b/crates/viewer/re_view_spatial/src/visualizers/cameras.rs @@ -41,7 +41,10 @@ impl IdentifiedViewSystem for CamerasVisualizer { } struct CameraComponentDataWithFallbacks { - pinhole: crate::Pinhole, + image_from_camera: glam::Mat3, + resolution: glam::Vec2, + color: egui::Color32, + line_width: re_renderer::Size, camera_xyz: components::ViewCoordinates, image_plane_distance: f32, } @@ -49,7 +52,6 @@ struct CameraComponentDataWithFallbacks { impl CamerasVisualizer { fn visit_instance( &mut self, - tokens: &re_ui::DesignTokens, line_builder: &mut re_renderer::LineDrawableBuilder<'_>, transforms: &TransformTreeContext, data_result: &DataResult, @@ -57,13 +59,10 @@ impl CamerasVisualizer { entity_highlight: &ViewOutlineMasks, ) { // Check for valid resolution. - let w = pinhole_properties.pinhole.resolution.x; - let h = pinhole_properties.pinhole.resolution.y; + let w = pinhole_properties.resolution.x; + let h = pinhole_properties.resolution.y; let z = pinhole_properties.image_plane_distance; - let color = pinhole_properties - .pinhole - .color - .unwrap_or(tokens.frustum_color); + let color = pinhole_properties.color; if !w.is_finite() || !h.is_finite() || w <= 0.0 || h <= 0.0 { return; } @@ -72,13 +71,20 @@ impl CamerasVisualizer { let ent_path = &data_result.entity_path; let frame_id = transforms.transform_frame_id_for(ent_path.hash()); + let pinhole = crate::Pinhole { + image_from_camera: pinhole_properties.image_from_camera, + resolution: pinhole_properties.resolution, + color: Some(pinhole_properties.color), + line_width: Some(pinhole_properties.line_width), + }; + // If the camera is the target frame, there is nothing for us to display. if transforms.target_frame() == frame_id { self.space_cameras.push(SpaceCamera3D { ent_path: ent_path.clone(), pinhole_view_coordinates: pinhole_properties.camera_xyz, world_from_camera: macaw::IsoTransform::IDENTITY, - pinhole: Some(pinhole_properties.pinhole), + pinhole: Some(pinhole), picture_plane_distance: pinhole_properties.image_plane_distance, }); return; @@ -109,24 +115,22 @@ impl CamerasVisualizer { ent_path: ent_path.clone(), pinhole_view_coordinates: pinhole_properties.camera_xyz, world_from_camera: world_from_camera_iso, - pinhole: Some(pinhole_properties.pinhole), + pinhole: Some(pinhole), picture_plane_distance: pinhole_properties.image_plane_distance, }); // Setup a RDF frustum (for non-RDF we apply a transformation matrix later). let corners = [ - pinhole_properties.pinhole.unproject(vec3(0.0, 0.0, z)), - pinhole_properties.pinhole.unproject(vec3(0.0, h, z)), - pinhole_properties.pinhole.unproject(vec3(w, h, z)), - pinhole_properties.pinhole.unproject(vec3(w, 0.0, z)), + pinhole.unproject(vec3(0.0, 0.0, z)), + pinhole.unproject(vec3(0.0, h, z)), + pinhole.unproject(vec3(w, h, z)), + pinhole.unproject(vec3(w, 0.0, z)), ]; let up_triangle = [ - pinhole_properties.pinhole.unproject(vec3(0.4 * w, 0.0, z)), - pinhole_properties - .pinhole - .unproject(vec3(0.5 * w, -0.1 * w, z)), - pinhole_properties.pinhole.unproject(vec3(0.6 * w, 0.0, z)), + pinhole.unproject(vec3(0.4 * w, 0.0, z)), + pinhole.unproject(vec3(0.5 * w, -0.1 * w, z)), + pinhole.unproject(vec3(0.6 * w, 0.0, z)), ]; let strips = vec![ @@ -158,11 +162,7 @@ impl CamerasVisualizer { ), ]; - let radius = pinhole_properties - .pinhole - .line_width - .unwrap_or(re_renderer::Size::new_ui_points(1.0)); - + let radius = pinhole_properties.line_width; let instance_path_for_picking = re_entity_db::InstancePathHash::instance(ent_path, instance); let instance_layer_id = @@ -262,19 +262,20 @@ impl VisualizerSystem for CamerasVisualizer { Pinhole::descriptor_image_plane_distance().component, ); let color = query_results - .get_mono::(Pinhole::descriptor_color().component) - .map(|color| color.into()); - let line_width = query_results - .get_mono::(Pinhole::descriptor_line_width().component) - .map(|radius| process_radius(&data_result.entity_path, radius)); + .get_mono_with_fallback::(Pinhole::descriptor_color().component) + .into(); + let line_width = process_radius( + &data_result.entity_path, + query_results.get_mono_with_fallback::( + Pinhole::descriptor_line_width().component, + ), + ); let component_data = CameraComponentDataWithFallbacks { - pinhole: crate::Pinhole { - image_from_camera: pinhole_projection.0.into(), - resolution: resolution.into(), - color, - line_width, - }, + image_from_camera: pinhole_projection.0.into(), + resolution: resolution.into(), + color, + line_width, camera_xyz, image_plane_distance: image_plane_distance.into(), }; @@ -284,7 +285,6 @@ impl VisualizerSystem for CamerasVisualizer { .entity_outline_mask(data_result.entity_path.hash()); self.visit_instance( - ctx.tokens(), &mut line_builder, transforms, data_result, diff --git a/crates/viewer/re_view_spatial/tests/transform_hierarchy.rs b/crates/viewer/re_view_spatial/tests/transform_hierarchy.rs index e451894c67bd..cf7d0a9ab90c 100644 --- a/crates/viewer/re_view_spatial/tests/transform_hierarchy.rs +++ b/crates/viewer/re_view_spatial/tests/transform_hierarchy.rs @@ -150,13 +150,29 @@ pub fn test_transform_hierarchy() { } fn setup_blueprint(test_context: &mut TestContext) -> ViewId { - test_context.setup_viewport_blueprint(|_ctx, blueprint| { + test_context.setup_viewport_blueprint(|ctx, blueprint| { let view_blueprint = ViewBlueprint::new_with_root_wildcard(re_view_spatial::SpatialView3D::identifier()); let view_id = view_blueprint.id; blueprint.add_views(std::iter::once(view_blueprint), None, None); + let property = ViewProperty::from_archetype::( + ctx.blueprint_db(), + ctx.blueprint_query(), + view_id, + ); + property.save_blueprint_component( + ctx, + &EyeControls3D::descriptor_position(), + &Position3D::new(0.0, 8.0, 10.0), + ); + property.save_blueprint_component( + ctx, + &EyeControls3D::descriptor_look_target(), + &Position3D::new(0.0, 0.0, 2.0), + ); + view_id }) } @@ -187,24 +203,6 @@ fn run_view_ui_and_save_snapshot( // * 6: The logo rotated 45 degrees around the y axis (green). // * 7: The logo is back to normal (frame 0) again. - test_context.with_blueprint_ctx(|ctx, _| { - let property = ViewProperty::from_archetype::( - ctx.current_blueprint(), - ctx.blueprint_query(), - view_id, - ); - property.save_blueprint_component( - &ctx, - &EyeControls3D::descriptor_position(), - &Position3D::new(0.0, 8.0, 10.0), - ); - property.save_blueprint_component( - &ctx, - &EyeControls3D::descriptor_look_target(), - &Position3D::new(0.0, 0.0, 2.0), - ); - }); - let mut errors = Vec::new(); for time in 0..=7 { let name = format!("{name}_{}_{time}", timeline.name()); diff --git a/crates/viewer/re_viewer/tests/snapshots/all_component_fallbacks__arch_fallback_rerun.archetypes.Pinhole.snap b/crates/viewer/re_viewer/tests/snapshots/all_component_fallbacks__arch_fallback_rerun.archetypes.Pinhole.snap index 52e4c285c39f..edaf045cedc2 100644 --- a/crates/viewer/re_viewer/tests/snapshots/all_component_fallbacks__arch_fallback_rerun.archetypes.Pinhole.snap +++ b/crates/viewer/re_viewer/tests/snapshots/all_component_fallbacks__arch_fallback_rerun.archetypes.Pinhole.snap @@ -6,5 +6,5 @@ image_from_camera: [[100.0, 0.0, 0.0, 0.0, 100.0, 0.0, 100.0, 100.0, 1.0]] resolution: [[0.0, 0.0]] camera_xyz: [[3, 2, 5]] image_plane_distance: [1.0] -color: [2428259839] -line_width: [-1.5] +color: [2392761855] +line_width: [-1.0] diff --git a/crates/viewer/re_viewer_context/src/store_hub.rs b/crates/viewer/re_viewer_context/src/store_hub.rs index d171280f437a..715f29fe8d8e 100644 --- a/crates/viewer/re_viewer_context/src/store_hub.rs +++ b/crates/viewer/re_viewer_context/src/store_hub.rs @@ -340,6 +340,21 @@ impl StoreHub { .retain(|_, id| id != store_id); } } + + // Drop the store itself on a separate thread, + // so that recursing through it and freeing the memory doesn’t block the UI thread. + #[allow( + clippy::allow_attributes, + clippy::disallowed_types, + reason = "If this thread spawn fails due to running on Wasm (or for any other reason), + the error will be ignored and the store will be dropped on this thread." + )] + let (Ok(_) | Err(_)) = std::thread::Builder::new() + .name("drop-removed-store".into()) + .spawn(|| { + re_tracing::profile_scope!("drop store"); + drop(removed_store); + }); } pub fn remove(&mut self, entry: &RecordingOrTable) { diff --git a/crates/viewer/re_viewer_context/src/time_control.rs b/crates/viewer/re_viewer_context/src/time_control.rs index ba8c611ad197..39ec55706f9e 100644 --- a/crates/viewer/re_viewer_context/src/time_control.rs +++ b/crates/viewer/re_viewer_context/src/time_control.rs @@ -182,7 +182,7 @@ impl TimeBlueprintExt for T { } fn clear_time_selection(&self) { - self.clear_static_blueprint_component( + self.clear_blueprint_component( time_panel_blueprint_entity_path(), TimePanelBlueprint::descriptor_time_selection(), ); @@ -453,6 +453,7 @@ impl TimeControl { self.timeline = ActiveTimeline::Auto(*self.timeline()); } + let old_timeline = *self.timeline().name(); // Make sure we are on a valid timeline. if let Some(times_per_timeline) = times_per_timeline { self.select_valid_timeline(times_per_timeline); @@ -501,13 +502,23 @@ impl TimeControl { let play_state = self.play_state(); // Update the last paused time if we are paused. - if let Some(state) = self.states.get_mut(self.timeline.name()) { + let timeline = *self.timeline.name(); + if let Some(state) = self.states.get_mut(&timeline) { if let Some(fps) = blueprint_ctx.fps() { state.fps = fps as f32; } - if let Some(new_time_selection) = blueprint_ctx.time_selection() { - state.loop_selection = Some(new_time_selection.into()); + let bp_loop_section = blueprint_ctx.time_selection(); + // If we've switched timeline, use the new timeline's cached time selection. + if old_timeline != timeline { + match state.loop_selection { + Some(selection) => blueprint_ctx.set_time_selection(selection.to_int()), + None => { + blueprint_ctx.clear_time_selection(); + } + } + } else { + state.loop_selection = bp_loop_section.map(|r| r.into()); } match play_state { @@ -816,9 +827,15 @@ impl TimeControl { self.timeline = ActiveTimeline::Pending(Timeline::new_sequence(*timeline_name)); } - if let Some(full_valid_range) = self.full_valid_range(times_per_timeline) - && !self.states.contains_key(timeline_name) - { + if let Some(state) = self.states.get(timeline_name) { + // Use the new timeline's cached time selection. + if let Some(blueprint_ctx) = blueprint_ctx { + match state.loop_selection { + Some(selection) => blueprint_ctx.set_time_selection(selection.to_int()), + None => blueprint_ctx.clear_time_selection(), + } + } + } else if let Some(full_valid_range) = self.full_valid_range(times_per_timeline) { self.states .insert(*timeline_name, TimeState::new(full_valid_range.min)); } @@ -949,6 +966,13 @@ impl TimeControl { blueprint_ctx.clear_time_selection(); } state.loop_selection = None; + if self.loop_mode == LoopMode::Selection { + self.loop_mode = LoopMode::Off; + + if let Some(blueprint_ctx) = blueprint_ctx { + blueprint_ctx.set_loop_mode(self.loop_mode); + } + } NeedsRepaint::Yes } else { diff --git a/crates/viewer/re_web_viewer_server/Cargo.toml b/crates/viewer/re_web_viewer_server/Cargo.toml index 84a3ca32bfc9..f14f0f0f9086 100644 --- a/crates/viewer/re_web_viewer_server/Cargo.toml +++ b/crates/viewer/re_web_viewer_server/Cargo.toml @@ -24,6 +24,7 @@ include = [ "web_viewer/re_viewer_bg.wasm", "web_viewer/re_viewer.js", "web_viewer/sw.js", + "src/signed-in.html", ] [lints] diff --git a/deny.toml b/deny.toml index 7a0ea557a860..3b15b3cf1acc 100644 --- a/deny.toml +++ b/deny.toml @@ -69,6 +69,7 @@ skip = [ { name = "itertools" }, # Too popular { name = "libloading" }, # datafusion-ffi needs an older version than wgpu { name = "lru" }, # because of lance + { name = "lz4_flex" }, # the Arrow ecosystem is a bit behind, but it's fine, this is a very tiny, flat dependency { name = "memmap2" }, # because of walkers { name = "nom" }, # lance { name = "objc2-app-kit" }, # `accesskit_macos` uses a different version than `arboard` diff --git a/docs/content/concepts/blueprint.md b/docs/content/concepts/blueprint.md index 26fb12306864..0e755815849a 100644 --- a/docs/content/concepts/blueprint.md +++ b/docs/content/concepts/blueprint.md @@ -1,5 +1,5 @@ --- -title: Code of Conduct -order: 100 -redirect: /docs/concepts/blueprints +title: Blueprint +hidden: true +redirect: concepts/blueprints --- diff --git a/docs/content/getting-started.md b/docs/content/getting-started.md index b27634f9634f..fe1aca7cbd03 100644 --- a/docs/content/getting-started.md +++ b/docs/content/getting-started.md @@ -1,5 +1,5 @@ --- -title: Quickstart +title: Getting Started order: 1 redirect: getting-started/quick-start --- diff --git a/docs/content/getting-started/installing-viewer.md b/docs/content/getting-started/installing-viewer.md index 8ff3e65c5ce7..8d1f99edcd63 100644 --- a/docs/content/getting-started/installing-viewer.md +++ b/docs/content/getting-started/installing-viewer.md @@ -1,5 +1,5 @@ --- title: Installing the Viewer -order: 1 +hidden: true redirect: overview/installing-viewer#installing-the-viewer --- diff --git a/docs/content/getting-started/navigating-the-viewer.md b/docs/content/getting-started/navigating-the-viewer.md index caa4efc896cf..f5b88542000a 100644 --- a/docs/content/getting-started/navigating-the-viewer.md +++ b/docs/content/getting-started/navigating-the-viewer.md @@ -1,5 +1,5 @@ --- title: Navigating the viewer -order: 600 +hidden: true redirect: getting-started/configure-the-viewer/navigating-the-viewer --- diff --git a/docs/content/getting-started/what-is-rerun.md b/docs/content/getting-started/what-is-rerun.md index b2a0aff7819c..d342712cfa4b 100644 --- a/docs/content/getting-started/what-is-rerun.md +++ b/docs/content/getting-started/what-is-rerun.md @@ -1,5 +1,5 @@ --- title: What is Rerun? -order: 0 +hidden: true redirect: overview/what-is-rerun --- diff --git a/docs/content/reference/migration/migration-0-21.md b/docs/content/reference/migration/migration-0-21.md index 481c17a509bb..76ed0fd6a244 100644 --- a/docs/content/reference/migration/migration-0-21.md +++ b/docs/content/reference/migration/migration-0-21.md @@ -82,7 +82,7 @@ To achieve the same effect, you can log any of the following "invalid" transform Previously, the `DisconnectedSpace` archetype played a double role by governing view spawn heuristics & being used as a transform placeholder. This led to a lot of complexity and often broke or caused confusion (see https://github.com/rerun-io/rerun/issues/6817, https://github.com/rerun-io/rerun/issues/4465, https://github.com/rerun-io/rerun/issues/4221). By now, explicit blueprints offer a better way to express which views should be spawned and what content they should query. -(you can learn more about blueprints [here](https://rerun.io/docs/getting-started/configure-the-viewer/through-code-tutorial)). +(you can learn more about blueprints [here](https://rerun.io/docs/getting-started/configure-the-viewer)). `DisconnectedSpace` will be removed in a future release. diff --git a/docs/content/reference/migration/migration-0-22.md b/docs/content/reference/migration/migration-0-22.md index fb84518b9338..b500a067288c 100644 --- a/docs/content/reference/migration/migration-0-22.md +++ b/docs/content/reference/migration/migration-0-22.md @@ -498,4 +498,4 @@ To achieve the same effect, you can log any of the following "invalid" transform Previously, the `DisconnectedSpace` archetype played a double role by governing view spawn heuristics & being used as a transform placeholder. This led to a lot of complexity and often broke or caused confusion (see https://github.com/rerun-io/rerun/issues/6817, https://github.com/rerun-io/rerun/issues/4465, https://github.com/rerun-io/rerun/issues/4221). By now, explicit blueprints offer a better way to express which views should be spawned and what content they should query. -(you can learn more about blueprints [here](https://rerun.io/docs/getting-started/configure-the-viewer/through-code-tutorial)). +(you can learn more about blueprints [here](../../getting-started/configure-the-viewer#programmatic-blueprints)). diff --git a/docs/content/reference/migration/migration-0-27.md b/docs/content/reference/migration/migration-0-27.md index 2b8143ce3773..5d2aba7649de 100644 --- a/docs/content/reference/migration/migration-0-27.md +++ b/docs/content/reference/migration/migration-0-27.md @@ -6,9 +6,9 @@ order: 983 ## Dropped support for Intel Macs -We've dropped official support for Intel (x86) maxOS in [PR #11719](https://github.com/rerun-io/rerun/pull/11719). +We've dropped official support for Intel (x86) macOS in [PR #11719](https://github.com/rerun-io/rerun/pull/11719). -This means our Python pheels on PyPi.org and our other pre-built artifact does no longer include Intel Mac binaries. +This means our Python wheels on PyPi.org and our other pre-built artifact does no longer include Intel Mac binaries. You can still build Rerun from source. There are instructions for that in [`BUILD.md`](https://github.com/rerun-io/rerun/blob/main/BUILD.md). diff --git a/docs/content/reference/types/archetypes/coordinate_frame.md b/docs/content/reference/types/archetypes/coordinate_frame.md index b603bb39b47a..d274e465324c 100644 --- a/docs/content/reference/types/archetypes/coordinate_frame.md +++ b/docs/content/reference/types/archetypes/coordinate_frame.md @@ -24,9 +24,9 @@ To learn more about transforms see [Spaces & Transforms](https://rerun.io/docs/c * [DataframeView](../views/dataframe_view.md) ## API reference links - * 🌊 [C++ API docs for `CoordinateFrame`](https://ref.rerun.io/docs/cpp/stable/structrerun_1_1archetypes_1_1CoordinateFrame.html?speculative-link) - * 🐍 [Python API docs for `CoordinateFrame`](https://ref.rerun.io/docs/python/stable/common/archetypes?speculative-link#rerun.archetypes.CoordinateFrame) - * πŸ¦€ [Rust API docs for `CoordinateFrame`](https://docs.rs/rerun/latest/rerun/archetypes/struct.CoordinateFrame.html?speculative-link) + * 🌊 [C++ API docs for `CoordinateFrame`](https://ref.rerun.io/docs/cpp/stable/structrerun_1_1archetypes_1_1CoordinateFrame.html) + * 🐍 [Python API docs for `CoordinateFrame`](https://ref.rerun.io/docs/python/stable/common/archetypes#rerun.archetypes.CoordinateFrame) + * πŸ¦€ [Rust API docs for `CoordinateFrame`](https://docs.rs/rerun/latest/rerun/archetypes/struct.CoordinateFrame.html) ## Example diff --git a/docs/content/reference/types/components/transform_frame_id.md b/docs/content/reference/types/components/transform_frame_id.md index 626dcd94e43e..b5f4a55d04a4 100644 --- a/docs/content/reference/types/components/transform_frame_id.md +++ b/docs/content/reference/types/components/transform_frame_id.md @@ -24,12 +24,12 @@ utf8 ``` ## API reference links - * 🌊 [C++ API docs for `TransformFrameId`](https://ref.rerun.io/docs/cpp/stable/structrerun_1_1components_1_1TransformFrameId.html?speculative-link) - * 🐍 [Python API docs for `TransformFrameId`](https://ref.rerun.io/docs/python/stable/common/components?speculative-link#rerun.components.TransformFrameId) - * πŸ¦€ [Rust API docs for `TransformFrameId`](https://docs.rs/rerun/latest/rerun/components/struct.TransformFrameId.html?speculative-link) + * 🌊 [C++ API docs for `TransformFrameId`](https://ref.rerun.io/docs/cpp/stable/structrerun_1_1components_1_1TransformFrameId.html) + * 🐍 [Python API docs for `TransformFrameId`](https://ref.rerun.io/docs/python/stable/common/components#rerun.components.TransformFrameId) + * πŸ¦€ [Rust API docs for `TransformFrameId`](https://docs.rs/rerun/latest/rerun/components/struct.TransformFrameId.html) ## Used by -* [`CoordinateFrame`](../archetypes/coordinate_frame.md?speculative-link) +* [`CoordinateFrame`](../archetypes/coordinate_frame.md) * [`Transform3D`](../archetypes/transform3d.md) diff --git a/docs/content/reference/types/datatypes/absolute_time_range.md b/docs/content/reference/types/datatypes/absolute_time_range.md index 20eaeeb8ef2a..0aa7a6b4b3e3 100644 --- a/docs/content/reference/types/datatypes/absolute_time_range.md +++ b/docs/content/reference/types/datatypes/absolute_time_range.md @@ -26,8 +26,8 @@ Struct { ``` ## API reference links - * 🌊 [C++ API docs for `AbsoluteTimeRange`](https://ref.rerun.io/docs/cpp/stable/structrerun_1_1datatypes_1_1AbsoluteTimeRange.html?speculative-link) - * 🐍 [Python API docs for `AbsoluteTimeRange`](https://ref.rerun.io/docs/python/stable/common/datatypes?speculative-link#rerun.datatypes.AbsoluteTimeRange) - * πŸ¦€ [Rust API docs for `AbsoluteTimeRange`](https://docs.rs/rerun/latest/rerun/datatypes/struct.AbsoluteTimeRange.html?speculative-link) + * 🌊 [C++ API docs for `AbsoluteTimeRange`](https://ref.rerun.io/docs/cpp/stable/structrerun_1_1datatypes_1_1AbsoluteTimeRange.html) + * 🐍 [Python API docs for `AbsoluteTimeRange`](https://ref.rerun.io/docs/python/stable/common/datatypes#rerun.datatypes.AbsoluteTimeRange) + * πŸ¦€ [Rust API docs for `AbsoluteTimeRange`](https://docs.rs/rerun/latest/rerun/datatypes/struct.AbsoluteTimeRange.html) diff --git a/docs/content/reference/types/datatypes/time_int.md b/docs/content/reference/types/datatypes/time_int.md index 3f50d5762be6..22d9df1be5b9 100644 --- a/docs/content/reference/types/datatypes/time_int.md +++ b/docs/content/reference/types/datatypes/time_int.md @@ -19,6 +19,6 @@ int64 ## Used by -* [`AbsoluteTimeRange`](../datatypes/absolute_time_range.md?speculative-link) +* [`AbsoluteTimeRange`](../datatypes/absolute_time_range.md) * [`TimeRangeBoundary`](../datatypes/time_range_boundary.md) * [`Timestamp`](../components/timestamp.md) diff --git a/docs/content/reference/types/datatypes/utf8.md b/docs/content/reference/types/datatypes/utf8.md index 0bfb56dbe3f3..8b6224d7ce62 100644 --- a/docs/content/reference/types/datatypes/utf8.md +++ b/docs/content/reference/types/datatypes/utf8.md @@ -25,6 +25,6 @@ utf8 * [`Name`](../components/name.md) * [`TextLogLevel`](../components/text_log_level.md) * [`Text`](../components/text.md) -* [`TransformFrameId`](../components/transform_frame_id.md?speculative-link) +* [`TransformFrameId`](../components/transform_frame_id.md) * [`Utf8Pair`](../datatypes/utf8pair.md) * [`VisibleTimeRange`](../datatypes/visible_time_range.md) diff --git a/examples/rust/animated_urdf/Cargo.toml b/examples/rust/animated_urdf/Cargo.toml index 704603beef23..ef54f21a5855 100644 --- a/examples/rust/animated_urdf/Cargo.toml +++ b/examples/rust/animated_urdf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "animated_urdf" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/clock/Cargo.toml b/examples/rust/clock/Cargo.toml index 318853abd4c1..2d0b816c3fc5 100644 --- a/examples/rust/clock/Cargo.toml +++ b/examples/rust/clock/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clock" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/custom_callback/Cargo.toml b/examples/rust/custom_callback/Cargo.toml index 26c7330108a8..9e0a06cd7481 100644 --- a/examples/rust/custom_callback/Cargo.toml +++ b/examples/rust/custom_callback/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "custom_callback" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/custom_data_loader/Cargo.toml b/examples/rust/custom_data_loader/Cargo.toml index 100f8dc9a690..972d30fbeb7d 100644 --- a/examples/rust/custom_data_loader/Cargo.toml +++ b/examples/rust/custom_data_loader/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "custom_data_loader" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/custom_store_subscriber/Cargo.toml b/examples/rust/custom_store_subscriber/Cargo.toml index 5d7368eb55a2..0676dc5de921 100644 --- a/examples/rust/custom_store_subscriber/Cargo.toml +++ b/examples/rust/custom_store_subscriber/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "custom_store_subscriber" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/custom_view/Cargo.toml b/examples/rust/custom_view/Cargo.toml index 85778a35f52b..23778a01a74f 100644 --- a/examples/rust/custom_view/Cargo.toml +++ b/examples/rust/custom_view/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "custom_view" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/dataframe_query/Cargo.toml b/examples/rust/dataframe_query/Cargo.toml index 7ce6cd6fe6c7..03eb47c9cd3b 100644 --- a/examples/rust/dataframe_query/Cargo.toml +++ b/examples/rust/dataframe_query/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dataframe_query" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/dna/Cargo.toml b/examples/rust/dna/Cargo.toml index 10335bcaf759..c13ab6b36934 100644 --- a/examples/rust/dna/Cargo.toml +++ b/examples/rust/dna/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dna" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/extend_viewer_ui/Cargo.toml b/examples/rust/extend_viewer_ui/Cargo.toml index 9bf08b2b6ac7..ff1e54c85ff0 100644 --- a/examples/rust/extend_viewer_ui/Cargo.toml +++ b/examples/rust/extend_viewer_ui/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "extend_viewer_ui" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/external_data_loader/Cargo.toml b/examples/rust/external_data_loader/Cargo.toml index 62887c7c5cea..3b9725d2be57 100644 --- a/examples/rust/external_data_loader/Cargo.toml +++ b/examples/rust/external_data_loader/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rerun-loader-rust-file" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/graph_lattice/Cargo.toml b/examples/rust/graph_lattice/Cargo.toml index 8950e6431772..f80ecf5f70da 100644 --- a/examples/rust/graph_lattice/Cargo.toml +++ b/examples/rust/graph_lattice/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "graph_lattice" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/incremental_logging/Cargo.toml b/examples/rust/incremental_logging/Cargo.toml index fdc9c2c0391f..c86136df4a1b 100644 --- a/examples/rust/incremental_logging/Cargo.toml +++ b/examples/rust/incremental_logging/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "incremental_logging" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/lenses/Cargo.toml b/examples/rust/lenses/Cargo.toml index 9998d7452f94..5c8c6e868af2 100644 --- a/examples/rust/lenses/Cargo.toml +++ b/examples/rust/lenses/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lenses" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/log_file/Cargo.toml b/examples/rust/log_file/Cargo.toml index b316c575f6cb..6481ffaf51b6 100644 --- a/examples/rust/log_file/Cargo.toml +++ b/examples/rust/log_file/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "log_file" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/minimal/Cargo.toml b/examples/rust/minimal/Cargo.toml index 39d05f416048..c2bf5b84745e 100644 --- a/examples/rust/minimal/Cargo.toml +++ b/examples/rust/minimal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "minimal" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/minimal_options/Cargo.toml b/examples/rust/minimal_options/Cargo.toml index 875966bcd903..1e2095b5e88e 100644 --- a/examples/rust/minimal_options/Cargo.toml +++ b/examples/rust/minimal_options/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "minimal_options" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/minimal_serve/Cargo.toml b/examples/rust/minimal_serve/Cargo.toml index 0cabc83d0f50..c09f4f125b7a 100644 --- a/examples/rust/minimal_serve/Cargo.toml +++ b/examples/rust/minimal_serve/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "minimal_serve" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/objectron/Cargo.toml b/examples/rust/objectron/Cargo.toml index 4b1eff090d15..5f2a84d9ebce 100644 --- a/examples/rust/objectron/Cargo.toml +++ b/examples/rust/objectron/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "objectron" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/raw_mesh/Cargo.toml b/examples/rust/raw_mesh/Cargo.toml index eb43bbba3316..e0374e26e687 100644 --- a/examples/rust/raw_mesh/Cargo.toml +++ b/examples/rust/raw_mesh/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "raw_mesh" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/shared_recording/Cargo.toml b/examples/rust/shared_recording/Cargo.toml index 07f13cf08736..35689167e045 100644 --- a/examples/rust/shared_recording/Cargo.toml +++ b/examples/rust/shared_recording/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shared_recording" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/spawn_viewer/Cargo.toml b/examples/rust/spawn_viewer/Cargo.toml index 7977093fa9db..78ce124d5911 100644 --- a/examples/rust/spawn_viewer/Cargo.toml +++ b/examples/rust/spawn_viewer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spawn_viewer" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/stdio/Cargo.toml b/examples/rust/stdio/Cargo.toml index f9262af855d2..3d9825c8c339 100644 --- a/examples/rust/stdio/Cargo.toml +++ b/examples/rust/stdio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stdio" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/template/Cargo.toml b/examples/rust/template/Cargo.toml index fdd7369178e6..15f124663752 100644 --- a/examples/rust/template/Cargo.toml +++ b/examples/rust/template/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "template" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/examples/rust/viewer_callbacks/Cargo.toml b/examples/rust/viewer_callbacks/Cargo.toml index b61af336b905..f70d12cd83d1 100644 --- a/examples/rust/viewer_callbacks/Cargo.toml +++ b/examples/rust/viewer_callbacks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "viewer_callbacks" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/pixi.lock b/pixi.lock index 56c33b001e1e..3145abec15ae 100644 --- a/pixi.lock +++ b/pixi.lock @@ -210,6 +210,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.11.0-he8b52b9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.8-h04c0eec_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lychee-0.20.1-h358ba24_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py311h2dc5d0c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -617,6 +618,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxkbcommon-1.11.0-h95ca766_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.13.8-he58860d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lychee-0.20.1-h10803c1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.9.4-hd600fc2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.2-py311ha09ea12_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -983,6 +985,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-21.1.0-hf4e0ed4_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-16.0.6-hbedff68_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/lychee-0.20.1-h3c96896_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lz4-c-1.9.4-hf0c8a7f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/markupsafe-3.0.2-py311ha3cf9ac_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -1335,6 +1338,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-21.1.0-hbb9b287_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-16.0.6-hc4b4ae8_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lychee-0.20.1-hf7b78e7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.9.4-hb7217d7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-3.0.2-py311h4921393_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -1642,6 +1646,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.13.8-h741aa76_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-20.1.8-hfa2b4ca_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lychee-0.20.1-h85d3866_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.9.4-hcfcfb64_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libgfortran-5.3.0-6.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libs-5.3.0-7.tar.bz2 @@ -2038,6 +2043,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.11.0-he8b52b9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.8-h04c0eec_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lychee-0.20.1-h358ba24_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py311h2dc5d0c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -2436,6 +2442,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxkbcommon-1.11.0-h95ca766_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.13.8-he58860d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lychee-0.20.1-h10803c1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.9.4-hd600fc2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.2-py311ha09ea12_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -2790,6 +2797,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.13.8-he1bc88e_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-21.1.0-hf4e0ed4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/lychee-0.20.1-h3c96896_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lz4-c-1.9.4-hf0c8a7f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/markupsafe-3.0.2-py311ha3cf9ac_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -3129,6 +3137,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-21.1.0-hbb9b287_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-16.0.6-hc4b4ae8_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lychee-0.20.1-hf7b78e7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.9.4-hb7217d7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-3.0.2-py311h4921393_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -3437,6 +3446,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.13.8-h741aa76_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-20.1.8-hfa2b4ca_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lychee-0.20.1-h85d3866_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.9.4-hcfcfb64_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libgfortran-5.3.0-6.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libs-5.3.0-7.tar.bz2 @@ -6291,6 +6301,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.11.0-he8b52b9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.8-h04c0eec_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lychee-0.20.1-h358ba24_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py311h2dc5d0c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -6712,6 +6723,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcrypt-4.4.36-h31becfc_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.13.8-he58860d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lychee-0.20.1-h10803c1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.9.4-hd600fc2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.2-py311ha09ea12_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -7082,6 +7094,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-21.1.0-hbb9b287_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-16.0.6-hc4b4ae8_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lychee-0.20.1-hf7b78e7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.9.4-hb7217d7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-3.0.2-py311h4921393_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -7429,6 +7442,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.13.8-h741aa76_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-20.1.8-hfa2b4ca_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lychee-0.20.1-h85d3866_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.9.4-hcfcfb64_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libgfortran-5.3.0-6.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libs-5.3.0-7.tar.bz2 @@ -7841,6 +7855,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.11.0-he8b52b9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.8-h04c0eec_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lychee-0.20.1-h358ba24_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py311h2dc5d0c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -8256,6 +8271,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxkbcommon-1.11.0-h95ca766_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.13.8-he58860d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lychee-0.20.1-h10803c1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.9.4-hd600fc2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.2-py311ha09ea12_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -8627,6 +8643,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.13.8-he1bc88e_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-21.1.0-hf4e0ed4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/lychee-0.20.1-h3c96896_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/lz4-c-1.9.4-hf0c8a7f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/markupsafe-3.0.2-py311ha3cf9ac_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -8983,6 +9000,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-21.1.0-hbb9b287_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-16.0.6-hc4b4ae8_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lychee-0.20.1-hf7b78e7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.9.4-hb7217d7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-3.0.2-py311h4921393_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -9308,6 +9326,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.13.8-h741aa76_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-20.1.8-hfa2b4ca_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lychee-0.20.1-h85d3866_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.9.4-hcfcfb64_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libgfortran-5.3.0-6.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libs-5.3.0-7.tar.bz2 @@ -9726,6 +9745,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.8-h04c0eec_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvmlite-0.44.0-py311h1741904_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lychee-0.20.1-h358ba24_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py311h2dc5d0c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -10254,6 +10274,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-21.1.0-hbb9b287_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-16.0.6-hc4b4ae8_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvmlite-0.44.0-py311h674d19a_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lychee-0.20.1-hf7b78e7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.9.4-hb7217d7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-3.0.2-py311h4921393_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -10717,6 +10738,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.13.8-h741aa76_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/llvmlite-0.44.0-py311h7c248df_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lychee-0.20.1-h85d3866_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.9.4-hcfcfb64_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libgfortran-5.3.0-6.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libs-5.3.0-7.tar.bz2 @@ -11259,6 +11281,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.11.0-he8b52b9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.8-h04c0eec_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lychee-0.20.1-h358ba24_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py311h2dc5d0c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -11697,6 +11720,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcrypt-4.4.36-h31becfc_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.13.8-he58860d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lychee-0.20.1-h10803c1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.9.4-hd600fc2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.2-py311ha09ea12_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -12086,6 +12110,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-21.1.0-hbb9b287_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-16.0.6-hc4b4ae8_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lychee-0.20.1-hf7b78e7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.9.4-hb7217d7_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-3.0.2-py311h4921393_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda @@ -12440,6 +12465,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.13.8-h741aa76_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-20.1.8-hfa2b4ca_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lychee-0.20.1-h85d3866_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.9.4-hcfcfb64_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libgfortran-5.3.0-6.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/m2w64-gcc-libs-5.3.0-7.tar.bz2 @@ -28594,6 +28620,67 @@ packages: requires_dist: - rerun-sdk editable: true +- conda: https://conda.anaconda.org/conda-forge/linux-64/lychee-0.20.1-h358ba24_0.conda + sha256: d45399ea81174385684f555c41e0da934108825418d3342d3e55872ee4b73589 + md5: fd74bbefc9825a5be805701955cfa804 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - openssl >=3.5.2,<4.0a0 + constrains: + - __glibc >=2.17 + license: Apache-2.0 OR MIT + purls: [] + size: 6210519 + timestamp: 1756298578629 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lychee-0.20.1-h10803c1_0.conda + sha256: 55b0a65a24569b8bd0df7efa958faf208963eba4c0c7d8bd85ea701f36bda767 + md5: 0a3ea8d85f43092987d91b81024b6677 + depends: + - libgcc >=14 + - openssl >=3.5.2,<4.0a0 + constrains: + - __glibc >=2.17 + license: Apache-2.0 OR MIT + purls: [] + size: 6278763 + timestamp: 1756298588296 +- conda: https://conda.anaconda.org/conda-forge/osx-64/lychee-0.20.1-h3c96896_0.conda + sha256: 9cef42f31b78ede0ed3e5126319f29fa770f9233f539e104ab09452edac7c8f1 + md5: ef2490498af8be160f6877ac9bc1cbd6 + depends: + - __osx >=10.13 + - openssl >=3.5.2,<4.0a0 + constrains: + - __osx >=10.13 + license: Apache-2.0 OR MIT + purls: [] + size: 5686350 + timestamp: 1756299008273 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lychee-0.20.1-hf7b78e7_0.conda + sha256: bf31c630432c5e63535129c932323531346e7f165aa08710200b9751669928e3 + md5: b1c2d62532cd14ba499f3e2601627a7c + depends: + - __osx >=11.0 + - openssl >=3.5.2,<4.0a0 + constrains: + - __osx >=11.0 + license: Apache-2.0 OR MIT + purls: [] + size: 5571010 + timestamp: 1756298732575 +- conda: https://conda.anaconda.org/conda-forge/win-64/lychee-0.20.1-h85d3866_0.conda + sha256: 22d579f0c39c9d6d135ad98fbb3ccefaaa64afea50d5e2dea32f3b0179391b1e + md5: c6822e25fe8bda503f87fd08b1785d40 + depends: + - openssl >=3.5.2,<4.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 OR MIT + purls: [] + size: 5141672 + timestamp: 1756299462207 - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda sha256: 47326f811392a5fd3055f0f773036c392d26fdb32e4d8e7a8197eed951489346 md5: 9de5350a85c4a20c685259b889aa6393 @@ -34222,8 +34309,8 @@ packages: requires_python: '>=3.9' - pypi: ./rerun_py name: rerun-sdk - version: 0.27.0a8+dev - sha256: 302c772b5c76b0240035b66bef436351afe9503740ecb6ab62b8f92b76536efe + version: 0.28.0a1+dev + sha256: d79a4425ea617237290dc7baec6fb0fc00ffa3a0ff629d3f5b6746d9d3164921 requires_dist: - attrs>=23.1.0 - numpy>=2 @@ -34232,7 +34319,7 @@ packages: - typing-extensions>=4.5 - pytest==8.4.2 ; extra == 'tests' - syrupy==5.0.0 ; extra == 'tests' - - rerun-notebook==0.27.0a8+dev ; extra == 'notebook' + - rerun-notebook==0.28.0a1+dev ; extra == 'notebook' - datafusion==50.1.0 ; extra == 'datafusion' - rerun-sdk[notebook] ; extra == 'all' - rerun-sdk[datafusion] ; extra == 'all' diff --git a/pixi.toml b/pixi.toml index 527e91e8bdeb..8445bbb1c385 100644 --- a/pixi.toml +++ b/pixi.toml @@ -238,6 +238,12 @@ rs-fmt = "cargo fmt --all" format = { depends-on = ["cpp-fmt", "misc-fmt", "pb-fmt", "py-fmt", "rs-fmt", "toml-fmt"] } fmt = { depends-on = ["format"] } +# Check links +link-check-pr = { cmd = "python scripts/ci/pr_link_checker.py --base-ref {{ ref }}", args = [ + { arg = "ref" }, +] } +link-check = 'lychee --verbose --cache --max-cache-age 1d . --base . "**/*.md" "**/*.rs" "**/*.toml" "**/*.hpp" "**/*.cpp" "**/CMakeLists.txt" "**/*.py" "**/*.yml"' + # Assorted linting tasks fast-lint = "python scripts/fast_lint.py" lint-codegen = "cargo --quiet run --package re_types_builder -- --check" @@ -561,6 +567,7 @@ flatbuffers = ">=23" gitignore-parser = ">=0.1.9" gitpython = ">=3.1.40" jinja2 = ">=3.1.3,<3.2" # For `build_screenshot_compare.py` and other utilities that build websites. +lychee = "0.20.1.*" mypy = "1.14.1.*" nasm = ">=2.16" # Required by https://github.com/memorysafety/rav1d for native video support nbqa = "*" diff --git a/rerun_cpp/src/rerun/c/sdk_info.h b/rerun_cpp/src/rerun/c/sdk_info.h index 42c7d8982f1f..9cd639f2164a 100644 --- a/rerun_cpp/src/rerun/c/sdk_info.h +++ b/rerun_cpp/src/rerun/c/sdk_info.h @@ -2,13 +2,13 @@ /// /// This should match the string returned by `rr_version_string` (C) or `rerun::version_string` (C++). /// If not, the SDK's binary and the C header are out of sync. -#define RERUN_SDK_HEADER_VERSION "0.27.0-alpha.8+dev" +#define RERUN_SDK_HEADER_VERSION "0.28.0-alpha.1+dev" /// Major version of the Rerun C SDK. #define RERUN_SDK_HEADER_VERSION_MAJOR 0 /// Minor version of the Rerun C SDK. -#define RERUN_SDK_HEADER_VERSION_MINOR 27 +#define RERUN_SDK_HEADER_VERSION_MINOR 28 /// Patch version of the Rerun C SDK. #define RERUN_SDK_HEADER_VERSION_PATCH 0 diff --git a/rerun_js/web-viewer-react/README.md b/rerun_js/web-viewer-react/README.md index f1a5143d6eb3..d1ff837406ab 100644 --- a/rerun_js/web-viewer-react/README.md +++ b/rerun_js/web-viewer-react/README.md @@ -35,7 +35,7 @@ export default function App() { ``` The `rrd` in the snippet above should be a URL pointing to either: -- A hosted `.rrd` file, such as +- A hosted `.rrd` file, such as - A gRPC connection to the SDK opened via the [`serve`](https://www.rerun.io/docs/reference/sdk/operating-modes#serve) API If `rrd` is not set, the Viewer will display the same welcome screen as . diff --git a/rerun_js/web-viewer-react/package.json b/rerun_js/web-viewer-react/package.json index 7d0e5c2472ab..fa9bff61d6fe 100644 --- a/rerun_js/web-viewer-react/package.json +++ b/rerun_js/web-viewer-react/package.json @@ -1,6 +1,6 @@ { "name": "@rerun-io/web-viewer-react", - "version": "0.27.0-alpha.8+dev", + "version": "0.28.0-alpha.1+dev", "description": "Embed the Rerun web viewer in your React app", "licenses": [ { @@ -43,7 +43,7 @@ "tsconfig.json" ], "dependencies": { - "@rerun-io/web-viewer": "0.27.0-alpha.8" + "@rerun-io/web-viewer": "0.28.0-alpha.1" }, "peerDependencies": { "@types/react": "^18.2.33 || ^19.0.0", diff --git a/rerun_js/web-viewer/README.md b/rerun_js/web-viewer/README.md index da5703fd8b8a..1362b31246cc 100644 --- a/rerun_js/web-viewer/README.md +++ b/rerun_js/web-viewer/README.md @@ -28,7 +28,7 @@ This means that: ## Usage -The entrypoint for this packages is the [`WebViewer`](https://ref.rerun.io/docs/js/0.26.0/web-viewer/classes/WebViewer.html) class. +The entrypoint for this packages is the [`WebViewer`](https://ref.rerun.io/docs/js/0.27.1/web-viewer/classes/WebViewer.html) class. The web viewer is an object which manages a canvas element: ```js @@ -44,7 +44,7 @@ viewer.stop(); ``` The `rrd` in the snippet above should be a URL pointing to either: -- A hosted `.rrd` file, such as +- A hosted `.rrd` file, such as - A gRPC connection to the SDK opened via the [`serve`](https://www.rerun.io/docs/reference/sdk/operating-modes#serve) API If `rrd` is not set, the Viewer will display the same welcome screen as . diff --git a/rerun_js/web-viewer/index.ts b/rerun_js/web-viewer/index.ts index 82c390a64e3f..5d1f695b6ece 100644 --- a/rerun_js/web-viewer/index.ts +++ b/rerun_js/web-viewer/index.ts @@ -309,7 +309,7 @@ function delay(ms: number) { * ``` * * Data may be provided to the Viewer as: - * - An HTTP file URL, e.g. `viewer.start("https://app.rerun.io/version/0.27.0-alpha.7/examples/dna.rrd")` + * - An HTTP file URL, e.g. `viewer.start("https://app.rerun.io/version/0.27.1/examples/dna.rrd")` * - A Rerun gRPC URL, e.g. `viewer.start("rerun+http://127.0.0.1:9876/proxy")` * - A stream of log messages, via {@link WebViewer.open_channel}. * diff --git a/rerun_js/web-viewer/package.json b/rerun_js/web-viewer/package.json index 206882341131..8dc1d4d6f61f 100644 --- a/rerun_js/web-viewer/package.json +++ b/rerun_js/web-viewer/package.json @@ -1,6 +1,6 @@ { "name": "@rerun-io/web-viewer", - "version": "0.27.0-alpha.8+dev", + "version": "0.28.0-alpha.1+dev", "description": "Embed the Rerun web viewer in your app", "licenses": [ { diff --git a/rerun_notebook/pyproject.toml b/rerun_notebook/pyproject.toml index df7f13a6a2a2..2c561209cc24 100644 --- a/rerun_notebook/pyproject.toml +++ b/rerun_notebook/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "hatchling.build" [project] name = "rerun-notebook" description = "Implementation helper for running rerun-sdk in notebooks" -version = "0.27.0-alpha.8+dev" +version = "0.28.0-alpha.1+dev" dependencies = [ "anywidget", "jupyter-ui-poll", diff --git a/rerun_py/docs/gen_common_index.py b/rerun_py/docs/gen_common_index.py index f2f9aeb810d3..e35904d66e60 100755 --- a/rerun_py/docs/gen_common_index.py +++ b/rerun_py/docs/gen_common_index.py @@ -522,7 +522,7 @@ def make_slug(s: str) -> str: | **Rerun Version** | **Release Date** | **Supported Python Version** | |-------------------|------------------|------------------------------| -| 0.27 | Nov. 2025 (est.) | 3.10+ | +| 0.27 | Nov. 10, 2025 | 3.10+ | | 0.26 | Oct. 13, 2025 | 3.9+ | | 0.25 | Sep. 16, 2025 | 3.9+ | | 0.24 | Jul. 17, 2025 | 3.9+ | diff --git a/rerun_py/pyproject.toml b/rerun_py/pyproject.toml index eec2b95caa96..a72019fb35b7 100644 --- a/rerun_py/pyproject.toml +++ b/rerun_py/pyproject.toml @@ -36,7 +36,7 @@ text = "MIT OR Apache-2.0" [project.optional-dependencies] tests = ["pytest==8.4.2", "syrupy==5.0.0"] -notebook = ["rerun-notebook==0.27.0-alpha.8+dev"] +notebook = ["rerun-notebook==0.28.0-alpha.1+dev"] datafusion = ["datafusion==50.1.0"] all = ["rerun-sdk[notebook]", "rerun-sdk[datafusion]"] diff --git a/rerun_py/rerun_sdk/rerun/__init__.py b/rerun_py/rerun_sdk/rerun/__init__.py index 5934e692e2d6..8c8485b4b3e5 100644 --- a/rerun_py/rerun_sdk/rerun/__init__.py +++ b/rerun_py/rerun_sdk/rerun/__init__.py @@ -9,8 +9,8 @@ import numpy as np -__version__ = "0.27.0-alpha.8+dev" -__version_info__ = (0, 27, 0, "alpha.8") +__version__ = "0.28.0-alpha.1+dev" +__version_info__ = (0, 28, 0, "alpha.1") if sys.version_info < (3, 10): # noqa: UP036 raise RuntimeError("Rerun SDK requires Python 3.10 or later.") diff --git a/scripts/ci/wheel_utils.py b/scripts/ci/wheel_utils.py index b532eeabed75..b891786eb0d0 100644 --- a/scripts/ci/wheel_utils.py +++ b/scripts/ci/wheel_utils.py @@ -2,13 +2,11 @@ def check_expected_wheels(wheels: list[str]) -> None: - missing = {"windows", "macos_intel", "macos_arm", "linux"} + missing = {"windows", "macos_arm", "linux"} for wheel in wheels: if "win_amd64" in wheel: missing.remove("windows") - if "macosx" in wheel and "x86_64" in wheel: - missing.remove("macos_intel") if "macosx" in wheel and "arm64" in wheel: missing.remove("macos_arm") if "manylinux" in wheel and "x86_64" in wheel: diff --git a/tests/rust/re_integration_test/tests/re_integration.rs b/tests/rust/re_integration_test/tests/re_integration.rs index 49686d33bdb6..76b6224571de 100644 --- a/tests/rust/re_integration_test/tests/re_integration.rs +++ b/tests/rust/re_integration_test/tests/re_integration.rs @@ -38,12 +38,21 @@ pub async fn dataset_ui_test() { viewer_test_utils::step_until( "Redap server dataset appears", &mut harness, - |harness| harness.query_by_label_contains("my_dataset").is_some(), + // The label eventually appears twice: first in the left panel, and in the entries table + // when it refreshes. Here we wait for both to appear. Later we pick the first one (in the + // left panel). + |harness| harness.query_all_by_label_contains("my_dataset").count() == 2, Duration::from_millis(100), Duration::from_secs(5), ); - harness.get_by_label("my_dataset").click(); + // We pick the first one. + harness + .get_all_by_label("my_dataset") + .next() + .unwrap() + .click(); + viewer_test_utils::step_until( "Redap recording id appears", &mut harness,