Prune repo to spec and stack-folder only.

Remove cards stack, rack, trace, slab, relay, vault, unused preview
PNGs, and stack-only test scripts. Update home page, README, and Vite inputs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-21 21:41:33 -04:00
co-authored by Cursor
parent 21c75cdcba
commit 85229b09c8
26 changed files with 31 additions and 2005 deletions
-1
View File
@@ -13,7 +13,6 @@ mkdirSync(out, { recursive: true });
const shots = [
['spec', `${base}/spec/`],
['stack', `${base}/stack/`],
['auto', 'https://auto.levkin.ca'],
['caseware', 'https://caseware.levkin.ca'],
['iliadobkin', 'https://iliadobkin.com'],
-34
View File
@@ -1,34 +0,0 @@
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
await page.goto('http://localhost:5173/stack-folder/', { waitUntil: 'networkidle' });
for (const y of [0, 400, 800, 1200]) {
await page.evaluate((sy) => window.scrollTo(0, sy), y);
await page.waitForTimeout(150);
const data = await page.evaluate(() => {
return [...document.querySelectorAll('.folder')].map((f, i) => {
const cs = getComputedStyle(f);
const r = f.getBoundingClientRect();
const body = f.querySelector('.body');
const br = body.getBoundingClientRect();
const sec = f.closest('.scroll-section');
const sr = sec.getBoundingClientRect();
return {
i,
folderTop: Math.round(r.top),
bodyTop: Math.round(br.top),
position: cs.position,
top: cs.top,
zIndex: f.style.zIndex || cs.zIndex,
sectionTop: Math.round(sr.top),
sectionBottom: Math.round(sr.bottom),
sectionH: Math.round(sr.height),
};
});
});
console.log('scroll', y, JSON.stringify(data.filter((d) => d.sectionBottom > 0 && d.sectionTop < 800), null, 2));
}
await browser.close();
-50
View File
@@ -1,50 +0,0 @@
import { chromium } from 'playwright';
const BASE = process.env.BASE_URL || 'http://localhost:5173';
const REVEAL = 48 + 44 * 6 + 32; // approx px
async function testCover(page, path, bodySel, getTitle) {
await page.goto(BASE + path, { waitUntil: 'networkidle' });
const results = [];
for (const y of [0, 600, 1200, 1800]) {
await page.evaluate((sy) => window.scrollTo(0, sy), y);
await page.waitForTimeout(250);
const r = await page.evaluate(({ bodySel, reveal }) => {
const bodies = [...document.querySelectorAll(bodySel)];
const stacked = bodies.filter((b) => {
const br = b.getBoundingClientRect();
return Math.abs(br.top - reveal) < 30 && br.height > 100;
});
const top = stacked.sort((a, b) => {
const az = parseInt(getComputedStyle(a.closest('.folder, .layer, .frame, .unit') || a).zIndex) || 0;
const bz = parseInt(getComputedStyle(b.closest('.folder, .layer, .frame, .unit') || b).zIndex) || 0;
return bz - az;
})[0];
const el = document.elementFromPoint(innerWidth / 2, reveal + 120);
const hit = el?.closest('.folder, .layer, .frame, .unit');
const layer = hit?.closest('[data-layer]')?.dataset?.layer ?? hit?.className?.match(/f(\d)|layer-(\d)|u(\d)/)?.[1];
return {
scrollY: scrollY,
stackedCount: stacked.length,
topZ: top ? getComputedStyle(top.closest('.folder, .layer, .frame, .unit')).zIndex : null,
hitLayer: layer,
hitText: hit?.querySelector('h1, h2, strong')?.textContent?.slice(0, 40),
};
}, { bodySel, reveal: REVEAL });
results.push(r);
}
return results;
}
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
const folder = await testCover(page, '/stack-folder/', '.folder .body', (b) => b.querySelector('h1,h2')?.textContent);
console.log('folder', JSON.stringify(folder, null, 2));
await page.screenshot({ path: '/tmp/levkin-cover-folder-1200.png' });
await page.evaluate(() => window.scrollTo(0, 1200));
await page.waitForTimeout(300);
await page.screenshot({ path: '/tmp/levkin-cover-folder-1200b.png' });
await browser.close();
-118
View File
@@ -1,118 +0,0 @@
/**
* Automated scroll/blur tests for stack-folder.
* Run: node scripts/test-stack-scroll.mjs
*/
import { chromium } from 'playwright';
const URL = process.env.STACK_URL || 'http://localhost:5173/stack-folder/';
const VIEWPORT = { width: 1280, height: 800 };
function fail(msg) {
console.error('FAIL:', msg);
process.exitCode = 1;
}
function pass(msg) {
console.log('PASS:', msg);
}
async function readState(page) {
return page.evaluate(() => {
const stick =
parseFloat(getComputedStyle(document.documentElement).fontSize) * 3;
const l7Tab = document.querySelector('.f7 .tab');
const l0 = document.querySelector('.f0');
const l0Body = document.querySelector('.f0 .body');
const folderBlur = l0?.style.getPropertyValue('--stack-blur') || '';
const filter = l0Body ? getComputedStyle(l0Body).filter : '';
const blurMatch = filter.match(/blur\(([\d.]+)px\)/);
const blurPx = blurMatch ? parseFloat(blurMatch[1]) : 0;
return {
scrollY: window.scrollY,
docMax: document.documentElement.scrollHeight - innerHeight,
l7TabTop: l7Tab?.getBoundingClientRect().top ?? null,
stick,
l0Covered: l0?.classList.contains('is-covered'),
l0BlurPx: blurPx,
folderBlur,
l0Filter: filter,
runway: getComputedStyle(document.querySelector('.mount')).getPropertyValue(
'--stack-runway',
),
};
});
}
async function main() {
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: VIEWPORT });
await page.goto(URL, { waitUntil: 'networkidle' });
await page.waitForTimeout(400);
const top = await readState(page);
if (top.l0Covered || top.l0BlurPx > 0.1) {
fail(`L0 blurred at top (covered=${top.l0Covered}, blur=${top.l0BlurPx})`);
} else {
pass('L0 clear at scroll top');
}
await page.evaluate(() => window.scrollTo(0, 999999));
await page.waitForTimeout(350);
const end = await readState(page);
if (end.l7TabTop === null) fail('L7 tab missing');
else if (Math.abs(end.l7TabTop - end.stick) > 8) {
fail(`L7 tab not on stick: top=${end.l7TabTop} stick=${end.stick} scrollY=${end.scrollY}`);
} else {
pass(`L7 on stick at max scroll (y=${end.scrollY}, tabTop=${end.l7TabTop.toFixed(1)})`);
}
if (end.l0BlurPx < 2) {
fail(`L0 not blurred when stacked (blur=${end.l0BlurPx})`);
} else {
pass(`L0 blurred when stacked (blur=${end.l0BlurPx}px)`);
}
const midY = Math.floor(end.scrollY * 0.45);
await page.evaluate((y) => window.scrollTo(0, y), midY);
await page.waitForTimeout(200);
const mid = await readState(page);
if (mid.l0BlurPx > 2) {
fail(`L0 still heavily blurred mid-scroll out (blur=${mid.l0BlurPx} at y=${mid.scrollY})`);
} else {
pass(`L0 unfades when scrolling out (blur=${mid.l0BlurPx}px at y=${mid.scrollY})`);
}
await page.evaluate(() => window.scrollTo(0, 0));
await page.waitForTimeout(350);
const back = await readState(page);
if (back.l0Covered || back.l0BlurPx > 0.1) {
fail(`L0 still blurred after scroll to top (covered=${back.l0Covered}, blur=${back.l0BlurPx})`);
} else {
pass('L0 unfades after scroll back to top');
}
const maxY = end.scrollY;
await page.evaluate((y) => window.scrollTo(0, y), maxY);
await page.waitForTimeout(200);
await page.evaluate(() => window.scrollTo(0, 0));
await page.waitForTimeout(350);
const back2 = await readState(page);
if (back2.l0Covered || back2.l0BlurPx > 0.1) {
fail(`L0 stuck after down-up cycle (blur=${back2.l0BlurPx})`);
} else {
pass('L0 unfades after full down-up cycle');
}
await browser.close();
if (process.exitCode) {
console.log('\nTests failed.');
process.exit(1);
}
console.log('\nAll tests passed.');
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
-76
View File
@@ -1,76 +0,0 @@
import { chromium } from 'playwright';
import { writeFileSync, mkdirSync } from 'fs';
import { join } from 'path';
const BASE = process.env.BASE_URL || 'http://localhost:5173';
const OUT = '/tmp/levkin-stack-test';
mkdirSync(OUT, { recursive: true });
const pages = [
{ name: 'stack', path: '/stack/', bodySel: '.layer-inner' },
{ name: 'stack-folder', path: '/stack-folder/', bodySel: '.folder .body' },
{ name: 'stack-trace', path: '/stack-trace/', bodySel: '.frame-body' },
{ name: 'stack-rack', path: '/stack-rack/', bodySel: '.unit-body' },
];
const scrollY = [0, 400, 800, 1200, 1800, 2400];
async function analyze(page, bodySel) {
const reveal = await page.evaluate(() => {
const s = getComputedStyle(document.documentElement);
return parseFloat(s.getPropertyValue('--stack-reveal')) ||
(48 + 44 * 6 + 32);
});
return page.evaluate(({ bodySel, reveal }) => {
const bodies = [...document.querySelectorAll(bodySel)];
const stacked = bodies.filter((b) => {
const r = b.getBoundingClientRect();
return Math.abs(r.top - reveal) < 35 && r.height > 80;
});
const visible = bodies.filter((b) => {
const r = b.getBoundingClientRect();
return r.height > 80 && r.bottom > 0 && r.top < innerHeight;
});
const el = document.elementFromPoint(innerWidth / 2, reveal + 100);
const panel = el?.closest('.folder, .layer, .frame, .unit');
const layer = panel?.closest('[data-layer]')?.dataset?.layer;
const title = panel?.querySelector('h1, h2, strong')?.textContent?.trim().slice(0, 50);
return {
scrollY: Math.round(window.scrollY),
reveal: Math.round(reveal),
stackedCount: stacked.length,
visibleCount: visible.length,
topLayer: layer,
topTitle: title,
issues: [],
};
}, { bodySel, reveal });
}
const browser = await chromium.launch({ headless: true });
const report = [];
for (const { name, path, bodySel } of pages) {
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
await page.goto(BASE + path, { waitUntil: 'networkidle' });
const shots = [];
for (const y of scrollY) {
await page.evaluate((sy) => window.scrollTo(0, sy), y);
await page.waitForTimeout(250);
const data = await analyze(page, bodySel);
if (data.stackedCount < 2 && y > 200) data.issues.push('not stacking (need 2+ bodies at reveal line)');
if (data.visibleCount > 2 && y > 200) data.issues.push(`${data.visibleCount} bodies spread out, not covering`);
await page.screenshot({ path: join(OUT, `${name}-scroll-${y}.png`) });
shots.push({ y, ...data });
}
report.push({ name, shots });
await page.close();
}
await browser.close();
writeFileSync(join(OUT, 'report.json'), JSON.stringify(report, null, 2));
console.log(JSON.stringify(report.map((r) => ({
variant: r.name,
checks: r.shots.map((s) => ({ y: s.y, stacked: s.stackedCount, top: s.topTitle, issues: s.issues })),
})), null, 2));