[GH-ISSUE #775] WSL2: TUI frame stalls when system clock jumps backward (Date.now/setTimeout scheduling) #980

Open
opened 2026-03-14 09:11:47 +03:00 by kerem · 1 comment
Owner

Originally created by @turazashvili on GitHub (Mar 4, 2026).
Original GitHub issue: https://github.com/anomalyco/opentui/issues/775

Summary

On WSL2, the TUI intermittently freezes for ~2–10 seconds while typing or scrolling.
This appears to happen when wall-clock time jumps backward (e.g. host/guest time sync interactions in WSL).
Renderer scheduling currently relies on Date.now() + delayed setTimeout, which is sensitive to non-monotonic clock changes.

Environment

Observed behavior

  • During normal interaction (typing/scrolling), UI occasionally stalls for several seconds.
  • Stall resolves on its own; then interaction resumes.
  • Reproducible in WSL2, not observed the same way on native Linux/macOS in my tests.

Why this likely happens

Frame timing appears to use wall-clock (Date.now) and one-shot delayed setTimeout.
If wall-clock moves backward, delay calculations can become effectively “too far in the future,” causing visible render stalls.

Local workaround that resolves it

I patched @opentui/core locally and the freezes disappeared by:

  1. Using monotonic clock (performance.now()) for frame timing
  2. Replacing delayed one-shot setTimeout(..., delay) with a deadline loop:
    • deadline = performance.now() + delay
    • setImmediate(check) until performance.now() >= deadline, then render/loop
  3. Clearing scheduled handles with clearImmediate(...)

Proposed source-level change (renderer)

In packages/core/src/renderer.ts:

  • Use performance.now() in:
    • startRenderLoop()
    • requestRender()
    • loop()
  • Update renderTimeout type to ReturnType<typeof setImmediate> | null
  • Replace delayed setTimeout frame scheduling with setImmediate + deadline check
  • Use clearImmediate consistently for renderTimeout

Notes

I can help validate a test/canary build on WSL2 once a patch is available.

Originally created by @turazashvili on GitHub (Mar 4, 2026). Original GitHub issue: https://github.com/anomalyco/opentui/issues/775 ### Summary On WSL2, the TUI intermittently freezes for ~2–10 seconds while typing or scrolling. This appears to happen when wall-clock time jumps backward (e.g. host/guest time sync interactions in WSL). Renderer scheduling currently relies on `Date.now()` + delayed `setTimeout`, which is sensitive to non-monotonic clock changes. ### Environment - OS: Windows + WSL2 - Distro: Ubuntu (WSL2) - Runtime: Bun - Consumer app: opencode (uses `@opentui/core`) - Related reports: - https://github.com/anomalyco/opencode/issues/5361 - https://github.com/microsoft/WSL/issues/11790 ### Observed behavior - During normal interaction (typing/scrolling), UI occasionally stalls for several seconds. - Stall resolves on its own; then interaction resumes. - Reproducible in WSL2, not observed the same way on native Linux/macOS in my tests. ### Why this likely happens Frame timing appears to use wall-clock (`Date.now`) and one-shot delayed `setTimeout`. If wall-clock moves backward, delay calculations can become effectively “too far in the future,” causing visible render stalls. ### Local workaround that resolves it I patched `@opentui/core` locally and the freezes disappeared by: 1. Using monotonic clock (`performance.now()`) for frame timing 2. Replacing delayed one-shot `setTimeout(..., delay)` with a deadline loop: - `deadline = performance.now() + delay` - `setImmediate(check)` until `performance.now() >= deadline`, then render/loop 3. Clearing scheduled handles with `clearImmediate(...)` ### Proposed source-level change (renderer) In `packages/core/src/renderer.ts`: - Use `performance.now()` in: - `startRenderLoop()` - `requestRender()` - `loop()` - Update `renderTimeout` type to `ReturnType<typeof setImmediate> | null` - Replace delayed `setTimeout` frame scheduling with setImmediate + deadline check - Use `clearImmediate` consistently for `renderTimeout` ### Notes I can help validate a test/canary build on WSL2 once a patch is available.
Author
Owner

@turazashvili commented on GitHub (Mar 8, 2026):

@simonklee is there anyone working on this? I saw closed PR. If this is relevant, I can push PR in the next couple days :)

<!-- gh-comment-id:4019109373 --> @turazashvili commented on GitHub (Mar 8, 2026): @simonklee is there anyone working on this? I saw closed PR. If this is relevant, I can push PR in the next couple days :)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/opentui#980
No description provided.