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

This commit is contained in:
upstream-mirror
2026-09-23 16:12:52 +05:00
commit a774ac673a
4541 changed files with 770499 additions and 0 deletions

189
skills/shared/blog-guide.md Normal file
View File

@@ -0,0 +1,189 @@
# Blog style guide
This document defines the rules and conventions for tldraw technical blog posts.
**Prerequisite**: Read the [voice and style guide](../../VOICE.md) first. This document builds on those foundations with blog-specific patterns.
## What technical blog posts are
Technical blog posts are short articles about how we solved interesting problems. They need to be _interesting_ as well as informative—if the content isn't interesting or can't be made interesting, there's no point in writing it.
A technical blog post can be interesting for a number of reasons:
- It may describe a journey from discovery, investigation, and solution
- The problem area it describes may be hard, unintuitive, or notorious
- It reveals something curious about the implementation of a common feature
- It describes iteration and design decisions behind a feature
The best content combines many of these reasons into a single article.
An evergreen approach is to root the technical article in some anecdotal context. These problems don't just emerge from nowhere—they come from details, behaviors, conventions, or general "what feels right" expectations within the canvas domain. The real problem is how to write the code and convince the computer to do the thing that makes the experience feel right. Often times, that work is unintuitive and interesting in that it reveals something about the interaction or about the technologies involved.
## Opening pattern
Technical blog posts start by **framing the problem**—a sentence or two that tells the reader what this is about and why it's interesting before diving in.
**Example opening:**
> The tldraw SDK is all about making the little details work. If you've ever used dashed lines in tldraw, you might have noticed that the dashes always line up with the corners of your shape, the handles of a spline, or the start and end of an arrow. While this might seem like the obvious way that dashes _should_ work, you might be surprised to learn that SVG offers no such feature. We implement these perfect dashes entirely ourselves.
>
> Here's how it works.
The opening establishes context (what we're talking about), tension (there's a problem or unmet expectation), and stakes (why you should care) before getting into the solution.
### Concrete vs abstract tension
The tension needs to be concrete and specific, not an abstract problem statement.
**Too abstract:**
> How do you render ephemeral, performant drawing feedback that needs to behave differently depending on the tool?
**Concrete:**
> SVG's `stroke-dasharray` doesn't give you complete dashes at both ends. We had to calculate them ourselves.
Abstract tension describes a category of problem. Concrete tension names a specific thing that doesn't work, a surprising limitation, or an unexpected behavior. Concrete tension makes the reader think "oh, I didn't know that" or "huh, I've never thought about that."
### Example openings
**Too abrupt:**
> Tldraw calculates dash patterns that fit paths exactly. Complete dashes at both ends, even spacing throughout.
**Better (starts with our experience):**
> When we added dashed lines to tldraw, we wanted them to look right—complete dashes at both ends, even spacing, corners that line up on rectangles. SVG's `stroke-dasharray` doesn't do this.
**Also good (frames the problem):**
> Arrow routing sounds simple until you try it. Given two shapes, draw a line between them that doesn't pass through anything else. We spent a while getting this right.
## Structure
Technical blog posts typically follow this arc:
1. **Frame the problem** — What's this about? What problem did we encounter and solve? Why was it hard, unintuitive, or interesting?
2. **Show the insight** — What's the key idea that makes the solution work?
3. **Walk through the implementation** — Code and explanation, building up complexity
4. **Wrap up** — Where this lives in the codebase, tradeoffs, links to files. Also unexplored areas, more we could do, or related problems.
Wrap-ups can end with an opinion ("that's worth the complexity") but avoid promotional language. Don't summarize with adjective lists like "fast, flexible, and powerful" or "performant but smooth"—these read like marketing copy.
## Tone
Technical blog posts have warmth and personality. They:
- Use phrases like "the trick is..." or "the insight is..." to signal key ideas
- Include brief asides about why something is hard or interesting
- Show the journey, not just the destination ("we tried X, but Y worked better")
- End with opinions ("that's worth the tradeoff")
- Use "we" narratively throughout
They still shouldn't:
- Ramble or over-explain
- Use hollow importance claims ("this is crucial for...")
- Get too casual or jokey
- Overdo the storytelling at the expense of the technical content
## Describe what we did, not what to do
Technical blog posts explain how tldraw solved a problem. Frame solutions as "here's what we do" rather than prescriptive instructions.
**Don't:**
> The solution: don't decide immediately. Watch what the fingers do, then commit once the pattern is clear.
> Instead of guessing, implement a state machine that starts undecided.
**Do:**
> Since we don't have enough information to know either way, we defer the decision. The gesture handler watches what the pointers do, then commits once we know enough to recognize the interaction pattern.
> Instead of guessing, we use a state machine that starts undecided and resolves as more information comes in.
The reader learns from seeing our approach, not from being told what to do.
## Code in technical blog posts
Code examples illustrate our solution and build understanding. They show how we approached the problem, not just the final answer.
### Show progression
Build up complexity to reveal the insight:
```ts
// First attempt: simple but wrong
function getDashOffset(length: number, dashSize: number) {
return length % dashSize
}
```
Then explain why that doesn't work, and show what we actually do:
```ts
// What we actually do: account for both ends
function getDashOffset(length: number, dashSize: number, gapSize: number) {
const dashCount = Math.ceil(length / (dashSize + gapSize))
const totalDashLength = dashCount * dashSize
const totalGapLength = (dashCount - 1) * gapSize
return (length - totalDashLength - totalGapLength) / 2
}
```
### Link to the actual code
End with links to where this lives in the codebase:
> You can find this implementation in [`packages/editor/src/lib/utils/dashes.ts`](https://github.com/tldraw/tldraw/blob/main/packages/editor/src/lib/utils/dashes.ts).
## Length and depth
Technical blog posts should be:
- **Long enough** to fully explain the problem and solution
- **Short enough** to read in one sitting (5-10 minutes)
- **Deep enough** to be interesting to developers who've faced similar problems
- **Accessible enough** that someone unfamiliar with tldraw can follow along
A typical technical blog post is 800-1500 words, but length should follow from the complexity of the topic.
## Topics that make good technical blog posts
Good technical blog post topics share these traits:
- **Unintuitive solutions** — The obvious approach didn't work, so we had to think differently
- **Hidden complexity** — Something that looks simple has interesting depth
- **Canvas-specific problems** — Challenges unique to building visual, interactive software
- **Platform/browser quirks** — Working around limitations in SVG, Canvas, browsers
- **Performance insights** — How we made something fast (with measurements)
### Examples of good topics
- How we calculate perfect dash patterns for arbitrary paths
- Why arrow routing is harder than it looks
- How we detect whether a pinch gesture is zoom or rotate
- Making text editing feel right on an infinite canvas
- How we handle undo/redo across multiplayer sessions
### Topics that aren't technical blog posts
- Feature announcements (better as release notes or marketing content)
- Tutorials teaching how to use the SDK (better as docs)
- General programming wisdom unconnected to tldraw
- Internal refactoring without user-facing interest
## Evaluation checklist
When reviewing a technical blog post, check:
- [ ] **Opening** — Does it frame a problem before diving into solution?
- [ ] **Insight** — Is there a clear "aha" moment or key idea?
- [ ] **Specificity** — Is this grounded in tldraw's actual implementation?
- [ ] **Code** — Do examples build understanding, not just show syntax?
- [ ] **Tone** — Warm and personal, but not rambling?
- [ ] **Links** — Points to actual code in the repo?
- [ ] **Length** — Appropriate depth for the topic?
For voice and style, refer to the [voice and style guide](../../VOICE.md) checklist.

231
skills/shared/docs-guide.md Normal file
View File

@@ -0,0 +1,231 @@
# Documentation style guide
This document defines the rules and conventions for tldraw SDK documentation in `apps/docs/content/`.
**Prerequisite**: Read the [voice and style guide](../../VOICE.md) first. This document builds on those foundations with docs-specific patterns.
## Document structure
### Opening pattern
Start with a clear, direct definition:
> The Editor class is the main way of controlling tldraw's editor.
> In tldraw, a shape is something that can exist on the page, like an arrow, an image, or some text.
> In tldraw, persistence means storing information about the editor's state to a database and then restoring it later.
**One concept per sentence.** If your opening packs definition, use cases, and API references together, split it:
**Don't:**
> The scribble system draws temporary freehand paths for pointer-based interactions, used for visual feedback during erasing, laser drawing, or scribble-brush selection, accessed through Editor#scribbles.
**Do:**
> The scribble system draws temporary freehand paths for pointer-based interactions. Use scribbles to show visual feedback during tool operations like erasing, laser pointer drawing, or scribble-brush selection.
The API reference can come after the opening paragraph or inline where first relevant.
### Concept, explanation, code
Every concept should be followed by a working example:
> You can access the editor in two ways:
>
> 1. From the Tldraw component's `onMount` callback:
>
> ```tsx
> function App() {
> return (
> <Tldraw
> onMount={(editor) => {
> // your editor code here
> }}
> />
> )
> }
> ```
### Progressive disclosure
Move from simple to complex:
1. Start with the most common use case
2. Add complexity incrementally
3. Leave edge cases and advanced patterns for later sections
**Example from persistence docs:**
1. First: `persistenceKey` prop (simplest)
2. Then: State snapshots (more control)
3. Then: The `store` prop (full control)
4. Finally: Migrations (advanced)
### Short paragraphs
Keep paragraphs to 1-3 sentences. Dense blocks of text are hard to scan:
**Do:**
> Meta information is information that is not used by tldraw but is instead used by your application. For example, you might want to store the name of the user who created a shape, or the date that the shape was created.
**Don't:**
> Meta information is additional data that can be attached to shapes and is not used internally by tldraw but can be leveraged by your application for custom functionality. This could include things like the user who created the shape, timestamps, custom identifiers, or any other application-specific data that you want to associate with shapes but don't want to store in the props object.
### Tables for related information
Use tables to organize related methods, options, or concepts:
| Method | Description |
| ------------------ | ---------------------------------------------- |
| `Editor#setCamera` | Moves the camera to the provided coordinates. |
| `Editor#zoomIn` | Zooms the camera in to the nearest zoom step. |
| `Editor#zoomOut` | Zooms the camera out to the nearest zoom step. |
### Notes and callouts
Use blockquotes for important asides:
> If all you're interested in is the state below `root`, there is a convenience method, `Editor#getCurrentToolId`, that can help.
Use stronger callout syntax for warnings:
```
<Callout type="warning">
You must make sure that the tldraw version in your client matches the version on the server.
</Callout>
```
## Cross-referencing
### Link liberally
Reference related concepts inline rather than explaining everything:
> For more information about how to synchronize the store with other processes, see the [Persistence](/docs/persistence) page.
### API references use consistent format
Link to API docs using the `[MethodName](?)` pattern:
> Use the [Editor#createShapes](?) method.
> See [TLInstancePresence](?) for the full record type.
### Point to working examples
Always link to runnable examples when available:
> For an example of how to create custom shapes, see our [custom shapes example](/examples/shapes/tools/custom-shape).
## Nuggets (tech blog posts)
Nuggets are short technical articles about how we solved interesting problems. They're different from reference documentation—more like posts you'd find on a company engineering blog.
### Different opening pattern
Reference docs start with definitions. Nuggets start by **framing the problem**—a sentence or two that tells the reader what this is about and why it's interesting before diving in.
**Reference doc opening:**
> The Editor class is the main way of controlling tldraw's editor.
**Nugget opening:**
> The tldraw SDK is all about making the little details work. If you've ever used dashed lines in tldraw, you might have noticed that the dashes always line up with the corners of your shape, the handles of a spline, or the start and end of an arrow. While this might seem like the obvious way that dashes _should_ work, you might be surprised to learn that SVG offers no such feature. We implement these perfect dashes entirely ourselves.
>
> Here's how it works.
The nugget opening establishes context (what we're talking about), tension (there's a problem or unmet expectation), and stakes (why you should care) before getting into the solution.
The goal is to root the technical article in some anecdotal context. These problems don't just emerge from nowhere, but rather they come from details, behaviors, conventions, or general "what feels right" expectations within the canvas domain. The real problem is how to write the code and convince the computer to do the thing that makes the experience feel right. Often times, that work is unintuitive and interesting in that it reveals something about the interaction or about the technologies involved.
### Structure
Nuggets typically follow this arc:
1. **Frame the problem** — What's this about? What problem did we encounter and solve? Why was it hard, unintuitive, or interesting?
2. **Show the insight** — What's the key idea that makes the solution work?
3. **Walk through the implementation** — Code and explanation, building up complexity
4. **Wrap up** — Where this lives in the codebase, tradeoffs, links to files. Also unexplored areas, more we could do, or related problems.
### Tone differences
Nuggets are warmer than reference docs. They can:
- Use "the trick is..." or "the insight is..." to signal key ideas
- Include brief asides about why something is hard or interesting
- Show the journey, not just the destination ("we tried X, but Y worked better")
- End with opinions ("that's worth the tradeoff")
They still shouldn't:
- Ramble or over-explain
- Use hollow importance claims ("this is crucial for...")
- Get too casual or jokey
### Describe what we did, not what to do
Nuggets explain how tldraw solved a problem—they're not tutorials. Frame solutions as "here's what we do" rather than prescriptive instructions.
**Don't:**
> The solution: don't decide immediately. Watch what the fingers do, then commit once the pattern is clear.
> Instead of guessing, implement a state machine that starts undecided.
**Do:**
> Since we don't have enough information to know either way, we defer the decision. The gesture handler watches what the pointers do, then commits once we know enough to recognize the interaction pattern.
> Instead of guessing, we use a state machine that starts undecided and resolves as more information comes in.
The reader learns from seeing our approach, not from being told what to do.
### Example openings
**Too abrupt (reads like docs):**
> Tldraw calculates dash patterns that fit paths exactly. Complete dashes at both ends, even spacing throughout.
**Better (starts with our experience):**
> When we added dashed lines to tldraw, we wanted them to look right—complete dashes at both ends, even spacing, corners that line up on rectangles. SVG's `stroke-dasharray` doesn't do this.
**Also good (frames the problem we faced):**
> Arrow routing sounds simple until you try it. Given two shapes, draw a line between them that doesn't pass through anything else. We spent a while getting this right.
## Priorities
1. **Accuracy** — Code must work. API refs must be correct.
2. **Clarity** — Understand on first read.
3. **Brevity** — Say it once, move on. Cut sections that repeat what's already shown elsewhere.
4. **Scannability** — Short paragraphs, clear headers, lots of code.
### Avoid redundant sections
If detailed examples already demonstrate a pattern, don't repeat the same information in a "Common use cases" section with shorter snippets. Either:
- Keep only the detailed examples (preferred)
- Keep only the quick-reference snippets
- Ensure each section adds genuinely new information
**Don't:** Show a complete eraser implementation, then have a "Common use cases > Eraser" section with the same code trimmed down.
**Do:** Show complete implementations once. If you need a quick-reference section, make it a table pointing to the detailed examples.
## Evaluation checklist
When reviewing documentation, check:
- [ ] **Opening sentence** — Does it immediately define what this thing is?
- [ ] **Code examples** — Is every concept followed by working code?
- [ ] **Progressive disclosure** — Does complexity build gradually?
- [ ] **Links** — Are related concepts cross-referenced?
- [ ] **Scannability** — Short paragraphs, clear headers?
For voice and style, refer to the [voice and style guide](../../VOICE.md) checklist.

View File

@@ -0,0 +1,281 @@
# Release notes style guide
This document defines the rules and conventions for tldraw SDK release notes articles in `apps/docs/content/releases/`.
**Prerequisite**: Read the [voice and style guide](../../VOICE.md) first. This document builds on those foundations with release-notes-specific patterns.
## Editorial guidance
### What to include
- Breaking changes that require user action
- New features that solve common pain points
- API additions that unlock new capabilities
- Changes that affect how developers integrate tldraw
- Bug fixes for user-reported issues
### What to omit
- Internal performance optimizations (unless user-visible)
- Fixes for bugs introduced in the same release cycle
- Implementation details that don't affect public API
- Pure code quality improvements
### When to create a featured section
Promote changes to the "What's new" section when:
- It's a breaking change requiring a migration guide
- It introduces a major new capability
- It is an interesting or significant new feature, possibly the result of multiple PRs
- Users need detailed guidance (migration guides, platform tables)
Featured sections should include:
- Clear description of what changed and why it matters
- Code examples where helpful
- Migration guides in collapsible `<details>` blocks for breaking changes
- Links to relevant documentation
## PR categorization
| Category | Labels | Indicators |
| ------------ | ---------------------------- | -------------------------------- |
| API changes | `api`, `feature`, `major` | Adds/removes/modifies public API |
| Improvements | `improvement`, `enhancement` | Enhances existing functionality |
| Bug fixes | `bugfix`, `bug`, | Fixes issues |
Look for `### Release notes` and `### API changes` sections in PR bodies. Search for "breaking" to identify breaking changes. Search for "deprecat" to identify deprecated APIs (mark with 🔜, not 💥).
### PRs to skip
Skip PRs with these labels:
- `other`
- `skip-release`
- `chore`
- `dotcom`
Also skip:
- Reverts, unless they fix something user-facing
- Fixes for bugs introduced in the same release cycle (i.e., the bug was caused by a PR that is also in `next.mdx` and was not in the previous release)
When a PR is reverted, also remove the original PR's entry from `next.mdx` if it is present.
## Team members (do not credit)
angrycaptain19, AniKrisn, ds300, kaneel, kostyafarber, max-dra, mimecuvalo, MitjaBezensek, profdl, Siobhantldraw, steveruizok, tldrawdaniel, danieljamesross, jsscclr, frolic, huppy-bot, github-actions, Somehats, todepond, Taha-Hassan-Git, alex-mckenna-1, max-drake, m31-galaxy, meg-an31
Credit community contributors with:
```markdown
(contributed by [@username](https://github.com/username))
```
## General notes
- Do not include AI attribution
- Write as if the release has already happened
- Omit empty sections
- The release listing is maintained in `apps/docs/content/getting-started/releases.mdx`
---
## Formatting conventions
### Section order
Use these sections in order (omit empty sections):
1. **Introduction paragraph** - 1-2 sentence summary of the release highlights
2. **What's new** (`## What's new`) - Featured sections (H3s) for major features and breaking changes
3. **API changes** (`## API changes`) - New methods, properties, options, deprecations, and breaking changes
4. **Improvements** (`## Improvements`) - Enhancements to existing functionality
5. **Bug fixes** (`## Bug fixes`) - Fixed issues
6. **Patch releases** (`## Patch releases`) - Separated by `---`, contains bulleted changes for each patch version
### Introduction paragraph
Start each release with a 1-2 sentence summary highlighting the most significant changes. Lead with concrete features, then mention infrastructure and performance:
```markdown
This release introduces several significant changes: a new pattern for defining custom shape/binding typings, pluggable storage for `TLSocketRoom` with a new SQLite option, reactive `editor.inputs`, and optimized draw shape encoding. It also adds various other API improvements, performance optimizations, and bug fixes.
```
### Entry format
Start entries with a verb: "Add", "Fix", "Improve", "Remove". Keep descriptions concise but informative.
```markdown
- Add `Editor.newMethod()` for doing something useful. ([#7123](https://github.com/tldraw/tldraw/pull/7123))
```
For multiple related PRs:
```markdown
- Improve arrow snapping performance. ([#7145](https://github.com/tldraw/tldraw/pull/7145), [#7150](https://github.com/tldraw/tldraw/pull/7150))
```
With code examples:
````markdown
- Add `localStorageAtom` to `@tldraw/state`. ([#6876](https://github.com/tldraw/tldraw/pull/6876))
```tsx
const myAtom = localStorageAtom('my-key', defaultValue)
```
````
### Breaking changes
Mark breaking API changes with a 💥 prefix. Mark deprecations (APIs that still work but will be removed in a future release) with a 🔜 prefix. Place breaking changes at the top of the API changes section, followed by deprecations:
```markdown
## API changes
- 💥 **`ShapeUtil.canEdit()`** signature changed to accept a `TLEditStartInfo` parameter. ([#7361](https://github.com/tldraw/tldraw/pull/7361))
- 💥 **`oldMethod`** renamed to `newMethod`. ([#7400](https://github.com/tldraw/tldraw/pull/7400))
- 🔜 **`Editor.legacyMethod()`** is deprecated. Use `Editor.newMethod()` instead. ([#7450](https://github.com/tldraw/tldraw/pull/7450))
- Add `Editor.newMethod()` for doing something useful. ([#7123](https://github.com/tldraw/tldraw/pull/7123))
```
### What's new section
The `## What's new` section contains featured subsections (H3s) for headline features and major breaking changes.
**Basic structure:**
```markdown
## What's new
### Feature name ([#7320](https://github.com/tldraw/tldraw/pull/7320))
Brief description of what this feature does and why it matters.
```
**Multiple related PRs:**
```markdown
### Pluggable storage for TLSocketRoom ([#7320](https://github.com/tldraw/tldraw/pull/7320), [#7123](https://github.com/tldraw/tldraw/pull/7123))
```
**Deprecation featured sections** - add 🔜 to the heading:
```markdown
### 🔜 Deprecation of old API ([#0000](https://github.com/tldraw/tldraw/pull/0000))
Brief description of what is deprecated and what to use instead.
```
**Breaking change featured sections** - add 💥 to the heading and include a migration guide:
```markdown
### 💥 Feature name ([#0000](https://github.com/tldraw/tldraw/pull/0000))
Brief description of what this feature does and why it matters.
<details>
<summary>Migration guide</summary>
Before:
\`\`\`ts
// old code
\`\`\`
After:
\`\`\`ts
// new code
\`\`\`
</details>
```
**Collapsible explanations** - use for supplementary context:
```markdown
<details>
<summary>Why SQLite?</summary>
- **Automatic persistence**: Data survives process restarts
- **Lower memory usage**: No need to keep entire documents in memory
</details>
```
**Platform support tables:**
```markdown
<details>
<summary>Platform support</summary>
| Platform | Wrapper | Library |
| -------------------------- | -------------------------------- | --------------------------------- |
| Cloudflare Durable Objects | `DurableObjectSqliteSyncWrapper` | Built-in `ctx.storage` |
| Node.js/Deno | `NodeSqliteWrapper` | `better-sqlite3` or `node:sqlite` |
</details>
```
### GitHub release link
Add a link to the GitHub release at the end of each release section:
- **For minor releases**: Place after the last content section and before the `---` separator
- **For patch releases**: Place after the bulleted list of changes
```markdown
[View release on GitHub](https://github.com/tldraw/tldraw/releases/tag/v4.3.0)
```
### Patch releases
Add patch releases at the bottom of the minor release file, after a horizontal rule. List in chronological order:
```markdown
---
## Patch releases
### v4.2.1
- Fix text selection flakiness when clicking into text shapes. ([#3643](https://github.com/tldraw/tldraw/pull/3643))
[View release on GitHub](https://github.com/tldraw/tldraw/releases/tag/v4.2.1)
### v4.2.2
- Fix arrow binding when target shape is rotated. ([#3650](https://github.com/tldraw/tldraw/pull/3650))
[View release on GitHub](https://github.com/tldraw/tldraw/releases/tag/v4.2.2)
```
### Horizontal rules
Use `---` only before the `## Patch releases` section. Do not use horizontal rules elsewhere.
### Headings
Use sentence case: "API changes" not "API Changes", "Bug fixes" not "Bug Fixes".
### Frontmatter
```yaml
---
title: 'v4.3.0'
created_at: 12/19/2024
updated_at: 12/19/2024
keywords:
- changelog
- release
- v4.3
- v4.3.0
- v4.3.1
- feature-keyword
---
```
- Dates in MM/DD/YYYY format
- Always include `changelog` and `release` as keywords
- Include the minor version without patch (e.g., `v4.3`), the `.0` release, and all patch versions
- Add 2-5 content-relevant keywords (lowercase, hyphens for multi-word)