← back to Quadrille Showroom
CONTACT GROUNDING: soft radial-gradient contact shadows on the floor under each wingboard + the planter + the console — a shared warm-charcoal alpha sprite (no light/shadow-map cost, depthWrite off, polygonOffset). Boards now sit IN the room instead of floating ON it — the #1 'is it real' tell after the shell. FPS 72, errorCount 0, specs intact (27x27, China Seas)
c49c3dba937f800102042479b37bb1850f637ff4 · 2026-06-27 12:27:51 -0700 · Steve
Files touched
Diff
commit c49c3dba937f800102042479b37bb1850f637ff4
Author: Steve <steve@designerwallcoverings.com>
Date: Sat Jun 27 12:27:51 2026 -0700
CONTACT GROUNDING: soft radial-gradient contact shadows on the floor under each wingboard + the planter + the console — a shared warm-charcoal alpha sprite (no light/shadow-map cost, depthWrite off, polygonOffset). Boards now sit IN the room instead of floating ON it — the #1 'is it real' tell after the shell. FPS 72, errorCount 0, specs intact (27x27, China Seas)
---
public/js/showroom.js | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/public/js/showroom.js b/public/js/showroom.js
index aa6d00e..83a57c8 100644
--- a/public/js/showroom.js
+++ b/public/js/showroom.js
@@ -265,6 +265,42 @@ function initMaterials() {
});
}
+// ============================================================
+// CONTACT GROUNDING — cheap baked-AO contact shadows under objects
+// ============================================================
+// A single soft radial-gradient alpha sprite, shared by every contact shadow, so
+// boards / planter / console sit IN the room instead of floating ON it — the single
+// biggest "is it real" tell after the room shell. No light, no shadow-map cost: each
+// is one transparent dark plane laid flat just above the floor. (REVIEW.md #3.)
+let _contactTex = null;
+function contactShadowTexture() {
+ if (_contactTex) return _contactTex;
+ const c = document.createElement('canvas'); c.width = c.height = 128;
+ const ctx = c.getContext('2d');
+ const g = ctx.createRadialGradient(64, 64, 4, 64, 64, 62);
+ g.addColorStop(0.0, 'rgba(20,18,14,0.55)'); // warm charcoal core (never pure black)
+ g.addColorStop(0.45, 'rgba(20,18,14,0.30)');
+ g.addColorStop(1.0, 'rgba(20,18,14,0.0)'); // fades to nothing at the rim
+ ctx.fillStyle = g; ctx.fillRect(0, 0, 128, 128);
+ _contactTex = new THREE.CanvasTexture(c);
+ return _contactTex;
+}
+
+// Drop a soft contact shadow on the floor. (cx,cz) = world centre; w,d = footprint;
+// opacity scales the darkness. Returns the mesh so callers can group/parent it.
+function addContactShadow(cx, cz, w, d, opacity) {
+ const mat = new THREE.MeshBasicMaterial({
+ map: contactShadowTexture(), transparent: true, opacity: opacity == null ? 1 : opacity,
+ depthWrite: false, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: -1
+ });
+ const m = new THREE.Mesh(new THREE.PlaneGeometry(w, d), mat);
+ m.rotation.x = -Math.PI / 2;
+ m.position.set(cx, 0.006, cz); // 6 mm above the floor → no z-fight, reads as contact
+ m.renderOrder = 1; // draw after the floor
+ scene.add(m);
+ return m;
+}
+
// ============================================================
// TEXTURE POOL — 24 shared patterns (instead of 1 per wing)
// ============================================================
@@ -585,6 +621,11 @@ function buildFurniture() {
// ONE restrained olive in a honed-stone planter — quiet, expensive, off to the side
// by the left wall. Replaces the two sphere "toy" plants.
buildOliveTree(-W/2 + 0.55, 0, D/2 - 0.55);
+ // Contact shadow grounds the planter on the floor.
+ addContactShadow(-W/2 + 0.55, D/2 - 0.55, 0.6, 0.6, 0.85);
+
+ // Contact shadow grounds the console/table.
+ addContactShadow(-1.0, 1.5, 2.0, 1.1, 0.7);
// (Removed: framed abstract "art" on the right wall — the sample boards are the art.)
}
@@ -943,6 +984,21 @@ function buildWingWall() {
};
wallGroup.add(pivot);
wingBoards.push(pivot);
+
+ // CONTACT GROUNDING — a soft radial contact shadow on the floor directly under
+ // this wingboard so it sits IN the room, not floating ON it. Parented to the
+ // wallGroup at local (wingX,0,0) → lands at world (wingX, floor, backZ). The
+ // footprint is a touch wider than the 30" board face and shallow front-to-back
+ // (the board is thin), the strongest "is it real" tell after the room shell.
+ const shadeMat = new THREE.MeshBasicMaterial({
+ map: contactShadowTexture(), transparent: true, opacity: 0.85,
+ depthWrite: false, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: -1
+ });
+ const shade = new THREE.Mesh(new THREE.PlaneGeometry(wingW + 0.12, 0.34), shadeMat);
+ shade.rotation.x = -Math.PI / 2;
+ shade.position.set(wingX, 0.006, 0.02); // 6 mm above floor, nudged just forward of the wall
+ shade.renderOrder = 1;
+ wallGroup.add(shade);
}
// Vendor section labels and dividers — colors from the loaded brand list
← 7dcf846 CEILING: replace crude 64px procedural grid (read as a wiref
·
back to Quadrille Showroom
·
PHOTOGRAPHIC DEPTH: subtle CSS vignette + soft top-down dire d2c6df4 →