diff --git a/web/src/plugins/radio/RadioTab.tsx b/web/src/plugins/radio/RadioTab.tsx index 54a4e0b..88ac901 100644 --- a/web/src/plugins/radio/RadioTab.tsx +++ b/web/src/plugins/radio/RadioTab.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import Globe from 'globe.gl'; -import { CanvasTexture, LinearFilter } from 'three'; +import { CanvasTexture, Color, LinearFilter, SRGBColorSpace } from 'three'; import { TileTextureManager } from './TileTextureManager'; // ── Types ── @@ -160,7 +160,7 @@ export default function RadioTab({ data }: { data: any }) { const accentRgb = style.getPropertyValue('--accent-rgb').trim(); globeRef.current .pointColor(() => `rgba(${accentRgb}, 0.85)`) - .atmosphereColor(`rgba(${accentRgb}, 0.25)`); + .atmosphereColor(`rgb(${accentRgb})`); } }, [theme]); @@ -215,7 +215,7 @@ export default function RadioTab({ data }: { data: any }) { const globe = new Globe(containerRef.current) .backgroundColor('rgba(0,0,0,0)') - .atmosphereColor(`rgba(${initRgb}, 0.25)`) + .atmosphereColor(`rgb(${initRgb})`) .atmosphereAltitude(0.12) .pointsData(places) // Radio Garden geo format: [lng, lat] @@ -237,9 +237,11 @@ export default function RadioTab({ data }: { data: any }) { const texture = new CanvasTexture(tileMgr.canvas); texture.minFilter = LinearFilter; texture.generateMipmaps = false; + texture.colorSpace = SRGBColorSpace; tileTextureRef.current = texture; const mat = globe.globeMaterial() as any; mat.map = texture; + mat.color = new Color(0xffffff); mat.needsUpdate = true; // Start loading tiles (progressive: zoom 1 → 2 → 3) diff --git a/web/src/plugins/radio/TileTextureManager.ts b/web/src/plugins/radio/TileTextureManager.ts index 7a5f4fc..c9e6058 100644 --- a/web/src/plugins/radio/TileTextureManager.ts +++ b/web/src/plugins/radio/TileTextureManager.ts @@ -8,6 +8,7 @@ // Proxy through our server (CDN requires Referer: radio.garden) const TILE_CDN = '/api/radio/tile'; +const FALLBACK_TEXTURE = '/earth-night.jpg'; // ── Mercator math ── @@ -51,6 +52,7 @@ export class TileTextureManager { // Ocean background this.ctx.fillStyle = '#070b15'; this.ctx.fillRect(0, 0, width, height); + this.drawFallbackTexture(); } /** Load base layers progressively (zoom 1 → 3) */ @@ -108,6 +110,16 @@ export class TileTextureManager { await Promise.all(batch); } + private drawFallbackTexture(): void { + const img = new Image(); + img.onload = () => { + if (this.drawn.size > 0) return; + this.ctx.drawImage(img, 0, 0, this.width, this.height); + this.scheduleUpdate(); + }; + img.src = FALLBACK_TEXTURE; + } + private loadTile(z: number, x: number, y: number): Promise { const k = `${z}/${x}/${y}`; if (this.cache.has(k) || this.loading.has(k)) return Promise.resolve();