Minor Changes
-
9264ebb: Unify the coordinate frame: the Three.js scene is now Rhino's frame (Z-up), end to end.
Previously the display pipeline rotated Rhino Z-up geometry into Three's native Y-up
((x, y, z) → (x, z, −y)) during mesh decompression and display-item parsing. That hidden
rotation meant every feature producing or consuming positions — measurements, mesh metadata,
label anchors, picking, the new camera presets/grid — had to round-trip through it or silently
land in the wrong frame.The rotation is removed everywhere. A Rhino point
(x, y, z)is now the Three point(x, y, z):rhinoToThreeis the identity (kept, deprecated, for call-site compatibility).- The int16/float32 vertex paths in
webdisplay/batch-parser.tspass vertices through unrotated. initThreeorients the camera, default iso position, sunlight, floor, and reference grid to the
scene up axis (Z-up by default); the camera controller's presets are likewise up-derived.
Breaking: any consumer that assumed viewer geometry was Y-up (e.g. reading mesh vertex
positions, placing objects, or computing directions in Three space) must drop the
(x, z, −y)conversion — Three space now equals Rhino space. TheapplyTransformsoption is
retained but no longer rotates; it will be removed in a future release. -
9264ebb: Release v2.1.0: Z-up coordinate frame, measurement tool, and CAD viewer tooling.
Coordinate frame unification (breaking)
The Three.js scene is now Z-up end-to-end, matching Rhino's native frame. The hidden
(x, y, z) → (x, z, −y)rotation that was applied during mesh decompression and display-item parsing is removed.rhinoToThreeis kept as an identity for call-site compatibility but deprecated. Consumers that read mesh vertex positions or place objects in Three space must drop any(x, z, −y)conversion — Three space now equals Rhino space.CAD viewer tooling — public exports
The camera controller, reference grid, view gizmo, edge overlays, label layer, and measurement tool are now exported from the public
visualizationentry point. Previously their factories and types were only available internally. New exports includecreateCameraController,createGrid,createViewGizmo,addEdges/removeEdges,createLabelLayer,createMeasureTool/snapToVertex, and all associated config/option types (GridConfig,GizmoConfig,EdgesConfig,MeasureConfig,ViewPreset,CameraProjection, …). Additive only — no existing export changed.Measurement tool improvements
- Snapping extended to lines and points:
snapToVertexsnaps to the nearer endpoint of a struck segment and to the struck vertex on point objects. Raycast thresholds for lines and points are scaled by view distance so thin geometry is actually clickable at any zoom. - Cursor preview: a ghost marker follows the cursor and jumps to the snap vertex before a click commits it.
- Drag-to-orbit no longer disturbs a measurement — clicks that follow a drag past the slop threshold are ignored.
- Labels now show per-axis deltas (
Δx/Δy/Δz) alongside the total distance. Theformatcallback is widened to(distance, delta) => string; existing(distance) => stringcallbacks remain valid. - Labels ship with a default dark-pill style so they are legible on any background. Pass
labelClassNameto opt out.
Camera, grid, and label layer fixes
initThreesetscamera.upbefore constructing OrbitControls so preset views (top/front/…) and orbit behavior are correct for Z-up scenes.- The grid's default plane is derived from the scene up axis (Z-up →
plane: 'z'); an explicitplanestill takes precedence. clearScenepreserves the persistentfloor,grid, andlabel-layergroups across content updates, fixing measurement labels disappearing in streaming viewers (e.g. per Grasshopper solve).- The CSS2D label overlay gets an explicit
z-indexso labels stack above container scrims while staying below menus and popovers.
- Snapping extended to lines and points:
-
9264ebb: Export the CAD viewer tooling from the public
visualizationentry point.The camera controller, reference grid, view gizmo, edge overlays, label layer, and
measurement tool shipped in 2.1.0-beta.1 were wired throughinitThreeat runtime, but
their factories and types were only re-exported from the internal
features/visualization/index.tsbarrel — not fromsrc/visualization.ts, the actual
published entry. Consumers could enable the tools via options and read them off the
initThreereturn, but could not import the supporting type names
(CameraController,MeasureTool,ViewPreset,CameraProjection, …) or the
config types (GridConfig,GizmoConfig,EdgesConfig,MeasureConfig).- Re-export
createCameraController,createGrid,createViewGizmo,addEdges/removeEdges/isEdgeOverlay,createRenderPipeline,createLabelLayer,createMeasureTool/snapToVertexand their types fromvisualization. - Re-export the
GridConfig/GizmoConfig/EdgesConfig/MeasureConfigoption types. - Also surface
parseColor,applyOffset, andcomputeCombinedBoundingBoxfromthree-helpers.
Additive only — no existing export changed.
- Re-export
Patch Changes
-
9264ebb: Fix measurement/dimension labels never appearing in viewers that stream new content (e.g. per
Grasshopper solve).updateScene/clearSceneremoved every top-level scene child except the floor on each update,
which detached the persistent CSS2Dlabel-layergroup. Labels added afterwards were parented to
an orphaned group, so the CSS2D renderer (which walks the live scene) never injected their DOM.
clearScenenow preserves persistent infrastructure —floor,grid, andlabel-layer— across
content updates. Demos that add geometry directly (never callingupdateScene) were unaffected,
which is why the label only went missing in consumer apps.- The CSS2D label overlay also gets an explicit
z-indexso it stacks above container scrims (e.g.
blur/loading overlays) that previously painted over it, while staying below menu/popover layers.
-
9264ebb: Extend the measurement tool to lines and points, not just meshes.
snapToVertexnow snaps line hits to the nearer endpoint of the struck segment and point hits to
the struck vertex, in addition to the existing mesh triangle-vertex snapping. Hits without usable
vertex indices (e.g. fatLine2) still fall back to the raw point.- Line and Points raycast thresholds are raised per-pick, scaled by the view distance, so thin lines
and points are actually clickable at any zoom instead of being nearly impossible to hit with the
default ~1-unit threshold.
-
9264ebb: Make the measurement tool easier to read and aim, and report per-axis deltas.
- Distance labels now carry a default style (dark translucent pill, light text) so they stay
legible on any background instead of inheriting the page color (previously invisible white-on-white).
PassinglabelClassNamestill opts out of all default styling. - The tool previews the snap point: a ghost marker follows the cursor and jumps to the vertex a
click would lock onto, so you can aim before committing.MeasureToolgainshandleMove(event),
whichinitThreewires to canvasmousemove. - Orbiting/panning no longer disturbs a measurement: the
clicka drag fires on release is ignored
(pointer moved past a small slop threshold), so in-progress points and finished measurements survive
rotation instead of being cleared or mis-placed. - The default label now shows the per-axis breakdown (
Δx/Δy/Δz) under the total distance. The
formatcallback signature widens to(distance, delta) => string; existing(distance) => string
callbacks remain valid.
- Distance labels now carry a default style (dark translucent pill, light text) so they stay
-
9264ebb: Make the viewer's camera controller, presets, and grid respect the scene up axis.
The CAD tooling assumed Three's native Y-up, but Selva scenes are Z-up.
initThreeset
scene.upto Z yet never setcamera.up, so OrbitControls orbited as if Y-up and the
preset views (top/front/…) framed the wrong faces; the grid also defaulted to the
horizontal Y-up plane.initThreenow setscamera.upto the configuredsceneUpbefore constructing
OrbitControls and the camera controller (both capture the orbit/preset basis from up).- The camera controller derives its preset view directions, iso angle, and orthographic
camera up from the up axis instead of a hardcoded Y-up table, via a new optionalup
dependency (defaults to the perspective camera's up). - The grid's default plane is derived from the up axis (Z-up →
plane: 'z'), so the grid
lies under the model without callers passingplaneexplicitly. An explicitplane
still wins.
No API changes; behavior is corrected for non-Y-up scenes and unchanged for Y-up.