From bf04a0bf63baaeb5dd7e4564926257c1f3bf03d7 Mon Sep 17 00:00:00 2001 From: i2cjak Date: Mon, 2 Nov 2026 13:44:26 -0500 Subject: [PATCH] test: restore mirrored-board render regression --- test/fixtures/solid-handedness/README.md | 14 ++++++++++++++ test/tools/solid_mesh_render_test.mjs | 9 ++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/test/fixtures/solid-handedness/README.md b/test/fixtures/solid-handedness/README.md index 803d719fe3..e9f79d2d4e 100644 --- a/test/fixtures/solid-handedness/README.md +++ b/test/fixtures/solid-handedness/README.md @@ -47,6 +47,20 @@ the reviewed output (IoU >= 0.95), and saves actual PNGs plus source/wire/browse identity to build/solid-handedness. At verification, both scores were 1.0. The unchanged pre-fix source fails this regression (top silk IoU 0). +Issue #45 was rechecked on `origin/main` at `a8339af0f` on 2026-11-02. +The production WebGL renderer still shows readable `TOP F12` and +`BOTTOM R37`, correctly placed asymmetric pads and the chamfer, and the +authored reversed/rotated back text. Both faces match these reviewed silk +masks exactly (IoU 1.0). The test now serves the renderer's mesh-worker +dependency and pins the original reference camera distance: production Fit +has since changed its framing, independently of handedness. + +PR #57's encoder negation was read as a reference and was not applied. +The wire remains in board axes; WebGL's decoders and the phones' MVPs +already negate Y. As a negative control, negating the frozen wire's signed +Y deltas (the encoder change proposed in #57) makes the top render fail +with silk IoU 0. Adding that negation would restore the reflection. + The numerical check covers signed coordinate deltas, correct normal winding, colours, bounds, front/back orientation, and camera panning. The existing orbit test covers drag, zoom and pan behavior. No live UI or device is driven. diff --git a/test/tools/solid_mesh_render_test.mjs b/test/tools/solid_mesh_render_test.mjs index 416ab9b196..f1709e303b 100644 --- a/test/tools/solid_mesh_render_test.mjs +++ b/test/tools/solid_mesh_render_test.mjs @@ -20,6 +20,7 @@ const server=Bun.serve({hostname:'127.0.0.1',port:0,fetch(req){ // production source; App only supplies the localized progress strings. if(p==='/solid.js')return new Response(solid+'\nexport {view as testView};',{headers:{'Content-Type':'application/javascript'}}); if(p==='/solid-assets.js')return new Response(readFileSync('src/web/solid-assets.js','utf8'),{headers:{'Content-Type':'application/javascript'}}); + if(p==='/mesh-worker.js')return new Response(readFileSync('src/web/mesh-worker.js','utf8'),{headers:{'Content-Type':'application/javascript'}}); if(p==='/solid-framing.js')return new Response(readFileSync('src/web/solid-framing.js','utf8'),{headers:{'Content-Type':'application/javascript'}}); if(p==='/solid-dof.js')return new Response(readFileSync('src/web/solid-dof.js','utf8'),{headers:{'Content-Type':'application/javascript'}}); if(p==='/solid-materials.js')return new Response(readFileSync('src/web/solid-materials.js','utf8'),{headers:{'Content-Type':'application/javascript'}}); @@ -46,7 +47,13 @@ try{ const image=await createImageBitmap(await(await fetch(`/${name}.png`)).blob()); const ref=new OffscreenCanvas(1000,700),r=ref.getContext('2d');r.drawImage(image,0,0); const expected=r.getImageData(0,0,1000,700).data; - const v=window.S.testView;v.fit();v.cam.aim(bottom?Math.PI:0,bottom?-Math.PI/2:Math.PI/2);v.draw(); + const v=window.S.testView;v.fit();v.cam.aim(bottom?Math.PI:0,bottom?-Math.PI/2:Math.PI/2); + // Keep the reviewed images' sphere-fit distance. Production Fit now + // preserves the current face and fits its projected corners, so calling + // it in this loop changes the scale between the top and bottom shots. + // Orientation must be compared at the reference pose, independently of Fit. + v.cam.dist=Math.hypot(v.box[3]-v.box[0],v.box[4]-v.box[1],v.box[5]-v.box[2])/2/Math.sin(v.cam.fov/2)*1.05; + v.draw(); const copy=new OffscreenCanvas(1000,700),c=copy.getContext('2d');c.drawImage(v.canvas,0,0); const actual=c.getImageData(0,0,1000,700).data; const white=(a,i)=>a[i]>220&&a[i+1]>220&&a[i+2]>220&&a[i+3]>128;