snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
This commit is contained in:
127
apps/docs/content/sdk-features/ticks.mdx
Normal file
127
apps/docs/content/sdk-features/ticks.mdx
Normal file
@@ -0,0 +1,127 @@
|
||||
---
|
||||
title: Ticks
|
||||
created_at: 12/20/2025
|
||||
updated_at: 12/20/2025
|
||||
keywords:
|
||||
- tick
|
||||
- frame
|
||||
- animation
|
||||
- TickManager
|
||||
- requestAnimationFrame
|
||||
status: published
|
||||
date: 12/20/2025
|
||||
readability: 9
|
||||
voice: 8
|
||||
completeness: 9
|
||||
accuracy: 10
|
||||
notes: ''
|
||||
---
|
||||
|
||||
The tick system provides a frame-synchronized update loop for the editor. On every animation frame the editor emits a `frame` event and then a `tick` event, each with the elapsed time in milliseconds since the last frame.
|
||||
|
||||
While pointer and keyboard events fire in response to user input, tick events fire continuously. Use them when you need updates that run every frame regardless of user interaction.
|
||||
|
||||
> The editor emits `frame` first so its own bookkeeping (pointer velocity, following a collaborator) runs before `tick` handlers. Use `tick` in application code.
|
||||
|
||||
## Subscribing to tick events
|
||||
|
||||
The most common way to use ticks is by subscribing to the `tick` event on the editor. The callback receives the elapsed time in milliseconds since the last frame:
|
||||
|
||||
```tsx
|
||||
import { Tldraw } from 'tldraw'
|
||||
import 'tldraw/tldraw.css'
|
||||
|
||||
export default function TickExample() {
|
||||
return (
|
||||
<div style={{ position: 'fixed', inset: 0 }}>
|
||||
<Tldraw
|
||||
onMount={(editor) => {
|
||||
const handleTick = (elapsed: number) => {
|
||||
// elapsed is typically ~16ms at 60fps
|
||||
updateAnimation(elapsed)
|
||||
}
|
||||
|
||||
editor.on('tick', handleTick)
|
||||
|
||||
// Clean up when done
|
||||
return () => editor.off('tick', handleTick)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Remember to unsubscribe when your component unmounts or when you no longer need tick updates. Scale movement by `elapsed` rather than assuming a fixed framerate. For one-off work on the next frame, use `editor.timers.requestAnimationFrame`, which is cleaned up when the editor is disposed.
|
||||
|
||||
## Tick events in tools
|
||||
|
||||
When building custom tools using the state machine pattern, you can handle tick events by implementing the `onTick` method on your [StateNode](?). The editor dispatches tick events through the state tree after flushing any pending pointer events for that frame, so your active tool states receive them automatically:
|
||||
|
||||
```typescript
|
||||
import { StateNode, TLTickEventInfo } from 'tldraw'
|
||||
|
||||
export class MyDraggingState extends StateNode {
|
||||
static override id = 'dragging'
|
||||
|
||||
override onTick({ elapsed }: TLTickEventInfo) {
|
||||
// Update something every frame while this state is active
|
||||
this.updateDragPosition(elapsed)
|
||||
}
|
||||
|
||||
private updateDragPosition(elapsed: number) {
|
||||
// Your frame-based logic here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[TLTickEventInfo](?) contains the elapsed time in milliseconds.
|
||||
|
||||
## Edge scrolling example
|
||||
|
||||
The most common use of `onTick` in tools is edge scrolling during drag operations. When you drag near the edge of the viewport, the canvas scrolls automatically. Here's how tldraw's built-in `Translating` state handles it:
|
||||
|
||||
```typescript
|
||||
import { StateNode, TLTickEventInfo } from 'tldraw'
|
||||
|
||||
export class Translating extends StateNode {
|
||||
static override id = 'translating'
|
||||
|
||||
override onTick({ elapsed }: TLTickEventInfo) {
|
||||
const { editor } = this
|
||||
if (!editor.inputs.getIsDragging() || editor.inputs.getIsPanning()) return
|
||||
editor.edgeScrollManager.updateEdgeScrolling(elapsed)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The [EdgeScrollManager](?) accumulates elapsed time to create a smooth acceleration effect. After a short delay, scrolling begins slowly and speeds up the longer you hold near the edge.
|
||||
|
||||
For more details on edge scrolling, see the [edge scrolling](/sdk-features/edge-scrolling) documentation.
|
||||
|
||||
## How the editor uses ticks internally
|
||||
|
||||
The editor uses tick and frame events for several internal features.
|
||||
|
||||
The [ScribbleManager](?) animates the trails you see while erasing, using the laser pointer, or scribble-selecting. On each tick it adds new points to active scribbles and shrinks them from the tail, so the trail fades.
|
||||
|
||||
The [InputsManager](?) computes pointer velocity on each `frame` event. Read it with `editor.inputs.getPointerVelocity()`; the select tool uses it to decide when to snap or drop into a container.
|
||||
|
||||
Camera methods like `editor.zoomIn()` and `editor.zoomToFit()` animate when you pass an `animation` option. The animation subscribes to `tick` for its duration and unsubscribes when complete.
|
||||
|
||||
## When to use tick events
|
||||
|
||||
Tick events are appropriate when you need continuous updates that run every frame:
|
||||
|
||||
- Animations and interpolation that should run regardless of user input
|
||||
- Edge scrolling during drag operations
|
||||
- Physics simulations or particle systems
|
||||
- Debouncing based on frame counts rather than timeouts
|
||||
|
||||
Don't use tick events for responding to user input. Pointer, keyboard, and wheel events are better for that since they fire immediately when the user acts. Tick events add a frame of latency.
|
||||
|
||||
## Related
|
||||
|
||||
- [Events](/sdk-features/events) - Overview of all editor events including tick
|
||||
- [Edge scrolling](/sdk-features/edge-scrolling) - Detailed documentation on edge scrolling behavior
|
||||
- [Snowstorm example](https://github.com/tldraw/tldraw/tree/main/apps/examples/src/examples/use-cases/snowstorm) - Uses tick events to animate falling snowflakes
|
||||
Reference in New Issue
Block a user