perf: increase target rate to 120fps and add dynamic throttling#6868
perf: increase target rate to 120fps and add dynamic throttling#6868MitjaBezensek merged 8 commits intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
4 Skipped Deployments
💡 Enable Vercel Agent with $100 free credit for automated AI reviews |
|
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. |
|
🤖 Claude Code Review SummaryThis PR increases the target FPS from 60 to 120 and adds dynamic FPS throttling based on presence mode ('solo' vs collaborative). The browser will naturally throttle via requestAnimationFrame based on display capabilities. Code Quality ✅Strengths:
Areas for Improvement: 1. Logic Issue: Duplicate Timing Checks
|
Browser will throttle us on screens that can suport it (raf won't run more often than the device supports).
ebae44a to
5eae162
Compare
We double checked whether they should be called.
|
🤖 Claude Code Review SummaryThis PR increases the target frame rate from 60fps to 120fps and adds custom FPS throttling capabilities to fpsThrottle(). The changes allow high-refresh-rate devices to benefit from smoother updates while maintaining backwards compatibility. Code Quality and Best PracticesPositive Aspects
Issues and Concerns1. Logic Bug: Premature timing update The custom FPS timing is updated BEFORE the function is queued, not when it actually runs. If the function gets queued but doesn't execute immediately, the timing will be inaccurate. The next call could be rejected even though the function hasn't actually run yet. Recommendation: Update the timestamp AFTER the function executes, within the flush() function. 2. Mixed throttling strategies
Functions with custom FPS are checked twice. Is this intentional? A function with getTargetFps() = 1 could still run up to 120 times per second if called frequently enough. 3. Performance consideration Test CoverageNo tests found for the fpsThrottle function or these changes. Recommendations:
ConclusionThe change addresses a real UX improvement for high-refresh-rate displays. However, there is a timing logic bug that should be fixed before merging. The implementation also introduces complexity with dual throttling that deserves clearer documentation. Recommendation: Request changes to fix timing update logic and add test coverage. |
|
🤖 Claude Code Review SummaryThis PR increases the target FPS from 60 to 120 and adds custom per-function FPS throttling capabilities. The changes are well-structured and the implementation appears sound for supporting high refresh rate displays. Code Quality ✅Strengths:
Minor concerns:
Performance Considerations
|
53216b8 to
ac6ba44
Compare
|
🤖 Claude Code Review SummaryThis PR bumps the target frame rate from 60fps to 120fps and adds adaptive throttling for network sync operations. The changes are well-structured, but there are a few concerns to address. Code Quality & Architecture✅ Strengths
|
mimecuvalo
left a comment
There was a problem hiding this comment.
nice! i'm down with this change.
- nit: can we also pull the change from #6470 that updates
DefaultDebugPanel.tsx? - does this work as expected on iOS?
|
|
||
| /** Get the target FPS for network operations based on presence mode */ | ||
| private getSyncFps(): number { | ||
| return this.presenceMode?.get() === 'solo' ? SOLO_MODE_FPS : COLLABORATIVE_MODE_FPS |
There was a problem hiding this comment.
nice, much clearer than my version!
packages/utils/src/lib/throttle.ts
Outdated
| const targetFps = 60 | ||
| const targetTimePerFrame = Math.floor(1000 / targetFps) * 0.9 // ~15ms - we allow for some variance as browsers aren't that precise. | ||
| const targetFps = 120 | ||
| const targetTimePerFrame = Math.floor(1000 / targetFps) * 0.9 // ~7ms - we allow for some variance as browsers aren't that precise. |
There was a problem hiding this comment.
actually, is the 0.9 still necessary? i'm forgetting a bit on why this was needed... let's expand the comment if we still need this, we're gonna forget again in the future why we did this 🙃
There was a problem hiding this comment.
Added a comment here.
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| 🔵 In progress View logs |
multiplayer-template | a0a5622 | Oct 20 2025, 08:30 AM |
|
woo woo! 🎉 |
This reverts commit 2e5f9f2.
This reverts commit 2e5f9f2. ### API changes - Revert the 120 fps changes. ### Change type - [x] `bugfix` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Standardizes throttling to 60fps (removing custom/120fps logic), updates TLSyncClient scheduling, simplifies FPS debug display, and adjusts the utils API. > > - **Utils**: > - Reverts `fpsThrottle` to fixed 60fps; removes custom FPS support and related state. > - Updates docs/comments and `throttleToNextFrame` to reference 60fps. > - API change: `fpsThrottle(fn)` no longer accepts `getTargetFps`. > - **Sync Core** (`packages/sync-core/src/lib/TLSyncClient.ts`): > - Removes dynamic sync FPS logic (`SOLO_MODE_FPS`, `COLLABORATIVE_MODE_FPS`, `getSyncFps`). > - `flushPendingPushRequests` and `scheduleRebase` now use `fpsThrottle()` without FPS getter. > - **UI** (`packages/tldraw/src/lib/ui/components/DefaultDebugPanel.tsx`): > - Simplifies FPS output to `FPS <current>` (removes max FPS display). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c9995c0. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This reverts commit 2e5f9f2. ### API changes - Revert the 120 fps changes. ### Change type - [x] `bugfix` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Standardizes throttling to 60fps (removing custom/120fps logic), updates TLSyncClient scheduling, simplifies FPS debug display, and adjusts the utils API. > > - **Utils**: > - Reverts `fpsThrottle` to fixed 60fps; removes custom FPS support and related state. > - Updates docs/comments and `throttleToNextFrame` to reference 60fps. > - API change: `fpsThrottle(fn)` no longer accepts `getTargetFps`. > - **Sync Core** (`packages/sync-core/src/lib/TLSyncClient.ts`): > - Removes dynamic sync FPS logic (`SOLO_MODE_FPS`, `COLLABORATIVE_MODE_FPS`, `getSyncFps`). > - `flushPendingPushRequests` and `scheduleRebase` now use `fpsThrottle()` without FPS getter. > - **UI** (`packages/tldraw/src/lib/ui/components/DefaultDebugPanel.tsx`): > - Simplifies FPS output to `FPS <current>` (removes max FPS display). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c9995c0. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This is an automated hotfix for dotcom deployment. Original PR: #6985 Original Author: @MitjaBezensek
…7418) 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` - [x] `improvement` - [ ] `feature` - [ ] `api` - [ ] `other` ### Test plan - [x] 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 <!-- CURSOR_SUMMARY --> --- > [!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})`) > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 871ad95. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
* Add VSCode extension v2.129.0 [skip ci] * embeds: fix replit if it has a hash present (#6892) if a Replit URL is like: https://replit.com/@omar/Blob-Generator#index.html it was failing. before: `https://replit.com/@omar/Blob-Generator#index.html?embed=true` after: `https://replit.com/@omar/Blob-Generator?embed=true#index.html` ### Change type - [x] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [ ] `other` ### Test plan - [x] Unit tests - [ ] End to end tests ### Release notes - embeds: fix replit if it has a hash present * license: record sku in watermark ping (#6902) ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` * a11y: fix up togglegroup warning for shared state (#6904) fix up warning in console, this happens when selecting multiple shapes, some that don't have a `size` property set. <img width="2594" height="998" alt="Screenshot 2025-10-09 at 12 17 55" src="https://github.com/user-attachments/assets/1e36e023-3eef-4d48-93fc-f01be0536cb0" /> ### Change type - [x] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [ ] `other` ### Release notes - a11y: fix up togglegroup warning for shared state * Stop agent prompting when agent is stopped (via stop button) (#6901) Fixed a bug in the AI Agent template where stopping the agent was not possible if there are open items on the todo list ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` ### Test plan 1. Prompt the AI agent 2. make sure there are multiple items in the todo list 3. hit the `stop` button 4. -> agents doesnt stop without the fix in this PR - [ ] Unit tests - [ ] End to end tests ### Release notes - Fixed a bug in the AI Agent template where stopping the agent was not possible if there are open items on the todo list Co-authored-by: Lu Wilson <[email protected]> * claude: fix deleting old comments (#6914) Describe what your pull request does. If you can, add GIFs or images showing the before and after of your change. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` * claude: actually do the removal in a separate step (#6915) followup to https://github.com/tldraw/tldraw/pull/6914 ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` * claude: update PR perms to write (#6916) once more, w feeling ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` * Fix convert-to-bookmark action (#6894) Consolidated the logic we use for pasting and the conversion action, and exposed it as a helper function for our users. ### Change type - [x] `bugfix` ### API Changes - Added `createBookmarkFromUrl` helper function for creating bookmark shapes more easily. * Improve agent: better bends, better arrows, don't stay inside the viewport (#6898) This PR improves the agent based on some feedback. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` ### Test plan 1. Create a shape... 2. - [ ] Unit tests - [ ] End to end tests ### Release notes - We made the agent better at bending and attaching arrows. - We made the agent free to manipulate the canvas outside its viewport. * Fix broken ink on iOS by disabling coalesced events (#6917) ## Summary - Fixes ink/drawing issues on iOS by disabling coalesced pointer events on that platform - iOS sometimes doesn't have `getCoalescedEvents` available, causing broken drawing behavior - Adds platform check to only use coalesced events when not on iOS ## Changes Modified `packages/editor/src/lib/hooks/useCanvasEvents.ts:166`: - Added `!tlenv.isIos` check before using coalesced events - This prevents attempting to use `getCoalescedEvents()` on iOS devices where it may be unreliable ## Test plan - [ ] Test drawing/ink tool on iOS devices - [ ] Verify drawing works smoothly without breaks - [ ] Ensure drawing still works correctly on other platforms (desktop, Android) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Mime Čuvalo <[email protected]> * Remove excalidraw embed definition, it doesn't support collaboration inside iframes (#6897) Excalidraw stopped supporting collaboration inside iframes (pr for this is [here](https://github.com/excalidraw/excalidraw/pull/6646)) which means nothing syncs between the iframe inside the tldraw canvas and your excalidraw room. This removes the usefulness of this particular embed, so lets remove it. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` ### API changes - Removed the excalidraw embed ### Release notes - Removed the excalidraw embed * new extract draft changelog script (#6771) Adds a new script for extracting draft changelogs. This is based entirely on my personal workflow for writing changelogs, which usually involves checking each PR anyway. So this script includes almost the entire commit message, just cleaning it up a little by removing sections and commits we don't need. ### Change type - [x] `other` --------- Co-authored-by: David Sheldrick <[email protected]> * Add marquee animation to cookie accept button (#6922) ## Summary - Added marquee animation to the "Accept all" button text in the cookie consent banner - Added slide-up animation to the cookie banner itself for a smoother entrance - Updated button styling for better visual consistency ## Changes - Wrapped button text in divs with animation classes - Added CSS keyframe animations for marquee and slide-up effects - Adjusted cookie banner entrance animation timing ## Test plan - [x] View the cookie consent banner on tldraw.com - [x] Verify the "Accept all" button text scrolls continuously - [x] Verify the banner slides up smoothly on page load - [x] Test button functionality remains intact 🤖 Generated with [Claude Code](https://claude.com/claude-code) * analytics: add consent property to identify and ui events (#6924) - add analytics_consent property to a person - add UI event when changing the consent state ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` * SDK publish: Use github release draft instead of gist (#6923) This PR makes it so we can use the github release draft system as a source of truth for upcoming release notes, instead of pasting the notes into a gist before hitting the deploy button. The SDK release will fail if there isn't a draft release notes available named after the upcoming version e.g. `v4.1.0` For patch releases nothing changes, it generates notes on its own. ### Change type - [x] `other` * Update `create-tldraw` and starter kit descriptions. (#6921) This PR: - updates the descriptions of the starter kits - gives explicit order to the starter kits - in the CLI - moves the description to a bottom line - adds some links to tldraw.dev/docs - adds a post to an endpoint on dashboard.tldraw.pro ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Steve Ruiz <[email protected]> * Swap Settings and Opt out buttons in cookie consent (#6925) ## Summary Swaps the position of the "Settings" and "Opt out" buttons in the cookie consent dialog. ## Changes - "Opt out" button now appears first (left position) - "Settings" button now appears second (middle position) - "Accept" button remains in the rightmost position ## Related Follows up on recent cookie consent UI changes (#6924, #6922) * Add custom error capture example (#6927) ## Summary Adds a new example demonstrating how to customize the `ErrorFallback` component to capture and display error information from the editor. ## Changes - New example at `apps/examples/src/examples/custom-error-capture/` - Shows how to override the `ErrorFallback` component in the `components` prop - Demonstrates using `getErrorAnnotations` to retrieve debugging information attached to errors - Displays error annotations (tags and extras) in a scrollable UI - Useful for integrating with error reporting services like Sentry ## Test plan - Run the example with `yarn dev` and navigate to `/custom-error-capture` - Click the "Throw an error" button to trigger the custom error fallback - Verify the custom error screen displays with error message and annotations 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Add slide-in and marquee animations to analytics cookie banner (#6929) ## Summary Adds slide-in and marquee text animations to the analytics cookie banner, matching the animations used in the dotcom client (#6925, #6927). ## Changes - **Slide-in animation**: Banner slides up from bottom over 5 seconds with 2-second delay - **Marquee animation**: "Accept all" button text scrolls continuously - **Accessibility**: Respects `prefers-reduced-motion` setting to disable animations for users with motion sensitivity - **Preview HTML**: Added `index.html` for local development testing ## Implementation Details - Slide-in uses `translateY(100%)` → `translateY(0)` with 5s ease-in-out timing - Marquee uses `translateX(100%)` → `translateX(-100%)` in a 3s infinite loop - Animations match dotcom client cookie consent styling - `@media (prefers-reduced-motion: reduce)` disables both animations for accessibility ## Accessibility When users have "Reduce motion" enabled in their browser or OS settings: - Cookie banner appears immediately without slide-in animation - Button text remains stationary without marquee scrolling ## Test plan 1. Run `cd apps/analytics && yarn dev` 2. Visit http://localhost:5173/ 3. Verify banner slides in after 2 second delay 4. Verify "Accept all" button text marquee scrolls 5. Enable "Reduce motion" in browser/OS settings and verify animations are disabled 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]> * dotcom hotfix sdk release infra (#6926) adds some infra we're gonna need for tomorrow to dotcom. will merge in the morning ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` --------- Co-authored-by: alex <[email protected]> * Add VSCode extension v2.130.0 [skip ci] * Add option to pass callback to onInteractionEnd (#6919) Simplifies and standardizes the logic for handling onInteractionEnd across SelectTool child states by using early returns and reducing nested conditionals. This improves code readability and ensures consistent behavior when transitioning between tool states (picked up from @steveruizok commit). Lets ship this change in a separate PR from the https://github.com/tldraw/tldraw/pull/6908. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [x] `api` - [ ] `other` ### Release notes - Add an option to add `onInteractionEnd` callback instead of passing a tool state string --------- Co-authored-by: Steve Ruiz <[email protected]> * Add shader starter kit to docs (#6928) This PR adds the shader starter kit to the docs site. Still in progress: Deploying the starter kit. Don't hotfix until that's done. See project: https://www.notion.so/tldraw/Starter-kit-Shader-2783e4c324c080dbbaf4f8f61183556c ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Lu Wilson <[email protected]> Co-authored-by: Steve Ruiz <[email protected]> * [HOTFIX] Add shader starter kit to docs (#6931) This is an automated hotfix PR for dotcom deployment. **Original PR:** [#6928](https://github.com/tldraw/tldraw/pull/6928) **Original Title:** Add shader starter kit to docs **Original Author:** @TodePond This PR cherry-picks the changes from the original PR to the hotfixes branch for immediate dotcom deployment. /cc @TodePond <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds the Shader starter kit documentation and updates the starter kits overview to include it. > > - **Docs**: > - **New page**: `apps/docs/content/starter-kits/shader.mdx` documenting the Shader starter kit, usage, examples, and resources. > - **Overview update**: `apps/docs/content/starter-kits/overview.mdx` adds `Shader` entry with description and use cases. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit ef8646b3d80a3d8454918a44e05a07e0c5a7e60b. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Lu Wilson <[email protected]> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Lu Wilson <[email protected]> Co-authored-by: Steve Ruiz <[email protected]> * Add VSCode extension v2.131.0 [skip ci] * Add tldraw SDK promo link to sidebar (#6930) ## Summary Adds a promotional link to the tldraw SDK in the sidebar. <img width="572" height="303" alt="image" src="https://github.com/user-attachments/assets/ea34c9ca-6d27-4418-96df-f79fa649ac8b" /> ## Test plan - Verify the link appears in the sidebar - Verify the link points to the correct destination 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds a dismissible "Build with the tldraw SDK" link in the sidebar with i18n and styles, and adds a safety check for extra applied migrations in the replicator. > > - **Frontend (Sidebar)** > - **New promo link**: Adds `TlaSidebarDotDevLink` with external link to `https://tldraw.dev`, shown in `TlaSidebar` bottom area; dismissible via `useLocalStorageState('showDotDevLink')`. > - **i18n**: Adds `"Build with the tldraw SDK"` string in `public/tla/locales*.json` under key `95d2109dc8`. > - **Styles**: Introduces `.sidebarDotDevLink` and `.sidebarDotDevDismissButton` in `sidebar.module.css`. > - **Backend (Replicator)** > - **Migration validation**: In `replicatorMigrations.ts`, throws if there are more applied migrations than defined, with counts and offending `id`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f9fb75469b55cf1fef2d01ec026332854355de7e. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude <[email protected]> * Refactor shader template CSS class names for consistency (#6932) ## Summary Fixed missing / wrong styles on the config panel. Refactored CSS class names in the shader template to follow a more consistent BEM-like naming convention, improving maintainability and clarity. ## Changes - Updated all shader-related CSS classes to use consistent prefixes: - `shader-app__*` for app-level components - `shader-config-panel__*` for config panel components - Adopted BEM-style modifiers with `--` separator (e.g., `shader-app__canvas--pixelated`) - Applied naming convention across all files: - App.tsx: `shader-example-toggle` → `shader-app__example-menu` - WebGLCanvas.tsx: `shader-canvas` → `shader-app__canvas` - ConfigPanel.tsx: `shader-config-header/content` → `shader-config-panel__header/content` - ConfigPanelBooleanControl.tsx: `shader-boolean-control/input` → `shader-config-panel__control--boolean` and `shader-config-panel__boolean-input` - ConfigPanelSlider.tsx: `shader-slider-container` → `shader-config-panel__control--slider` - ConfigPanelLabel.tsx: `shader-panel-label` → `shader-config-panel__label` - Updated documentation in config-panel.md to reflect new class names - Improved CSS organization and structure ## Test plan - [x] Verified shader template still renders correctly - [x] Confirmed config panel functionality works as expected - [x] Checked both expanded and collapsed states - [x] Tested all control types (sliders, booleans) 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Renames shader CSS classes to a consistent BEM scheme and updates components, styles, and docs accordingly. > > - **UI Components**: > - `templates/shader/src/App.tsx`: `shader-example-toggle` → `shader-app__example-menu`. > - `templates/shader/src/WebGLCanvas.tsx` and `templates/shader/src/fluid/FluidRenderer.tsx`: `shader-canvas` → `shader-app__canvas` with `--pixelated` modifier. > - Config panel components (`ConfigPanel.tsx`, `ConfigPanelSlider.tsx`, `ConfigPanelBooleanControl.tsx`, `ConfigPanelLabel.tsx`): migrate to `shader-config-panel__*` classes (header, content, reset button, toggle, control variants, label). > - **Styles (`shader.css`)**: > - Introduce `.shader-app` container; rename selectors to `shader-app__*` and `shader-config-panel__*`. > - Add `shader-app__canvas--pixelated` modifier; update example menu class. > - Adjust config panel layout (max-height calc, padding, control heights) and simplify selector nesting. > - **Docs**: > - `config-panel.md`: update class names list and example canvas class to `shader-app__canvas`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 1e00f8dbccfcb6abb78a9f8079957f4bd592db55. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * [automated] update i18n strings (#6933) This PR updates the i18n strings. ### Change type - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Updates and expands i18n strings across numerous locales (new actions, tools, menus, accessibility, media/image, navigation, toasts, etc.), plus a minor README list formatting fix. > > - **i18n/localization**: > - Add and expand translation keys across many locales (actions, accessibility, menus, input modes, navigation/minimap, tools, image/media crop/alt text/zoom/replace, rotate/resize handles, text formatting, keyboard shortcuts, toasts, statuses, arrow kinds, shapes, style panel, UI states). > - Include new strings for toggle options (mouse/trackpad/auto-pan/auto-zoom), enhanced accessibility mode, and avatar color. > - **Docs**: > - Fix ordered list formatting in `templates/workflow/README.md`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 4d1fc1d5622af448fabcf6a02328db103613b1a9. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com> Co-authored-by: Mime Čuvalo <[email protected]> * Refactor style panel pickers for inline variants (#6920) Introduces inline variants for StylePanelButtonPicker, StylePanelDropdownPicker, and StylePanelDoubleDropdownPicker to improve composability and UI flexibility. Updates usage in DefaultStylePanelContent and adjusts exports and internal structure for better separation between toolbar-wrapped and inline picker components. The bug was that several components included <TldrawUiToolbar> wrappers, but were included in other rows that also include <TldrawUiToolbar> wrappers. Nesting these would cause the bug. An alternative solution (and a better one, though breaking) would be for the "inline" variants shared here to be the default, and for the <TldrawUiToolbars> to be provided where the components are used. <img width="307" height="731" alt="image" src="https://github.com/user-attachments/assets/2ce4b6c3-4ffd-43b8-9b08-c92a894f3e9b" /> ### Change type - [x] `bugfix` - [ ] `improvement` - [ ] `feature` - [x] `api` - [ ] `other` ### Test plan 1. Create lines and text shapes and geo shapes 2. Zoom out to 90% in the browser 3. Toolbar items should not wrap ### API changes - Adds `StylePanelButtonPickerInline`, `StylePanelDoubleDropdownPickerInline`, and `StylePanelDropdownPickerInline`. Use these components inside of `TldrawUiToolbar` components where needed. ### Release notes - Fixed a bug with the style panel * claude review: dont run in merge-queue or when merged to main (#6934) ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Add a job-level condition to skip the Claude review workflow when base or head refs contain `gh-readonly-queue`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 2417c7c0458297e1ba505aa29a229d027b7929df. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * Fix starter kit page titles (#6937) This PR fixes this: <img width="688" height="217" alt="image" src="https://github.com/user-attachments/assets/1fad1021-5ea0-4d9f-9aa3-56a5ed7fb27a" /> ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Update HTML page titles in `templates/shader` and `templates/sync-cloudflare` to reflect shader and multiplayer templates. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 87503909569db4ed0d2de59a90d9015ce9928734. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * Remove a gotcha implementation detail from `fromScratch` (#6936) This is just an internal change to remove a tricky behavior spotted by Cursor [here](https://github.com/tldraw/tldraw/pull/6739#discussion_r2431748869). empty slots are usually skipped by iteration methods so all of this works fine, see: ```ts let arr = Array(3) arr.push('foo') arr.push('bar') console.log('length', arr.length) arr.sort((a, b) => { console.log('sort', { a, b }) return a.length - b.length }) arr.forEach((v) => { console.log('forEach', { v }) }) ``` But the array is preallocated for no reason at all given the `.push` usage. In cases like that a direct index-based assignment should be used instead but it feels to me this preallocation doesn't matter anyway so I just decided to replace it with an idiomatic `Array.from` call. * [HOTFIX] Refactor shader template CSS class names for consistency (#6938) This is an automated hotfix PR for dotcom deployment. **Original PR:** [#6932](https://github.com/tldraw/tldraw/pull/6932) **Original Title:** Refactor shader template CSS class names for consistency **Original Author:** @steveruizok This PR cherry-picks the changes from the original PR to the hotfixes branch for immediate dotcom deployment. /cc @steveruizok <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Renames shader template CSS classes to a new BEM-style scheme and updates components, docs, and styles (canvas, example menu, config panel controls). > > - **UI/CSS Refactor** > - Rename shader classes to BEM-style: `shader-app__canvas` (+ `--pixelated`), `shader-app__example-menu`, `shader-config-panel__header|__content|__reset-button|__toggle|__label|__control` (+ `--slider`, `--boolean`). > - Adjust styles: panel expanded `max-height` and padding; boolean control/label layout; app container fixed positioning; remove old scoped selectors. > - **Components** > - Update class names in `App.tsx`, `WebGLCanvas.tsx`, `fluid/FluidRenderer.tsx` and config panel components (`ConfigPanel*`) to match new classes. > - **Docs** > - Update `config-panel.md` to reference new class names and canvas class in examples. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 3c7e9e1f437efcd9130674c6f7526a1cc1e6c8cf. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Steve Ruiz <[email protected]> * Add VSCode extension v2.132.0 [skip ci] * Fix dragging behavior when menu is open (#6918) ## Summary - Fixes dragging behavior when a menu overlay is open - Ensures pointer move events are properly dispatched after drag starts - Prevents duplicate pointer down events during drag sequences ## Changes The `MenuClickCapture` component now: - Tracks whether a pointer down and drag has occurred while the menu is open using a ref - Dispatches `pointer_move` events to the editor after drag starts - Only calls `onPointerDown` once when the drag threshold is exceeded - Resets the drag tracking state on pointer up This fixes an issue where dragging interactions weren't properly handled when initiated over the menu click capture overlay. ## Test plan - [ ] Open a menu in the editor - [ ] Click and drag over the canvas while the menu is open - [ ] Verify that dragging works correctly and the interaction is smooth - [ ] Verify that pointer move events are properly tracked during the drag 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Steve Ruiz <[email protected]> * More shader starter style fixes (#6940) This PR fixes various styling issues with the shader starter's config panel. - Spacing on boolean options. - Restore scrolling. - Fix tooltips. - Fix cursor on boolean options. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Show percentage on slider labels and adjust boolean control spacing/cursor in the shader config panel. > > - **Shader config panel**: > - **Slider (`templates/shader/src/config-panel/ConfigPanelSlider.tsx`)**: Display current value as a percentage in the slider label (`label` now uses `sliderValue.toFixed(0) + '%'`). > - **Boolean controls (`templates/shader/src/shader.css`)**: > - Adjust spacing: change padding to `padding-right: var(--tl-space-4)` on `.shader-config-panel__control--boolean`. > - Improve usability: add `cursor: pointer` to `.shader-config-panel__boolean-input`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 9fa66b3b3a35de3323037b2cdd1ce3cd4484ba0d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * Change everything to sentence case (#6869) This PR changes every title in the repo to sentence case. This will help agents to stick to sentence case when creating things for us. For example, agents currently like to use title case for example titles. This is annoying because you have to go back and manually change them. This PR also updates our agent style guides to remind them to stick to sentence case. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Standardizes documentation headings, UI labels, and translations to sentence case across the repo, including adding style guidance. > > - **Docs and guidelines**: > - Convert headings and section titles to sentence case across `CONTEXT.md` files, templates, and docs. > - Add explicit sentence‑case guidance in `CLAUDE.md` (writing style guidelines). > - **UI and translations**: > - Standardize UI labels/toast titles and submenu labels to sentence case in `tldraw` UI components. > - Update translation keys/values (and default translations) to sentence case (e.g., bookmark/embed, wrap mode, people menu). > - **Scope**: Widespread textual changes only; no functional logic changes. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit e65ce30a16d82664cc19046c16db24d894d81a5d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Steve Ruiz <[email protected]> * [hotfix] starter kit titles (#6941) This PR fixes this: <img width="688" height="217" alt="image" src="https://github.com/user-attachments/assets/1fad1021-5ea0-4d9f-9aa3-56a5ed7fb27a" /> - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > <sup>[Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) is generating a summary for commit d32c355d58297fa5393610a03316b01354d97839. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Lu Wilson <[email protected]> * Add VSCode extension v2.133.0 [skip ci] * Add e2e tests for cookie consent banner and sidebar dotdev link (#6939) ## Summary Adds comprehensive end-to-end tests for the cookie consent banner and sidebar dotdev link functionality, plus some related improvements. ## Changes ### New E2E Tests - **Cookie consent banner** (apps/dotcom/client/e2e/tests/cookie-consent.spec.ts): - Tests banner visibility and button presence - Verifies animations work correctly without `prefers-reduced-motion` - Verifies animations are instant with `prefers-reduced-motion` - Tests accepting cookies hides banner and persists choice in localStorage - Tests opting out hides banner and persists choice in localStorage - Tests that banner remains hidden after page reload for both scenarios - **Sidebar dotdev link** (apps/dotcom/client/e2e/tests/sidebar-dotdev-link.spec.ts): - Tests link visibility and correct href with UTM parameters - Verifies clicking opens tldraw.dev in a new tab - Tests dismiss button functionality - Verifies dismissal persists in localStorage and remains hidden after reload ### Improvements - **UTM Parameters**: Added tracking parameters to tldraw.dev links in sidebar and menu (`utm_source=dotcom&utm_medium=organic&utm_campaign=...`) - **Accessibility**: Added `aria-label="Dismiss"` to sidebar dotdev dismiss button - **Media Query Fix**: Wrapped sidebar hover styles in `@media (hover: hover)` to prevent issues on touch devices ## Test plan - Run `yarn e2e-dotcom` to verify all new tests pass - Manually test cookie consent banner on tldraw.com - Manually test sidebar dotdev link interactions 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds e2e tests for cookie consent and sidebar dotdev link, and updates UI links with UTM params plus accessibility and hover behavior tweaks. > > - **E2E tests**: > - `apps/dotcom/client/e2e/tests/cookie-consent.spec.ts`: Verify banner visibility, buttons, animation behavior (incl. `prefers-reduced-motion`), accept/opt-out persistence in `localStorage`, and hidden state after reload. > - `apps/dotcom/client/e2e/tests/sidebar-dotdev-link.spec.ts`: Verify sidebar link visibility, UTM `href`, opens in new tab, dismiss button hides and persists via `localStorage`. > - **UI updates**: > - `TlaSidebarDotDevLink.tsx`: Update link to `https://tldraw.dev?utm_source=dotcom&utm_medium=organic&utm_campaign=sidebar-link`; add `aria-label="Dismiss"` to dismiss button. > - `menu-items.tsx` (`DotDevMenuItem`): Use UTM URL `...utm_campaign=sidebar-menu`. > - `sidebar.module.css`: Scope hover animations and dismiss-button opacity changes under `@media (hover: hover)`; keep arrow animation defaults; adjust hover styles accordingly. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d331ab7a721575ce9a9f99bd72fe562e57823cdb. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * [automated] update i18n strings (#6933) (#6944) This PR updates the i18n strings. ### Change type - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Updates and expands i18n strings across numerous locales (new actions, tools, menus, accessibility, media/image, navigation, toasts, etc.), plus a minor README list formatting fix. > > - **i18n/localization**: > - Add and expand translation keys across many locales (actions, accessibility, menus, input modes, navigation/minimap, tools, image/media crop/alt text/zoom/replace, rotate/resize handles, text formatting, keyboard shortcuts, toasts, statuses, arrow kinds, shapes, style panel, UI states). > - Include new strings for toggle options (mouse/trackpad/auto-pan/auto-zoom), enhanced accessibility mode, and avatar color. > - **Docs**: > - Fix ordered list formatting in `templates/workflow/README.md`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 4d1fc1d5622af448fabcf6a02328db103613b1a9. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com> * Add VSCode extension v2.134.0 [skip ci] * Shader: Final fixes (#6943) This PR fixes: - Hidden reset button in light mode. - Non-existant CSS variable use. - Hopefully fix production-only issue where resizes don't happen on first page load. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Ensure initial canvas resize on initialization and update shader config panel styles to use tl-prefixed theme variables. > > - **WebGL**: > - Call `resize()` during `initialize()` in `templates/shader/src/WebGLManager.ts` to set canvas size before starting the animation loop. > - **Styles** (`templates/shader/src/shader.css`): > - Replace non-existent theme vars with `--tl-*` equivalents (e.g., `--tl-color-text`, `--tl-color-muted-2`). > - Adjust `.shader-config-panel` and `.shader-config-panel__header` colors/border to tl theme. > - Simplify `.shader-config-panel__reset-button` (use text color, remove background/hover styles). > - Remove `accent-color` from `.shader-config-panel__boolean-input`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d7dafc31cc3bf30101965e19065dc57226583770. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * [HOTFIX] Refactor style panel pickers for inline variants (#6920) (#6945) - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Introduces inline variants of style panel pickers and updates DefaultStylePanelContent to use them with enhanced a11y, plus exports and minor type adjustments. > > - **UI • Style Panel**: > - **Inline variants**: Add `StylePanelButtonPickerInline`, `StylePanelDropdownPickerInline`, and `StylePanelDoubleDropdownPickerInline`. > - **Refactor**: Split pickers into wrapper (with toolbar/subheading) and core inline implementations; `DefaultStylePanelContent` now uses inline variants and shows subheadings when `enhancedA11yMode` is enabled. > - **Exports/APIs**: > - Export new inline components from `src/index.ts`; API report updated accordingly. > - Adjust `StylePanelButtonPicker` return type to `React.JSX.Element`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f686e6c2e98b54e56aa46ce4a66f35ffae26db2c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Steve Ruiz <[email protected]> * [HOTFIX] More shader starter style fixes (#6942) This is an automated hotfix PR for dotcom deployment. **Original PR:** [#6940](https://github.com/tldraw/tldraw/pull/6940) **Original Title:** More shader starter style fixes **Original Author:** @TodePond This PR cherry-picks the changes from the original PR to the hotfixes branch for immediate dotcom deployment. /cc @TodePond <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Display slider value as a percentage and refine boolean control styles in the shader template. > > - **Shader UI**: > - `ConfigPanelSlider`: slider `label` now displays the current value as a percentage (e.g., `"75%"`). > - `shader.css`: adjust boolean control padding to use `padding-right` only; add `cursor: pointer` to `.shader-config-panel__boolean-input`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f579ae4c5dc003f57f00938a2bd85be74c80556d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Lu Wilson <[email protected]> Co-authored-by: David Sheldrick <[email protected]> * [HOTFIX] Shader: Final fixes (#6946) This is an automated hotfix PR for dotcom deployment. **Original PR:** [#6943](https://github.com/tldraw/tldraw/pull/6943) **Original Title:** Shader: Final fixes **Original Author:** @TodePond This PR cherry-picks the changes from the original PR to the hotfixes branch for immediate dotcom deployment. /cc @TodePond <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Call resize during WebGL initialization and update shader config panel styles to use tl color tokens with simplified button/input styling. > > - **WebGL**: > - `WebGLManager.initialize()` now calls `resize()` before starting the animation loop to ensure canvas/viewport match current size. > - **Styles**: > - Migrate shader config panel colors from `--color-*` to `--tl-color-*` (e.g., text and header border). > - Simplify `shader-config-panel__reset-button` (remove accent background/hover; use `--tl-color-text`). > - Remove `accent-color` from `shader-config-panel__boolean-input`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c265ad460ef531f28fb9adf80e2b1cda6804621a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Lu Wilson <[email protected]> * Add VSCode extension v2.135.0 [skip ci] * Bump versions to 4.1.0 [skip ci] * Add VSCode extension v2.136.0 [skip ci] * Bump versions to 4.1.1 [skip ci] * Fix fresh shader starter installs (#6947) This PR fixes the shader starter not working when you do a fresh install from `npm create tldraw@latest`. The issue was caused by the starter using decorators but we didn't have the right config for this in the exported starter itself. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` ### Release notes - Fixed fresh installs of the shader starter. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Enable TypeScript decorators for the shader template and streamline Vite config to ensure decorator support on fresh installs. > > - **Shader template**: > - **TypeScript config**: Add `"experimentalDecorators": true` in `templates/shader/tsconfig.json` to enable decorators. > - **Vite config**: Simplify `templates/shader/vite.config.ts` plugin setup to `react({ tsDecorators: true })`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 394f781e924088af77a1e81fa32fbeed32ce8e23. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * claude: omg the github api doesnt always return all comments :smh: (#6948) Describe what your pull request does. If you can, add GIFs or images showing the before and after of your change. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Enhances the GitHub Actions cleanup to delete Claude review issue comments, inline review comments, and review summaries using paginated GH API calls. > > - **CI Workflow (`.github/workflows/claude-code-review.yml`)**: > - **Cleanup step**: Replaces single delete command with paginated, scoped deletions using `gh api`. > - Deletes `issues` comments containing "🤖 Claude Code Review". > - Deletes `pulls` review comments (inline code comments). > - Deletes `pulls` review summaries. > - Introduces `PR_NUMBER` and `REPO` env vars for API calls. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 7ccfc25ed2b7446cd517158ae5857d3f111a79d3. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * tiptap v3 (#5717) This updates our TipTap usage to v3 to get the latest and greatest. - https://tiptap.dev/tiptap-editor-v3 - https://next.tiptap.dev/docs/guides/upgrade-tiptap-v2 - https://github.com/ueberdosis/tiptap/discussions/5793 ### Change type - [ ] `bugfix` - [x] `improvement` - [ ] `feature` - [ ] `api` - [ ] `other` ### Release notes - Upgrade TipTap to version 3. If you've done any customization to our standard TipTap kit, please refer to TipTap's Guide [How to upgrade Tiptap v2 to v3](https://tiptap.dev/docs/guides/upgrade-tiptap-v2) as to any breaking changes you might experience from a custom homebrew of the rich text editor in tldraw. * Groups data model (#6905) Describe what your pull request does. If you can, add GIFs or images showing the before and after of your change. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Introduce groups (group, group_user, group_file) with owningGroupId; update mutators, permissions, sync, and UI to support group ownership, pinning, and dual init modes. > > - **Data Model & Permissions**: > - Add `group`, `group_user`, `group_file` tables and `file.owningGroupId`; relax `file.ownerId` PK; new constraints, triggers, and migrations (incl. user migration function). > - Extend Zero schema, permissions, and types (incl. `TlaFlags.groups_backend`). > - **Mutators & Store**: > - New mutators: `init`, `createFile`, `pinFile`/`unpinFile`, `removeFileFromGroup`, `onEnterFile`; legacy paths kept but gated. > - Optimistic store/update behavior hardened (allow insert overwrite; no-op update guard). > - **Sync Worker & Replicator**: > - Subscribe/propagate via topic graph (user/group/file), include new tables in WAL; update history migrations and add subscription backfill migration. > - Enforce group access for file write/connect; DOs handle group ownership and session permissions. > - Full-load SQL now returns group, group_user, group_file; replay and topic building updated. > - **Client App (dotcom)**: > - TldrawApp supports groups: flags, group memberships, recent/pinned via `group_file`, canUpdateFile checks, new file creation flow, enter-file hook. > - UI updates for pin/unpin (group-aware), menus, recent files, and duplicate/copy flows; various handlers now route by `fileId`. > - **Admin & E2E**: > - Admin: migrate user to groups endpoint/UI; hard delete improvements; testing routes to prepare users. > - E2E: add dual init-mode runner and verification test; env/localStorage flag wiring. > - **Misc/Build**: > - Adjust worker bundle limit; tsconfig moduleResolution change; utils add `sortByMaybeIndex`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d5afd7f75cd4113c42821fff0bfb788c2deeb859. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * fairy (#6909) you know, for kids: https://www.youtube.com/watch?v=7G5F8ObYgjI  ### Change type - [ ] `bugfix` - [ ] `improvement` - [x] `feature` - [ ] `api` - [ ] `other` ### Release notes - Adds ✨magic pixie dust ✨ to the canvas (internal only for now) ### API changes - adds customizability to `DefaultDebugMenuContent` and exports some members from `debug-flags` to assist with creating custom debug/feature flags. - adds `setTool`/`removeTool` to the `Editor`. Useful if you need to add/remove a tool to the state chart on demand, after the editor has already been initialized. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds an internal AI “Fairy” agent end‑to‑end (client UI + shared lib + Cloudflare worker) with editor/debug hooks and infra/tooling updates. > > - **AI “Fairy” System (internal)**: > - **Client (dotcom)**: New fairy UI (HUD, sprite, vision), drag/throw tool, agent wiring, lazy‑loaded under a feature flag; adds `FAIRY_WORKER` env/config. > - **Shared Lib**: New `@tldraw/fairy-shared` package (actions, prompt parts, models, helpers, icons). > - **Worker**: New Cloudflare `fairy-worker` (Durable Object, streaming via Anthropic/OpenAI/Google, Clerk auth, CORS), with wrangler config and deploy integration. > - **Editor & UI APIs**: > - Add `editor.setTool` / `editor.removeTool`. > - Expose `createDebugValue` and allow custom debug/feature flags in `DefaultDebugMenuContent`; new Debug/Feature flags props. > - **Tooling/Infra**: > - Vite plugin to shim zod locales (client/templates); CSP/connect and deploy script updated for `FAIRY_WORKER`; new ESLint rule `no-fairy-imports`. > - Templates bump `ai`/`zod` and add the zod‑locale shim. > - **Misc**: Test/asset additions (fairy sprites/placeholders), yarn/deps updates. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit a6b5622ac281c66066109b99e7e4ecb0ec956d8c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Lu[ke] Wilson <[email protected]> Co-authored-by: Max Drake <[email protected]> * docs: add podcast redirect (#6953) ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Add a permanent redirect from `/codewithjason` to `/` with UTM campaign parameters. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 928d799bef0c9bc58aaf9014ecd95baf66176cf7. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * Use locks to prevent legacy mutations committing during/after migration (#6955) prevent race conditions where legacy mutations may commit after the data migration has run. ### Change type - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Add per-user advisory locks (shared in mutations, exclusive in migration) to prevent race conditions during groups migration. > > - **Backend**: > - `apps/dotcom/sync-worker/src/TLUserDurableObject.ts`: > - Before running mutators, acquire a transaction-scoped shared advisory lock using `pg_advisory_xact_lock_shared(hashtext(userId))` to coordinate with migration. > - `apps/dotcom/zero-cache/migrations/023_groups.sql`: > - In `migrate_user_to_groups`, acquire a per-user transaction-scoped exclusive advisory lock via `pg_advisory_xact_lock(hashtext(target_user_id))` before migrating; add minimal notices for lock acquisition. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 48b56b9764f05a85fd896f2300f78652082e3632. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * `useSync` custom socket api (#6859) Alternative take on #6855. Instead of exposing `TLSyncClient` and forcing people to re-implement most of `useSync`, this is a little more targeted. As an alternative to passing `uri`, you can now pass a `connect` function that returns a `TLPersistentClientSocket`. With this hook, it's possible to use a custom transport with tldraw sync without having to re-implement all the complex logic around the store and presence that lives in `useSync`. This also adds a template that uses this custom hook with socket.io. Thanks @Digital39999 - that's mostly copied from your version. ### Change type - [x] `api` ### API changes - `useSync` now accepts a `connect` method, which allows creating custom socket-like transports for tldraw sync. - The `TLSyncClient` class now public for people who need to stray from the happy path of `useSync`. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds a connect option to useSync for custom transports, exposes a generic/public TLPersistentClientSocket/TLSyncClient API, and includes a Socket.IO example template. > > - **Sync (useSync)**: > - Introduces `connect` option returning a `TLPersistentClientSocket`, as an alternative to `uri` (`UseSyncOptions` split into `UseSyncOptionsWithUri` and `UseSyncOptionsWithConnectFn`; `UseSyncConnectFn` exported). > - Implementation chooses between `connect` and `uri`, wires status via `onStatusChange`, and cleans up listeners on unmount. > - Re-exports new option types in `packages/sync/src/index.ts`. > - **Sync Core (API surface and typing)**: > - Make `TLPersistentClientSocket` public and generic: `TLPersistentClientSocket<ClientSentMessage, ServerSentMessage>`; adds `close()`; `onStatusChange` uses `TLSocketStatusChangeEvent`. > - Update `ClientWebSocketAdapter` and tests to implement the new generic interface. > - Promote `SubscribingFn`, `TLPresenceMode`, and `TLSyncClient` to public; rename `TlSocketStatusChangeEvent` to `TLSocketStatusChangeEvent` (and adjust exports/usages). > - Narrow several `TLSyncClient` members to `@internal` and refine socket typing to `TLPersistentClientSocket<TLSocketClientSentEvent<R>, TLSocketServerSentEvent<R>>`. > - **Templates**: > - Add `templates/socketio-server-example` showing a custom Socket.IO transport (client + Node server), asset upload, and bookmark unfurling. > - **API Reports**: > - Update `@tldraw/sync` and `@tldraw/sync-core` API reports to reflect new public types, renamed events, and `useSync` options. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit b848292bb5ce82e30c0aa67f207272cb8d6e23dd. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: David Sheldrick <[email protected]> Co-authored-by: Digital39999 <[email protected]> * robots: allow crawling favicon and static assets on dotcom (#6956) related to Daniel's note that this was busted on google search ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Updates robots.txt to allow crawling favicon, sitemap, and common static assets while keeping the rest of the site disallowed. > > - **Robots config**: Update `apps/dotcom/client/public/robots.txt` > - Add `Allow` rules for `/favicon*`, `/sitemap.xml`, `/*.css`, `/*.js`, `/*.png`, `/assets/*`, and `/manifest.webmanifest`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 444ce0a1b8a1498e320353f4d70013fe7280d54a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * robots: allow crawling favicon and static assets on dotcom (#6956) (#6958) related to Daniel's note that this was busted on google search ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Updates robots.txt to permit indexing of favicon, sitemap, static assets, and manifest while keeping other paths disallowed. > > - **Robots** (`apps/dotcom/client/public/robots.txt`): > - Add `Allow` rules for `/favicon*`, `/sitemap.xml`, `/*.css`, `/*.js`, `/*.png`, `/assets/*`, and `/manifest.webmanifest`. > - Retain global `Disallow: /` with `Allow: /$`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 1f0771f91c9033c3cec96dcd6a4fd40758d7e0ef. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * Add VSCode extension v2.137.0 [skip ci] * claude: use_sticky_comment (#6959) - still too many comments, after reading the docs we should use `use_sticky_comment` and remove all the custom logic - also we need to have concurrency block b/c opened+synchornized can have a race condition ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Updates the Claude review workflow to use a single sticky comment, add concurrency control, expand PR triggers, and simplify the review prompt. > > - **GitHub Actions** (`.github/workflows/claude-code-review.yml`): > - **Review behavior**: > - Enable `use_sticky_comment: true` to keep a single updated summary comment. > - Simplify prompt to focus on correctness, security, tests, and performance; prefer concise inline comments. > - Remove manual cleanup step for previous comments and `claude_args` tool allowances. > - **Execution controls**: > - Add `concurrency` group `claude-review-${{ github.event.pull_request.number }}` with `cancel-in-progress: true`. > - Expand `pull_request` triggers to include `reopened` and `ready_for_review`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit cf0e9b28ca2d76031f7cf03ab99c13f1fc392936. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * license: narrow reporting, add markdown, add inline code (#6952) ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Enhances license reporting to scan inline licenses, generate HTML+Markdown with a new Source column and filtered workspaces; adds CSS license header and ignores generated markdown report. > > - **License reporting** (`internal/scripts/license-report.ts`): > - Parse and include inline license comments from source files in reports. > - Generate both HTML and Markdown outputs (`license-report[-dev|-prod].{html,md}`). > - Add `Source` column to HTML and Markdown tables; adjust HTML rows accordingly. > - Filter workspaces to exclude `apps/`, `internal/`, and `templates/`; simplify parsing of `yarn workspaces list` output. > - **Docs** (`apps/docs/app/github-dark.css`): > - Add MIT license attribution lines. > - **Repo config** (`.gitignore`): > - Ignore generated `license-report.md`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8900ce85d2944964e5ef5c9bd55da4cd5bf03599. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * claude: try #457 (#6960) testing 123 ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Updates the Claude code review workflow to allow specific gh Bash tools and expands the review prompt with clearer, concise guidance. > > - **CI/GitHub Actions** (`.github/workflows/claude-code-review.yml`): > - Configure `claude_args` to allow Bash `gh` tools: `issue view`, `search`, `issue list`, `pr comment`, `pr diff`, `pr view`, `pr list`. > - Expand and clarify the review `prompt` (quality, bugs, performance, security, tests; be terse; reference `CLAUDE.md`; use `gh pr comment`). > - Add reference comment to action usage docs. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d51de07b465bd4eaad9c3a60e15c4dc49c2bd828. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * Remove Claude Code Review workflow (#6965) ## Summary Removed the automated Claude Code Review GitHub Actions workflow. ## Test plan - N/A - This is a configuration change removing an automated review workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Removes the Claude Code Review GitHub Actions workflow from `.github/workflows`. > > - **CI**: > - Remove ` .github/workflows/claude-code-review.yml`, eliminating the PR review job using `anthropics/claude-code-action@v1` (including its triggers, concurrency settings, permissions, and steps). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit b646db40cc59c92d706b8ede958a23c68f3a4515. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude <[email protected]> * Bump up the target rate to 120fps. (#6868) Browser will throttle us on screens that can't support 120hz (raf won't run more often than the device supports). ### Change type - [x] `improvement` ### Release notes - Support high refresh devices (up to 120hz) ### API changes * `fpsThrottle` no accepts an optional callback which returns the target fps for the throttled function to run at. If no function is provided we will use the default fps of 120. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Increase throttling to 120fps with optional per-caller FPS, use presence-aware network sync rates (1fps solo, 30fps collaborative), and show max FPS in debug panel. > > - **Utils**: > - **`fpsThrottle`**: Increase default target to 120fps and accept optional `getTargetFps` callback for per-caller throttling. Implementation tracks per-function timing and variance; docs/comments updated. (`packages/utils/src/lib/throttle.ts`) > - **API**: Update signature in `packages/utils/api-report.api.md` to include `getTargetFps?: () => number`. > - **Sync/Core**: > - **Dynamic network FPS**: Add `SOLO_MODE_FPS` (1) and `COLLABORATIVE_MODE_FPS` (30); compute via `getSyncFps()` and pass to `fpsThrottle` for `flushPendingPushRequests` and `scheduleRebase`. (`packages/sync-core/src/lib/TLSyncClient.ts`) > - **UI**: > - **Debug panel**: Display `max` observed FPS in `DefaultDebugPanel`'s FPS readout. (`packages/tldraw/src/lib/ui/components/DefaultDebugPanel.tsx`) > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d7f6bfca9dd7756d38d5eda9082b48851b30b378. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * [automated] update i18n strings (#6966) This PR updates the i18n strings. ### Change type - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds new i18n key `95d2109dc8` ("Build with tldraw SDK") across all locales and compiled locale files. > > - **Internationalization**: > - Add new translation key `95d2109dc8` for "Build with tldraw SDK" in `apps/dotcom/client/public/tla/locales/*` and compiled `locales-compiled/*` across all supported languages. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit bc1373b8d6b25e10b9883a0a042c1a53302c8744. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com> Co-authored-by: Mime Čuvalo <[email protected]> * analytics: fix regression on properties (#6967) @steveruizok oh i see - yeah this is a regression from last week's change https://github.com/tldraw/tldraw/pull/6924 this app will just hotfix by itself when i land this PR ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Spread user properties in PostHog `identify` call instead of nesting them under `properties`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 76ea674504a88eec3772566503811908a3452190. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * workers: unify origin checks (#6951) We have disparate origin checks that are varying in domains, and we want to tighten up asset-upload as well. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Moves origin checks into shared utilities and applies unified CORS/origin middleware across workers, updating the request post-processing hook signature. > > - **Shared (worker-shared)**: > - **Origins utilities**: Add `isAllowedOrigin` and `blockUnknownOrigins` in `packages/worker-shared/src/origins.ts` and export from `index.ts`. > - **Request handling**: Change `handleApiRequest` `after` hook signature to `(response, request)` to support CORS helpers that need the request. > - **Workers**: > - **asset-upload-worker**: Switch CORS `origin` to `isAllowedOrigin`; add `blockUnknownOrigins` middleware; update to `corsify` via new hook signature. > - **sync-worker**: Replace local origin logic with shared `blockUnknownOrigins`/`isAllowedOrigin`; pass `request` to `corsify`; remove duplicated origin helpers. > - **image-resize-worker**: Reuse shared `isAllowedOrigin` for `isValidOrigin`; tidy imports. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 60477d1e277131dcd393836c5106ca586b568e17. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * csp: allow analytics.google.com (#6969) ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds `https://analytics.google.com` to CSP `connect-src` allowlist. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8e97fc56a6975196d0ff02a574e133238b4f837c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * [HOTFIX] csp: allow analytics.google.com (#6970) This is an automated hotfix PR for dotcom deployment. **Original PR:** [#6969](https://github.com/tldraw/tldraw/pull/6969) **Original Title:** csp: allow analytics.google.com **Original Author:** @mimecuvalo This PR cherry-picks the changes from the original PR to the hotfixes branch for immediate dotcom deployment. /cc @mimecuvalo <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Add `https://analytics.google.com` to CSP `connect-src` in `apps/dotcom/client/src/utils/csp.ts`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 28ca54fab746e8d69867e83bea1ee2fe15c8b3a8. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Mime Čuvalo <[email protected]> * Add VSCode extension v2.138.0 [skip ci] * worker-shared: move build dependencies to devDependencies (#6968) ## Summary - Reorganized `packages/worker-shared/package.json` to correctly classify development and build-time dependencies - Moved `@cloudflare/workers-types`, `typescript`, and `lazyrepo` to `devDependencies` ## Rationale These dependencies are only needed during development and build time, not at runtime. This change: - Clarifies the actual runtime dependencies of the package - Follows best practices for dependency classification - May reduce bundle size in environments that distinguish between production and development dependencies ## Changes **Moved to devDependencies:** - `@cloudflare/workers-types` - TypeScript type definitions - `typescript` - Build-time compiler - `lazyrepo` - Build system tool **Remaining in dependencies:** - `@tldraw/utils` - `@tldraw/validate` - `cloudflare-workers-unfurl` - `itty-router` - `toucan-js` 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Reclassifies build-only packages from dependencies to devDependencies in packages/worker-shared/package.json. > > - **package.json (worker-shared)**: > - **Dependency classification**: > - Moved `@cloudflare/workers-types`, `typescript`, and `lazyrepo` to `devDependencies`. > - Kept runtime deps: `@tldraw/utils`, `@tldraw/validate`, `cloudflare-workers-unfurl`, `itty-router`, `toucan-js`. > - **Dev tooling**: > - Ensured `vitest` remains in `devDependencies`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit cf8887d8297598c95480553061ae41777d7e0470. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude <[email protected]> * Improve hotfix pr checking (#6972) Add 15-minute timeout to dotcom hotfix script to prevent action timeouts. Now throws an error (sent to Discord) if PR checks don't complete in time, leaving 5 minutes buffer before the 20-minute GitHub Action timeout. ### Change type - [x] `improvement` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds a 15-minute timeout to the dotcom hotfix script while waiting for PR checks, throwing an error if not ready in time. > > - **Scripts**: > - `internal/scripts/trigger-dotcom-hotfix.ts` > - Add 15-minute maximum wait with elapsed-time tracking when polling PR `mergeable_state`. > - On timeout, log and throw an error with PR link. > - Retains initial 5-minute delay and 15s polling cadence. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c3dfe88188a8437d193bfcc09…
This reverts commit 2e5f9f2. ### API changes - Revert the 120 fps changes. ### Change type - [x] `bugfix` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Standardizes throttling to 60fps (removing custom/120fps logic), updates TLSyncClient scheduling, simplifies FPS debug display, and adjusts the utils API. > > - **Utils**: > - Reverts `fpsThrottle` to fixed 60fps; removes custom FPS support and related state. > - Updates docs/comments and `throttleToNextFrame` to reference 60fps. > - API change: `fpsThrottle(fn)` no longer accepts `getTargetFps`. > - **Sync Core** (`packages/sync-core/src/lib/TLSyncClient.ts`): > - Removes dynamic sync FPS logic (`SOLO_MODE_FPS`, `COLLABORATIVE_MODE_FPS`, `getSyncFps`). > - `flushPendingPushRequests` and `scheduleRebase` now use `fpsThrottle()` without FPS getter. > - **UI** (`packages/tldraw/src/lib/ui/components/DefaultDebugPanel.tsx`): > - Simplifies FPS output to `FPS <current>` (removes max FPS display). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c9995c0. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
Browser will throttle us on screens that can't support 120hz (raf won't run more often than the device supports).
Change type
improvementTest plan
Release notes
API changes
fpsThrottleno accepts an optional callback which returns the target fps for the throttled function to run at. If no function is provided we will use the default fps of 120.Note
Increase throttling to 120fps with optional per-caller FPS, use presence-aware network sync rates (1fps solo, 30fps collaborative), and show max FPS in debug panel.
fpsThrottle: Increase default target to 120fps and accept optionalgetTargetFpscallback for per-caller throttling. Implementation tracks per-function timing and variance; docs/comments updated. (packages/utils/src/lib/throttle.ts)packages/utils/api-report.api.mdto includegetTargetFps?: () => number.SOLO_MODE_FPS(1) andCOLLABORATIVE_MODE_FPS(30); compute viagetSyncFps()and pass tofpsThrottleforflushPendingPushRequestsandscheduleRebase. (packages/sync-core/src/lib/TLSyncClient.ts)maxobserved FPS inDefaultDebugPanel's FPS readout. (packages/tldraw/src/lib/ui/components/DefaultDebugPanel.tsx)Written by Cursor Bugbot for commit d7f6bfc. This will update automatically on new commits. Configure here.