/**
* RenderableComposition - Composition for Client-Side Rendering
*
* This composition uses @remotion/media components which are required for CSR.
* The standard remotion components (OffthreadVideo, Audio) are used in Player preview,
* but CSR requires @remotion/media versions.
*
* Key difference from editor Composition:
* - Uses Video/Audio from @remotion/media (CSR compatible)
* - Gets design data from props instead of store
* - No editing features
*/
import { AbsoluteFill, useCurrentFrame, Sequence, useVideoConfig } from "remotion";
import { Video as CSRVideo, Audio as CSRAudio } from "@remotion/media";
import type { IDesign, ITrackItem, IVideo, IAudio, IImage, IText } from "@designcombo/types";
import { Img } from "remotion";
interface RenderableCompositionProps {
design: IDesign;
}
// CSR-compatible Video component
const CSRVideoItem = ({ item, fps }: { item: IVideo; fps: number }) => {
const { details } = item;
const playbackRate = item.playbackRate || 1;
return (
);
};
// CSR-compatible Audio component
const CSRAudioItem = ({ item, fps }: { item: IAudio; fps: number }) => {
const { details } = item;
const playbackRate = item.playbackRate || 1;
return (
);
};
// CSR-compatible Image component
const CSRImageItem = ({ item }: { item: IImage }) => {
const { details } = item;
return (
);
};
// CSR-compatible Text component
const CSRTextItem = ({ item }: { item: IText }) => {
const { details } = item;
return (
);
};
/**
* Render a single track item based on its type
*/
const renderItem = (item: ITrackItem, fps: number) => {
switch (item.type) {
case 'video':
return ;
case 'audio':
return ;
case 'image':
return ;
case 'text':
return ;
default:
return null;
}
};
/**
* RenderableComposition for CSR (renderMediaOnWeb)
*/
export const RenderableComposition: React.FC = ({ design }) => {
const { width: renderWidth, height: renderHeight } = useVideoConfig(); // Output resolution
const fps = 30;
const trackItemIds = design.trackItemIds || [];
const trackItemsMap = design.trackItemsMap || {};
// Calculate scale factor matches the output resolution
const designWidth = design.size.width;
const designHeight = design.size.height;
// Determine scale based on width ratio (assuming aspect ratio is maintained)
const scale = renderWidth / designWidth;
return (
{trackItemIds.map((id) => {
const item = trackItemsMap[id] as ITrackItem;
if (!item) return null;
const startFrame = Math.round((item.display.from / 1000) * fps);
const durationFrames = Math.round(((item.display.to - item.display.from) / 1000) * fps);
return (
{renderItem(item, fps)}
);
})}
);
};
export default RenderableComposition;