codebase overhaul (#697)

This commit is contained in:
Maze
2026-01-31 00:20:04 +01:00
committed by GitHub
parent 0173db9944
commit 7bf0984698
469 changed files with 36184 additions and 32931 deletions
@@ -0,0 +1,124 @@
"use client";
import { useCallback, useMemo, useRef } from "react";
import useDeepCompareEffect from "use-deep-compare-effect";
import { useEditor } from "@/hooks/use-editor";
import { useRafLoop } from "@/hooks/use-raf-loop";
import { CanvasRenderer } from "@/services/renderer/canvas-renderer";
import type { RootNode } from "@/services/renderer/nodes/root-node";
import { buildScene } from "@/services/renderer/scene-builder";
import { getLastFrameTime } from "@/lib/time";
function usePreviewSize() {
const editor = useEditor();
const activeProject = editor.project.getActive();
return {
width: activeProject?.settings.canvasSize.width,
height: activeProject?.settings.canvasSize.height,
};
}
function RenderTreeController() {
const editor = useEditor();
const tracks = editor.timeline.getTracks();
const mediaAssets = editor.media.getAssets();
const activeProject = editor.project.getActive();
const { width, height } = usePreviewSize();
useDeepCompareEffect(() => {
if (!activeProject) return;
const duration = editor.timeline.getTotalDuration();
const renderTree = buildScene({
tracks,
mediaAssets,
duration,
canvasSize: { width, height },
background: activeProject.settings.background,
});
editor.renderer.setRenderTree({ renderTree });
}, [tracks, mediaAssets, activeProject?.settings.background, width, height]);
return null;
}
export function PreviewPanel() {
return (
<div className="bg-panel relative flex h-full min-h-0 w-full min-w-0 flex-col rounded-sm">
<div className="flex min-h-0 min-w-0 flex-1 items-center justify-center p-2">
<PreviewCanvas />
<RenderTreeController />
</div>
</div>
);
}
function PreviewCanvas() {
const ref = useRef<HTMLCanvasElement>(null);
const lastFrameRef = useRef(-1);
const lastSceneRef = useRef<RootNode | null>(null);
const renderingRef = useRef(false);
const { width, height } = usePreviewSize();
const editor = useEditor();
const activeProject = editor.project.getActive();
const renderer = useMemo(() => {
return new CanvasRenderer({
width,
height,
fps: activeProject.settings.fps,
});
}, [width, height, activeProject.settings.fps]);
const renderTree = editor.renderer.getRenderTree();
const render = useCallback(() => {
if (ref.current && renderTree && !renderingRef.current) {
const time = editor.playback.getCurrentTime();
const lastFrameTime = getLastFrameTime({
duration: renderTree.duration,
fps: renderer.fps,
});
const renderTime = Math.min(time, lastFrameTime);
const frame = Math.floor(renderTime * renderer.fps);
if (
frame !== lastFrameRef.current ||
renderTree !== lastSceneRef.current
) {
renderingRef.current = true;
lastSceneRef.current = renderTree;
lastFrameRef.current = frame;
renderer
.renderToCanvas({
node: renderTree,
time: renderTime,
targetCanvas: ref.current,
})
.then(() => {
renderingRef.current = false;
});
}
}
}, [renderer, renderTree, editor.playback]);
useRafLoop(render);
return (
<canvas
ref={ref}
width={width}
height={height}
className="block max-h-full max-w-full border"
style={{
background:
activeProject.settings.background.type === "blur"
? "transparent"
: activeProject?.settings.background.color,
}}
/>
);
}