feat: Stage 2C CAD assembly cleanup, full-height canvas, physics parity

Remove default Measurement overlay and procedural motor duplicate; force
opaque CAD materials; modular extension pitch from CAD; shared runtime/
headless physics config hash; layout e2e and Stage 2C artifacts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Даня Архипов
2026-07-30 12:35:50 +00:00
parent 0a1be376eb
commit 68327635ce
50 changed files with 3051 additions and 100 deletions

View File

@@ -0,0 +1,49 @@
import { test, expect } from '@playwright/test';
test.setTimeout(90_000);
test.describe('Stage 2C layout + measurement panel', () => {
test('default / has no Measurement panel and canvas fills viewport height', async ({ page }) => {
await page.goto('/?playback=paused');
await expect(page.locator('canvas')).toBeVisible({ timeout: 60_000 });
await page.waitForFunction(() => !document.body.innerText.includes('Loading 3D'), {
timeout: 60_000,
});
await page.waitForTimeout(500);
await expect(page.locator('.cv-overlay')).toHaveCount(0);
await expect(page.getByTestId('measurement-compact')).toHaveCount(0);
const metrics = await page.evaluate(() => {
const vh = window.innerHeight;
const canvas = document.querySelector('canvas');
const svg = document.querySelector('[data-testid="main-svg-fallback"]');
const scene = canvas ?? svg;
if (!scene) return { ok: false as const, reason: 'no scene' };
const r = scene.getBoundingClientRect();
const heightRatio = r.height / vh;
const emptyBelow = Math.max(0, vh - (r.top + r.height));
const emptyRatio = emptyBelow / vh;
return {
ok: true as const,
heightRatio,
emptyRatio,
sceneTop: r.top,
sceneHeight: r.height,
vh,
};
});
expect(metrics.ok).toBe(true);
if (!metrics.ok) return;
expect(metrics.heightRatio).toBeGreaterThanOrEqual(0.85);
expect(metrics.emptyRatio).toBeLessThanOrEqual(0.2);
});
test('full Measurement panel only with debug=1&measurement=full', async ({ page }) => {
await page.setViewportSize({ width: 1280, height: 800 });
await page.goto('/?debug=1&playback=paused');
await expect(page.locator('canvas')).toBeVisible({ timeout: 60_000 });
await expect(page.locator('.cv-overlay:not(.cv-overlay-compact)')).toHaveCount(0);
});
});