feat: enhance video presentation agent with parallel theme assignment and watermarking

This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-03-21 23:02:09 -07:00
parent 0fe5e034fe
commit d90b6d35ce
9 changed files with 123 additions and 197 deletions

View file

@ -2,7 +2,7 @@
import React, { useMemo } from "react";
import { Player } from "@remotion/player";
import { Sequence, AbsoluteFill } from "remotion";
import { Sequence, AbsoluteFill, useCurrentFrame, useVideoConfig, interpolate } from "remotion";
import { Audio } from "@remotion/media";
import { FPS } from "@/lib/remotion/constants";
@ -14,6 +14,68 @@ export interface CompiledSlide {
audioUrl?: string;
}
const WATERMARK_STYLES = {
container: {
position: "absolute" as const,
bottom: 28,
right: 36,
display: "flex",
alignItems: "center",
gap: 8,
padding: "6px 14px 6px 10px",
borderRadius: 9999,
background: "rgba(0, 0, 0, 0.35)",
backdropFilter: "blur(12px)",
WebkitBackdropFilter: "blur(12px)",
border: "1px solid rgba(255, 255, 255, 0.12)",
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
pointerEvents: "none" as const,
zIndex: 9999,
},
logo: {
width: 22,
height: 22,
filter: "brightness(0) invert(1)",
},
text: {
fontFamily: "Inter, system-ui, -apple-system, sans-serif",
fontSize: 15,
fontWeight: 600,
color: "rgba(255, 255, 255, 0.95)",
letterSpacing: "0.01em",
lineHeight: 1,
},
};
function Watermark() {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const opacity = interpolate(frame, [0, fps * 0.5], [0, 1], {
extrapolateRight: "clamp",
});
return (
<div style={{ ...WATERMARK_STYLES.container, opacity }}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/icon-128.svg" alt="" style={WATERMARK_STYLES.logo} />
<span style={WATERMARK_STYLES.text}>SurfSense</span>
</div>
);
}
export function buildSlideWithWatermark(
SlideComponent: React.ComponentType,
): React.FC {
const Wrapped: React.FC = () => (
<AbsoluteFill>
<SlideComponent />
<Watermark />
</AbsoluteFill>
);
return Wrapped;
}
function CombinedComposition({ scenes }: { scenes: CompiledSlide[] }) {
let offset = 0;
@ -29,6 +91,7 @@ function CombinedComposition({ scenes }: { scenes: CompiledSlide[] }) {
</Sequence>
);
})}
<Watermark />
</AbsoluteFill>
);
}

View file

@ -19,6 +19,7 @@ import { FPS } from "@/lib/remotion/constants";
import {
CombinedPlayer,
buildCompositionComponent,
buildSlideWithWatermark,
type CompiledSlide,
} from "./combined-player";
@ -397,11 +398,12 @@ function VideoPresentationPlayer({
const holdFrame = Math.floor(slide.durationInFrames * 0.3);
const root = createRoot(wrapper);
const SlideWithWatermark = buildSlideWithWatermark(slide.component);
flushSync(() => {
root.render(
React.createElement(Thumbnail, {
component: slide.component,
component: SlideWithWatermark,
compositionWidth: 1920,
compositionHeight: 1080,
frameToDisplay: holdFrame,