├── .eslintrc.json ├── .gitignore ├── README.md ├── jsconfig.json ├── next.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── next.svg ├── thirteen.svg └── vercel.svg └── src ├── components ├── Footer.js ├── Hero.js └── ScrollSection.js ├── pages ├── _app.js ├── _document.js ├── about.js ├── api │ └── hello.js └── index.js └── styles └── globals.css /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Next.js Horizontal Scroll With Gsap ScrollTrigger 2 | 3 | Repository of the [YouTube video](https://youtu.be/PeFqGrEHnp0) on how to develop a horizontal scroll section using Next.js and Gsap ScrollTrigger. 4 | 5 | ## Stack used 6 | 7 | - Next.js 8 | - Gsap Scrolltrigger 9 | - CSS 10 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@/*": ["./src/*"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next-gsap-scroll", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@next/font": "13.1.6", 13 | "eslint": "8.34.0", 14 | "eslint-config-next": "13.1.6", 15 | "gsap": "^3.11.4", 16 | "next": "13.1.6", 17 | "react": "18.2.0", 18 | "react-dom": "18.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IvanSmiths/next-gsap-scroll/6f657937f66497d7d89d3993c4c5a8cdbf238ad4/public/favicon.ico -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/thirteen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function Footer() { 4 | return ( 5 | 8 | ); 9 | } 10 | 11 | export default Footer; 12 | -------------------------------------------------------------------------------- /src/components/Hero.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function Hero() { 4 | return ( 5 |
6 |

John Doe

7 |

Frontend Developer

8 |
9 | ); 10 | } 11 | 12 | export default Hero; 13 | -------------------------------------------------------------------------------- /src/components/ScrollSection.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect } from "react"; 2 | import { gsap } from "gsap"; 3 | import { ScrollTrigger } from "gsap/dist/ScrollTrigger"; 4 | 5 | 6 | function ScrollSection() { 7 | const sectionRef = useRef(null); 8 | const triggerRef = useRef(null); 9 | 10 | gsap.registerPlugin(ScrollTrigger); 11 | 12 | useEffect(() => { 13 | const pin = gsap.fromTo( 14 | sectionRef.current, 15 | { 16 | translateX: 0, 17 | }, 18 | { 19 | translateX: "-300vw", 20 | ease: "none", 21 | duration: 1, 22 | scrollTrigger: { 23 | trigger: triggerRef.current, 24 | start: "top top", 25 | end: "2000 top", 26 | scrub: 0.6, 27 | pin: true, 28 | }, 29 | } 30 | ); 31 | return () => { 32 | {/* A return function for killing the animation on component unmount */ } 33 | pin.kill(); 34 | }; 35 | }, []); 36 | 37 | return ( 38 |
39 | {/* The section up act just as a wrapper. If the trigger (below) is the 40 | first jsx element in the component, you get an error on route change */} 41 | 42 | {/* The div below act just as a trigger. As the doc suggests, the trigger and 43 | the animation should alway be two separated refs */} 44 |
45 |
46 |
47 |

Section 1

48 |
49 |
50 |

Section 2

51 |
52 |
53 |

Section 3

54 |
55 |
56 |

Section 4

57 |
58 |
59 |
60 |
61 | ); 62 | } 63 | 64 | export default ScrollSection; 65 | -------------------------------------------------------------------------------- /src/pages/_app.js: -------------------------------------------------------------------------------- 1 | import '@/styles/globals.css' 2 | 3 | export default function App({ Component, pageProps }) { 4 | return 5 | } 6 | -------------------------------------------------------------------------------- /src/pages/_document.js: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from 'next/document' 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/about.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function about() { 4 | return
about
; 5 | } 6 | 7 | export default about; 8 | -------------------------------------------------------------------------------- /src/pages/api/hello.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | export default function handler(req, res) { 4 | res.status(200).json({ name: 'John Doe' }) 5 | } 6 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import Footer from "@/components/Footer"; 2 | import Hero from "@/components/Hero"; 3 | import ScrollSection from "@/components/ScrollSection"; 4 | 5 | export default function Home() { 6 | return ( 7 | <> 8 | 9 | 10 |