Skip to content

Commit

Permalink
Fix: Dynamically import three.js libraries (#1166)
Browse files Browse the repository at this point in the history
* dynamically import three js libraries

* move all models to models file

* smarter import

* specific import

* dynamic import of rigidbody

* better loading / color / comments
  • Loading branch information
kirkas authored Oct 29, 2024
1 parent 8d72e3c commit a162cca
Show file tree
Hide file tree
Showing 5 changed files with 354 additions and 250 deletions.
10 changes: 5 additions & 5 deletions apps/web/app/(base-org)/(root)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ import Link from 'apps/web/src/components/Link';
import MissionSection from 'apps/web/src/components/base-org/root/MissionSection';
import OpLogo from 'apps/web/public/images/op_logo.svg';

const DynamicThreeHero = dynamic(async () => import('apps/web/src/components/ThreeHero'), {
ssr: false,
});

const Scene = dynamic(
async () => import('apps/web/src/components/ThreeHero').then((mod) => mod.Scene),
{ ssr: false },
);
export default async function Home() {
return (
<ErrorsProvider context="base_landing_page">
<AnalyticsProvider context="hero">
<div className="relative z-10 h-screen w-full">
<DynamicThreeHero />
<Scene />
<div className="absolute bottom-0 z-20 flex w-full flex-col justify-between gap-6 pb-20 text-white lg:flex-row">
<div className="lg:ml-20">
<Container>
Expand Down
34 changes: 34 additions & 0 deletions apps/web/src/components/ThreeHero/DynamicRigidBody.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use client';

import { useEffect, useState, forwardRef } from 'react';
import type { RigidBodyProps, RapierRigidBody, RigidBody } from '@react-three/rapier';
import { useErrors } from 'apps/web/contexts/Errors';

// RigidBody cannot be imported using dynamic() due to some import issues
export const DynamicRigidBody = forwardRef<RapierRigidBody, RigidBodyProps>(
({ children, ...props }, ref) => {
const [RigidBodyDynamic, setRigidBody] = useState<typeof RigidBody>();
const { logError } = useErrors();

// Import needs to happens on render
useEffect(() => {
import('@react-three/rapier')
.then((mod) => {
setRigidBody(() => mod.RigidBody);
})
.catch((error) => logError(error, 'Failed to load RigidBody'));
}, [logError]);

if (!RigidBodyDynamic) return null;

return (
<RigidBodyDynamic ref={ref} {...props}>
{children}
</RigidBodyDynamic>
);
},
);

DynamicRigidBody.displayName = 'DynamicRigidBody';

export default DynamicRigidBody;
83 changes: 83 additions & 0 deletions apps/web/src/components/ThreeHero/PhysicsMesh.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use client';

// Libraries
import { useMemo, useRef } from 'react';
import dynamic from 'next/dynamic';

// Components
import DynamicRigidBody from 'apps/web/src/components/ThreeHero/DynamicRigidBody';

// 3D libraries - types
import type { BallArgs, RapierRigidBody } from '@react-three/rapier';

// 3D Libraries - static - These cannot be dynamically imported
import { Vector3 } from 'three';
import { randFloatSpread } from 'three/src/math/MathUtils.js';
import { useFrame, useThree } from '@react-three/fiber';

// Dynamic - react-three/rapier
const BallCollider = dynamic(
async () => import('@react-three/rapier').then((mod) => mod.BallCollider),
{ ssr: false },
);

const ballArguments: BallArgs = [1];

export function PhysicsMesh({
r = randFloatSpread,
scale = 1,
gravityEffect = 0.2,
children,
}: {
r?: (a: number) => number;
scale?: number;
gravityEffect?: number;
children: React.ReactNode;
}) {
const rigidBodyApiRef = useRef<RapierRigidBody>(null);
const { viewport } = useThree();
const vec = new Vector3();

const randomNumberBetween = (min: number, max: number) => {
const posOrNeg = Math.random() > 0.5 ? 1 : -1;
const num = Math.min(Math.random() * (max - min) + min, 14);
return posOrNeg * num;
};

const pos = useMemo(
() =>
new Vector3(
randomNumberBetween(viewport.width * 0.5, viewport.width * 2),
randomNumberBetween(viewport.height * 0.5, viewport.height * 2),
randomNumberBetween(viewport.width * 0.5, viewport.width * 2),
),
[viewport.height, viewport.width],
);
const rot = useMemo(() => new Vector3(r(Math.PI), r(Math.PI), r(Math.PI)), [r]);

useFrame(() => {
if (!rigidBodyApiRef.current) return;
const vector = rigidBodyApiRef.current.translation();
const vector3 = new Vector3(vector.x, vector.y, vector.z);
rigidBodyApiRef.current.applyImpulse(
vec.copy(vector3).negate().multiplyScalar(gravityEffect),
true,
);
});

return (
<DynamicRigidBody
linearDamping={4}
angularDamping={1}
friction={0.1}
position={pos.toArray()}
rotation={rot.toArray()}
ref={rigidBodyApiRef}
colliders={false}
scale={scale}
>
<BallCollider args={ballArguments} />
{children}
</DynamicRigidBody>
);
}
Loading

0 comments on commit a162cca

Please sign in to comment.