Aquarium Interactive Calculator

So for those of you needing a great tool to help with your aquarium math here is a great tool I created to simplify the process for you and give you a good visual.

3D Aquarium Load Simulator .aq3d-wrapper { font-family: ‘Segoe UI’, system-ui, sans-serif; max-width: 900px; margin: 0 auto; background: #ffffff; border: 1px solid #e0e0e0; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); display: flex; flex-wrap: wrap; overflow: hidden; } .aq3d-sidebar { flex: 1; min-width: 300px; padding: 25px; background: #f8fcfd; border-right: 1px solid #e0e0e0; box-sizing: border-box; } .aq3d-canvas-container { flex: 2; min-width: 300px; min-height: 400px; position: relative; background: #eef5f9; } .aq3d-canvas-container canvas { display: block; width: 100% !important; height: 100% !important; outline: none; } .aq3d-overlay-text { position: absolute; top: 15px; right: 15px; background: rgba(255, 255, 255, 0.8); padding: 5px 10px; border-radius: 4px; font-size: 0.8em; color: #555; pointer-events: none; } .aq3d-sidebar h3 { margin-top: 0; color: #0056b3; font-size: 1.4em; } .aq3d-input-group { margin-bottom: 12px; } .aq3d-input-group label { display: flex; justify-content: space-between; font-weight: 600; font-size: 0.85em; color: #495057; margin-bottom: 4px; } .aq3d-input-group input[type=”range”] { width: 100%; cursor: pointer; accent-color: #0056b3; } .aq3d-input-group select { width: 100%; padding: 6px; border: 1px solid #ced4da; border-radius: 4px; } .aq3d-results { margin-top: 20px; background: #ffffff; padding: 15px; border-radius: 8px; border: 1px solid #d0e8f2; } .aq3d-result-row { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 0.9em; color: #333; } .aq3d-total { font-weight: bold; font-size: 1.1em; color: #004085; border-top: 2px solid #adb5bd; padding-top: 8px; margin-top: 8px; } https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js

3D Load Simulator

Length: 48 in
Width: 18 in
Height: 24 in
Substrate Depth: 2 in
Stand Height: 30 in
Stand Weight: 80 lbs
Tank Material Glass Acrylic
Tank Volume:90 Gal
Water Wt:693 lbs
Substrate Wt:100 lbs
Empty Tank Wt:144 lbs
10% Buffer:94 lbs
Total Load:1111 lbs
Left Click: Rotate | Scroll: Zoom
// 1. Setup Three.js Scene const container = document.getElementById(‘canvas-container’); const scene = new THREE.Scene(); scene.background = new THREE.Color(‘#eef5f9’); const camera = new THREE.PerspectiveCamera(45, container.clientWidth / container.clientHeight, 0.1, 1000); camera.position.set(80, 80, 100); const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(container.clientWidth, container.clientHeight); container.appendChild(renderer.domElement); const controls = new THREE.OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.05; controls.target.set(0, 20, 0); // Lights const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); const dirLight = new THREE.DirectionalLight(0xffffff, 0.5); dirLight.position.set(50, 100, 50); scene.add(dirLight); // 2. Create Base 3D Objects (1x1x1 cubes that we will scale) const baseGeometry = new THREE.BoxGeometry(1, 1, 1); // Stand const standMat = new THREE.MeshLambertMaterial({ color: 0x3e2723 }); // Dark wood const standMesh = new THREE.Mesh(baseGeometry, standMat); scene.add(standMesh); // Substrate const subMat = new THREE.MeshLambertMaterial({ color: 0x8b5a2b }); // Gravel brown const subMesh = new THREE.Mesh(baseGeometry, subMat); scene.add(subMesh); // Water const waterMat = new THREE.MeshPhongMaterial({ color: 0x1ca3ec, transparent: true, opacity: 0.6, shininess: 100 }); const waterMesh = new THREE.Mesh(baseGeometry, waterMat); scene.add(waterMesh); // Glass Tank (Outer Shell) const glassMat = new THREE.MeshPhysicalMaterial({ color: 0xffffff, transmission: 0.9, opacity: 0.2, transparent: true, roughness: 0.1 }); const tankMesh = new THREE.Mesh(baseGeometry, glassMat); scene.add(tankMesh); // Tank Edges for visibility const edges = new THREE.EdgesGeometry(baseGeometry); const lineMat = new THREE.LineBasicMaterial({ color: 0x8fc3e3, linewidth: 2 }); const tankEdges = new THREE.LineSegments(edges, lineMat); scene.add(tankEdges); // 3. Update Function function updateSystem() { // Get values const L = parseFloat(document.getElementById(‘inLen’).value); const W = parseFloat(document.getElementById(‘inWid’).value); const H = parseFloat(document.getElementById(‘inHgt’).value); let SubH = parseFloat(document.getElementById(‘inSub’).value); const StandH = parseFloat(document.getElementById(‘inStandH’).value); const StandW = parseFloat(document.getElementById(‘inStandW’).value); const Mat = document.getElementById(‘inMat’).value; if(SubH > H) { SubH = H; document.getElementById(‘inSub’).value = SubH; } // Update Text Labels document.getElementById(‘vLen’).innerText = L + ‘ in’; document.getElementById(‘vWid’).innerText = W + ‘ in’; document.getElementById(‘vHgt’).innerText = H + ‘ in’; document.getElementById(‘vSub’).innerText = SubH + ‘ in’; document.getElementById(‘vStandH’).innerText = StandH + ‘ in’; document.getElementById(‘vStandW’).innerText = StandW + ‘ lbs’; // Math Calculations const volTotalInches = L * W * H; const galsTotal = volTotalInches / 231; // Water occupies volume minus substrate, minus 1 inch at the top const waterHeight = Math.max(0, H – SubH – 1); const waterGals = (L * W * waterHeight) / 231; const waterWt = waterGals * 8.34; const subWt = (L * W * SubH) * 0.058; const tankWt = Mat === ‘glass’ ? galsTotal * 1.6 : galsTotal * 0.8; const buffer = (waterWt + subWt + tankWt) * 0.10; const totalLoad = waterWt + subWt + tankWt + StandW + buffer; // Update Results Panel document.getElementById(‘rVol’).innerText = Math.round(galsTotal) + ‘ Gal’; document.getElementById(‘rWat’).innerText = Math.round(waterWt) + ‘ lbs’; document.getElementById(‘rSub’).innerText = Math.round(subWt) + ‘ lbs’; document.getElementById(‘rTank’).innerText = Math.round(tankWt) + ‘ lbs’; document.getElementById(‘rBuf’).innerText = Math.round(buffer) + ‘ lbs’; document.getElementById(‘rTot’).innerText = Math.round(totalLoad) + ‘ lbs’; // Update 3D Model Scales and Positions // Stand standMesh.scale.set(L, StandH, W); standMesh.position.set(0, StandH / 2, 0); // Tank & Edges tankMesh.scale.set(L, H, W); tankMesh.position.set(0, StandH + (H / 2), 0); tankEdges.scale.set(L, H, W); tankEdges.position.set(0, StandH + (H / 2), 0); // Substrate subMesh.scale.set(L – 0.2, SubH, W – 0.2); // Slightly smaller than glass to fit inside subMesh.position.set(0, StandH + (SubH / 2), 0); // Water if(waterHeight > 0) { waterMesh.visible = true; waterMesh.scale.set(L – 0.4, waterHeight, W – 0.4); waterMesh.position.set(0, StandH + SubH + (waterHeight / 2), 0); } else { waterMesh.visible = false; } // Keep the camera looking at the center of the tank controls.target.set(0, StandH + (H/2), 0); } // Event Listeners for inputs const inputs = document.querySelectorAll(‘input, select’); inputs.forEach(input => input.addEventListener(‘input’, updateSystem)); // Handle Window Resize window.addEventListener(‘resize’, () => { const width = container.clientWidth; const height = container.clientHeight; renderer.setSize(width, height); camera.aspect = width / height; camera.updateProjectionMatrix(); }); // Animation Loop function animate() { requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); } // Initialize updateSystem(); animate();