From 51afce967446980b292936d45e95b04ccab466dd Mon Sep 17 00:00:00 2001 From: Hiren Kangad Date: Mon, 9 Mar 2026 23:35:52 +0530 Subject: [PATCH] Add viewport culling and LOD ticker to PixiCanvas Runs a culling check every 200ms alongside the spring ticker. Off-screen image sprites are hidden (visible=false), on-screen ones get updateLOD() called with the current zoom level. Video sprites get onVisibilityChange() to auto-play/pause based on viewport visibility. Uses a 200px margin to avoid popping. --- frontend/src/canvas/PixiCanvas.tsx | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/frontend/src/canvas/PixiCanvas.tsx b/frontend/src/canvas/PixiCanvas.tsx index fb2925a..fb9990b 100644 --- a/frontend/src/canvas/PixiCanvas.tsx +++ b/frontend/src/canvas/PixiCanvas.tsx @@ -160,6 +160,41 @@ const PixiCanvas = forwardRef( springs.tick(ticker.deltaMS / 1000); }); + // -- Culling + LOD ticker (runs every 200ms, not every frame) ------ + + let lastCullCheck = 0; + app.ticker.add((ticker) => { + lastCullCheck += ticker.deltaMS; + if (lastCullCheck < 200) return; + lastCullCheck = 0; + + const zoom = viewport.scale.x; + const bounds = viewport.getVisibleBounds(); + const margin = 200; + + for (const item of scene.getAllItems()) { + const d = item.displayObject; + const ib = d.getBounds(); + const inView = + ib.x + ib.width > bounds.x - margin && + ib.x < bounds.x + bounds.width + margin && + ib.y + ib.height > bounds.y - margin && + ib.y < bounds.y + bounds.height + margin; + + if (item.type === 'image' && 'updateLOD' in d) { + if (inView) { + (d as any).updateLOD(zoom); + d.visible = true; + } else { + d.visible = false; + } + } + if (item.type === 'video' && 'onVisibilityChange' in d) { + (d as any).onVisibilityChange(inView); + } + } + }); + // -- Store refs ------------------------------------------------------ appRef.current = app;