[
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.development.local\n.env.test.local\n.env.production.local\n.env.local\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n.cache\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v2\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n.vercel\n"
  },
  {
    "path": "README.md",
    "content": "# React Three Fiber WebGPU Post Processing\n\n<h4>by Anderson Mancini</h4>\n\n[![screenshot](https://r3f-webgpu-post-processing.vercel.app/social.jpg)](https://r3f-webgpu-post-processing.vercel.app/)\n\nA very simple scene to demonstrate how to integrate Threejs WebGPU with React Three Fiber using Post Processing effects.\n[See the demo here](https://r3f-webgpu-post-processing.vercel.app/)\n\n### Getting Started using this demo project\n\nDownload and install Node.js on your computer (https://nodejs.org/en/download/).\n\nThen, open VSCODE, drag the project folder to it. Open VSCODE terminal and install dependencies (you need to do this only in the first time)\n\n```shell\nnpm install\n```\n\nRun this command in your terminal to open a local server at localhost:3000\n\n```shell\nnpm run start\n```\n\n### Can you leave a star please?\n\nI genuinely appreciate your support! If you're willing to show your appreciation, you can <strong>give me a star on GitHub 🎉 </strong>or consider buying a coffee to support my development at https://www.buymeacoffee.com/andersonmancini. The funds received will be utilized to create more valuable content about Three.js and invest in acquiring new courses. Thank you for your consideration!\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"basic-demo\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Shows how to form self-contained components with their own state and user interaction.\",\n  \"keywords\": [\n    \"interaction\",\n    \"pointer-events\"\n  ],\n  \"main\": \"src/index.js\",\n  \"dependencies\": {\n    \"@react-three/drei\": \"^9.99.0\",\n    \"@react-three/fiber\": \"^8.15.0\",\n    \"@types/three\": \"^0.177.0\",\n    \"maath\": \"0.10.8\",\n    \"react\": \"18.2.0\",\n    \"react-dom\": \"18.2.0\",\n    \"react-scripts\": \"5.0.1\",\n    \"three\": \"^0.177.0\",\n    \"three-mesh-bvh\": \"^0.8.0\"\n  },\n  \"scripts\": {\n    \"start\": \"set HOST=0.0.0.0 && react-scripts start\",\n    \"build\": \"GENERATE_SOURCEMAP=false react-scripts build\",\n    \"test\": \"react-scripts test --env=jsdom\",\n    \"eject\": \"react-scripts eject\",\n    \"deploy\": \"vercel --prod\"\n  },\n  \"browserslist\": [\n    \">1%\",\n    \"not dead\",\n    \"not ie <= 11\",\n    \"not op_mini all\"\n  ]\n}\n"
  },
  {
    "path": "public/favicon/about.txt",
    "content": "This favicon was generated using the following graphics from Twitter Twemoji:\n\n- Graphics Title: 1f441-200d-1f5e8.svg\n- Graphics Author: Copyright 2020 Twitter, Inc and other contributors (https://github.com/twitter/twemoji)\n- Graphics Source: https://github.com/twitter/twemoji/blob/master/assets/svg/1f441-200d-1f5e8.svg\n- Graphics License: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/)\n"
  },
  {
    "path": "public/favicon/site.webmanifest",
    "content": "{\"name\":\"\",\"short_name\":\"\",\"icons\":[{\"src\":\"/android-chrome-192x192.png\",\"sizes\":\"192x192\",\"type\":\"image/png\"},{\"src\":\"/android-chrome-512x512.png\",\"sizes\":\"512x512\",\"type\":\"image/png\"}],\"theme_color\":\"#ffffff\",\"background_color\":\"#ffffff\",\"display\":\"standalone\"}"
  },
  {
    "path": "public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width, initial-scale=1, shrink-to-fit=no\"\n    />\n    <title>WebGPU Post Processing Example - By Anderson Mancini</title>\n    <meta\n      name=\"description\"\n      content=\"This is a demo of React Three Fiber using post processing with threejs and WebGPU, featuring Screen Space Reflections.\"\n    />\n\n    <meta\n      property=\"og:url\"\n      content=\"https://r3f-webgpu-post-processing.vercel.app\"\n    />\n    <meta property=\"og:type\" content=\"website\" />\n    <meta\n      property=\"og:title\"\n      content=\"This is a demo of React Three Fiber using post processing with threejs and WebGPU, featuring Screen Space Reflections.\"\n    />\n    <meta\n      property=\"og:description\"\n      content=\"This is a demo of React Three Fiber using post processing with threejs and WebGPU, featuring Screen Space Reflections.\"\n    />\n    <meta\n      property=\"og:image\"\n      content=\"https://r3f-webgpu-post-processing.vercel.app/social.jpg\"\n    />\n\n    <meta name=\"twitter:card\" content=\"summary_large_image\" />\n    <meta\n      property=\"twitter:domain\"\n      content=\"r3f-webgpu-post-processing.vercel.app\"\n    />\n    <meta\n      property=\"twitter:url\"\n      content=\"https://r3f-webgpu-post-processing.vercel.app\"\n    />\n    <meta\n      name=\"twitter:title\"\n      content=\"This is a demo of React Three Fiber using post processing with threejs and WebGPU, featuring Screen Space Reflections.\"\n    />\n    <meta\n      name=\"twitter:description\"\n      content=\"This is a demo of React Three Fiber using post processing with threejs and WebGPU, featuring Screen Space Reflections.\"\n    />\n    <meta\n      name=\"twitter:image\"\n      content=\"https://r3f-webgpu-post-processing.vercel.app/social.jpg\"\n    />\n\n    <meta\n      name=\"keywords\"\n      content=\"react three fiber, webgpu, post processing, threejs, HTML, CSS, JavaScript\"\n    />\n    <meta name=\"author\" content=\"Anderson Mancini.dev\" />\n    <meta name=\"msapplication-TileColor\" content=\"#000000\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n\n    <link\n      rel=\"apple-touch-icon\"\n      sizes=\"180x180\"\n      href=\"favicon/apple-touch-icon.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      sizes=\"32x32\"\n      href=\"favicon/favicon-32x32.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      sizes=\"16x16\"\n      href=\"favicon/favicon-16x16.png\"\n    />\n    <link rel=\"manifest\" href=\"favicon/site.webmanifest\" />\n  </head>\n\n  <body>\n    <noscript> You need to enable JavaScript to run this app. </noscript>\n    <div id=\"root\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "src/App.js",
    "content": "import { useState } from \"react\";\nimport { Loader } from \"@react-three/drei\";\nimport { WebGPUPostProcessing } from \"./components/WebGPUPostProcessing\";\nimport { Hall } from \"./components/Hall\";\nimport { Overlay } from \"./components/Overlay\";\nimport RoyalNaboo from \"./components/Royal\";\nimport { Light_Environment } from \"./components/Light_Environment\";\nimport { VaderScene } from \"./components/VaderScene\";\nimport { ManciniCanvas } from \"./components/ManciniCanvas\";\n\nexport default function App() {\n  const [currentScene, setCurrentScene] = useState(\"vader\");\n  const [quality, setQuality] = useState(\"default\");\n  const [isPostProcessingEnabled, setIsPostProcessingEnabled] = useState(true);\n  // Disable frameloop by default, waiting for WebGPU to be ready\n\n  return (\n    <>\n      <Overlay\n        isPostProcessingEnabled={isPostProcessingEnabled}\n        setIsPostProcessingEnabled={setIsPostProcessingEnabled}\n        setCurrentScene={setCurrentScene}\n        currentScene={currentScene}\n        setQuality={setQuality}\n        quality={quality}\n      />\n\n      <Loader />\n\n      <ManciniCanvas quality={quality}>\n        <color attach=\"background\" args={[\"black\"]} />\n\n        {isPostProcessingEnabled && (\n          <WebGPUPostProcessing\n            strength={0.25}\n            radius={0.1}\n            quality={quality}\n          />\n        )}\n\n        <Light_Environment />\n\n        <group position={[-1, 0, 0]}>\n          <Hall position={[16.3, 0, -0.15]} scale={[1, 1, 1.3]} />\n\n          <group\n            visible={currentScene === \"vader\"}\n            scale={[0.8, 0.8, 0.8]}\n            position={[0, -0.25, 0]}\n          >\n            <VaderScene />\n          </group>\n\n          <RoyalNaboo\n            visible={currentScene === \"royal\"}\n            position={[3, -0.5, -2.2]}\n            scale={0.35}\n            rotation={[0, 0, 0]}\n          />\n        </group>\n      </ManciniCanvas>\n    </>\n  );\n}\n"
  },
  {
    "path": "src/components/Darth.js",
    "content": "/*\nAuto-generated by: https://github.com/pmndrs/gltfjsx\nAuthor: AFTONBLADET (https://sketchfab.com/wallander)\nLicense: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)\nSource: https://sketchfab.com/3d-models/darth-vader-by-makeamo-5b3371f4789c41eeaa691c9a3dfe1a96\nTitle: Darth Vader by Makeamo\n*/\n\nimport React, { useRef } from \"react\";\nimport { useGLTF } from \"@react-three/drei\";\n\nexport function Darth(props) {\n  const { nodes, materials } = useGLTF(\"/darth-transformed.glb\");\n\n  materials.Sabel_svart.emissiveIntensity = 20;\n  materials.darthvader_VaderConsolesFlickermat.roughness = 0.2;\n  materials.darthvader_VaderCapemat.roughness = 0.2;\n  materials.darthvader_VaderCapemat.metalness = 0.7;\n  materials.darthvader_VaderHelmetRimmat.roughness = 0.3;\n  materials.darthvader_VaderHelmetRimmat.metalness = 0.6;\n  materials.darthvader_VaderBodyArmourmat.roughness = 0.2;\n  materials.darthvader_VaderBodyArmourmat.metalness = 0.9;\n\n  return (\n    <group {...props} dispose={null}>\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes.DARTH_Sabel_vit_0.geometry}\n        material={materials.Sabel_vit}\n      />\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes.DARTH_darthvader_VaderConsolesFlickermat_0.geometry}\n        material={materials.darthvader_VaderConsolesFlickermat}\n      />\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes.DARTH_darthvader_VaderCapemat_0.geometry}\n        material={materials.darthvader_VaderCapemat}\n      />\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes.DARTH_darthvader_VaderHelmetRimmat_0.geometry}\n        material={materials.darthvader_VaderHelmetRimmat}\n      />\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes.DARTH_darthvader_VaderBodyArmourmat_0.geometry}\n        material={materials.darthvader_VaderBodyArmourmat}\n      />\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes.DARTH_Laser_0.geometry}\n        material={materials.Laser}\n      />\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes.DARTH_Sabel_svart_0.geometry}\n        material={materials.Sabel_svart}\n      />\n    </group>\n  );\n}\n\nuseGLTF.preload(\"/darth-transformed.glb\");\n"
  },
  {
    "path": "src/components/Hall.js",
    "content": "/*\nAuto-generated by: https://github.com/pmndrs/gltfjsx\n*/\n\nimport React, { useRef } from \"react\";\nimport { useGLTF } from \"@react-three/drei\";\nimport { FrontSide } from \"three\";\nexport function Hall(props) {\n  const { nodes, materials } = useGLTF(\"/hall-transformed.glb\");\n\n  materials.VenatorV3_SmallDoor_WallLight.emissiveIntensity = 2.6;\n  materials.Venator_Floor.color.set(\"black\");\n  materials.Venator_Floor.roughness = 0.95;\n  materials.Venator_Floor.normalMap = null;\n\n  //   materials.Venator_Floor.roughnessMap = null;\n  //   materials.Venator_Floor.roughnessMap = null;\n  //   materials.Venator_Floor.metalnessMap = null;\n  //   materials.Venator_Floor.emissiveIntensity = 0;\n\n  materials.Venator_Floor.metalness = 1;\n  materials.Venator_Floor.metalnessMap = null;\n  materials.VenatorV3_WallPanels.color.set(\"grey\");\n  materials.VenatorV3_WallPanels.roughness = 0.8;\n  materials.VenatorV3_WallPanels.metalness = 0.5;\n  materials.VenatorV3_WallPanels.side = FrontSide;\n  materials.VenatorV3_LargeDoor.side = FrontSide;\n  materials.VenatorV3_SmallDoor_WallLight.side = FrontSide;\n\n  return (\n    <group {...props} dispose={null}>\n      <group rotation={[-Math.PI / 2, 0, 0]} scale={0.012}>\n        <group rotation={[Math.PI / 2, 0, 0]}>\n          <group position={[-1448.93, -5.342, -159.366]} scale={6.463}>\n            <mesh\n              receiveShadow\n              geometry={nodes.WallPanel21_VenatorV3_WallPanels_0001.geometry}\n              material={materials.VenatorV3_WallPanels}\n            />\n            <mesh\n              receiveShadow\n              geometry={nodes.WallPanel21_VenatorV3_WallPanels_0001_1.geometry}\n              material={materials.VenatorV3_LargeDoor}\n            />\n            <mesh\n              receiveShadow\n              geometry={nodes.WallPanel21_VenatorV3_WallPanels_0001_2.geometry}\n              material={materials.Venator_Floor}\n            >\n              {/* <meshPhysicalMaterial\n                color=\"black\"\n                metalness={0.8}\n                roughness={0.7}\n              /> */}\n            </mesh>\n            <mesh\n              receiveShadow\n              geometry={nodes.WallPanel21_VenatorV3_WallPanels_0001_3.geometry}\n              material={materials.VenatorV3_SmallDoor_WallLight}\n            />\n          </group>\n        </group>\n      </group>\n    </group>\n  );\n}\n\nuseGLTF.preload(\"/hall-transformed.glb\");\n"
  },
  {
    "path": "src/components/JetEngineMaterial.js",
    "content": "import { useFrame } from \"@react-three/fiber\";\nimport {\n  uniform,\n  float,\n  vec2,\n  sin,\n  cos,\n  uv,\n  mod,\n  div,\n  sub,\n  length,\n  pow,\n  abs,\n  vec3,\n  add,\n  mul,\n} from \"three/tsl\";\n\nexport function useJetEngineMaterial() {\n  // Create uniform and shader calculations\n  const uTime = uniform(float(0.0));\n  const TAU = float(6.28318530718);\n  const MAX_ITER = float(8);\n  const inten = float(0.007);\n\n  // Get UV coordinates and time\n  const currentUV = uv();\n  const currentTime = mul(uTime, float(2.5));\n\n  // Rotate UV coordinates\n  const angle = float(3.147);\n  const s = sin(angle);\n  const c = cos(angle);\n\n  // Create rotation matrix manually\n  const rotatedX = add(mul(currentUV.x, c), mul(currentUV.y, s));\n  const rotatedY = sub(mul(currentUV.x, s), mul(currentUV.y, c));\n  const uvRotated = add(vec2(rotatedX, rotatedY), mul(uTime, float(2.4)));\n\n  // Calculate base coordinates\n  const p = sub(mod(mul(uvRotated, TAU), TAU), float(256.0));\n\n  // Initialize accumulator\n  let accumulator = float(0.9);\n\n  // Unroll the loop\n  for (let i = 0; i < 8; i++) {\n    const t = mul(currentTime, sub(float(1.0), div(float(3.5), float(i + 1))));\n\n    const px = add(cos(sub(t, p.x)), sin(add(t, p.y)));\n    const py = add(sin(sub(t, p.y)), cos(add(t, p.x)));\n\n    const iVec = add(p, vec2(px, py));\n\n    const lenVec = vec2(\n      div(p.x, div(sin(add(iVec.x, t)), inten)),\n      div(p.y, div(cos(add(iVec.y, t)), inten))\n    );\n\n    accumulator = add(accumulator, div(float(1.1), length(lenVec)));\n  }\n\n  // Final color calculations\n  accumulator = div(accumulator, float(MAX_ITER));\n  accumulator = sub(float(1.1), pow(accumulator, float(1.5)));\n\n  const engineColor = pow(abs(accumulator), float(30.0));\n  const finalColor = add(\n    vec3(engineColor).mul(vec3(0, 0.5, 1.0)),\n    vec3(0.0, 0.0, 0.0)\n  ).mul(float(25.0));\n\n  // Update time in animation frame\n  useFrame((state, delta) => {\n    uTime.value += delta * 0.5;\n  });\n\n  return {\n    key: uTime.id,\n    colorNode: finalColor,\n  };\n}\n"
  },
  {
    "path": "src/components/Light_Environment.js",
    "content": "import { Environment } from \"@react-three/drei\";\nimport { OrbitControls } from \"@react-three/drei\";\n\nexport function Light_Environment() {\n  return (\n    <>\n      <directionalLight\n        position={[-0.7, 1.8, 0.1]}\n        intensity={6}\n        castShadow\n        shadow-mapSize={[128, 128]}\n        shadow-camera-near={2}\n        shadow-camera-far={100}\n        shadow-camera-top={3}\n        shadow-camera-right={3}\n        shadow-camera-bottom={-3}\n        shadow-camera-left={-3}\n        shadow-bias={-0.002}\n      />\n      <OrbitControls\n        target={[2, -0.6, 0]}\n        // zoomSpeed={0.8}\n        screenSpacePanning={false}\n        dampingFactor={0.08}\n        maxPolarAngle={Math.PI / 1.75}\n        minPolarAngle={Math.PI / 2.7}\n        maxDistance={2.4}\n        minDistance={1}\n        minZoom={0.5}\n        maxZoom={1}\n      />\n      <Environment\n        preset=\"warehouse\"\n        environmentIntensity={0.2}\n        environmentRotation={[0.4, 0, 1.4]}\n      />\n    </>\n  );\n}\n"
  },
  {
    "path": "src/components/ManciniCanvas.js",
    "content": "import { Canvas, extend } from \"@react-three/fiber\";\nimport { useRef, useState } from \"react\";\nimport * as THREE from \"three/webgpu\";\nimport { ResizeHandler } from \"./ResizeHandler\";\n\nextend(THREE);\n\nexport function ManciniCanvas({ quality, children }) {\n  const rendererRef = useRef();\n  const [frameloop, setFrameloop] = useState(\"never\");\n  return (\n    <Canvas\n      onCreated={(state) => {\n        state.setSize(window.innerWidth, window.innerHeight);\n      }}\n      frameloop={frameloop}\n      dpr={quality === \"default\" ? 1 : [1, 1.5]}\n      camera={{\n        position: [18.6, -0.6, 0],\n        near: 0.1,\n        far: 50,\n        fov: 65,\n        // zoom: 1,\n      }}\n      shadows={\"variance\"}\n      gl={(canvas) => {\n        const renderer = new THREE.WebGPURenderer({\n          canvas,\n          powerPreference: \"high-performance\",\n          antialias: false,\n          alpha: false,\n          stencil: false,\n        });\n\n        // Initialize WebGPU and store renderer reference\n        renderer.init().then(() => setFrameloop(\"always\"));\n        rendererRef.current = renderer;\n        return renderer;\n      }}\n    >\n      {children}\n      <ResizeHandler quality={quality} rendererRef={rendererRef} />\n    </Canvas>\n  );\n}\n"
  },
  {
    "path": "src/components/Overlay.js",
    "content": "export function Overlay({\n  isPostProcessingEnabled,\n  setIsPostProcessingEnabled,\n  currentScene,\n  setCurrentScene,\n  quality,\n  setQuality,\n}) {\n  return (\n    <div className=\"overlay\">\n      <header>\n        <h1>\n          R3F <span>WebGPU</span>\n        </h1>\n        <p>\n          This is a demo of React Three Fiber using post processing with threejs\n          and WebGPU, featuring Screen Space Reflections.\n        </p>\n      </header>\n      <footer>\n        <p className=\"footer-text\">\n          Created by <a href=\"https://andersonmancini.dev\">Anderson Mancini</a>\n        </p>\n        <div className=\"footer-buttons\">\n          <button\n            onClick={() => setIsPostProcessingEnabled(!isPostProcessingEnabled)}\n          >\n            {isPostProcessingEnabled ? \"Disable\" : \"Enable\"} Post Processing\n          </button>\n          <button\n            className=\"toggle\"\n            onClick={() =>\n              setCurrentScene(currentScene === \"vader\" ? \"royal\" : \"vader\")\n            }\n          >\n            Toggle Scene\n          </button>\n          <button\n            onClick={() =>\n              setQuality(quality === \"default\" ? \"high\" : \"default\")\n            }\n            className=\"toggle-quality\"\n          >\n            {quality === \"default\" ? \"Higher Quality\" : \"Performance Mode\"}\n          </button>\n        </div>\n        <a\n          href=\"https://github.com/ektogamat/r3f-webgpu-starter\"\n          download\n          className=\"download-button\"\n        >\n          <SvgIcon />\n        </a>\n      </footer>\n    </div>\n  );\n}\n\nconst SvgIcon = (props) => (\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    width=\"24\"\n    height=\"24\"\n    viewBox=\"0 0 24 24\"\n    fill=\"white\"\n  >\n    <path\n      d=\"m20.59 12-3.3-3.3a1 1 0 1 1 1.42-1.4l4 4a1 1 0 0 1 0 1.4l-4 4a1 1 0 0 1-1.42-1.4zM3.4 12l3.3 3.3a1 1 0 0 1-1.42 1.4l-4-4a1 1 0 0 1 0-1.4l4-4A1 1 0 0 1 6.7 8.7zm7.56 8.24a1 1 0 0 1-1.94-.48l4-16a1 1 0 1 1 1.94.48z\"\n      className=\"heroicon-ui\"\n    ></path>\n  </svg>\n);\n"
  },
  {
    "path": "src/components/Probe.js",
    "content": "import React, { useRef } from \"react\";\nimport { useGLTF } from \"@react-three/drei\";\n\nexport function Probe(props) {\n  const { nodes, materials } = useGLTF(\"/probe-transformed.glb\");\n  const lightMaterial = materials.light.clone();\n  lightMaterial.emissiveIntensity = 10;\n  lightMaterial.emissive.set(props.color);\n\n  return (\n    <group {...props} dispose={null}>\n      <group position={[-0.423, 0.036, -0.084]} rotation={[-Math.PI / 2, 0, 0]}>\n        <mesh\n          castShadow\n          receiveShadow\n          geometry={nodes[\"cam_low_Material_#26_0_1\"].geometry}\n          material={materials.Material_26}\n        />\n        <mesh\n          castShadow\n          receiveShadow\n          geometry={nodes[\"cam_low_Material_#26_0_2\"].geometry}\n          material={lightMaterial}\n        />\n      </group>\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes[\"ball_low_Material_#26_0\"].geometry}\n        material={materials.Material_26}\n        position={[-0.423, 0.036, -0.084]}\n        rotation={[-Math.PI / 2, 0, 0]}\n      />\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes[\"d_low_Material_#26_0\"].geometry}\n        material={materials.Material_26}\n        position={[-0.423, 0.036, -0.084]}\n        rotation={[-Math.PI / 2, 0, 0]}\n      />\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes[\"inner_low_Material_#26_0\"].geometry}\n        material={materials.Material_26}\n        position={[-0.211, -0.033, 7.813]}\n        rotation={[-Math.PI / 2, 0, 0]}\n      />\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes[\"Object018_Material_#26_0\"].geometry}\n        material={lightMaterial}\n        position={[-0.423, 0.036, -0.084]}\n        rotation={[-Math.PI / 2, 0, 0]}\n      />\n      <mesh\n        castShadow\n        receiveShadow\n        geometry={nodes[\"shell_low_Material_#26_0\"].geometry}\n        position={[-0.423, 0.036, -0.084]}\n        rotation={[-Math.PI / 2, 0, 0]}\n      >\n        <meshPhysicalMaterial\n          color=\"white\"\n          roughness={0.35}\n          metalness={1}\n          clearcoat={1}\n        />\n      </mesh>\n    </group>\n  );\n}\n\nuseGLTF.preload(\"/probe-transformed.glb\");\n"
  },
  {
    "path": "src/components/ResizeHandler.js",
    "content": "import { useEffect } from \"react\";\n\nexport function ResizeHandler({ quality, rendererRef }) {\n  useEffect(() => {\n    const handleResize = () => {\n      if (rendererRef.current) {\n        rendererRef.current.setSize(window.innerWidth, window.innerHeight);\n      }\n    };\n\n    window.addEventListener(\"resize\", handleResize);\n\n    // Cleanup\n    return () => window.removeEventListener(\"resize\", handleResize);\n  }, [quality]);\n\n  return null;\n}\n"
  },
  {
    "path": "src/components/Royal.js",
    "content": "/*\nAuto-generated by: https://github.com/pmndrs/gltfjsx\nCommand: npx gltfjsx@6.1.4 naboo_royal_starship.glb --transform --simplify\nAuthor: hobbit84 (https://sketchfab.com/hobbit84)\nLicense: CC-BY-NC-4.0 (http://creativecommons.org/licenses/by-nc/4.0/)\nSource: https://sketchfab.com/3d-models/naboo-royal-starship-j-type-327-nubian-f631077977754b5591298ecfa201380b\nTitle: Naboo Royal Starship (J-type 327 Nubian)\n*/\n\nimport React from \"react\";\nimport { Float, useGLTF } from \"@react-three/drei\";\nimport { AdditiveBlending, DoubleSide } from \"three\";\nimport { useJetEngineMaterial } from \"./JetEngineMaterial\";\n\nexport default function RoyalNaboo(props) {\n  const { nodes, materials } = useGLTF(\"/naboo_royal_starship-transformed.glb\");\n  const { key, colorNode } = useJetEngineMaterial();\n\n  materials[\"blinn1.002\"].roughness = 0.15;\n  materials[\"blinn1.002\"].metalness = 1;\n  materials[\"blinn1.002\"].roughnessMap = null;\n\n  return (\n    <Float speed={2} floatIntensity={0.2} rotationIntensity={0.3}>\n      <group {...props} dispose={null}>\n        <group position={[-0.01, 0, 6.5]} rotation={[-Math.PI / 2, 0, Math.PI]}>\n          <mesh\n            castShadow\n            receiveShadow\n            geometry={nodes.Object_2.geometry}\n            material={materials[\"Material.002\"]}\n          />\n          <mesh\n            castShadow\n            receiveShadow\n            geometry={nodes.Object_3.geometry}\n            material={materials[\"aiwindow.002\"]}\n          />\n          <mesh\n            castShadow\n            receiveShadow\n            geometry={nodes.Object_4.geometry}\n            material={materials[\"blinn1.002\"]}\n          />\n          <mesh\n            castShadow\n            receiveShadow\n            geometry={nodes.Object_5.geometry}\n            material={materials[\"blinn1.002\"]}\n          />\n          <mesh\n            castShadow\n            receiveShadow\n            geometry={nodes.Object_6.geometry}\n            material={materials[\"blinn1.002\"]}\n          />\n          <mesh position={[-1.48, -4.1, -0.36]}>\n            <cylinderGeometry args={[0.2, 0.01, 2.9, 16, 8, true]} />\n            <meshStandardNodeMaterial\n              key={key}\n              colorNode={colorNode}\n              transparent\n              blending={AdditiveBlending}\n              side={DoubleSide}\n              emissiveNode={colorNode}\n            />\n          </mesh>\n          <mesh position={[1.48, -4.1, -0.36]}>\n            <cylinderGeometry args={[0.2, 0.01, 2.9, 16, 8, true]} />\n            <meshStandardNodeMaterial\n              key={key}\n              colorNode={colorNode}\n              transparent\n              blending={AdditiveBlending}\n              side={DoubleSide}\n              emissiveNode={colorNode}\n            />\n          </mesh>\n          <mesh\n            rotation={[Math.PI / 2, 0, 0]}\n            position={[1.51, -2.68, -0.37]}\n            renderOrder={-1}\n          >\n            <torusGeometry args={[0.2, 0.03, 24, 24]} />\n            <meshStandardNodeMaterial\n              color=\"red\"\n              transparent\n              emissive=\"cyan\"\n              emissiveIntensity={10}\n            />\n          </mesh>\n          <mesh\n            rotation={[Math.PI / 2, 0, 0]}\n            position={[-1.5, -2.68, -0.36]}\n            renderOrder={-1}\n          >\n            <torusGeometry args={[0.2, 0.03, 24, 24]} />\n            <meshStandardNodeMaterial\n              color=\"cyan\"\n              transparent\n              emissive=\"cyan\"\n              emissiveIntensity={10}\n            />\n          </mesh>\n        </group>\n      </group>\n    </Float>\n  );\n}\n\nuseGLTF.preload(\"/naboo_royal_starship-transformed.glb\");\n"
  },
  {
    "path": "src/components/VaderScene.js",
    "content": "import { Float } from \"@react-three/drei\";\nimport { Probe } from \"./Probe\";\nimport { Darth } from \"./Darth\";\n\nexport function VaderScene() {\n  return (\n    <>\n      <Float speed={3.5} floatIntensity={0.2} rotationIntensity={0.3}>\n        <Probe\n          position={[3, 0, 1.2]}\n          scale={0.05}\n          rotation={[0, Math.PI / 2, 0]}\n          color=\"red\"\n        />\n      </Float>\n      <Float speed={6.5} floatIntensity={0.4} rotationIntensity={0.5}>\n        <Probe\n          position={[-1.5, 0, -1.5]}\n          scale={0.1}\n          rotation={[0, Math.PI / 2, 0]}\n          color=\"cyan\"\n        />\n      </Float>\n      <Float speed={3.5} floatIntensity={0.2} rotationIntensity={0.3}>\n        <Probe\n          position={[3.5, -0.8, -1.2]}\n          scale={0.05}\n          rotation={[0, Math.PI / 2, 0]}\n          color=\"red\"\n        />\n      </Float>\n      <Float speed={3.5} floatIntensity={1.5} rotationIntensity={0.4}>\n        <Probe\n          position={[3, 0.2, -2.8]}\n          scale={0.05}\n          rotation={[0, Math.PI / 2 - 0.2, 0.1]}\n          color=\"cyan\"\n        />\n      </Float>\n      <Float speed={3.5} floatIntensity={1.5} rotationIntensity={0.4}>\n        <Probe\n          position={[2.6, 0.2, 2.8]}\n          scale={0.05}\n          rotation={[0, Math.PI / 2 + 0.5, 0.1]}\n          color=\"cyan\"\n        />\n      </Float>\n      <Darth\n        scale={0.008}\n        position={[3.5, -1.325, 0.4]}\n        rotation={[0, Math.PI / 2, 0]}\n      />\n    </>\n  );\n}\n"
  },
  {
    "path": "src/components/WebGPUPostProcessing.js",
    "content": "import * as THREE from \"three/webgpu\";\nimport {\n  pass,\n  mrt,\n  output,\n  transformedNormalView,\n  metalness,\n  blendColor,\n  depth,\n  emissive,\n} from \"three/tsl\";\nimport { bloom } from \"three/addons/tsl/display/BloomNode.js\";\nimport { ssr } from \"three/addons/tsl/display/SSRNode.js\";\nimport { smaa } from \"three/addons/tsl/display/SMAANode.js\";\nimport { useThree, useFrame } from \"@react-three/fiber\";\nimport { useEffect, useRef } from \"react\";\n\nexport function WebGPUPostProcessing({\n  strength = 2.5,\n  radius = 0.5,\n  quality = \"default\",\n}) {\n  const { gl: renderer, scene, camera, size } = useThree();\n  const postProcessingRef = useRef(null);\n\n  useEffect(() => {\n    if (!renderer || !scene || !camera) return;\n\n    // Create post-processing setup with specific filters\n    const scenePass = pass(scene, camera, {\n      minFilter: THREE.LinearFilter,\n      magFilter: THREE.LinearFilter,\n    });\n\n    // Setup Multiple Render Targets (MRT)\n    scenePass.setMRT(\n      mrt({\n        output: output,\n        normal: transformedNormalView,\n        metalness: metalness,\n        emissive: emissive,\n      })\n    );\n\n    // Get texture nodes\n    const scenePassColor = scenePass.getTextureNode(\"output\");\n    const scenePassNormal = scenePass.getTextureNode(\"normal\");\n    const scenePassDepth = scenePass.getTextureNode(\"depth\");\n    const scenePassMetalness = scenePass.getTextureNode(\"metalness\");\n    const scenePassEmissive = scenePass.getTextureNode(\"emissive\");\n\n    // Create SSR pass\n    const ssrPass = ssr(\n      scenePassColor,\n      scenePassDepth,\n      scenePassNormal,\n      scenePassMetalness,\n      camera\n    );\n    ssrPass.resolutionScale = 0.65;\n    ssrPass.maxDistance.value = 0.65;\n    ssrPass.opacity.value = 0.85;\n    ssrPass.thickness.value = 0.015;\n\n    // Create bloom pass\n    const bloomPass = bloom(scenePassEmissive, strength, radius, 0.6);\n\n    // Blend SSR over beauty with SMAA\n    const outputNode = smaa(blendColor(scenePassColor.add(bloomPass), ssrPass));\n\n    // Setup post-processing\n    const postProcessing = new THREE.PostProcessing(renderer);\n    postProcessing.outputNode = outputNode;\n    postProcessingRef.current = postProcessing;\n\n    // Handle window resize\n\n    if (postProcessingRef.current.setSize) {\n      postProcessingRef.current.setSize(size.width, size.height);\n      postProcessingRef.current.needsUpdate = true;\n    }\n\n    return () => {\n      postProcessingRef.current = null;\n    };\n  }, [renderer, scene, camera, size, strength, radius, quality]);\n\n  useFrame(({ gl, scene, camera }) => {\n    if (postProcessingRef.current) {\n      gl.clear();\n      postProcessingRef.current.render();\n    }\n  }, 1);\n\n  return null;\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import { createRoot } from 'react-dom/client'\nimport './styles.css'\nimport App from './App'\n\ncreateRoot(window.root).render(<App />)\n"
  },
  {
    "path": "src/styles.css",
    "content": "@import url(\"https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap\");\n\n:root {\n  --bg-background: #111827;\n  --clr-card: #1f2937;\n  --clr-1: #6420aa;\n  --clr-2: #ff3ea5;\n  --clr-3: #ff7ed4;\n}\n\n* {\n  box-sizing: border-box;\n}\n\nhtml,\nbody,\ncanvas {\n  width: 100%;\n  height: 100%;\n  margin: 0;\n  padding: 0;\n  font-family: \"Inter\", sans-serif;\n  overflow: hidden;\n  touch-action: none;\n}\n\nbody {\n  background: #020202;\n}\n\n.overlay {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  z-index: 1000;\n  pointer-events: none;\n  display: flex;\n  justify-content: center;\n  align-items: flex-start;\n}\n\nheader {\n  background-image: linear-gradient(\n    to bottom,\n    #020202,\n    rgba(0, 0, 0, 0.775),\n    #02020200\n  );\n  width: 100%;\n  height: 170px;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n}\n\nheader h1 {\n  margin: 0;\n  padding: 0;\n  color: white;\n  font-size: 3rem;\n  font-weight: 300;\n  letter-spacing: -0.04em;\n  text-transform: uppercase;\n  text-align: center;\n}\n\nheader h1 span {\n  font-weight: 900;\n}\n\nheader p {\n  color: white;\n  font-size: 0.8rem;\n  font-weight: 200;\n  letter-spacing: -0.04em;\n  text-align: center;\n  margin-top: 0.5rem;\n  padding: 0;\n  max-width: 500px;\n}\n\nfooter {\n  width: 100%;\n  height: 110px;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  position: absolute;\n  bottom: 0;\n}\n\n.footer-buttons {\n  display: flex;\n  gap: 2rem;\n}\n\n@property --gradient-angle {\n  syntax: \"<angle>\";\n  initial-value: 90deg;\n  inherits: false;\n}\n\nfooter button {\n  color: white;\n  padding: 1rem 1.3rem;\n  border-radius: 0.5rem;\n  box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);\n  font-size: 0.45rem;\n  text-transform: uppercase;\n  letter-spacing: 0.06em;\n  font-weight: 300;\n  pointer-events: all;\n  cursor: pointer;\n  position: relative;\n  cursor: pointer;\n  border: none;\n  border-radius: 50px;\n  background-color: var(--clr-card);\n  transition: all 0.3s ease;\n}\n\nfooter button:hover {\n  background: rgb(65, 60, 79);\n  color: white;\n}\n\nfooter button:hover:after {\n  transform: scale(1.5);\n  filter: blur(2rem);\n  transition: all 0.3s ease;\n}\n\nfooter button::after,\nfooter button::before {\n  content: \" \";\n  position: absolute;\n  z-index: -1;\n  inset: -0.06rem;\n  background: conic-gradient(\n    from var(--gradient-angle),\n    var(--clr-card),\n    var(--clr-1),\n    var(--clr-2),\n    var(--clr-3),\n    var(--clr-2),\n    var(--clr-1),\n    var(--clr-card)\n  );\n  border-radius: inherit;\n  animation: rotate 2.5s ease-in-out infinite;\n  transition: all 0.3s ease;\n}\n\nfooter button.toggle::before {\n  content: \" \";\n  position: absolute;\n  z-index: -1;\n  inset: -0.06rem;\n  background: conic-gradient(\n    from var(--gradient-angle),\n    var(--clr-card),\n    var(--clr-1),\n    var(--clr-2),\n    var(--clr-3),\n    var(--clr-2),\n    var(--clr-1),\n    var(--clr-card)\n  );\n  border-radius: inherit;\n  animation: rotate2 3.5s ease-in-out infinite;\n  transition: all 0.3s ease;\n}\n\nfooter button::after {\n  filter: blur(3rem);\n}\n\n@keyframes rotate {\n  0% {\n    --gradient-angle: 0deg;\n  }\n  100% {\n    --gradient-angle: 360deg;\n  }\n}\n\n@keyframes rotate2 {\n  0% {\n    --gradient-angle: 0deg;\n  }\n  50% {\n    --gradient-angle: 120deg;\n  }\n  100% {\n    --gradient-angle: 360deg;\n  }\n}\n\n.footer-text {\n  color: white;\n  font-size: 0.8rem;\n  font-weight: 200;\n  letter-spacing: -0.04em;\n  text-align: center;\n  padding: 0;\n  position: absolute;\n  bottom: 20px;\n  left: 20px;\n  width: max-content;\n  opacity: 0.3;\n}\n\n.footer-text a {\n  color: white;\n  font-weight: 400;\n  text-decoration: none;\n  pointer-events: all;\n}\n\n.download-button {\n  position: fixed;\n  bottom: 20px;\n  right: 20px;\n  background-color: transparent;\n  border: 1px solid white;\n  border-radius: 50px;\n  padding: 10px 10px;\n  text-align: center;\n  cursor: pointer;\n  z-index: 1000;\n  pointer-events: all;\n  display: flex;\n  opacity: 0.3;\n}\n\n.download-button img {\n  width: 20px;\n  height: 20px;\n  vertical-align: middle;\n}\n\n.download-button:hover {\n  background-color: #ffffff7b;\n}\n\n/* Mobile */\n@media (max-width: 768px) {\n  header h1 {\n    font-size: 2.5rem;\n  }\n\n  header p {\n    font-size: 0.9rem;\n    max-width: 300px;\n  }\n  .download-button {\n    display: none;\n  }\n\n  .footer-buttons {\n    gap: 0.5rem;\n  }\n  footer {\n    height: 150px;\n  }\n\n  footer button {\n    padding: 0.9rem 1.3rem;\n    font-size: 0.5rem;\n  }\n\n  footer button.toggle-quality {\n    display: none;\n  }\n\n  .footer-text {\n    font-size: 0.6rem;\n    bottom: 10px;\n    left: 50%;\n    transform: translateX(-50%);\n  }\n}\n"
  }
]