Severity: High (memory leak)
sisyphus-web/src/components/GraphView.tsx:148-174 rebuilds the bloom post-processing chain on every [snapshot, rendering, dimensions] change but never disposes the previous one.
Problem
useEffect(() => {
const composer = new EffectComposer(...);
composer.addPass(new RenderPass(...));
composer.addPass(new UnrealBloomPass(...));
// ... patch fg._animationCycle
return () => {
// restore _animationCycle only — no composer.dispose(), no pass.dispose()
};
}, [snapshot, rendering, dimensions]);
Every filter switch, dimension change, or snapshot mutation creates new EffectComposer, RenderPass, UnrealBloomPass, and the bloom render targets — but the cleanup only restores fg._animationCycle. After many filter switches, GPU memory balloons.
Two more concerns:
- Patching
fg._animationCycle (a private react-force-graph-3d API) is fragile across upstream versions.
- The deps array depends on
snapshot and rendering, which change frequently — this effect re-runs on basically every state mutation.
Remediation
const composerRef = useRef<EffectComposer | null>(null);
const bloomPassRef = useRef<UnrealBloomPass | null>(null);
useEffect(() => {
// create composer + passes ONCE per dimensions change
// patch _animationCycle
return () => {
bloomPassRef.current?.dispose();
composerRef.current?.dispose();
composerRef.current = null;
bloomPassRef.current = null;
// restore _animationCycle
};
}, [dimensions]); // not [snapshot, rendering, dimensions]
If bloom intensity / radius depends on snapshot/rendering, mutate the existing pass's properties (bloomPassRef.current.strength = ...) — don't recreate.
Detection
DevTools → Memory snapshot → search for WebGLRenderTarget. Should stay constant across filter switches; today it grows monotonically.
Severity: High (memory leak)
sisyphus-web/src/components/GraphView.tsx:148-174rebuilds the bloom post-processing chain on every[snapshot, rendering, dimensions]change but never disposes the previous one.Problem
Every filter switch, dimension change, or snapshot mutation creates new
EffectComposer,RenderPass,UnrealBloomPass, and the bloom render targets — but the cleanup only restoresfg._animationCycle. After many filter switches, GPU memory balloons.Two more concerns:
fg._animationCycle(a privatereact-force-graph-3dAPI) is fragile across upstream versions.snapshotandrendering, which change frequently — this effect re-runs on basically every state mutation.Remediation
If bloom intensity / radius depends on
snapshot/rendering, mutate the existing pass's properties (bloomPassRef.current.strength = ...) — don't recreate.Detection
DevTools → Memory snapshot → search for
WebGLRenderTarget. Should stay constant across filter switches; today it grows monotonically.