Animation
Apple Watch Website in Framer
I recreated the Apple Watch website in Framer, using very little code (almost none). Feel free to remix this project and see for yourself how capable Framer is. Explore how far you can go with this tool in terms of building complex animations and effects.
Created by
About the resource
This website is 99% no-code. The only element that required code is the 3D render video that begins playing as you start scrolling down the page.
For this, I used the video component in Framer and applied a code override to it. I've provided the code below for you to copy and use in your projects.
Video scroll scrub override
You can also copy this code to create a code override from scratch in your project, which will enable the video to progress as you scroll down the website.
About the resource
This website is 99% no-code. The only element that required code is the 3D render video that begins playing as you start scrolling down the page.
For this, I used the video component in Framer and applied a code override to it. I've provided the code below for you to copy and use in your projects.
Video scroll scrub override
You can also copy this code to create a code override from scratch in your project, which will enable the video to progress as you scroll down the website.
About the resource
This website is 99% no-code. The only element that required code is the 3D render video that begins playing as you start scrolling down the page.
For this, I used the video component in Framer and applied a code override to it. I've provided the code below for you to copy and use in your projects.
Video scroll scrub override
You can also copy this code to create a code override from scratch in your project, which will enable the video to progress as you scroll down the website.
import type { ComponentType } from "react"
import { useState, useEffect } from "react"
import type { MotionValue, Transition } from "framer-motion"
import { useViewportScroll, useTransform } from "framer-motion"
import { gsap } from "gsap"
export function withScrolledProgress(Component): ComponentType {
const startY = 0
const distance = 6000
const endY = startY + distance
return (props) => {
const { scrollY } = useViewportScroll()
const progress = useTransform(scrollY, [startY, endY], [0, 1])
useEffect(() => {
const video = document.getElementById("video") as HTMLVideoElement
gsap.to(video, {
scrollTrigger: {
trigger: ".scroll-container",
start: "top top",
end: "bottom bottom",
scrub: 1,
markers: true,
},
keyframes: [
{ progress: 0 },
{ progress: 0.1 },
{ progress: 0.2 },
{ progress: 0.3 },
{ progress: 0.4 },
{ progress: 0.5 },
{ progress: 0.6 },
{ progress: 0.7 },
{ progress: 0.8 },
{ progress: 0.9 },
{ progress: 1 },
],
ease: "linear",
duration: 10,
})
return () => {
gsap.killTweensOf(video)
}
}, [scrollY, distance])
return <Component {...props} progress={progress} />
}
}
import type { ComponentType } from "react"
import { useState, useEffect } from "react"
import type { MotionValue, Transition } from "framer-motion"
import { useViewportScroll, useTransform } from "framer-motion"
import { gsap } from "gsap"
export function withScrolledProgress(Component): ComponentType {
const startY = 0
const distance = 6000
const endY = startY + distance
return (props) => {
const { scrollY } = useViewportScroll()
const progress = useTransform(scrollY, [startY, endY], [0, 1])
useEffect(() => {
const video = document.getElementById("video") as HTMLVideoElement
gsap.to(video, {
scrollTrigger: {
trigger: ".scroll-container",
start: "top top",
end: "bottom bottom",
scrub: 1,
markers: true,
},
keyframes: [
{ progress: 0 },
{ progress: 0.1 },
{ progress: 0.2 },
{ progress: 0.3 },
{ progress: 0.4 },
{ progress: 0.5 },
{ progress: 0.6 },
{ progress: 0.7 },
{ progress: 0.8 },
{ progress: 0.9 },
{ progress: 1 },
],
ease: "linear",
duration: 10,
})
return () => {
gsap.killTweensOf(video)
}
}, [scrollY, distance])
return <Component {...props} progress={progress} />
}
}
import type { ComponentType } from "react"
import { useState, useEffect } from "react"
import type { MotionValue, Transition } from "framer-motion"
import { useViewportScroll, useTransform } from "framer-motion"
import { gsap } from "gsap"
export function withScrolledProgress(Component): ComponentType {
const startY = 0
const distance = 6000
const endY = startY + distance
return (props) => {
const { scrollY } = useViewportScroll()
const progress = useTransform(scrollY, [startY, endY], [0, 1])
useEffect(() => {
const video = document.getElementById("video") as HTMLVideoElement
gsap.to(video, {
scrollTrigger: {
trigger: ".scroll-container",
start: "top top",
end: "bottom bottom",
scrub: 1,
markers: true,
},
keyframes: [
{ progress: 0 },
{ progress: 0.1 },
{ progress: 0.2 },
{ progress: 0.3 },
{ progress: 0.4 },
{ progress: 0.5 },
{ progress: 0.6 },
{ progress: 0.7 },
{ progress: 0.8 },
{ progress: 0.9 },
{ progress: 1 },
],
ease: "linear",
duration: 10,
})
return () => {
gsap.killTweensOf(video)
}
}, [scrollY, distance])
return <Component {...props} progress={progress} />
}
}