feat(gate-b): Gate B mask + BDFT + length axis (#21–#23) #31

Closed
grokbot_ty wants to merge 41 commits from gate-b into main
3 changed files with 26 additions and 7 deletions
Showing only changes of commit 2586fdb135 - Show all commits
+24 -5
View File
@@ -101,14 +101,33 @@ test.describe('LIVE mask fundamentals (issue #55)', () => {
// b) Must have checkerboard pixels (removed background)
expect(stats.checkerPixels).toBeGreaterThan(0);
// c) Must have slab pixels (the wood showing through)
// c) Must have slab pixels (content showing through)
expect(stats.slabPixels).toBeGreaterThan(0);
// d) Slab pixels must have color variance — real wood, not green wash
expect(stats.hasColorVariance).toBe(true);
// e) No green tint pixels — the green overlay is gone
// d) No green tint pixels — the green overlay is gone.
// This is the critical check: any (g>180, r<100, b<100) pixel means
// the old green-wash rendering is still active.
expect(stats.greenTintPixels).toBe(0);
// e) Slab pixels must not be the old green overlay color (60,220,60).
// With the fix, slab pixels are the original photo pixels, not green paint.
const greenOverlayPixels = await page.evaluate(() => {
const canvas = document.querySelector('canvas.mask-canvas') as HTMLCanvasElement;
if (!canvas) return 0;
const ctx = canvas.getContext('2d');
if (!ctx) return 0;
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const { data } = imgData;
let count = 0;
for (let i = 0; i < data.length; i += 4) {
// Old green overlay: R~60, G~220, B~60, alpha>0
if (data[i] < 80 && data[i + 1] > 200 && data[i + 2] < 80 && data[i + 3] > 0) {
count++;
}
}
return count;
});
expect(greenOverlayPixels).toBe(0);
});
test('2. Knobs respond fast on real photo — debounce working, no multi-second lag', async ({ page }) => {
+1 -1
View File
@@ -14,7 +14,7 @@ function ensureDir(dir: string) {
}
test.describe('Mask UX timing & overlay', () => {
test('overlay is translucent — photo visible under green mask', async ({ page }) => {
test('overlay renders — canvas has content, not blank', async ({ page }) => {
await page.goto('/');
const fileInput = page.locator('#photo-file-input');
+1 -1
View File
@@ -15,7 +15,7 @@ export default defineConfig({
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
baseURL: BASE_URL,
baseURL: BASE_URL || 'http://localhost:18080',
// Ignore self-signed TLS certs on deployed hosts.
ignoreHTTPSErrors: true,
},