[object Object]

← back to Scarlet Riverboat Masquerade

Add 3D Three.js orb floating over the riverboat — beat-reactive wireframe icosahedron that pulses to the LIVE Dead stream (via the react analyser), warm ember palette; gentle idle when music is off

4adfed7c17dca30deff2e894433d054fe8d60366 · 2026-09-02 06:44:38 -0700 · Steve Abrams

Files touched

Diff

commit 4adfed7c17dca30deff2e894433d054fe8d60366
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Sep 2 06:44:38 2026 -0700

    Add 3D Three.js orb floating over the riverboat — beat-reactive wireframe icosahedron that pulses to the LIVE Dead stream (via the react analyser), warm ember palette; gentle idle when music is off
---
 index.html | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/index.html b/index.html
index 6480a9a..0e96dd4 100644
--- a/index.html
+++ b/index.html
@@ -23,6 +23,7 @@
   html,body{margin:0;height:100%;background:#0a0406;color:var(--ink);font-family:var(--sans);overflow:hidden}
   #stage{position:fixed;inset:0;display:block}
   canvas{position:absolute;inset:0;width:100%;height:100%}
+  #orb{z-index:4;pointer-events:none}
   /* construction-paper grain — the cutout/South-Park texture over the whole scene */
   .grain{position:fixed;inset:0;pointer-events:none;z-index:5;opacity:.10;mix-blend-mode:overlay;
     background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 220 220' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
@@ -224,6 +225,7 @@
 
   <canvas id="sky" aria-hidden="true"></canvas>
   <canvas id="scene" aria-hidden="true"></canvas>
+  <canvas id="orb" aria-hidden="true"></canvas>
   <div class="grain" aria-hidden="true"></div>
 
   <div class="titleplate">
@@ -1672,5 +1674,42 @@ if(_p.endsWith('/room') || /dead\.agentabrams/i.test(location.hostname)){
 }
 })();
 </script>
+
+<!-- 3D orb (Three.js) floating over the boat, pulsing to the LIVE Dead stream. Classic build so it runs from file://; skips if offline. -->
+<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/build/three.min.js"></script>
+<script>
+(function(){
+  if(!window.THREE) return;
+  const canvas=document.getElementById('orb'); if(!canvas) return;
+  let W=innerWidth,H=innerHeight;
+  const renderer=new THREE.WebGLRenderer({canvas,alpha:true,antialias:true});
+  renderer.setPixelRatio(Math.min(2,devicePixelRatio||1)); renderer.setSize(W,H,false);
+  const scene=new THREE.Scene();
+  const camera=new THREE.PerspectiveCamera(50,W/H,0.1,100); camera.position.z=5;
+  const group=new THREE.Group(); group.position.y=1.45; scene.add(group);   // floats up in the sky over the boat
+  const wire=new THREE.Mesh(new THREE.IcosahedronGeometry(0.95,2), new THREE.MeshBasicMaterial({wireframe:true,color:0xf2b64a,transparent:true,opacity:0.8}));
+  const core=new THREE.Mesh(new THREE.IcosahedronGeometry(0.76,3), new THREE.MeshStandardMaterial({color:0x2a0810,emissive:0xc9432b,emissiveIntensity:0.7,roughness:0.35,metalness:0.6,transparent:true,opacity:0.85}));
+  group.add(core,wire);
+  const l1=new THREE.PointLight(0xff8a4a,1.3,60); l1.position.set(4,3,5); scene.add(l1);
+  const l2=new THREE.PointLight(0xf2b64a,1.0,60); l2.position.set(-4,-1,4); scene.add(l2);
+  scene.add(new THREE.AmbientLight(0x402028,0.9));
+  const col=new THREE.Color();
+  addEventListener('resize',()=>{ W=innerWidth;H=innerHeight; camera.aspect=W/H; camera.updateProjectionMatrix(); renderer.setSize(W,H,false); });
+  function loop(){ requestAnimationFrame(loop);
+    const s=window.SRM||{}, t=performance.now()/1000;
+    const pulse=s.pulse||0, level=(s.react?(s.level||0):0);
+    const idle=0.5+0.5*Math.sin(t*1.2);                 // gentle breathing when no music
+    const energy=s.react ? (level*0.6+pulse*0.7) : idle*0.12;
+    group.rotation.y+=0.008+energy*0.02; group.rotation.x=Math.sin(t*0.3)*0.18;
+    group.scale.setScalar(1+energy*0.35);
+    core.material.emissiveIntensity=0.5+energy*1.6;
+    const hue=(28 + Math.sin(t*0.2)*16 + level*40)%360;  // warm ember range, shifts with the music
+    wire.material.color.setHSL(((hue+18)%360)/360,0.85,0.6);
+    col.setHSL(hue/360,0.85,0.5); core.material.emissive.copy(col);
+    renderer.render(scene,camera);
+  }
+  loop();
+})();
+</script>
 </body>
 </html>

← 88dc7e0 Riverboat room: searchable full Grateful Dead archive — type  ·  back to Scarlet Riverboat Masquerade  ·  Back-link: room now links '← The Main Stage' (stage.agentabr ced8032 →