Skip to content

Instantly share code, notes, and snippets.

@Aakash67
Last active March 28, 2025 12:27
Show Gist options
  • Select an option

  • Save Aakash67/062d5e96618918dfa0e74cf350599818 to your computer and use it in GitHub Desktop.

Select an option

Save Aakash67/062d5e96618918dfa0e74cf350599818 to your computer and use it in GitHub Desktop.
Interactive Bouncing Balls in a 3D Cube by Grok 3 Think mode
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Scene with Bouncing Balls</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<!-- Include Three.js and OrbitControls from CDN -->
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
<script>
// Initialize Scene, Camera, and Renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 5);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Define Cube Size
const cubeSize = 3;
const cubeHalfSize = cubeSize / 2; // 1.5
// Create the Transparent Cube
const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
const cubeMaterial = new THREE.MeshPhongMaterial({
color: 0xffffff,
transparent: true,
opacity: 0.5,
side: THREE.DoubleSide
});
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);
// Create 10 Colored Balls
const sphereGeometry = new THREE.SphereGeometry(0.2, 32, 32);
const colors = [
0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff,
0x00ffff, 0x990000, 0x009900, 0x000099, 0x999900
];
const balls = [];
for (let i = 0; i < 10; i++) {
const material = new THREE.MeshPhongMaterial({ color: colors[i] });
const ball = new THREE.Mesh(sphereGeometry, material);
const ballRadius = 0.2;
const positionRange = 2 * (cubeHalfSize - ballRadius); // 2 * (1.5 - 0.2) = 2.6
ball.position.set(
(Math.random() - 0.5) * positionRange,
(Math.random() - 0.5) * positionRange,
(Math.random() - 0.5) * positionRange
);
ball.velocity = new THREE.Vector3(
(Math.random() - 0.5) * 0.06,
(Math.random() - 0.5) * 0.06,
(Math.random() - 0.5) * 0.06
);
scene.add(ball);
balls.push(ball);
}
// Add Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
// Set Up OrbitControls
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Mouse Tracking
const mouse = new THREE.Vector2();
window.addEventListener('mousemove', (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}, false);
// Raycaster for Mouse Interaction
const raycaster = new THREE.Raycaster();
// Animation Loop
function animate() {
requestAnimationFrame(animate);
controls.update();
// Update ball positions based on mouse and camera
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(cube);
if (intersects.length > 0) {
const targetPosition = intersects[0].point;
const k = 0.001; // Attraction strength
const damping = 0.99; // Velocity damping
const ballRadius = 0.2;
balls.forEach(ball => {
ball.velocity.multiplyScalar(damping);
const direction = new THREE.Vector3().subVectors(targetPosition, ball.position);
const force = direction.multiplyScalar(k);
ball.velocity.add(force);
ball.position.add(ball.velocity);
// Bounce off cube walls
if (ball.position.x - ballRadius < -cubeHalfSize) {
ball.position.x = -cubeHalfSize + ballRadius;
ball.velocity.x *= -1;
} else if (ball.position.x + ballRadius > cubeHalfSize) {
ball.position.x = cubeHalfSize - ballRadius;
ball.velocity.x *= -1;
}
if (ball.position.y - ballRadius < -cubeHalfSize) {
ball.position.y = -cubeHalfSize + ballRadius;
ball.velocity.y *= -1;
} else if (ball.position.y + ballRadius > cubeHalfSize) {
ball.position.y = cubeHalfSize - ballRadius;
ball.velocity.y *= -1;
}
if (ball.position.z - ballRadius < -cubeHalfSize) {
ball.position.z = -cubeHalfSize + ballRadius;
ball.velocity.z *= -1;
} else if (ball.position.z + ballRadius > cubeHalfSize) {
ball.position.z = cubeHalfSize - ballRadius;
ball.velocity.z *= -1;
}
});
}
renderer.render(scene, camera);
}
// Start the animation
animate();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment