tldraw-mods

Share your own mod

Your mod stays in your own GitHub repo. This site only keeps a list that points at it, checks every night that it still installs, and shows it on the front page.

1. Write the mod

A mod is one file, src/mods/<name>.tsx. Its default export is a function that gets the app's setup object and adds to it: a shape class, a tool class, whatever you need. It is the same function the app already uses for its own config.js. Two optional exports, tool and commands, add a toolbar button and right-click menu entries.

import type { ModConfig, ModTool } from '@/mod'
import { MyShapeTool, MyShapeUtil, myIcon } from './my-shape-impl'

export const tool: ModTool = { id: 'my-shape', label: 'My shape', icon: myIcon }
export default (({ config }) => {
  config.shapeUtils.push(MyShapeUtil)
  config.tools.push(MyShapeTool)
}) satisfies ModConfig

Write it inside a folder made by npx tldraw-mods init, with a drawing saved there and open in the app. npm run apply puts your work into the drawing so you can try it.

2. Add a registry.json to the root of your repo

This file tells the installer what to download and where to put it.

{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "my-mods",
  "homepage": "https://github.com/you/my-mods",
  "items": [{
    "name": "my-shape",
    "type": "registry:component",
    "title": "My shape",
    "description": "One sentence.",
    "dependencies": ["lucide-react"],
    "registryDependencies": ["btn0s/tldraw-mods/tool-chrome"],
    "files": [{ "path": "src/mods/my-shape.tsx", "type": "registry:component", "target": "~/src/mods/my-shape.tsx" }]
  }]
}

Once pushed, anyone can install it: npx tldraw-mods add you/my-mods/my-shape.

3. Get it listed here

Open a pull request on btn0s/tldraw-mods that adds an entry to registry.json pointing at yours:

{ "name": "my-shape", "type": "registry:component", "title": "My shape", "description": "One sentence.",
  "categories": ["shape"], "registryDependencies": ["you/my-mods/my-shape"], "files": [],
  "meta": { "video": "https://…/my-shape.mp4", "poster": "https://…/my-shape.jpg" } }

meta.video is optional: a short silent mp4 (16:10, about 10 seconds) that loops on your card. Link to a file in your repo through raw.githubusercontent.com, or to a release asset.

The check that runs on every pull request and every night installs from your repo. If that stops working, the entry is marked broken rather than removed.