generated from fahricansecer/boilerplate-be
@@ -20,9 +20,10 @@ export type SceneProp = {
|
||||
export type MainVideoProps = {
|
||||
scenes: SceneProp[];
|
||||
musicPath?: string;
|
||||
visualEffect?: string;
|
||||
};
|
||||
|
||||
export const MainVideo: React.FC<MainVideoProps> = ({ scenes, musicPath }) => {
|
||||
export const MainVideo: React.FC<MainVideoProps> = ({ scenes, musicPath, visualEffect }) => {
|
||||
const { fps } = useVideoConfig();
|
||||
|
||||
// Helper: map local absolute path to standard file:// URL so Remotion Chromium can load it
|
||||
@@ -50,7 +51,7 @@ export const MainVideo: React.FC<MainVideoProps> = ({ scenes, musicPath }) => {
|
||||
from={startFrame}
|
||||
durationInFrames={scene.durationInFrames}
|
||||
>
|
||||
<SceneRenderer scene={scene} index={index} />
|
||||
<SceneRenderer scene={scene} index={index} visualEffect={visualEffect} />
|
||||
</Sequence>
|
||||
);
|
||||
})}
|
||||
@@ -58,18 +59,40 @@ export const MainVideo: React.FC<MainVideoProps> = ({ scenes, musicPath }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const SceneRenderer: React.FC<{ scene: SceneProp; index: number }> = ({ scene, index }) => {
|
||||
const SceneRenderer: React.FC<{ scene: SceneProp; index: number; visualEffect?: string }> = ({ scene, index, visualEffect }) => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps } = useVideoConfig();
|
||||
|
||||
// Ken Burns Effect (Zoom In / Pan)
|
||||
// Even scenes zoom in, odd scenes zoom out slightly for variation
|
||||
const scale = interpolate(
|
||||
frame,
|
||||
[0, scene.durationInFrames],
|
||||
index % 2 === 0 ? [1, 1.1] : [1.1, 1],
|
||||
{ extrapolateRight: "clamp" }
|
||||
);
|
||||
// Base scale for kenburns and general movement
|
||||
let scale = 1;
|
||||
let filter = "";
|
||||
let mixBlendMode: any = "normal";
|
||||
|
||||
// If no effect or kenburns, apply the default Ken Burns
|
||||
if (!visualEffect || visualEffect === "kenburns" || visualEffect === "filmgrain" || visualEffect === "lightleaks" || visualEffect === "sparkles") {
|
||||
scale = interpolate(
|
||||
frame,
|
||||
[0, scene.durationInFrames],
|
||||
index % 2 === 0 ? [1, 1.1] : [1.1, 1],
|
||||
{ extrapolateRight: "clamp" }
|
||||
);
|
||||
}
|
||||
|
||||
if (visualEffect === "glitch") {
|
||||
// Quick jitter
|
||||
const jitter = Math.sin(frame * 0.5) * 5;
|
||||
const jitterScale = index % 2 === 0 ? 1.05 : 1.0;
|
||||
scale = jitterScale + Math.abs(jitter) * 0.01;
|
||||
if (frame % 15 < 3) {
|
||||
filter = `hue-rotate(${jitter * 10}deg) contrast(150%)`;
|
||||
}
|
||||
}
|
||||
|
||||
// Common effect overlays
|
||||
const noiseOpacity = interpolate(frame % 10, [0, 5, 10], [0.1, 0.15, 0.1]);
|
||||
const lightLeakOpacity = interpolate(Math.sin(frame * 0.05), [-1, 1], [0.1, 0.4]);
|
||||
|
||||
const makeFileUrl = (path?: string) => {
|
||||
if (!path) return undefined;
|
||||
@@ -84,6 +107,8 @@ const SceneRenderer: React.FC<{ scene: SceneProp; index: number }> = ({ scene, i
|
||||
style={{
|
||||
transform: `scale(${scale})`,
|
||||
transformOrigin: "center center",
|
||||
filter: filter ? filter : undefined,
|
||||
mixBlendMode: mixBlendMode
|
||||
}}
|
||||
>
|
||||
{scene.imagePath ? (
|
||||
@@ -98,6 +123,48 @@ const SceneRenderer: React.FC<{ scene: SceneProp; index: number }> = ({ scene, i
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
)}
|
||||
|
||||
{visualEffect === "filmgrain" && (
|
||||
<AbsoluteFill style={{
|
||||
opacity: noiseOpacity,
|
||||
backgroundColor: "white",
|
||||
mixBlendMode: "overlay",
|
||||
filter: "url(#noiseFilter)"
|
||||
}}>
|
||||
<svg>
|
||||
<filter id="noiseFilter">
|
||||
<feTurbulence type="fractalNoise" baseFrequency="0.8" numOctaves="3" stitchTiles="stitch"/>
|
||||
</filter>
|
||||
</svg>
|
||||
</AbsoluteFill>
|
||||
)}
|
||||
|
||||
{visualEffect === "lightleaks" && (
|
||||
<AbsoluteFill style={{
|
||||
background: "linear-gradient(45deg, rgba(255,100,0,0) 0%, rgba(255,50,0,0.5) 50%, rgba(255,0,0,0) 100%)",
|
||||
opacity: lightLeakOpacity,
|
||||
mixBlendMode: "screen",
|
||||
transform: `scale(1.5) rotate(${frame * 0.5}deg)`
|
||||
}} />
|
||||
)}
|
||||
|
||||
{visualEffect === "sparkles" && (
|
||||
<AbsoluteFill style={{
|
||||
background: "radial-gradient(circle at center, rgba(255,255,255,0.8) 0%, rgba(255,255,255,0) 10%)",
|
||||
backgroundSize: "50px 50px",
|
||||
backgroundPosition: `${frame}px ${frame * 2}px`,
|
||||
opacity: interpolate(Math.sin(frame * 0.1), [-1, 1], [0.3, 0.8]),
|
||||
mixBlendMode: "screen"
|
||||
}} />
|
||||
)}
|
||||
|
||||
{visualEffect === "glitch" && frame % 20 < 4 && (
|
||||
<AbsoluteFill style={{
|
||||
backgroundColor: "rgba(255, 0, 0, 0.2)",
|
||||
mixBlendMode: "color-burn",
|
||||
transform: `translateX(${Math.random() * 20 - 10}px)`
|
||||
}} />
|
||||
)}
|
||||
</AbsoluteFill>
|
||||
|
||||
{/* Audio Tracks */}
|
||||
|
||||
Reference in New Issue
Block a user