shipping this slop

This commit is contained in:
Maze Winther
2026-01-20 22:14:49 +01:00
parent 7117f17ece
commit 6e4069b42f
97 changed files with 3357 additions and 1858 deletions
-63
View File
@@ -6,9 +6,6 @@ import { MediaManager } from "./managers/media-manager";
import { RendererManager } from "./managers/renderer-manager";
import { CommandManager } from "./managers/commands";
import { SaveManager } from "./managers/save-manager";
import { buildScene } from "@/services/renderer/scene-builder";
import { SceneExporter } from "@/services/renderer/scene-exporter";
import type { ExportOptions } from "@/types/export";
export class EditorCore {
private static instance: EditorCore | null = null;
@@ -45,64 +42,4 @@ export class EditorCore {
EditorCore.instance = null;
}
async export({
format,
quality,
includeAudio = true,
onProgress,
}: ExportOptions): Promise<{
success: boolean;
buffer?: ArrayBuffer;
error?: string;
}> {
const project = this.project.getActive();
if (!project) {
return { success: false, error: "No active project" };
}
const duration = this.timeline.getTotalDuration();
if (duration === 0) {
return { success: false, error: "Timeline is empty" };
}
try {
const sceneGraph = buildScene({
tracks: this.timeline.getTracks(),
mediaAssets: this.media.getAssets(),
duration,
canvasSize: project.settings.canvasSize,
background: project.settings.background,
});
const exporter = new SceneExporter({
width: project.settings.canvasSize.width,
height: project.settings.canvasSize.height,
fps: project.settings.fps,
format,
quality,
includeAudio,
});
let progressHandler: ((progress: number) => void) | undefined;
if (onProgress) {
progressHandler = (progress: number) => onProgress({ progress });
exporter.on("progress", progressHandler);
}
const buffer = await exporter.export(sceneGraph);
if (progressHandler) {
exporter.off("progress", progressHandler);
}
if (!buffer) {
return { success: false, error: "Export was cancelled" };
}
return { success: true, buffer };
} catch (error) {
const message = error instanceof Error ? error.message : "Export failed";
return { success: false, error: message };
}
}
}
+4 -4
View File
@@ -1,8 +1,8 @@
import type { EditorCore } from "@/core";
import type { MediaAsset } from "@/types/assets";
import { storageService } from "@/lib/storage/storage-service";
import { storageService } from "@/services/storage/storage-service";
import { generateUUID } from "@/lib/utils";
import { videoCache } from "@/lib/video-cache";
import { videoCache } from "@/services/media/video-cache";
import { hasMediaId } from "@/lib/timeline/element-utils";
export class MediaManager {
@@ -10,7 +10,7 @@ export class MediaManager {
private isLoading = false;
private listeners = new Set<() => void>();
constructor(private editor: EditorCore) {}
constructor(private editor: EditorCore) { }
async addMediaAsset({
projectId,
@@ -45,7 +45,7 @@ export class MediaManager {
}): Promise<void> {
const asset = this.assets.find((asset) => asset.id === id);
videoCache.clearVideo(id);
videoCache.clearVideo({ mediaId: id });
if (asset?.url) {
URL.revokeObjectURL(asset.url);
+15 -4
View File
@@ -4,8 +4,9 @@ import type {
TProjectMetadata,
TProjectSettings,
} from "@/types/project";
import type { ExportOptions, ExportResult } from "@/types/export";
import type { TimelineElement } from "@/types/timeline";
import { storageService } from "@/lib/storage/storage-service";
import { storageService } from "@/services/storage/storage-service";
import { toast } from "sonner";
import { generateUUID } from "@/lib/utils";
import { UpdateProjectSettingsCommand } from "@/lib/commands/project";
@@ -15,12 +16,12 @@ import {
DEFAULT_COLOR,
} from "@/constants/project-constants";
import { buildDefaultScene } from "@/lib/scene-utils";
import { generateThumbnail } from "@/lib/media-processing-utils";
import { generateThumbnail } from "@/lib/media/processing";
import {
CURRENT_STORAGE_VERSION,
migrations,
runStorageMigrations,
} from "@/lib/migrations";
} from "@/services/storage/migrations";
export interface MigrationState {
isMigrating: boolean;
@@ -44,7 +45,7 @@ export class ProjectManager {
projectName: null,
};
constructor(private editor: EditorCore) {}
constructor(private editor: EditorCore) { }
private async ensureStorageMigrations(): Promise<void> {
if (this.storageMigrationPromise) {
@@ -97,6 +98,7 @@ export class ProjectManager {
settings: {
fps: DEFAULT_FPS,
canvasSize: DEFAULT_CANVAS_SIZE,
originalCanvasSize: null,
background: {
type: "color",
color: DEFAULT_COLOR,
@@ -186,6 +188,10 @@ export class ProjectManager {
}
}
async export({ options }: { options: ExportOptions }): Promise<ExportResult> {
return this.editor.renderer.exportProject({ options });
}
async loadAllProjects(): Promise<void> {
if (!this.isInitialized) {
this.isLoading = true;
@@ -474,6 +480,11 @@ export class ProjectManager {
return this.active;
}
/**
* for agents:
* in most cases, the project is guaranteed to be active, in which getActive() should be used instead.
* for very rare cases, this function may be used.
*/
getActiveOrNull(): TProject | null {
return this.active;
}
+1 -1
View File
@@ -78,7 +78,7 @@ export class SaveManager {
if (this.isSaving) return;
if (!this.hasPendingSave) return;
const activeProject = this.editor.project.getActiveOrNull();
const activeProject = this.editor.project.getActive();
if (!activeProject) return;
if (this.editor.project.getIsLoading()) return;
if (this.editor.project.getMigrationState().isMigrating) return;
+3 -3
View File
@@ -1,6 +1,6 @@
import type { EditorCore } from "@/core";
import type { TimelineTrack, TScene } from "@/types/timeline";
import { storageService } from "@/lib/storage/storage-service";
import { storageService } from "@/services/storage/storage-service";
import {
getMainScene,
ensureMainScene,
@@ -10,7 +10,7 @@ import {
import {
getFrameTime,
isBookmarkAtTime,
} from "@/lib/timeline/bookmark-utils";
} from "@/lib/timeline/bookmarks";
import { ensureMainTrack } from "@/lib/timeline/track-utils";
import {
CreateSceneCommand,
@@ -25,7 +25,7 @@ export class ScenesManager {
private list: TScene[] = [];
private listeners = new Set<() => void>();
constructor(private editor: EditorCore) {}
constructor(private editor: EditorCore) { }
async createScene({
name,
@@ -13,7 +13,7 @@ import {
RemoveTrackCommand,
ToggleTrackMuteCommand,
ToggleTrackVisibilityCommand,
AddElementToTrackCommand,
InsertElementCommand,
UpdateElementTrimCommand,
UpdateElementDurationCommand,
DeleteElementsCommand,
@@ -26,11 +26,12 @@ import {
UpdateElementStartTimeCommand,
MoveElementCommand,
} from "@/lib/commands/timeline";
import { InsertElementParams } from "@/lib/commands/timeline/element/insert-element";
export class TimelineManager {
private listeners = new Set<() => void>();
constructor(private editor: EditorCore) {}
constructor(private editor: EditorCore) { }
addTrack({ type, index }: { type: TrackType; index?: number }): string {
const command = new AddTrackCommand(type, index);
@@ -43,14 +44,11 @@ export class TimelineManager {
this.editor.command.execute({ command });
}
addElementToTrack({
trackId,
insertElement({
element,
}: {
trackId: string;
element: CreateTimelineElement;
}): void {
const command = new AddElementToTrackCommand(trackId, element);
placement,
}: InsertElementParams): void {
const command = new InsertElementCommand({ element, placement });
this.editor.command.execute({ command });
}