feat: full studio build -- light theme, canvas thumbnails, i18n (fa/en)
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
import type { RenderScene, RenderSettings } from "../src/lib/render-schemas";
|
||||
import { RESOLUTION_DIMENSIONS } from "../src/lib/render-schemas";
|
||||
|
||||
export interface NexrenderAsset {
|
||||
type: string;
|
||||
layerName?: string;
|
||||
composition?: string;
|
||||
property?: string;
|
||||
value?: string | number;
|
||||
src?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
time?: number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface NexrenderJob {
|
||||
template: {
|
||||
src: string;
|
||||
composition: string;
|
||||
frameStart?: number;
|
||||
frameEnd?: number;
|
||||
};
|
||||
assets: NexrenderAsset[];
|
||||
actions?: {
|
||||
postrender?: Array<Record<string, unknown>>;
|
||||
};
|
||||
onRenderProgress?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
function layerToAsset(
|
||||
layer: RenderScene["layers"][number],
|
||||
scene: RenderScene,
|
||||
sceneIndex: number
|
||||
): NexrenderAsset | null {
|
||||
const time = sceneIndex * scene.duration;
|
||||
|
||||
switch (layer.type) {
|
||||
case "text": {
|
||||
const text =
|
||||
typeof layer.props.text === "string" ? layer.props.text : "Text";
|
||||
return {
|
||||
type: "data",
|
||||
layerName: `Scene${sceneIndex + 1}_Text`,
|
||||
composition: scene.name,
|
||||
property: "Source Text",
|
||||
value: text,
|
||||
time,
|
||||
};
|
||||
}
|
||||
case "image": {
|
||||
const src = typeof layer.props.src === "string" ? layer.props.src : "";
|
||||
if (!src) return null;
|
||||
return {
|
||||
type: "image",
|
||||
layerName: `Scene${sceneIndex + 1}_Image`,
|
||||
composition: scene.name,
|
||||
src,
|
||||
width: layer.width,
|
||||
height: layer.height,
|
||||
time,
|
||||
};
|
||||
}
|
||||
case "video": {
|
||||
const src = typeof layer.props.src === "string" ? layer.props.src : "";
|
||||
if (!src) return null;
|
||||
return {
|
||||
type: "video",
|
||||
layerName: `Scene${sceneIndex + 1}_Video`,
|
||||
composition: scene.name,
|
||||
src,
|
||||
time,
|
||||
};
|
||||
}
|
||||
case "shape":
|
||||
return {
|
||||
type: "data",
|
||||
layerName: `Scene${sceneIndex + 1}_Shape`,
|
||||
composition: scene.name,
|
||||
property: "Opacity",
|
||||
value: Math.round(layer.opacity * 100),
|
||||
time,
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function buildNexrenderJob(
|
||||
scenes: RenderScene[],
|
||||
settings: RenderSettings,
|
||||
jobId: string,
|
||||
outputPath: string
|
||||
): NexrenderJob {
|
||||
const templateSrc =
|
||||
process.env.NEXRENDER_TEMPLATE_SRC ??
|
||||
"file:///templates/creatorstudio-base.aep";
|
||||
const composition =
|
||||
process.env.NEXRENDER_COMPOSITION ?? "CreatorStudio_Main";
|
||||
|
||||
const { width, height } = RESOLUTION_DIMENSIONS[settings.resolution];
|
||||
const totalDuration = scenes.reduce((sum, scene) => sum + scene.duration, 0);
|
||||
const frameEnd = Math.ceil(totalDuration * settings.fps);
|
||||
|
||||
const assets: NexrenderAsset[] = [
|
||||
{
|
||||
type: "data",
|
||||
layerName: "Settings",
|
||||
composition,
|
||||
property: "Width",
|
||||
value: width,
|
||||
},
|
||||
{
|
||||
type: "data",
|
||||
layerName: "Settings",
|
||||
composition,
|
||||
property: "Height",
|
||||
value: height,
|
||||
},
|
||||
{
|
||||
type: "data",
|
||||
layerName: "Settings",
|
||||
composition,
|
||||
property: "Frame Rate",
|
||||
value: settings.fps,
|
||||
},
|
||||
];
|
||||
|
||||
scenes.forEach((scene, sceneIndex) => {
|
||||
assets.push({
|
||||
type: "data",
|
||||
layerName: `Scene${sceneIndex + 1}`,
|
||||
composition,
|
||||
property: "Duration",
|
||||
value: scene.duration,
|
||||
time: sceneIndex * scene.duration,
|
||||
});
|
||||
|
||||
const sortedLayers = [...scene.layers].sort(
|
||||
(a, b) => a.zIndex - b.zIndex
|
||||
);
|
||||
|
||||
sortedLayers.forEach((layer) => {
|
||||
const asset = layerToAsset(layer, scene, sceneIndex);
|
||||
if (asset) assets.push(asset);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
template: {
|
||||
src: templateSrc,
|
||||
composition,
|
||||
frameStart: 0,
|
||||
frameEnd,
|
||||
},
|
||||
assets,
|
||||
actions: {
|
||||
postrender: [
|
||||
{
|
||||
module: "@nexrender/action-copy",
|
||||
output: outputPath,
|
||||
},
|
||||
],
|
||||
},
|
||||
metadata: {
|
||||
jobId,
|
||||
resolution: settings.resolution,
|
||||
fps: settings.fps,
|
||||
format: settings.format,
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user