Optimized camera controls for That Open Components viewers with instant response and intelligent proximity-based speed adjustment.
- Instant Response - Direct camera movement, no animation delays
- Proximity-Based Speed - Automatically slows near objects, speeds up far away
- Smart Orbit Point - Automatically sets orbit center based on what you click
- Auto Orbit Update - Fixes truck movement slowdown when zoomed out
- Touch Support - Full mobile device support
- Keyboard Modifiers - Shift for 3x speed, Ctrl/Alt for 10x precision
- Highly Configurable - Customize all speed zones and behaviors
- Performance Optimized - Throttled raycasting, cached values, non-blocking operations
Copy smoothWheelControl.ts and mouseOrbitControl.ts into your project.
Dependencies:
npm install @thatopen/components @thatopen/components-front threeFor React/TypeScript projects:
npm install -D @types/reactimport * as OBC from '@thatopen/components'
import { createSmoothWheelControl } from './smoothWheelControl'
import { createMouseOrbitControl } from './mouseOrbitControl'
// Setup your That Open Components world
const world = /* your OBC.World */
const components = /* your OBC.Components */
const containerRef = /* React.RefObject or HTMLDivElement */
// Create controls
const smoothWheel = createSmoothWheelControl(world, components, containerRef)
const mouseOrbit = createMouseOrbitControl(world, components)
// Add event listeners
containerRef.current.addEventListener('wheel', smoothWheel.wheelHandler, { passive: false })
containerRef.current.addEventListener('mousedown', mouseOrbit.mouseDownHandler, true)
containerRef.current.addEventListener('mousemove', mouseOrbit.mouseMoveHandler, true)
containerRef.current.addEventListener('touchstart', mouseOrbit.touchStartHandler, true)
// Cleanup on unmount
smoothWheel.cleanup()createSmoothWheelControl(world, components, containerRef, {
shiftBoost: 3, // Shift key multiplier (3x faster)
fineModifier: 0.1, // Ctrl/Alt precision multiplier (10x slower)
fragmentUpdateDelay: 300, // Fragment update delay (ms)
enableSmoothing: true, // Smooth camera movement interpolation
proximitySlowdown: true, // Enable distance-based speed adjustment
proximitySlowDistance: 1.0, // Distance (units) where speed is minimum
proximityNormalDistance: 10.0, // Distance where speed is normal (1x)
proximityFastDistance: 80.0, // Distance where speed reaches maximum
proximityMinSpeed: 0.2, // Min speed multiplier when close (20%)
proximityMaxSpeed: 10.0 // Max speed multiplier when far (1000%)
})import { DOLLY_STEP_REF } from './smoothWheelControl'
DOLLY_STEP_REF.value = 1.0 // Double speed
DOLLY_STEP_REF.value = 0.25 // Quarter speed| Action | Effect |
|---|---|
| Mouse wheel | Instant zoom towards cursor |
| Shift + Wheel | 3x faster zoom |
| Ctrl/Alt + Wheel | 10x slower (precision) |
| Click + Drag | Rotate around clicked point |
| Touch + Drag | Rotate around touched point |
The proximity system creates intuitive speed zones:
Speed Multiplier
10.0x | _________________ (80m+)
| /
6.0x | /
| /
1.0x |_________(10m)________/
| /
0.6x | /
| /
0.2x |____/ (0-1m)
|_____|_____|_____|_____|_____|_____|_____|
0 20 40 60 80 100 120 140m (distance)
- 0-1m: Slows to 20%-100% for precision near objects
- 1-10m: Normal speed 100%
- 10-80m: Speeds up 100%-1000% for large scenes
- 80m+: Maximum speed 1000%
Uses THREE.MathUtils.lerp for smooth transitions between zones.
- Instant camera movement on wheel scroll
- Throttled raycasting (100ms interval) - only when stationary
- Cached speed factor - uses last known value during movement
- Auto orbit point update - fixes truck slowdown when zoomed out
- Cached THREE.js objects (Vector3, Vector2, Raycaster) for zero allocations
- Configurable speed modifiers (Shift, Ctrl/Alt)
- Fragment update optimization with delayed final raycast (50ms)
- OBC raycast-based orbit point selection (mouse, touch, programmatic)
- Non-blocking raycasting - uses promise chain instead of async/await
- Drag threshold to prevent accidental triggers on clicks
- Full touch device support
- Async raycasting for all operations
- Manual orbit point utility function
- Raycasts only execute every 100ms and only when stationary
- During fast scrolling, uses cached speed factor from last raycast
- Final raycast performed 50ms after movement stops for accuracy
mouseDownHandleruses promise chain (.then()/.catch()) instead ofasync/await- Prevents blocking the main thread during mouse interactions
- UI remains responsive even with heavy raycasting
- Automatically updates orbit point when raycasting objects
- Fixes truck (pan) movement slowdown when camera is far from orbit point
- camera-controls library scales truck speed based on orbit distance
- All THREE.js objects (Vector3, Vector2, Raycaster) cached and reused
- Zero allocations per frame during movement
- Cleanup function properly clears all timeouts
- IFC/BIM model viewers
- Architectural visualization
- 3D product configurators
- CAD model viewers
- Any That Open Components application
See TUTORIAL.md for:
- Step-by-step setup guide
- Complete React component example
- Parameter customization
- Performance tips
- Troubleshooting
MIT License - use freely in your projects!
Built for That Open Components by That Open Company.