diff --git a/apps/web/src/app/docs/tutorials/bridge/page.tsx b/apps/web/src/app/docs/tutorials/bridge/page.tsx index 4bc858f..6b35473 100644 --- a/apps/web/src/app/docs/tutorials/bridge/page.tsx +++ b/apps/web/src/app/docs/tutorials/bridge/page.tsx @@ -6,6 +6,7 @@ import Link from 'next/link'; import { useState } from 'react'; import { AppFooter } from '~/components/AppFooter'; import { AppHeader } from '~/components/AppHeader'; +import { BridgeArchitectureDiagram } from '~/components/docs/BridgeArchitectureDiagram'; interface Slide { id: string; @@ -129,32 +130,7 @@ const slides: Slide[] = [
-
-              {`┌─────────────────────────────────────────────────────────────┐
-│                     Your Machine                             │
-│                                                              │
-│  ┌─────────────┐     ┌─────────────────────────────────┐    │
-│  │ Chrome MCP  │────▶│                                 │    │
-│  │   Server    │     │      @tpmjs/bridge CLI          │    │
-│  └─────────────┘     │                                 │    │
-│  ┌─────────────┐     │  • Connects to MCP servers      │    │
-│  │ Filesystem  │────▶│  • Registers tools with TPMJS   │    │
-│  │   Server    │     │  • Polls for tool calls         │    │
-│  └─────────────┘     │  • Returns results              │    │
-│  ┌─────────────┐     │                                 │    │
-│  │ Your Custom │────▶│                                 │    │
-│  │   Server    │     └──────────────┬──────────────────┘    │
-│  └─────────────┘                    │                        │
-└─────────────────────────────────────┼────────────────────────┘
-                                      │ HTTPS
-                                      ▼
-                            ┌─────────────────┐
-                            │   TPMJS Cloud   │
-                            │                 │
-                            │  Your AI uses   │
-                            │  bridge tools   │
-                            └─────────────────┘`}
-            
+
diff --git a/apps/web/src/components/docs/BridgeArchitectureDiagram.tsx b/apps/web/src/components/docs/BridgeArchitectureDiagram.tsx new file mode 100644 index 0000000..cf09e47 --- /dev/null +++ b/apps/web/src/components/docs/BridgeArchitectureDiagram.tsx @@ -0,0 +1,233 @@ +'use client'; + +import * as d3 from 'd3'; +import { useEffect, useRef } from 'react'; + +interface BridgeArchitectureDiagramProps { + className?: string; +} + +export function BridgeArchitectureDiagram({ className }: BridgeArchitectureDiagramProps) { + const svgRef = useRef(null); + + useEffect(() => { + if (!svgRef.current) return; + + const svg = d3.select(svgRef.current); + svg.selectAll('*').remove(); + + const width = 700; + const height = 500; + + svg.attr('viewBox', `0 0 ${width} ${height}`); + + // Colors + const colors = { + machineBox: '#1e293b', + machineStroke: '#475569', + serverBox: '#334155', + serverStroke: '#64748b', + bridgeBox: '#0f766e', + bridgeStroke: '#14b8a6', + cloudBox: '#1e40af', + cloudStroke: '#3b82f6', + text: '#e2e8f0', + textMuted: '#94a3b8', + arrow: '#64748b', + }; + + // User's Machine container + const machineGroup = svg.append('g'); + + // Machine box + machineGroup + .append('rect') + .attr('x', 20) + .attr('y', 20) + .attr('width', width - 40) + .attr('height', 280) + .attr('rx', 12) + .attr('fill', colors.machineBox) + .attr('stroke', colors.machineStroke) + .attr('stroke-width', 2); + + // Machine label + machineGroup + .append('text') + .attr('x', width / 2) + .attr('y', 50) + .attr('text-anchor', 'middle') + .attr('fill', colors.text) + .attr('font-size', '16px') + .attr('font-weight', '600') + .text('Your Machine'); + + // MCP Servers + const servers = [ + { name: 'Chrome MCP', y: 90 }, + { name: 'Filesystem', y: 160 }, + { name: 'Custom Server', y: 230 }, + ]; + + servers.forEach((server) => { + // Server box + machineGroup + .append('rect') + .attr('x', 50) + .attr('y', server.y) + .attr('width', 140) + .attr('height', 50) + .attr('rx', 8) + .attr('fill', colors.serverBox) + .attr('stroke', colors.serverStroke) + .attr('stroke-width', 1); + + // Server label + machineGroup + .append('text') + .attr('x', 120) + .attr('y', server.y + 30) + .attr('text-anchor', 'middle') + .attr('fill', colors.text) + .attr('font-size', '13px') + .text(server.name); + + // Arrow from server to bridge + machineGroup + .append('path') + .attr('d', `M 190 ${server.y + 25} L 270 ${server.y + 25}`) + .attr('stroke', colors.arrow) + .attr('stroke-width', 2) + .attr('fill', 'none') + .attr('marker-end', 'url(#arrowhead)'); + }); + + // Bridge CLI box + machineGroup + .append('rect') + .attr('x', 280) + .attr('y', 80) + .attr('width', 360) + .attr('height', 210) + .attr('rx', 10) + .attr('fill', colors.bridgeBox) + .attr('stroke', colors.bridgeStroke) + .attr('stroke-width', 2); + + // Bridge label + machineGroup + .append('text') + .attr('x', 460) + .attr('y', 115) + .attr('text-anchor', 'middle') + .attr('fill', colors.text) + .attr('font-size', '15px') + .attr('font-weight', '600') + .text('@tpmjs/bridge CLI'); + + // Bridge features + const features = [ + 'Connects to MCP servers', + 'Registers tools with TPMJS', + 'Polls for tool calls', + 'Returns results', + ]; + + features.forEach((feature, i) => { + machineGroup + .append('text') + .attr('x', 320) + .attr('y', 155 + i * 28) + .attr('fill', colors.textMuted) + .attr('font-size', '13px') + .text(`• ${feature}`); + }); + + // Arrow marker definition + svg + .append('defs') + .append('marker') + .attr('id', 'arrowhead') + .attr('viewBox', '0 0 10 10') + .attr('refX', 8) + .attr('refY', 5) + .attr('markerWidth', 6) + .attr('markerHeight', 6) + .attr('orient', 'auto') + .append('path') + .attr('d', 'M 0 0 L 10 5 L 0 10 z') + .attr('fill', colors.arrow); + + // HTTPS Arrow from machine to cloud + svg + .append('path') + .attr('d', `M ${width / 2} 300 L ${width / 2} 340`) + .attr('stroke', colors.arrow) + .attr('stroke-width', 3) + .attr('fill', 'none') + .attr('marker-end', 'url(#arrowhead)'); + + // HTTPS label + svg + .append('text') + .attr('x', width / 2 + 15) + .attr('y', 328) + .attr('fill', colors.textMuted) + .attr('font-size', '12px') + .text('HTTPS'); + + // TPMJS Cloud box + const cloudGroup = svg.append('g'); + + cloudGroup + .append('rect') + .attr('x', width / 2 - 140) + .attr('y', 350) + .attr('width', 280) + .attr('height', 120) + .attr('rx', 12) + .attr('fill', colors.cloudBox) + .attr('stroke', colors.cloudStroke) + .attr('stroke-width', 2); + + // Cloud label + cloudGroup + .append('text') + .attr('x', width / 2) + .attr('y', 385) + .attr('text-anchor', 'middle') + .attr('fill', colors.text) + .attr('font-size', '16px') + .attr('font-weight', '600') + .text('TPMJS Cloud'); + + // Cloud description + cloudGroup + .append('text') + .attr('x', width / 2) + .attr('y', 420) + .attr('text-anchor', 'middle') + .attr('fill', colors.textMuted) + .attr('font-size', '14px') + .text('Your AI uses'); + + cloudGroup + .append('text') + .attr('x', width / 2) + .attr('y', 445) + .attr('text-anchor', 'middle') + .attr('fill', colors.textMuted) + .attr('font-size', '14px') + .text('bridge tools'); + }, []); + + return ( +
+ +
+ ); +}