import { useEffect, type RefObject } from "react"; import type { AppStore } from "@editor/store"; import { createRenderer, type RenderFrame } from "@renderer/index"; import { canvasRenderFramesEqual, selectCanvasRenderFrame } from "./renderFrame"; export function useCanvasRenderer(canvasRef: RefObject, store: AppStore) { useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const renderer = createRenderer(canvas); let renderedFrame = selectCanvasRenderFrame(store.getState()); let pendingFrame: RenderFrame | undefined; let animationFrame: number | undefined; const flushRender = () => { animationFrame = undefined; const frame = pendingFrame; if (!frame) return; pendingFrame = undefined; renderedFrame = frame; renderer.render(frame); }; const scheduleRender = (frame: RenderFrame) => { pendingFrame = frame; if (animationFrame !== undefined) return; animationFrame = requestAnimationFrame(flushRender); }; scheduleRender(renderedFrame); const unsubscribe = store.subscribe((state) => { const nextFrame = selectCanvasRenderFrame(state); const currentFrame = pendingFrame ?? renderedFrame; if (canvasRenderFramesEqual(currentFrame, nextFrame)) return; scheduleRender(nextFrame); }); return () => { unsubscribe(); if (animationFrame !== undefined) cancelAnimationFrame(animationFrame); renderer.dispose(); }; }, [canvasRef, store]); }