[object Object]

← back to Dw Photo Capture

TK-12162: capture at high res on all simple-* pages + route minimal/wizard/probooth

14e31944a15ca6cdcb6fc49908d34e4617a2ae48 · 2026-09-24 13:53:39 -0700 · Steve Abrams

Wizard, Instant and Minimal now match Pro Booth: ask the camera for 4096x3072,
keep up to a 2000px long edge, JPEG 0.92 (was 1920x1080/1440, 1600px cap, 0.85).
server.js served only /simple-instant; the other three pages 404'd. One fixed
allow-list regex now serves all four.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014WCvaA6QQCJp2LMdcXyrUD

Files touched

Diff

commit 14e31944a15ca6cdcb6fc49908d34e4617a2ae48
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Sep 24 13:53:39 2026 -0700

    TK-12162: capture at high res on all simple-* pages + route minimal/wizard/probooth
    
    Wizard, Instant and Minimal now match Pro Booth: ask the camera for 4096x3072,
    keep up to a 2000px long edge, JPEG 0.92 (was 1920x1080/1440, 1600px cap, 0.85).
    server.js served only /simple-instant; the other three pages 404'd. One fixed
    allow-list regex now serves all four.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_014WCvaA6QQCJp2LMdcXyrUD
---
 public/simple-instant.html |  6 +++---
 public/simple-minimal.html |  8 +++++---
 public/simple-wizard.html  |  6 +++---
 server.js                  | 10 ++++++----
 4 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/public/simple-instant.html b/public/simple-instant.html
index 8e5b946..c0d1524 100644
--- a/public/simple-instant.html
+++ b/public/simple-instant.html
@@ -273,7 +273,7 @@
     }
     try{
       if (stream) stream.getTracks().forEach(function(t){ t.stop(); });
-      stream = await navigator.mediaDevices.getUserMedia({ video:{ facingMode:{ ideal:f }, width:{ ideal:1920 }, height:{ ideal:1440 } }, audio:false });
+      stream = await navigator.mediaDevices.getUserMedia({ video:{ facingMode:{ ideal:f }, width:{ ideal:4096 }, height:{ ideal:3072 } }, audio:false });
     }catch(e){
       try{ stream = await navigator.mediaDevices.getUserMedia({ video:true, audio:false }); }
       catch(e2){ toast('Camera unavailable — check permissions.'); return; }
@@ -323,10 +323,10 @@
     busy = true; shutterBtn.disabled = true;
 
     var vw = video.videoWidth || 1280, vh = video.videoHeight || 960;
-    var maxDim = 1600, scale = Math.min(1, maxDim / Math.max(vw, vh));
+    var maxDim = 2000, scale = Math.min(1, maxDim / Math.max(vw, vh));
     canvas.width = Math.round(vw * scale); canvas.height = Math.round(vh * scale);
     canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
-    capturedDataUrl = canvas.toDataURL('image/jpeg', 0.86);
+    capturedDataUrl = canvas.toDataURL('image/jpeg', 0.92);
 
     // ── SPEED: fire the REAL network call the instant we have pixels — before any
     // flash/develop UI even starts. The cosmetic animation below runs on its own
diff --git a/public/simple-minimal.html b/public/simple-minimal.html
index dfbe554..060f3c8 100644
--- a/public/simple-minimal.html
+++ b/public/simple-minimal.html
@@ -238,7 +238,7 @@
   function startCamera(){
     permWrap.classList.remove('on');
     if (stream) { stream.getTracks().forEach(function(t){ t.stop(); }); stream = null; }
-    var constraints = { audio:false, video:{ facingMode:{ ideal:facing }, width:{ideal:1920}, height:{ideal:1080} } };
+    var constraints = { audio:false, video:{ facingMode:{ ideal:facing }, width:{ideal:4096}, height:{ideal:3072} } };
     navigator.mediaDevices.getUserMedia(constraints).then(function(s){
       stream = s; camEl.srcObject = s; camEl.classList.toggle('mirror', facing==='user');
     }).catch(function(e){
@@ -293,12 +293,14 @@
   // Another" needs no getUserMedia round trip either — just hide the frozen frame. ────────
   var shotCanvas = document.createElement('canvas');
   function captureFrame(){
-    var w = camEl.videoWidth || 1280, h = camEl.videoHeight || 960;
+    var vw = camEl.videoWidth || 1280, vh = camEl.videoHeight || 960;
+    var k = Math.min(1, 2000 / Math.max(vw, vh));   // same 2000px max edge as Pro Booth
+    var w = Math.round(vw * k), h = Math.round(vh * k);
     shotCanvas.width = w; shotCanvas.height = h;
     var ctx = shotCanvas.getContext('2d');
     if (facing === 'user') { ctx.translate(w,0); ctx.scale(-1,1); }
     ctx.drawImage(camEl, 0, 0, w, h);
-    return shotCanvas.toDataURL('image/jpeg', 0.85);
+    return shotCanvas.toDataURL('image/jpeg', 0.92);
   }
 
   var tStart = 0;
diff --git a/public/simple-wizard.html b/public/simple-wizard.html
index 7d4a91c..01b14ef 100644
--- a/public/simple-wizard.html
+++ b/public/simple-wizard.html
@@ -300,7 +300,7 @@
       throw new Error('This device/browser can\'t access the camera. Try Safari on iPhone/iPad or Chrome on Android.');
     }
     const constraints = [
-      { video:{ facingMode:{ ideal:'environment' }, width:{ ideal:1920 }, height:{ ideal:1440 } }, audio:false },
+      { video:{ facingMode:{ ideal:'environment' }, width:{ ideal:4096 }, height:{ ideal:3072 } }, audio:false },
       { video:{ facingMode:{ ideal:'environment' } }, audio:false },
       { video:true, audio:false }
     ];
@@ -384,12 +384,12 @@
     const canvas = $('snapCanvas');
     // downscale to a sane max edge — keeps the base64 payload small so the (already-fast) round
     // trips to /api/extract and /api/create-item aren't padded by an unnecessarily huge JPEG.
-    const MAXW = 1600;
+    const MAXW = 2000;   // same max edge as Pro Booth
     const vw = v.videoWidth || 1280, vh = v.videoHeight || 960;
     const scale = Math.min(1, MAXW / Math.max(vw, vh));
     canvas.width = Math.round(vw * scale); canvas.height = Math.round(vh * scale);
     canvas.getContext('2d').drawImage(v, 0, 0, canvas.width, canvas.height);
-    capturedDataUrl = canvas.toDataURL('image/jpeg', 0.85);
+    capturedDataUrl = canvas.toDataURL('image/jpeg', 0.92);
     mark('frameGrabbed');
 
     $('reviewImg').src = capturedDataUrl;
diff --git a/server.js b/server.js
index 7491877..1290a93 100644
--- a/server.js
+++ b/server.js
@@ -1337,10 +1337,12 @@ const appHandler = (req, res) => {
 
   // ── TK-12162 "Instant Film" concept — additive, self-contained page, own route (mirrors /batch
   //    below). NOT wired into any nav/menu; reuses the EXISTING /api/extract + /api/create-item
-  //    endpoints as-is. Local exploration only — never linked from index.html, never deployed.
-  if (u.pathname === '/simple-instant' || u.pathname === '/simple-instant.html') {
-    const f = path.join(ROOT, 'public/simple-instant.html');
-    if (!fs.existsSync(f)) return send(res, 404, { err: 'simple-instant.html missing' });
+  //    endpoints as-is. Not linked from index.html. The other three TK-12162 concept pages
+  //    (minimal, wizard, probooth) are served by the same fixed allow-list.
+  const _simple = /^\/(simple-(?:instant|minimal|wizard|probooth))(?:\.html)?$/.exec(u.pathname);
+  if (_simple) {
+    const f = path.join(ROOT, 'public', _simple[1] + '.html');
+    if (!fs.existsSync(f)) return send(res, 404, { err: _simple[1] + '.html missing' });
     return res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store' }), res.end(fs.readFileSync(f, 'utf8'));
   }
 

← 2b1d006 Consolidate SKU field cleanup into shared field-clean.js hel  ·  back to Dw Photo Capture  ·  TK-12162: full-res native-camera capture on all simple-* pag 4d1311b →