{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ecosystem-constellation",
  "title": "Ecosystem Constellation",
  "description": "A central logo orbited by integration satellites with pulsing data lines.",
  "dependencies": [
    "remotion"
  ],
  "files": [
    {
      "path": "registry/bases/editframe/components/ecosystem-constellation/index.tsx",
      "content": "\"use client\";\n\nimport { Timegroup } from \"@editframe/react\";\nimport type { CSSProperties } from \"react\";\n\nconst FONT_FAMILY =\n  \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\";\n\nconst GitHubMark = () => (\n  <svg viewBox=\"0 0 24 24\" width={30} height={30} aria-hidden=\"true\">\n    <path\n      fill=\"#fff\"\n      d=\"M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.91.58.11.79-.25.79-.55v-2.06c-3.2.7-3.87-1.36-3.87-1.36-.52-1.33-1.27-1.69-1.27-1.69-1.04-.71.08-.7.08-.7 1.15.08 1.76 1.18 1.76 1.18 1.02 1.75 2.69 1.24 3.35.95.1-.74.4-1.24.72-1.53-2.55-.29-5.24-1.28-5.24-5.7 0-1.26.45-2.29 1.18-3.1-.12-.29-.51-1.46.11-3.05 0 0 .97-.31 3.18 1.18.92-.26 1.91-.39 2.89-.39s1.97.13 2.89.39c2.21-1.49 3.18-1.18 3.18-1.18.62 1.59.23 2.76.11 3.05.74.81 1.18 1.84 1.18 3.1 0 4.43-2.7 5.41-5.27 5.69.41.36.77 1.06.77 2.13v3.16c0 .31.21.67.8.55C20.21 21.39 23.5 17.08 23.5 12 23.5 5.65 18.35.5 12 .5z\"\n    />\n  </svg>\n);\n\nconst VercelMark = () => (\n  <svg viewBox=\"0 0 24 24\" width={28} height={28} aria-hidden=\"true\">\n    <path fill=\"#fff\" d=\"M12 2 L23 21 L1 21 Z\" />\n  </svg>\n);\n\nconst StripeMark = () => (\n  <svg viewBox=\"0 0 24 24\" width={28} height={28} aria-hidden=\"true\">\n    <path\n      fill=\"#fff\"\n      d=\"M13.5 9.6c0-.6.5-.85 1.3-.85 1.15 0 2.6.35 3.75.97V6.16c-1.25-.5-2.5-.7-3.75-.7C11.7 5.46 9.6 7.06 9.6 9.7c0 4.13 5.7 3.47 5.7 5.25 0 .7-.6.93-1.45.93-1.25 0-2.85-.52-4.1-1.2v3.65c1.4.6 2.8.85 4.1.85 3.2 0 5.4-1.55 5.4-4.25-.02-4.45-5.75-3.65-5.75-5.33z\"\n    />\n  </svg>\n);\n\nconst SlackMark = () => (\n  <svg viewBox=\"0 0 24 24\" width={26} height={26} aria-hidden=\"true\">\n    <rect x=\"2\" y=\"10\" width=\"9\" height=\"2.5\" rx=\"1.25\" fill=\"#36C5F0\" />\n    <rect x=\"13\" y=\"10\" width=\"9\" height=\"2.5\" rx=\"1.25\" fill=\"#2EB67D\" />\n    <rect x=\"10\" y=\"2\" width=\"2.5\" height=\"9\" rx=\"1.25\" fill=\"#ECB22E\" />\n    <rect x=\"10\" y=\"13\" width=\"2.5\" height=\"9\" rx=\"1.25\" fill=\"#E01E5A\" />\n  </svg>\n);\n\nconst LinearMark = () => (\n  <svg viewBox=\"0 0 24 24\" width={28} height={28} aria-hidden=\"true\">\n    <defs>\n      <linearGradient id=\"linear-grad\" x1=\"0\" x2=\"1\" y1=\"0\" y2=\"1\">\n        <stop offset=\"0%\" stopColor=\"#fff\" stopOpacity=\"0.95\" />\n        <stop offset=\"100%\" stopColor=\"#fff\" stopOpacity=\"0.55\" />\n      </linearGradient>\n    </defs>\n    <circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"url(#linear-grad)\" />\n    <path\n      d=\"M5 13 L11 19 M5 9 L15 19 M15 9 V19\"\n      stroke=\"#0a0a0a\"\n      strokeWidth=\"0.9\"\n      strokeLinecap=\"round\"\n      opacity=\"0.85\"\n    />\n  </svg>\n);\n\nconst FigmaMark = () => (\n  <svg viewBox=\"0 0 24 24\" width={26} height={26} aria-hidden=\"true\">\n    <circle cx=\"9\" cy=\"4\" r=\"3.5\" fill=\"#F24E1E\" />\n    <circle cx=\"15\" cy=\"4\" r=\"3.5\" fill=\"#FF7262\" />\n    <circle cx=\"9\" cy=\"11\" r=\"3.5\" fill=\"#A259FF\" />\n    <circle cx=\"15\" cy=\"11\" r=\"3.5\" fill=\"#1ABCFE\" />\n    <circle cx=\"9\" cy=\"18\" r=\"3.5\" fill=\"#0ACF83\" />\n  </svg>\n);\n\nconst NotionMark = () => (\n  <svg viewBox=\"0 0 24 24\" width={26} height={26} aria-hidden=\"true\">\n    <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"3\" fill=\"#fff\" />\n    <path\n      d=\"M8 7 V17 M8 7 L16 17 M16 7 V17\"\n      stroke=\"#0a0a0a\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      fill=\"none\"\n    />\n  </svg>\n);\n\nconst DiscordMark = () => (\n  <svg viewBox=\"0 0 24 24\" width={28} height={28} aria-hidden=\"true\">\n    <path\n      fill=\"#fff\"\n      d=\"M19.5 4.7A18 18 0 0 0 15 3.3l-.2.4a16.5 16.5 0 0 0-5.6 0L9 3.3a18 18 0 0 0-4.5 1.4C2 8.7 1.4 12.5 1.7 16.3a18 18 0 0 0 5.5 2.8l.4-.6a13 13 0 0 1-2-1l.5-.4a13 13 0 0 0 11.7 0l.5.4a13 13 0 0 1-2 1l.4.6a18 18 0 0 0 5.5-2.8c.4-4.4-.6-8.2-2.7-11.6zM8.5 14c-.9 0-1.7-.9-1.7-2s.8-2 1.7-2 1.7.9 1.7 2-.8 2-1.7 2zm7 0c-.9 0-1.7-.9-1.7-2s.8-2 1.7-2 1.7.9 1.7 2-.8 2-1.7 2z\"\n    />\n  </svg>\n);\n\ninterface SatelliteBrand {\n  Logo: React.ComponentType;\n  bg: string;\n}\n\nconst SATELLITE_BRANDS: SatelliteBrand[] = [\n  { Logo: GitHubMark, bg: \"#1f1f23\" },\n  { Logo: VercelMark, bg: \"#0a0a0a\" },\n  { Logo: StripeMark, bg: \"#635bff\" },\n  { Logo: SlackMark, bg: \"#1a1d21\" },\n  { Logo: LinearMark, bg: \"#5e6ad2\" },\n  { Logo: FigmaMark, bg: \"#1e1e1e\" },\n  { Logo: NotionMark, bg: \"#1a1a1a\" },\n  { Logo: DiscordMark, bg: \"#5865f2\" },\n];\n\nexport interface EcosystemConstellationProps {\n  satelliteCount?: number;\n  centerLabel?: string;\n  accentColor?: string;\n  speed?: number;\n  fps?: number;\n  durationInFrames?: number;\n  width?: number;\n  height?: number;\n  className?: string;\n}\n\nexport const EcosystemConstellation = ({\n  satelliteCount = 6,\n  centerLabel = \"V\",\n  accentColor = \"#a855f7\",\n  speed = 1,\n  fps = 30,\n  durationInFrames = 240,\n  width = 1280,\n  height = 720,\n  className,\n}: EcosystemConstellationProps) => {\n  const safeSpeed = Math.max(0.01, speed);\n  const durationMs = ((durationInFrames / fps) * 1000) / safeSpeed;\n  const frameMs = 1000 / fps;\n\n  const count = Math.max(\n    3,\n    Math.min(SATELLITE_BRANDS.length, Math.floor(satelliteCount))\n  );\n\n  const cx = width / 2;\n  const cy = height / 2;\n  const baseRadiusX = 230;\n  const baseRadiusY = 180;\n\n  // Generate positions for satellites in an elliptical orbit\n  const satellites = Array.from({ length: count }).map((_, i) => {\n    const angle = (i / count) * Math.PI * 2;\n    const orbitOffset = i * 22;\n    const rX = baseRadiusX + orbitOffset;\n    const rY = baseRadiusY + orbitOffset * 0.7;\n    const x = cx + Math.cos(angle) * rX;\n    const y = cy + Math.sin(angle) * rY;\n    const brand = SATELLITE_BRANDS[i % SATELLITE_BRANDS.length];\n    return {\n      Logo: brand.Logo,\n      color: brand.bg,\n      index: i,\n      x,\n      y,\n    };\n  });\n\n  const containerStyle: CSSProperties = {\n    background: \"radial-gradient(ellipse at center, #14101e 0%, #05030a 75%)\",\n    fontFamily: FONT_FAMILY,\n    height,\n    overflow: \"hidden\",\n    position: \"relative\",\n    width,\n  };\n\n  return (\n    <Timegroup\n      className={className}\n      duration={`${durationMs}ms`}\n      mode=\"fixed\"\n      style={containerStyle}\n    >\n      <>\n        <style>{`\n          @keyframes framecn-eco-pulse {\n            0%, 100% { transform: scale(1); opacity: 0.12; }\n            50% { transform: scale(1.06); opacity: 0.18; }\n          }\n          @keyframes framecn-eco-center {\n            0%, 100% { transform: scale(1); }\n            50% { transform: scale(1.06); }\n          }\n          @keyframes framecn-eco-sat-fade {\n            from { opacity: 0; transform: scale(0.8); }\n            to { opacity: 1; transform: scale(1); }\n          }\n          @keyframes framecn-eco-line {\n            from { opacity: 0; }\n            to { opacity: 0.15; }\n          }\n        `}</style>\n        <svg\n          width=\"100%\"\n          height=\"100%\"\n          viewBox={`0 0 ${width} ${height}`}\n          style={{ inset: 0, position: \"absolute\" }}\n        >\n          {/* Connection lines */}\n          {satellites.map((s, i) => (\n            <line\n              key={`line-${i}`}\n              x1={cx}\n              y1={cy}\n              x2={s.x}\n              y2={s.y}\n              stroke={accentColor}\n              strokeWidth={2}\n              strokeLinecap=\"round\"\n              style={{\n                animation: `framecn-eco-line ${frameMs * 20}ms ease-out ${i * frameMs * 4}ms backwards`,\n              }}\n            />\n          ))}\n\n          {/* Center glow */}\n          <circle\n            cx={cx}\n            cy={cy}\n            r={70}\n            fill={accentColor}\n            style={{\n              animation: `framecn-eco-pulse 3000ms ease-in-out infinite`,\n            }}\n          />\n          <circle cx={cx} cy={cy} r={50} fill={accentColor} opacity={0.2} />\n        </svg>\n\n        {/* Center logo */}\n        <div\n          style={{\n            alignItems: \"center\",\n            animation: `framecn-eco-center 3000ms ease-in-out infinite`,\n            background: `linear-gradient(180deg, ${accentColor} 0%, ${accentColor}cc 100%)`,\n            border: \"1px solid rgba(255,255,255,0.15)\",\n            borderRadius: 24,\n            boxShadow: `0 0 60px ${accentColor}66, inset 0 1px 0 rgba(255,255,255,0.3)`,\n            color: \"white\",\n            display: \"flex\",\n            fontSize: 52,\n            fontWeight: 800,\n            height: 96,\n            justifyContent: \"center\",\n            left: cx,\n            letterSpacing: \"-0.05em\",\n            marginLeft: -48,\n            marginTop: -48,\n            position: \"absolute\",\n            top: cy,\n            transform: `scale(1)`,\n            width: 96,\n          }}\n        >\n          {centerLabel}\n        </div>\n\n        {/* Satellites */}\n        {satellites.map((s, i) => {\n          const { Logo } = s;\n          return (\n            <div\n              key={`sat-${i}`}\n              style={{\n                alignItems: \"center\",\n                animation: `framecn-eco-sat-fade ${frameMs * 20}ms cubic-bezier(0.16, 1, 0.3, 1) ${i * frameMs * 4}ms backwards`,\n                background: `linear-gradient(180deg, ${s.color} 0%, ${s.color}dd 100%)`,\n                border: \"1px solid rgba(255,255,255,0.12)\",\n                borderRadius: 14,\n                boxShadow: `0 8px 30px ${s.color}66, inset 0 1px 0 rgba(255,255,255,0.18)`,\n                display: \"flex\",\n                height: 56,\n                justifyContent: \"center\",\n                left: s.x,\n                marginLeft: -28,\n                marginTop: -28,\n                position: \"absolute\",\n                top: s.y,\n                transform: `scale(1)`,\n                width: 56,\n              }}\n            >\n              <Logo />\n            </div>\n          );\n        })}\n      </>\n    </Timegroup>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/framecn/ecosystem-constellation.tsx"
    }
  ],
  "type": "registry:component"
}