// Upstream peering map for gohegan.net — the real topology. // // AS198657 gohegan.net // ├─ AS212895 ROUTE64 ── AS215638 Cilix ── { THG → Zayo, RETN → {Sparkle, Telxius, Lumen}, Arelion } // │ └── AS52025 PARADOX ── { ZET.NET → Orange, Eranium → {Cogent, Lumen}, TATA } // ├─ AS207841 Inferno ── AS61049 Exascale ── { GTT, NTT, Hurricane, PCCW, DTAG, AT&T } // ├─ AS11967 Hop179 // └─ AS209735 Lagrange ── { Hurricane, Liberty } // // Packets pulse from origin out through the chain along the actual paths. const VB_W = 216; const VB_H = 112; const BOX_W = 18; const BOX_H = 6.2; const T1_BOX_W = 17; const T1_BOX_H = 5.6; const NODES = { // Origin "gohegan.net": { x: 11, y: 58, asn: "198657", name: "gohegan.net", primary: true, }, // Direct transits (gohegan.net's upstreams) route64: { x: 58, y: 18, asn: "212895", name: "ROUTE64" }, inferno: { x: 58, y: 46, asn: "207841", name: "Inferno" }, hop179: { x: 58, y: 72, asn: "11967", name: "Hop179" }, lagrange: { x: 58, y: 98, asn: "209735", name: "Lagrange" }, // Mid (upstream of upstream) cilix: { x: 108, y: 13, asn: "215638", name: "Cilix" }, paradox: { x: 108, y: 33, asn: "52025", name: "PARADOX" }, exascale: { x: 108, y: 83, asn: "61049", name: "Exascale" }, // Sub (upstream feeders into Tier 1) thg: { x: 156, y: 6, asn: "13213", name: "THG" }, retn: { x: 156, y: 19, asn: "9002", name: "RETN" }, zetnet: { x: 156, y: 33, asn: "6204", name: "ZET.NET" }, eranium: { x: 156, y: 46, asn: "35133", name: "Eranium" }, // Tier 1 ISPs — vertical stack at col 4 zayo: { x: 200, y: 6, asn: "6461", name: "Zayo", tier1: true }, sparkle: { x: 200, y: 13, asn: "6762", name: "Sparkle", tier1: true }, arelion: { x: 200, y: 20, asn: "1299", name: "Arelion", tier1: true }, telxius: { x: 200, y: 27, asn: "12956", name: "Telxius", tier1: true }, lumen: { x: 200, y: 34, asn: "3356", name: "Lumen", tier1: true }, orange: { x: 200, y: 41, asn: "5511", name: "Orange", tier1: true }, tata: { x: 200, y: 48, asn: "6453", name: "TATA", tier1: true }, cogent: { x: 200, y: 55, asn: "174", name: "Cogent", tier1: true }, gtt: { x: 200, y: 64, asn: "3257", name: "GTT", tier1: true }, ntt: { x: 200, y: 71, asn: "2914", name: "NTT", tier1: true }, hurricane: { x: 200, y: 78, asn: "6939", name: "Hurricane", tier1: true }, pccw: { x: 200, y: 85, asn: "3491", name: "PCCW", tier1: true }, dtag: { x: 200, y: 92, asn: "3320", name: "DTAG", tier1: true }, att: { x: 200, y: 99, asn: "7018", name: "AT&T", tier1: true }, liberty: { x: 200, y: 106, asn: "6830", name: "Liberty", tier1: true }, }; const EDGES = [ ["gohegan.net", "route64"], ["gohegan.net", "inferno"], ["gohegan.net", "hop179"], ["gohegan.net", "lagrange"], ["route64", "cilix"], ["route64", "paradox"], ["inferno", "exascale"], ["lagrange", "hurricane"], ["lagrange", "liberty"], ["cilix", "thg"], ["cilix", "retn"], ["cilix", "arelion"], ["paradox", "zetnet"], ["paradox", "eranium"], ["paradox", "tata"], ["exascale", "gtt"], ["exascale", "ntt"], ["exascale", "hurricane"], ["exascale", "pccw"], ["exascale", "dtag"], ["exascale", "att"], ["thg", "zayo"], ["retn", "sparkle"], ["retn", "telxius"], ["retn", "lumen"], ["zetnet", "orange"], ["eranium", "cogent"], ["eranium", "lumen"], ]; // Full origin-to-tier-1 routes for packet animation. const PATHS = [ ["gohegan.net", "route64", "cilix", "thg", "zayo"], ["gohegan.net", "route64", "cilix", "retn", "sparkle"], ["gohegan.net", "route64", "cilix", "retn", "telxius"], ["gohegan.net", "route64", "cilix", "retn", "lumen"], ["gohegan.net", "route64", "cilix", "arelion"], ["gohegan.net", "route64", "paradox", "zetnet", "orange"], ["gohegan.net", "route64", "paradox", "eranium", "cogent"], ["gohegan.net", "route64", "paradox", "eranium", "lumen"], ["gohegan.net", "route64", "paradox", "tata"], ["gohegan.net", "inferno", "exascale", "gtt"], ["gohegan.net", "inferno", "exascale", "ntt"], ["gohegan.net", "inferno", "exascale", "hurricane"], ["gohegan.net", "inferno", "exascale", "pccw"], ["gohegan.net", "inferno", "exascale", "dtag"], ["gohegan.net", "inferno", "exascale", "att"], ["gohegan.net", "hop179"], ["gohegan.net", "lagrange", "hurricane"], ["gohegan.net", "lagrange", "liberty"], ]; // Edge endpoints: clip to the box edges (not the centers) so lines look right. const edgeEndpoints = (a, b) => { const A = NODES[a], B = NODES[b]; const aw = A.tier1 ? T1_BOX_W : BOX_W; const bw = B.tier1 ? T1_BOX_W : BOX_W; return { x1: A.x + aw / 2, y1: A.y, x2: B.x - bw / 2, y2: B.y, }; }; // Polyline length for a path. const pathPolyline = (path) => { const pts = []; for (let i = 0; i < path.length - 1; i++) { const e = edgeEndpoints(path[i], path[i + 1]); if (i === 0) pts.push({ x: e.x1, y: e.y1 }); pts.push({ x: e.x2, y: e.y2 }); } let total = 0; const segs = []; for (let i = 0; i < pts.length - 1; i++) { const dx = pts[i + 1].x - pts[i].x; const dy = pts[i + 1].y - pts[i].y; const len = Math.hypot(dx, dy); segs.push({ from: pts[i], to: pts[i + 1], len }); total += len; } return { pts, segs, total }; }; const PATH_GEOMETRY = PATHS.map(pathPolyline); const positionAtT = (geom, t) => { const target = t * geom.total; let acc = 0; for (const s of geom.segs) { if (acc + s.len >= target) { const u = (target - acc) / s.len; return { x: s.from.x + (s.to.x - s.from.x) * u, y: s.from.y + (s.to.y - s.from.y) * u, }; } acc += s.len; } const last = geom.segs[geom.segs.length - 1]; return { x: last.to.x, y: last.to.y }; }; const NetworkGraph = ({ animate = true }) => { const [packets, setPackets] = React.useState(() => // Pre-seed with packets at varied progress so the initial frame looks alive. Array.from({ length: 8 }, () => ({ id: Math.random().toString(36).slice(2), pathIdx: Math.floor(Math.random() * PATHS.length), t: Math.random() * 0.95, duration: 2.4 + Math.random() * 1.6, tone: Math.random() < 0.22 ? 'accent' : 'fg', })) ); const lastSpawnRef = React.useRef(0.4); const rafRef = React.useRef(0); React.useEffect(() => { if (!animate) return; let last = performance.now(); const step = (now) => { const dt = Math.min(0.06, (now - last) / 1000); last = now; lastSpawnRef.current -= dt; setPackets(prev => { let next = prev .map(p => ({ ...p, t: p.t + dt / p.duration })) .filter(p => p.t < 1); while (lastSpawnRef.current <= 0) { lastSpawnRef.current += 0.18 + Math.random() * 0.32; if (next.length >= 18) break; next.push({ id: Math.random().toString(36).slice(2), pathIdx: Math.floor(Math.random() * PATHS.length), t: 0, duration: 2.4 + Math.random() * 1.6, tone: Math.random() < 0.22 ? 'accent' : 'fg', }); } return next; }); rafRef.current = requestAnimationFrame(step); }; rafRef.current = requestAnimationFrame(step); return () => cancelAnimationFrame(rafRef.current); }, [animate]); return ( {/* Tier 1 zone backdrop */} tier 1 · 15 {/* Column labels */} {[ { x: NODES["gohegan.net"].x, label: "origin" }, { x: NODES["route64"].x, label: "transit" }, { x: NODES["cilix"].x, label: "upstream" }, { x: NODES["thg"].x, label: "upstream" }, ].map((c) => ( {c.label} ))} {/* Edges */} {EDGES.map(([a, b], i) => { const e = edgeEndpoints(a, b); return ( ); })} {/* Packets */} {packets.map((p) => { const geom = PATH_GEOMETRY[p.pathIdx]; const pos = positionAtT(geom, p.t); const colour = p.tone === "accent" ? "var(--accent)" : "var(--fg-0)"; // Trail: position slightly behind on the path const tt = Math.max(0, p.t - 0.012); const trail = positionAtT(geom, tt); return ( ); })} {/* Nodes */} {Object.entries(NODES).map(([id, n]) => ( ))} ); }; const NodeBox = ({ node: n }) => { const w = n.tier1 ? T1_BOX_W : BOX_W; const h = n.tier1 ? T1_BOX_H : BOX_H; const fill = n.primary ? 'var(--accent)' : 'var(--bg-0)'; const stroke = n.primary ? 'var(--accent)' : (n.tier1 ? 'var(--accent)' : 'var(--fg-0)'); const asnColor = n.primary ? 'var(--accent-fg)' : 'var(--fg-0)'; const nameColor = n.primary ? 'rgba(255,255,255,0.78)' : (n.tier1 ? 'var(--fg-1)' : 'var(--fg-2)'); return ( AS{n.asn} {n.name} ); }; Object.assign(window, { NetworkGraph });