Skip to content

perf: introduce FpsScheduler for independent UI and network queues#7418

Merged
mimecuvalo merged 5 commits intomainfrom
mime/120fps-x2
Jan 14, 2026
Merged

perf: introduce FpsScheduler for independent UI and network queues#7418
mimecuvalo merged 5 commits intomainfrom
mime/120fps-x2

Conversation

@mimecuvalo
Copy link
Copy Markdown
Member

@mimecuvalo mimecuvalo commented Dec 17, 2025

once more with feeling. the previous attempts were trying to put schedule UI and network events on the same queue, which ... I don't know what we were thinking :P
Anyway, this creates a proper FpsScheduler class that can take different target rates which solves the issues we were seeing. But also, it solves the fact that even without the 120fps change, we shouldn't be combining these queues.

I recommend reviewing this PR with "hide whitespace" on. you'll note that it had less changes than you would expect. it's really more about just creating a JS class to encapsulate the throttle queue.

this lays the groundwork for the child PR here that does the network bit of this: #7657

previous PRs: #6868 to #6470

Change type

  • bugfix
  • improvement
  • feature
  • api
  • other

Test plan

  • Unit tests (if present)
  • End to end tests (if present)

Release notes

  • Improved performance by separating UI and network scheduling queues.

API changes

  • adds FpsScheduler to be able to create a FPS-throttled queue of functions to execute

Note

Introduce per-instance FPS scheduling

  • Add FpsScheduler class in lib/throttle with its own queue/state and configurable target FPS; create a default 120fps instance and have fpsThrottle/throttleToNextFrame delegate to it
  • Export FpsScheduler from utils (src/index.ts); update API report accordingly
  • Add comprehensive unit tests (lib/throttle.test.ts) covering throttling, next-frame batching, cancelation, and real-world scenarios
  • UI tweak: DefaultDebugPanel FPS readout now includes maxKnownFps (FPS ${fps} (max: ${maxKnownFps}))

Written by Cursor Bugbot for commit 871ad95. This will update automatically on new commits. Configure here.

@huppy-bot huppy-bot bot added the improvement Product improvement label Dec 17, 2025
@vercel
Copy link
Copy Markdown

vercel bot commented Dec 17, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
analytics Ready Ready Preview Jan 12, 2026 5:10pm
examples Ready Ready Preview Jan 12, 2026 5:10pm
4 Skipped Deployments
Project Deployment Review Updated (UTC)
chat-template Ignored Ignored Preview Jan 12, 2026 5:10pm
tldraw-docs Ignored Ignored Preview Jan 12, 2026 5:10pm
tldraw-shader Ignored Ignored Preview Jan 12, 2026 5:10pm
workflow-template Ignored Ignored Preview Jan 12, 2026 5:10pm

@huppy-bot
Copy link
Copy Markdown
Contributor

huppy-bot bot commented Dec 17, 2025

API Changes Check Passed

Great! The PR description now includes the required "### API changes" section. This helps reviewers and SDK users understand the impact of your changes.

@steveruizok
Copy link
Copy Markdown
Collaborator

Could you separate the "solo mode" improvements from the "120fps tick" improvements? The 120fps change is going to produce some problems across different browsers and may require us to change the way that we handle draw shapes. (Same bugs we ran into last few times we tried this, or with coalescing). But I would love to save the CPU cost of "syncing with myself" when working alone on tldraw.com.

@steveruizok steveruizok added the sdk Affects the tldraw sdk label Jan 2, 2026
@steveruizok steveruizok changed the title perf: UI speed ⬆️ 120fps; solo network mode ⬇️ 1fps perf: introduce FpsScheduler for independent UI and network queues Jan 2, 2026
@vercel vercel bot temporarily deployed to Preview – workflow-template January 8, 2026 17:10 Inactive
@vercel vercel bot temporarily deployed to Preview – chat-template January 8, 2026 17:10 Inactive
@vercel vercel bot temporarily deployed to Preview – tldraw-shader January 8, 2026 17:10 Inactive
@mimecuvalo
Copy link
Copy Markdown
Member Author

Could you separate the "solo mode" improvements from the "120fps tick" improvements? The 120fps change is going to produce some problems across different browsers and may require us to change the way that we handle draw shapes. (Same bugs we ran into last few times we tried this, or with coalescing). But I would love to save the CPU cost of "syncing with myself" when working alone on tldraw.com.

sounds good 👍

@MitjaBezensek @steveruizok i moved the solo mode changes into a separate PR (child branch of this PR): #7657

// eslint-disable-next-line no-restricted-globals
frameRaf = requestAnimationFrame(() => {
frameRaf = undefined
tick(true)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zero FPS causes infinite RAF loop and blocked queue

Medium Severity

When targetFps is 0, getTargetTimePerFrame(0) returns Infinity (from 1000/0). After the first flush sets lastFlushTime to a normal timestamp, subsequent tick() calls will always find elapsed < Infinity is true, causing an infinite requestAnimationFrame loop. Queued functions will never execute, and the scheduler will continuously consume resources. The @public class lacks validation in both the constructor and updateTargetFps to prevent zero or negative FPS values.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor

@MitjaBezensek MitjaBezensek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Left a few smaller comments.

@MitjaBezensek MitjaBezensek mentioned this pull request Jan 13, 2026
1 task
@mimecuvalo mimecuvalo added this pull request to the merge queue Jan 14, 2026
Merged via the queue into main with commit ce745d1 Jan 14, 2026
16 checks passed
@mimecuvalo mimecuvalo deleted the mime/120fps-x2 branch January 14, 2026 11:40
@random-yang
Copy link
Copy Markdown

Does this mean I can unlock the 120 Hz TLdraw canvas experience?

@mimecuvalo
Copy link
Copy Markdown
Member Author

Does this mean I can unlock the 120 Hz TLdraw canvas experience?

Yes, this will be available in the SDK in the next release.
This will be available on tldraw.com in a week or so.

github-merge-queue bot pushed a commit that referenced this pull request Jan 21, 2026
parent PR: #7418
this makes just the solo mode change for better network usage.

### Change type

- [ ] `bugfix`
- [x] `improvement`
- [ ] `feature`
- [ ] `api`
- [ ] `other`

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Optimizes network scheduling and reduces solo-mode traffic by using a
dedicated FPS-based scheduler.
> 
> - Introduces `FpsScheduler` instance in `TLSyncClient` to throttle
network operations independently of UI
> - Adds dynamic sync rates: `SOLO_MODE_FPS = 1`,
`COLLABORATIVE_MODE_FPS = 30`; updates target FPS based on
`presenceMode`
> - Replaces `fpsThrottle` with `fpsScheduler.fpsThrottle` for
`flushPendingPushRequests` and `scheduleRebase`
> - Adds `getSyncFps()` and calls `updateTargetFps` during presence
reactions; minor debug log on push send
> - Removes old `fpsThrottle`-based implementations
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
2f029e7. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Product improvement sdk Affects the tldraw sdk

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants