It’s time to make your website come alive! In this milestone, you’ll animate your 3D dog with movement and gestures based on scroll position — and let users interact with it through fun buttons.


✅ What You'll Do


🧠 Step 1: Responsive Animation Based on Scroll

The model’s position and rotation will change depending on the section the user scrolls to. First, add this logic to your app.js:

// Responsive position arrays
const getPositionArray = () => {
  const isMobile = window.innerWidth <= 767;
  const isTablet = window.innerWidth <= 1023 && window.innerWidth > 767;

  if (isMobile) {
    return [
      {
        id: "banner",
        position: { x: 0, y: -20, z: 0 },
        rotation: { x: 0, y: 0, z: 0 },
        animation: ["clip3"],
      },
      {
        id: "intro",
        position: { x: -10, y: -1, z: -3 },
        rotation: { x: 0.3, y: -0.3, z: 0 },
        animation: ["clip3"],
      },
      {
        id: "description",
        position: { x: 0, y: -1, z: -3 },
        rotation: { x: 0, y: 0.3, z: 0 },
        animation: ["clip3"],
      },
      {
        id: "playground",
        position: { x: 0, y: -15, z: -3 },
        rotation: { x: 0, y: 0, z: 0 },
        animation: ["clip4"],
      },
    ];
  } else if (isTablet) {
    return [
      {
        id: "banner",
        position: { x: 15, y: -20, z: 0 },
        rotation: { x: 0, y: 0, z: 0 },
        animation: ["clip3"],
      },
      {
        id: "intro",
        position: { x: -15, y: -1, z: -4 },
        rotation: { x: 0.4, y: -0.4, z: 0 },
        animation: ["clip3"],
      },
      {
        id: "description",
        position: { x: -1, y: -1, z: -4 },
        rotation: { x: 0, y: 0.4, z: 0 },
        animation: ["clip3"],
      },
      {
        id: "playground",
        position: { x: 0, y: -18, z: -4 },
        rotation: { x: 0, y: 0, z: 0 },
        animation: ["clip4"],
      },
    ];
  } else {
    return [
      {
        id: "banner",
        position: { x: 20, y: -20, z: 0 },
        rotation: { x: 0, y: 0, z: 0 },
        animation: ["clip3"],
      },
      {
        id: "intro",
        position: { x: -20, y: -1, z: -5 },
        rotation: { x: 0.5, y: -0.5, z: 0 },
        animation: ["clip3"],
      },
      {
        id: "description",
        position: { x: -1, y: -1, z: -5 },
        rotation: { x: 0, y: 0.5, z: 0 },
        animation: ["clip3"],
      },
      {
        id: "playground",
        position: { x: 0, y: 20, z: 0 },
        rotation: { x: 0, y: 0, z: 0 },
        animation: ["clip4"],
      },
    ];
  }
};

// Model movement function
const modelMove = () => {
  const sections = document.querySelectorAll(".section");
  let currentSection;

  sections.forEach((section) => {
    const rect = section.getBoundingClientRect();
    if (rect.top <= window.innerHeight / 3) {
      currentSection = section.id;
    }
  });

  const arrPositionModel = getPositionArray();
  let position_active = arrPositionModel.findIndex(
    (val) => val.id === currentSection
  );

  if (position_active >= 0) {
    let target = arrPositionModel[position_active];

    // Move model with GSAP
    gsap.to(dog.position, {
      x: target.position.x,
      y: target.position.y,
      z: target.position.z,
      duration: 3,
      ease: "power1.out",
    });

    gsap.to(dog.rotation, {
      x: target.rotation.x,
      y: target.rotation.y,
      z: target.rotation.z,
      duration: 3,
      ease: "power1.out",
    });

    // Switch animation
    if (
      mixer &&
      actions[target.animation] &&
      currentAction !== actions[target.animation]
    ) {
      if (currentAction) {
        currentAction.fadeOut(0.5);
      }
      currentAction = actions[target.animation];
      currentAction.reset().fadeIn(0.5).play();
    }
  }
};

window.addEventListener("scroll", () => {
  if (dog) modelMove();
});


🐾 Step 2: Button Interactions

Let users click buttons to trigger custom animations. This is how you hook up the dog’s tricks:

// Button interactions
const changeAnimation = (animationName) => {
  if (
    mixer &&
    actions[animationName] &&
    currentAction !== actions[animationName]
  ) {
    if (currentAction) {
      currentAction.fadeOut(0.5);
    }
    currentAction = actions[animationName];
    currentAction.reset().fadeIn(0.5).play();

    // Auto-revert after 5 seconds
    setTimeout(() => {
      currentAction.fadeOut(0.5);
      currentAction = actions["clip4"];
      currentAction.reset().fadeIn(0.5).play();
    }, 5000);
  }
};

// Event listeners
document
  .getElementById("bang")
  .addEventListener("click", () => changeAnimation("clip0"));
document
  .getElementById("paw")
  .addEventListener("click", () => changeAnimation("clip2"));
document
  .getElementById("roll")
  .addEventListener("click", () => changeAnimation("clip1"));
document
  .getElementById("sit")
  .addEventListener("click", () => changeAnimation("clip3"));

🖱️ Step 3: Final Touches

Make your model responsive and interactive:


window.addEventListener("resize", () => {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  if (dog) modelMove();
});