dotcanvas
GitHub用于创建和编辑Grida .canvas设计板,管理包含参考图、生成图像及笔记的无限画布布局。通过操作目录结构和JSON清单实现文档的空间排列与可视化设计工作。
Trigger Scenarios
Install
npx skills add gridaco/grida --skill dotcanvas -g -y
SKILL.md
Frontmatter
{
"name": "dotcanvas",
"description": "Author and edit a Grida `.canvas` board — a `.canvas.json` manifest plus document files (references, generated images, notes) placed on an infinite canvas. Use when working on a `.canvas` bundle or arranging visuals\/design work spatially. For a linear deck\/presentation, use the `slides` skill instead."
}
A .canvas is a Grida design board — a directory bundle, not a single
file. You work it like any other files: with read_file / write_file /
edit_file (no special canvas tool). It is the durable, spatial home for a
piece of work: reference images, generated outputs, and notes, arranged on an
infinite canvas. Prefer a .canvas board for freeform visual/design work; for
a linear deck / presentation / pitch / slideshow, use the slides skill.
Structure
- The bundle is a folder whose name ends in
.canvas(e.g.poster.canvas/). .canvas.json(the manifest) holds the STRUCTURE: which documents are on the board, their placement, order, and theeditormode.- Each document's CONTENT is a separate file (or a URL) referenced by its
src. - Manifest shape (only
srcis required per document):{ "editor": "board", "documents": [ { "src": "https://…/ref.jpg", "id": "ref1", "layout": { "x": 0, "y": 0, "w": 480, "h": 320 } }, { "src": "outputs/hero.png", "id": "hero", "layout": { "x": 520, "y": 0, "w": 768, "h": 512 } } ] } editor: "board"= freeform infinite canvas (placement vialayout).editor: "slides"= linear deck (order) — see theslidesskill.layoutis{ x, y, w, h, z? }in world space (z = paint order, optional). A document with nolayoutis unplaced — the host positions it; set alayoutto place it deliberately.
Working pattern
- To start, make the bundle folder first — a NEW directory whose name ends
in
.canvas(e.g.poster.canvas/); a plain folder, or files loose in the workspace root, is NOT a board and won't open. Thenwrite_fileits.canvas.jsonand each document file INSIDE that folder. To add to an existing board,read_file.canvas.jsonfirst (preserveversion/$schema/editorand any unknown fields), then write the FULL updated manifest back. - A document's
srcmay be a URL (a pointable reference — a picked library image, used as-is, no download) OR a file path inside the bundle. Both are first-class placed documents. - To place a generated image (or any produced file) on the board:
materialize it into the bundle, then reference it. Copy it from your
scratch dir into the bundle with the shell — e.g.
cp <scratch>/image-….png <board>.canvas/outputs/hero.png— then add a document whosesrcis that bundle-relative path. (Asrccan point at any file the host can read, but a file inside the bundle is the durable, portable choice.) - To move / resize / reorder, edit the
layout(and document order) in the manifest. The human can also drag pins directly — re-read.canvas.jsonbefore editing so you don't clobber their changes (last write per file wins).
Show the result
- Treat presentation as the first production milestone, not the final
"validate and open" step. For a new board, establish a meaningful renderable
checkpoint early: the manifest references at least one existing, valid
document with a basic visible composition. Call
surface_openimmediately with the workspace-rooted.canvasbundle directory (for example,/poster.canvas), then continue building and polishing it while the user can watch. Intentionally use a lightweight initial composition instead of authoring the finished board before opening it. Do not wait for all content, assets, polish, preview generation, exhaustive validation, or task completion. - Never open an empty bundle or a broken manifest. Open only when the manifest
references at least one existing, renderable document. Pass the bundle
directory, never its
.canvas.jsonmanifest. - For an existing primary board, open it after reading its manifest and before substantial edits.
- If the
.canvasbundle itself is mounted as/in a dedicated file surface, it is already presented; do not callsurface_openjust to reopen it. - Treat presentation as auxiliary: continue regardless of the result, never
retry based on presentation status, and do not call
surface_openafter every write. - Use
surface_list_openonly when the current host surface state is materially useful. It is not required beforesurface_open.
Version History
- 29f3afa Current 2026-08-20 15:55


