/**
* One machine, built from primitives.
*
* Geometry is boxes and cylinders on purpose. Sourcing or modelling CAD-accurate
* machines is a day of work that adds nothing to the argument being made, and it
* is the classic way a two-day demo becomes a four-day demo.
*
* What the geometry DOES carry is state, three ways: a status-coloured status bar
* on the machine, a pulse when it is stopped on a fault, and - the detail that
* lands with maintenance engineers - a physical shake on CNC-02 that scales with
* measured bearing vibration.
*/
import { useMemo, useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import { Html } from '@react-three/drei';
import { stateMeta } from '../lib/format.js';
function Body({ w, h, d, y, color, roughness = 0.6, metalness = 0.35 }) {
return (
);
}
/** Per-kind machine shape. */
function Machine({ kind, station, spinRef }) {
const shell = '#4a4941';
const dark = '#2f2e28';
switch (kind) {
case 'conveyor':
return (
{[-0.5, 0, 0.5].map((x) => (
))}
);
case 'cnc':
return (
{/* enclosure window */}
{/* spindle, rotates while cutting */}
);
case 'oven': {
// Zone glow follows burner duty, so a saturated burner visibly runs hot.
const duty = (station.signals.burnerDuty || 0) / 100;
return (
{/* tunnel mouth */}
{/* three zone strips on the roof */}
{[-0.75, 0, 0.75].map((x, i) => (
))}
);
}
case 'inspection':
return (
{/* gantry */}
{[-0.6, 0.6].map((x) => (
))}
{/* camera + light cone */}
);
case 'packer':
return (
{/* film roll */}
);
default:
return