diff --git a/web/src/plugins/radio/RadioTab.tsx b/web/src/plugins/radio/RadioTab.tsx index 59d7d6d..a86c092 100644 --- a/web/src/plugins/radio/RadioTab.tsx +++ b/web/src/plugins/radio/RadioTab.tsx @@ -1,6 +1,5 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import Globe from 'globe.gl'; -import { CanvasTexture, Sprite, SpriteMaterial } from 'three'; // ── Types ── interface RadioPlace { @@ -63,29 +62,9 @@ const THEMES = [ { id: 'cherry', color: '#e74c6f', label: 'Cherry' }, ]; -function createMarkerTexture(color: string): CanvasTexture | null { - const canvas = document.createElement('canvas'); - canvas.width = 64; - canvas.height = 64; - - const ctx = canvas.getContext('2d'); - if (!ctx) return null; - - const gradient = ctx.createRadialGradient(32, 32, 3, 32, 32, 32); - gradient.addColorStop(0, 'rgba(255,255,255,1)'); - gradient.addColorStop(0.35, color); - gradient.addColorStop(0.7, color.replace('rgb(', 'rgba(').replace(')', ',0.42)')); - gradient.addColorStop(1, 'rgba(0,0,0,0)'); - - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 64, 64); - - return new CanvasTexture(canvas); -} - -function markerScale(size: number): number { - return Math.max(0.55, Math.min(1.75, 0.42 + size * 0.035)); -} +// ── Zoom scaling constants ── +const BASE_ALT = 2.0; +const BASE_RADIUS = 0.18; // ── Component ── export default function RadioTab({ data }: { data: any }) { @@ -179,21 +158,9 @@ export default function RadioTab({ data }: { data: any }) { if (globeRef.current && containerRef.current) { const style = getComputedStyle(containerRef.current.parentElement!); const accentRgb = style.getPropertyValue('--accent-rgb').trim(); - const spriteTexture = createMarkerTexture(`rgb(${accentRgb})`); - globeRef.current.atmosphereColor(`rgb(${accentRgb})`); - globeRef.current.objectsData(places); - globeRef.current.objectThreeObject((d: any) => { - const material = new SpriteMaterial({ - map: spriteTexture ?? undefined, - color: `rgb(${accentRgb})`, - transparent: true, - depthWrite: false, - }); - const sprite = new Sprite(material); - const scale = markerScale(d.size ?? 1); - sprite.scale.set(scale, scale, 1); - return sprite; - }); + globeRef.current + .pointColor(() => `rgba(${accentRgb}, 0.85)`) + .atmosphereColor(`rgba(${accentRgb}, 0.25)`); } }, [theme]); @@ -231,41 +198,32 @@ export default function RadioTab({ data }: { data: any }) { if (!containerRef.current || places.length === 0) return; if (globeRef.current) { - globeRef.current.objectsData(places); + globeRef.current.pointsData(places); return; } // Read accent color from theme const initStyle = getComputedStyle(containerRef.current.parentElement!); const initRgb = initStyle.getPropertyValue('--accent-rgb').trim() || '230, 126, 34'; - const markerTexture = createMarkerTexture(`rgb(${initRgb})`); + const globe = new Globe(containerRef.current) .backgroundColor('rgba(0,0,0,0)') - .atmosphereColor(`rgb(${initRgb})`) + .atmosphereColor(`rgba(${initRgb}, 0.25)`) .atmosphereAltitude(0.12) .globeImageUrl('/nasa-blue-marble.jpg') - .objectsData(places) - .objectLat((d: any) => d.geo[1]) - .objectLng((d: any) => d.geo[0]) - .objectAltitude(0.0012) - .objectFacesSurface(false) - .objectLabel((d: any) => + .pointsData(places) + // Radio Garden geo format: [lng, lat] + .pointLat((d: any) => d.geo[1]) + .pointLng((d: any) => d.geo[0]) + .pointColor(() => `rgba(${initRgb}, 0.85)`) + .pointRadius(BASE_RADIUS) + .pointAltitude(0.001) + .pointResolution(24) + .pointLabel((d: any) => `