feat(core): add Deck#waitForFrameReady() Promise API#10362
Draft
akre54 wants to merge 1 commit into
Draft
Conversation
Adds a public method on the Deck class that resolves once all pending
updates have settled and a frame has been rendered. Useful for headless
capture, video export, and any flow that needs to know the next canvas
read will reflect a fully-settled scene.
Settled means:
- All layers report `layer.isLoaded === true`
- LayerManager.needsUpdate() returns false
- Deck.needsRedraw() returns false
- An onAfterRender cycle has completed since the call started
(skipped when the scene is already settled at call time)
Options:
- timeout (default 5000 ms): rejects with an Error if exceeded
- checkLayers (default true): include the per-layer isLoaded check
- checkAttributes (default true): include the LayerManager.needsUpdate check
The implementation chains a one-shot frame-completion handler over the
user-provided onAfterRender and restores the original handler before
resolving or rejecting, so existing render hooks continue to fire.
Motivating use case: noodles.gl video export currently relies on a
"skip first render + 16ms timeout" heuristic to avoid stale data; a
deterministic Promise API lets the exporter wait for actual readiness.
Tests cover the happy path, async-data settle, timeout rejection,
checkLayers=false escape hatch, the not-initialized error case, and
that the user-provided onAfterRender is preserved across the wait.
This was referenced Jun 10, 2026
Open
| * A Promise that resolves with an object describing the final state: | ||
| + `layersReady` (boolean) - whether all layers reported loaded | ||
| + `attributesReady` (boolean) - whether the attribute manager reported settled | ||
| + `duration` (number) - elapsed time in milliseconds |
Collaborator
There was a problem hiding this comment.
Do the majority of applications need duration? Can't they measure this trivially if they want it?
| If the deadline passes before the scene settles, the Promise rejects with an `Error`. | ||
|
|
||
| ```ts | ||
| const result = await deck.waitForFrameReady({timeout: 5000}); |
Collaborator
There was a problem hiding this comment.
This is a good pattern, but I don't see why this needs to be a part of deck's API.
Wouldn't a utility function with deck as a parameter be just as effective?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a waitForFrameReady() Promise API to Deck for detecting when a frame is safe to capture during sequential rendering (video export, image sequences, headless rendering).
Motivation
When exporting video from deck.gl applications (e.g., noodles.gl), detecting when a frame is "ready to capture" is critical for correctness. The existing onAfterRender callback fires after GPU command submission but doesn't wait for:
This leads to captured frames with stale/incomplete data. Polling onAfterRender with debounced timeouts works but is slow (~300ms per frame). This PR adds a deterministic signal for frame readiness, achieving 8.6× faster video export (308ms→36ms/frame) in noodles.gl.
API
Resolves when:
Rejects if timeout is reached before the above conditions are met.
Usage Example
Implementation Details
Tests
6 new tests in test/modules/core/lib/deck.spec.ts:
All 27 deck.spec.ts tests pass. All 272 core module tests pass.
Performance
Less than 1ms overhead per frame when layers are already loaded (single RAF + state check).
Limitations
Does not check for in-progress animations (layer transitions, viewport easing). For video export use cases, disable animations:
Or use the onFrameComplete callback (#10361) which provides animationsInProgress flag.
Breaking Changes
None - purely additive API.
Related PRs
Companion MapLibre PRs
Benchmarks
Tested in noodles.gl video export (30fps, 100 frames, cached tiles):
Co-authored-by: Claude Sonnet 4.5 noreply@anthropic.com