← back to Wallco Ai
seam-debug: localize ALL joints (4 edge-wrap pairs + 2 internal latent-grid) — orange edge boxes + blue edge-wrap lines + box pairing across the wrap
5a5d6f7ce435d34eda211734e4597c5fad16a666 · 2026-05-28 05:51:46 -0700 · Steve Abrams
Files touched
M data/auto-decide-ledger.jsonlM data/cactus-decisions.jsonlM public/admin/seam-debug.htmlM scripts/seam-defect-boxes.py
Diff
commit 5a5d6f7ce435d34eda211734e4597c5fad16a666
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu May 28 05:51:46 2026 -0700
seam-debug: localize ALL joints (4 edge-wrap pairs + 2 internal latent-grid) — orange edge boxes + blue edge-wrap lines + box pairing across the wrap
---
data/auto-decide-ledger.jsonl | 91 +++++++++++++++++++++++++++++++++++++++++++
data/cactus-decisions.jsonl | 12 ++++++
public/admin/seam-debug.html | 32 ++++++++++-----
scripts/seam-defect-boxes.py | 71 +++++++++++++++++++--------------
4 files changed, 167 insertions(+), 39 deletions(-)
diff --git a/data/auto-decide-ledger.jsonl b/data/auto-decide-ledger.jsonl
index 2d5eadb..1c3aaaa 100644
--- a/data/auto-decide-ledger.jsonl
+++ b/data/auto-decide-ledger.jsonl
@@ -4152,3 +4152,94 @@
{"t":"2026-05-28T12:38:38.223Z","id":53947,"verdict":"not","reason":"centered-hero (n=5)","see":"A centered vase with flowers and birds."}
{"t":"2026-05-28T12:38:40.752Z","id":53948,"verdict":"hot_candidate","n":6,"see":"A wallpaper tile with a repeating pattern of stylized glasses and flowers."}
{"t":"2026-05-28T12:38:43.792Z","id":53949,"verdict":"hot_candidate","n":12,"see":"A wallpaper tile featuring a repeating pattern of vases and bottles on a shelf."}
+{"t":"2026-05-28T12:38:46.187Z","id":53950,"verdict":"not","reason":"centered-hero (n=2)","see":"A large martini glass is centered with other partial glasses around it."}
+{"t":"2026-05-28T12:38:48.619Z","id":53951,"verdict":"not","reason":"large-empty-void","see":"I see a tile with a few instances of a still life motif and a large empty area."}
+{"t":"2026-05-28T12:38:50.777Z","id":53952,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"There are two partial motifs with a large empty area."}
+{"t":"2026-05-28T12:38:53.093Z","id":53953,"verdict":"not","reason":"centered-hero (n=1)","see":"I see a single large cat motif in a pot."}
+{"t":"2026-05-28T12:38:55.505Z","id":53954,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"I see a tile with a large empty area and two instances of the motif."}
+{"t":"2026-05-28T12:38:57.733Z","id":53955,"verdict":"not","reason":"centered-hero (n=1)","see":"A large tree motif is centered with a large empty area."}
+{"t":"2026-05-28T12:39:00.405Z","id":53956,"verdict":"hot_candidate","n":7,"see":"A repeating pattern of bottles and skulls."}
+{"t":"2026-05-28T12:39:02.852Z","id":53957,"verdict":"hot_candidate","n":5,"see":"A repeating pattern of frogs and leaves."}
+{"t":"2026-05-28T12:39:05.474Z","id":53958,"verdict":"not","reason":"large-empty-void","see":"I see a pattern of glasses and a bird with a large empty area."}
+{"t":"2026-05-28T12:39:07.966Z","id":53959,"verdict":"hot_candidate","n":7,"see":"A wallpaper tile with a repeating pattern of vases and other objects."}
+{"t":"2026-05-28T12:39:10.488Z","id":53960,"verdict":"hot_candidate","n":5,"see":"This is a wallpaper tile with a repeating pattern of bottles and cherries."}
+{"t":"2026-05-28T12:39:13.389Z","id":53961,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of various objects in green and purple."}
+{"t":"2026-05-28T12:39:16.151Z","id":53962,"verdict":"hot_candidate","n":10,"see":"This is a wallpaper tile with a repeating pattern of various objects."}
+{"t":"2026-05-28T12:39:20.477Z","id":53963,"verdict":"hot_candidate","n":6,"see":"This is a wallpaper repeat with bottles, beavers, and other objects."}
+{"t":"2026-05-28T12:39:22.955Z","id":53964,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"I see two bird motifs with a large empty area."}
+{"t":"2026-05-28T12:39:25.060Z","id":53965,"verdict":"hot_candidate","n":3,"see":"I see a repeating pattern of a face in a bowl."}
+{"t":"2026-05-28T12:39:27.430Z","id":53966,"verdict":"hot_candidate","n":4,"see":"A repeating pattern of frogs and leaves."}
+{"t":"2026-05-28T12:39:30.062Z","id":53967,"verdict":"hot_candidate","n":5,"see":"A wallpaper tile with a repeating still life motif."}
+{"t":"2026-05-28T12:39:32.227Z","id":53968,"verdict":"hot_candidate","n":4,"see":"A repeating pattern of abstract shapes."}
+{"t":"2026-05-28T12:39:34.692Z","id":53969,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"I see two instances of a motif with a large empty area."}
+{"t":"2026-05-28T12:39:36.921Z","id":53970,"verdict":"hot_candidate","n":6,"see":"A wallpaper tile with a repeating pattern of bottles and birds."}
+{"t":"2026-05-28T12:39:39.240Z","id":53971,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"I see a tile with two partial motifs and a large empty area."}
+{"t":"2026-05-28T12:39:41.979Z","id":53972,"verdict":"not","reason":"large-empty-void","see":"I see three instances of a face-like motif with a large empty area."}
+{"t":"2026-05-28T12:39:44.421Z","id":53973,"verdict":"hot_candidate","n":4,"see":"The image shows a repeating pattern of monkey-like figures holding objects."}
+{"t":"2026-05-28T12:39:46.869Z","id":53974,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of cocktail glasses and other objects."}
+{"t":"2026-05-28T12:39:49.121Z","id":53975,"verdict":"hot_candidate","n":4,"see":"A wallpaper tile with a repeating pattern of floral cocktail glasses."}
+{"t":"2026-05-28T12:39:51.539Z","id":53976,"verdict":"hot_candidate","n":4,"see":"This is a wallpaper tile with a repeating pattern of bottles and plants."}
+{"t":"2026-05-28T12:39:54.025Z","id":53977,"verdict":"hot_candidate","n":12,"see":"A wallpaper tile with a repeating pattern of stylized giraffe-like figures."}
+{"t":"2026-05-28T12:39:56.400Z","id":53978,"verdict":"hot_candidate","n":4,"see":"A wallpaper tile with a repeating lemur motif."}
+{"t":"2026-05-28T12:39:58.686Z","id":53979,"verdict":"hot_candidate","n":5,"see":"A repeating pattern of elephants and other objects."}
+{"t":"2026-05-28T12:40:00.954Z","id":53980,"verdict":"hot_candidate","n":6,"see":"This is a wallpaper tile with a repeating pattern of leaves and branches."}
+{"t":"2026-05-28T12:40:03.268Z","id":53981,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of animals in martini glasses."}
+{"t":"2026-05-28T12:40:05.621Z","id":53982,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of urns and birds among foliage."}
+{"t":"2026-05-28T12:40:07.965Z","id":53983,"verdict":"hot_candidate","n":3,"see":"A wallpaper tile with a repeating motif of a vase and a cup."}
+{"t":"2026-05-28T12:40:10.117Z","id":53984,"verdict":"hot_candidate","n":4,"see":"A repeating pattern of green floral motifs."}
+{"t":"2026-05-28T12:40:12.478Z","id":53985,"verdict":"not","reason":"centered-hero (n=2)","see":"Two raccoons are balancing a bowl."}
+{"t":"2026-05-28T12:40:14.919Z","id":53986,"verdict":"hot_candidate","n":4,"see":"A wallpaper tile with a repeating leaf and fruit motif."}
+{"t":"2026-05-28T12:40:17.412Z","id":53987,"verdict":"hot_candidate","n":6,"see":"A wallpaper tile with a repeating motif of plants and animals on platforms."}
+{"t":"2026-05-28T12:40:19.794Z","id":53988,"verdict":"hot_candidate","n":7,"see":"A wallpaper tile with a repeating pattern of bottles and glasses."}
+{"t":"2026-05-28T12:40:22.023Z","id":53989,"verdict":"not","reason":"centered-hero (n=1)","see":"A single hourglass is centered."}
+{"t":"2026-05-28T12:40:24.479Z","id":53990,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of various green monster-like figures."}
+{"t":"2026-05-28T12:40:26.752Z","id":53991,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"There are two snake heads on a plain background."}
+{"t":"2026-05-28T12:40:29.165Z","id":53992,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of stylized plant motifs."}
+{"t":"2026-05-28T12:40:38.006Z","id":53993,"verdict":"hot_candidate","n":4,"see":"A wallpaper tile with a repeating elephant motif."}
+{"t":"2026-05-28T12:40:40.589Z","id":53994,"verdict":"not","reason":"large-empty-void","see":"I see a wallpaper tile with a repeating pattern of wine bottles, but with a large empty area."}
+{"t":"2026-05-28T12:40:42.771Z","id":53995,"verdict":"not","reason":"large-empty-void","see":"There are three instances of the cocktail motif with a large empty area."}
+{"t":"2026-05-28T12:40:44.983Z","id":53996,"verdict":"not","reason":"centered-hero (n=1)","see":"A single frog motif is centered with a large empty area."}
+{"t":"2026-05-28T12:40:47.353Z","id":53997,"verdict":"not","reason":"large-empty-void","see":"I see a wallpaper tile with a repeating motif of leaves and a can."}
+{"t":"2026-05-28T12:40:49.414Z","id":53998,"verdict":"hot_candidate","n":4,"see":"A repeating pattern of cocktail glasses."}
+{"t":"2026-05-28T12:40:51.832Z","id":53999,"verdict":"hot_candidate","n":6,"see":"This is a wallpaper tile with a repeating pattern of stylized fish and other objects."}
+{"t":"2026-05-28T12:40:54.468Z","id":54000,"verdict":"hot_candidate","n":5,"see":"Repeating pattern of wine glasses."}
+{"t":"2026-05-28T12:40:57.080Z","id":54001,"verdict":"not","reason":"centered-hero (n=1)","see":"A centered bottle with large empty area."}
+{"t":"2026-05-28T12:40:59.437Z","id":54002,"verdict":"hot_candidate","n":4,"see":"A wallpaper tile with a repeating elephant motif."}
+{"t":"2026-05-28T12:41:01.845Z","id":54003,"verdict":"hot_candidate","n":10,"see":"A repeating pattern of stylized cocktail glasses."}
+{"t":"2026-05-28T12:41:04.295Z","id":54004,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of cocktail glasses with skulls and other objects."}
+{"t":"2026-05-28T12:41:06.814Z","id":54005,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"I see two instances of a bird motif with a large empty area."}
+{"t":"2026-05-28T12:41:09.436Z","id":54006,"verdict":"hot_candidate","n":4,"see":"A repeating pattern of abstract shapes."}
+{"t":"2026-05-28T12:41:11.740Z","id":54007,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"Two instances of a potted plant motif with a large empty area in the middle."}
+{"t":"2026-05-28T12:41:14.295Z","id":54008,"verdict":"hot_candidate","n":5,"see":"A repeating pattern of potted plants."}
+{"t":"2026-05-28T12:41:16.756Z","id":54009,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"I see two partial skull motifs with a large empty area."}
+{"t":"2026-05-28T12:41:19.536Z","id":54010,"verdict":"hot_candidate","n":4,"see":"I see a wallpaper repeat of various containers."}
+{"t":"2026-05-28T12:41:21.992Z","id":54011,"verdict":"hot_candidate","n":10,"see":"A repeating pattern of stylized fruit and glassware."}
+{"t":"2026-05-28T12:41:24.405Z","id":54012,"verdict":"not","reason":"large-empty-void","see":"I see three instances of the motif with a large empty area."}
+{"t":"2026-05-28T12:41:26.995Z","id":54013,"verdict":"hot_candidate","n":3,"see":"I see a wallpaper tile with a repeating pattern of a bow and arrow with other motifs."}
+{"t":"2026-05-28T12:41:29.277Z","id":54014,"verdict":"not","reason":"centered-hero (n=2)","see":"A centered motif with a large empty area."}
+{"t":"2026-05-28T12:41:31.730Z","id":54015,"verdict":"not","reason":"centered-hero (n=3)","see":"A large glass and banana motif is centered."}
+{"t":"2026-05-28T12:41:34.308Z","id":54016,"verdict":"hot_candidate","n":7,"see":"A wallpaper tile with a repeating motif of vases and birds."}
+{"t":"2026-05-28T12:41:36.591Z","id":54017,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"Two martini glasses with a monster in the middle."}
+{"t":"2026-05-28T12:41:39.472Z","id":54018,"verdict":"hot_candidate","n":3,"see":"There are multiple instances of a bird-like motif."}
+{"t":"2026-05-28T12:41:42.121Z","id":54019,"verdict":"hot_candidate","n":4,"see":"I see a repeating pattern of cats, birds, and flowers."}
+{"t":"2026-05-28T12:41:47.166Z","id":54020,"verdict":"hot_candidate","n":5,"see":"A repeating floral and leaf pattern."}
+{"t":"2026-05-28T12:41:49.136Z","id":54021,"verdict":"not","reason":"centered-hero (n=2)","see":"A centered hero motif with a large empty area."}
+{"t":"2026-05-28T12:41:51.384Z","id":54022,"verdict":"not","reason":"large-empty-void","see":"I see a bird, a hanging figure, and a large empty area."}
+{"t":"2026-05-28T12:41:53.763Z","id":54023,"verdict":"hot_candidate","n":5,"see":"A wallpaper tile with a repeating elephant motif."}
+{"t":"2026-05-28T12:41:56.139Z","id":54024,"verdict":"hot_candidate","n":10,"see":"A wallpaper tile with a repeating pattern of abstract cocktail glasses."}
+{"t":"2026-05-28T12:41:58.296Z","id":54025,"verdict":"hot_candidate","n":4,"see":"I see a repeating pattern of monstera leaves and a cocktail."}
+{"t":"2026-05-28T12:42:01.525Z","id":54026,"verdict":"hot_candidate","n":5,"see":"A repeating pattern of stylized frogs and insects."}
+{"t":"2026-05-28T12:42:04.005Z","id":54027,"verdict":"not","reason":"centered-hero (n=1)","see":"A single wine glass with capybaras inside."}
+{"t":"2026-05-28T12:42:06.859Z","id":54028,"verdict":"not","reason":"centered-hero (n=3)","see":"A centered peacock motif with vases on shelves."}
+{"t":"2026-05-28T12:42:09.339Z","id":54029,"verdict":"hot_candidate","n":7,"see":"There are multiple instances of the bottle motif with leaves."}
+{"t":"2026-05-28T12:42:12.076Z","id":54030,"verdict":"not","reason":"centered-hero (n=1)","see":"A centered giraffe motif with a large empty area."}
+{"t":"2026-05-28T12:42:14.333Z","id":54031,"verdict":"hot_candidate","n":4,"see":"A wallpaper tile with a repeating skull motif."}
+{"t":"2026-05-28T12:42:16.990Z","id":54032,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of various cocktail glasses and vases."}
+{"t":"2026-05-28T12:42:19.604Z","id":54033,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"I see two motifs with a large empty area."}
+{"t":"2026-05-28T12:42:21.936Z","id":54034,"verdict":"hot_candidate","n":6,"see":"A wallpaper tile with a repeating pattern of vases and plants."}
+{"t":"2026-05-28T12:42:24.525Z","id":54035,"verdict":"hot_candidate","n":4,"see":"A repeating pattern of bottles and leaves."}
+{"t":"2026-05-28T12:42:26.871Z","id":54036,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"There are two partial motifs on the sides with a large empty area in the middle."}
+{"t":"2026-05-28T12:42:29.221Z","id":54037,"verdict":"not","reason":"large-empty-void","see":"A vertical band of floral motifs with a large empty area to the left."}
+{"t":"2026-05-28T12:42:31.738Z","id":54038,"verdict":"hot_candidate","n":5,"see":"A repeating pattern of stylized green fruits with frogs."}
+{"t":"2026-05-28T12:42:34.001Z","id":54039,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"I see a wallpaper tile with a large empty area and two instances of the main motif."}
+{"t":"2026-05-28T12:42:36.142Z","id":54040,"verdict":"hot_candidate","n":7,"see":"A repeating pattern of floral and abstract motifs."}
diff --git a/data/cactus-decisions.jsonl b/data/cactus-decisions.jsonl
index 2c83f10..347b207 100644
--- a/data/cactus-decisions.jsonl
+++ b/data/cactus-decisions.jsonl
@@ -3044,3 +3044,15 @@
{"ts":"2026-05-28T12:24:15.105Z","id":29629,"action":"bad"}
{"ts":"2026-05-28T12:24:18.623Z","id":29556,"action":"bad"}
{"ts":"2026-05-28T12:24:21.753Z","id":35419,"action":"bad"}
+{"ts":"2026-05-28T12:51:18.336Z","id":53769,"action":"live"}
+{"ts":"2026-05-28T12:51:20.632Z","id":53784,"action":"live"}
+{"ts":"2026-05-28T12:51:23.174Z","id":53774,"action":"live"}
+{"ts":"2026-05-28T12:51:25.512Z","id":53787,"action":"live"}
+{"ts":"2026-05-28T12:51:28.046Z","id":53788,"action":"live"}
+{"ts":"2026-05-28T12:51:30.310Z","id":53776,"action":"live"}
+{"ts":"2026-05-28T12:51:32.571Z","id":53794,"action":"live"}
+{"ts":"2026-05-28T12:51:34.869Z","id":53799,"action":"live"}
+{"ts":"2026-05-28T12:51:35.635Z","id":53799,"action":"live"}
+{"ts":"2026-05-28T12:51:37.869Z","id":53777,"action":"live"}
+{"ts":"2026-05-28T12:51:40.311Z","id":53778,"action":"live"}
+{"ts":"2026-05-28T12:51:42.654Z","id":53783,"action":"live"}
diff --git a/public/admin/seam-debug.html b/public/admin/seam-debug.html
index f0b188c..357491f 100644
--- a/public/admin/seam-debug.html
+++ b/public/admin/seam-debug.html
@@ -22,11 +22,15 @@
.stage{background:#000;border:1px solid var(--line);border-radius:10px;position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;min-height:520px;}
.stage img{display:block;max-width:100%;max-height:80vh;height:auto;}
.overlay{position:absolute;pointer-events:none;}
- .seam-line{position:absolute;background:rgba(123,201,111,.35);}
- .seam-line.v{width:1px;top:0;bottom:0;}
- .seam-line.h{height:1px;left:0;right:0;}
+ .seam-line{position:absolute;}
+ .seam-line.mid{background:rgba(123,201,111,.55);}
+ .seam-line.edge{background:rgba(74,163,255,.55);}
+ .seam-line.v{width:2px;top:0;bottom:0;}
+ .seam-line.h{height:2px;left:0;right:0;}
.box{position:absolute;border:2px solid var(--bad);background:rgba(255,77,77,.18);box-shadow:0 0 0 1px rgba(0,0,0,.65) inset, 0 0 14px rgba(255,77,77,.45);}
+ .box.edge{border-color:#ff9a3c;background:rgba(255,154,60,.18);box-shadow:0 0 0 1px rgba(0,0,0,.65) inset, 0 0 14px rgba(255,154,60,.45);}
.box .lbl{position:absolute;top:-18px;left:0;background:var(--bad);color:#fff;font:11px/1 ui-monospace,monospace;padding:2px 5px;border-radius:3px;white-space:nowrap;}
+ .box.edge .lbl{background:#ff9a3c;color:#1a1a1a;}
aside{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:14px;font-size:13px;align-self:start;}
aside h2{font-size:13px;margin:0 0 8px;letter-spacing:.05em;text-transform:uppercase;color:var(--mut);font-weight:600;}
aside .row{display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px dashed var(--line);}
@@ -64,8 +68,9 @@
<h2 style="margin-top:14px">Defect boxes</h2>
<div id="boxlist" style="font-size:12px;font-family:ui-monospace,monospace;max-height:38vh;overflow:auto"></div>
<div class="legend">
- <div><span class="sw" style="background:rgba(255,77,77,.6);border:1px solid var(--bad)"></span>localized mid-line defect (peak ΔE shown)</div>
- <div><span class="sw" style="background:rgba(123,201,111,.5)"></span>theoretical mid-line (W/2, H/2)</div>
+ <div><span class="sw" style="background:rgba(255,77,77,.6);border:1px solid var(--bad)"></span>internal joint (h_mid / v_mid — latent-grid)</div>
+ <div><span class="sw" style="background:rgba(255,154,60,.6);border:1px solid #ff9a3c"></span>edge joint (top↔bottom · left↔right wrap)</div>
+ <div><span class="sw" style="background:rgba(123,201,111,.5)"></span>internal mid-line · <span class="sw" style="background:rgba(74,163,255,.5)"></span>edge-wrap line</div>
<div style="margin-top:6px;color:var(--mut)">PASS ≤ 5 · WARN ≤ 12 · FAIL > 12. Per-row trigger 8, min run 24 px.</div>
</div>
</aside>
@@ -96,16 +101,23 @@ function redraw(){
ovl.style.left=img.offsetLeft+'px'; ovl.style.top=img.offsetTop+'px';
ovl.style.width=iw+'px'; ovl.style.height=ih+'px';
if($('t_seam').checked){
- const vline=document.createElement('div'); vline.className='seam-line v'; vline.style.left=(CUR.width/2*sx)+'px'; ovl.appendChild(vline);
- const hline=document.createElement('div'); hline.className='seam-line h'; hline.style.top=(CUR.height/2*sy)+'px'; ovl.appendChild(hline);
+ // green crosshair = internal latent-grid joints; blue lines = edge-wrap joints
+ const mk=(cls,style)=>{ const e=document.createElement('div'); e.className='seam-line '+cls; Object.assign(e.style,style); ovl.appendChild(e); };
+ mk('mid v',{left:(CUR.width/2*sx)+'px'});
+ mk('mid h',{top:(CUR.height/2*sy)+'px'});
+ mk('edge v',{left:'0px'});
+ mk('edge v',{left:(iw-2)+'px'});
+ mk('edge h',{top:'0px'});
+ mk('edge h',{top:(ih-2)+'px'});
}
if($('t_box').checked){
(CUR.boxes||[]).forEach((b,i)=>{
- const d=document.createElement('div'); d.className='box';
+ const isEdge=/_edge$/.test(b.kind);
+ const d=document.createElement('div'); d.className='box'+(isEdge?' edge':'');
d.style.left=(b.x*sx)+'px'; d.style.top=(b.y*sy)+'px';
- d.style.width=(b.w*sx)+'px'; d.style.height=(b.h*sy)+'px';
+ d.style.width=Math.max(2,b.w*sx)+'px'; d.style.height=Math.max(2,b.h*sy)+'px';
d.innerHTML=`<span class="lbl">${b.kind} · ΔE ${b.peak_de}</span>`;
- d.title=`${b.kind} · x=${b.x} y=${b.y} w=${b.w} h=${b.h} · peak ΔE ${b.peak_de} (mean ${b.mean_de})`;
+ d.title=`${b.kind}${b.edge_pair?' ['+b.edge_pair+']':''} · x=${b.x} y=${b.y} w=${b.w} h=${b.h} · peak ΔE ${b.peak_de} (mean ${b.mean_de})`;
ovl.appendChild(d);
});
}
diff --git a/scripts/seam-defect-boxes.py b/scripts/seam-defect-boxes.py
index e648206..ffe5515 100644
--- a/scripts/seam-defect-boxes.py
+++ b/scripts/seam-defect-boxes.py
@@ -127,38 +127,51 @@ def scan(arr):
de = (((lab_a - lab_b) ** 2).sum(axis=-1)) ** 0.5 # (rows, cols) ΔE map
scores[lens] = round(float(de.mean()), 2)
- # Localize ONLY for the midlines (the "fatal" defect Steve flagged).
- if lens not in ('h_mid', 'v_mid'):
- continue
-
+ # Localize every joint where the tile meets itself — the 2 internal
+ # latent-grid joints (h_mid, v_mid) AND the 4 edge-wrap joints
+ # (top↔bottom, left↔right). For edges, we surface boxes on BOTH
+ # sides of the seam — when the tile repeats, those segments touch.
if lens == 'v_mid':
- # de shape (H, STRIP_PX) — collapse cols → per-row vector along the seam
- per_row = de.mean(axis=1)
+ per_row = de.mean(axis=1) # (H,) along x=W/2
for s, e, peak, mean in find_runs(per_row):
- m = W // 2
- boxes.append({
- 'kind': 'v_mid',
- 'x': max(0, m - BAND_PX // 2),
- 'y': s,
- 'w': BAND_PX,
- 'h': e - s,
- 'peak_de': round(peak, 2),
- 'mean_de': round(mean, 2),
- })
- else:
- # h_mid: de shape (STRIP_PX, W) — collapse rows → per-col vector
- per_col = de.mean(axis=0)
+ boxes.append({'kind': 'v_mid',
+ 'x': max(0, W // 2 - BAND_PX // 2), 'y': s,
+ 'w': BAND_PX, 'h': e - s,
+ 'peak_de': round(peak, 2), 'mean_de': round(mean, 2)})
+ elif lens == 'h_mid':
+ per_col = de.mean(axis=0) # (W,) along y=H/2
for s, e, peak, mean in find_runs(per_col):
- m = H // 2
- boxes.append({
- 'kind': 'h_mid',
- 'x': s,
- 'y': max(0, m - BAND_PX // 2),
- 'w': e - s,
- 'h': BAND_PX,
- 'peak_de': round(peak, 2),
- 'mean_de': round(mean, 2),
- })
+ boxes.append({'kind': 'h_mid',
+ 'x': s, 'y': max(0, H // 2 - BAND_PX // 2),
+ 'w': e - s, 'h': BAND_PX,
+ 'peak_de': round(peak, 2), 'mean_de': round(mean, 2)})
+ elif lens in ('top', 'bottom'):
+ # de shape (STRIP_PX, W) — collapse rows → per-col vector along edge
+ per_col = de.mean(axis=0)
+ # de-dup: top and bottom produce mirror-identical scans (same
+ # strips, reversed). Only emit from 'top'.
+ if lens == 'top':
+ for s, e, peak, mean in find_runs(per_col):
+ # Box on top edge…
+ boxes.append({'kind': 'top_edge', 'edge_pair': 'top↔bottom',
+ 'x': s, 'y': 0, 'w': e - s, 'h': STRIP_PX,
+ 'peak_de': round(peak, 2), 'mean_de': round(mean, 2)})
+ # …and the corresponding box on bottom edge (same x-range)
+ boxes.append({'kind': 'bottom_edge', 'edge_pair': 'top↔bottom',
+ 'x': s, 'y': max(0, H - STRIP_PX),
+ 'w': e - s, 'h': STRIP_PX,
+ 'peak_de': round(peak, 2), 'mean_de': round(mean, 2)})
+ elif lens in ('left', 'right'):
+ per_row = de.mean(axis=1)
+ if lens == 'left':
+ for s, e, peak, mean in find_runs(per_row):
+ boxes.append({'kind': 'left_edge', 'edge_pair': 'left↔right',
+ 'x': 0, 'y': s, 'w': STRIP_PX, 'h': e - s,
+ 'peak_de': round(peak, 2), 'mean_de': round(mean, 2)})
+ boxes.append({'kind': 'right_edge', 'edge_pair': 'left↔right',
+ 'x': max(0, W - STRIP_PX), 'y': s,
+ 'w': STRIP_PX, 'h': e - s,
+ 'peak_de': round(peak, 2), 'mean_de': round(mean, 2)})
edges_max = max(scores[k] for k in ('top', 'bottom', 'left', 'right'))
mids_max = max(scores['h_mid'], scores['v_mid'])
← a55e2ac seam-defect localizer + /admin/seam-debug viewer (per-row/pe
·
back to Wallco Ai
·
drunk-curator: richer ID cues — density tier, subject+emoji, 041d703 →