{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "venetian-blinds",
  "title": "Venetian Blinds",
  "description": "The outgoing scene splits into horizontal slats that turn edge-on in a staggered ripple, revealing the next scene behind them.",
  "dependencies": ["remotion", "@remotion/transitions"],
  "files": [
    {
      "path": "registry/remocn/venetian-blinds/index.tsx",
      "content": "\"use client\";\n\nimport type {\n  TransitionPresentation,\n  TransitionPresentationComponentProps,\n} from \"@remotion/transitions\";\nimport type React from \"react\";\nimport { AbsoluteFill, Easing, interpolate, useVideoConfig } from \"remotion\";\n\nexport type VenetianBlindsDirection = \"top-down\" | \"bottom-up\" | \"center\";\n\nexport type VenetianBlindsProps = {\n  /** Number of horizontal slats. */\n  slats?: number;\n  /** Share of the transition spent rippling across slats, 0 to 0.9. */\n  stagger?: number;\n  /** Which slat turns first. */\n  direction?: VenetianBlindsDirection;\n  /** Tint a slat picks up as it turns away from the light. */\n  shadeColor?: string;\n};\n\nexport const venetianBlindsDefaults: Required<VenetianBlindsProps> = {\n  slats: 12,\n  stagger: 0.55,\n  direction: \"top-down\",\n  shadeColor: \"#000000\",\n};\n\nconst turnEase = Easing.bezier(0.55, 0, 0.35, 1);\nconst clamp = {\n  extrapolateLeft: \"clamp\" as const,\n  extrapolateRight: \"clamp\" as const,\n};\n\nfunction slatDelay(\n  index: number,\n  count: number,\n  direction: VenetianBlindsDirection,\n) {\n  if (count <= 1) return 0;\n  const t = index / (count - 1);\n  if (direction === \"bottom-up\") return 1 - t;\n  if (direction === \"center\") return Math.abs(t - 0.5) * 2;\n  return t;\n}\n\nconst VenetianBlindsPresentation: React.FC<\n  TransitionPresentationComponentProps<VenetianBlindsProps>\n> = ({\n  children,\n  presentationProgress,\n  presentationDirection,\n  passedProps,\n}) => {\n  const { width, height } = useVideoConfig();\n  const { slats, stagger, direction, shadeColor } = {\n    ...venetianBlindsDefaults,\n    ...passedProps,\n  };\n  const p = presentationProgress;\n\n  if (presentationDirection === \"entering\") {\n    // The incoming scene settles back a touch as the blinds open on it.\n    const scale = interpolate(p, [0, 1], [1.06, 1], {\n      ...clamp,\n      easing: Easing.out(Easing.cubic),\n    });\n    return (\n      <AbsoluteFill style={{ transform: `scale(${scale})` }}>\n        {children}\n      </AbsoluteFill>\n    );\n  }\n\n  const count = Math.max(1, Math.round(slats));\n  const spread = Math.min(0.9, Math.max(0, stagger));\n\n  return (\n    <AbsoluteFill\n      style={{\n        zIndex: 2,\n        perspective: height * 2.2,\n        perspectiveOrigin: \"50% 50%\",\n      }}\n    >\n      {Array.from({ length: count }, (_, i) => {\n        const top = Math.floor((i * height) / count);\n        const bottom = Math.floor(((i + 1) * height) / count);\n        const start = slatDelay(i, count, direction) * spread;\n        const local = turnEase(\n          interpolate(p, [start, start + 1 - spread], [0, 1], clamp),\n        );\n        const angle = local * 90;\n        // Fade out near edge-on so the last sliver never reads as a hairline.\n        const fade = interpolate(angle, [76, 88], [1, 0], clamp);\n        if (fade <= 0) return null;\n        return (\n          <div\n            key={top}\n            style={{\n              position: \"absolute\",\n              left: 0,\n              top,\n              width,\n              // 1px overlap hides hairline seams between resting slats.\n              height: bottom - top + (i < count - 1 ? 1 : 0),\n              overflow: \"hidden\",\n              transformOrigin: \"50% 50%\",\n              transform: `rotateX(${angle}deg)`,\n              backfaceVisibility: \"hidden\",\n              opacity: fade,\n            }}\n          >\n            <div\n              style={{\n                position: \"absolute\",\n                left: 0,\n                top: -top,\n                width,\n                height,\n              }}\n            >\n              {children}\n            </div>\n            <div\n              style={{\n                position: \"absolute\",\n                inset: 0,\n                backgroundColor: shadeColor,\n                opacity: Math.sin((angle * Math.PI) / 180) * 0.75,\n              }}\n            />\n          </div>\n        );\n      })}\n    </AbsoluteFill>\n  );\n};\n\nexport function venetianBlinds(\n  props: VenetianBlindsProps = {},\n): TransitionPresentation<VenetianBlindsProps> {\n  return { component: VenetianBlindsPresentation, props };\n}\n",
      "type": "registry:component",
      "target": "components/remocn/venetian-blinds.tsx"
    }
  ],
  "type": "registry:component"
}
