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,129 @@
import type { EditorCore } from "@/core";
import type { RootNode } from "@/services/renderer/nodes/root-node";
import type { ExportOptions, ExportResult } from "@/types/export";
import { SceneExporter } from "@/services/renderer/scene-exporter";
import { buildScene } from "@/services/renderer/scene-builder";
import { createTimelineAudioBuffer } from "@/lib/media/audio";
export class RendererManager {
private renderTree: RootNode | null = null;
private listeners = new Set<() => void>();
constructor(private editor: EditorCore) {}
setRenderTree({ renderTree }: { renderTree: RootNode | null }): void {
this.renderTree = renderTree;
this.notify();
}
getRenderTree(): RootNode | null {
return this.renderTree;
}
async exportProject({
options,
}: {
options: ExportOptions;
}): Promise<ExportResult> {
const { format, quality, fps, includeAudio, onProgress, onCancel } =
options;
try {
const tracks = this.editor.timeline.getTracks();
const mediaAssets = this.editor.media.getAssets();
const activeProject = this.editor.project.getActive();
if (!activeProject) {
return { success: false, error: "No active project" };
}
const duration = this.editor.timeline.getTotalDuration();
if (duration === 0) {
return { success: false, error: "Project is empty" };
}
const exportFps = fps || activeProject.settings.fps;
const canvasSize = activeProject.settings.canvasSize;
let audioBuffer: AudioBuffer | null = null;
if (includeAudio) {
onProgress?.({ progress: 0.05 });
audioBuffer = await createTimelineAudioBuffer({
tracks,
mediaAssets,
duration,
});
}
const scene = buildScene({
tracks,
mediaAssets,
duration,
canvasSize,
background: activeProject.settings.background,
});
const exporter = new SceneExporter({
width: canvasSize.width,
height: canvasSize.height,
fps: exportFps,
format,
quality,
shouldIncludeAudio: !!includeAudio,
audioBuffer: audioBuffer || undefined,
});
exporter.on("progress", (progress) => {
const adjustedProgress = includeAudio
? 0.05 + progress * 0.95
: progress;
onProgress?.({ progress: adjustedProgress });
});
let cancelled = false;
const checkCancel = () => {
if (onCancel?.()) {
cancelled = true;
exporter.cancel();
}
};
const cancelInterval = setInterval(checkCancel, 100);
try {
const buffer = await exporter.export({ rootNode: scene });
clearInterval(cancelInterval);
if (cancelled) {
return { success: false, cancelled: true };
}
if (!buffer) {
return { success: false, error: "Export failed to produce buffer" };
}
return {
success: true,
buffer,
};
} finally {
clearInterval(cancelInterval);
}
} catch (error) {
console.error("Export failed:", error);
return {
success: false,
error: error instanceof Error ? error.message : "Unknown export error",
};
}
}
subscribe(listener: () => void): () => void {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
}
private notify(): void {
this.listeners.forEach((fn) => fn());
}
}