HyperFrames
HyperFrames source walkthrough: same-time seeks and GPU completion
Read the GSAP adapter and shared seek dispatcher at a fixed commit, compare their tests, and understand why a duplicate timestamp sometimes needs a forced render.
What you will learn
- GSAP receives a suppressed adjustment before an exact same-time seek.
- The dispatcher deduplicates against the last value, not an elapsed-time window.
- Promise registration must be synchronous even when completion is asynchronous.
Before you start
- Basic HTML, CSS and JavaScript
- Node.js 22+ and FFmpeg for the local exercise
Explain the chapter boundary and use its checklist to evaluate a repeatable video workflow.
Key takeaways
- GSAP receives a suppressed adjustment before an exact same-time seek.
- The dispatcher deduplicates against the last value, not an elapsed-time window.
- Promise registration must be synchronous even when completion is asynchronous.
Pin a small reading route
This walkthrough uses commit 0d5d3f3eb3aecd9fd64954d2767d3d64e97e58fc and the runtime adapter files gsap.ts, seek-dispatch.ts and their tests. Start with the concrete question: what happens when the renderer asks for the same time twice? A focused question is more useful than describing a large repository tree without following behavior.
createGsapAdapter returns early when no timeline exists. Otherwise seek pauses the timeline and prefers totalTime when available. It calls totalTime once at the target plus 0.001 with events suppressed, then again at the target with the requested event policy. The comment explains that the adjustment forces a dirty state when GSAP would otherwise skip an unchanged time.
Compare ordinary dispatch with forced dispatch
dispatchSeekEvent stores the last dispatched time and suppresses a consecutive identical value. forceDispatchSeekEvent updates that stored value but dispatches regardless. The inspected tests cover ordinary deduplication, forced repetition and ordinary deduplication immediately after a forced event. This makes the difference between these two functions directly visible.
The module comment describes same-stack duplicate calls as the motivation, but the implementation does not reset the stored time on a microtask or timer boundary. Its concrete guard is equality with the last dispatched value. Do not infer a broader scheduling guarantee from the comment alone; test any behavior that depends on time passing between calls.
Follow completion and failure, not only the event count
An hf-seek listener must call detail.waitUntil synchronously while dispatch is accepting registrations. The registered promise may finish later. The dispatcher groups that work, retains a rejection and exposes waitForSeekCompletion to drain pending generations. A listener that registers only after an await is outside the accepted registration window.
The upstream tests include overlapping generations, work added while a capture wait is active, and rejection observed by concurrent barriers. Read those cases alongside the loop and retained-failure variable. This article inspected their source but did not run the upstream test suite. The small sequence below is a reading exercise, not a claim that browser capture was measured.
Implementation steps
- 1
Read gsap.ts with gsap.test.ts at the fixed commit.
- 2
Compare dispatchSeekEvent and forceDispatchSeekEvent.
- 3
Trace synchronous waitUntil registration into pending completions.
- 4
Read rejection and concurrent-barrier tests before designing an extension.
Copy-ready example
dispatchSeekEvent(4) -> one event
dispatchSeekEvent(4) -> no new event
forceDispatchSeekEvent(4) -> another event
dispatchSeekEvent(4) -> no new event
During the event: register promise with detail.waitUntil(promise).
After dispatch: waitForSeekCompletion() observes completion or failure.Frequently asked questions
Does ordinary deduplication expire on the next event-loop turn?
No such reset appears in the inspected implementation. It compares the requested time with the stored last value.
May a listener await before calling waitUntil?
The registration must occur synchronously during dispatch. The promise registered at that point may itself complete asynchronously.
Sources
- Fixed READMESource checked 2026-09-07
- GSAP adapterSource checked 2026-09-07
- Seek dispatcherSource checked 2026-09-07
- Three.js adapterSource checked 2026-09-07
- GSAP testsSource checked 2026-09-07
- Seek dispatcher testsSource checked 2026-09-07