├── 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 |
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 |
Try me!
18 |
TOP
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 | 
6 |
7 | 
8 |
9 | 
10 |
11 | 
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 |
22 |
23 |
24 |
25 |
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 | Buy
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 |
19 |
Big and bigger.
20 |
21 | From $41.62/mo. for 24 mo. or $999 before trade-in
22 |
23 |
24 |
25 |
26 | Buy
27 |
28 |
29 |
30 | Learn more
31 |
32 |
33 |
34 |
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 |
9 |
10 |
69 |
70 |
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 | Exit
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 | }
--------------------------------------------------------------------------------