Conventions and patterns for developing polyscope-rs.
cargo build # Build all crates
cargo build --release # Release mode
cargo test # Run tests
cargo check # Check without building
cargo fmt # Format code
cargo clippy # LintRust edition 2024, MSRV 1.85.
crates/
├── polyscope-core/ # Core traits, registry, state management
├── polyscope-render/ # wgpu rendering backend
├── polyscope-ui/ # egui UI integration
├── polyscope-structures/ # Structure implementations
└── polyscope/ # Main crate, re-exports all sub-crates
- Create module in
polyscope-structures/src/ - Implement
Structuretrait (withas_any,as_any_mut,bounding_box,length_scale,transform, etc.) - Implement
HasQuantitiesif it supports quantities - Add registration function in main
polyscopecrate - Add GPU init/draw/pick code in
polyscope/src/app/render.rs - Add UI in
polyscope-ui/src/structure_ui.rs - Add tests
- Implement
Quantitytrait (withname,kind,is_enabled,set_enabled,as_any,as_any_mut,refresh) - Add marker trait if needed (
VertexQuantity,FaceQuantity, etc.) - Add GPU rendering fields:
render_data,init_gpu_resources(),update_uniforms(),render_data() - Add active accessor on parent structure (e.g.,
active_vertex_vector_quantity()) - Add
auto_scale()call in the structure's registration method - Add init/update/draw code in
polyscope/src/app/render.rs - Add convenience method on parent structure (e.g.,
mesh.add_vector_quantity(...)) - Add UI controls in
polyscope-ui
GPU data from structure geometry must be transformed by the model matrix. When adding new rendered quantities:
- Include
model: mat4x4<f32>in shader uniform struct - Apply in vertex shader: positions (w=1), directions (w=0)
- Pass
structure.transform()every frame viaupdate_uniforms() - Never assume GPU-baked positions are in world space — they are local/object space
Failure to do this causes quantities to stay frozen when the user moves/rotates the structure via gizmos.
All shaders are WGSL (WebGPU Shading Language). No geometry shader support in wgpu — use compute shaders and instancing instead.
- Group 0: Per-object uniforms (model matrix, colors, parameters)
- Group 1: Slice planes / reflection uniforms
- Group 2: Matcap textures (4-channel blend or single-texture)
All scene shaders call light_surface_matcap(view_normal, base_color) via Group 2 for consistent lighting.
Always set explicit min_binding_size (via NonZeroU64) rather than None. This works around wgpu Issue #7359 where late validation can cross-contaminate between pipelines.
WGSL alignment caveat: vec3<T> aligns to 16 bytes, not 12. Padding fields must use scalar types (e.g., _pad0: u32) rather than vec3<u32> to match Rust #[repr(C)] struct sizes.
For label+widget rows (sliders, drag values, color pickers), always use egui::Grid with 2 columns instead of ui.horizontal + ui.add_sized. Grid auto-sizes the label column and left-aligns labels. For buttons, ui.add_sized with a fixed width is fine.
Global state is managed via OnceLock<RwLock<Context>>:
with_context(|ctx| ...)— Read accesswith_context_mut(|ctx| ...)— Write access
The render loop in app/render.rs follows this order:
- Shadow map pass
- Slice plane visualization
- Ground plane (with shadows/reflections)
- Depth prepass
- Main geometry pass (points, curves, vectors)
- Surface mesh pass
- Depth peel transparency (multi-pass)
- SSAO
- Tone mapping
- egui overlay
// C++ Polyscope
polyscope::PointCloud* pc = polyscope::registerPointCloud("my points", points);
pc->addScalarQuantity("height", heights);
pc->setPointRadius(0.01);// polyscope-rs
register_point_cloud("my points", points);
with_point_cloud("my points", |pc| {
pc.add_scalar_quantity("height", heights);
pc.set_point_radius(0.01);
});- Pointers to handles: C++ uses raw pointers; Rust uses handle structs or closure-based
with_*access - Error handling: C++ exceptions → Rust
Result<T, E> - Vector types:
glm::vec3→glam::Vec3 - Face format: polyscope-rs accepts
UVec3(triangles),[u32; 3], orVec<Vec<u32>>(polygons) viaIntoFaceList - Initialization:
init()returnsResult, use?orunwrap() - Thread safety: Global state uses
RwLock
- Local C++ Polyscope source:
~/repo/polyscope— check for implementation details - C++ Polyscope repo: https://github.com/nmwsharp/polyscope
- Polyscope docs: https://polyscope.run
- Design document:
docs/plans/2026-01-21-polyscope-rs-design.md