diff --git a/.changeset/light-mangos-add.md b/.changeset/light-mangos-add.md new file mode 100644 index 0000000..99c7c58 --- /dev/null +++ b/.changeset/light-mangos-add.md @@ -0,0 +1,5 @@ +--- +'basekit': patch +--- + +Keep the 3D viewer responsive without browser resize warnings. diff --git a/e2e/generator.spec.ts b/e2e/generator.spec.ts index 8b35fd1..193be7c 100644 --- a/e2e/generator.spec.ts +++ b/e2e/generator.spec.ts @@ -66,6 +66,19 @@ test('builds the default base on load', { tag: '@ci' }, async ({ page }) => { expect(await triangles(page)).toBeGreaterThan(0) }) +test('keeps the 3D canvas out of the observed viewer layout', { tag: '@ci' }, async ({ page }) => { + const resizeErrors: string[] = [] + page.on('pageerror', (error) => { + if (error.message.includes('ResizeObserver')) resizeErrors.push(error.message) + }) + const canvas = page.locator('main canvas') + await expect(canvas).toHaveCSS('position', 'absolute') + await page.setViewportSize({ width: 390, height: 844 }) + await expect(canvas).toHaveCSS('position', 'absolute') + await expect.poll(() => triangles(page)).toBeGreaterThan(0) + expect(resizeErrors).toEqual([]) +}) + test('links to the source repository', async ({ page }) => { await expect(page.getByRole('link', { name: 'GitHub' })).toHaveAttribute('href', 'https://github.com/richardsolomou/basekit') }) diff --git a/src/components/Viewer.tsx b/src/components/Viewer.tsx index 630eb4e..233d219 100644 --- a/src/components/Viewer.tsx +++ b/src/components/Viewer.tsx @@ -94,6 +94,10 @@ export function Viewer({ mesh, width, length, height, round, fitToPart = false } // once per geometry swap instead. renderer.shadowMap.autoUpdate = false shadowsDirty.current = renderer + // Keep the canvas out of the observed container's layout. setSize() writes + // CSS dimensions as well as buffer dimensions, so an in-flow canvas can + // otherwise resize its own ResizeObserver ancestor. + Object.assign(renderer.domElement.style, { position: 'absolute', inset: '0' }) container.append(renderer.domElement) const world = new THREE.Scene() @@ -160,8 +164,13 @@ export function Viewer({ mesh, width, length, height, round, fitToPart = false } held.current = true }) + let lastWidth = -1 + let lastHeight = -1 const resize = () => { const { clientWidth: w, clientHeight: h } = container + if (w === lastWidth && h === lastHeight) return + lastWidth = w + lastHeight = h renderer.setSize(w, h) camera.aspect = w / Math.max(h, 1) camera.updateProjectionMatrix() @@ -302,7 +311,7 @@ export function Viewer({ mesh, width, length, height, round, fitToPart = false } return (
-
+
{/* Registration marks rather than a frame: the sheet is trimmed to size. */}
{CORNERS.map((corner) => (