canvas-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 93fdaafeda16
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 788ba0fa01083b300ad50913
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
AGENTS.md
# Canvas

Canvas is a free online whiteboard, and a free alternative to Miro, FigJam and Mural. It is an OpenApp in the OpenApps free apps store (https://openapps.free/), owned by the OpenApps team. The drawing editor is Excalidraw (MIT license), loaded from the `@excalidraw/excalidraw` npm package.

## What it promises

- Free, with no limit on boards or people, no ads and no paid tier. Never add a cap, an upsell or tracking.
- No sign-up. Every visitor is a guest account created in the browser.
- Three links per board: the view link (`/b/<id>`), the edit link (`/b/<id>#edit=<key>`) and the owner's admin link (`/b/<id>/admin#k=<key>`). Owners can turn either link off, make a new edit link (the old one stops at once) and delete the board.
- Honest limits: images up to 2 MB (PNG, JPEG or WebP), no comments, voting, timers, AI, embeds or offline editing, and boards are not end-to-end encrypted. The landing page says so; keep it true.
- AI assistants can start boards (diagram, mind map, sticky-note columns, template), read them back and manage them through the public API (`functions/api.ts`), documented in `public/llms.txt` and `public/openapi.json`. Keep both true whenever the API changes.

## How it is built

- `index.html` is the static landing page that search engines and AI crawlers read; `public/index.md` is the same page in Markdown. Keep their copy, FAQ and JSON-LD in step with each other and with what the app does. `template-pages.ts` writes `/templates` and `/templates/<id>` at build time from the template data.
- `src/main.tsx` routes: `/` mounts the board starter and "Your boards" into the landing; `/b/<id>` (`BoardPage.tsx`) joins the board, presents the edit or admin key, then lazily loads `Editor.tsx`; `/new` and `/new/<template>` make a board and open it.
- `src/Editor.tsx` renders Excalidraw: sticky-note button, Share sheet (`ShareDialog.tsx`), main menu (export PNG and SVG, copy, save file), local shape library.
- `src/lib/sync.ts` keeps boards live. Each element is one document (`boards/<id>/els/<elementId>`, its Excalidraw JSON plus a server time `at`). A device sends elements whose version went up (at most every 120 ms, in batches of 100), and follows only recently changed elements live (filter `at >= ...`, moved forward as the set grows), because a live feed re-sends every document it follows on each change. Excalidraw's `reconcileElements` merges by version, so arrival order does not matter. Deleted elements stay as tombstones. Pointers and selections are in-memory documents (`boards/<id>/cursors/<userId>`). Images are stored files (`boards/<id>/files/<fileId>`); images over 2 MB or of other types are re-encoded as WebP first.
- `src/lib/seed.ts` draws what a new board starts with (stored as `seed` on the board): a template or columns of notes in frames, or a diagram laid out with dagre (`src/lib/layout.ts`). Ids, seeds and nonces come from the input, so two devices opening a fresh board draw identical elements. The first device that can edit saves them.
- `functions/lib/canvas.ts` is shared by the app, the API and the build: limits, colors, templates, checking API input, and the board summary the API returns.
- `policy.json` holds the rules. Owners: the creator, or whoever presents the admin key (`boardkeys`, claimed through `boardclaims`). Editors: a device whose join (`boards/<id>/joins/<userId>`) holds the current edit key (`editkeys`) while the edit link is on. Readers: joined devices while the view link is on, plus editors and owners. `boardkeys` and `editkeys` are readable by the API's public principal, which checks the key every caller presents. Policy tests are in `policy-tests/`.
- `vite.config.ts` leaves out Excalidraw's translations and its Mermaid importer to keep the site small, and gives Excalidraw's export worker its own small chunk. Excalidraw's fonts are served from `public/fonts/` (`window.EXCALIDRAW_ASSET_PATH = "/"`), except its Chinese, Japanese and Korean font, which Excalidraw fetches from its CDN only when such text is drawn.

## Working on it

`npm install && npm run build` typechecks and builds `dist/`. `bounded tests run` checks the policy. Ship changes through previews and releases as your runtime instructions describe; the app is an OpenApp, so nobody deploys it directly.

Check a change by drawing on one board from two browsers (shapes, arrows, notes, text, an image), reloading, opening the view link, turning links off from the Share sheet, opening the admin link on another device, deleting the board, and calling the API with curl.

## Voice

Plain words, short sentences, no jargon, no em dashes. Say what happens, not how clever it is.

Change history

Point OpenApps links to openapps.free
93fdaafeda · 18 hours ago
Bind AGENT_ADDRESS in policy constants
bf8f43b096 · 20 hours ago
Use functions.openapps.xyz alias, add OpenApp contribution strip
56f1a381b2 · 20 hours ago
Bounded source sync
9ec707aeb8 · 1 day ago
Bounded source sync
5645481c23 · 1 day ago
Bounded source sync
c38fe71874 · 1 day ago
Bounded source sync
28c0350b40 · 1 day ago