# Cosmo Frontend Asset Loading Strategy Analysis ## Executive Summary The Cosmo frontend project implements a 3D solar system visualization using Three.js and React-Three-Fiber. The asset loading strategy currently uses a mix of on-demand fetching and preloading patterns, with assets served through a backend API proxy. --- ## 1. Asset Inventory ### 1.1 Texture Assets (Primary Location: Backend Upload) **Backend Location**: `/Users/jiliu/WorkSpace/cosmo/backend/upload/texture/` - **Total Size**: ~19 MB - **Format**: Primarily JPEG with some PNG - **Built/Dist Location**: `/Users/jiliu/WorkSpace/cosmo/frontend/dist/textures/` #### Key Texture Files (by size): | File | Size | Purpose | |------|------|---------| | 2k_moon.jpg | 1.0 MB | Moon surface texture | | 2k_venus_surface.jpg | 868 KB | Venus surface | | 2k_mercury.jpg | 856 KB | Mercury surface | | 2k_sun.jpg | 804 KB | Sun/Star texture | | 2k_mars.jpg | 736 KB | Mars surface | | 2k_jupiter.jpg | 488 KB | Jupiter surface | | 2k_earth_daymap.jpg | 456 KB | Earth day side | | 2k_earth_nightmap.jpg | 256 KB | Earth night side | | 2k_stars_milky_way.jpg | 248 KB | Milky Way background | | 2k_neptune.jpg | 236 KB | Neptune surface | | 2k_venus_atmosphere.jpg | 228 KB | Venus atmosphere | | 2k_saturn.jpg | 196 KB | Saturn surface | | 2k_uranus.jpg | 76 KB | Uranus surface | | 2k_saturn_ring_alpha.png | 12 KB | Saturn ring transparency | **Additional Textures** (comets, dwarf planets, moons): - 2k_pluto.jpg: 3.8 MB (largest single file) - Various comet/asteroid textures: 300-500 KB each - Moon textures (Ganymede, Io, Titan, Mimas): 350-360 KB each --- ### 1.2 3D Model Assets (GLB/GLTF Format) **Backend Location**: `/Users/jiliu/WorkSpace/cosmo/backend/upload/model/` - **Total Size**: ~24 MB - **Format**: GLB (binary GLTF) #### Key Model Files (by size): | File | Size | Purpose | |------|------|---------| | juno.glb | 8.6 MB | Juno space probe | | cassini.glb | 1.6 MB | Cassini spacecraft | | voyager_2.glb | 1.6 MB | Voyager 2 probe | | parker_solar_probe.glb | 436 KB | Parker Solar Probe | | voyager_1.glb | 280 KB | Voyager 1 probe | | webb_space_telescope.glb | ~1-2 MB (from list) | JWST | | new_horizons.glb | ~1-2 MB (from list) | New Horizons probe | | perseverance.glb | ~1-2 MB (from list) | Mars Perseverance rover | **Observations**: - Juno.glb (8.6 MB) is significantly larger than other models - Most probes range 280 KB to 1.6 MB - Total probe models: ~24 MB for ~8 spacecraft --- ## 2. Asset Loading Strategy ### 2.1 Texture Loading (Detailed Implementation) **File**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/CelestialBody.tsx` ```typescript // Current Loading Pattern: 1. Component mounts (Planet component) 2. fetchBodyResources(body.id, 'texture') - calls API 3. Finds main texture (excludes 'atmosphere' and 'night') 4. Constructs URL: /upload/{file_path} 5. useTexture(texturePath) - Three.js texture loader 6. Renders mesh with loaded texture // Key Line: const texture = texturePath ? useTexture(texturePath) : null; ``` **Loading Characteristics**: - **Type**: On-demand (per celestial body) - **Caching**: useTexture hook likely caches within session - **Error Handling**: Falls back to null (gray placeholder material) - **Performance**: No preloading - each body texture loads when component mounts ### 2.2 Model Loading (3D Probes) **File**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/Probe.tsx` ```typescript // Current Loading Pattern: 1. Component mounts (Probe component) 2. fetchBodyResources(body.id, 'model') - calls API 3. Gets first model resource + scale metadata 4. Constructs URL: /upload/{file_path} 5. useGLTF.preload(fullPath) - PRELOADING ENABLED 6. setModelPath(fullPath) 7. useGLTF(modelPath) - loads and parses GLB // Key Implementation: useGLTF.preload(fullPath); // Preload before rendering const gltf = useGLTF(modelPath); // Actual load ``` **Loading Characteristics**: - **Type**: On-demand with optional preloading - **Preloading**: Yes - `useGLTF.preload()` is called (Line 281) - **Caching**: useGLTF hook caches in session - **Scale Handling**: Custom scale from `extra_data.scale` - **Fallback**: ProbeFallback component renders red sphere if load fails - **Performance**: Preload triggered immediately, improves perceived load time ### 2.3 Background/Static Assets **File**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/Scene.tsx` ```typescript // Procedural Assets (NO external files): 1. BackgroundStars (radius=300, count=5000, procedural) 2. AsteroidBelts (procedurally generated) 3. Nebulae (procedurally generated) 4. Constellations (data-driven but rendered procedurally) // Data-Driven Assets (fetched from API): 1. Stars (real star catalog data) 2. Galaxies (CanvasTexture generated) 3. Satellites/Planets (textures fetched on demand) ``` **Observations**: - Extensive use of procedural generation reduces asset file count - Galaxy textures created with CanvasTexture (no disk files) - Star data loaded from API, rendered with simple geometry --- ## 3. Loading Flow & Architecture ### 3.1 Request Path ``` Frontend Component ↓ fetchBodyResources(bodyId, type) ↓ API Call: /api/celestial/resources/{bodyId}?resource_type=texture|model ↓ Backend API (Port 8000) ↓ Vite Proxy Dev: localhost:8000/upload/{type}/{filename} OR Nginx Production: proxy to backend ↓ Actual File: /backend/upload/{type}/{filename} ↓ Response to Frontend ↓ useTexture() or useGLTF() ↓ Three.js Renderer ``` ### 3.2 API Integration Points **File**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/utils/api.ts` ```typescript // Fetch function signature: export async function fetchBodyResources( bodyId: string, resourceType?: string ): Promise<{ body_id: string; resources: Array<{ id: number; resource_type: string; file_path: string; // e.g., "texture/2k_sun.jpg" file_size: number; mime_type: string; created_at: string; extra_data?: Record; // scale, etc. }>; }> ``` --- ## 4. Vite Build Configuration **File**: `/Users/jiliu/WorkSpace/cosmo/frontend/vite.config.ts` ```typescript export default defineConfig({ plugins: [react()], server: { host: '0.0.0.0', port: 5173, proxy: { '/api': { target: 'http://localhost:8000', changeOrigin: true, }, '/upload': { target: 'http://localhost:8000', changeOrigin: true, }, '/public': { target: 'http://localhost:8000', changeOrigin: true, }, }, }, }) ``` **Current Configuration Analysis**: - **No explicit asset optimization**: No image compression, no WebP conversion - **No size limits**: All assets proxied without size constraints - **No chunking strategy**: Vite default chunks (1.2 MB JS bundle observed) - **Proxy strategy**: All assets proxied through backend (good for dynamic content) --- ## 5. Build Output Analysis **Dist Directory**: `/Users/jiliu/WorkSpace/cosmo/frontend/dist/` - **Total Size**: ~20 MB - **JavaScript Bundle**: 1.2 MB (index-c2PfKiPB.js) - **CSS**: 9.8 KB - **Textures**: ~7.9 MB (in dist, smaller than backend copy) - **Models**: ~12.8 MB (in dist) **Key Finding**: Textures in dist folder are smaller than backend source, suggesting some optimization (JPEG compression) during build/deploy. --- ## 6. Lazy Loading & Code Splitting **File**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/App.tsx` ```typescript // Already Implemented: const InterstellarTicker = lazy(() => import('./components/InterstellarTicker') .then(m => ({ default: m.InterstellarTicker })) ); const MessageBoard = lazy(() => import('./components/MessageBoard') .then(m => ({ default: m.MessageBoard })) ); const BodyDetailOverlay = lazy(() => import('./components/BodyDetailOverlay') .then(m => ({ default: m.BodyDetailOverlay })) ); // Wrapped in Suspense: ``` **Status**: - Lazy loading implemented for 3 non-critical components - Suspense fallback set to null (no skeleton loading) - No lazy loading for 3D rendering components (CelestialBody, Probe, Scene) --- ## 7. Current Optimization Opportunities ### 7.1 Identified Issues 1. **No Texture Compression** - Total texture size: 19 MB (backend) → 7.9 MB (dist) - JPEG quality likely could be reduced further - No WebP fallback for modern browsers - No LOD (Level of Detail) system 2. **Large Model File** - Juno.glb: 8.6 MB (30% of all model assets) - No model optimization/decimation - No LOD for probes - All vertices/triangles loaded even when zoomed out 3. **No Batch Asset Loading** - Each body texture loaded individually - 10+ API calls for visible celestial bodies - No batching or parallel loading optimization - No request deduplication 4. **All-or-Nothing Texture Loading** - Texture loading blocks render until complete - Falls back to gray if load fails - No progressive/streaming load 5. **Limited Caching Strategy** - useTexture/useGLTF cache only within session - No persistent browser cache headers optimization - No service worker caching 6. **Background Star Data** - Stars component loads 1000+ star systems per API call - No pagination or frustum culling - All stars rendered regardless of visibility ### 7.2 Existing Optimizations ``` POSITIVE: ✓ Procedural generation for backgrounds (saves ~10 MB+ in textures) ✓ useGLTF.preload() for probe models ✓ useTexture hook caching ✓ Lazy loading for non-critical UI components ✓ Reused geometry for identical objects (stars use single SphereGeometry) ✓ Billboard optimization for labels (distance culling) ✓ Selective texture filtering (excludes atmosphere/night variants) ``` --- ## 8. Performance Summary ### Asset Totals: - **Textures**: 19 MB (backend) / 7.9 MB (dist) - **Models**: 24 MB (backend) / 12.8 MB (dist) - **JavaScript**: 1.2 MB - **Total Transfer**: ~32 MB initial + on-demand loading ### Loading Pattern: - **Initial Load**: 1.2 MB (JS) + procedural background rendering - **Per-Scene**: ~100-500 KB (depending on visible bodies) - **Per-Probe**: 280 KB - 8.6 MB (first load) ### Current Bottlenecks: 1. Juno probe (8.6 MB) loading time 2. Sequential texture API calls 3. No partial/progressive loading 4. Large JPEG files (Moon: 1 MB, Venus: 868 KB) --- ## 9. File Locations Summary ### Source Code: - **Main 3D Scene**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/Scene.tsx` - **Texture Loading**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/CelestialBody.tsx` (Line 102-123) - **Model Loading**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/components/Probe.tsx` (Line 261-295) - **API Integration**: `/Users/jiliu/WorkSpace/cosmo/frontend/src/utils/api.ts` - **Build Config**: `/Users/jiliu/WorkSpace/cosmo/frontend/vite.config.ts` ### Asset Locations: - **Texture Source**: `/Users/jiliu/WorkSpace/cosmo/backend/upload/texture/` - **Model Source**: `/Users/jiliu/WorkSpace/cosmo/backend/upload/model/` - **Texture Build Output**: `/Users/jiliu/WorkSpace/cosmo/frontend/dist/textures/` - **Model Build Output**: `/Users/jiliu/WorkSpace/cosmo/frontend/dist/models/` - **Documentation**: `/Users/jiliu/WorkSpace/cosmo/frontend/PERFORMANCE_OPTIMIZATION.md` --- ## 10. Recommendations (Priority Order) ### Quick Wins (1-2 hours): 1. Implement image compression (JPEG quality: 80-85%) 2. Add WebP format with JPEG fallback 3. Set proper Cache-Control headers on backend 4. Implement batch/parallel texture loading ### Medium Term (4-8 hours): 1. Add texture LOD (Load specific resolution by distance) 2. Implement model decimation for Juno probe 3. Add progressive texture loading (low-res → high-res) 4. Implement frustum culling for star systems ### Long Term (16+ hours): 1. Implement texture atlas for small textures 2. Add KTX2/Basis texture compression 3. Implement virtual scrolling for star catalog 4. Add service worker for persistent caching