Crazy Ones & Framer Motion

3 min read

I have an awesome typographical poster on my wall made up from Apple's iconic Think Different Commercial...

crazy ones poster

I've had this for so long I cant even remember where it came from but I really love the styles and the way it's put together. I decided it would be cool to try and recreate it using Framer Motion and React.

The Result

This short video showcases the scrolling effects on the poster, with various animations triggered based on the scroll position.

You can check out the demo here.

Framer Motion useScroll

Framer Motion is a popular animation library for React applications that makes it easy to create fluid animations and interactions. The useScroll hook allows you to manipulate elements based on the user's scroll position.

Basic Example

First, we need to set up a basic page with a few inline styles and imports:

import { useRef } from "react";
import { motion, useScroll } from "framer-motion";
 
export default function App() {
  return (
    <div
      style={{
        fontFamily: "sans-serif",
        marginBottom: "1000px",
      }}
    >
      <div
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          height: "100vh",
          margin: "0 auto",
          textAlign: "center",
        }}
      >
        <h1 style={{ fontSize: "32px" }}>Scroll down</h1>
      </div>
    </div>
  );
}

We intentionally set the container to 100vh and add a large bottom margin to create more scrollable area.

Next, let's create a simple component that will scale based on the scroll position:

const BoxScale = () => {
  const ref = React.useRef(null);
  const { scrollYProgress } = useScroll({ target: ref });
  const scale = useTransform(scrollYProgress, [0, 1], [1, 0]);
 
  return (
    <section
      style={{
        height: "100vh",
      }}
    >
      <motion.div
        ref={ref}
        style={{
          width: "150px",
          height: "150px",
          borderRadius: "1em",
          backgroundColor: "#77037B",
          marginLeft: "auto",
          marginRight: "auto",
          x: -50,
          scale,
        }}
      />
    </section>
  );
};
  • useScroll This hook allows us to access the page's scroll position. We specifically set a target to track the progress of this element in the viewport. Check out the docs here.
  • useTransform This helper function enables us to map a value from one range to another. In this case, we are simply mapping the scroll progress from 0 to 1 to a scale value from 1 to 0 .Check out the docs here.

Another Example

Let's create another box that will move along the x-axis as the page scrolls:

const BoxXPos = () => {
  const ref = React.useRef(null);
  const { scrollYProgress } = useScroll({ target: ref });
  const translateX = useTransform(
    scrollYProgress,
    [0, 0.5, 1],
    ["-100%", "0%", "100%"]
  );
 
  return (
    <section
      style={{
        height: "100vh",
      }}
    >
      <motion.div
        ref={ref}
        style={{
          width: "150px",
          height: "150px",
          borderRadius: "1em",
          backgroundColor: "#009FBD",
          marginLeft: "auto",
          marginRight: "auto",
          translateX,
        }}
      />
    </section>
  );
};

Similar to the previous example, we use useScroll to track the scroll position and then employ useTransform to map the scroll progress to a translateX value that we pass to the box.

Code Sandbox

Feel free to explore and modify the code provided in this CodeSandbox.

Crazy Ones Example

And if you'd like to play with the Crazy Ones SVG I made, wwhich extends the principles discussed above, you can check out the playground here.