├── public ├── robots.txt ├── scene.glb ├── favicon.ico ├── scene-black.glb ├── manifest.json ├── logo.svg └── vite.svg ├── src ├── assets │ ├── images │ │ ├── iphone-14.jpg │ │ ├── iphone-hand.png │ │ ├── logo-animated.gif │ │ ├── search.svg │ │ ├── store.svg │ │ └── logo.svg │ └── react.svg ├── main.jsx ├── components │ ├── Loader.jsx │ ├── DisplaySection.jsx │ ├── SoundSection.jsx │ ├── Jumbotron.jsx │ ├── Nav.jsx │ └── WebgiViewer.jsx ├── App.jsx ├── lib │ └── scroll-animation.js └── index.css ├── vite.config.js ├── .gitignore ├── index.html ├── README.md └── package.json /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/scene.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SamarthHChinivar/iPhone-14-Pro-Landing-Page/HEAD/public/scene.glb -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SamarthHChinivar/iPhone-14-Pro-Landing-Page/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/scene-black.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SamarthHChinivar/iPhone-14-Pro-Landing-Page/HEAD/public/scene-black.glb -------------------------------------------------------------------------------- /src/assets/images/iphone-14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SamarthHChinivar/iPhone-14-Pro-Landing-Page/HEAD/src/assets/images/iphone-14.jpg -------------------------------------------------------------------------------- /src/assets/images/iphone-hand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SamarthHChinivar/iPhone-14-Pro-Landing-Page/HEAD/src/assets/images/iphone-hand.png -------------------------------------------------------------------------------- /src/assets/images/logo-animated.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SamarthHChinivar/iPhone-14-Pro-Landing-Page/HEAD/src/assets/images/logo-animated.gif -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')).render() 7 | -------------------------------------------------------------------------------- /src/components/Loader.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import AnimatedLogo from '../assets/images/logo-animated.gif' 3 | const Loader = () => { 4 | return ( 5 |
6 | Apple Loader 7 |
8 | ) 9 | } 10 | 11 | export default Loader -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/assets/images/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | iPhone 14 Pro Landing Page 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/assets/images/store.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/DisplaySection.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const DisplaySection = ({triggerPreview}) => { 4 | 5 | const handleScrollToTop = () => { 6 | window.scrollTo({top: 0, left: 0, behavior: 'smooth'}); 7 | }; 8 | 9 | return ( 10 |
11 |

New

12 |

Brilliant.

13 | 14 | A display that's up to 2x brighter in the sun. 15 | 16 | 17 | 18 | 19 |
20 | ) 21 | } 22 | 23 | export default DisplaySection -------------------------------------------------------------------------------- /src/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iPhone 14 Pro Landing Page 2 | - The website is similar to the Apple iPhone 14’s landing page, which is built using React.js, WebGi, Three.js, and GSAP ScrollTrigger. 3 | - Experience this website LIVE 4 | 5 | ![iPhone14Pro-1](https://github.com/SamarthHChinivar/iPhone-14-Pro-Landing-Page/assets/104615876/4ed560b8-0581-4088-bda1-2204a7bd78db) 6 |


7 | ![iPhone14Pro-2](https://github.com/SamarthHChinivar/iPhone-14-Pro-Landing-Page/assets/104615876/fbfcefce-2432-46df-a574-9819a7855d1c) 8 |


9 | ![iPhone14Pro-3](https://github.com/SamarthHChinivar/iPhone-14-Pro-Landing-Page/assets/104615876/a688751d-eee3-497b-8f5a-09453d44241b) 10 |


11 | ![iPhone14Pro-4](https://github.com/SamarthHChinivar/iPhone-14-Pro-Landing-Page/assets/104615876/1a29270a-d94e-4495-9c9e-1742dfc25ce4) 12 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import Nav from './components/Nav' 2 | import Jumbotron from './components/Jumbotron' 3 | import SoundSection from './components/SoundSection' 4 | import DisplaySection from './components/DisplaySection' 5 | import WebgiViewer from './components/WebgiViewer' 6 | import Loader from './components/Loader' 7 | import { useRef } from 'react' 8 | 9 | function App() { 10 | const webgiViewerRef = useRef(); 11 | const contentRef = useRef(); 12 | 13 | const handlePreview = () => { 14 | webgiViewerRef.current.triggerPreview(); 15 | } 16 | 17 | return ( 18 |
19 | 20 |
21 |
26 | 27 | 28 |
29 | ); 30 | } 31 | 32 | export default App; -------------------------------------------------------------------------------- /src/components/SoundSection.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const SoundSection = () => { 4 | 5 | const handleLearnMore = () => { 6 | const element = document.querySelector('.display-section'); 7 | window.scrollTo({ 8 | top: element?.getBoundingClientRect().bottom, 9 | left: 0, 10 | behavior: 'smooth' 11 | }); 12 | }; 13 | 14 | return ( 15 |
16 |
17 |
18 |

New Sound System

19 |

Feel the base.

20 | 21 | From $41.62/mo. for 24 mo. or $999 before trade-in 22 | 23 | 24 |
    25 |
  • 26 | 27 |
  • 28 | 29 |
  • 30 | Learn more 31 |
  • 32 |
33 |
34 |
35 |
36 | ); 37 | } 38 | 39 | export default SoundSection -------------------------------------------------------------------------------- /src/components/Jumbotron.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Iphone from '../assets/images/iphone-14.jpg' 3 | import HoldingIphone from '../assets/images/iphone-hand.png' 4 | 5 | const Jumbotron = () => { 6 | const handleLearnMore = () => { 7 | const element = document.querySelector('.sound-section'); 8 | window.scrollTo({ 9 | top: element?.getBoundingClientRect().top, 10 | left:0, 11 | behavior: 'smooth' 12 | }); 13 | }; 14 | 15 | return ( 16 |
17 |

New

18 | iPhone 14 Pro 19 |

Big and bigger.

20 | 21 | From $41.62/mo. for 24 mo. or $999 before trade-in 22 | 23 | 24 | 33 | 34 | iPhone 35 |
36 | ) 37 | } 38 | 39 | export default Jumbotron -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-react-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0", 14 | "@studio-freight/lenis": "^0.2.28", 15 | "@testing-library/jest-dom": "^5.16.5", 16 | "@testing-library/react": "^13.4.0", 17 | "@testing-library/user-event": "^13.5.0", 18 | "@types/three": "^0.139.0", 19 | "@types/webgi": "https://storage.googleapis.com/dist.pixotronics.com/webgi/runtime/bundle-types-0.5.5.tgz", 20 | "gsap": "^3.11.4", 21 | "postcss-flexbugs-fixes": "^5.0.2", 22 | "postcss-normalize": "^10.0.1", 23 | "postcss-preset-env": "^8.0.1", 24 | "web-vitals": "^2.1.4", 25 | "webgi": "https://storage.googleapis.com/dist.pixotronics.com/webgi/runtime/bundle-0.5.8.tgz" 26 | }, 27 | "devDependencies": { 28 | "@types/react": "^18.0.27", 29 | "@types/react-dom": "^18.0.10", 30 | "@vitejs/plugin-react": "^3.1.0", 31 | "vite": "^4.1.0", 32 | "@types/three": "^0.139.0", 33 | "@types/webgi": "https://storage.googleapis.com/dist.pixotronics.com/webgi/runtime/bundle-types-0.5.5.tgz", 34 | "cross-env": "^7.0.3", 35 | "webgi": "https://storage.googleapis.com/dist.pixotronics.com/webgi/runtime/bundle-0.5.5.tgz" 36 | } 37 | } -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/lib/scroll-animation.js: -------------------------------------------------------------------------------- 1 | import gsap from "gsap"; 2 | 3 | export const scrollAnimation = (position, target, isMobile, onUpdate) => { 4 | const ti = gsap.timeline(); 5 | ti.to(position, { 6 | x: !isMobile ? -3.38 : -7.0, 7 | y: !isMobile ? -10.74 : -12.2, 8 | z: !isMobile ? -5.93 : -6.0, 9 | scrollTrigger: { 10 | trigger: ".sound-section", 11 | start: "top bottom", 12 | end: "top top", 13 | scrub: 2, 14 | immediateRender: false, 15 | }, 16 | onUpdate, 17 | }) 18 | .to(target, { 19 | x: !isMobile ? 1.52 : 0.7, 20 | y: !isMobile ? 0.77 : 1.9, 21 | z: !isMobile ? -1.08 : 0.7, 22 | scrollTrigger: { 23 | trigger: ".sound-section", 24 | start: "top bottom", 25 | end: "top top", 26 | scrub: 2, 27 | immediateRender: false, 28 | }, 29 | }) 30 | .to(".jumbotron-section", { 31 | opacity: 0, 32 | scrollTrigger: { 33 | trigger: ".sound-section", 34 | start: "top bottom", 35 | end: "top top", 36 | scrub: 2, 37 | immediateRender: false, 38 | }, 39 | }) 40 | .to(".sound-section-content", { 41 | opacity: 1, 42 | scrollTrigger: { 43 | trigger: ".sound-section", 44 | start: "top bottom", 45 | end: "top top", 46 | scrub: 2, 47 | immediateRender: false, 48 | }, 49 | }) 50 | .to(position, { 51 | x: !isMobile ? 1.56 : 9.36, 52 | y: !isMobile ? 5.0 : 10.95, 53 | z: !isMobile ? 0.01 : 0.09, 54 | scrollTrigger: { 55 | trigger: ".display-section", 56 | start: "top bottom", 57 | end: "top top", 58 | scrub: 2, 59 | immediateRender: false, 60 | }, 61 | onUpdate, 62 | }) 63 | .to(target, { 64 | x: !isMobile ? -0.55 : -1.62, 65 | y: !isMobile ? 0.32 : 0.02, 66 | z: !isMobile ? 0.0 : -0.06, 67 | scrollTrigger: { 68 | trigger: ".display-section", 69 | start: "top bottom", 70 | end: "top top", 71 | scrub: 2, 72 | immediateRender: false, 73 | }, 74 | }) 75 | .to(".display-section", { 76 | opacity: 1, 77 | scrollTrigger: { 78 | trigger: ".display-section", 79 | start: "top bottom", 80 | end: "top top", 81 | scrub: 2, 82 | immediateRender: false, 83 | }, 84 | }); 85 | }; -------------------------------------------------------------------------------- /src/components/Nav.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Logo from '../assets/images/logo.svg' 3 | import Search from '../assets/images/search.svg' 4 | import Store from '../assets/images/store.svg' 5 | 6 | const Nav = () => { 7 | return ( 8 | 71 | ) 72 | } 73 | 74 | export default Nav -------------------------------------------------------------------------------- /src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/WebgiViewer.jsx: -------------------------------------------------------------------------------- 1 | import React, { 2 | useRef, 3 | useState, 4 | useCallback, 5 | forwardRef, 6 | useImperativeHandle, 7 | useEffect 8 | } from 'react' 9 | 10 | import { 11 | ViewerApp, 12 | AssetManagerPlugin, 13 | GBufferPlugin, 14 | ProgressivePlugin, 15 | TonemapPlugin, 16 | SSRPlugin, 17 | SSAOPlugin, 18 | BloomPlugin, 19 | GammaCorrectionPlugin, 20 | addBasePlugins, 21 | CanvasSnipperPlugin, 22 | mobileAndTabletCheck 23 | } from "webgi" 24 | 25 | import gsap from 'gsap' 26 | 27 | import {ScrollTrigger} from 'gsap/ScrollTrigger' 28 | 29 | import { scrollAnimation } from '../lib/scroll-animation'; 30 | 31 | gsap.registerPlugin(ScrollTrigger); 32 | 33 | //Implementing and Caching 3D Model with help of WebGI 34 | const WebgiViewer = forwardRef((props,ref) => { 35 | 36 | const canvasRef = useRef(null); 37 | const [viewerRef, setViewerRef] = useState(null); 38 | const [targetRef, setTargetRef] = useState(null); 39 | const [cameraRef, setCameraRef] = useState(null); 40 | const [positionRef, setPositionRef] = useState(null); 41 | const canvasContainerRef = useRef(null); 42 | const [previewMode, setPreviewMode] = useState(false); 43 | const [isMobile, setIsMobile] = useState(null); 44 | 45 | useImperativeHandle(ref, () => ({ 46 | triggerPreview() { 47 | setPreviewMode(true); 48 | canvasContainerRef.current.style.pointerEvents = "all"; 49 | props.contentRef.current.style.opacity = 0; 50 | 51 | gsap.to(positionRef, { 52 | x: 13.04, 53 | y: -2.01, 54 | z: 2.29, 55 | duration: 2, 56 | onUpdate: () => { 57 | viewerRef.setDirty(); 58 | cameraRef.positionTargetUpdated(true); 59 | }, 60 | }); 61 | 62 | gsap.to(targetRef, {x: 0.11, y: 0.0, z:0.0, duration: 2}); 63 | 64 | viewerRef.scene.activeCamera.setCameraOptions({controlsEnabled: true}); 65 | }, 66 | })); 67 | 68 | const memoizedScrollAnimation = useCallback( 69 | (position, target, isMobile , onUpdate) => { 70 | if(position && target && onUpdate) { 71 | scrollAnimation(position, target, isMobile, onUpdate); 72 | } 73 | }, [] 74 | ); 75 | 76 | const setupViewer = useCallback(async () => { 77 | // Initialize the viewer 78 | const viewer = new ViewerApp({ 79 | canvas: canvasRef.current, 80 | }); 81 | 82 | setViewerRef(viewer); 83 | const isMobileOrTablet = mobileAndTabletCheck(); 84 | setIsMobile(isMobileOrTablet); 85 | 86 | // Add some plugins 87 | const manager = await viewer.addPlugin(AssetManagerPlugin); 88 | 89 | const camera = viewer.scene.activeCamera; 90 | const position = camera.position; 91 | const target = camera.target; 92 | 93 | setCameraRef(camera); 94 | setPositionRef(position); 95 | setTargetRef(target); 96 | 97 | // Add a popup(in HTML) with download progress when any asset is downloading. 98 | // await viewer.addPlugin(AssetManagerBasicPopupPlugin) 99 | 100 | // Add plugins individually. 101 | await viewer.addPlugin(GBufferPlugin); 102 | await viewer.addPlugin(new ProgressivePlugin(32)); 103 | await viewer.addPlugin(new TonemapPlugin(true)); 104 | await viewer.addPlugin(GammaCorrectionPlugin); 105 | await viewer.addPlugin(SSRPlugin); 106 | await viewer.addPlugin(SSAOPlugin); 107 | await viewer.addPlugin(BloomPlugin); 108 | 109 | // or use this to add all main ones at once. 110 | // await addBasePlugins(viewer); 111 | 112 | // Add more plugins not available in base, like CanvasSnipperPlugin which has helpers to download an image of the canvas. 113 | // await viewer.addPlugin(CanvasSnipperPlugin); 114 | 115 | // This must be called once after all plugins are added. 116 | viewer.renderer.refreshPipeline() 117 | 118 | // Import and add a GLB file. 119 | await manager.addFromPath("scene-black.glb"); 120 | 121 | viewer.getPlugin(TonemapPlugin).config.clipBackground = true; 122 | 123 | viewer.scene.activeCamera.setCameraOptions({controlsEnabled: false}); 124 | 125 | if(isMobileOrTablet){ 126 | position.set(-16.7, 1.17, 11.7); 127 | target.set(0.0, 1.37, 0.0); 128 | props.contentRef.current.className = "mobile-or-tablet"; 129 | } 130 | 131 | window.scrollTo(0, 0); 132 | 133 | let needsUpdate = true; 134 | const onUpdate = () => { 135 | needsUpdate = true; 136 | viewer.setDirty(); 137 | }; 138 | 139 | viewer.addEventListener('preFrame', () => { 140 | if(needsUpdate) { 141 | camera.positionTargetUpdated(true); 142 | needsUpdate = false; 143 | } 144 | }); 145 | 146 | memoizedScrollAnimation(position, target, isMobileOrTablet, onUpdate); 147 | 148 | }, []); 149 | 150 | useEffect(() => { 151 | setupViewer(); 152 | }, []); 153 | 154 | const handleExit = useCallback(() => { 155 | canvasContainerRef.current.style.pointerEvents = "none"; 156 | props.contentRef.current.style.opacity = 1; 157 | viewerRef.scene.activeCamera.setCameraOptions({controlsEnabled: false}); 158 | setPreviewMode(false); 159 | 160 | gsap.to(positionRef, { 161 | x:!isMobile ? 1.56: 9.36, 162 | y:!isMobile ? 5.0: 10.95, 163 | z:!isMobile ? 0.01: 0.09, 164 | scrollTrigger: { 165 | trigger: '.display-section', 166 | start: 'top botttom', 167 | end: 'top top', 168 | scrub: 2, 169 | immediateRender: false 170 | }, 171 | onUpdate: () => { 172 | viewerRef.setDirty(); 173 | cameraRef.positionTargetUpdated(true); 174 | }, 175 | }); 176 | 177 | gsap.to(targetRef, { 178 | x: !isMobile ? -0.55: -1.62, 179 | y: !isMobile ? 0.32: 0.02, 180 | z: !isMobile ? 0.0: -0.06, 181 | scrollTrigger: { 182 | trigger: '.display-section', 183 | start: 'top botttom', 184 | end: 'top top', 185 | scrub: 2, 186 | immediateRender: false 187 | }, 188 | }); 189 | }, [canvasContainerRef, viewerRef, positionRef, cameraRef, targetRef]); 190 | 191 | return ( 192 |
193 | 194 | { 195 | previewMode && ( 196 | 197 | ) 198 | } 199 |
200 | ); 201 | }); 202 | 203 | export default WebgiViewer -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.cdnfonts.com/css/sf-pro-display"); 2 | 3 | body { 4 | margin: 0; 5 | font-family: "SF Pro Display", SF Pro Icons, Helvetica Neue, Helvetica, Arial, 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | background-color: #000; 10 | color: #f5f5f7; 11 | } 12 | 13 | code { 14 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 15 | monospace; 16 | } 17 | 18 | body::-webkit-scrollbar-track { 19 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 20 | border-radius: 10px; 21 | background-color: #f5f5f5; 22 | } 23 | 24 | body::-webkit-scrollbar { 25 | width: 12px; 26 | background-color: #aaaaaa; 27 | } 28 | 29 | body::-webkit-scrollbar-thumb { 30 | border-radius: 10px; 31 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 32 | background-color: #555; 33 | } 34 | 35 | .App #content { 36 | transition-duration: 0.3s; 37 | } 38 | 39 | #webgi-canvas { 40 | width: 100%; 41 | height: 100%; 42 | background: transparent; 43 | } 44 | 45 | #webgi-canvas-container { 46 | width: 100vw; 47 | height: 100vh; 48 | position: fixed; 49 | display: flex; 50 | justify-content: flex-end; 51 | flex-direction: column; 52 | align-items: center; 53 | top: 0; 54 | pointer-events: none; 55 | min-height: 831px; 56 | background: transparent; 57 | } 58 | 59 | #webgi-canvas-container .button { 60 | background: #0071e3; 61 | color: #fff; 62 | cursor: pointer; 63 | text-align: center; 64 | white-space: nowrap; 65 | font-size: 17px; 66 | font-weight: 400; 67 | min-width: 28px; 68 | padding: 8px 16px; 69 | border-radius: 980px; 70 | position: absolute; 71 | top: 30px; 72 | border: none; 73 | z-index: 1; 74 | transition-duration: 0.3s; 75 | } 76 | 77 | .display-section.wrapper { 78 | margin-left: auto; 79 | margin-right: auto; 80 | max-width: 980px; 81 | width: 100%; 82 | display: flex; 83 | align-items: center; 84 | flex-direction: column; 85 | padding: 50px 0 400px 0; 86 | height: 100vh; 87 | box-sizing: border-box; 88 | opacity: 0; 89 | position: relative; 90 | } 91 | 92 | .display-section .title { 93 | color: #86868b; 94 | font-size: 17px; 95 | font-weight: 400; 96 | letter-spacing: -0.022em; 97 | margin-bottom: 0; 98 | } 99 | 100 | .display-section .text { 101 | display: inline-block; 102 | color: transparent; 103 | background-image: linear-gradient(180deg, #ffb6ff, #b344ff); 104 | -webkit-background-clip: text; 105 | background-clip: text; 106 | padding-top: 0.5px; 107 | margin-top: 16px; 108 | font-size: 48px; 109 | font-weight: 600; 110 | margin-bottom: 18px; 111 | } 112 | 113 | .display-section .description { 114 | font-size: 21px; 115 | font-weight: 400; 116 | } 117 | 118 | .display-section .button { 119 | background: #0071e3; 120 | color: #fff; 121 | cursor: pointer; 122 | display: inline-block; 123 | text-align: center; 124 | white-space: nowrap; 125 | font-size: 17px; 126 | font-weight: 400; 127 | min-width: 28px; 128 | padding: 8px 16px; 129 | border-radius: 980px; 130 | margin: 15px; 131 | } 132 | 133 | .display-section .back-button { 134 | background: white; 135 | color: black; 136 | border: none; 137 | border-radius: 50px; 138 | padding: 10px 30px; 139 | font-size: 0.6rem; 140 | cursor: pointer; 141 | transition: all 0.8s ease; 142 | position: fixed; 143 | bottom: 10px; 144 | right: 10px; 145 | } 146 | 147 | nav.nav-wrapper { 148 | margin: 0; 149 | width: 100%; 150 | min-width: 320px; 151 | height: 48px; 152 | max-height: 44px; 153 | font-size: 17px; 154 | background-color: #f2f2f2; 155 | } 156 | 157 | nav .nav-content { 158 | margin: 0 auto; 159 | box-sizing: border-box; 160 | width: 100%; 161 | max-width: 1024px; 162 | padding: 0 22px; 163 | } 164 | 165 | nav .list-styled { 166 | cursor: default; 167 | margin: 0 -9px; 168 | width: auto; 169 | height: 44px; 170 | display: flex; 171 | justify-content: space-between; 172 | list-style: none; 173 | } 174 | 175 | nav .link-styled { 176 | font-size: 12px; 177 | font-weight: 400; 178 | letter-spacing: -0.01em; 179 | line-height: 1; 180 | display: flex; 181 | align-items: center; 182 | justify-content: center; 183 | height: 44px; 184 | color: #000000cc; 185 | } 186 | 187 | .jumbotron-section.wrapper { 188 | margin-left: auto; 189 | margin-right: auto; 190 | max-width: 980px; 191 | width: 100%; 192 | box-sizing: border-box; 193 | height: calc(100vh - 40px); 194 | display: flex; 195 | align-items: center; 196 | flex-direction: column; 197 | padding-top: 60px; 198 | position: relative; 199 | z-index: 1; 200 | min-height: 831px; 201 | } 202 | 203 | .jumbotron-section .title { 204 | color: #86868b; 205 | font-size: 17px; 206 | font-weight: 400; 207 | letter-spacing: -0.022em; 208 | } 209 | 210 | .jumbotron-section .logo { 211 | width: 140px; 212 | } 213 | 214 | .jumbotron-section .text { 215 | display: inline-block; 216 | color: transparent; 217 | background-image: linear-gradient(180deg, #ffb6ff, #b344ff); 218 | -webkit-background-clip: text; 219 | background-clip: text; 220 | padding-top: 0.5px; 221 | margin-top: 16px; 222 | font-size: 48px; 223 | font-weight: 600; 224 | margin-bottom: 18px; 225 | } 226 | 227 | .jumbotron-section .description { 228 | font-size: 21px; 229 | font-weight: 400; 230 | } 231 | 232 | .jumbotron-section .links { 233 | display: flex; 234 | justify-content: center; 235 | margin-top: 24px; 236 | align-items: center; 237 | margin-left: 0; 238 | margin-right: 0; 239 | padding-left: 0; 240 | list-style: none; 241 | } 242 | 243 | .jumbotron-section .button { 244 | background: #0071e3; 245 | color: #fff; 246 | cursor: pointer; 247 | display: inline-block; 248 | text-align: center; 249 | white-space: nowrap; 250 | font-size: 17px; 251 | font-weight: 400; 252 | min-width: 28px; 253 | padding: 8px 16px; 254 | border-radius: 980px; 255 | margin: 0 14px; 256 | } 257 | 258 | .jumbotron-section .link { 259 | text-decoration: none; 260 | color: #2997ff; 261 | font-size: 21px; 262 | font-weight: 400; 263 | margin: 0 14px; 264 | cursor: pointer; 265 | } 266 | 267 | .jumbotron-section .iphone-img { 268 | margin-right: -400px; 269 | height: 516px; 270 | position: absolute; 271 | bottom: 0; 272 | } 273 | 274 | .mobile-or-tablet .iphone-img { 275 | display: none; 276 | } 277 | 278 | @keyframes fadeOut { 279 | from { 280 | opacity: 1; 281 | } 282 | to { 283 | opacity: 0; 284 | } 285 | } 286 | 287 | .loader { 288 | position: fixed; 289 | z-index: 2; 290 | background-color: white; 291 | top: 0; 292 | left: 0; 293 | width: 100%; 294 | height: 100%; 295 | display: flex; 296 | justify-content: center; 297 | align-items: center; 298 | animation-name: fadeOut; 299 | animation-duration: 0.3s; 300 | animation-delay: 9s; 301 | animation-fill-mode: forwards; 302 | pointer-events: none; 303 | } 304 | 305 | .loader .logo { 306 | max-width: 400px; 307 | max-height: 300px; 308 | width: 100%; 309 | height: 100%; 310 | } 311 | 312 | .sound-section.wrapper { 313 | width: 100%; 314 | color: #1d1d1f; 315 | background-color: #fbfbfd; 316 | height: 100vh; 317 | } 318 | 319 | .sound-section .body { 320 | max-width: 980px; 321 | margin: 0 auto; 322 | } 323 | 324 | .sound-section .content { 325 | max-width: 490px; 326 | width: 100%; 327 | padding: 200px 0; 328 | display: flex; 329 | align-items: center; 330 | flex-direction: column; 331 | opacity: 0; 332 | } 333 | 334 | .sound-section .title { 335 | color: #1d1d1f; 336 | font-size: 17px; 337 | font-weight: 400; 338 | margin-bottom: 0; 339 | } 340 | 341 | .sound-section .text { 342 | display: inline-block; 343 | color: transparent; 344 | background-image: linear-gradient( 345 | 90deg, 346 | #1e3791 0%, 347 | #2948b1 40%, 348 | #3153c6 55%, 349 | #385fda 60% 350 | ); 351 | -webkit-background-clip: text; 352 | background-clip: text; 353 | padding-top: 0.5px; 354 | margin-top: 16px; 355 | font-size: 48px; 356 | font-weight: 600; 357 | margin-bottom: 18px; 358 | } 359 | 360 | .sound-section .description { 361 | font-size: 21px; 362 | font-weight: 400; 363 | } 364 | 365 | .sound-section .links { 366 | display: flex; 367 | justify-content: center; 368 | margin-top: 24px; 369 | align-items: center; 370 | margin-left: 0; 371 | margin-right: 0; 372 | padding-left: 0; 373 | list-style: none; 374 | } 375 | 376 | .sound-section .button { 377 | background: #0071e3; 378 | color: #fff; 379 | cursor: pointer; 380 | display: inline-block; 381 | text-align: center; 382 | white-space: nowrap; 383 | font-size: 17px; 384 | font-weight: 400; 385 | min-width: 28px; 386 | padding: 8px 16px; 387 | border-radius: 980px; 388 | margin: 0 14px; 389 | border: none; 390 | } 391 | 392 | .sound-section .link { 393 | text-decoration: none; 394 | color: #2997ff; 395 | font-size: 21px; 396 | font-weight: 400; 397 | margin: 0 14px; 398 | cursor: pointer; 399 | } 400 | 401 | @media screen and (max-width: 990px) { 402 | .jumbotron-section .iphone-img, 403 | nav .link-styled { 404 | display: none; 405 | } 406 | 407 | nav .list-styled { 408 | padding-left: 0; 409 | } 410 | 411 | .jumbotron-section.wrapper, 412 | .sound-section.wrapper, 413 | .display-section.wrapper { 414 | padding-left: 20px; 415 | padding-right: 20px; 416 | box-sizing: border-box; 417 | } 418 | 419 | .jumbotron-section .description, 420 | .sound-section .description, 421 | .display-section .description { 422 | font-size: 14px; 423 | } 424 | 425 | .jumbotron-section.wrapper, 426 | .sound-section .content, 427 | .display-section.wrapper { 428 | padding-top: 20px; 429 | } 430 | 431 | #webgi-canvas-container, 432 | .jumbotron-section.wrapper { 433 | min-height: 746px; 434 | height: 100vh; 435 | } 436 | 437 | .sound-section.wrapper { 438 | height: 100vh; 439 | } 440 | 441 | .sound-section .content { 442 | max-width: 100%; 443 | } 444 | } --------------------------------------------------------------------------------