{"$schema":"https://ui.shadcn.com/schema/registry.json","homepage":"https://uicapsule.com/ui/ascii-renderer","name":"ascii-renderer","type":"registry:block","author":"Kaiyu Hsu <uicapsule@kyh.io>","dependencies":["@react-three/drei","@react-three/fiber","three"],"devDependencies":["@types/three"],"registryDependencies":[],"files":[{"type":"registry:file","path":"/ascii-renderer.tsx","content":"\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { OrbitControls } from \"@react-three/drei\";\nimport { Canvas, useFrame, useThree } from \"@react-three/fiber\";\nimport type { Mesh } from \"three\";\nimport { AsciiEffect } from \"three/examples/jsm/effects/AsciiEffect.js\";\n\nexport const AsciiRenderer = () => {\n  return (\n    <Canvas>\n      <ambientLight intensity={0.5} />\n      <pointLight position={[10, 10, 10]} intensity={1} />\n      <directionalLight position={[-10, -10, -5]} intensity={1} />\n      <Torusknot />\n      <OrbitControls />\n      <Renderer />\n    </Canvas>\n  );\n};\n\nconst Torusknot = () => {\n  const meshRef = useRef<Mesh>(null);\n\n  useFrame((_state, delta) => {\n    const mesh = meshRef.current;\n    if (!mesh) return;\n    mesh.rotation.y += delta / 2;\n    mesh.rotation.x = mesh.rotation.y;\n  });\n\n  return (\n    <mesh ref={meshRef} scale={1.25}>\n      <torusKnotGeometry args={[1, 0.2, 128, 32]} />\n      <meshStandardMaterial color=\"#ffffff\" />\n    </mesh>\n  );\n};\n\nconst Renderer = () => {\n  const { gl, scene, camera, size } = useThree();\n  const effectRef = useRef<AsciiEffect>(null);\n\n  useEffect(() => {\n    const effect = new AsciiEffect(gl, \" .:-+*=%@#\");\n\n    effect.domElement.style.position = \"absolute\";\n    effect.domElement.style.top = \"0px\";\n    effect.domElement.style.left = \"0px\";\n    effect.domElement.style.color = \"white\";\n    effect.domElement.style.backgroundColor = \"black\";\n    effect.domElement.style.pointerEvents = \"none\";\n\n    const container = gl.domElement.parentNode;\n    if (container) {\n      container.replaceChild(effect.domElement, gl.domElement);\n    }\n\n    effectRef.current = effect;\n\n    return () => {\n      effectRef.current = null;\n      if (container && effect.domElement.parentNode) {\n        container.replaceChild(gl.domElement, effect.domElement);\n      }\n    };\n  }, [gl]);\n\n  // Resizing must not tear the effect down: recreating it would detach and\n  // reattach the ASCII <div>, dropping a frame on every resize tick.\n  useEffect(() => {\n    effectRef.current?.setSize(size.width, size.height);\n  }, [size.width, size.height]);\n\n  useFrame(() => {\n    if (effectRef.current) {\n      effectRef.current.render(scene, camera);\n    }\n  }, 1);\n\n  return null;\n};\n","target":"uicapsule/ascii-renderer/ascii-renderer.tsx"},{"type":"registry:file","path":"/package.json","content":"{\n  \"name\": \"@uicapsule/ascii-renderer\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"exports\": {\n    \"./preview\": \"./preview.tsx\"\n  },\n  \"scripts\": {\n    \"clean\": \"git clean -xdf .cache .turbo dist node_modules\"\n  },\n  \"dependencies\": {\n    \"@react-three/drei\": \"^10.7.7\",\n    \"@react-three/fiber\": \"^9.6.1\",\n    \"react\": \"catalog:\",\n    \"react-dom\": \"catalog:\",\n    \"three\": \"^0.185.1\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"catalog:\",\n    \"@types/react-dom\": \"catalog:\",\n    \"@types/three\": \"^0.185.1\"\n  }\n}\n","target":"uicapsule/ascii-renderer/package.json"},{"type":"registry:file","path":"/preview.tsx","content":"\"use client\";\n\nimport { AsciiRenderer } from \"./ascii-renderer\";\n\nconst Preview = () => {\n  return <AsciiRenderer />;\n};\n\nexport default Preview;\n","target":"uicapsule/ascii-renderer/preview.tsx"}]}