'use client' import { useScrollProgress } from '@/lib/useScroll' import styles from './gizmo.module.css' const AXES = [ { label: 'X', vector: [1, 0, 0], color: 'var(--x)' }, { label: 'Y', vector: [0, 1, 0], color: 'var(--y)' }, { label: 'Z', vector: [0, 0, 1], color: 'var(--z)' }, ] as const const PITCH = 0.46 const LENGTH = 29 const CENTER = 48 function project([x, y, z]: readonly [number, number, number], yaw: number) { const x1 = x * Math.cos(yaw) + z * Math.sin(yaw) const z1 = -x * Math.sin(yaw) + z * Math.cos(yaw) const y2 = y * Math.cos(PITCH) - z1 * Math.sin(PITCH) const depth = y * Math.sin(PITCH) + z1 * Math.cos(PITCH) return { x: CENTER + x1 * LENGTH, y: CENTER - y2 * LENGTH, depth } } /** Orientation gizmo of a 3D viewport. It orbits as the page scrolls and returns to the top when pressed. */ export default function Gizmo() { const progress = useScrollProgress() const yaw = 0.62 + progress * Math.PI * 1.35 const ends = AXES.flatMap((axis) => ([1, -1] as const).map((sign) => ({ axis, positive: sign === 1, ...project([axis.vector[0] * sign, axis.vector[1] * sign, axis.vector[2] * sign], yaw), })), ).sort((a, b) => a.depth - b.depth) return ( ) }