Canvas
Bundled free-form HTML canvas module for arbitrary visualizations, tables, diagrams, and agent-edited files.
What it does
Canvas is a bundled module for free-form HTML files: tables, sheet-like layouts, diagrams, text pages, dashboards, and one-off visualizations that do not fit a specific document editor. Files are plain .html documents that you and the agent can create, edit visually, share instance-wide, and export as PDF. Reusable templates with semantic placeholders let recurring documents (for example invoices) be regenerated from structured data.
How to open it
- Open the module from the Clapilot module menu; the route is
/modules/canvas. - Canvas is a bundled module (
bundled-modules/canvas/module.json, slugcanvas, rendererreact, iconchart) rendered directly in the app shell viasrc/components/modules/canvas-module.tsxandsrc/app/(app)/modules/[slug]/page.tsx. - The open module publishes page context with the active
filePath,activeFilePath, andcanvasTitle, so the global chat agent knows which file you are looking at.
Key workflows
Create and edit a file
- Create a file from the Files sidebar (or ask the agent). Nested relative paths are supported, so files can live in subfolders such as
reports/q2-overview.html. - Edit in the visual editor. The compact toolbar (visual view only) offers: undo, redo, bold, italic, underline, a font-family dropdown, a font-size dropdown (Small/Normal/Large/Huge), a text-color picker, a text-style dropdown (Normal / Heading 1–3, applied with
formatBlock), and bulleted/numbered lists; the save indicator and the draw-image button sit at the right. Buttons act on the current selection via the contenteditable bridge (document.execCommand, withstyleWithCSSso color/font/size apply as inline CSS), and active states reflect the selection. - Autosave persists dirty edits ~1.5s after typing stops (for already-persisted files and templates). The header indicator shows
Saving …,Unsaved, orSaved <time>; the manual Save button still works, and autosave pauses while an agent is live-editing the document. The native iOS/macOS Canvas editor follows the same existing-file autosave rule. - Images, boxes, and tables can be resized directly with edge-drag handles.
Insert images
- Drag & drop: dropping image files onto the document inserts them as block images at the drop point (same placement rule as draw-to-generate). Files embed as
data:URLs and are automatically downscaled/re-encoded to fit the embed size cap; oversized or non-image drops show a localized status message. An image dragged over from another browser page inserts as a URL-referenced<img>. Dragging an image that is already inside the document keeps the browser's native move behavior. - Draw-to-generate (AI image): toggle Draw image in the toolbar, drag a rectangle over the document, type a description in the popover, choose an image model, and select Generate. The default model option preserves provider-side routing and omits
modelfromPOST /api/generated-images/generate; an explicit choice is sent as an override. The per-browser choice is stored inlocalStorageunderclapilot.canvas.imageModel. The drawn frame's aspect ratio selects the closest provider size bucket (1024x1024,1536x1024, or1024x1536). The finished image is inserted as a block element at the drawn spot, reflows with text, and can be resized like any other Canvas image. - AI image editing: click an existing image to select it, then choose Edit image in the toolbar. The shared image popover accepts an edit instruction and the same model override. Generated-image URLs reuse their asset ID directly; embedded
data:images and fetchable external images are imported throughPOST /api/generated-images/importbeforePOST /api/generated-images/edit. External images that cannot be fetched because of access or CORS restrictions show a localized error and remain unchanged. Successful edits replace only the selected image's source while preserving its element attributes, position, and width, and they participate in the normal undo, dirty, and autosave flow.
Organize files
- The Files sidebar switches between two layouts with the list/grid toggle next to the search field: List (default; one divided surface with compact rows, a small document thumbnail, the title, and a shared badge) and Grid (two-column cards with a larger preview, the title below, and the same share/rename/delete actions on hover or right-click).
- Both layouts share folder navigation, search filter, and selection state. The chosen layout is per-browser, persisted in
localStorage(clapilot:canvas:file-layout), and applies only to the Files section; Templates keep their existing layout. This is a UI-only affordance with no API or agent-tool surface. - Folders can be created, renamed (contained files move with the folder), and deleted.
Templates
- Upload a PDF, Word, Excel, or CSV source document as a template source. PDF sources are converted into image-backed HTML pages that preserve the source layout, colors, logos, lines, and icons, with detected dynamic values masked by placeholder overlays. Tabular/text sources provide an extracted preview and draft placeholder HTML.
- Refine the saved template HTML (yourself or via the agent) with semantic placeholders such as
{{customer_name}},{{invoice_number}}, and{{total}}. - Render the template with structured data to create new Canvas files. Templates are stored under
.clapilotaicore/canvas-templates/.
Sharing
Canvas files, folders, and templates can be shared instance-wide; sharing is owner-controlled:
- A shared item is visible and editable for every user in the Clapilot instance; sharing a folder shares its whole subtree.
- Only the original owner can unshare or delete a shared item; other users may view and edit it but cannot revoke the share.
- List/get responses include
sharedandowned_by_meon each record so clients and agents can render share badges and gate owner-only actions.
Export & public link
The toolbar export button opens a menu with three options: Export as PDF, Export as HTML, and a public link action (create/copy/remove). PDF suits static, print-ready documents; functional or interactive canvases (JavaScript, forms, calculators, animated dashboards) should be exported as HTML or shared via public link, because a PDF freezes a scriptless snapshot.
Export to PDF
The PDF menu entry opens a compact settings dialog for A4, A3, A5, Letter, or Legal; portrait or landscape orientation; and narrow (8 mm), normal (15 mm), or wide (25 mm) margins. Leaving all controls on Document / default preserves an existing @page rule. If the HTML has no @page, Canvas preserves the existing edge-to-edge A4 portrait behavior. Each explicitly selected control overrides only its corresponding document page setting. Fixed A4 documents reject non-A4 or landscape geometry to prevent clipping.
POST /api/modules/canvas/export-pdf ({ title, path?, content_html, page_format?, orientation?, margin? }) renders Canvas HTML to a PDF, stores the generated file as a private Documents entry, and returns documentUrl for opening it in Clapilot, downloadUrl for direct download, and pages with the generated page count. In addition to the three UI margin presets, API and agent callers may pass a numeric margin from 0 through 50 millimeters (margin_mm is an alias).
Document-like Canvas files opt into deterministic A4 pagination with data-clapilot-document="a4" on <html> or <body> and one .page container per intended sheet. The Canvas preview and PDF renderer then use the same fixed 210mm × 297mm border box, zero print margin, and explicit page breaks. Add data-page-bottom to a footer or signature region that must stay at the bottom of its sheet; data-page-footer is an equivalent footer marker. Signature blocks (data-signature-block or .signature-block), table rows, and figures avoid internal breaks.
If an opted-in .page exceeds its A4 frame, Canvas reports the affected page and overflow in millimetres. PDF export returns 422 with code: "CANVAS_A4_PAGE_OVERFLOW" and an overflows array instead of clipping content or creating an accidental extra sheet. Authors can then move a semantic block to the next explicit .page. Canvas files without the marker—including presentations, dashboards, diagrams, and other free-form HTML—retain their existing rendering and export behavior.
Export to HTML
POST /api/modules/canvas/export-html ({ title, path?, content_html }) saves the canvas as a standalone .html file in Documents (mime_type: text/html) and returns documentUrl and downloadUrl. Bare HTML fragments are wrapped in a full document, and signed generated-image URLs are inlined as data: URIs so the exported file works outside Clapilot. Scripts and interactivity are preserved as-is.
Public link
A canvas file can be published under a login-free URL. POST /api/modules/canvas/public-share ({ path, shared?, expires_in?, force_new? }) creates — or returns the existing — active share and responds with its public url of the form /share/canvas/<hash>; GET (query path, shared) reads the current share, DELETE revokes it. Shares are stored in the canvas_public_shares table and point at the file by path, so the link always serves the current file content, including later edits. The public route GET /share/canvas/[hash] is rate-limited, marked noindex, and served with a sandboxing CSP (scripts run with an opaque origin and cannot use a logged-in viewer's session against app APIs). Expired or revoked links stop resolving; deleting or renaming the underlying canvas file makes the link return 404. The public link is separate from instance-internal sharing (see Sharing above).
How the agent can drive it (tools)
Canvas exposes first-class native ClapilotAICore tools:
canvas_list_filescanvas_get_filecanvas_get_turn_assetscanvas_duplicate_filecanvas_create_filecanvas_update_filecanvas_edit_filecanvas_delete_filecanvas_create_foldercanvas_delete_foldercanvas_list_templatescanvas_get_templatecanvas_create_templatecanvas_create_file_from_templatecanvas_export_pdfcanvas_export_htmlcanvas_render_imagecanvas_share_itemcanvas_unshare_itemcanvas_create_public_linkcanvas_revoke_public_linkcanvas_get_style_settingscanvas_update_style_settings
Behavior notes:
canvas_edit_fileapplies targetedold_string/new_stringreplacements to the stored HTML atomically (eachold_stringmust match exactly once unlessreplace_all=true) and never re-applies the global Canvas style — it is the preferred tool for localized edits, whilecanvas_update_fileremains the path for full rewrites.canvas_get_turn_assetsexposes only images attached to the current turn as ordered, compact signed Canvas asset URLs. Shared viewers can load those URLs, while server-side render/PDF export hydrates only these verified local assets without opening general network access. Presentation edits map those assets to explicit slide numbers and embed them into the active file; attached references never implyimages_generate.canvas_duplicate_filecreates and selects a personal HTML-preserving version of the active or specified file. Presentation agents use it before substantial redesigns, validate one named example slide first, and only roll the design out after approval.- During presentation rebuilds, the latest user instruction and the open file's
activeFilePath/canvasTitleoverride retrieved memory and older chat context. The original remains an untouched backup; the duplicate receives only the decisions relevant to the current request, and broader rollout waits for approval of one rendered example slide. canvas_get_file,canvas_update_file,canvas_edit_file, andcanvas_delete_filecan resolve the active file from Canvas page context whenpathis omitted. Shared files publishactiveFilePath=shared:<path>; the same canonical reference (orshared=truewith a plain path) preserves collaborator read/write scope through the agent bridge.canvas_update_fileis restart-safe: its durable run/tool-call identity is journaled with a content hash and Canvas revision, so repeated recovery returns the already-applied revision without a duplicate write; callers may passexpected_revisionfor optimistic concurrency.- Mutating tools emit
canvas.file.updated, which the open Canvas module consumes to upsert, select, update, or remove the visible file without a manual reload. canvas_create_file,canvas_update_file, andcanvas_create_templateapply the global Canvas style settings to agent-authored HTML by default. Agents should keepuse_canvas_style=trueunless the user explicitly supplies or requests a custom style that must be preserved.canvas_get_style_settings/canvas_update_style_settingsread and change those global style settings, which are edited in the app under Settings → Styleguide (/settings/styleguide; the former/settings/canvas-stylepath redirects there).canvas_get_style_settingsadditionally returnsstyleguide_assets— the workspace's uploaded brand-asset library (also listable viastyleguide_list_assets) — so agents embed real brand marks via each asset'surlinstead of generating lookalikes.- Template tools let agents learn recurring document layouts. For example, after a user uploads an outgoing invoice PDF, the agent should inspect the source preview, save refined template HTML with placeholders via
canvas_create_template, and later callcanvas_create_file_from_templatewith invoice data to generate new invoices. canvas_export_pdfrenders the active or specified Canvas HTML file as a PDF, accepts the same format/orientation/margin controls as the UI, saves it in Documents, and returns the Clapilot document preview URL, direct download URL, and page count.canvas_export_htmlsaves the active or specified Canvas HTML file as a standalone.htmlDocuments entry with generated images inlined. Agents prefer it overcanvas_export_pdfwhen the canvas is functional or interactive (scripts, forms, calculators, animations) — a PDF would freeze the interactivity. On a plain "export" request without a format, agents choose PDF for document-like content and HTML for interactive content and say which they picked.canvas_create_public_linkcreates (or returns the existing) public share link for a canvas file and returns its login-free URL; the link always serves the current file content. Because it makes the file reachable for anyone with the URL, agents only call it when the user clearly asks to share or publish.canvas_revoke_public_linkdeactivates the link. Both are separate from instance-internalcanvas_share_item/canvas_unshare_item.canvas_render_imagerenders the active or specified Canvas HTML file (screen media, JavaScript enabled, network blocked) as a PNG screenshot and delivers it to the model as vision input so the agent can visually verify its own output. The tool is only advertised to vision-capable models; providers whose transport cannot carry tool images receive a text note instead of the screenshot.canvas_share_itemandcanvas_unshare_itemtoggle instance-wide sharing for afile,folder, ortemplate(owner-controlled; see Sharing above). Shared files and templates remain readable and editable by collaborators in both the UI and agent tools; deletion and unsharing remain owner-only. List/get responses exposesharedandowned_by_meso the agent can tell which items are already shared and which it owns before unsharing.- When the active UI context is
/modules/canvas, agent requests for diagrams, charts, tables, dashboards, text pages, or HTML visualizations should create or update Canvas files with these tools instead of returning inline chat artifacts such as[clapilot_canvas]. - In active Canvas context, the current user message controls routing. Image generation/editing tools are unavailable unless that message explicitly asks for an image asset; a Canvas edit or negative instruction such as “kein Bild generieren” therefore cannot fall through to image generation.
- Existing Canvas files are read with
canvas_get_filebefore mutation. Additive requests—such as another creator, profile, section, or slide in a shared shortlist—preserve existing content and update the active file instead of creating a second presentation. The agent reports completion only after a Canvas mutation succeeds. - Agents should use these tools for Canvas edits instead of writing directly to the filesystem or only returning suggested HTML.
- New image creation remains available by explicitly combining
images_generatewith Canvas editing tools. User-supplied images take the separatecanvas_get_turn_assetspath and are not regenerated.
Configuration & limits
- Storage: user-owned
.htmlfiles live under the Clapilot workspace runtime state area at.clapilotaicore/canvas/; templates under.clapilotaicore/canvas-templates/. - Image embedding cap: generated and dropped images are embedded as
data:URLs when small enough so the.htmlfile stays self-contained and renders in shared or exported copies. Above the size cap, generated images fall back to an owner-gated/api/generated-images/{id}reference. - Shared addressing: the files, folders, and templates
GET/PUT/PATCH/DELETEendpoints accept a?shared=1query parameter (also?scope=shared) to address the shared copy of an item instead of the caller's private one. - Toolbar/autosave scope: the formatting toolbar, autosave, and drag & drop are UI-only affordances; they reuse the existing
PUT /files/:pathsave contract and add no new API or agent-tool surface.
API endpoints exposed by module
Base: /api/modules/canvas/api — implementation: bundled-modules/canvas/api/handler.mjs.
GET /files(recent recursive.htmlfiles; supportslimit,search, andfolder)POST /files({ title?, path?, folder?, content_html? }) creates a new Canvas fileGET /files/:pathloads one Canvas file and its HTMLPUT /files/:pathorPATCH /files/:pathreplaces one Canvas fileDELETE /files/:pathdeletes one Canvas fileGET /folderslists Canvas folders, including empty foldersPOST /folders({ path }) creates a subfolderPUT /folders/:pathorPATCH /folders/:pathrenames a folder path and keeps contained Canvas files under the new pathDELETE /folders/:pathdeletes a folder and all contained Canvas files/subfoldersGET /templateslists reusable Canvas templatesPOST /templatescreates a template from JSON or a multipart uploaded source documentGET /templates/:idloads one template, including HTML, fields, and source previewPUT /templates/:idorPATCH /templates/:idupdates a templateDELETE /templates/:iddeletes a templatePOST /templates/:id/filesrenders a template into a new Canvas.htmlfile withdataPOST /share({ kind: "file" | "folder" | "template", path?, template_id? }) shares an item with every user in the instancePOST /unshare(same body) revokes a share; only the owner may unshare. Usepathforfile/folderandtemplate_idfortemplate.GET /preview/:pathserves one HTML file as a no-store preview responseGET /health
Additional app APIs:
POST /api/modules/canvas/export-pdf(see Export to PDF above; marked A4 overflow returns422with{ code, overflows: [{ page, overflowMm }] })POST /api/modules/canvas/export-htmlsaves the canvas as a standalone.htmlDocuments entry (see Export to HTML above)GET/POST/DELETE /api/modules/canvas/public-sharereads, creates/rotates, or revokes the public link of a canvas file (see Public link above)GET /share/canvas/[hash]— public, login-free route serving the current HTML content of a shared canvas file (rate-limited,noindex, sandboxing CSP)
Troubleshooting
- A shared file shows one broken image: a generated image above the embed size cap is stored as an owner-gated
/api/generated-images/{id}reference; it renders only for the owner. Regenerate a smaller image or embed it manually. - Applying a heading changed the paragraph color: headings are block-level, so applying a heading restyles the whole paragraph (including its color); use the color picker to adjust afterwards.
- Autosave seems paused: autosave intentionally pauses while an agent is live-editing the document and only covers already-persisted files and templates.
File context menu
Right-click a file in list or grid view for Rename, Copy, Share, Download and Delete. Download offers HTML and PDF. Share offers Email, Fax, Post and Chat (Channel or Direct message). Exports include unsaved changes for the clicked active file; other files are read independently. Source shared/private scope is preserved.
The Apple clients use native context menus (right-click on Mac, long-press on iPhone/iPad). Sharing opens the authenticated Clapilot review/composer flow. Channel and direct-message sharing links to the original authenticated module/item and retains its permissions; no export or public link is created. Email continues to use a revocable public document link. No message is sent automatically.
Internal links in chat automatically show authenticated inline media or a clickable reference to the original item. Videos have playback controls, images have previews, and other documents/module items use document-style references. This also applies to existing messages and the Apple clients; no exported copy or public link is generated.
