{
  "name": "transition-fade",
  "type": "registry:ui",
  "description": "Crossfade between scenes, or dip the cut through a colour",
  "dependencies": [
    "remotion",
    "@remotion/transitions"
  ],
  "registryDependencies": [
    "transition-timing"
  ],
  "files": [
    {
      "path": "registry/bases/default/primitives/transition-fade.tsx",
      "type": "registry:ui",
      "content": "import type { TransitionPresentation } from \"@remotion/transitions\";\nimport { AbsoluteFill, interpolate } from \"remotion\";\nimport {\n  resolveTransitionTiming,\n  transitionPhase,\n  type TransitionVariant,\n} from \"@/remotion/lib/transition-timing\";\n\nexport type FadeProps = {\n  /** Colour the cut passes through. Undefined crossfades the scenes directly. */\n  dipTo?: string;\n};\n\n/**\n * Dip to colour: the outgoing scene sinks into `dipTo`, the frame holds that\n * colour for an instant, and the incoming scene rises back out of it. Each\n * scene paints its own colour layer, so the dip is opaque at the midpoint\n * whatever is behind the transition.\n */\nconst FadePresentation: React.FC<\n  React.ComponentProps<\n    NonNullable<TransitionPresentation<FadeProps>[\"component\"]>\n  >\n> = ({\n  children,\n  presentationProgress,\n  presentationDirection,\n  passedProps: { dipTo },\n}) => {\n  const phase = transitionPhase(presentationProgress, presentationDirection, {\n    lead: 1,\n    fade: true,\n  });\n\n  if (dipTo === undefined) {\n    return <AbsoluteFill style={{ opacity: phase.opacity }}>{children}</AbsoluteFill>;\n  }\n  // Reaches full colour by the halfway point rather than at the very end, so\n  // the two half-covered scenes meet as one opaque field instead of a muddy\n  // 75% blend of both.\n  const veil = interpolate(phase.displace, [0, 0.5, 1], [0, 1, 1], {\n    extrapolateLeft: \"clamp\",\n    extrapolateRight: \"clamp\",\n  });\n\n  return (\n    <AbsoluteFill>\n      {children}\n      <AbsoluteFill style={{ background: dipTo, opacity: veil }} />\n    </AbsoluteFill>\n  );\n};\n\nexport function crossfade(\n  props: FadeProps = {},\n): TransitionPresentation<FadeProps> {\n  return { component: FadePresentation, props };\n}\n\nexport type TransitionFadeConfig = {\n  durationInFrames?: number;\n  /** `spring` uses organic motion; `editorial` ease-out; `linear` is constant speed */\n  variant?: TransitionVariant;\n  /**\n   * Pass a colour to dip through it instead of crossfading the two scenes\n   * directly — the classic dip to black between beats.\n   */\n  dipTo?: string;\n};\n\n/** Fade transition config for use with TransitionSeries.Transition */\nexport function transitionFade({\n  durationInFrames = 18,\n  variant = \"editorial\",\n  dipTo,\n}: TransitionFadeConfig = {}) {\n  return {\n    presentation: crossfade({ dipTo }),\n    timing: resolveTransitionTiming({ durationInFrames, variant }),\n  };\n}\n\n/** Total overlap frames consumed by a transition (for composition duration math) */\nexport function getTransitionFadeDuration(\n  config: TransitionFadeConfig = {},\n  fps: number,\n): number {\n  return transitionFade(config).timing.getDurationInFrames({ fps });\n}\n"
    }
  ],
  "atlas": {
    "lane": "cuts",
    "drive": "time",
    "tier": "core"
  }
}