chore: replace glb files and lottie with optimized variants (#19503)
As per title. Replaced .json file with .lottie file - it is 10x smaller. Illustrations folder went from 150mb to 5.9mb with compressed variants of 3D models. The DracoLoader, GLTFLoader and some other logic logic is repetitive across files, but Thomas is working on the same files at the moment, so not touching too much to avoid conflicts with his PR. Once he's done styling, we can extract shared logic into helpers.
@@ -13,6 +13,7 @@
|
||||
"@gsap/react": "2.1.2",
|
||||
"@linaria/core": "^7.0.0",
|
||||
"@linaria/react": "^7.0.1",
|
||||
"@lottiefiles/dotlottie-react": "^0.18.10",
|
||||
"@react-three/drei": "^10.7.7",
|
||||
"@react-three/fiber": "^9.5.0",
|
||||
"@tabler/icons-react": "^3.41.1",
|
||||
@@ -20,7 +21,6 @@
|
||||
"axios": "^1.14.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"gsap": "^3.14.2",
|
||||
"lottie-react": "^2.4.1",
|
||||
"next": "16.1.7",
|
||||
"next-with-linaria": "^1.3.0",
|
||||
"react": "19.2.3",
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
@@ -4,6 +4,7 @@ import { theme } from '@/theme';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/common/faq/faq.glb';
|
||||
@@ -178,7 +179,14 @@ export function FaqBackground() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -241,6 +249,7 @@ export function FaqBackground() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/common/footer/footer.glb';
|
||||
@@ -188,7 +189,14 @@ export function FooterBackground() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -329,6 +337,7 @@ export function FooterBackground() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/home/helped/money.glb';
|
||||
@@ -191,7 +192,14 @@ export function Money() {
|
||||
const cameraWorldPosition = new THREE.Vector3();
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -357,6 +365,7 @@ export function Money() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/home/helped/spaceship.glb';
|
||||
@@ -191,7 +192,14 @@ export function Spaceship() {
|
||||
const cameraWorldPosition = new THREE.Vector3();
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -357,6 +365,7 @@ export function Spaceship() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/home/helped/target.glb';
|
||||
@@ -191,7 +192,14 @@ export function Target() {
|
||||
const cameraWorldPosition = new THREE.Vector3();
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -357,6 +365,7 @@ export function Target() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { theme } from '@/theme';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/product/hero/hero.glb';
|
||||
@@ -179,7 +180,14 @@ export function Product() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -320,6 +328,7 @@ export function Product() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/why-twenty/hero/hero.glb';
|
||||
@@ -221,7 +222,14 @@ export function WhyTwenty() {
|
||||
let targetRotationX = 0;
|
||||
let targetRotationY = 0;
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(GLB_URL, (gltf) => {
|
||||
if (cancelled) {
|
||||
disposeObjectSubtree(gltf.scene);
|
||||
@@ -315,6 +323,7 @@ export function WhyTwenty() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/pricing/Price/organization.glb';
|
||||
@@ -171,7 +172,14 @@ export function Organization() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -324,6 +332,7 @@ export function Organization() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/pricing/Price/pro.glb';
|
||||
@@ -171,7 +172,14 @@ export function Pro() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -324,6 +332,7 @@ export function Pro() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { theme } from '@/theme';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useLayoutEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/why-twenty/quote/quote.glb';
|
||||
@@ -189,7 +190,14 @@ export function Quotes() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -329,6 +337,7 @@ export function Quotes() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { theme } from '@/theme';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useLayoutEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/home/testimonials/hourglass.glb';
|
||||
@@ -188,7 +189,14 @@ export function Hourglass() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -332,6 +340,7 @@ export function Hourglass() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { theme } from '@/theme';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useLayoutEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/partner/testimonials/quote.glb';
|
||||
@@ -188,7 +189,14 @@ export function Partner() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -328,6 +336,7 @@ export function Partner() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/partner/three-cards/connect.glb';
|
||||
@@ -182,7 +183,14 @@ export function Connect() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -346,6 +354,7 @@ export function Connect() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/home/three-cards/diamond.glb';
|
||||
@@ -182,7 +183,14 @@ export function Diamond() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -346,6 +354,7 @@ export function Diamond() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/product/three-cards/eye.glb';
|
||||
@@ -182,7 +183,14 @@ export function Eye() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -346,6 +354,7 @@ export function Eye() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/home/three-cards/flash.glb';
|
||||
@@ -182,7 +183,14 @@ export function Flash() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -346,6 +354,7 @@ export function Flash() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/partner/three-cards/grow.glb';
|
||||
@@ -182,7 +183,14 @@ export function Grow() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -346,6 +354,7 @@ export function Grow() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/home/three-cards/lock.glb';
|
||||
@@ -182,7 +183,14 @@ export function Lock() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -346,6 +354,7 @@ export function Lock() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/partner/three-cards/programming.glb';
|
||||
@@ -182,7 +183,14 @@ export function Programming() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -346,6 +354,7 @@ export function Programming() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/product/three-cards/single-screen.glb';
|
||||
@@ -182,7 +183,14 @@ export function SingleScreen() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -346,6 +354,7 @@ export function SingleScreen() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/product/three-cards/speed.glb';
|
||||
@@ -182,7 +183,14 @@ export function Speed() {
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(
|
||||
GLB_URL,
|
||||
(gltf) => {
|
||||
@@ -346,6 +354,7 @@ export function Speed() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { theme } from '@/theme';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useLayoutEffect, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
const GLB_URL = '/illustrations/why-twenty/stepper/logo.glb';
|
||||
@@ -264,7 +265,14 @@ export function Logo() {
|
||||
|
||||
syncResolutionUniforms();
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
'https://www.gstatic.com/draco/versioned/decoders/1.5.6/',
|
||||
);
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
loader.load(GLB_URL, (gltf) => {
|
||||
if (cancelled) {
|
||||
disposeObjectSubtree(gltf.scene);
|
||||
@@ -353,6 +361,7 @@ export function Logo() {
|
||||
window.cancelAnimationFrame(animationFrameId);
|
||||
disposeObjectSubtree(scene);
|
||||
renderer.dispose();
|
||||
dracoLoader.dispose();
|
||||
if (canvas.parentNode === container) {
|
||||
container.removeChild(canvas);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
'use client';
|
||||
|
||||
import { styled } from '@linaria/react';
|
||||
import { DotLottieReact, type DotLottie } from '@lottiefiles/dotlottie-react';
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { scrollProgressToHomeStepperLottieFrame } from '@/sections/HomeStepper/utils/home-stepper-lottie-frame-map';
|
||||
import { theme } from '@/theme';
|
||||
import { styled } from '@linaria/react';
|
||||
import Lottie, { type LottieRefCurrentProps } from 'lottie-react';
|
||||
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||
|
||||
export const HOME_STEPPER_LOTTIE_SRC = '/images/home/stepper/lottie.json';
|
||||
export const HOME_STEPPER_LOTTIE_SRC = '/lottie/stepper/stepper.lottie';
|
||||
|
||||
const LottieSlot = styled.div`
|
||||
box-sizing: border-box;
|
||||
@@ -17,100 +24,72 @@ const LottieSlot = styled.div`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
type LottieAnimationData = {
|
||||
ip?: number;
|
||||
op?: number;
|
||||
} & Record<string, unknown>;
|
||||
|
||||
type StepperLottieProps = {
|
||||
scrollProgress: number;
|
||||
};
|
||||
|
||||
function lottieTotalFrameCount(animationData: LottieAnimationData): number {
|
||||
const op = typeof animationData.op === 'number' ? animationData.op : 0;
|
||||
const ip = typeof animationData.ip === 'number' ? animationData.ip : 0;
|
||||
const rounded = Math.round(op - ip);
|
||||
return rounded >= 1 ? rounded : 0;
|
||||
}
|
||||
|
||||
function applyScrollToLottie(
|
||||
lottieApi: LottieRefCurrentProps | null,
|
||||
function applyScrollToDotLottie(
|
||||
dotLottie: DotLottie | null,
|
||||
scrollProgress: number,
|
||||
totalFrames: number,
|
||||
) {
|
||||
if (!lottieApi?.animationLoaded || totalFrames <= 0) {
|
||||
if (!dotLottie?.isLoaded || totalFrames <= 0) {
|
||||
return;
|
||||
}
|
||||
const frame = scrollProgressToHomeStepperLottieFrame(
|
||||
scrollProgress,
|
||||
totalFrames,
|
||||
);
|
||||
lottieApi.goToAndStop(frame, true);
|
||||
dotLottie.setFrame(frame);
|
||||
}
|
||||
|
||||
export function StepperLottie({ scrollProgress }: StepperLottieProps) {
|
||||
const [animationData, setAnimationData] =
|
||||
useState<LottieAnimationData | null>(null);
|
||||
const [player, setPlayer] = useState<DotLottie | null>(null);
|
||||
const [totalFrames, setTotalFrames] = useState(0);
|
||||
const lottieRef = useRef<LottieRefCurrentProps | null>(null);
|
||||
const scrollProgressRef = useRef(scrollProgress);
|
||||
scrollProgressRef.current = scrollProgress;
|
||||
const totalFramesRef = useRef(totalFrames);
|
||||
totalFramesRef.current = totalFrames;
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
|
||||
fetch(HOME_STEPPER_LOTTIE_SRC, { signal: controller.signal })
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Lottie fetch failed: ${response.status}`);
|
||||
}
|
||||
return response.json() as Promise<LottieAnimationData>;
|
||||
})
|
||||
.then((data) => {
|
||||
setAnimationData(data);
|
||||
setTotalFrames(lottieTotalFrameCount(data));
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
if (error instanceof Error && error.name === 'AbortError') {
|
||||
return;
|
||||
}
|
||||
setAnimationData(null);
|
||||
});
|
||||
|
||||
return () => {
|
||||
controller.abort();
|
||||
};
|
||||
const dotLottieRefCallback = useCallback((instance: DotLottie | null) => {
|
||||
setPlayer(instance);
|
||||
}, []);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!animationData) {
|
||||
useEffect(() => {
|
||||
if (!player) {
|
||||
setTotalFrames(0);
|
||||
return;
|
||||
}
|
||||
applyScrollToLottie(lottieRef.current, scrollProgress, totalFrames);
|
||||
}, [animationData, scrollProgress, totalFrames]);
|
||||
|
||||
if (!animationData) {
|
||||
return <LottieSlot aria-hidden />;
|
||||
}
|
||||
const onReady = () => {
|
||||
const frames = player.totalFrames;
|
||||
setTotalFrames(frames);
|
||||
applyScrollToDotLottie(player, scrollProgressRef.current, frames);
|
||||
};
|
||||
|
||||
if (player.isLoaded) {
|
||||
onReady();
|
||||
return;
|
||||
}
|
||||
|
||||
player.addEventListener('load', onReady);
|
||||
return () => {
|
||||
player.removeEventListener('load', onReady);
|
||||
};
|
||||
}, [player]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
applyScrollToDotLottie(player, scrollProgress, totalFrames);
|
||||
}, [player, scrollProgress, totalFrames]);
|
||||
|
||||
return (
|
||||
<LottieSlot aria-hidden>
|
||||
<Lottie
|
||||
animationData={animationData}
|
||||
<DotLottieReact
|
||||
autoplay={false}
|
||||
dotLottieRefCallback={dotLottieRefCallback}
|
||||
layout={{ align: [0.5, 0.5], fit: 'contain' }}
|
||||
loop={false}
|
||||
lottieRef={lottieRef}
|
||||
src={HOME_STEPPER_LOTTIE_SRC}
|
||||
style={{ height: '100%', maxWidth: '100%', width: '100%' }}
|
||||
onDOMLoaded={() => {
|
||||
lottieRef.current?.setSubframe(true);
|
||||
applyScrollToLottie(
|
||||
lottieRef.current,
|
||||
scrollProgressRef.current,
|
||||
totalFramesRef.current,
|
||||
);
|
||||
}}
|
||||
useFrameInterpolation
|
||||
/>
|
||||
</LottieSlot>
|
||||
);
|
||||
|
||||
@@ -11200,6 +11200,24 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@lottiefiles/dotlottie-react@npm:^0.18.10":
|
||||
version: 0.18.10
|
||||
resolution: "@lottiefiles/dotlottie-react@npm:0.18.10"
|
||||
dependencies:
|
||||
"@lottiefiles/dotlottie-web": "npm:0.70.0"
|
||||
peerDependencies:
|
||||
react: ^17 || ^18 || ^19
|
||||
checksum: 10c0/5cd7350dbe44717bb920dd6534a9826a801128f396853c04371b05b0adb34a2a8b62b33f5c44f50597f5f32919f47ba22c24f9ee0276cc67b9feb7d6db7a15c9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@lottiefiles/dotlottie-web@npm:0.70.0":
|
||||
version: 0.70.0
|
||||
resolution: "@lottiefiles/dotlottie-web@npm:0.70.0"
|
||||
checksum: 10c0/814df634325393c376d05541f4c3e1e92b383c16f9673e443c671fbaef5414fa9da0d4bcfc1453d6ffe2390c82f79cf68e04785a66ba75a030d3d9d3cd799aa2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@lukeed/csprng@npm:^1.0.0":
|
||||
version: 1.1.0
|
||||
resolution: "@lukeed/csprng@npm:1.1.0"
|
||||
@@ -46887,25 +46905,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lottie-react@npm:^2.4.1":
|
||||
version: 2.4.1
|
||||
resolution: "lottie-react@npm:2.4.1"
|
||||
dependencies:
|
||||
lottie-web: "npm:^5.10.2"
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
checksum: 10c0/7f6a0a2cf2af25deabe7b4d4c9917e47d12016673613c59dcdd8ef52e10e914dd0c1f71d4a275d56aaba03fe9d85b333087f7c8d40a8f967ece4a0444c7a3cdf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lottie-web@npm:^5.10.2":
|
||||
version: 5.13.0
|
||||
resolution: "lottie-web@npm:5.13.0"
|
||||
checksum: 10c0/b463ad462169df3f7e04b7f3716274e269842554f1d72b8303ca7245628f2512982a59ae31698b3d57fbcda886228ae160fcb2aa518c6cecd8a95974db2458ee
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"loupe@npm:^3.1.0":
|
||||
version: 3.2.0
|
||||
resolution: "loupe@npm:3.2.0"
|
||||
@@ -60905,6 +60904,7 @@ __metadata:
|
||||
"@gsap/react": "npm:2.1.2"
|
||||
"@linaria/core": "npm:^7.0.0"
|
||||
"@linaria/react": "npm:^7.0.1"
|
||||
"@lottiefiles/dotlottie-react": "npm:^0.18.10"
|
||||
"@react-three/drei": "npm:^10.7.7"
|
||||
"@react-three/fiber": "npm:^9.5.0"
|
||||
"@tabler/icons-react": "npm:^3.41.1"
|
||||
@@ -60917,7 +60917,6 @@ __metadata:
|
||||
babel-plugin-react-compiler: "npm:1.0.0"
|
||||
gray-matter: "npm:^4.0.3"
|
||||
gsap: "npm:^3.14.2"
|
||||
lottie-react: "npm:^2.4.1"
|
||||
next: "npm:16.1.7"
|
||||
next-with-linaria: "npm:^1.3.0"
|
||||
react: "npm:19.2.3"
|
||||
|
||||