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
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@
- Library builds must externalize `three` with a pattern that also matches subpaths like `three/webgpu`, `three/tsl`, and `three/examples/jsm/*`; externalizing only bare `three` bundles a second Three runtime into `build/` and triggers `THREE.WARNING: Multiple instances of Three.js being imported.` in consumers
- State action migrations must use `AnimationSystem.fromTargets(...).play()` and `Toolbox.enableTool()`; lingering `animate()` or `useTool()` calls can still let `yarn build` exit 0 while `vite-plugin-dts` reports TS2339 API drift
- When swapping canvases under WebGPU, `DIVEEnvironment.setRenderer()` must run before disposing the previous `WebGPURenderer`; disposing the old renderer first can crash `PMREMGenerator.dispose()` inside Three's `NodeManager.delete` with `usedTimes` access errors
- `OrientationDisplay.tick()` should size its overlay viewport from `DIVERenderer.canvas.clientHeight` and restore the prior `webgpurenderer.autoClear` value; unit tests can fall back to the saved viewport height when the mock omits `canvas`
8 changes: 6 additions & 2 deletions src/plugins/orientationdisplay/src/OrientationDisplay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,18 @@ export class OrientationDisplay implements DIVETicker {
public tick(): void {
// save current background reference and set it to transparent
const restoreBackground = this._scene.background ?? null;
const restoreAutoClear = this._renderer.webgpurenderer.autoClear;
this._scene.background = null;

// save current viewport and set it to desired size
this._renderer.webgpurenderer.getViewport(this._restoreViewport);
const canvasHeight =
this._renderer.webgpurenderer.domElement?.clientHeight ??
this._restoreViewport.w;

this._renderer.webgpurenderer.setViewport(
0,
this._renderer.webgpurenderer.domElement.clientHeight - 150,
Math.max(0, canvasHeight - 150),
150,
150,
);
Expand All @@ -70,7 +74,7 @@ export class OrientationDisplay implements DIVETicker {

// restore viewport and background
this._renderer.webgpurenderer.setViewport(this._restoreViewport);
this._renderer.webgpurenderer.autoClear = true;
this._renderer.webgpurenderer.autoClear = restoreAutoClear;
this._scene.background = restoreBackground;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,17 @@ const mockCamera = {
matrix: new Matrix4(),
} as unknown as DIVEPerspectiveCamera;

const mockCanvas = document.createElement('canvas');
Object.defineProperty(mockCanvas, 'clientHeight', {
value: 600,
configurable: true,
});

const mockRenderer = {
render: vi.fn(),
canvas: mockCanvas,
webgpurenderer: {
getViewport: vi.fn().mockReturnValue(new Vector4(0, 0, 800, 600)),
getViewport: vi.fn((viewport: Vector4) => viewport.set(0, 0, 800, 600)),
setViewport: vi.fn(),
render: vi.fn(),
autoClear: true,
Expand Down Expand Up @@ -108,7 +115,7 @@ describe('OrientationDisplay', () => {
).toHaveBeenCalledWith(orientationDisplay['_restoreViewport']);
expect(
mockRenderer.webgpurenderer.setViewport,
).toHaveBeenCalledWith(0, 0, 150, 150);
).toHaveBeenCalledWith(0, 450, 150, 150);
expect(mockRenderer.webgpurenderer.render).toHaveBeenCalledWith(
mockScene,
orientationDisplay['_orthographicCamera'],
Expand Down Expand Up @@ -140,10 +147,23 @@ describe('OrientationDisplay', () => {
);
});

it('should manage autoClear property correctly', () => {
it('should restore the previous autoClear property', () => {
mockRenderer.webgpurenderer.autoClear = false;

orientationDisplay.tick();

expect(mockRenderer.webgpurenderer.autoClear).toBe(false);
});

it('should fall back to the stored viewport height when canvas height is unavailable', () => {
mockRenderer.webgpurenderer.domElement =
undefined as unknown as HTMLCanvasElement;

orientationDisplay.tick();

expect(mockRenderer.webgpurenderer.autoClear).toBe(true);
expect(
mockRenderer.webgpurenderer.setViewport,
).toHaveBeenCalledWith(0, 450, 150, 150);
});
});
});
Loading