Files
doormile-next/src/components/optimization/HologramCity.tsx
2026-05-30 17:24:26 +05:30

192 lines
6.4 KiB
TypeScript

"use client";
import React, { useMemo, useRef } from "react";
import { useFrame } from "@react-three/fiber";
import * as THREE from "three";
import { COLORS } from "./constants";
import { damp, lerp, seeded, smoothstep } from "./math";
type Props = {
progress: React.RefObject<number>;
count?: number;
reduced?: boolean;
};
const CYAN = new THREE.Color(COLORS.cyan);
const RED = new THREE.Color(COLORS.red);
const GREEN = new THREE.Color(COLORS.green);
// Generate deterministic cluster centers matching routes.ts
const clusterCount = 5;
const clusterCenters = Array.from({ length: clusterCount }, (_, c) => {
const baseAngle = (c / clusterCount) * Math.PI * 2 + 0.3;
const radius = 7 + seeded(c * 7 + 1) * 3;
const cx = Math.cos(baseAngle) * radius;
const cz = Math.sin(baseAngle) * radius;
return new THREE.Vector3(cx, 0.1, cz);
});
function HologramCity({ progress, reduced = false }: Props) {
const mainWarehouseRef = useRef<THREE.Group>(null);
const radarRefs = useRef<(THREE.Group | null)[]>([]);
const corridorMats = useRef<(THREE.LineBasicMaterial | null)[]>([]);
const zoneMats = useRef<(THREE.MeshBasicMaterial | null)[]>([]);
const eased = useRef(0);
// Pre-generate corridor geometries (Warehouse [0, 0, 0] to Cluster Centers)
const corridorGeometries = useMemo(() => {
return clusterCenters.map((center) => {
const pts = [
new THREE.Vector3(0, 0.15, 0),
new THREE.Vector3(center.x * 0.5, 0.6, center.z * 0.5), // arch up slightly in the middle
new THREE.Vector3(center.x, 0.15, center.z),
];
return new THREE.CatmullRomCurve3(pts).getPoints(24);
});
}, []);
useFrame((state, dt) => {
const p = progress.current ?? 0;
eased.current = damp(eased.current, p, 3, dt);
const e = eased.current;
const t = state.clock.elapsedTime;
// Animate Main Warehouse central beacon rotation
if (mainWarehouseRef.current) {
mainWarehouseRef.current.position.y = Math.sin(t * 1.2) * 0.04;
}
// Rotate Radar dishes on top of the Regional Hubs
radarRefs.current.forEach((radar, idx) => {
if (radar) {
radar.rotation.y = t * (0.8 + idx * 0.2);
}
});
// Animate corridor line opacity and color:
// Under unoptimized states (chaos/scan) they are faint or red.
// As optimization settles, they light up with active cyan/green.
corridorMats.current.forEach((mat, idx) => {
if (mat) {
const activeColor = idx % 2 === 0 ? CYAN : GREEN;
const colorFactor = smoothstep(0.45, 0.8, e);
mat.color.copy(RED).lerp(activeColor, colorFactor);
mat.opacity = lerp(0.12, 0.7, colorFactor) * (0.8 + Math.sin(t * 4 - idx * 0.5) * 0.2);
}
});
// Animate ground delivery zone circles
zoneMats.current.forEach((mat, idx) => {
if (mat) {
const activeColor = idx % 2 === 0 ? CYAN : GREEN;
const colorFactor = smoothstep(0.5, 0.82, e);
mat.color.copy(RED).lerp(activeColor, colorFactor);
mat.opacity = lerp(0.06, 0.22, colorFactor) * (0.85 + Math.sin(t * 3 - idx) * 0.15);
}
});
});
return (
<group>
{/* Sleek Dark Cyber Ground Grid */}
<gridHelper
args={[60, 48, COLORS.cyan, COLORS.cyan]}
position={[0, -0.01, 0]}
>
<lineBasicMaterial
attach="material"
color={COLORS.cyan}
transparent
opacity={0.05}
/>
</gridHelper>
{/* Primary Transport Corridors (Warehouse to Cluster Hubs) */}
{corridorGeometries.map((points, i) => (
<line key={`corr${i}`}>
<bufferGeometry>
<float32BufferAttribute
attach="attributes-position"
args={[new Float32Array(points.flatMap(p => [p.x, p.y, p.z])), 3]}
/>
</bufferGeometry>
<lineBasicMaterial
ref={(el) => {
corridorMats.current[i] = el;
}}
transparent
opacity={0.15}
depthWrite={false}
/>
</line>
))}
{/* CENTRAL LOGISTICS ASSET: Main Warehouse Hub */}
<group ref={mainWarehouseRef} position={[0, 0, 0]}>
{/* Core foundation structure */}
<mesh position={[0, 0.35, 0]}>
<boxGeometry args={[2.2, 0.7, 1.8]} />
<meshBasicMaterial color={COLORS.ink} />
</mesh>
<mesh position={[0, 0.35, 0]}>
<boxGeometry args={[2.2, 0.7, 1.8]} />
<meshBasicMaterial color={COLORS.cyan} wireframe transparent opacity={0.65} />
</mesh>
{/* Loading Docks */}
{[-0.6, 0, 0.6].map((offset, i) => (
<mesh key={i} position={[offset, 0.18, 0.91]}>
<boxGeometry args={[0.3, 0.35, 0.06]} />
<meshBasicMaterial color={COLORS.cyan} transparent opacity={0.8} />
</mesh>
))}
{/* Upper Level / Control Deck */}
<mesh position={[0, 0.85, 0]}>
<boxGeometry args={[1.2, 0.3, 1.0]} />
<meshBasicMaterial color={COLORS.cyan} transparent opacity={0.15} />
</mesh>
<mesh position={[0, 0.85, 0]}>
<boxGeometry args={[1.2, 0.3, 1.0]} />
<meshBasicMaterial color={COLORS.cyan} wireframe transparent opacity={0.9} />
</mesh>
{/* Rooftop Solar Panels */}
{[-0.4, 0.4].map((offset, i) => (
<mesh key={i} position={[offset, 0.71, -0.4]} rotation={[0.15, 0, 0]}>
<boxGeometry args={[0.5, 0.03, 0.6]} />
<meshBasicMaterial color="#1e293b" />
</mesh>
))}
{/* Central Communications Array / Tower */}
<group position={[0, 1.0, 0]}>
{/* Main rod */}
<mesh position={[0, 0.4, 0]}>
<cylinderGeometry args={[0.03, 0.03, 0.8, 8]} />
<meshBasicMaterial color={COLORS.cyan} />
</mesh>
{/* Glowing Beacon */}
<mesh position={[0, 0.8, 0]}>
<sphereGeometry args={[0.12, 16, 16]} />
<meshBasicMaterial color="#ffffff" />
</mesh>
</group>
{/* Pulsing ground base glow */}
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, 0.02, 0]}>
<ringGeometry args={[1.8, 2.2, 32]} />
<meshBasicMaterial
color={COLORS.cyan}
transparent
opacity={0.3}
blending={THREE.AdditiveBlending}
/>
</mesh>
</group>
</group>
);
}
export default React.memo(HologramCity);