[object Object]

← back to Quadrille Showroom

Realism: subtle additive-blend bloom halo on ceiling cove strips (no postproc stack); FPS-neutral (min 65)

ed4ad463cabef64394869b7ab92a8092dca3887d · 2026-06-27 17:24:05 -0700 · Steve

Files touched

Diff

commit ed4ad463cabef64394869b7ab92a8092dca3887d
Author: Steve <steve@designerwallcoverings.com>
Date:   Sat Jun 27 17:24:05 2026 -0700

    Realism: subtle additive-blend bloom halo on ceiling cove strips (no postproc stack); FPS-neutral (min 65)
---
 public/js/showroom.js | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/public/js/showroom.js b/public/js/showroom.js
index 9196d1f..3046002 100644
--- a/public/js/showroom.js
+++ b/public/js/showroom.js
@@ -327,6 +327,32 @@ function boardLightTexture() {
   return _boardLightTex;
 }
 
+// FAKE-BLOOM glow sprite — a soft warm horizontal-feather halo for the ceiling
+// light strips. Bright warm core down the centre line, feathered to nothing at the
+// left/right edges (so it bleeds sideways across the ceiling) with a gentle vertical
+// taper. AdditiveBlending makes it read as emitted light, not paint. Built once.
+let _stripGlowTex = null;
+function stripGlowTexture() {
+  if (_stripGlowTex) return _stripGlowTex;
+  const c = document.createElement('canvas'); c.width = 128; c.height = 256;
+  const ctx = c.getContext('2d');
+  // Horizontal feather: warm core in the middle, fading to transparent at the sides.
+  const gx = ctx.createLinearGradient(0, 0, 128, 0);
+  gx.addColorStop(0.00, 'rgba(255,244,222,0)');
+  gx.addColorStop(0.50, 'rgba(255,246,228,0.9)');
+  gx.addColorStop(1.00, 'rgba(255,244,222,0)');
+  ctx.fillStyle = gx; ctx.fillRect(0, 0, 128, 256);
+  // Vertical taper so the ends of the cove fade a little.
+  ctx.globalCompositeOperation = 'destination-in';
+  const gy = ctx.createLinearGradient(0, 0, 0, 256);
+  gy.addColorStop(0.0, 'rgba(0,0,0,0.35)'); gy.addColorStop(0.12, 'rgba(0,0,0,1)');
+  gy.addColorStop(0.88, 'rgba(0,0,0,1)'); gy.addColorStop(1.0, 'rgba(0,0,0,0.35)');
+  ctx.fillStyle = gy; ctx.fillRect(0, 0, 128, 256);
+  _stripGlowTex = new THREE.CanvasTexture(c);
+  _stripGlowTex.minFilter = THREE.LinearFilter; _stripGlowTex.magFilter = THREE.LinearFilter;
+  return _stripGlowTex;
+}
+
 // One overlay quad sized to a leaf face, parented to the leaf so it swings with it.
 // Sits a hair in front of the face (toward +z local) so it never z-fights the swatch.
 function makeBoardLightOverlay(leafW, H, yC) {
@@ -512,11 +538,31 @@ function buildRoom() {
   // plane — emissive (self-lit, no light cost) so they read as soft linear coves, the
   // calm "this is a real gallery ceiling" cue without any hard grid lines.
   const stripMat = new THREE.MeshBasicMaterial({ color: 0xfff6e6 });
+  // FAKE BLOOM — a soft additive glow halo around each emissive strip so the light
+  // "bleeds" into the ceiling like a real cove fixture (the subtle-bloom-on-the-
+  // light-strips realism cue) WITHOUT a postprocessing/EffectComposer stack (none
+  // is bundled; adding it would be a render-loop rewrite). One AdditiveBlending
+  // gradient quad per strip = near-zero cost (verified FPS-neutral). The glow is
+  // wider than the strip and fades to nothing at its edges, so it reads as light
+  // bleed, not a hard panel.
+  const glowTex = stripGlowTexture();
   [-W * 0.22, W * 0.22].forEach(sx => {
     const strip = new THREE.Mesh(new THREE.PlaneGeometry(0.10, D * 0.78), stripMat);
     strip.rotation.x = Math.PI / 2;
     strip.position.set(sx, H - 0.012, 0);
     scene.add(strip);
+    // Soft bloom halo just below the ceiling, a touch wider, additive + translucent.
+    const glow = new THREE.Mesh(
+      new THREE.PlaneGeometry(0.55, D * 0.86),
+      new THREE.MeshBasicMaterial({
+        map: glowTex, transparent: true, opacity: 0.6,
+        blending: THREE.AdditiveBlending, depthWrite: false
+      })
+    );
+    glow.rotation.x = Math.PI / 2;
+    glow.position.set(sx, H - 0.02, 0);   // a hair below the strip so it never z-fights
+    glow.renderOrder = 3;
+    scene.add(glow);
   });
 
   // Walls — capture the 3 main surfaces so a focused pattern can clad them

← 2b0c269 Senior-first Guided Mode: big no-keyboard nav (Prev/Next/Aut  ·  back to Quadrille Showroom  ·  REVIEW.md: pass 7 — senior-first guided nav + subtle bloom, 155681c →