Hi team,
I’m currently developing a city-scale digital twin platform using CesiumJS, and I’m facing performance issues during the initial loading phase, especially under poor client network conditions.
Context
-
Use case: City-scale digital twin (urban analysis platform)
-
Data includes:
-
3D Tiles (buildings)
-
Terrain
-
Imagery layers
-
Client environment varies, but includes low-bandwidth networks
Problem
When users access the platform:
-
Initial rendering takes a long time
-
Significant delay before the scene becomes interactive
-
This leads to poor user experience, especially for first-time loading
What we suspect
We believe the issue is related to:
-
Large amount of data being requested at startup
-
Network latency / bandwidth limitations
-
Possibly suboptimal loading strategy
Questions
-
Are there recommended best practices for improving initial loading performance in CesiumJS for large-scale scenes?
-
What strategies are commonly used to reduce initial load time?
- e.g., progressive loading, LOD tuning, lazy loading, etc.
-
Are there any guidelines or recommended client network / hardware specifications for stable usage of CesiumJS-based platforms?
-
In real-world deployments, how do teams handle users in low network environments?
Additional Info
To optimize CesiumJS for city scale digital twins, following are some suggestions
1. Diagnostics & Metrics
- Instrument your startup to identify bottlenecks
- Monitor Tiles: Use viewer.scene.globe.tileLoadProgressEvent to track the queue
- Measure Interaction: Log performance.now() when the tile count hits zero
- Network Audit: Use DevTools (XHR/Size) to find “blocking” heavy tiles.
2. 3D Tiles & SSE Tuning
- Adjust the Screen Space Error (SSE) to balance detail vs performance
- Initial Load: Set maximumScreenSpaceError: 32 (double default) and preloadWhenHidden: false
- Dynamic SSE: Enable dynamicScreenSpaceError: true to reduce detail on distant objects
- Memory: Cap maximumMemoryUsage (e.g: 512MB) to prevent browser crashing
- Data Health: Use 3d-tiles-tools to ensure your tileset has a proper spatial hierarchy (Octree/Quadtree) and Draco compression
3. Progressive & Adaptive Loading
- Don’t load everything at once. Use a phased strategy:
- Phased Strategy: 1. Terrain (No normals) > 2. Low-res Imagery > 3. Viewport-specific Tiles
- Network Awareness: Use navigator.connection to detect bandwidth.
- Low Bandwidth: Force requestRenderMode: true, lower resolutionScale (0.75), and disable 3D buildings
- High Bandwidth: Enable full LOD and 60 FPS
4. Scene-Level Micro-Optimizations
- Lower the rendering overhead of the Cesium engine
- Render on Demand: Set requestRenderMode: true (cuts CPU/GPU usage by 60%)
- Disable Effects: Turn off fog, skyAtmosphere, fxaa, and globe.enableLighting during initial movement
- Refresh Rate: Cap targetFrameRate at 30 FPS
5. Server-Side (Nginx)
- Protocol: Use HTTP/2 for multiplexing tile requests
- Caching: Set aggressive Cache-Control (e.g., 1 year for static tiles)
- Compression: Gzip terrain, but disable it for 3D Tiles if already using Draco
Priority Implementation Order
- Enable requestRenderMode: true
- Switch to HTTP/2
- Implement dynamicScreenSpaceError
- Audit tileset hierarchy with 3d-tiles-tools
Are there any recommended minimum client PC specifications for running a CesiumJS-based application?
there is no official CesiumJS spec sheet.
At the minimum, a dualcore 2.0GHz CPU, 4GB RAM, and WebGL 2.0 compatible integrated graphics like Intel HD 4000 can run basic scenes over a 2Mbps connection, but for 3DTiles, a minimum quadcore 3.0GHz CPU, 8GB RAM, and a dedicated GPU with 2GB VRAM over 10Mbps should be able to load 3DTile (depends on your application), for a mid range spec, 6core 3.5GHz CPU, 16GB RAM, 25Mbps network speed, a dedicated GPU with 4 to 6GB VRAM should be able to handle city scale scene with optimisations.
Note: GPU is the primary bottleneck as CesiumJS offloads geometry, terrain, and image decoding to GPU, you can detect integrated or low end GPU at runtime and dynamically adjust your settings as needed.
Hey @Seonghyun_Seo,
It sounds like you’re primarily bottle necked by network conditions and not computational performance (CPU or GPU).
You could try only loading terrain at start-up, and use layers or some other UI to load more on request, you can also hide things behind loading screen, tutorial popups etc.
You mention self-hosted, are you using cesium ion self-hosted? Are your 3D tiles hosted on-prem? Or is it just your site that is hosted on prem but requests are still going out to cesium ion/wherever 3D tiles are hosted?
It would be helpful to have a better understanding of your architecture to know where your issue may most likely lie.
For now I can say:
-
If your 3D tiles aren’t hosted locally/on-premises and you cannot easily improve download speeds, look into on-prem hosting
-
try to utilise maximumSimultaneousTileLoads and maximumMemoryUsage on your tilesets.
maximumSimultaneousTileLoads: Caps how many tiles can be fetched concurrently. Lowering it (e.g., 6–10) reduces network contention on slow connections. Raising it (e.g., 30+) can speed up loading on fast connections but may saturate bandwidth or overload the GPU.
maximumMemoryUsage: The memory threshold (in MB) at which the tileset starts unloading tiles that aren’t visible. Lowering it helps on memory-constrained devices (mobile, embedded). Raising it keeps more tiles cached, reducing re-fetching when the camera revisits areas.
Leveraging both of these may improve the user experience.
-
I can’t really give recommendations on network speed as this is highly dependant on the complexity of the content you are trying to load