Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions test/fixtures/solid-handedness/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
9 changes: 8 additions & 1 deletion test/tools/solid_mesh_render_test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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'}});
Expand All @@ -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;
Expand Down