Skip to content

Commit ee78469

Browse files
a16iclaude
andcommitted
Simplify globe: just spinning Earth, no fake transaction arcs
Removed cities, arcs, slerp, spawner. Just continent outlines slowly rotating. Will hook up to real payment data later. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2f8a7dd commit ee78469

1 file changed

Lines changed: 3 additions & 112 deletions

File tree

web/src/components/Globe.tsx

Lines changed: 3 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,6 @@
1-
import { useRef, useEffect, useCallback } from "react";
1+
import { useRef, useEffect } from "react";
22
import { CONTINENTS } from "./worlddata";
33

4-
const CITIES: [number, number, string][] = [
5-
[40.71, -74.01, "New York"], [37.77, -122.42, "San Francisco"],
6-
[51.51, -0.13, "London"], [48.86, 2.35, "Paris"],
7-
[35.68, 139.69, "Tokyo"], [1.35, 103.82, "Singapore"],
8-
[-33.87, 151.21, "Sydney"], [55.76, 37.62, "Moscow"],
9-
[-23.55, -46.63, "Sao Paulo"], [19.43, -99.13, "Mexico City"],
10-
[28.61, 77.21, "Delhi"], [31.23, 121.47, "Shanghai"],
11-
[37.57, 126.98, "Seoul"], [52.52, 13.41, "Berlin"],
12-
[25.20, 55.27, "Dubai"], [22.32, 114.17, "Hong Kong"],
13-
[-1.29, 36.82, "Nairobi"], [6.52, 3.38, "Lagos"],
14-
[43.65, -79.38, "Toronto"], [34.05, -118.24, "Los Angeles"],
15-
];
16-
17-
type Arc = { from: [number, number]; to: [number, number]; birth: number; duration: number };
18-
194
function latLngToXYZ(lat: number, lng: number, r: number): [number, number, number] {
205
const phi = (90 - lat) * (Math.PI / 180);
216
const theta = (lng + 180) * (Math.PI / 180);
@@ -39,45 +24,17 @@ function transform(lat: number, lng: number, R: number, rY: number, rX: number):
3924
return [x, y, z];
4025
}
4126

42-
function slerp(lat1: number, lng1: number, lat2: number, lng2: number, t: number, alt: number): [number, number, number] {
43-
const p1 = latLngToXYZ(lat1, lng1, 1), p2 = latLngToXYZ(lat2, lng2, 1);
44-
const dot = p1[0] * p2[0] + p1[1] * p2[1] + p1[2] * p2[2];
45-
const omega = Math.acos(Math.max(-1, Math.min(1, dot)));
46-
let x: number, y: number, z: number;
47-
if (omega < 0.001) {
48-
x = p1[0] * (1 - t) + p2[0] * t; y = p1[1] * (1 - t) + p2[1] * t; z = p1[2] * (1 - t) + p2[2] * t;
49-
} else {
50-
const sinO = Math.sin(omega), a = Math.sin((1 - t) * omega) / sinO, b = Math.sin(t * omega) / sinO;
51-
x = a * p1[0] + b * p2[0]; y = a * p1[1] + b * p2[1]; z = a * p1[2] + b * p2[2];
52-
}
53-
const len = Math.sqrt(x * x + y * y + z * z);
54-
const lift = 1 + alt * Math.sin(t * Math.PI);
55-
return [(x / len) * lift, (y / len) * lift, (z / len) * lift];
56-
}
57-
5827
export function Globe() {
5928
const canvasRef = useRef<HTMLCanvasElement>(null);
60-
const arcsRef = useRef<Arc[]>([]);
6129
const rotRef = useRef(0);
6230
const frameRef = useRef(0);
6331

64-
const spawnArc = useCallback(() => {
65-
const from = CITIES[Math.floor(Math.random() * CITIES.length)];
66-
let to = from;
67-
while (to === from) to = CITIES[Math.floor(Math.random() * CITIES.length)];
68-
arcsRef.current.push({ from: [from[0], from[1]], to: [to[0], to[1]], birth: Date.now(), duration: 1800 + Math.random() * 1200 });
69-
if (arcsRef.current.length > 20) arcsRef.current.shift();
70-
}, []);
71-
7232
useEffect(() => {
7333
const canvas = canvasRef.current;
7434
if (!canvas) return;
7535
const ctx = canvas.getContext("2d")!;
7636
let running = true;
7737

78-
const spawner = setInterval(() => { spawnArc(); if (Math.random() < 0.4) spawnArc(); }, 600);
79-
for (let i = 0; i < 5; i++) spawnArc();
80-
8138
function resize() {
8239
const rect = canvas!.getBoundingClientRect();
8340
const dpr = window.devicePixelRatio || 1;
@@ -94,7 +51,6 @@ export function Globe() {
9451
const w = rect.width, h = rect.height;
9552
const cx = w / 2, cy = h / 2;
9653
const R = Math.min(w, h) * 0.40;
97-
const now = Date.now();
9854
const rY = rotRef.current, rX = -0.35;
9955

10056
ctx.clearRect(0, 0, w, h);
@@ -122,86 +78,21 @@ export function Globe() {
12278
ctx.strokeStyle = "#2a2a2a";
12379
ctx.lineWidth = 1;
12480
ctx.stroke();
125-
// Subtle fill
12681
ctx.fillStyle = "rgba(255,255,255,0.02)";
12782
ctx.fill();
12883
}
12984

130-
// City dots
131-
for (const [lat, lng] of CITIES) {
132-
const [x, y, z] = transform(lat, lng, R, rY, rX);
133-
if (z < 0) continue;
134-
ctx.beginPath();
135-
ctx.arc(cx + x, cy - y, 2, 0, Math.PI * 2);
136-
ctx.fillStyle = "#555";
137-
ctx.fill();
138-
}
139-
140-
// Arcs
141-
const alive: Arc[] = [];
142-
for (const arc of arcsRef.current) {
143-
const elapsed = now - arc.birth;
144-
if (elapsed > arc.duration + 600) continue;
145-
alive.push(arc);
146-
147-
const progress = Math.min(elapsed / arc.duration, 1);
148-
const fade = elapsed > arc.duration ? 1 - (elapsed - arc.duration) / 600 : 1;
149-
const steps = 40;
150-
const headT = progress, tailT = Math.max(0, progress - 0.35);
151-
152-
// Trail
153-
ctx.beginPath();
154-
let started = false;
155-
for (let i = 0; i <= steps; i++) {
156-
const t = tailT + (headT - tailT) * (i / steps);
157-
const [sx, sy, sz] = slerp(arc.from[0], arc.from[1], arc.to[0], arc.to[1], t, 0.15);
158-
let [x, y, z] = [sx * R, sy * R, sz * R];
159-
[x, y, z] = rotateY(x, y, z, rY);
160-
[x, y, z] = rotateX(x, y, z, rX);
161-
if (z < 0) { started = false; continue; }
162-
if (!started) { ctx.moveTo(cx + x, cy - y); started = true; }
163-
else ctx.lineTo(cx + x, cy - y);
164-
}
165-
ctx.strokeStyle = `rgba(200,200,200,${fade * 0.7})`;
166-
ctx.lineWidth = 1.5;
167-
ctx.stroke();
168-
169-
// Head
170-
const [hx, hy, hz] = slerp(arc.from[0], arc.from[1], arc.to[0], arc.to[1], headT, 0.15);
171-
let [rx2, ry2, rz2] = [hx * R, hy * R, hz * R];
172-
[rx2, ry2, rz2] = rotateY(rx2, ry2, rz2, rY);
173-
[rx2, ry2, rz2] = rotateX(rx2, ry2, rz2, rX);
174-
if (rz2 >= 0 && progress < 1) {
175-
const px = cx + rx2, py = cy - ry2;
176-
ctx.beginPath(); ctx.arc(px, py, 3, 0, Math.PI * 2);
177-
ctx.fillStyle = `rgba(255,255,255,${fade * 0.9})`; ctx.fill();
178-
ctx.beginPath(); ctx.arc(px, py, 7, 0, Math.PI * 2);
179-
ctx.fillStyle = `rgba(255,255,255,${fade * 0.12})`; ctx.fill();
180-
}
181-
182-
// Arrival flash
183-
if (progress >= 1 && fade > 0.3) {
184-
const [dx, dy, dz] = transform(arc.to[0], arc.to[1], R, rY, rX);
185-
if (dz >= 0) {
186-
ctx.beginPath(); ctx.arc(cx + dx, cy - dy, 8, 0, Math.PI * 2);
187-
ctx.fillStyle = `rgba(255,255,255,${fade * 0.3})`; ctx.fill();
188-
}
189-
}
190-
}
191-
arcsRef.current = alive;
192-
19385
rotRef.current += 0.0015;
19486
frameRef.current = requestAnimationFrame(draw);
19587
}
19688

19789
frameRef.current = requestAnimationFrame(draw);
198-
return () => { running = false; cancelAnimationFrame(frameRef.current); clearInterval(spawner); window.removeEventListener("resize", resize); };
199-
}, [spawnArc]);
90+
return () => { running = false; cancelAnimationFrame(frameRef.current); window.removeEventListener("resize", resize); };
91+
}, []);
20092

20193
return (
20294
<div className="globe-wrap">
20395
<canvas ref={canvasRef} className="globe-canvas" />
204-
<div className="globe-label">Live Transaction Routing</div>
20596
</div>
20697
);
20798
}

0 commit comments

Comments
 (0)