The Cesium globe is not rendering.
Context:
I can see all the issues. There are several root causes for the blank/black globe:
window.CESIUM_BASE_URL is set AFTER import('cesium') — it must be set before the first module evaluation, not after the import resolvescleanedUpRef is never reset — once it's set true, the component can never re-initialize (React Strict Mode unmounts/remounts)Cesium.Terrain.fromWorldTerrain() is called synchronously in the Viewer constructor options — it returns a Promise and should be passed as the resolved value or handled asynchronouslyViewer container needs explicit pixel dimensions — absolute inset-0 works only if the parent has a measured heightwidgets.css must be imported or the canvas renders unstyled/invisibleNow fix the container div to guarantee Cesium gets real pixel dimensions — the parent <main> uses h-dvh which is fine, but we need to ensure the container is explicitly sized:
Now also strip Cesium's own toolbar/widget chrome that fights with the dark background by suppressing its default CSS overrides. Add a global override in globals.css:
Also update the font to Inter/JetBrains Mono to match the layout.tsx update, and add the Cesium widget overrides:
Four targeted fixes applied to CesiumGlobe.tsx and globals.css:
CESIUM_BASE_URL moved before the import — it must exist on window before CesiumJS resolves workers/assets; setting it after the dynamic import is too lateterrainProvider awaited separately — Cesium.Terrain.fromWorldTerrain() returns a Promise, so it's now await-ed and passed as terrainProvider (not terrain) to the Viewer constructorwidgets.css explicitly imported — import('cesium/Build/Cesium/Widgets/widgets.css') is co-awaited with the module; without it the canvas has zero size and is invisibleresize detection reliably reads the computed dimensions; cleanedUpRef is reset on each effect run so Strict Mode's double-invoke doesn't permanently block re-initializationThe code returns the following error:
⨯ unhandledRejection: ChunkLoadError: Failed to load chunk /_next/static/chunks/aa825_cesium_Build_Cesium_Widgets_widgets_e9822b56.css from module [project]/node_modules/.pnpm/cesium@1.139.0/node_modules/cesium/Build/Cesium/Widgets/widgets.css [app-client] (css, async loader)
Revise the code to address the error.
The root cause is clear: import('cesium/Build/Cesium/Widgets/widgets.css') is a dynamic CSS import inside an async function — Next.js/Turbopack can't chunk CSS this way. The fix is to move the widgets CSS import to the top of the file at module level, and in the initCesium function just import cesium alone.
However, CesiumGlobe.tsx is already 'use client' but it's loaded via a dynamic import with ssr: false — the static import 'cesium/...' at module level still triggers during the SSR bundle traversal before the dynamic loader can gate it. We need to ensure the widgets CSS import stays isolated to the client-only dynamic chunk. Let me check the wrapper:
Good — CesiumGlobe is dynamically loaded with ssr: false, which means Next.js won't execute it server-side. The static import 'cesium/Build/Cesium/Widgets/widgets.css' at module top is the correct pattern here since the entire module is client-only. However, Turbopack can still fail on the CSS if Next.js tries to statically analyse the import. The safest fix is to inject the stylesheet imperatively at runtime inside initCesium rather than either a static or dynamic import — this avoids the bundler touching the CSS entirely:
Now inject the stylesheet via a <link> tag at the start of initCesium, before the Cesium import:
The CSS is now served from /public/cesium/Widgets/widgets.css (already copied there by the webpack plugin at build time) and injected as a <link rel="stylesheet"> DOM element — the bundler never touches it. This sidesteps both the Turbopack async CSS chunk error and the Webpack SSR CSS evaluation issue entirely. The getElementById guard ensures it only gets added once even across Strict Mode double-invokes.
You can send messages while the preview loads