diff --git a/src/app/badge/page.jsx b/src/app/badge/page.jsx new file mode 100644 index 0000000..86694c9 --- /dev/null +++ b/src/app/badge/page.jsx @@ -0,0 +1,335 @@ +"use client"; + +import * as THREE from "three"; +import { useEffect, useRef, useState } from "react"; +import { Canvas, extend, useThree, useFrame } from "@react-three/fiber"; +import { + useGLTF, + useTexture, + Environment, + Lightformer, + RenderTexture, + Text3D, + Resize, + Center, + PerspectiveCamera, +} from "@react-three/drei"; +import { + BallCollider, + CuboidCollider, + Physics, + RigidBody, + useRopeJoint, + useSphericalJoint, +} from "@react-three/rapier"; +import { MeshLineGeometry, MeshLineMaterial } from "meshline"; +import { useControls } from "leva"; + +extend({ MeshLineGeometry, MeshLineMaterial }); + +useTexture.preload( + "https://github.com/user-attachments/assets/999b5d58-ac8a-4c20-8fc6-74e8ab7876e7", +); + +export default function App() { + const { debug } = useControls({ debug: false }); + return ( + + + + + + + + + + + + + + ); +} + +function BadgeTexture() { + // const viewport = useThree((state) => state.viewport); + + return ( + <> + + {/* + + + */} +
+ + + hyamero + + + omsimos.com + + +
+ + ); +} + +function Band({ maxSpeed = 50, minSpeed = 10 }) { + const band = useRef(), fixed = useRef(), j1 = useRef(), j2 = useRef(), j3 = useRef(), card = useRef() // prettier-ignore + const vec = new THREE.Vector3(), ang = new THREE.Vector3(), rot = new THREE.Vector3(), dir = new THREE.Vector3() // prettier-ignore + const segmentProps = { + type: "dynamic", + canSleep: true, + colliders: false, + angularDamping: 2, + linearDamping: 2, + }; + useGLTF.preload( + "https://assets.vercel.com/image/upload/contentful/image/e5382hct74si/5huRVDzcoDwnbgrKUo1Lzs/53b6dd7d6b4ffcdbd338fa60265949e1/tag.glb", + ); + + const { nodes, materials } = useGLTF( + "https://assets.vercel.com/image/upload/contentful/image/e5382hct74si/5huRVDzcoDwnbgrKUo1Lzs/53b6dd7d6b4ffcdbd338fa60265949e1/tag.glb", + ); + + // const texture = useTexture( + // "https://assets.vercel.com/image/upload/contentful/image/e5382hct74si/SOT1hmCesOHxEYxL7vkoZ/c57b29c85912047c414311723320c16b/band.jpg", + // ); + + const texture = useTexture("/band.jpg"); + const { width, height } = useThree((state) => state.size); + const [curve] = useState( + () => + new THREE.CatmullRomCurve3([ + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + ]), + ); + const [dragged, drag] = useState(false); + const [hovered, hover] = useState(false); + + useRopeJoint(fixed, j1, [[0, 0, 0], [0, 0, 0], 1]) // prettier-ignore + useRopeJoint(j1, j2, [[0, 0, 0], [0, 0, 0], 1]) // prettier-ignore + useRopeJoint(j2, j3, [[0, 0, 0], [0, 0, 0], 1]) // prettier-ignore + useSphericalJoint(j3, card, [[0, 0, 0], [0, 1.45, 0]]) // prettier-ignore + + useEffect(() => { + if (hovered) { + document.body.style.cursor = dragged ? "grabbing" : "grab"; + return () => void (document.body.style.cursor = "auto"); + } + }, [hovered, dragged]); + + useFrame((state, delta) => { + if (dragged) { + vec.set(state.pointer.x, state.pointer.y, 0.5).unproject(state.camera); + dir.copy(vec).sub(state.camera.position).normalize(); + vec.add(dir.multiplyScalar(state.camera.position.length())); + [card, j1, j2, j3, fixed].forEach((ref) => ref.current?.wakeUp()); + card.current?.setNextKinematicTranslation({ + x: vec.x - dragged.x, + y: vec.y - dragged.y, + z: vec.z - dragged.z, + }); + } + if (fixed.current) { + // Fix most of the jitter when over pulling the card + [j1, j2].forEach((ref) => { + if (!ref.current.lerped) + ref.current.lerped = new THREE.Vector3().copy( + ref.current.translation(), + ); + const clampedDistance = Math.max( + 0.1, + Math.min(1, ref.current.lerped.distanceTo(ref.current.translation())), + ); + ref.current.lerped.lerp( + ref.current.translation(), + delta * (minSpeed + clampedDistance * (maxSpeed - minSpeed)), + ); + }); + // Calculate catmul curve + curve.points[0].copy(j3.current.translation()); + curve.points[1].copy(j2.current.lerped); + curve.points[2].copy(j1.current.lerped); + curve.points[3].copy(fixed.current.translation()); + band.current.geometry.setPoints(curve.getPoints(32)); + // Tilt it back towards the screen + ang.copy(card.current.angvel()); + rot.copy(card.current.rotation()); + card.current.setAngvel({ x: ang.x, y: ang.y - rot.y * 0.25, z: ang.z }); + } + }); + + curve.curveType = "chordal"; + texture.wrapS = texture.wrapT = THREE.RepeatWrapping; + + return ( + <> + + + + + + + + + + + + + + hover(true)} + onPointerOut={() => hover(false)} + onPointerUp={(e) => ( + e.target.releasePointerCapture(e.pointerId), drag(false) + )} + onPointerDown={(e) => ( + e.target.setPointerCapture(e.pointerId), + drag( + new THREE.Vector3() + .copy(e.point) + .sub(vec.copy(card.current.translation())), + ) + )} + > + {/* + + */} + + + + {/* */} + + + + + + {/*
+ + + Joseph Dale + + + Omsimos + + +
*/} + + +
+
+
+ + + + + + ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index e843eac..7343d4b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -16,12 +16,9 @@ export default async function Home() { )} > - - ✨ Contribute to GitHub + + ✨ Experimental: + Visit 3D Badge