|
| 1 | +/** |
| 2 | + * Two-surface architecture: |
| 3 | + * - Control plane: Unix socket (0600) ← App, agents |
| 4 | + * - Data plane: GET-only HTTP blob store on 127.0.0.1:<ephemeral> → iframes |
| 5 | + * Both bind locally only; nothing is reachable off-host. |
| 6 | + */ |
| 7 | +export function SocketDiagram() { |
| 8 | + return ( |
| 9 | + <div className="not-prose my-12 flex justify-center"> |
| 10 | + <svg |
| 11 | + width="720" |
| 12 | + height="340" |
| 13 | + viewBox="0 0 720 340" |
| 14 | + fill="none" |
| 15 | + className="w-full max-w-[720px]" |
| 16 | + > |
| 17 | + <title> |
| 18 | + runtimed exposes two local-only surfaces: a Unix socket for control |
| 19 | + and a GET-only HTTP blob store for binary output data |
| 20 | + </title> |
| 21 | + <style>{` |
| 22 | + .sd-label { fill: #e5e5e5; font-family: 'Space Grotesk', system-ui, sans-serif; font-size: 13px; font-weight: 600; } |
| 23 | + .sd-sub { fill: #ababab; font-family: 'JetBrains Mono', monospace; font-size: 9px; letter-spacing: 0.15em; text-transform: uppercase; } |
| 24 | + .sd-mono { fill: #ababab; font-family: 'JetBrains Mono', monospace; font-size: 10px; } |
| 25 | + .sd-purple { fill: #a993d1; font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: 0.05em; } |
| 26 | + .sd-teal { fill: #7dd3c4; font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: 0.05em; } |
| 27 | + .sd-check { fill: #86efac; font-family: 'JetBrains Mono', monospace; font-size: 10px; } |
| 28 | + .sd-circle { fill: none; stroke: #a993d1; stroke-width: 2; } |
| 29 | + .sd-circle-fill { fill: #a993d1; opacity: 0.1; } |
| 30 | + .sd-iframe { fill: none; stroke: #7dd3c4; stroke-width: 2; } |
| 31 | + .sd-iframe-fill { fill: #7dd3c4; opacity: 0.08; } |
| 32 | + .sd-ctrl-line { stroke: #a993d1; stroke-width: 1.5; stroke-dasharray: 4 4; opacity: 0.55; } |
| 33 | + .sd-data-line { stroke: #7dd3c4; stroke-width: 1.5; opacity: 0.55; } |
| 34 | + .sd-hex { fill: #0e0e0e; stroke: #a993d1; stroke-width: 2; } |
| 35 | + .sd-hex-fill { fill: #a993d1; opacity: 0.15; } |
| 36 | + .sd-divider { stroke: #484848; stroke-width: 1; stroke-dasharray: 2 4; opacity: 0.5; } |
| 37 | + @keyframes sd-pulse { 0%, 100% { opacity: 0.25; } 50% { opacity: 0.8; } } |
| 38 | + .sd-pulse { animation: sd-pulse 2.5s ease-in-out infinite; } |
| 39 | + `}</style> |
| 40 | + |
| 41 | + {/* ── Daemon (center hexagon) ── */} |
| 42 | + <g transform="translate(360, 150)"> |
| 43 | + <polygon points="0,-44 38,-22 38,22 0,44 -38,22 -38,-22" className="sd-hex-fill" /> |
| 44 | + <polygon points="0,-44 38,-22 38,22 0,44 -38,22 -38,-22" className="sd-hex" /> |
| 45 | + <text y="-2" textAnchor="middle" className="sd-label" style={{ fontSize: "11px" }}>runtimed</text> |
| 46 | + <text y="14" textAnchor="middle" className="sd-sub">daemon</text> |
| 47 | + </g> |
| 48 | + |
| 49 | + {/* ── Control-plane lines (left) ── */} |
| 50 | + <line x1="130" y1="80" x2="322" y2="128" className="sd-ctrl-line" /> |
| 51 | + <line x1="130" y1="220" x2="322" y2="172" className="sd-ctrl-line" /> |
| 52 | + |
| 53 | + {/* Pulse dots */} |
| 54 | + <circle r="2.5" fill="#a993d1" className="sd-pulse"> |
| 55 | + <animateMotion dur="2.2s" repeatCount="indefinite" path="M 130 80 L 322 128" /> |
| 56 | + </circle> |
| 57 | + <circle r="2.5" fill="#a993d1" className="sd-pulse" style={{ animationDelay: "0.9s" }}> |
| 58 | + <animateMotion dur="2.6s" repeatCount="indefinite" path="M 130 220 L 322 172" /> |
| 59 | + </circle> |
| 60 | + |
| 61 | + <text x="220" y="116" textAnchor="middle" className="sd-sub" transform="rotate(-12, 220, 116)">unix socket</text> |
| 62 | + |
| 63 | + {/* ── App (upper left) ── */} |
| 64 | + <g transform="translate(100, 75)"> |
| 65 | + <circle r="30" className="sd-circle-fill" /> |
| 66 | + <circle r="30" className="sd-circle" /> |
| 67 | + <rect x="-12" y="-9" width="24" height="16" rx="2" stroke="#a993d1" strokeWidth="1.5" fill="none" /> |
| 68 | + <line x1="-12" y1="-2" x2="12" y2="-2" stroke="#a993d1" strokeWidth="1" /> |
| 69 | + <circle cx="-8" cy="-6" r="1" fill="#a993d1" /> |
| 70 | + <text y="-42" textAnchor="middle" className="sd-label">nteract App</text> |
| 71 | + </g> |
| 72 | + |
| 73 | + {/* ── Agents (lower left) ── */} |
| 74 | + <g transform="translate(100, 220)"> |
| 75 | + <circle r="30" className="sd-circle-fill" /> |
| 76 | + <circle r="30" className="sd-circle" /> |
| 77 | + <rect x="-8" y="-10" width="16" height="12" rx="2" stroke="#a993d1" strokeWidth="1.5" fill="none" /> |
| 78 | + <circle cx="-3" cy="-4" r="1.4" fill="#a993d1" /> |
| 79 | + <circle cx="3" cy="-4" r="1.4" fill="#a993d1" /> |
| 80 | + <path d="M -4 8 L 4 8" stroke="#a993d1" strokeWidth="1.5" /> |
| 81 | + <text y="48" textAnchor="middle" className="sd-label">MCP agents</text> |
| 82 | + <text y="62" textAnchor="middle" className="sd-sub">claude · codex · warp</text> |
| 83 | + </g> |
| 84 | + |
| 85 | + {/* ── Data-plane line (right) ── */} |
| 86 | + <line x1="400" y1="150" x2="560" y2="150" className="sd-data-line" /> |
| 87 | + <circle r="2.5" fill="#7dd3c4" className="sd-pulse" style={{ animationDelay: "0.3s" }}> |
| 88 | + <animateMotion dur="2.4s" repeatCount="indefinite" path="M 400 150 L 560 150" /> |
| 89 | + </circle> |
| 90 | + <text x="480" y="142" textAnchor="middle" className="sd-sub" style={{ letterSpacing: "0.1em" }}>http get</text> |
| 91 | + |
| 92 | + {/* ── Iframe (right) ── */} |
| 93 | + <g transform="translate(605, 150)"> |
| 94 | + <rect x="-45" y="-34" width="90" height="68" rx="3" className="sd-iframe-fill" /> |
| 95 | + <rect x="-45" y="-34" width="90" height="68" rx="3" className="sd-iframe" /> |
| 96 | + <line x1="-45" y1="-22" x2="45" y2="-22" stroke="#7dd3c4" strokeWidth="1" opacity="0.5" /> |
| 97 | + <circle cx="-38" cy="-28" r="1.5" fill="#7dd3c4" opacity="0.8" /> |
| 98 | + <circle cx="-32" cy="-28" r="1.5" fill="#7dd3c4" opacity="0.8" /> |
| 99 | + <circle cx="-26" cy="-28" r="1.5" fill="#7dd3c4" opacity="0.8" /> |
| 100 | + {/* output glyph */} |
| 101 | + <path d="M -20 0 L -8 -12 L 6 4 L 20 -10" stroke="#7dd3c4" strokeWidth="1.5" fill="none" opacity="0.7" /> |
| 102 | + <circle cx="-20" cy="0" r="2" fill="#7dd3c4" /> |
| 103 | + <circle cx="-8" cy="-12" r="2" fill="#7dd3c4" /> |
| 104 | + <circle cx="6" cy="4" r="2" fill="#7dd3c4" /> |
| 105 | + <circle cx="20" cy="-10" r="2" fill="#7dd3c4" /> |
| 106 | + <text y="-52" textAnchor="middle" className="sd-label">Output iframes</text> |
| 107 | + <text y="52" textAnchor="middle" className="sd-sub">blob: origin</text> |
| 108 | + </g> |
| 109 | + |
| 110 | + {/* ── Legend divider ── */} |
| 111 | + <line x1="30" y1="272" x2="690" y2="272" className="sd-divider" /> |
| 112 | + |
| 113 | + {/* ── Legend: Control plane ── */} |
| 114 | + <g transform="translate(60, 296)"> |
| 115 | + <rect x="0" y="-8" width="12" height="4" fill="#a993d1" opacity="0.55" /> |
| 116 | + <rect x="16" y="-8" width="4" height="4" fill="#a993d1" opacity="0.55" /> |
| 117 | + <rect x="24" y="-8" width="4" height="4" fill="#a993d1" opacity="0.55" /> |
| 118 | + <text x="40" y="-3" className="sd-purple">CONTROL</text> |
| 119 | + <text x="40" y="14" className="sd-mono">unix socket · chmod 0600 · owner-only</text> |
| 120 | + </g> |
| 121 | + |
| 122 | + {/* ── Legend: Data plane ── */} |
| 123 | + <g transform="translate(400, 296)"> |
| 124 | + <rect x="0" y="-8" width="28" height="4" fill="#7dd3c4" opacity="0.55" /> |
| 125 | + <text x="40" y="-3" className="sd-teal">DATA</text> |
| 126 | + <text x="40" y="14" className="sd-mono">127.0.0.1:<random> · GET /blob/{sha256}</text> |
| 127 | + </g> |
| 128 | + </svg> |
| 129 | + </div> |
| 130 | + ); |
| 131 | +} |
0 commit comments