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
5 changes: 5 additions & 0 deletions .changeset/light-mangos-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'basekit': patch
---

Keep the 3D viewer responsive without browser resize warnings.
13 changes: 13 additions & 0 deletions e2e/generator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
})
Expand Down
11 changes: 10 additions & 1 deletion src/components/Viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -302,7 +311,7 @@ export function Viewer({ mesh, width, length, height, round, fitToPart = false }

return (
<div className="relative h-full w-full">
<div ref={host} className="sheet h-full w-full" />
<div ref={host} className="sheet relative h-full w-full" />
{/* Registration marks rather than a frame: the sheet is trimmed to size. */}
<div className="pointer-events-none absolute inset-5" aria-hidden>
{CORNERS.map((corner) => (
Expand Down
Loading