{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "event-badge-3d",
  "title": "Event Badge 3D",
  "description": "component for the Event Badge 3D",
  "dependencies": [
    "three",
    "@react-three/fiber",
    "@react-three/drei",
    "@react-three/rapier",
    "meshline"
  ],
  "files": [
    {
      "path": "app/registry/badge/badgedemo.tsx",
      "content": "\"use client\";\nimport * as THREE from \"three\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { Canvas, extend, useThree, useFrame } from \"@react-three/fiber\";\nimport {\n  useGLTF,\n  useTexture,\n  Environment,\n  Lightformer,\n} from \"@react-three/drei\";\nimport {\n  BallCollider,\n  CuboidCollider,\n  Physics,\n  RigidBody,\n  useRopeJoint,\n  useSphericalJoint,\n} from \"@react-three/rapier\";\nimport { MeshLineGeometry, MeshLineMaterial } from \"meshline\";\n\nextend({ MeshLineGeometry, MeshLineMaterial });\n\ndeclare global {\n  namespace JSX {\n    interface IntrinsicElements {\n      meshLineGeometry: any;\n      meshLineMaterial: any;\n    }\n  }\n}\n\n// Preload assets\nif (typeof window !== \"undefined\") {\n  useGLTF.preload(\n    \"https://assets.vercel.com/image/upload/contentful/image/e5382hct74si/5huRVDzcoDwnbgrKUo1Lzs/53b6dd7d6b4ffcdbd338fa60265949e1/tag.glb\",\n  );\n  useTexture.preload(\n    \"https://assets.vercel.com/image/upload/contentful/image/e5382hct74si/SOT1hmCesOHxEYxL7vkoZ/c57b29c85912047c414311723320c16b/band.jpg\",\n  );\n}\n\nexport default function EventIdcard() {\n  //   const { debug } = useControls({ debug: false })\n  return (\n    <div className=\"w-full h-[500px]\">\n      <Canvas camera={{ position: [0, 0, 13], fov: 25 }}>\n        <ambientLight intensity={Math.PI} />\n        <Physics interpolate gravity={[0, -40, 0]} timeStep={1 / 60}>\n          <Band />\n        </Physics>\n        <Environment background blur={0.75}>\n          <color attach=\"background\" args={[\"black\"]} />\n          <Lightformer\n            intensity={2}\n            color=\"white\"\n            position={[0, -1, 5]}\n            rotation={[0, 0, Math.PI / 3]}\n            scale={[100, 0.1, 1]}\n          />\n          <Lightformer\n            intensity={3}\n            color=\"white\"\n            position={[-1, -1, 1]}\n            rotation={[0, 0, Math.PI / 3]}\n            scale={[100, 0.1, 1]}\n          />\n          <Lightformer\n            intensity={3}\n            color=\"white\"\n            position={[1, 1, 1]}\n            rotation={[0, 0, Math.PI / 3]}\n            scale={[100, 0.1, 1]}\n          />\n          <Lightformer\n            intensity={10}\n            color=\"white\"\n            position={[-10, 0, 14]}\n            rotation={[0, Math.PI / 2, Math.PI / 3]}\n            scale={[100, 10, 1]}\n          />\n        </Environment>\n      </Canvas>\n    </div>\n  );\n}\n\ntype GLTFResult = {\n  nodes: {\n    card: THREE.Mesh;\n    clip: THREE.Mesh;\n    clamp: THREE.Mesh;\n  };\n  materials: {\n    base: THREE.MeshStandardMaterial;\n    metal: THREE.MeshStandardMaterial;\n  };\n};\n\ntype DragPosition = THREE.Vector3 | false;\n\ntype RigidBodySegmentProps = {\n  type: \"dynamic\" | \"fixed\" | \"kinematicPosition\";\n  canSleep: boolean;\n  colliders: \"ball\" | \"cuboid\" | \"hull\" | \"trimesh\" | false;\n  angularDamping: number;\n  linearDamping: number;\n};\n\nfunction Band({ maxSpeed = 50, minSpeed = 10 }) {\n  const band = useRef<THREE.Mesh>(null);\n  const lineGeometry = useRef<MeshLineGeometry>(null);\n  const fixed = useRef<any>(null);\n  const j1 = useRef<any>(null);\n  const j2 = useRef<any>(null);\n  const j3 = useRef<any>(null);\n  const card = useRef<any>(null);\n\n  const vec = new THREE.Vector3();\n  const ang = new THREE.Vector3();\n  const rot = new THREE.Vector3();\n  const dir = new THREE.Vector3();\n\n  const segmentProps: RigidBodySegmentProps = {\n    type: \"dynamic\",\n    canSleep: true,\n    colliders: false,\n    angularDamping: 2,\n    linearDamping: 2,\n  };\n\n  const { nodes, materials } = useGLTF(\n    \"https://assets.vercel.com/image/upload/contentful/image/e5382hct74si/5huRVDzcoDwnbgrKUo1Lzs/53b6dd7d6b4ffcdbd338fa60265949e1/tag.glb\",\n  ) as unknown as GLTFResult;\n  const texture = useTexture(\n    \"https://assets.vercel.com/image/upload/contentful/image/e5382hct74si/SOT1hmCesOHxEYxL7vkoZ/c57b29c85912047c414311723320c16b/band.jpg\",\n  );\n  const { width, height } = useThree((state) => state.size);\n  const [curve] = useState(\n    () =>\n      new THREE.CatmullRomCurve3([\n        new THREE.Vector3(),\n        new THREE.Vector3(),\n        new THREE.Vector3(),\n        new THREE.Vector3(),\n      ]),\n  );\n  const [dragged, drag] = useState<DragPosition>(false);\n  const [hovered, hover] = useState(false);\n\n  useRopeJoint(fixed, j1, [[0, 0, 0], [0, 0, 0], 1]);\n  useRopeJoint(j1, j2, [[0, 0, 0], [0, 0, 0], 1]);\n  useRopeJoint(j2, j3, [[0, 0, 0], [0, 0, 0], 1]);\n  useSphericalJoint(j3, card, [\n    [0, 0, 0],\n    [0, 1.45, 0],\n  ]);\n\n  useEffect(() => {\n    if (hovered) {\n      document.body.style.cursor = dragged ? \"grabbing\" : \"grab\";\n      return () => void (document.body.style.cursor = \"auto\");\n    }\n  }, [hovered, dragged]);\n\n  useFrame((state, delta) => {\n    if (dragged && card.current) {\n      vec.set(state.pointer.x, state.pointer.y, 0.5).unproject(state.camera);\n      dir.copy(vec).sub(state.camera.position).normalize();\n      vec.add(dir.multiplyScalar(state.camera.position.length()));\n      [card, j1, j2, j3, fixed].forEach((ref) => ref.current?.wakeUp());\n      card.current?.setNextKinematicTranslation({\n        x: vec.x - (dragged as THREE.Vector3).x,\n        y: vec.y - (dragged as THREE.Vector3).y,\n        z: vec.z - (dragged as THREE.Vector3).z,\n      });\n    }\n    if (fixed.current) {\n      [j1, j2].forEach((ref) => {\n        if (!ref.current.lerped)\n          ref.current.lerped = new THREE.Vector3().copy(\n            ref.current.translation(),\n          );\n        const clampedDistance = Math.max(\n          0.1,\n          Math.min(1, ref.current.lerped.distanceTo(ref.current.translation())),\n        );\n        ref.current.lerped.lerp(\n          ref.current.translation(),\n          delta * (minSpeed + clampedDistance * (maxSpeed - minSpeed)),\n        );\n      });\n\n      curve.points[0].copy(j3.current.translation());\n      curve.points[1].copy(j2.current.lerped);\n      curve.points[2].copy(j1.current.lerped);\n      curve.points[3].copy(fixed.current.translation());\n\n      if (lineGeometry.current && lineGeometry.current.setPoints) {\n        const points = curve.getPoints(32);\n        lineGeometry.current.setPoints(points);\n      }\n\n      ang.copy(card.current.angvel());\n      rot.copy(card.current.rotation());\n      card.current.setAngvel({ x: ang.x, y: ang.y - rot.y * 0.25, z: ang.z });\n    }\n  });\n\n  curve.curveType = \"chordal\";\n  texture.wrapS = texture.wrapT = THREE.RepeatWrapping;\n\n  return (\n    <>\n      <group position={[0, 4, 0]}>\n        <RigidBody ref={fixed} {...segmentProps} type=\"fixed\" />\n        <RigidBody position={[0.5, 0, 0]} ref={j1} {...segmentProps}>\n          <BallCollider args={[0.1]} />\n        </RigidBody>\n        <RigidBody position={[1, 0, 0]} ref={j2} {...segmentProps}>\n          <BallCollider args={[0.1]} />\n        </RigidBody>\n        <RigidBody position={[1.5, 0, 0]} ref={j3} {...segmentProps}>\n          <BallCollider args={[0.1]} />\n        </RigidBody>\n        <RigidBody\n          position={[2, 0, 0]}\n          ref={card}\n          {...segmentProps}\n          type={dragged ? \"kinematicPosition\" : \"dynamic\"}\n        >\n          <CuboidCollider args={[0.8, 1.125, 0.01]} />\n          <group\n            scale={2.25}\n            position={[0, -1.2, -0.05]}\n            onPointerOver={() => hover(true)}\n            onPointerOut={() => hover(false)}\n            onPointerUp={(e: THREE.Event) => {\n              const target = e.target as HTMLElement;\n              if (target instanceof HTMLElement) {\n                target.releasePointerCapture(\n                  (e as unknown as globalThis.PointerEvent).pointerId,\n                );\n              }\n              drag(false);\n            }}\n            onPointerDown={(e: THREE.Event) => {\n              const target = e.target as HTMLElement;\n              if (target instanceof HTMLElement) {\n                target.setPointerCapture(\n                  (e as unknown as globalThis.PointerEvent).pointerId,\n                );\n              }\n              drag(\n                new THREE.Vector3()\n                  .copy((e as unknown as { point: THREE.Vector3 }).point)\n                  .sub(vec.copy(card.current.translation())),\n              );\n            }}\n          >\n            <mesh geometry={nodes.card.geometry}>\n              <meshPhysicalMaterial\n                map={materials.base.map}\n                map-anisotropy={16}\n                clearcoat={1}\n                clearcoatRoughness={0.15}\n                roughness={0.3}\n                metalness={0.5}\n              />\n            </mesh>\n            <mesh\n              geometry={nodes.clip.geometry}\n              material={materials.metal}\n              material-roughness={0.3}\n            />\n            <mesh geometry={nodes.clamp.geometry} material={materials.metal} />\n          </group>\n        </RigidBody>\n      </group>\n      <mesh ref={band}>\n        <bufferGeometry ref={lineGeometry} attach=\"geometry\" />\n        <lineBasicMaterial\n          attach=\"material\"\n          color=\"white\"\n          depthTest={false}\n          map={texture}\n          linewidth={1}\n        />\n      </mesh>\n    </>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/spectrumui/event_badge-3d.tsx"
    }
  ],
  "type": "registry:component"
}
