diff --git a/ui/index.html b/ui/index.html index 931609b..fecb0dd 100644 --- a/ui/index.html +++ b/ui/index.html @@ -86,8 +86,8 @@ import * as THREE from 'three'; // --- Three.js scene --- const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100); -camera.position.set(0, 2, 5); -camera.lookAt(0, 0, 0); +camera.position.set(0, 1.2, 5); +camera.lookAt(0, 0.8, 0); const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(window.innerWidth, window.innerHeight); @@ -107,70 +107,67 @@ scene.add(pointLight); // Grid scene.add(new THREE.GridHelper(10, 20, 0x222244, 0x111122)); -// FC Board model +// SaltyBot robot model — two-wheeled self-balancing robot +// Pivot at wheel axle (y=0); body rises upward; pitches ±pitch_deg around X axis. const boardGroup = new THREE.Group(); -// PCB +// Main body (vertical rectangle, ~1.2 tall, center above wheel axle) boardGroup.add(new THREE.Mesh( - new THREE.BoxGeometry(1.6, 0.08, 1.6), - new THREE.MeshPhongMaterial({ color: 0x1a1a1a, specular: 0x333333 }) + new THREE.BoxGeometry(0.7, 1.2, 0.3), + new THREE.MeshPhongMaterial({ color: 0x1a2a4a, specular: 0x334466 }) )); +boardGroup.children[boardGroup.children.length - 1].position.set(0, 0.7, 0); -// Copper traces -const traceMat = new THREE.MeshPhongMaterial({ color: 0xcc8833, specular: 0xffaa44 }); -for (let i = -0.6; i <= 0.6; i += 0.3) { - const trace = new THREE.Mesh(new THREE.BoxGeometry(1.4, 0.005, 0.02), traceMat); - trace.position.set(0, 0.043, i); - boardGroup.add(trace); -} +// Left wheel +const wheelGeo = new THREE.CylinderGeometry(0.4, 0.4, 0.14, 20); +const wheelMat = new THREE.MeshPhongMaterial({ color: 0x1a1a1a, specular: 0x333333 }); +const leftWheel = new THREE.Mesh(wheelGeo, wheelMat); +leftWheel.rotation.z = Math.PI / 2; +leftWheel.position.set(-0.47, 0, 0); +boardGroup.add(leftWheel); -// MCU chip -const mcu = new THREE.Mesh( - new THREE.BoxGeometry(0.5, 0.06, 0.5), - new THREE.MeshPhongMaterial({ color: 0x222222, specular: 0x444444 }) -); -mcu.position.set(0, 0.07, 0); -boardGroup.add(mcu); +// Right wheel +const rightWheel = new THREE.Mesh(wheelGeo, wheelMat); +rightWheel.rotation.z = Math.PI / 2; +rightWheel.position.set(0.47, 0, 0); +boardGroup.add(rightWheel); -// IMU chip -const imuChip = new THREE.Mesh( - new THREE.BoxGeometry(0.2, 0.04, 0.2), - new THREE.MeshPhongMaterial({ color: 0x331111, specular: 0x442222 }) -); -imuChip.position.set(-0.4, 0.06, -0.3); -boardGroup.add(imuChip); +// Wheel rims (blue accent) +const rimGeo = new THREE.TorusGeometry(0.37, 0.025, 8, 20); +const rimMat = new THREE.MeshPhongMaterial({ color: 0x0055cc, specular: 0x0088ff }); +[[-0.54], [0.54]].forEach(([x]) => { + const rim = new THREE.Mesh(rimGeo, rimMat); + rim.rotation.z = Math.PI / 2; + rim.position.set(x, 0, 0); + boardGroup.add(rim); +}); -// USB connector -const usb = new THREE.Mesh( - new THREE.BoxGeometry(0.35, 0.1, 0.15), - new THREE.MeshPhongMaterial({ color: 0x888888, specular: 0xaaaaaa }) -); -usb.position.set(0, 0.06, -0.85); -boardGroup.add(usb); +// Display panel on front face +boardGroup.add(new THREE.Mesh( + new THREE.BoxGeometry(0.48, 0.36, 0.02), + new THREE.MeshPhongMaterial({ color: 0x001133, specular: 0x003366, emissive: 0x000a1a }) +)); +boardGroup.children[boardGroup.children.length - 1].position.set(0, 0.75, 0.16); // Status LED const ledMat = new THREE.MeshBasicMaterial({ color: 0xff0000 }); -const led = new THREE.Mesh(new THREE.SphereGeometry(0.03, 8, 8), ledMat); -led.position.set(0.5, 0.06, 0.5); +const led = new THREE.Mesh(new THREE.SphereGeometry(0.04, 8, 8), ledMat); +led.position.set(0.22, 1.1, 0.16); boardGroup.add(led); -// Mounting holes -const holeMat = new THREE.MeshPhongMaterial({ color: 0x444444 }); -[[-0.55, -0.55], [-0.55, 0.55], [0.55, -0.55], [0.55, 0.55]].forEach(([x, z]) => { - const ring = new THREE.Mesh(new THREE.TorusGeometry(0.06, 0.015, 8, 16), holeMat); - ring.rotation.x = Math.PI / 2; - ring.position.set(x, 0.05, z); - boardGroup.add(ring); -}); +// Sensor stem (thin post above body) +boardGroup.add(new THREE.Mesh( + new THREE.BoxGeometry(0.1, 0.28, 0.1), + new THREE.MeshPhongMaterial({ color: 0x2a2a2a, specular: 0x444444 }) +)); +boardGroup.children[boardGroup.children.length - 1].position.set(0, 1.44, 0); -// Forward arrow -const arrow = new THREE.Mesh( - new THREE.ConeGeometry(0.08, 0.2, 8), - new THREE.MeshBasicMaterial({ color: 0xff4444, transparent: true, opacity: 0.8 }) -); -arrow.rotation.x = -Math.PI / 2; -arrow.position.set(0, 0.06, -0.65); -boardGroup.add(arrow); +// Sensor head (camera/LIDAR box at top) +boardGroup.add(new THREE.Mesh( + new THREE.BoxGeometry(0.28, 0.16, 0.28), + new THREE.MeshPhongMaterial({ color: 0x111122, specular: 0x333355 }) +)); +boardGroup.children[boardGroup.children.length - 1].position.set(0, 1.66, 0); scene.add(boardGroup);