The galaxy the way Mapbox does it: engine fog with stars, black space
Some checks are pending
build-gate / build (push) Waiting to run

Mapbox renders space and the starfield engine-side through the fog API
(documented in their globe guide: stars and atmosphere are customized with
the fog property). Applied their documented example values with one change:
space-color is pure black on the Driver's instruction, star-intensity 0.6.

The container behind the sphere is plain black now, no gradient -- on
Mapbox the engine paints its own space so it never shows; on an engine
without fog (MapLibre) black is the honest fallback.

Verified by reading the rendered screenshot: stars in black space,
atmosphere glow at the limb, vivid blue oceans, the choropleth legible.
This commit is contained in:
doxa-maps-88655c70 2026-09-23 20:54:57 +00:00
parent 3bd2a7bebf
commit ae01086662
8 changed files with 37 additions and 20 deletions

View file

@ -1023,6 +1023,23 @@ function addLayers() {
}
} catch (_) { /* verify hook */ }
applyProjection()
// ★ THE GALAXY, THE WAY MAPBOX DOES IT (Driver: "find out how Mapbox does the galaxy stars and
// see if we can use that"). Mapbox GL renders space and the starfield ENGINE-SIDE via the fog
// API -- documented at docs.mapbox.com/mapbox-gl-js/guides/globe/ ("stars and atmosphere are
// customized with the fog property"). These are their documented example values with one
// change: space-color is pure black on the Driver's instruction ("not grey"). star-intensity
// 0..1 is the engine's own star layer -- no canvas, no custom code, the actual Mapbox stars.
// Guarded: MapLibre has no setFog (its equivalent is the sky spec), so on that provider this is
// a silent no-op and the plain black container behind the transparent sphere carries the void.
try {
if (typeof m.setFog === 'function') m.setFog({
'color': 'rgb(186, 210, 235)', // lower-atmosphere haze at the horizon
'high-color': 'rgb(36, 92, 223)', // upper atmosphere
'horizon-blend': 0.02,
'space-color': '#000000', // the void — black, not grey
'star-intensity': 0.6,
})
} catch (_) { /* an engine without fog keeps the container background instead */ }
// selection pen: rebuild the highlight source whenever the selectionSet changes (toggle on/off).
if (bus) bus.on('select', refreshSelected)
refreshSelected()
@ -1513,8 +1530,10 @@ useShadowStyles(`
wash behind the sphere, while the tiles keep their normal daylight colours. Scoped to
[data-projection="globe"] so flat mercator keeps the neutral ground — space behind a flat
rectangle would read as a mistake. */
.rd-mapwrap[data-projection="globe"]{
background:radial-gradient(ellipse at 50% 42%, #101a33 0%, #070b18 45%, #02040a 100%); }
/* Plain BLACK behind the sphere (Driver: "if not, then just do black background, not grey").
On Mapbox the engine paints its own space + stars over the whole canvas via fog, so this only
shows on engines without fog support (MapLibre), where black is the honest fallback. */
.rd-mapwrap[data-projection="globe"]{ background:#000; }
.rd-mapwrap .rd-mapc{ position:absolute; inset:0; }
.rd-proj{ position:absolute; right:8px; top:8px; z-index:3; font-size:11px; font-weight:700; cursor:pointer; user-select:none;
background:#1a1a2ecc; color:#fff; border:1px solid #ffffff33; border-radius:6px; padding:4px 9px; backdrop-filter:blur(4px); }

File diff suppressed because one or more lines are too long

View file

@ -40,7 +40,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <dashboard-plus-grid> custom element. -->
<script src="../../dashboard-plus-grid.js" integrity="sha384-gMsZ4bvxNvSJNUW6CoRAnCyy3o169BiDoNO8ZRyfXO7i2EWlcJdrMFOcgBaB8o8k" crossorigin="anonymous"></script>
<script src="../../dashboard-plus-grid.js" integrity="sha384-0dHEuXcYnhojSzU+gLjQ4LfJfUijduDh8AvMKNZKmDgoaRgI67IHbB3IqO4s+0sr" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -40,7 +40,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <dashboard-plus-grid> custom element. -->
<script src="../dashboard-plus-grid.js" integrity="sha384-gMsZ4bvxNvSJNUW6CoRAnCyy3o169BiDoNO8ZRyfXO7i2EWlcJdrMFOcgBaB8o8k" crossorigin="anonymous"></script>
<script src="../dashboard-plus-grid.js" integrity="sha384-0dHEuXcYnhojSzU+gLjQ4LfJfUijduDh8AvMKNZKmDgoaRgI67IHbB3IqO4s+0sr" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

View file

@ -193,7 +193,7 @@
"bundle": "dashboard-plus-grid",
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
"output": "doxa-maps/dashboard-plus-grid/dashboard-plus-grid.js",
"integrity": "sha384-gMsZ4bvxNvSJNUW6CoRAnCyy3o169BiDoNO8ZRyfXO7i2EWlcJdrMFOcgBaB8o8k",
"integrity": "sha384-0dHEuXcYnhojSzU+gLjQ4LfJfUijduDh8AvMKNZKmDgoaRgI67IHbB3IqO4s+0sr",
"elements": [
"dashboard-plus-grid"
],
@ -213,7 +213,7 @@
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
"embed": {
"iframe": "<iframe src=\"./dashboard-plus-grid/dashboard-plus-grid/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-gMsZ4bvxNvSJNUW6CoRAnCyy3o169BiDoNO8ZRyfXO7i2EWlcJdrMFOcgBaB8o8k\" crossorigin=\"anonymous\"></script>\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-0dHEuXcYnhojSzU+gLjQ4LfJfUijduDh8AvMKNZKmDgoaRgI67IHbB3IqO4s+0sr\" crossorigin=\"anonymous\"></script>\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>"
},
"instances": [
{
@ -878,7 +878,7 @@
"bundle": "research-dashboard",
"scriptUrl": "./research-dashboard/research-dashboard.js",
"output": "doxa-maps/research-dashboard/research-dashboard.js",
"integrity": "sha384-qpbBcC2J15C05AK4lY2IYE71fT5KdEudshshQlQfBYR086ZNkSgF27prL1/NW9n9",
"integrity": "sha384-myMGoGuI7dz3b9Wu3CfAJow2aHdDhlPP4DVBIRrNksXL96BRsSRTmhO34DuLyUnJ",
"elements": [
"research-dashboard-map"
],
@ -894,7 +894,7 @@
"scriptUrl": "./research-dashboard/research-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./research-dashboard/research-dashboard/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-qpbBcC2J15C05AK4lY2IYE71fT5KdEudshshQlQfBYR086ZNkSgF27prL1/NW9n9\" crossorigin=\"anonymous\"></script>\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-myMGoGuI7dz3b9Wu3CfAJow2aHdDhlPP4DVBIRrNksXL96BRsSRTmhO34DuLyUnJ\" crossorigin=\"anonymous\"></script>\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>"
},
"bundle": "research-dashboard"
}

File diff suppressed because one or more lines are too long

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <research-dashboard-map> custom element. -->
<script src="../research-dashboard.js" integrity="sha384-qpbBcC2J15C05AK4lY2IYE71fT5KdEudshshQlQfBYR086ZNkSgF27prL1/NW9n9" crossorigin="anonymous"></script>
<script src="../research-dashboard.js" integrity="sha384-myMGoGuI7dz3b9Wu3CfAJow2aHdDhlPP4DVBIRrNksXL96BRsSRTmhO34DuLyUnJ" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order: