diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-26 20:44:07 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-04-26 20:44:07 +0200 |
| commit | 6b1f38a9a31a0eedaa7abea70f232960469351d5 (patch) | |
| tree | 4050d69056c1d9f14075b784535e2b33719f477b /apps/web/src/preview/components | |
| parent | 56ca09692a308b22455420d11376ff8d41244c47 (diff) | |
| parent | 0b7597b31fa956c7f3d4838923b545ba5e341422 (diff) | |
| download | opencut-6b1f38a9a31a0eedaa7abea70f232960469351d5.tar.gz | |
refactor: split animation helpers by domain
Diffstat (limited to 'apps/web/src/preview/components')
| -rw-r--r-- | apps/web/src/preview/components/index.tsx | 100 | ||||
| -rw-r--r-- | apps/web/src/preview/components/text-edit-overlay.tsx | 2 | ||||
| -rw-r--r-- | apps/web/src/preview/components/toolbar.tsx | 11 |
3 files changed, 63 insertions, 50 deletions
diff --git a/apps/web/src/preview/components/index.tsx b/apps/web/src/preview/components/index.tsx index d3cb2a49..e8f5c572 100644 --- a/apps/web/src/preview/components/index.tsx +++ b/apps/web/src/preview/components/index.tsx @@ -132,7 +132,7 @@ function PreviewCanvas({ isVisible: boolean; }) => void; }) { - const canvasRef = useRef<HTMLCanvasElement>(null); + const canvasMountRef = useRef<HTMLDivElement>(null); const viewportRef = useRef<HTMLDivElement>(null); const lastFrameRef = useRef(-1); const lastSceneRef = useRef<RootNode | null>(null); @@ -158,35 +158,51 @@ function PreviewCanvas({ }); }, [nativeWidth, nativeHeight, activeProject.settings.fps]); + // Mount the compositor's output canvas directly into the preview. wgpu + // renders straight into this element, so there is no intermediate copy — + // the container div owns positioning/styling, the canvas itself fills it. + useEffect(() => { + const mount = canvasMountRef.current; + if (!mount) return; + const outputCanvas = renderer.getOutputCanvas(); + outputCanvas.style.display = "block"; + outputCanvas.style.width = "100%"; + outputCanvas.style.height = "100%"; + mount.appendChild(outputCanvas); + return () => { + if (outputCanvas.parentElement === mount) { + mount.removeChild(outputCanvas); + } + }; + }, [renderer]); + const render = useCallback(() => { - if (canvasRef.current && renderTree && !renderingRef.current) { - const renderTime = Math.min( - editor.playback.getCurrentTime(), - editor.timeline.getLastFrameTime(), - ); - const ticksPerFrame = Math.round( - (TICKS_PER_SECOND * renderer.fps.denominator) / renderer.fps.numerator, - ); - const frame = Math.floor(renderTime / ticksPerFrame); + if (!renderTree || renderingRef.current) return; - if ( - frame !== lastFrameRef.current || - renderTree !== lastSceneRef.current - ) { - renderingRef.current = true; - lastSceneRef.current = renderTree; - lastFrameRef.current = frame; - renderer - .renderToCanvas({ - node: renderTree, - time: renderTime, - targetCanvas: canvasRef.current, - }) - .then(() => { - renderingRef.current = false; - }); - } + const renderTime = Math.min( + editor.playback.getCurrentTime(), + editor.timeline.getLastFrameTime(), + ); + const ticksPerFrame = Math.round( + (TICKS_PER_SECOND * renderer.fps.denominator) / renderer.fps.numerator, + ); + const frame = Math.floor(renderTime / ticksPerFrame); + + if ( + frame === lastFrameRef.current && + renderTree === lastSceneRef.current + ) { + return; } + + renderingRef.current = true; + lastSceneRef.current = renderTree; + lastFrameRef.current = frame; + renderer + .render({ node: renderTree, time: renderTime }) + .then(() => { + renderingRef.current = false; + }); }, [renderer, renderTree, editor.playback, editor.timeline]); useRafLoop(render); @@ -286,22 +302,20 @@ function PreviewCanvas({ ref={viewportRef} className="relative flex size-full min-h-0 min-w-0 items-center justify-center overflow-hidden" > - <canvas - ref={canvasRef} - width={nativeWidth} - height={nativeHeight} - className="absolute block border" - style={{ - left: viewport.sceneLeft, - top: viewport.sceneTop, - width: viewport.sceneWidth, - height: viewport.sceneHeight, - background: - activeProject.settings.background.type === "blur" - ? "transparent" - : activeProject?.settings.background.color, - }} - /> + <div + ref={canvasMountRef} + className="absolute block border" + style={{ + left: viewport.sceneLeft, + top: viewport.sceneTop, + width: viewport.sceneWidth, + height: viewport.sceneHeight, + background: + activeProject.settings.background.type === "blur" + ? "transparent" + : activeProject?.settings.background.color, + }} + /> <PreviewOverlayLayer instances={overlayInstances} plane="under-interaction" diff --git a/apps/web/src/preview/components/text-edit-overlay.tsx b/apps/web/src/preview/components/text-edit-overlay.tsx index bc27c724..1d599b3b 100644 --- a/apps/web/src/preview/components/text-edit-overlay.tsx +++ b/apps/web/src/preview/components/text-edit-overlay.tsx @@ -7,8 +7,8 @@ import type { TextElement } from "@/timeline"; import { DEFAULTS } from "@/timeline/defaults"; import { getElementLocalTime, - resolveTransformAtTime, } from "@/animation"; +import { resolveTransformAtTime } from "@/rendering/animation-values"; import { resolveTextLayout } from "@/text/primitives"; export function TextEditOverlay({ diff --git a/apps/web/src/preview/components/toolbar.tsx b/apps/web/src/preview/components/toolbar.tsx index 857b43e2..1a5ce1bc 100644 --- a/apps/web/src/preview/components/toolbar.tsx +++ b/apps/web/src/preview/components/toolbar.tsx @@ -8,12 +8,10 @@ import { EditableTimecode } from "@/components/editable-timecode"; import { Button } from "@/components/ui/button"; import { FullScreenIcon, - GridTableIcon, PauseIcon, PlayIcon, } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; -import { getGuideById } from "@/guides"; import { Separator } from "@/components/ui/separator"; import { Select, @@ -33,9 +31,6 @@ export function PreviewToolbar({ }: { onToggleFullscreen: () => void; }) { - const activeGuide = usePreviewStore((state) => state.activeGuide); - const activeGuideDefinition = getGuideById(activeGuide); - return ( <div className="grid grid-cols-[1fr_auto_1fr] items-center pb-3 pt-5 px-5"> <TimecodeDisplay /> @@ -93,7 +88,11 @@ function TimecodeDisplay() { /> <span className="text-muted-foreground px-2 font-mono text-xs">/</span> <span className="text-muted-foreground font-mono text-xs"> - {formatTimecode({ time: totalDuration, format: "HH:MM:SS:FF", rate: fps })} + {formatTimecode({ + time: totalDuration, + format: "HH:MM:SS:FF", + rate: fps, + })} </span> </div> ); |
