Skip to content

Add distance measurement, rescaling, and coordinate recenter#281

Open
MasahiroOgawa wants to merge 35 commits intosparkjsdev:mainfrom
sensyn-robotics:feature/recenter_coordinate
Open

Add distance measurement, rescaling, and coordinate recenter#281
MasahiroOgawa wants to merge 35 commits intosparkjsdev:mainfrom
sensyn-robotics:feature/recenter_coordinate

Conversation

@MasahiroOgawa
Copy link

Summary

  • Add interactive distance measurement and rescaling example for 3D Gaussian Splatting models
  • Enable orbit origin recentering via right double-click for better navigation
  • Enable infinite vertical rotation in OrbitControls
  • Add PlyWriter for exporting rescaled point clouds
  • Add comprehensive documentation (English + Japanese)

Features

Distance Measurement & Rescale

Place two markers on a 3DGS model to measure distance, enter a known real-world distance, and rescale the model accordingly. Supports PLY export of rescaled models.

Coordinate Recenter

Right double-click any point on the model to move the orbit center there, enabling intuitive navigation around areas of interest.

Infinite Rotation

Removes polar angle limits on OrbitControls for full spherical orbit capability.

PlyWriter

New utility class to export point cloud data as PLY files, with comprehensive unit tests.

Files changed

  • examples/distance-rescale/ — interactive example (HTML + JS)
  • examples/js/orbit-controls-utils.js — shared orbit control utilities
  • src/PlyWriter.ts — PLY file writer with export in src/index.ts
  • test/PlyWriter.test.ts — unit tests for PlyWriter
  • docs/ — usage guides in English and Japanese
  • mkdocs.yml, examples.html, index.html — navigation updates
  • lefthook.yml — add detect-secrets pre-commit hook

Test plan

  • Verify distance-rescale example loads and measures correctly
  • Verify right double-click recenters the orbit origin
  • Verify infinite vertical rotation works smoothly
  • Run npm test — PlyWriter unit tests pass

🤖 Generated with Claude Code

MasahiroOgawa and others added 30 commits December 25, 2025 13:42
- Add PlyWriter class to export PackedSplats to standard PLY format
- Add distance-rescale example with interactive point selection
- Support ray-based point selection with visible ray lines
- Allow dragging points along ray lines to adjust depth
- Implement model rescaling based on measured vs desired distance
- Export rescaled models as PLY files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add PlyWriter class to export PackedSplats to standard PLY format
- Add distance-rescale example with interactive point selection
- Support ray-based point selection with visible ray lines
- Allow dragging points along ray lines to adjust depth
- Implement model rescaling based on measured vs desired distance
- Export rescaled models as PLY files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Switch from SparkControls to OrbitControls for reliability
- Auto-center camera on model using getBoundingBox
- Dynamic marker/ray sizing based on model dimensions
- Change newDistance to text input (was slider limited to 0.001-100)
- Add proper rotation.x = Math.PI for PLY orientation
- Improve error handling and add debug logging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Increase marker radius from 0.5% to 2% of model size
- Add white ring outline around markers for contrast
- Ring billboards to always face camera
- Markers now visible against any background

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove overly restrictive minT clamping (was markerRadius*5, now 0.01)
- Allow movement beyond visible ray line (maxT = rayLineLength * 2)
- Keep current point when rays are parallel instead of jumping
- Pass current point to closestPointOnRay for better fallback behavior

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The markers are now THREE.Group (sphere + ring), so intersectObjects
returns child meshes, not the group. Walk up the parent chain to find
which marker group was actually hit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove world-space marker sizing (markerRadius)
- Add MARKER_SCREEN_SIZE constant (3% of screen height)
- Scale markers dynamically based on camera distance in render loop
- Markers now stay same visual size when zooming in/out

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add explicit else-if check for point2 in drag handler for safety
- Add disposeObject helper to properly dispose Three.js geometries/materials
- Prevent memory leaks when resetting selection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 15 comprehensive unit tests for PlyWriter:
  - Constructor with default/custom options
  - PLY header generation validation
  - Binary data size verification
  - Position, scale, quaternion encoding
  - Log scale encoding with zero fallback
  - Sigmoid opacity encoding with edge case clamping
  - Color DC coefficient encoding
  - Empty splats handling
  - Big endian format support
  - Multiple splats ordering

- Fix bug: replace() only replaced first underscore in format string
  Changed to replaceAll() for proper "binary little endian" output

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PLY reader expects "binary_little_endian" with underscores, not spaces.
This was causing exported PLY files to fail to load (appearing all black).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add GitHub Actions workflow for automated deployment
- Add staticwebapp.config.json for SWA configuration
- Update rename-assets-to-static.js to copy SWA config to site output

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
on-behalf-of: @Azure opensource@microsoft.com
- Update workflow to use AZURE_STATIC_WEB_APPS_API_TOKEN_NICE_MEADOW_018297C00
- Remove Azure auto-generated workflow (missing build steps)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use --ignore-scripts for npm ci to skip prepare script
- Add skip_api_build: true to prevent API build attempts
- Set output_location to empty for pre-built content
- Add conditional WASM build step

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Pre-built WASM files are already in the repo.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove gitignore and commit pre-built spark-internal-rs WASM files
so CI can build without Rust toolchain.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The example folder existed but wasn't listed in examples.html.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Configure lefthook to run detect-secrets before commits to prevent
accidentally pushing sensitive information like API keys, tokens, or passwords.

- Uses baseline file from global hooks: ~/.config/git/hooks/.secrets.baseline
- Gracefully handles case where detect-secrets is not installed
- Runs alongside existing lint and test jobs

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove polar angle limits to allow infinite vertical (up/down) rotation,
not just horizontal rotation.

Before: Vertical rotation limited to 180° (0 to π)
After: Vertical rotation unlimited (can rotate continuously)

This allows users to spin the model infinitely in all directions.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fix issues with coordinate origin transform and measurement points:

1. **Change to right double-click for origin transform**
   - Left double-click was conflicting with measurement point placement
   - Now: Right double-click to set coordinate origin
   - Prevents context menu with contextmenu event handler

2. **Fix measurement point placement**
   - Only left clicks place measurement points (was both left and right)
   - Right clicks no longer duplicate left click behavior

3. **Update all instructions for clarity**
   - Initial: 'Left-click to measure distance | Right double-click to set origin'
   - After first point: 'Left-click to select second measurement point'
   - After complete: 'Drag markers to adjust | Right double-click to set origin'
   - After origin set: 'Origin set! Left-click to measure | Right double-click for new origin'

This provides a clear separation between measurement (left click) and
origin transform (right double-click) functions.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Two major fixes to address user-reported issues:

1. **Fix right double-click for origin transform**
   - dblclick event doesn't reliably capture button property
   - Implement manual right-click timing detection
   - Track mousedown events with 300ms threshold
   - Position tolerance of 10px for double-click detection
   - Now works reliably for setting coordinate origin

2. **Enable true infinite vertical rotation**
   - Switch from OrbitControls to TrackballControls
   - OrbitControls has built-in gimbal lock prevention (limits polar angle)
   - TrackballControls allows full 360° rotation in ALL directions
   - No azimuth/polar angle restrictions
   - Smooth damping with dynamicDampingFactor = 0.15
   - Remove controls.target references (TrackballControls don't have target)
   - Add controls.handleResize() for proper window resizing

TrackballControls differences from OrbitControls:
- No 'target' property (uses camera lookAt)
- No gimbal lock - truly infinite rotation
- Different feel: can rotate past vertical axis
- Update required in render loop

This provides the requested functionality:
- Right double-click to set origin (separated from measurement)
- Infinite rotation in both horizontal AND vertical directions

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Use mouseup instead of mousedown for better event handling
- Add drag detection to distinguish clicks from drags
- Stop event propagation to prevent TrackballControls interference
- Fix axes helper to stay at world origin (0,0,0)
- Add extensive debug logging to track transformation
- Add event capture to ensure handlers run before TrackballControls
- Set staticMoving=true to disable smooth damping (improves performance)
- Reduce zoomSpeed from 1.2 to 0.8 for better control
- Add minDistance=0.5 to prevent zooming too close (causes slowness)
- Add maxDistance=50 to limit zoom range
- Add more debug logging for right-click events
The bug: Vector3.toFixed() doesn't exist - toFixed() is a Number method
Fix: Access individual x, y, z properties and format each coordinate

This was preventing the entire transformOriginTo function from running,
causing right double-click to silently fail.
Removed emoji-based debug console.log statements that were added
during development:
- transformOriginTo: Removed verbose transformation logs
- Right-click handlers: Removed mousedown/mouseup/detection logs

Kept only essential warning messages (e.g., 'No model loaded').
MasahiroOgawa and others added 5 commits March 4, 2026 13:27
- Create English guide: distance-rescale-guide.md
- Update Japanese guide: distance-rescale-guide-ja.md
- Add guides to mkdocs.yml navigation

New features documented:
- Three file loading methods (button, drag & drop, default)
- Toggle coordinate axes visualization
- Right double-click to set new origin
- Infinite camera rotation in all directions
- Zoom performance limits
- Updated UI layout (lil-gui top-right)

Both guides include:
- Complete usage instructions
- Control reference table
- UI layout description
- Tips and notes
Replace sparkjs.dev URL with correct Azure Static Web Apps deployment URL.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use disposeObject() helper for AxesHelper instead of non-existent dispose()
- Add e.target check in dragleave to prevent flicker from child elements
- Add file extension validation (.ply, .spz, .splat) for drag-and-drop

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove files that are specific to the sensyn-robotics fork's Azure
hosting and should not be submitted upstream:
- Azure Static Web Apps workflow and config
- Pre-built WASM package (for Azure CI)
- Azure config copy in rename-assets script
- Restore upstream README content

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add npm overrides to force patched minimatch versions:
- minimatch <3.1.3 → 3.1.3 (via @microsoft/api-extractor)
- minimatch >=9.0.0 <9.0.7 → 9.0.7 (via @vue/language-core)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dmarcos
Copy link
Contributor

dmarcos commented Mar 7, 2026

What’s the use case / need that is driving this?

@dmarcos
Copy link
Contributor

dmarcos commented Mar 7, 2026

I saw you submitted a similar PR in the past. I still think this should be kept as a 3rd party enhancement. You have a cool example / demo / code you can post on X? Happy to give it flexibility.

The idea is that each spark example features one specific feature of the renderer. For more complex use cases applications, demos is better to keep them separate so spark core staystight and simple.

@MasahiroOgawa
Copy link
Author

This is for moviing around inside large 3DGS scene.
It can rotate around new center.
But OK, I see, you seems not need these updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants