/**
* The 3D hero view of the line.
*
* No external assets are loaded anywhere in this scene - no HDRI environment, no
* CDN font, no texture. Everything is primitives and analytic lights, because the
* demo has to survive a room with no working wifi.
*/
import { Suspense } from 'react';
import { Canvas } from '@react-three/fiber';
import { OrbitControls, ContactShadows } from '@react-three/drei';
import { useStore } from '../store.js';
import { Station } from './Station.jsx';
import { Belt, QueueBoxes, FlowBoxes } from './Conveyor.jsx';
import { stateMeta } from '../lib/format.js';
/** Station centres, evenly spaced along the line. */
const SPACING = 4.3;
const stationX = (i, n) => (i - (n - 1) / 2) * SPACING;
function Floor() {
return (
<>
{/* aisle markings, purely to give the eye a ground plane to read depth from */}
{[-3.2, 3.2].map((z) => (
))}
>
);
}
function LineContent() {
const frame = useStore((s) => s.frame);
const meta = useStore((s) => s.meta);
const selected = useStore((s) => s.selected);
const select = useStore((s) => s.select);
if (!frame || !meta) return null;
const n = frame.stations.length;
return (
{frame.stations.map((st, i) => (
x.id === st.id)}
x={stationX(i, n)}
selected={selected === st.id}
onSelect={select}
/>
))}
{frame.buffers.map((level, i) => {
const x = (stationX(i, n) + stationX(i + 1, n)) / 2;
const width = SPACING - 2.15;
const upstream = frame.stations[i];
return (
= frame.bufferCapacity}
/>
);
})}
);
}
export function Scene() {
const frame = useStore((s) => s.frame);
const connected = useStore((s) => s.connected);
const worstState = frame
? (frame.stations.find((s) => s.state === 'fault' || s.state === 'down')
|| frame.stations.find((s) => s.state === 'blocked'))
: null;
return (
LINE-1 · Assembly & Cure
{connected ? 'Live twin' : 'Disconnected'}
{worstState ? ` · ${worstState.id} ${stateMeta(worstState.state).label.toLowerCase()}` : ' · all stations nominal'}
{/* Legend pairs every status colour with its word. */}
{['running', 'microstop', 'blocked', 'fault'].map((s) => {
const sm = stateMeta(s);
return (
{sm.label}
);
})}
Drag to orbit · scroll to zoom · click a machine to inspect
);
}