{ "$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 \n \n \n );\n}\n\nfunction VercelMark() {\n return (\n \n \n \n );\n}\n\nfunction StripeMark() {\n return (\n \n \n \n );\n}\n\nfunction SlackMark() {\n return (\n \n \n \n \n \n \n );\n}\n\nfunction LinearMark() {\n return (\n \n \n \n \n \n \n \n \n \n \n );\n}\n\nfunction FigmaMark() {\n return (\n \n \n \n \n \n \n \n );\n}\n\nfunction NotionMark() {\n return (\n \n \n \n \n );\n}\n\nfunction DiscordMark() {\n return (\n \n \n \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 \n \n {/* Connection lines */}\n {satellites.map((s, i) => (\n \n ))}\n\n {/* Center glow */}\n \n \n \n\n {/* Center logo */}\n \n {centerLabel}\n \n\n {/* Satellites */}\n {satellites.map((s, i) => {\n const Logo = s.Logo;\n return (\n \n \n \n );\n })}\n \n );\n}\n", "type": "registry:component", "target": "components/remocn/ecosystem-constellation.tsx" } ], "type": "registry:component" }