{
  "$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/remocn/ecosystem-constellation/index.tsx",
      "content": "\"use client\";\n\nimport type { ComponentType } from \"react\";\nimport { interpolate, spring, useCurrentFrame, useVideoConfig } from \"remotion\";\n\nexport interface EcosystemConstellationProps {\n  satelliteCount?: number;\n  centerLabel?: string;\n  accentColor?: string;\n  speed?: number;\n  className?: string;\n}\n\nconst FONT_FAMILY =\n  \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\";\n\n// Inline brand mark components — stylized for demo identification, drawn from\n// primitive SVG shapes only so the component stays self-contained.\n\nfunction GitHubMark() {\n  return (\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}\n\nfunction VercelMark() {\n  return (\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}\n\nfunction StripeMark() {\n  return (\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}\n\nfunction SlackMark() {\n  return (\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}\n\nfunction LinearMark() {\n  return (\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 M5 5 L19 19 M9 5 L19 15 M13 5 L19 11\"\n        stroke=\"#0a0a0a\"\n        strokeWidth=\"0.9\"\n        strokeLinecap=\"round\"\n        opacity=\"0.85\"\n      />\n    </svg>\n  );\n}\n\nfunction FigmaMark() {\n  return (\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}\n\nfunction NotionMark() {\n  return (\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}\n\nfunction DiscordMark() {\n  return (\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}\n\ninterface SatelliteBrand {\n  Logo: 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 function EcosystemConstellation({\n  satelliteCount = 6,\n  centerLabel = \"V\",\n  accentColor = \"#a855f7\",\n  speed = 1,\n  className,\n}: EcosystemConstellationProps) {\n  const frame = useCurrentFrame() * speed;\n  const { fps } = useVideoConfig();\n\n  const count = Math.max(\n    3,\n    Math.min(SATELLITE_BRANDS.length, Math.floor(satelliteCount)),\n  );\n\n  // Center pulse (0..1)\n  const pulse = (Math.sin(frame / 12) + 1) / 2;\n  const centerScale = 1 + pulse * 0.06;\n\n  // Geometry\n  const cx = 640;\n  const cy = 360;\n  const baseRadiusX = 230;\n  const baseRadiusY = 180;\n  const offscreenRadius = 1200; // 150% of width\n\n  // Per-satellite assembly spring (staggered)\n  const satellites = Array.from({ length: count }).map((_, i) => {\n    const stagger = i * 4;\n    const sp = spring({\n      frame: frame - stagger,\n      fps,\n      config: { mass: 1.1, damping: 16, stiffness: 70 },\n      durationInFrames: 50,\n    });\n    const radiusFactor = interpolate(sp, [0, 1], [offscreenRadius, 1]);\n\n    // Slight elliptical variation per satellite\n    const orbitOffset = i * 22;\n    const rX = baseRadiusX + orbitOffset;\n    const rY = baseRadiusY + orbitOffset * 0.7;\n    // Different angular speed per orbit (slower for outer)\n    const angularSpeed = 0.012 - i * 0.0008;\n    const baseAngle = (i / count) * Math.PI * 2;\n    const angle = baseAngle + frame * angularSpeed;\n\n    // Use radiusFactor as a multiplier on the orbit radius\n    const x = cx + Math.cos(angle) * rX * radiusFactor;\n    const y = cy + Math.sin(angle) * rY * radiusFactor;\n\n    // Data pulse: which satellite is currently \"firing\"\n    const activeIdx = Math.floor(frame / 30) % count;\n    const isActive = activeIdx === i;\n    // Within the active 30-frame window, fade the line in/out\n    const localFrame = frame - Math.floor(frame / 30) * 30;\n    const lineOpacity = isActive\n      ? interpolate(localFrame, [0, 8, 22, 30], [0.15, 0.9, 0.9, 0.15], {\n          extrapolateLeft: \"clamp\",\n          extrapolateRight: \"clamp\",\n        })\n      : 0.15;\n    const satScale = isActive\n      ? interpolate(localFrame, [0, 8, 22, 30], [1, 1.1, 1.1, 1], {\n          extrapolateLeft: \"clamp\",\n          extrapolateRight: \"clamp\",\n        })\n      : 1;\n\n    const brand = SATELLITE_BRANDS[i % SATELLITE_BRANDS.length];\n    return {\n      x,\n      y,\n      Logo: brand.Logo,\n      color: brand.bg,\n      lineOpacity,\n      satScale,\n      visible: sp > 0.02,\n    };\n  });\n\n  return (\n    <div\n      className={className}\n      style={{\n        position: \"absolute\",\n        inset: 0,\n        overflow: \"hidden\",\n        background: \"transparent\",\n        fontFamily: FONT_FAMILY,\n      }}\n    >\n      <svg\n        width=\"100%\"\n        height=\"100%\"\n        viewBox=\"0 0 1280 720\"\n        style={{ position: \"absolute\", inset: 0 }}\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            opacity={s.visible ? s.lineOpacity : 0}\n          />\n        ))}\n\n        {/* Center glow */}\n        <circle\n          cx={cx}\n          cy={cy}\n          r={70 + pulse * 8}\n          fill={accentColor}\n          opacity={0.12}\n        />\n        <circle\n          cx={cx}\n          cy={cy}\n          r={50 + pulse * 4}\n          fill={accentColor}\n          opacity={0.2}\n        />\n      </svg>\n\n      {/* Center logo */}\n      <div\n        style={{\n          position: \"absolute\",\n          left: cx,\n          top: cy,\n          width: 96,\n          height: 96,\n          marginLeft: -48,\n          marginTop: -48,\n          borderRadius: 24,\n          background: `linear-gradient(180deg, ${accentColor} 0%, ${accentColor}cc 100%)`,\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          color: \"white\",\n          fontWeight: 800,\n          fontSize: 52,\n          letterSpacing: \"-0.05em\",\n          transform: `scale(${centerScale})`,\n          boxShadow: `0 0 60px ${accentColor}66, inset 0 1px 0 rgba(255,255,255,0.3)`,\n          border: \"1px solid rgba(255,255,255,0.15)\",\n        }}\n      >\n        {centerLabel}\n      </div>\n\n      {/* Satellites */}\n      {satellites.map((s, i) => {\n        const Logo = s.Logo;\n        return (\n          <div\n            key={`sat-${i}`}\n            style={{\n              position: \"absolute\",\n              left: s.x,\n              top: s.y,\n              width: 56,\n              height: 56,\n              marginLeft: -28,\n              marginTop: -28,\n              borderRadius: 14,\n              background: `linear-gradient(180deg, ${s.color} 0%, ${s.color}dd 100%)`,\n              display: \"flex\",\n              alignItems: \"center\",\n              justifyContent: \"center\",\n              transform: `scale(${s.satScale})`,\n              boxShadow: `0 8px 30px ${s.color}66, inset 0 1px 0 rgba(255,255,255,0.18)`,\n              border: \"1px solid rgba(255,255,255,0.12)\",\n              opacity: s.visible ? 1 : 0,\n              willChange: \"transform\",\n            }}\n          >\n            <Logo />\n          </div>\n        );\n      })}\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/ecosystem-constellation.tsx"
    }
  ],
  "type": "registry:component"
}
