Skip to content

Commit cfba831

Browse files
Update Globe3D.tsx
1 parent f06e0cb commit cfba831

File tree

1 file changed

+81
-33
lines changed

1 file changed

+81
-33
lines changed

src/components/Globe3D.tsx

Lines changed: 81 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type Continent = 'North America' | 'South America' | 'Europe' | 'Africa' | 'Asia
1818
const getContinent = (lng: number): Continent => {
1919
if (lng > -125 && lng < -66) return 'North America';
2020
if (lng > -81 && lng < -34) return 'South America';
21-
if (lng > -10 && lng < 44) return 'Europe'; // Europe/Africa
21+
if (lng > -10 && lng < 44) return 'Europe'; // Europe/Africa are grouped for simplicity
2222
if (lng > 100 && lng < 180) return 'Oceania';
2323
return 'Asia'; // Asia/Africa
2424
};
@@ -71,43 +71,43 @@ const Globe3D = () => {
7171
globeGroup.rotation.z = 23.5 * (Math.PI / 180);
7272
scene.add(globeGroup);
7373

74-
// Globe Layers
74+
// --- Globe Layers ---
75+
7576
globeGroup.add(new THREE.Mesh(
7677
new THREE.SphereGeometry(globeRadius, 64, 64),
77-
new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true, opacity: 0.0 })
78+
new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true, opacity: 0.05 })
7879
));
7980

8081
const earthTexture = new THREE.TextureLoader().load('/earth-dark.jpeg');
8182
earthTexture.colorSpace = THREE.SRGBColorSpace;
8283
earthTexture.anisotropy = renderer.capabilities.getMaxAnisotropy();
83-
globeGroup.add(new THREE.Mesh(
84-
new THREE.SphereGeometry(globeRadius, 64, 64),
85-
new THREE.MeshBasicMaterial({ map: earthTexture, transparent: true, opacity: 0.0 })
86-
));
8784

88-
// --- NEW: Faint Lat/Long Grid Lines ---
85+
const earthMaterial = new THREE.MeshBasicMaterial({
86+
map: earthTexture,
87+
transparent: true,
88+
blending: THREE.AdditiveBlending,
89+
color: 0x777777,
90+
});
91+
const earthMesh = new THREE.Mesh(new THREE.SphereGeometry(globeRadius, 64, 64), earthMaterial);
92+
globeGroup.add(earthMesh);
93+
8994
const gridPoints: THREE.Vector3[] = [];
90-
const gridRadius = globeRadius + 0.005; // Slightly above the surface
91-
// Latitude lines
95+
const gridRadius = globeRadius + 0.005;
9296
for (let lat = -90; lat <= 90; lat += 15) {
9397
for (let lng = -180; lng <= 180; lng += 5) {
94-
gridPoints.push(latLngToVector3(lat, lng, gridRadius));
95-
gridPoints.push(latLngToVector3(lat, lng + 5, gridRadius));
98+
gridPoints.push(latLngToVector3(lat, lng, gridRadius), latLngToVector3(lat, lng + 5, gridRadius));
9699
}
97100
}
98-
// Longitude lines
99101
for (let lng = -180; lng <= 180; lng += 15) {
100102
for (let lat = -90; lat <= 90; lat += 5) {
101-
gridPoints.push(latLngToVector3(lat, lng, gridRadius));
102-
gridPoints.push(latLngToVector3(lat + 5, lng, gridRadius));
103+
gridPoints.push(latLngToVector3(lat, lng, gridRadius), latLngToVector3(lat + 5, lng, gridRadius));
103104
}
104105
}
105106
const gridGeom = new THREE.BufferGeometry().setFromPoints(gridPoints);
106-
const gridMaterial = new THREE.LineBasicMaterial({ color: 0x00ff00, transparent: true, opacity: 0.1 });
107+
const gridMaterial = new THREE.LineBasicMaterial({ color: 0x00ff00, transparent: true, opacity: 0.05 });
107108
const gridLines = new THREE.LineSegments(gridGeom, gridMaterial);
108109
globeGroup.add(gridLines);
109110

110-
111111
const connections: Connection[] = [];
112112

113113
Promise.all([
@@ -116,8 +116,7 @@ const Globe3D = () => {
116116
]).then(([countriesData, serverJson]) => {
117117
const servers: Server[] = serverJson.servers;
118118

119-
// **ENHANCEMENT:** Bolder country lines
120-
const outlineMaterial = new THREE.LineBasicMaterial({ color: 0x00ff00, transparent: true, opacity: 0.25 });
119+
const outlineMaterial = new THREE.LineBasicMaterial({ color: 0x00ff00, transparent: true, opacity: 0.4 });
121120
const outlinePoints: THREE.Vector3[] = [];
122121
countriesData.features.forEach((feature: any) => {
123122
if (feature.geometry?.type === 'LineString') {
@@ -153,7 +152,9 @@ const Globe3D = () => {
153152
establishedConnections.add(key);
154153

155154
const distance = start.vector.distanceTo(end.vector);
156-
const controlPoint = start.vector.clone().lerp(end.vector, 0.5).normalize().multiplyScalar(globeRadius + distance * 0.2);
155+
const arcHeight = distance * distance * 0.05;
156+
const controlPoint = start.vector.clone().lerp(end.vector, 0.5).normalize().multiplyScalar(globeRadius + arcHeight);
157+
157158
const curve = new THREE.QuadraticBezierCurve3(start.vector, controlPoint, end.vector);
158159

159160
const tubeGeom = new THREE.TubeGeometry(curve, 32, 0.005, 8, false);
@@ -170,30 +171,77 @@ const Globe3D = () => {
170171
connections.push({
171172
curve,
172173
trailMaterial,
173-
packet1: { sprite: packet1, position: Math.random(), speed: Math.random() * 0.01 + 0.005 },
174-
packet2: { sprite: packet2, position: Math.random(), speed: Math.random() * 0.01 + 0.005 },
174+
packet1: { sprite: packet1, position: Math.random(), speed: Math.random() * 0.02 + 0.005 },
175+
packet2: { sprite: packet2, position: Math.random(), speed: Math.random() * 0.02 + 0.005 },
175176
});
176177
};
178+
179+
// --- THE NEW CONNECTION ALGORITHM ---
180+
181+
const serversByContinent = new Map<Continent, ServerPoint[]>();
182+
serverPoints.forEach(p => {
183+
if (!serversByContinent.has(p.continent)) serversByContinent.set(p.continent, []);
184+
serversByContinent.get(p.continent)!.push(p);
185+
});
177186

178-
serverPoints.forEach(startServer => {
179-
const others = serverPoints.filter(p => p.name !== startServer.name);
180-
const nearest = others.sort((a, b) => startServer.vector.distanceTo(a.vector) - startServer.vector.distanceTo(b.vector))[0];
181-
createConnection(startServer, nearest);
182-
183-
const sameContinent = others.filter(p => p.continent === startServer.continent).sort(() => 0.5 - Math.random()).slice(0, 2);
184-
sameContinent.forEach(peer => createConnection(startServer, peer));
187+
// 1. Identify Gateways
188+
const gateways = new Map<Continent, ServerPoint>();
189+
for (const [continent, points] of serversByContinent.entries()) {
190+
let bestGateway: ServerPoint | null = null;
191+
let minAvgDist = Infinity;
185192

186-
if (Math.random() < 0.2) {
187-
const differentContinent = others.filter(p => p.continent !== startServer.continent);
188-
if(differentContinent.length > 0) createConnection(startServer, differentContinent[Math.floor(Math.random() * differentContinent.length)]);
193+
for (const candidate of points) {
194+
let totalDist = 0;
195+
let otherCount = 0;
196+
for (const other of serverPoints) {
197+
if (other.continent !== continent) {
198+
totalDist += candidate.vector.distanceTo(other.vector);
199+
otherCount++;
200+
}
201+
}
202+
const avgDist = totalDist / otherCount;
203+
if (avgDist < minAvgDist) {
204+
minAvgDist = avgDist;
205+
bestGateway = candidate;
206+
}
189207
}
208+
if (bestGateway) gateways.set(continent, bestGateway);
209+
}
210+
const gatewayList = Array.from(gateways.values());
211+
212+
// 2. Connect Gateways (Intercontinental Backbone)
213+
for(let i=0; i < gatewayList.length; i++) {
214+
for(let j=i+1; j < gatewayList.length; j++) {
215+
createConnection(gatewayList[i], gatewayList[j]);
216+
}
217+
}
218+
219+
// 3. Connect regional servers to their gateway (Spoke-to-Hub)
220+
for (const [continent, points] of serversByContinent.entries()) {
221+
const gateway = gateways.get(continent);
222+
if (gateway) {
223+
points.forEach(point => {
224+
if (point !== gateway) {
225+
createConnection(point, gateway);
226+
}
227+
});
228+
}
229+
}
230+
231+
// 4. Create local peering (nearest neighbor)
232+
serverPoints.forEach(startServer => {
233+
const nearest = serverPoints
234+
.filter(p => p.name !== startServer.name)
235+
.sort((a,b) => startServer.vector.distanceTo(a.vector) - startServer.vector.distanceTo(b.vector))[0];
236+
createConnection(startServer, nearest);
190237
});
238+
191239
});
192240

193241
const animate = () => {
194242
requestAnimationFrame(animate);
195243
connections.forEach(conn => {
196-
if (conn.trailMaterial.map) conn.trailMaterial.map.offset.x -= 0.0005;
244+
if (conn.trailMaterial.map) conn.trailMaterial.map.offset.x -= 0.002;
197245
conn.packet1.position = (conn.packet1.position + conn.packet1.speed) % 1;
198246
conn.packet2.position = (conn.packet2.position + conn.packet2.speed) % 1;
199247
conn.curve.getPointAt(conn.packet1.position, conn.packet1.sprite.position);

0 commit comments

Comments
 (0)