Catalog

Edit Props (live)

IMAGE
IMAGE
IMAGE
AUDIO
config
config
config

Source

115 lines
import React from "react";
import {
  AbsoluteFill,
  Audio,
  Img,
  OffthreadVideo,
  staticFile,
  useCurrentFrame,
  useVideoConfig,
  interpolate,
} from "remotion";
import { KineticCaption } from "./KineticCaption";

interface WordTimestamp {
  word: string;
  start: number;
  end: number;
  emphasis?: boolean;
}

export interface EspnDebrief2Props {
  avatarSrc: string;
  screenshotSrc: string;
  screenshotHeight: number;
  audioSrc: string | null;
  wordTimestamps: WordTimestamp[];
  fps: number;
  durationSec: number;
}

export const EspnDebrief2: React.FC<EspnDebrief2Props> = ({
  avatarSrc,
  screenshotSrc,
  screenshotHeight,
  audioSrc,
  wordTimestamps,
  fps,
  durationSec,
}) => {
  const frame = useCurrentFrame();
  const { width, height, durationInFrames } = useVideoConfig();

  // Screenshot box: ~78% width, height derived from screenshot aspect ratio
  const boxW = Math.round(width * 0.78);
  const screenshotAspect = screenshotHeight / 850; // screenshot is always 850px wide
  const boxH = Math.min(Math.round(boxW * screenshotAspect), Math.round(height * 0.65));
  const boxX = Math.round((width - boxW) / 2); // centered horizontally
  const boxY = Math.round((height - boxH) / 2 + height * 0.1); // centered + 10% down

  // Static — no scroll, show top of article

  return (
    <AbsoluteFill>
      {/* Avatar video — fullscreen background */}
      {avatarSrc && (
        <OffthreadVideo
          src={staticFile(avatarSrc)}
          style={{
            width: "100%",
            height: "100%",
            objectFit: "cover",
          }}
        />
      )}

      {/* Article screenshot box — bottom-right with rounded corners */}
      {screenshotSrc && (
        <div
          style={{
            position: "absolute",
            top: boxY,
            left: boxX,
            width: boxW,
            height: boxH,
            borderRadius: 24,
            overflow: "hidden",
            boxShadow: "0 8px 40px rgba(0,0,0,0.5)",
          }}
        >
          <Img
            src={staticFile(screenshotSrc)}
            style={{
              position: "absolute",
              top: 0,
              left: 0,
              width: "100%",
            }}
          />
        </div>
      )}

      {/* Kinetic captions — bottom */}
      {wordTimestamps.length > 0 && (
        <div
          style={{
            position: "absolute",
            bottom: 60,
            left: 0,
            right: 0,
            display: "flex",
            justifyContent: "center",
          }}
        >
          <KineticCaption words={wordTimestamps} />
        </div>
      )}

      {/* Separate audio if provided */}
      {audioSrc && (
        <Audio src={staticFile(audioSrc)} volume={1} />
      )}
    </AbsoluteFill>
  );
};

Schema (Zod)

// Auto-extracted from Props interface — see source for authoritative types.
// Component: EspnDebrief2
// 7 props detected · 4 port(s)

Espn Debrief2

espn_debrief2

Espn Debrief2 — Andy's hand-crafted Remotion scene. 7 props. avatarSrc:IMAGE, screenshotSrc:IMAGE, screenshotHeight:IMAGE, +1 more.

Workflow Inputs (4)

  • Avatar Src
    avatarSrc
    IMAGERequired
  • Screenshot Src
    screenshotSrc
    IMAGERequired
  • Screenshot Height
    screenshotHeight
    IMAGERequired
  • Audio Src
    audioSrc
    AUDIORequired

Config Fields (3)

  • fps
  • durationSec
  • wordTimestamps

Meta

Updated
4/21/2026