[object Object]

← back to Wallco Ai

fix(api/room): pass full mural width to upstream renderer for kind=mural

8584a8ad2c0601b2bac6117e31c72a69c9e86aa5 · 2026-05-24 01:14:03 -0700 · Steve Abrams

The /api/room handler hard-defaulted patternWidth=27, patternHeight=27 for
EVERY design — meaning when a mural (kind='mural' or 'mural_panel') was
sent to the upstream room renderer at 45.61.58.125:3075, it tile-repeated
the mural as if it were a 27" repeat motif. Result: chopped scenes,
visible seams, half-mural fragments stacked across the wall.

For murals the renderer must treat the pattern as a single image at full
wall-width, not a tileable repeat. Fix: look up the design's actual
width_in / height_in alongside local_path on the PG query, and when
designKind is mural/mural_panel AND the caller did NOT explicitly pass
patternWidth/patternHeight in the request body, override the defaults
with the design's stored dims.

Backward-compat: explicit patternWidth from the client still wins (admin
testing knob preserved). Non-mural designs (seamless_tile, mural_panel-
adjacent-but-categorized-as-tile like designer-scenic) are unchanged —
only kind='mural' and kind='mural_panel' trip the override.

This is the missing piece for "Generate Room with This Mural" to render
correctly — the existing UI button now hits the right scale.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 8584a8ad2c0601b2bac6117e31c72a69c9e86aa5
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun May 24 01:14:03 2026 -0700

    fix(api/room): pass full mural width to upstream renderer for kind=mural
    
    The /api/room handler hard-defaulted patternWidth=27, patternHeight=27 for
    EVERY design — meaning when a mural (kind='mural' or 'mural_panel') was
    sent to the upstream room renderer at 45.61.58.125:3075, it tile-repeated
    the mural as if it were a 27" repeat motif. Result: chopped scenes,
    visible seams, half-mural fragments stacked across the wall.
    
    For murals the renderer must treat the pattern as a single image at full
    wall-width, not a tileable repeat. Fix: look up the design's actual
    width_in / height_in alongside local_path on the PG query, and when
    designKind is mural/mural_panel AND the caller did NOT explicitly pass
    patternWidth/patternHeight in the request body, override the defaults
    with the design's stored dims.
    
    Backward-compat: explicit patternWidth from the client still wins (admin
    testing knob preserved). Non-mural designs (seamless_tile, mural_panel-
    adjacent-but-categorized-as-tile like designer-scenic) are unchanged —
    only kind='mural' and kind='mural_panel' trip the override.
    
    This is the missing piece for "Generate Room with This Mural" to render
    correctly — the existing UI button now hits the right scale.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 server.js | 31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)

diff --git a/server.js b/server.js
index 2f558f6..5f73acf 100644
--- a/server.js
+++ b/server.js
@@ -13571,24 +13571,49 @@ function localPathForDesign(d) {
 // ── POST /api/room — generate room visualization for a design
 app.post('/api/room', async (req, res) => {
   const { design_id, roomType = 'bedroom', angle = 'straight_on',
-          cameraDistance = 5, patternWidth = 27, patternHeight = 27 } = req.body || {};
+          cameraDistance = 5 } = req.body || {};
+  let { patternWidth = 27, patternHeight = 27 } = req.body || {};
   // FRESH-PATH FIX (2026-05-12): the in-memory DESIGNS snapshot can be stale
   // for designs that were composed/baked after server start — leading to the
   // upstream renderer receiving the OLD pattern file. Always read local_path
   // live from spoon_all_designs to guarantee we send the CURRENT pattern.
   let file = null;
+  let designKind = null, designWidthIn = null, designHeightIn = null;
   try {
-    const lp = psqlQuery(`SELECT local_path FROM spoon_all_designs WHERE id=${pgEsc(parseInt(design_id, 10))} LIMIT 1;`);
-    if (lp && lp.trim()) file = lp.trim();
+    const row = psqlQuery(`SELECT row_to_json(t) FROM (SELECT local_path, kind,
+      width_in, height_in FROM spoon_all_designs WHERE id=${pgEsc(parseInt(design_id, 10))} LIMIT 1) t;`);
+    if (row && row.trim()) {
+      const r = JSON.parse(row);
+      if (r.local_path) file = r.local_path;
+      designKind     = r.kind || null;
+      designWidthIn  = Number(r.width_in)  || null;
+      designHeightIn = Number(r.height_in) || null;
+    }
   } catch (e) { /* fall through to in-memory */ }
   if (!file) {
     const d = findDesign(design_id);
     if (!d) return res.status(404).json({ ok: false, error: 'design not found' });
     file = localPathForDesign(d);
+    designKind     = designKind     || d.kind || null;
+    designWidthIn  = designWidthIn  || Number(d.width_in)  || null;
+    designHeightIn = designHeightIn || Number(d.height_in) || null;
   }
   if (!file || !fs.existsSync(file)) {
     return res.status(404).json({ ok: false, error: 'design file missing on disk', file });
   }
+  // Mural-aware pattern scale (2026-05-24): when the design is a mural or
+  // mural_panel, the upstream renderer must use the FULL mural width as the
+  // pattern width — otherwise it tile-repeats the mural as if it were a
+  // small motif, which is structurally wrong and produces visible seams /
+  // chopped scenes across the wall. Override default 27" with the design's
+  // own width_in / height_in if the caller didn't pass explicit dims.
+  const isMural = designKind === 'mural' || designKind === 'mural_panel';
+  if (isMural && designWidthIn && req.body && req.body.patternWidth == null) {
+    patternWidth = designWidthIn;
+  }
+  if (isMural && designHeightIn && req.body && req.body.patternHeight == null) {
+    patternHeight = designHeightIn;
+  }
   try {
     const b64 = fs.readFileSync(file).toString('base64');
     // Upstream renderer (45.61.58.125:3075) drops ~5-15% of requests with

← 153962b fix(make_seamless): hard-cut mask threshold to eliminate gho  ·  back to Wallco Ai  ·  feat(design page): mural pan UI + on-screen arrow controls ea1d852 →