JIT
Animating a 3D brain model assembly with color transitions and camera movements
Load a 3D brain model that has already been split into 12 separate mesh pieces. Each piece is named exactly “piece_01,” “piece_02,” … “piece_12.” At time = 0, all 12 pieces should be positioned in random, scattered locations around the center of the scene. For example, each piece’s initial position might lie within a 10×6×4 unit bounding box (i.e. X ∈ [–5, +5], Y ∈ [–3, +3], Z ∈ [–2, +2]). Their orientations can be slightly rotated so they look “tumbled.” The final “assembled” brain shape is centered at world coordinates (0, 0, 0). Each piece’s “target position” is the exact x, y, z location it had in the original model before scattering. Record those target transforms for each piece in the 3D file’s metadata or assume the AI can infer that from the loaded scene if you supply an “assembled reference” frame. Piece‐by‐Piece Assembly Animation: For each piece from “piece_01” to “piece_12” in numeric order: Beginning at 0.5-second intervals (i.e., piece_01 starts at 0.0s, piece_02 at 0.5s, piece_03 at 1.0s, …, piece_12 at 5.5s), animate that piece’s position from its current random coordinates to its “target” coordinates at the center of the brain. Each piece’s move should take exactly 0.8 seconds. While each piece moves, smoothly interpolate its color from white to a specific hue in this sequence: piece_01 → bright yellow (#FFC300) piece_02 → bright yellow (#FFC300) piece_03 → green (#28A745) piece_04 → green (#28A745) piece_05 → green (#28A745) piece_06 → blue (#007BFF) piece_07 → blue (#007BFF) piece_08 → blue (#007BFF) piece_09 → purple (#800080) piece_10 → purple (#800080) piece_11 → purple (#800080) piece_12 → purple (#800080) The color transition for each piece should occur over the same 0.8-second window as its position tween, ending with the piece fully colored at its target location. Global Color Tint / Background Transition: Simultaneously, as each group of pieces finishes (e.g., once any piece finishes moving), slightly shift the entire scene’s background or ambient light color in four major steps: From time 0.0–2.0s (while pieces 01–04 are moving), have the background slowly fade from white (or transparent) to yellow (#FFC300). From time 2.0–4.0s (while pieces 05–08 are moving), fade the background from yellow to green (#28A745). From time 4.0–6.0s (while pieces 09–12 are moving), fade from green to blue (#007BFF). From time 6.0–7.0s (after piece_12 finishes), fade from blue to purple (#800080). By 7.0 seconds, the background or a subtle fill overlay should be fully purple, signaling the puzzle’s completion. Camera Animation: Initial Framing (0.0–0.5s): The camera starts slightly zoomed out (e.g., at z = 10) and angled so the brain is centered but small. Rotate‐in Place (0.5–3.0s): As pieces 01–05 assemble, the camera slowly orbits 20° around the brain (panning on the Y-axis), keeping the brain centered. Zoom In (3.0–5.0s): While pieces 06–10 assemble, smoothly dolly the camera from z = 8 to z = 5, and tilt it slightly down so the viewer can see the top hemisphere. Final Focus (5.0–7.0s): During the last two pieces, rotate the camera back to a straight-on front-center perspective (0° yaw), finalize zoom at z = 4.5, and hold on the now fully assembled, color-tinted brain. Hold & Ease Out (7.0–8.0s): Keep the camera fixed on the completed brain for 1 second, then slowly pull back to let the main navigation appear (optional placeholder animation for nav). Output Format: Provide the final animation as a single preset “brain_puzzle_assemble” clip in Collada (.dae) or JSON (Three.js animation clip format). The exported file should include each piece’s position keyframes and color-interpolation keyframes, plus a separate “camera” node with its path keyframes. Ensure the timing is baked so that any Three.js scene loading this clip will simply call mixer.clipAction('brain_puzzle_assemble').play() and see the entire sequence play back in exactly 8 seconds. Additional Notes / Constraints: The AI‐generated skeleton should preserve each piece’s mesh hierarchy. Namely, the root node of each piece remains piece_01 through piece_12. Don’t merge them. The scene’s pivot/origin for each piece must be at its logical center so that rotation (if any) looks correct. For this prompt, we only move positions, not rotate, but the origin must still be placed correctly. No external textures—use a simple Lambert or Phong material so color‐tweens work smoothly. If textures exist, color animation can target the material.color property. Frame rate should be 30 FPS (or higher) with baked keyframes to avoid jitter on lower‐end devices. Include a separate, very brief “fade-to-black” or “screen flash” event at exactly 8.0 s to signal “puzzle complete,” so your Three.js code can transition into revealing navigation. This can be a full-screen white quad that fades out in 0.3 s. Goal: By running the exported animation in your Three.js scene, each of the brain’s 12 pieces will automatically slide into place in the prescribed color order. The camera will orbit and zoom in at the right times. The overall background will shift through the yellow→green→blue→purple journey. After 8 seconds, everything will hold on the completed, purple-tinted brain, ready for the site to reveal navigation.

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>

This implementation includes:

  1. A scene setup with 12 brain pieces (represented by boxes for now)
  2. Random initial positions within the specified bounds
  3. Color transitions for each piece according to the specified sequence
  4. Background color transitions through the specified phases
  5. Camera animation with rotation, zoom, and final positioning
  6. A final flash effect at 8 seconds
  7. Responsive design that handles window resizing

To use this with actual brain pieces:

  1. Replace the box geometries with your actual brain piece models
  2. Set the correct target positions in the piecePositions array
  3. Adjust the materials to match your desired appearance

The 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.*_

Preview not available