Camera state persistence, serialization, restoration, and accessor functionality for saving and loading camera configurations.
Save and restore camera states for later use or reset functionality.
/**
* Save current camera state as the reset point
* Stores position, target, zoom, and other camera parameters
*/
saveState(): void;
/**
* Reset camera to saved state or initial position
* @param enableTransition - Whether to animate the transition
* @returns Promise array that resolves when all movements complete
*/
reset(enableTransition?: boolean): Promise<void[]>;Usage Examples:
// Save initial camera state
cameraControls.saveState();
// Move camera around...
await cameraControls.moveTo(10, 5, 15, true);
await cameraControls.rotateTo(Math.PI / 4, Math.PI / 3, true);
// Reset to saved state with animation
await cameraControls.reset(true);
// Reset instantly
await cameraControls.reset(false);
// Save new state after positioning
await cameraControls.fitToBox(mesh, true);
cameraControls.saveState(); // New reset pointConvert camera state to/from JSON for persistence across sessions.
/**
* Serialize current camera state to JSON string
* @returns JSON string containing complete camera state
*/
toJSON(): string;
/**
* Load camera state from JSON string
* @param json - JSON string from previous toJSON() call
* @param enableTransition - Whether to animate the transition
*/
fromJSON(json: string, enableTransition?: boolean): void;Usage Examples:
// Save camera state to localStorage
const cameraState = cameraControls.toJSON();
localStorage.setItem('cameraState', cameraState);
// Load camera state from localStorage
const savedState = localStorage.getItem('cameraState');
if (savedState) {
cameraControls.fromJSON(savedState, true);
}
// Save to file or database
const stateData = {
timestamp: Date.now(),
cameraState: cameraControls.toJSON(),
sceneName: 'main-scene'
};
// Send to server
fetch('/api/save-camera-state', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(stateData)
});
// Load from server response
const response = await fetch('/api/load-camera-state');
const loadedData = await response.json();
cameraControls.fromJSON(loadedData.cameraState, true);Retrieve current camera state values for analysis or custom operations.
/**
* Get current camera target position
* @param out - Vector3 to write result to
* @param receiveEndValue - Whether to get end value of transition (true) or current value (false)
* @returns Vector3 containing target position
*/
getTarget(out: THREE.Vector3, receiveEndValue?: boolean): THREE.Vector3;
/**
* Get current camera position
* @param out - Vector3 to write result to
* @param receiveEndValue - Whether to get end value of transition (true) or current value (false)
* @returns Vector3 containing camera position
*/
getPosition(out: THREE.Vector3, receiveEndValue?: boolean): THREE.Vector3;
/**
* Get current spherical coordinates
* @param out - Spherical to write result to
* @param receiveEndValue - Whether to get end value of transition (true) or current value (false)
* @returns Spherical containing camera's spherical coordinates
*/
getSpherical(out: THREE.Spherical, receiveEndValue?: boolean): THREE.Spherical;
/**
* Get current focal offset
* @param out - Vector3 to write result to
* @param receiveEndValue - Whether to get end value of transition (true) or current value (false)
* @returns Vector3 containing focal offset
*/
getFocalOffset(out: THREE.Vector3, receiveEndValue?: boolean): THREE.Vector3;Usage Examples:
import * as THREE from 'three';
// Get current camera state
const currentPosition = new THREE.Vector3();
const currentTarget = new THREE.Vector3();
const currentSpherical = new THREE.Spherical();
cameraControls.getPosition(currentPosition);
cameraControls.getTarget(currentTarget);
cameraControls.getSpherical(currentSpherical);
console.log('Camera Position:', currentPosition);
console.log('Target Position:', currentTarget);
console.log('Spherical Coords:', {
radius: currentSpherical.radius,
phi: currentSpherical.phi,
theta: currentSpherical.theta
});
// Get end values during transition (where camera is moving to)
const endPosition = new THREE.Vector3();
const endTarget = new THREE.Vector3();
cameraControls.getPosition(endPosition, true); // End position
cameraControls.getTarget(endTarget, true); // End target
// Calculate distance between current and end positions
const distance = currentPosition.distanceTo(endPosition);
console.log('Remaining distance to travel:', distance);State Comparison and Validation:
// Compare two camera states
function compareCameraStates(state1: string, state2: string): boolean {
try {
const parsed1 = JSON.parse(state1);
const parsed2 = JSON.parse(state2);
// Compare key properties (simplified)
return (
parsed1.target && parsed2.target &&
parsed1.position && parsed2.position &&
Math.abs(parsed1.target.x - parsed2.target.x) < 0.001 &&
Math.abs(parsed1.target.y - parsed2.target.y) < 0.001 &&
Math.abs(parsed1.target.z - parsed2.target.z) < 0.001
);
} catch {
return false;
}
}
// Validate state before loading
function isValidCameraState(json: string): boolean {
try {
const state = JSON.parse(json);
return state && typeof state === 'object' &&
state.target && state.position;
} catch {
return false;
}
}
// Safe state loading
const savedState = localStorage.getItem('cameraState');
if (savedState && isValidCameraState(savedState)) {
cameraControls.fromJSON(savedState, true);
}Multiple State Management:
// State manager class for multiple camera states
class CameraStateManager {
private states = new Map<string, string>();
saveState(name: string, controls: CameraControls): void {
this.states.set(name, controls.toJSON());
}
loadState(name: string, controls: CameraControls, animate = true): boolean {
const state = this.states.get(name);
if (state) {
controls.fromJSON(state, animate);
return true;
}
return false;
}
deleteState(name: string): boolean {
return this.states.delete(name);
}
listStates(): string[] {
return Array.from(this.states.keys());
}
}
// Usage
const stateManager = new CameraStateManager();
// Save named states
stateManager.saveState('overview', cameraControls);
stateManager.saveState('closeup', cameraControls);
stateManager.saveState('top-view', cameraControls);
// Load specific state
stateManager.loadState('overview', cameraControls, true);Transition Monitoring:
// Monitor state changes during transitions
function monitorTransition() {
const startPosition = new THREE.Vector3();
const currentPosition = new THREE.Vector3();
const endPosition = new THREE.Vector3();
cameraControls.getPosition(startPosition, false); // Current
cameraControls.getPosition(endPosition, true); // Target
const interval = setInterval(() => {
cameraControls.getPosition(currentPosition, false);
const remainingDistance = currentPosition.distanceTo(endPosition);
const totalDistance = startPosition.distanceTo(endPosition);
const progress = 1 - (remainingDistance / totalDistance);
console.log(`Transition progress: ${(progress * 100).toFixed(1)}%`);
if (remainingDistance < 0.01) { // Close enough
clearInterval(interval);
console.log('Transition complete');
}
}, 100);
}
// Start monitoring before transition
monitorTransition();
await cameraControls.moveTo(10, 5, 15, true);State Interpolation:
// Interpolate between two saved states
async function interpolateStates(
state1: string,
state2: string,
t: number, // 0-1 interpolation factor
controls: CameraControls,
animate = true
): Promise<void> {
const parsed1 = JSON.parse(state1);
const parsed2 = JSON.parse(state2);
// Interpolate position
const pos1 = new THREE.Vector3(parsed1.position.x, parsed1.position.y, parsed1.position.z);
const pos2 = new THREE.Vector3(parsed2.position.x, parsed2.position.y, parsed2.position.z);
const interpolatedPos = pos1.clone().lerp(pos2, t);
// Interpolate target
const target1 = new THREE.Vector3(parsed1.target.x, parsed1.target.y, parsed1.target.z);
const target2 = new THREE.Vector3(parsed2.target.x, parsed2.target.y, parsed2.target.z);
const interpolatedTarget = target1.clone().lerp(target2, t);
// Apply interpolated state
await Promise.all([
controls.setPosition(interpolatedPos.x, interpolatedPos.y, interpolatedPos.z, animate),
controls.setTarget(interpolatedTarget.x, interpolatedTarget.y, interpolatedTarget.z, animate)
]);
}
// Usage: animate between states
for (let i = 0; i <= 10; i++) {
const t = i / 10;
await interpolateStates(overviewState, closeupState, t, cameraControls, true);
await new Promise(resolve => setTimeout(resolve, 200));
}