Iphone
Recreate the Apple iPhone 15 Pro website, combining GSAP animations and Three.js 3D effects. From custom animations to animated 3D models, this tutorial covers it all.
Install / Use
/learn @adrianhajdin/IphoneREADME
📋 <a name="table">Table of Contents</a>
- 🤖 Introduction
- ⚙️ Tech Stack
- 🔋 Features
- 🤸 Quick Start
- 🕸️ Snippets
- 🔗 Links
- 🚀 More
🚨 Tutorial
This repository contains the code corresponding to an in-depth tutorial available on our YouTube channel, <a href="https://www.youtube.com/@javascriptmastery/videos" target="_blank"><b>JavaScript Mastery</b></a>.
If you prefer visual learning, this is the perfect resource for you. Follow our tutorial to learn how to build projects like these step-by-step in a beginner-friendly manner!
<a href="https://youtu.be/kRQbRAJ4-Fs" target="_blank"><img src="https://github.com/sujatagunale/EasyRead/assets/151519281/1736fca5-a031-4854-8c09-bc110e3bc16d" /></a>
<a name="introduction">🤖 Introduction</a>
This is a clone of Apple's iPhone 15 Pro website using React.js and TailwindCSS. It highlights the effective use of GSAP (Greensock Animations) and Three.js for displaying iPhone 15 Pro models in various colors and shapes.
If you're getting started and need assistance or face any bugs, join our active Discord community with over 27k+ members. It's a place where people help each other out.
<a href="https://discord.com/invite/n6EdbFJ" target="_blank"><img src="https://github.com/sujatagunale/EasyRead/assets/151519281/618f4872-1e10-42da-8213-1d69e486d02e" /></a>
<a name="tech-stack">⚙️ Tech Stack</a>
- React.js
- Three.js
- React Three Fiber
- React Three Drei
- GSAP (Greensock)
- Vite
- Tailwind CSS
<a name="features">🔋 Features</a>
👉 Beautiful Subtle Smooth Animations using GSAP: Enhanced user experience with seamless and captivating animations powered by GSAP.
👉 3D Model Rendering with Different Colors and Sizes: Explore the iPhone 15 Pro from every angle with dynamic 3D rendering, offering various color and size options.
👉 Custom Video Carousel (made with GSAP): Engage users with a unique and interactive video carousel developed using GSAP for a personalized browsing experience.
👉 Completely Responsive: Consistent access and optimal viewing on any device with a fully responsive design that adapts to different screen sizes.
and many more, including code architecture and reusability
<a name="quick-start">🤸 Quick Start</a>
Follow these steps to set up the project locally on your machine.
Prerequisites
Make sure you have the following installed on your machine:
Cloning the Repository
git clone https://github.com/JavaScript-Mastery-Pro/iphone-doc.git
cd iphone-doc
Installation
Install the project dependencies using npm:
npm install
Running the Project
npm run dev
Open http://localhost:5173 in your browser to view the project.
<a name="snippets">🕸️ Snippets</a>
<details> <summary><code>tailwind.config.js</code></summary>/** @type {import('tailwindcss').Config} */
export default {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {
colors: {
blue: "#2997FF",
gray: {
DEFAULT: "#86868b",
100: "#94928d",
200: "#afafaf",
300: "#42424570",
},
zinc: "#101010",
},
},
},
plugins: [],
};
</details>
<details>
<summary><code>constants/index.js</code></summary>
import {
blackImg,
blueImg,
highlightFirstVideo,
highlightFourthVideo,
highlightSecondVideo,
highlightThirdVideo,
whiteImg,
yellowImg,
} from "../utils";
export const navLists = ["Store", "Mac", "iPhone", "Support"];
export const hightlightsSlides = [
{
id: 1,
textLists: [
"Enter A17 Pro.",
"Game‑changing chip.",
"Groundbreaking performance.",
],
video: highlightFirstVideo,
videoDuration: 4,
},
{
id: 2,
textLists: ["Titanium.", "So strong. So light. So Pro."],
video: highlightSecondVideo,
videoDuration: 5,
},
{
id: 3,
textLists: [
"iPhone 15 Pro Max has the",
"longest optical zoom in",
"iPhone ever. Far out.",
],
video: highlightThirdVideo,
videoDuration: 2,
},
{
id: 4,
textLists: ["All-new Action button.", "What will yours do?."],
video: highlightFourthVideo,
videoDuration: 3.63,
},
];
export const models = [
{
id: 1,
title: "iPhone 15 Pro in Natural Titanium",
color: ["#8F8A81", "#ffe7b9", "#6f6c64"],
img: yellowImg,
},
{
id: 2,
title: "iPhone 15 Pro in Blue Titanium",
color: ["#53596E", "#6395ff", "#21242e"],
img: blueImg,
},
{
id: 3,
title: "iPhone 15 Pro in White Titanium",
color: ["#C9C8C2", "#ffffff", "#C9C8C2"],
img: whiteImg,
},
{
id: 4,
title: "iPhone 15 Pro in Black Titanium",
color: ["#454749", "#3b3b3b", "#181819"],
img: blackImg,
},
];
export const sizes = [
{ label: '6.1"', value: "small" },
{ label: '6.7"', value: "large" },
];
export const footerLinks = [
"Privacy Policy",
"Terms of Use",
"Sales Policy",
"Legal",
"Site Map",
];
</details>
<details>
<summary><code>Lights.jsx</code></summary>
import { Environment, Lightformer } from "@react-three/drei";
const Lights = () => {
return (
// group different lights and lightformers. We can use group to organize lights, cameras, meshes, and other objects in the scene.
<group name="lights">
{/**
* @description Environment is used to create a background environment for the scene
* https://github.com/pmndrs/drei?tab=readme-ov-file#environment
*/}
<Environment resolution={256}>
<group>
{/**
* @description Lightformer used to create custom lights with various shapes and properties in a 3D scene.
* https://github.com/pmndrs/drei?tab=readme-ov-file#lightformer
*/}
<Lightformer
form="rect"
intensity={10}
position={[-1, 0, -10]}
scale={10}
color={"#495057"}
/>
<Lightformer
form="rect"
intensity={10}
position={[-10, 2, 1]}
scale={10}
rotation-y={Math.PI / 2}
/>
<Lightformer
form="rect"
intensity={10}
position={[10, 0, 1]}
scale={10}
rotation-y={Math.PI / 2}
/>
</group>
</Environment>
{/**
* @description spotLight is used to create a light source positioned at a specific point
* in the scene that emits light in a specific direction.
* https://threejs.org/docs/#api/en/lights/SpotLight
*/}
<spotLight
position={[-2, 10, 5]}
angle={0.15}
penumbra={1} // the penumbra is the soft edge of a shadow cast by a point light
decay={0} // the amount the light dims as it moves away from the source
intensity={Math.PI * 0.2} // the light intensity
color={"#f8f9fa"}
/>
<spotLight
position={[0, -25, 10]}
angle={0.15}
penumbra={1}
decay={0}
intensity={Math.PI * 0.2}
color={"#f8f9fa"}
/>
<spotLight
position={[0, 15, 5]}
angle={0.15}
penumbra={1}
decay={0.1}
intensity={Math.PI * 3}
/>
</group>
);
};
export default Lights;
</details>
<details>
<summary><code>materials</code></summary>
useEffect(() => {
Object.entries(materials).map((material) => {
// these are the material names that can't be changed color
if (
material[0] !== "zFdeDaGNRwzccye" &&
material[0] !== "ujsvqBWRMnqdwPx" &&
material[0] !== "hUlRcbieVuIiOXG" &&
material[0] !== "jlzuBkUzuJqgiAK" &&
material[0] !== "xNrofRCqOXXHVZt"
) {
material[1].color = new THREE.Color(props.item.color[0]);
}
material[1].needsUpdate = true;
});
}, [materials, props.item]);
</details>
<details>
<summary><code>VideoCarousel.jsx</code></summary>
import gsap from "gsap";
import { useGSAP } from "@gsap/react";
import { ScrollTrigger } from "gsap/all";
gsap.registerPlugin(ScrollTrigger);
import { useEffect, useRef, useState } from "react";
import { hightlightsSlides } from "../constants";
import { pauseImg, playImg, replayImg } from "../utils";
const VideoCarousel = () => {
const videoRef = useRef([]);
const videoSpanRef = useRef([]);
const videoDivRef = useRef([]);
// video and indicator
const [video, setVideo] = useState({
isEnd: false,
startPlay: false,
videoId: 0,
isLastVideo: false,
isPlay
