← back to Quadrille Showroom
Clean+clear pass: bright even gallery lighting, true-colour crisp swatches (low env wash), hi-res brass CHINA SEAS plaque + hi-res placards
15f8c33c43860f61d99f0a80d887f54fab550dee · 2026-06-27 00:42:38 -0700 · Steve
Files touched
Diff
commit 15f8c33c43860f61d99f0a80d887f54fab550dee
Author: Steve <steve@designerwallcoverings.com>
Date: Sat Jun 27 00:42:38 2026 -0700
Clean+clear pass: bright even gallery lighting, true-colour crisp swatches (low env wash), hi-res brass CHINA SEAS plaque + hi-res placards
---
public/js/showroom.js | 60 ++++++++++++++++++++++++++++-----------------------
1 file changed, 33 insertions(+), 27 deletions(-)
diff --git a/public/js/showroom.js b/public/js/showroom.js
index 6c9b92e..1b0a428 100644
--- a/public/js/showroom.js
+++ b/public/js/showroom.js
@@ -75,7 +75,7 @@ function init() {
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 1.5));
if (THREE.sRGBEncoding) renderer.outputEncoding = THREE.sRGBEncoding; // correct gamma → no washed-out look
renderer.toneMapping = THREE.ACESFilmicToneMapping;
- renderer.toneMappingExposure = 1.06; // slight lift — opens shadows without washing highlights
+ renderer.toneMappingExposure = 1.12; // brighter clean gallery exposure
renderer.shadowMap.enabled = true; // contact shadows = the #1 realism lever
// Soft PCF — penumbra blur on the wing/furniture shadows reads far more believable than
// hard PCF. Cost is modest at one shadow-casting light; the adaptive guard protects FPS.
@@ -450,13 +450,13 @@ function revertWalls() {
// LIGHTING — minimal: ambient + hemi + 4 point
// ============================================================
function buildLighting() {
- // Lower fills — the environment map + key light now carry the scene, so heavy
- // ambient would just wash out the new contrast/shadows.
- scene.add(new THREE.AmbientLight(0xfff5e6, 0.32));
- scene.add(new THREE.HemisphereLight(0xfff8f0, 0x2a2a32, 0.32));
+ // Bright, EVEN gallery light — Phillip-Jeffries white-box: high ambient + hemi so the
+ // wallcovering swatches read crisp and true-colour, not greyed by moody low-key shadow.
+ scene.add(new THREE.AmbientLight(0xffffff, 0.62));
+ scene.add(new THREE.HemisphereLight(0xfffaf2, 0xded6c8, 0.5)); // sky/ground bounce — warm, even
- // KEY light — warm, casts soft shadows (the wings drop real shadows on wall + floor)
- const key = new THREE.DirectionalLight(0xfff3e2, 0.95);
+ // KEY light — soft, gentle shadow (clean contact, not dramatic)
+ const key = new THREE.DirectionalLight(0xfff6ea, 0.7);
key.position.set(2.4, CONFIG.room.height + 1.4, 2.2);
key.target.position.set(0, 1.0, -CONFIG.room.depth / 2);
key.castShadow = true;
@@ -824,18 +824,20 @@ function buildWingWall() {
// Gallery placard — engraved-look brass-on-dark plate under the board.
const pName = (product.pattern_name || product.name || 'Pattern').toString();
const pColor = (product.color_name || product.color || '').toString();
- const plc = document.createElement('canvas'); plc.width = 256; plc.height = 64;
+ const plc = document.createElement('canvas'); plc.width = 1024; plc.height = 256; // 4× — crisp
const pcx = plc.getContext('2d');
- pcx.fillStyle = '#1c1c22'; pcx.fillRect(0, 0, 256, 64);
- pcx.strokeStyle = 'rgba(201,169,110,0.5)'; pcx.lineWidth = 2; pcx.strokeRect(3, 3, 250, 58);
- pcx.fillStyle = '#c9a96e'; pcx.textAlign = 'center';
- pcx.font = '600 22px Georgia, serif';
- pcx.fillText(pName.length > 22 ? pName.slice(0, 21) + '…' : pName, 128, 28);
+ pcx.fillStyle = '#15110a'; pcx.fillRect(0, 0, 1024, 256);
+ pcx.strokeStyle = 'rgba(185,147,63,0.6)'; pcx.lineWidth = 6; pcx.strokeRect(10, 10, 1004, 236);
+ pcx.fillStyle = '#cbb073'; pcx.textAlign = 'center'; pcx.textBaseline = 'middle';
+ pcx.font = '600 76px Georgia, serif';
+ pcx.fillText(pName.length > 26 ? pName.slice(0, 25) + '…' : pName, 512, 100);
if (pColor) {
- pcx.fillStyle = '#9a8c6e'; pcx.font = '12px sans-serif';
- pcx.fillText(pColor.toUpperCase().slice(0, 30), 128, 48);
+ pcx.fillStyle = '#9a8c6e'; pcx.font = '500 44px sans-serif';
+ pcx.fillText(pColor.toUpperCase().slice(0, 34), 512, 172);
}
const plTex = new THREE.CanvasTexture(plc);
+ if (renderer.capabilities) plTex.anisotropy = renderer.capabilities.getMaxAnisotropy();
+ plTex.minFilter = THREE.LinearMipmapLinearFilter; plTex.generateMipmaps = true;
const placard = new THREE.Mesh(
new THREE.PlaneGeometry(Math.min(wingW * 0.9, 0.32), 0.075),
new THREE.MeshBasicMaterial({ map: plTex, transparent: true })
@@ -907,19 +909,22 @@ function buildWingWall() {
const centerX = (startX + endX) / 2;
const sectionW = (section.endIdx - section.startIdx + 1) * slotW;
- // Vendor label canvas
- const lc = document.createElement('canvas'); lc.width = 512; lc.height = 48;
+ // Vendor label — HIGH-RES engraved-brass gallery plaque (crisp, clean, PJ-style).
+ const lc = document.createElement('canvas'); lc.width = 2048; lc.height = 160;
const lx = lc.getContext('2d');
- lx.fillStyle = vColor; lx.fillRect(0, 0, 512, 48);
- const grad = lx.createLinearGradient(0, 0, 0, 48);
- grad.addColorStop(0, 'rgba(255,255,255,0.15)'); grad.addColorStop(1, 'rgba(0,0,0,0.2)');
- lx.fillStyle = grad; lx.fillRect(0, 0, 512, 48);
- lx.fillStyle = '#ffffff'; lx.font = 'bold 26px sans-serif'; lx.textAlign = 'center'; lx.textBaseline = 'middle';
- lx.fillText(section.vendor.toUpperCase(), 256, 26);
+ lx.clearRect(0, 0, 2048, 160); // transparent ground (no cheap colour bar)
+ lx.fillStyle = '#1a1206'; lx.font = '600 84px Georgia, "Times New Roman", serif';
+ lx.textAlign = 'center'; lx.textBaseline = 'middle';
+ // letter-spaced uppercase for an engraved-plaque feel
+ const txt = section.vendor.toUpperCase().split('').join(' ');
+ lx.fillStyle = '#b9933f'; lx.fillText(txt, 1024, 86); // brass
const lt = new THREE.CanvasTexture(lc);
- const labelW = Math.max(sectionW * 0.8, 0.3);
- const label = new THREE.Mesh(new THREE.PlaneGeometry(labelW, 0.07), new THREE.MeshBasicMaterial({ map: lt }));
- label.position.set(centerX, WC.height + 0.15, 0.01);
+ if (renderer.capabilities) lt.anisotropy = renderer.capabilities.getMaxAnisotropy();
+ lt.minFilter = THREE.LinearMipmapLinearFilter; lt.generateMipmaps = true;
+ const labelW = Math.max(sectionW * 0.9, 0.4);
+ const label = new THREE.Mesh(new THREE.PlaneGeometry(labelW, labelW * 160 / 2048),
+ new THREE.MeshBasicMaterial({ map: lt, transparent: true }));
+ label.position.set(centerX, WC.height + 0.18, 0.01);
wallGroup.add(label);
// Thin vertical divider at section start (except first)
@@ -1057,7 +1062,8 @@ function loadWingBook(pivot, onDone) {
const src = imageUrl.charAt(0) === '/' ? imageUrl : ('/api/proxy/image?url=' + encodeURIComponent(imageUrl));
const maxAniso = (renderer.capabilities && renderer.capabilities.getMaxAnisotropy) ? renderer.capabilities.getMaxAnisotropy() : 1;
- const leafMat = (tex) => new THREE.MeshStandardMaterial({ map: tex, roughness: 0.82, metalness: 0.0, envMapIntensity: 0.45 });
+ // Low env wash + matte paper sheen so the pattern reads crisp and true-colour, not greyed.
+ const leafMat = (tex) => new THREE.MeshStandardMaterial({ map: tex, roughness: 0.7, metalness: 0.0, envMapIntensity: 0.12 });
const apply = (cached) => {
ud.faceR.material = leafMat(cached.texture);
ud.faceL.material = leafMat(cached.mirror);
← 575ee37 Scene luxury pass 1: limewash plaster left wall (was brick),
·
back to Quadrille Showroom
·
Add 30s captioned how-to-use demo recorder 80afbd8 →