{"id":528,"date":"2025-06-13T22:06:23","date_gmt":"2025-06-13T22:06:23","guid":{"rendered":"https:\/\/kurtgrung.com\/blog\/?p=528"},"modified":"2025-06-14T10:38:21","modified_gmt":"2025-06-14T10:38:21","slug":"featured-on-codepen","status":"publish","type":"post","link":"https:\/\/kurtgrung.com\/blog\/featured-on-codepen\/","title":{"rendered":"Featured on CodePen"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"769\" src=\"https:\/\/kurtgrung.com\/blog\/wp-content\/uploads\/2025\/06\/Codepen-Picked-Three-1024x769.png\" alt=\"\" class=\"wp-image-529\" style=\"width:709px;height:auto\" srcset=\"https:\/\/kurtgrung.com\/blog\/wp-content\/uploads\/2025\/06\/Codepen-Picked-Three-1024x769.png 1024w, https:\/\/kurtgrung.com\/blog\/wp-content\/uploads\/2025\/06\/Codepen-Picked-Three-300x225.png 300w, https:\/\/kurtgrung.com\/blog\/wp-content\/uploads\/2025\/06\/Codepen-Picked-Three-768x577.png 768w, https:\/\/kurtgrung.com\/blog\/wp-content\/uploads\/2025\/06\/Codepen-Picked-Three-1536x1154.png 1536w, https:\/\/kurtgrung.com\/blog\/wp-content\/uploads\/2025\/06\/Codepen-Picked-Three-2048x1538.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><br><br>I recently built a generative animation using&nbsp;Three.js, and it was picked for CodePen\u2019s trending section! <br><br>In this post, I\u2019ll break down the techniques behind the animation from procedural geometry to camera movement through a tubular 3D curve.<br><br><br><strong>Overview<\/strong><br><br>This project explores how to animate a camera moving through a twisting tube generated along a curve using&nbsp;CatmullRomCurve3. The entire scene is rendered using&nbsp;TubeGeometry, enhanced with a glowing wireframe aesthetic and a subtle bloom pass.<br><br><br><strong>Core Techniques<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>CatmullRomCurve3&nbsp;to generate a looping path.<\/li>\n\n\n\n<li>TubeGeometry&nbsp;to form the main tunnel.<\/li>\n\n\n\n<li>FrenetFrames&nbsp;for correct orientation of ring segments along the curve.<\/li>\n\n\n\n<li>EffectComposer&nbsp;and&nbsp;UnrealBloomPass&nbsp;for post-processing.<\/li>\n\n\n\n<li>Responsive resizing and smooth camera movement using interpolation.<br><\/li>\n<\/ul>\n\n\n\n<p><br>Three.js continues to be a great way to blend art and code. This piece was built in under a day but became something visually captivating. I hope it inspires others. <br><\/p>\n\n\n\n<p><br>See it in action here! \ud83d\ude80 <a href=\"https:\/\/codepen.io\/kurtgrung\/pen\/LEVEGby\">https:\/\/codepen.io\/kurtgrung\/pen\/LEVEGby<\/a> <\/p>\n\n\n\n<p><br><\/p>\n\n\n\n<iframe height=\"600\" style=\"width: 100%;\" scrolling=\"no\" title=\"Wormhole using Three.js\" src=\"https:\/\/codepen.io\/kurtgrung\/embed\/LEVEGby?default-tab=\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href=\"https:\/\/codepen.io\/kurtgrung\/pen\/LEVEGby\">\n  Wormhole using Three.js<\/a> by Kurt Gr\u00fcng (<a href=\"https:\/\/codepen.io\/kurtgrung\">@kurtgrung<\/a>)\n  on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.\n<\/iframe>\n\n\n\n<p><br><br><strong>Code<\/strong><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><textarea class=\"code-block-pro-copy-button-textarea\" aria-hidden=\"true\" readonly>\/\/ code by Kurt Gr\u00fcng\n\nconst MathUtils = {\n  normalize: (value, min, max) => (value &#8211; min) \/ (max &#8211; min),\n  interpolate: (normValue, min, max) => min + (max &#8211; min) * normValue,\n  map: (value, min1, max1, min2, max2) => {\n    value = Math.min(Math.max(value, min1), max1);\n    return MathUtils.interpolate(\n      MathUtils.normalize(value, min1, max1),\n      min2,\n      max2\n    );\n  }\n};\n\nlet w = window.innerWidth;\nlet h = window.innerHeight;\n\nconst renderer = new THREE.WebGLRenderer({\n  canvas: document.querySelector(&#8220;canvas&#8221;),\n  antialias: true,\n  shadowMapEnabled: true,\n  shadowMapType: THREE.PCFSoftShadowMap\n});\nrenderer.setSize(w, h);\n\nconst scene = new THREE.Scene();\nscene.background = new THREE.Color(0x000000);\n\nconst camera = new THREE.PerspectiveCamera(45, w \/ h, 0.001, 200);\nlet cameraRotationProxyX = Math.PI;\nlet cameraRotationProxyY = 0;\ncamera.rotation.y = cameraRotationProxyX;\ncamera.rotation.z = cameraRotationProxyY;\n\nconst cameraGroup = new THREE.Group();\ncameraGroup.position.z = 400;\ncameraGroup.add(camera);\nscene.add(cameraGroup);\n\nconst generatePathPoints = (count = 10, spacing = 25) => {\n  const points = [];\n  for (let i = 0; i &lt; count; i++) {\n    const x = i * spacing;\n    const y = Math.sin(i * 0.5 + Math.random()) * 100 + 50;\n    const z = Math.cos(i * 0.3 + Math.random()) * 100 + 50;\n    points.push(new THREE.Vector3(x, z, y));\n  }\n  return points;\n};\n\nconst points = generatePathPoints(10);\nconst path = new THREE.CatmullRomCurve3(points);\npath.closed = true;\npath.tension = 1;\n\nconst ringCount = 600;\nconst ringRadius = 3;\nconst ringSegments = 32;\n\nconst geometry = new THREE.TubeGeometry(\n  path,\n  ringCount,\n  ringRadius,\n  ringSegments,\n  true\n);\nconst wireframe = new THREE.LineSegments(\n  new THREE.EdgesGeometry(geometry),\n  new THREE.LineBasicMaterial({ linewidth: 0.1, opacity: 0.1 })\n);\nscene.add(wireframe);\n\nconst ringMaterial = new THREE.LineBasicMaterial({ color: 0xffffff });\n\nconst ringMaterial1 = new THREE.LineBasicMaterial({\n  color: 0xffffff,\n  transparent: true,\n  opacity: 0.8,\n  depthWrite: false\n});\n\nconst frenetFrames = path.computeFrenetFrames(ringCount, true);\n\nfor (let i = 0; i &lt;= ringCount; i++) {\n  const t = i \/ ringCount;\n  const pos = path.getPointAt(t);\n  const normal = frenetFrames.normals[i];\n  const binormal = frenetFrames.binormals[i];\n\n  const ringPoints = [];\n  for (let j = 0; j &lt;= ringSegments; j++) {\n    const theta = (j \/ ringSegments) * Math.PI * 2;\n    const x = Math.cos(theta) * ringRadius;\n    const y = Math.sin(theta) * ringRadius;\n\n    const point = new THREE.Vector3().addVectors(\n      pos,\n      new THREE.Vector3()\n        .addScaledVector(normal, x)\n        .addScaledVector(binormal, y)\n    );\n\n    ringPoints.push(point);\n  }\n\n  const ringGeometry = new THREE.BufferGeometry().setFromPoints(ringPoints);\n  const ringMesh = new THREE.LineLoop(ringGeometry, ringMaterial);\n  scene.add(ringMesh);\n}\n\nconst light = new THREE.PointLight(0xffffff, 0.1, 4, 0);\nlight.castShadow = true;\nscene.add(light);\n\nconst renderScene = new THREE.RenderPass(scene, camera);\nconst bloomPass = new THREE.UnrealBloomPass(\n  new THREE.Vector2(w, h),\n  1.5,\n  0.4,\n  0.5\n);\nbloomPass.renderToScreen = true;\n\nconst composer = new THREE.EffectComposer(renderer);\ncomposer.setSize(w, h);\ncomposer.addPass(renderScene);\ncomposer.addPass(bloomPass);\n\nlet cameraTargetPercentage = 0;\nlet currentCameraPercentage = 0;\n\nfunction updateCameraPercentage(percentage) {\n  const p1 = path.getPointAt(percentage % 1);\n  const p2 = path.getPointAt((percentage + 0.01) % 1);\n\n  cameraGroup.position.set(p1.x, p1.y, p1.z);\n  cameraGroup.lookAt(p2);\n  light.position.set(p2.x, p2.y, p2.z);\n}\n\nconst tubePerc = { percent: 0 };\n\nfunction render() {\n  cameraTargetPercentage = (cameraTargetPercentage + 0.001) % 1;\n\n  camera.rotation.y += (cameraRotationProxyX &#8211; camera.rotation.y) \/ 15;\n  camera.rotation.x += (cameraRotationProxyY &#8211; camera.rotation.x) \/ 15;\n  updateCameraPercentage(cameraTargetPercentage);\n  composer.render();\n  requestAnimationFrame(render);\n  console.log(cameraTargetPercentage);\n}\n\nrequestAnimationFrame(render);\n\nwindow.addEventListener(&#8220;resize&#8221;, () => {\n  w = window.innerWidth;\n  h = window.innerHeight;\n  camera.aspect = w \/ h;\n  camera.updateProjectionMatrix();\n  renderer.setSize(w, h);\n  composer.setSize(w, h);\n});\n<\/textarea><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #616E88\">\/\/ code by Kurt Gr\u00fcng<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">MathUtils<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">normalize<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">value<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">min<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">max<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=&gt;<\/span><span style=\"color: #D8DEE9FF\"> (<\/span><span style=\"color: #D8DEE9\">value<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">-<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">min<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #81A1C1\">\/<\/span><span style=\"color: #D8DEE9FF\"> (<\/span><span style=\"color: #D8DEE9\">max<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">-<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">min<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">interpolate<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">normValue<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">min<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">max<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=&gt;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">min<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">+<\/span><span style=\"color: #D8DEE9FF\"> (<\/span><span style=\"color: #D8DEE9\">max<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">-<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">min<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #81A1C1\">*<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">normValue<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">map<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">value<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">min1<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">max1<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">min2<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">max2<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=&gt;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #D8DEE9\">value<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">Math<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">min<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">Math<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">max<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">value<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">min1<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">max1<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">return<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">MathUtils<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">interpolate<\/span><span style=\"color: #D8DEE9FF\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">      <\/span><span style=\"color: #D8DEE9\">MathUtils<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">normalize<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">value<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">min1<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">max1<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">      <\/span><span style=\"color: #D8DEE9\">min2<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">      <\/span><span style=\"color: #D8DEE9\">max2<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    )<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #ECEFF4\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">}<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">let<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">w<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">window<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">innerWidth<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">let<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">h<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">window<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">innerHeight<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">renderer<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">WebGLRenderer<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">canvas<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">document<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">querySelector<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">canvas<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">antialias<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">true<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">shadowMapEnabled<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">true<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">shadowMapType<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">PCFSoftShadowMap<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">}<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">renderer<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">setSize<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">w<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">h<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">scene<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">Scene<\/span><span style=\"color: #D8DEE9FF\">()<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">scene<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">background<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">Color<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #B48EAD\">0x000000<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">camera<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">PerspectiveCamera<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #B48EAD\">45<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">w<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">\/<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">h<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0.001<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">200<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">let<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">cameraRotationProxyX<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">Math<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">PI<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">let<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">cameraRotationProxyY<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">camera<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">rotation<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">y<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">cameraRotationProxyX<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">camera<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">rotation<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">z<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">cameraRotationProxyY<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">cameraGroup<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">Group<\/span><span style=\"color: #D8DEE9FF\">()<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">cameraGroup<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">position<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">z<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">400<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">cameraGroup<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">add<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">camera<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">scene<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">add<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">cameraGroup<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">generatePathPoints<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">count<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">10<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">spacing<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">25<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=&gt;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">points<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> []<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">for<\/span><span style=\"color: #D8DEE9FF\"> (<\/span><span style=\"color: #81A1C1\">let<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0<\/span><span style=\"color: #81A1C1\">;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">&lt;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">count<\/span><span style=\"color: #81A1C1\">;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #81A1C1\">++<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">x<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">*<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">spacing<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">y<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">Math<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">sin<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">*<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0.5<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">+<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">Math<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">random<\/span><span style=\"color: #D8DEE9FF\">()) <\/span><span style=\"color: #81A1C1\">*<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">100<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">+<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">50<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">z<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">Math<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">cos<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">*<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0.3<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">+<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">Math<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">random<\/span><span style=\"color: #D8DEE9FF\">()) <\/span><span style=\"color: #81A1C1\">*<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">100<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">+<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">50<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #D8DEE9\">points<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">push<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">Vector3<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">x<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">z<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">y<\/span><span style=\"color: #D8DEE9FF\">))<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #ECEFF4\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">return<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">points<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">}<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">points<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">generatePathPoints<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #B48EAD\">10<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">path<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">CatmullRomCurve3<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">points<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">path<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">closed<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">true;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">path<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">tension<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">1<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringCount<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">600<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringRadius<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">3<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringSegments<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">32<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">geometry<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">TubeGeometry<\/span><span style=\"color: #D8DEE9FF\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">path<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">ringCount<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">ringRadius<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">ringSegments<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">true<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">wireframe<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">LineSegments<\/span><span style=\"color: #D8DEE9FF\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">EdgesGeometry<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">geometry<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">LineBasicMaterial<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #ECEFF4\">{<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">linewidth<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0.1<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">opacity<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0.1<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">}<\/span><span style=\"color: #D8DEE9FF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">scene<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">add<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">wireframe<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringMaterial<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">LineBasicMaterial<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #ECEFF4\">{<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">color<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0xffffff<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">}<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringMaterial1<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">LineBasicMaterial<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">color<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0xffffff<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">transparent<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">true<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">opacity<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0.8<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">depthWrite<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">}<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">frenetFrames<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">path<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">computeFrenetFrames<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">ringCount<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">true<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">for<\/span><span style=\"color: #D8DEE9FF\"> (<\/span><span style=\"color: #81A1C1\">let<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0<\/span><span style=\"color: #81A1C1\">;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">&lt;=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringCount<\/span><span style=\"color: #81A1C1\">;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #81A1C1\">++<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">t<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">\/<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringCount<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">pos<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">path<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">getPointAt<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">t<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">normal<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">frenetFrames<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">normals<\/span><span style=\"color: #D8DEE9FF\">[<\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #D8DEE9FF\">]<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">binormal<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">frenetFrames<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">binormals<\/span><span style=\"color: #D8DEE9FF\">[<\/span><span style=\"color: #D8DEE9\">i<\/span><span style=\"color: #D8DEE9FF\">]<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringPoints<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> []<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">for<\/span><span style=\"color: #D8DEE9FF\"> (<\/span><span style=\"color: #81A1C1\">let<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">j<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0<\/span><span style=\"color: #81A1C1\">;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">j<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">&lt;=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringSegments<\/span><span style=\"color: #81A1C1\">;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">j<\/span><span style=\"color: #81A1C1\">++<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">theta<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> (<\/span><span style=\"color: #D8DEE9\">j<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">\/<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringSegments<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #81A1C1\">*<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">Math<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">PI<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">*<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">2<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">x<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">Math<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">cos<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">theta<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #81A1C1\">*<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringRadius<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">y<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">Math<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">sin<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">theta<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #81A1C1\">*<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringRadius<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">point<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">Vector3<\/span><span style=\"color: #D8DEE9FF\">()<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">addVectors<\/span><span style=\"color: #D8DEE9FF\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">      <\/span><span style=\"color: #D8DEE9\">pos<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">      <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">Vector3<\/span><span style=\"color: #D8DEE9FF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">        <\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">addScaledVector<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">normal<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">x<\/span><span style=\"color: #D8DEE9FF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">        <\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">addScaledVector<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">binormal<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">y<\/span><span style=\"color: #D8DEE9FF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    )<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #D8DEE9\">ringPoints<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">push<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">point<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #ECEFF4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringGeometry<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">BufferGeometry<\/span><span style=\"color: #D8DEE9FF\">()<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">setFromPoints<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">ringPoints<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringMesh<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">LineLoop<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">ringGeometry<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">ringMaterial<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">scene<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">add<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">ringMesh<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">light<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">PointLight<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #B48EAD\">0xffffff<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0.1<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">4<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">light<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">castShadow<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">true;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">scene<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">add<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">light<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">renderScene<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">RenderPass<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">scene<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">camera<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">bloomPass<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">UnrealBloomPass<\/span><span style=\"color: #D8DEE9FF\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">Vector2<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">w<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">h<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #B48EAD\">1.5<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #B48EAD\">0.4<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #B48EAD\">0.5<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">bloomPass<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">renderToScreen<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">true;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">composer<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">new<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">THREE<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">EffectComposer<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">renderer<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">composer<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">setSize<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">w<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">h<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">composer<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">addPass<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">renderScene<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">composer<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">addPass<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">bloomPass<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">let<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">cameraTargetPercentage<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">let<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">currentCameraPercentage<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">function<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">updateCameraPercentage<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">percentage<\/span><span style=\"color: #ECEFF4\">)<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">p1<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">path<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">getPointAt<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">percentage<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">%<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">1<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">p2<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">path<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">getPointAt<\/span><span style=\"color: #D8DEE9FF\">((<\/span><span style=\"color: #D8DEE9\">percentage<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">+<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0.01<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #81A1C1\">%<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">1<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">cameraGroup<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">position<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">set<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">p1<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">x<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">p1<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">y<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">p1<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">z<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">cameraGroup<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">lookAt<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">p2<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">light<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">position<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">set<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">p2<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">x<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">p2<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">y<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">p2<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">z<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">const<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">tubePerc<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">{<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">percent<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">}<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">function<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">render<\/span><span style=\"color: #ECEFF4\">()<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">cameraTargetPercentage<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> (<\/span><span style=\"color: #D8DEE9\">cameraTargetPercentage<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">+<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0.001<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #81A1C1\">%<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">1<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">camera<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">rotation<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">y<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">+=<\/span><span style=\"color: #D8DEE9FF\"> (<\/span><span style=\"color: #D8DEE9\">cameraRotationProxyX<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">-<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">camera<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">rotation<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">y<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #81A1C1\">\/<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">15<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">camera<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">rotation<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">x<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">+=<\/span><span style=\"color: #D8DEE9FF\"> (<\/span><span style=\"color: #D8DEE9\">cameraRotationProxyY<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">-<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">camera<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">rotation<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">x<\/span><span style=\"color: #D8DEE9FF\">) <\/span><span style=\"color: #81A1C1\">\/<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">15<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">updateCameraPercentage<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">cameraTargetPercentage<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">composer<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">render<\/span><span style=\"color: #D8DEE9FF\">()<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">requestAnimationFrame<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">render<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">console<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">log<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">cameraTargetPercentage<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #88C0D0\">requestAnimationFrame<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">render<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9\">window<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">addEventListener<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">resize<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">()<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=&gt;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">w<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">window<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">innerWidth<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">h<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">window<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">innerHeight<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">camera<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9\">aspect<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">w<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">\/<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">h<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">camera<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">updateProjectionMatrix<\/span><span style=\"color: #D8DEE9FF\">()<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">renderer<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">setSize<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">w<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">h<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #D8DEE9\">composer<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">setSize<\/span><span style=\"color: #D8DEE9FF\">(<\/span><span style=\"color: #D8DEE9\">w<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">h<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">}<\/span><span style=\"color: #D8DEE9FF\">)<\/span><span style=\"color: #81A1C1\">;<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"<p>I recently built a generative animation using&nbsp;Three.js, and it was picked for CodePen\u2019s trending section! In this post, I\u2019ll break down the techniques behind the animation from procedural geometry to camera movement through a tubular 3D curve. Overview This project explores how to animate a camera moving through a twisting tube generated along a curve [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[40,8,156],"tags":[168,165,167,11,169,166,108,55],"class_list":["post-528","post","type-post","status-publish","format-standard","hentry","category-art","category-code","category-code-snippets","tag-codepen","tag-creativecoding","tag-generativeart","tag-javascript","tag-shaderart","tag-threejs","tag-visualization","tag-webgl"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/kurtgrung.com\/blog\/wp-json\/wp\/v2\/posts\/528","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kurtgrung.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kurtgrung.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kurtgrung.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kurtgrung.com\/blog\/wp-json\/wp\/v2\/comments?post=528"}],"version-history":[{"count":15,"href":"https:\/\/kurtgrung.com\/blog\/wp-json\/wp\/v2\/posts\/528\/revisions"}],"predecessor-version":[{"id":545,"href":"https:\/\/kurtgrung.com\/blog\/wp-json\/wp\/v2\/posts\/528\/revisions\/545"}],"wp:attachment":[{"href":"https:\/\/kurtgrung.com\/blog\/wp-json\/wp\/v2\/media?parent=528"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kurtgrung.com\/blog\/wp-json\/wp\/v2\/categories?post=528"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kurtgrung.com\/blog\/wp-json\/wp\/v2\/tags?post=528"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}