When EVE Frontier Map launched, every page load transferred over 6MB of data—1.2MB for a single logo PNG, 5MB for the universe database downloaded on every session, and dozens of smaller assets. For users on mobile connections, first load could take 8-12 seconds.
Over the past week, we systematically eliminated bandwidth waste while improving UX. Here's how we cut loading times by 99.9% and reduced our CDN egress costs from £12-22/month to £1-2/month.
The Logo Problem: 1.2MB of Unnecessary Pixels
Our loading screen featured a high-resolution PNG logo: 600×600 pixels, 32-bit RGBA, weighing 1,212 KB. Users on slow connections would stare at a blank screen for 3-5 seconds waiting for the logo to appear—before the actual app even started loading.
Investigation
We analyzed the logo file:
- Simple geometric design (hexagon + star field + gradient)
- Sharp vector-style edges (no photographic content)
- Only 6 distinct colors in the palette
- Stored as raster PNG with millions of redundant pixels
This was a perfect candidate for SVG conversion.
The Fix: SVG Conversion
We converted the logo from PNG to SVG, manually tracing the geometric shapes:
Quality: Identical visual appearance at all resolutions
Scalability: Works on 4K displays without pixelation
Updated references in App.tsx, LoadingScreen.tsx, and index.html, keeping the original PNG as .backup for rollback safety.
Database Caching: Solving the 5MB Download Problem
EVE Frontier Map loads two SQLite databases on startup:
- Universe database (map_data_v2.db): 5 MB, stars/regions/gates
- Solar system database (frontierdata_compatible.db): 67 MB, planets/moons/Lagrange Points
Initially, every session fetched these from Cloudflare CDN—even though the universe database changes once per 90-day cycle, and the solar system database is updated manually.
Dual-Layer Cache Strategy
We implemented a two-tier caching system:
async function loadDatabase(dbUrl, dbName) {
// Layer 1: Check IndexedDB (browser storage)
let dbBlob = await indexedDbCache.get(dbName);
if (dbBlob) {
console.log(`✅ Cache hit: ${dbName} from IndexedDB`);
return dbBlob;
}
// Layer 2: Fetch with HTTP cache (Cloudflare CDN)
const response = await fetch(dbUrl, {
cache: 'force-cache' // Prefer cached response
});
// Layer 3: Network request (fallback)
if (!response.ok) throw new Error('Network load failed');
dbBlob = await response.blob();
// Store in IndexedDB for next session
await indexedDbCache.set(dbName, dbBlob);
return dbBlob;
}
Cache Duration Tuning
We set aggressive HTTP cache headers on the Cloudflare Worker:
// Universe database: 90 days (EVE Frontier cycle duration)
'Cache-Control': 'public, max-age=7776000, immutable'
// Solar system database: 90 days (manual updates)
'Cache-Control': 'public, max-age=7776000, immutable'
Subsequent visits: IndexedDB read only (~500ms)
Bandwidth savings: 5 MB × (sessions - 1) per user
CDN egress cost reduction: ~91% (£12-22/month → £1-2/month)
Cache Invalidation Strategy
When we update the databases manually:
- Bump the database filename (e.g.,
map_data_v3.db) - Update references in code to new filename
- Purge Cloudflare cache for the old URL
- Users automatically fetch new version on next session
Alternatively, purge Cloudflare cache without filename change—browsers will re-fetch on next session.
Loading Screen UX: Making Wait Times Feel Instant
While optimizing bandwidth, we noticed that 50% of traffic comes from iframe embeds on community sites like EveDataCo.re. These embeds (often 640×360 pixels) had a poor loading experience:
- Logo squashed vertically (aspect ratio broken)
- Loading screen ignored cinematic color mode
- Grey background didn't match embedded site theme
Responsive Logo Sizing
We added embed-specific styling:
// Full app: 600px logo
const logoSize = embedMode ? 200 : 600;
<img
src="/logo.svg"
style={{
width: `${logoSize}px`,
height: `${logoSize}px`,
aspectRatio: '1', // Force square
objectFit: 'contain' // Preserve proportions
}}
/>
The critical fix was adding aspect-ratio: 1 and removing max-height constraints. This prevents vertical squashing in small iframes while maintaining perfect logo proportions.
Theme-Aware Glow Effect
We detect cinematic color from URL parameters and apply it to the loading screen glow:
// Parse ?color=green from URL
const cinematicColor = new URLSearchParams(location.search).get('color');
// Map to theme accent
const glowColor = {
'green': '#34a853',
'blue': '#8ab4f8',
'red': '#ea4335',
'yellow': '#fbbc04',
'orange': '#ff6d00'
}[cinematicColor] || '#8ab4f8';
// Apply glow
boxShadow: `0 0 60px ${glowColor}`
This creates visual continuity—users never see a jarring color shift from loading screen to loaded app.
Background Color Consistency
We changed the loading screen background from grey (#1a1a1a) to match the app's theme black (#0b0f17). Combined with early theme application via localStorage, users experience seamless visual flow.
- Logo maintains square aspect ratio at all sizes
- Glow color matches cinematic mode (no orange flash)
- Background color consistent with embedded site
- 200px logo loads instantly (1.23 KB SVG)
Race Condition Fix: The Orange Flash Bug
During embed testing, we discovered a subtle bug: users with ?color=green would see a brief orange flash as the page loaded, then the correct green theme would apply.
Root Cause
Two competing useEffect hooks:
// LoadingScreen.tsx: Set glow to green
useEffect(() => {
document.documentElement.style.setProperty('--glow-color', green);
}, []);
// App.tsx: Restore saved orange theme from localStorage
useEffect(() => {
const savedTheme = localStorage.getItem('theme'); // 'orange'
document.documentElement.style.setProperty('--glow-color', savedTheme);
}, []);
The App.tsx effect ran after LoadingScreen mounted, overwriting the URL-specified color.
The Fix: isLoaded Guard
// App.tsx: Only restore theme AFTER loading completes
useEffect(() => {
if (!isLoaded) return; // Guard against premature execution
const savedTheme = localStorage.getItem('theme');
document.documentElement.style.setProperty('--glow-color', savedTheme);
}, [isLoaded]); // Depend on loading state
Measuring Impact
After all optimizations, here's the bandwidth breakdown:
Before Optimization
- Logo: 1,212 KB
- Universe DB (per session): 5,000 KB
- Solar System DB (per view): 67,000 KB
- Other assets: ~800 KB
- Total first load: ~74 MB
- Total per session: ~6 MB
After Optimization
- Logo: 1.23 KB (99.9% reduction)
- Universe DB (first visit): 5,000 KB
- Universe DB (cached): 0 KB (IndexedDB)
- Solar System DB (first view): 67,000 KB
- Solar System DB (cached): 0 KB (IndexedDB)
- Other assets: ~800 KB
- Total first load: ~73 MB (logo savings)
- Total subsequent sessions: ~800 KB (87% reduction)
With ~1,000 daily users and average 3 sessions per user:
- Before: 1,000 × 3 × 6 MB = 18 GB/day = 540 GB/month
- After: (1,000 × 73 MB) + (2,000 × 0.8 MB) = 74.6 GB/month
- Reduction: 86% less egress
- Cost impact: £12-22/month → £1-2/month (Cloudflare R2 pricing)
Key Takeaways
1. Vector > Raster for Logos
If your logo is geometric or illustrative (not photographic), convert it to SVG. The bandwidth savings are enormous, and resolution-independence is a bonus.
2. Cache Everything That's Stable
Universe data that changes once per 90-day cycle should never be fetched multiple times per user. Use IndexedDB for persistent client-side storage and aggressive HTTP caching for CDN efficiency.
3. Loading Screens Are UX, Not Just Placeholders
Users judge your app during the first 500ms of loading. Match colors, respect aspect ratios, and eliminate jarring transitions.
4. Embed Mode Deserves First-Class Treatment
If 50% of your traffic comes from iframes, optimize for that experience. Responsive sizing, theme detection, and visual consistency matter.
5. Race Conditions Hide in useEffect Chains
When multiple components modify global state (DOM styles, localStorage), add guards (isLoaded, isMounted) to prevent timing conflicts.
What's Next?
Bandwidth optimization is an ongoing process. Future improvements:
- Lazy-load solar system database: Only fetch when user clicks "View Solar System"
- Delta updates: Send only changed database rows instead of full re-downloads
- Brotli compression: Enable Cloudflare's best compression for .db files
- Service Worker caching: Offline-first PWA experience
But for now, we've achieved the core goal: fast, efficient, and polished loading experience for all users.
Visit EVE Frontier Map on a fresh browser profile and watch the console logs—you'll see IndexedDB cache hits on your second session. Or embed the map with ?color=green to see the theme-aware loading screen in action.