I'll create a Three.js project that loads a 3D brain model with 12 pieces and implements the specified animation sequence. Here's the implementation:
<project id="brain-puzzle" title="Three.js Brain Puzzle Animation">
<file path="index.html">
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Brain Puzzle Animation</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.166.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.166.0/examples/jsm/"
}
}
</script>
</head>
<body>
<script type="module" src="main.js"></script>
</body>
</html>
</file>
<file path="main.js">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
// Scene setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 10;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
// Controls for debugging (optional)
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
// Colors for each piece
const pieceColors = [
0xFFC300, 0xFFC300, 0x28A745, 0x28A745, 0x28A745,
0x007BFF, 0x007BFF, 0x007BFF, 0x800080, 0x800080,
0x800080, 0x800080
];
// Background colors for each phase
const backgroundColors = [
{ time: 0.0, color: 0xffffff },
{ time: 2.0, color: 0xFFC300 },
{ time: 4.0, color: 0x28A745 },
{ time: 6.0, color: 0x007BFF },
{ time: 7.0, color: 0x800080 }
];
// Create brain pieces with random positions
const brainPieces = [];
const piecePositions = [];
const pieceMaterials = [];
for (let i = 0; i < 12; i++) {
const geometry = new THREE.BoxGeometry(1, 1, 1); // Replace with actual brain piece geometry
const material = new THREE.MeshPhongMaterial({
color: 0xffffff,
transparent: true,
opacity: 0.8
});
const piece = new THREE.Mesh(geometry, material);
piece.name = `piece_${String(i + 1).padStart(2, '0')}`;
// Random position within specified bounds
const posX = (Math.random() * 10) - 5;
const posY = (Math.random() * 6) - 3;
const posZ = (Math.random() * 4) - 2;
piece.position.set(posX, posY, posZ);
piece.rotation.set(
Math.random() * Math.PI * 0.2,
Math.random() * Math.PI * 0.2,
Math.random() * Math.PI * 0.2
);
// Store original position (target position)
piecePositions.push(new THREE.Vector3(0, 0, 0)); // Replace with actual target positions
pieceMaterials.push(material);
scene.add(piece);
brainPieces.push(piece);
}
// Animation setup
const clock = new THREE.Clock();
let animationTime = 0;
const totalAnimationTime = 8;
// Camera animation parameters
const initialCameraPos = new THREE.Vector3(0, 0, 10);
const midCameraPos = new THREE.Vector3(0, 0, 8);
const finalCameraPos = new THREE.Vector3(0, 0, 4.5);
let currentCameraPos = initialCameraPos.clone();
// Animation loop
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
animationTime += delta;
// Update background color
for (let i = 0; i < backgroundColors.length - 1; i++) {
if (animationTime >= backgroundColors[i].time && animationTime < backgroundColors[i + 1].time) {
const progress = (animationTime - backgroundColors[i].time) / (backgroundColors[i + 1].time - backgroundColors[i].time);
const color = new THREE.Color(backgroundColors[i].color).lerp(
new THREE.Color(backgroundColors[i + 1].color),
progress
);
scene.background = color;
break;
}
}
// Update camera position
if (animationTime < 0.5) {
// Initial position
camera.position.copy(initialCameraPos);
} else if (animationTime < 3.0) {
// Rotate around Y axis
const progress = (animationTime - 0.5) / 2.5;
const angle = progress * Math.PI * 0.11; // 20 degrees
camera.position.x = Math.sin(angle) * 10;
camera.position.z = Math.cos(angle) * 10;
camera.lookAt(0, 0, 0);
} else if (animationTime < 5.0) {
// Zoom in
const progress = (animationTime - 3.0) / 2.0;
currentCameraPos.lerpVectors(midCameraPos, finalCameraPos, progress);
camera.position.copy(currentCameraPos);
camera.lookAt(0, 0, 0);
} else if (animationTime < 7.0) {
// Final position
camera.position.copy(finalCameraPos);
camera.lookAt(0, 0, 0);
}
// Animate brain pieces
for (let i = 0; i < brainPieces.length; i++) {
const piece = brainPieces[i];
const startTime = i * 0.5;
const endTime = startTime + 0.8;
if (animationTime >= startTime && animationTime <= endTime) {
const progress = (animationTime - startTime) / 0.8;
// Move to target position
piece.position.lerp(piecePositions[i], progress);
// Change color
pieceMaterials[i].color.lerp(new THREE.Color(pieceColors[i]), progress);
} else if (animationTime > endTime) {
// Ensure final position and color
piece.position.copy(piecePositions[i]);
pieceMaterials[i].color.set(pieceColors[i]);
}
}
// Final flash at 8 seconds
if (animationTime >= 8.0 && animationTime < 8.3) {
const flashProgress = (animationTime - 8.0) / 0.3;
scene.background = new THREE.Color(0xffffff).lerp(new THREE.Color(0x000000), flashProgress);
} else if (animationTime >= 8.3) {
scene.background = new THREE.Color(0x000000);
}
controls.update();
renderer.render(scene, camera);
}
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
animate();
</file>
</project>
<project id="brain-puzzle" title="Three.js Brain Puzzle Animation">
<file path="index.html">
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Brain Puzzle Animation</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.166.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.166.0/examples/jsm/"
}
}
</script>
</head>
<body>
<script type="module" src="main.js"></script>
</body>
</html>
</file>
<file path="main.js">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
// Scene setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 10;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
// Controls for debugging (optional)
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
// Colors for each piece
const pieceColors = [
0xFFC300, 0xFFC300, 0x28A745, 0x28A745, 0x28A745,
0x007BFF, 0x007BFF, 0x007BFF, 0x800080, 0x800080,
0x800080, 0x800080
];
// Background colors for each phase
const backgroundColors = [
{ time: 0.0, color: 0xffffff },
{ time: 2.0, color: 0xFFC300 },
{ time: 4.0, color: 0x28A745 },
{ time: 6.0, color: 0x007BFF },
{ time: 7.0, color: 0x800080 }
];
// Create brain pieces with random positions
const brainPieces = [];
const piecePositions = [];
const pieceMaterials = [];
for (let i = 0; i < 12; i++) {
const geometry = new THREE.BoxGeometry(1, 1, 1); // Replace with actual brain piece geometry
const material = new THREE.MeshPhongMaterial({
color: 0xffffff,
transparent: true,
opacity: 0.8
});
const piece = new THREE.Mesh(geometry, material);
piece.name = `piece_${String(i + 1).padStart(2, '0')}`;
// Random position within specified bounds
const posX = (Math.random() * 10) - 5;
const posY = (Math.random() * 6) - 3;
const posZ = (Math.random() * 4) - 2;
piece.position.set(posX, posY, posZ);
piece.rotation.set(
Math.random() * Math.PI * 0.2,
Math.random() * Math.PI * 0.2,
Math.random() * Math.PI * 0.2
);
// Store original position (target position)
piecePositions.push(new THREE.Vector3(0, 0, 0)); // Replace with actual target positions
pieceMaterials.push(material);
scene.add(piece);
brainPieces.push(piece);
}
// Animation setup
const clock = new THREE.Clock();
let animationTime = 0;
const totalAnimationTime = 8;
// Camera animation parameters
const initialCameraPos = new THREE.Vector3(0, 0, 10);
const midCameraPos = new THREE.Vector3(0, 0, 8);
const finalCameraPos = new THREE.Vector3(0, 0, 4.5);
let currentCameraPos = initialCameraPos.clone();
// Animation loop
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
animationTime += delta;
// Update background color
for (let i = 0; i < backgroundColors.length - 1; i++) {
if (animationTime >= backgroundColors[i].time && animationTime < backgroundColors[i + 1].time) {
const progress = (animationTime - backgroundColors[i].time) / (backgroundColors[i + 1].time - backgroundColors[i].time);
const color = new THREE.Color(backgroundColors[i].color).lerp(
new THREE.Color(backgroundColors[i + 1].color),
progress
);
scene.background = color;
break;
}
}
// Update camera position
if (animationTime < 0.5) {
// Initial position
camera.position.copy(initialCameraPos);
} else if (animationTime < 3.0) {
// Rotate around Y axis
const progress = (animationTime - 0.5) / 2.5;
const angle = progress * Math.PI * 0.11; // 20 degrees
camera.position.x = Math.sin(angle) * 10;
camera.position.z = Math.cos(angle) * 10;
camera.lookAt(0, 0, 0);
} else if (animationTime < 5.0) {
// Zoom in
const progress = (animationTime - 3.0) / 2.0;
currentCameraPos.lerpVectors(midCameraPos, finalCameraPos, progress);
camera.position.copy(currentCameraPos);
camera.lookAt(0, 0, 0);
} else if (animationTime < 7.0) {
// Final position
camera.position.copy(finalCameraPos);
camera.lookAt(0, 0, 0);
}
// Animate brain pieces
for (let i = 0; i < brainPieces.length; i++) {
const piece = brainPieces[i];
const startTime = i * 0.5;
const endTime = startTime + 0.8;
if (animationTime >= startTime && animationTime <= endTime) {
const progress = (animationTime - startTime) / 0.8;
// Move to target position
piece.position.lerp(piecePositions[i], progress);
// Change color
pieceMaterials[i].color.lerp(new THREE.Color(pieceColors[i]), progress);
} else if (animationTime > endTime) {
// Ensure final position and color
piece.position.copy(piecePositions[i]);
pieceMaterials[i].color.set(pieceColors[i]);
}
}
// Final flash at 8 seconds
if (animationTime >= 8.0 && animationTime < 8.3) {
const flashProgress = (animationTime - 8.0) / 0.3;
scene.background = new THREE.Color(0xffffff).lerp(new THREE.Color(0x000000), flashProgress);
} else if (animationTime >= 8.3) {
scene.background = new THREE.Color(0x000000);
}
controls.update();
renderer.render(scene, camera);
}
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
animate();
</file>
</project>
This implementation includes:
To use this with actual brain pieces:
piecePositions arrayThe animation will automatically play when the page loads, following all the specified timing and color transitions. The camera will move according to the specified path, and the background will transition through the color sequence. After 8 seconds, there will be a white-to-black flash effect.*_