Skip to main content

Connect to your camera

The package has no three.js dependency. The cube reports where the camera should go; your code moves it. Both examples animate with the exported easing and shortest-path helpers.

Z-up, pitch and yaw (CAD style)​

import { useRef, useState } from 'react';
import { ViewCube, interpolateAngles, resolveEasing, type ViewTarget } from '@jugaaadi/view-cube';
import '@jugaaadi/view-cube/styles.css';

export function ZUpCube({ fitAll }: { fitAll: () => void }) {
const [view, setView] = useState({ pitch: 45, yaw: 45 });
const frame = useRef(0);
const go = (target: ViewTarget) => {
cancelAnimationFrame(frame.current);
const ease = resolveEasing(target.transition.easing);
const start = performance.now();
const step = (now: number) => {
const t = target.transition.duration > 0 ? Math.min(1, (now - start) / target.transition.duration) : 1;
setView(interpolateAngles(target.from, { pitch: target.pitch, yaw: target.yaw }, ease(t)));
if (t < 1) frame.current = requestAnimationFrame(step);
};
frame.current = requestAnimationFrame(step);
};
return <ViewCube orientation={view} onViewChange={go} onFit={fitAll} />;
}

Feed view to your own camera: pitch is the angle from straight down, yaw the heading from Front.

Y-up, quaternion (three.js style)​

import { useEffect, useState } from 'react';
import { ViewCube, Y_UP_CONVENTION, type ViewTarget } from '@jugaaadi/view-cube';
import type { PerspectiveCamera, Vector3 } from 'three';

export function YUpCube({ camera, pivot, render }: { camera: PerspectiveCamera; pivot: Vector3; render: () => void }) {
const [quaternion, setQuaternion] = useState(camera.quaternion.toArray() as [number, number, number, number]);
useEffect(() => {
const sync = () => setQuaternion(camera.quaternion.toArray() as [number, number, number, number]);
window.addEventListener('camera-moved', sync);
return () => window.removeEventListener('camera-moved', sync);
}, [camera]);
const go = (target: ViewTarget) => {
const distance = camera.position.distanceTo(pivot);
const [dx, dy, dz] = target.direction;
camera.position.set(pivot.x + dx * distance, pivot.y + dy * distance, pivot.z + dz * distance);
camera.up.set(...target.up);
camera.lookAt(pivot);
render();
setQuaternion(camera.quaternion.toArray() as [number, number, number, number]);
};
return <ViewCube orientation={{ quaternion }} convention={Y_UP_CONVENTION} onViewChange={go} />;
}

target.direction points from the scene toward the camera and target.up is the camera's up, both in world axes of the convention you pass. For a smooth move, slerp from the current quaternion to target.quaternion over target.transition.duration milliseconds. Dispatch camera-moved (or call setQuaternion) from your orbit controls so the cube follows the user's own orbiting.