feat(core): add readiness adapters for map and visualization libraries (#1548)

Add readiness-only runtime adapters for Mapbox GL JS, Leaflet, Google
Maps, MapLibre GL JS, and D3. Each adapter gates `__renderReady` until
the library's async initialization completes, preventing the renderer
from capturing blank or half-loaded frames.

Built on the `getReadyPromise` adapter contract from #1543. A shared
`createReadinessAdapter()` helper in `_readiness.ts` owns the
settled-tracking WeakSet, promise-identity stability, and
`Promise.allSettled` gate — each adapter provides only its type, window
global name, and `waitFor` callback.

Readiness signals per library:
- Mapbox / MapLibre: `map.loaded()` + `map.on('load', ...)`
- Leaflet: `map.whenReady(cb)`
- Google Maps: `map.addListener('tilesloaded', cb)` with handle cleanup
- D3: `transition.end()` promise

50 unit tests across 5 test files covering happy path, no-instances,
stable promise identity, post-settle drain, loaded-before-subscribe
race, and listener cleanup. 5 producer regression tests with
Docker-generated baselines for end-to-end render verification.
This commit is contained in:
Miguel Ángel
2026-06-18 01:21:27 -04:00
committed by GitHub
parent bb5f5f8c5c
commit 75d92b55e0
33 changed files with 2294 additions and 0 deletions
+30
View File
@@ -102,6 +102,36 @@ declare global {
* window.__hfLottie.push(anim);
*/
__hfLottie?: unknown[];
/**
* Mapbox GL JS map instances. Push your map here after creating it:
* window.__hfMapbox = window.__hfMapbox || [];
* window.__hfMapbox.push(map);
*/
__hfMapbox?: unknown[];
/**
* Leaflet map instances. Push your map here after creating it:
* window.__hfLeaflet = window.__hfLeaflet || [];
* window.__hfLeaflet.push(map);
*/
__hfLeaflet?: unknown[];
/**
* Google Maps instances. Push your map here after creating it:
* window.__hfGoogleMaps = window.__hfGoogleMaps || [];
* window.__hfGoogleMaps.push(map);
*/
__hfGoogleMaps?: unknown[];
/**
* MapLibre GL JS map instances. Push your map here after creating it:
* window.__hfMaplibre = window.__hfMaplibre || [];
* window.__hfMaplibre.push(map);
*/
__hfMaplibre?: unknown[];
/**
* D3 transition instances. Push your transition here after creating it:
* window.__hfD3 = window.__hfD3 || [];
* window.__hfD3.push(transition);
*/
__hfD3?: unknown[];
/**
* Render-time variable overrides injected by the engine when the user
* passes `hyperframes render --variables '<json>'`. Read indirectly via