/* ===== BrewOS — CCT tank visual ===== */ const { useMemo } = React; let _uidc = 0; function useUid(){ return useMemo(()=> 'tk'+(_uidc++), []); } // Bubble field for active fermentation function Bubbles({ surfaceY, color, count }){ const items = useMemo(()=>{ const a=[]; for(let i=0;i upward a.push({ x, base, r: 0.7 + Math.random()*1.7, dur: 2.4 + Math.random()*3.2, delay: -Math.random()*5, rise, }); } return a; // eslint-disable-next-line },[count, Math.round(surfaceY)]); return ( {items.map((b,i)=>( ))} ); } /* props: state, fill(0..1), color, foam, glossy(bool), bubbles(bool), glow(bool) */ function Tank({ state='free', fill=0, color='#e6b13a', foam='#fbf2d2', glossy=true, bubbles=true, glow=true }){ const uid = useUid(); const stColor = (window.STATES[state]||{}).color || '#888'; const hasLiquid = fill>0.001; const surfaceY = 168 - 124*fill; // y of liquid surface const active = state==='ferment'; const showGlow = glow && (state==='ferment'||state==='ready'||state==='cold'); // interior path (clip for liquid + effects) const interior = "M28,40 L28,126 L60,168 L92,126 L92,40 Z"; return ( {/* ground shadow */} {/* legs */} {/* support ring */} {/* cone */} {/* outlet valve */} {/* body */} {/* ===== liquid + effects (clipped) ===== */} {hasLiquid && ( {/* inner shading on liquid */} {/* surface */} {/* krausen foam cap for fermenting */} {state==='ferment' && ( )} {active && bubbles && } {/* cold crash frost tint */} {state==='cold' && ( {[...Array(10)].map((_,i)=>( ))} )} )} {/* CIP spray swirl (empty) */} {state==='cip' && ( {[...Array(7)].map((_,i)=>{ const a=i/7*Math.PI*2; return ; })} )} {/* welded rings (over everything, subtle) */} {[50,64,78,92,106,120].map(y=>())} {[51,65,79,93,107,121].map(y=>())} {/* gloss highlight */} {glossy && } {/* top manway / lid */} {/* side arm pipe */} {/* thermowell pocket */} ); } Object.assign(window, { Tank });