There’s no rubiks cubs in this code when I run it fix it: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>3x3 Rubik's Cube in 3D</title>
<style>
  body { margin: 0; overflow: hidden; }
  #ui {
    position: absolute;
    top: 10px;
    left: 10px;
    z-index: 10;
    background: rgba(255,255,255,0.8);
    padding: 10px;
    border-radius: 5px;
  }
  button {
    margin: 5px;
    padding: 8px 12px;
  }
</style>
</head>
<body>
<div id="ui">
  <button id="shuffleBtn">Shuffle</button>
  <button id="solveBtn">Solve</button>
  <p>Click face buttons to rotate layers:</p>
  <button data-move="U">U</button>
  <button data-move="U'">U'</button>
  <button data-move="D">D</button>
  <button data-move="D'">D'</button>
  <button data-move="L">L</button>
  <button data-move="L'">L'</button>
  <button data-move="R">R</button>
  <button data-move="R'">R'</button>
  <button data-move="F">F</button>
  <button data-move="F'">F'</button>
  <button data-move="B">B</button>
  <button data-move="B'">B'</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/three@0.150.1/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.150.1/examples/js/controls/OrbitControls.js"></script>
<script>
  // Basic setup
  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
  camera.position.set(6, 6, 6);

  const renderer = new THREE.WebGLRenderer({antialias:true});
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  const controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.1;

  // Colors for faces: U, D, L, R, F, B
  const faceColors = {
    U: 0xffffff, // White
    D: 0xffff00, // Yellow
    L: 0xff8000, // Orange
    R: 0xff0000, // Red
    F: 0x00ff00, // Green
    B: 0x0000ff  // Blue
  };

  // Cubelets array
  let cubelets = [];

  // Size of each cubelet
  const cubeletSize = 1;
  const gap = 0.05;

  // Create materials for each face color
  function createFaceMaterials(position) {
    // position: THREE.Vector3 with x,y,z in -1,0,1
    // For each face, if cubelet is on that side, color it, else black
    const materials = [];

    // Order: +X, -X, +Y, -Y, +Z, -Z
    // Map to faces: R, L, U, D, F, B
    materials.push(new THREE.MeshBasicMaterial({color: (position.x === 1) ? faceColors.R : 0x000000}));
    materials.push(new THREE.MeshBasicMaterial({color: (position.x === -1) ? faceColors.L : 0x000000}));
    materials.push(new THREE.MeshBasicMaterial({color: (position.y === 1) ? faceColors.U : 0x000000}));
    materials.push(new THREE.MeshBasicMaterial({color: (position.y === -1) ? faceColors.D : 0x000000}));
    materials.push(new THREE.MeshBasicMaterial({color: (position.z === 1) ? faceColors.F : 0x000000}));
    materials.push(new THREE.MeshBasicMaterial({color: (position.z === -1) ? faceColors.B : 0x000000}));

    return materials;
  }

  // Create the 27 cubelets
  for(let x=-1; x<=1; x++) {
    for(let y=-1; y<=1; y++) {
      for(let z=-1; z<=1; z++) {
        const geometry = new THREE.BoxGeometry(cubeletSize, cubeletSize, cubeletSize);
        const materials = createFaceMaterials(new THREE.Vector3(x,y,z));
        const cubelet = new THREE.Mesh(geometry, materials);
        cubelet.position.set(
          x * (cubeletSize + gap),
          y * (cubeletSize + gap),
          z * (cubeletSize + gap)
        );
        cubelet.userData.cubePos = {x,y,z}; // track logical position
        scene.add(cubelet);
        cubelets.push(cubelet);
      }
    }
  }

  // Light
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
  scene.add(ambientLight);
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
  directionalLight.position.set(5,10,7);
  scene.add(directionalLight);

  // Helper function: get cubelets in a layer based on move
  // Moves: U, U', D, D', L, L', R, R', F, F', B, B'
  function getLayer(move) {
    switch(move[0]) {
      case 'U': return cubelets.filter(c => c.userData.cubePos.y === 1);
      case 'D': return cubelets.filter(c => c.userData.cubePos.y === -1);
      case 'L': return cubelets.filter(c => c.userData.cubePos.x === -1);
      case 'R': return cubelets.filter(c => c.userData.cubePos.x === 1);
      case 'F': return cubelets.filter(c => c.userData.cubePos.z === 1);
      case 'B': return cubelets.filter(c => c.userData.cubePos.z === -1);
    }
  }

  // Rotation axis for each move
  const axes = {
    U: new THREE.Vector3(0,1,0),
    D: new THREE.Vector3(0,-1,0),
    L: new THREE.Vector3(-1,0,0),
    R: new THREE.Vector3(1,0,0),
    F: new THREE.Vector3(0,0,1),
    B: new THREE.Vector3(0,0,-1)
  };

  // Rotate a layer by 90 degrees (clockwise or counterclockwise)
  // move: string like "U" or "U'"
  // Returns a Promise that resolves when rotation animation is done
  function rotateLayer(move) {
    return new Promise(resolve => {
      const clockwise = !move.includes("'");
      const face = move[0];
      const layer = getLayer(move);

      // Create a temporary group to rotate cubelets together
      const group = new THREE.Group();
      layer.forEach(cubelet => {
        THREE.SceneUtils.detach(cubelet, scene, group);
        group.add(cubelet);
      });
      scene.add(group);

      // Rotation axis
      let axis = axes[face].clone();
      if(!clockwise) axis.negate();

      // Animate rotation over 300ms
      let duration = 300;
      let elapsed = 0;
      function animateRotate(delta) {
        elapsed += delta;
        let t = Math.min(elapsed / duration, 1);
        group.rotation.set(0,0,0);
        group.rotateOnAxis(axis, t * Math.PI/2);
        if(t < 1) {
          requestAnimationFrame((time) => {
            let now = time || 0;
            animateRotate(16);
          });
        } else {
          // Finalize rotation
          group.rotation.set(0,0,0);
          group.rotateOnAxis(axis, Math.PI/2);

          // Detach cubelets back to scene and update logical positions
          layer.forEach(cubelet => {
            THREE.SceneUtils.detach(cubelet, group, scene);

            // Update cubelet.userData.cubePos based on rotation
            let pos = cubelet.userData.cubePos;
            let v = new THREE.Vector3(pos.x, pos.y, pos.z);

            // Rotate v around axis by +/- 90 degrees
            let angle = clockwise ? -Math.PI/2 : Math.PI/2; // Note: inverse direction for logical pos
            let matrix = new THREE.Matrix4().makeRotationAxis(axis, angle);
            v.applyMatrix4(matrix);

            // Round to nearest integer (-1,0,1)
            v.x = Math.round(v.x);
            v.y = Math.round(v.y);
            v.z = Math.round(v.z);

            cubelet.userData.cubePos = {x: v.x, y: v.y, z: v.z};

            // Snap position to grid
            cubelet.position.set(
              v.x * (cubeletSize + gap),
              v.y * (cubeletSize + gap),
              v.z * (cubeletSize + gap)
            );

            // Also rotate the cubelet's mesh to keep stickers oriented correctly
            // Rotate the cubelet mesh itself by +/- 90 degrees around axis
            cubelet.rotateOnWorldAxis(axis, clockwise ? Math.PI/2 : -Math.PI/2);
          });

          scene.remove(group);
          resolve();
        }
      }

      animateRotate(0);
    });
  }

  // Shuffle function: perform N random moves
  async function shuffleCube(movesCount=20) {
    const moves = ["U","U'","D","D'","L","L'","R","R'","F","F'","B","B'"];
    for(let i=0; i<movesCount; i++) {
      let move = moves[Math.floor(Math.random()*moves.length)];
      await rotateLayer(move);
    }
  }

  // Solve function: reset cube to solved state
  async function solveCube() {
    // For simplicity, just reset all cubelets to original positions and rotations
    cubelets.forEach(cubelet => {
      cubelet.userData.cubePos = {
        x: Math.round(cubelet.position.x / (cubeletSize + gap)),
        y: Math.round(cubelet.position.y / (cubeletSize + gap)),
        z: Math.round(cubelet.position.z / (cubeletSize + gap))
      };
      cubelet.position.set(
        cubelet.userData.cubePos.x * (cubeletSize + gap),
        cubelet.userData.cubePos.y * (cubeletSize + gap),
        cubelet.userData.cubePos.z * (cubeletSize + gap)
      );
      cubelet.rotation.set(0,0,0);
    });
  }

  // Animation loop
  function animate() {
    requestAnimationFrame(animate);
    controls.update();
    renderer.render(scene, camera);
  }
  animate();

  // UI event listeners
  document.getElementById('shuffleBtn').addEventListener('click', () => {
    shuffleCube(20);
  });

  document.getElementById('solveBtn').addEventListener('click', () => {
    solveCube();
  });

  document.querySelectorAll('#ui button[data-move]').forEach(button => {
    button.addEventListener('click', async () => {
      const move = button.getAttribute('data-move');
      await rotateLayer(move);
    });
  });

  // Handle window resize
  window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth/window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  });
</script>
</body>
</html>