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, slug canvas, renderer react, icon chart) rendered directly in the app shell via src/components/modules/canvas-module.tsx and src/app/(app)/modules/[slug]/page.tsx.
  • The open module publishes page context with the active filePath, activeFilePath, and canvasTitle, so the global chat agent knows which file you are looking at.

Key workflows

Create and edit a file

  1. 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.
  2. 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, with styleWithCSS so color/font/size apply as inline CSS), and active states reflect the selection.
  3. Autosave persists dirty edits ~1.5s after typing stops (for already-persisted files and templates). The header indicator shows Saving …, Unsaved, or Saved <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.
  4. 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 model from POST /api/generated-images/generate; an explicit choice is sent as an override. The per-browser choice is stored in localStorage under clapilot.canvas.imageModel. The drawn frame's aspect ratio selects the closest provider size bucket (1024x1024, 1536x1024, or 1024x1536). 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 through POST /api/generated-images/import before POST /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

  1. 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.
  2. Refine the saved template HTML (yourself or via the agent) with semantic placeholders such as {{customer_name}}, {{invoice_number}}, and {{total}}.
  3. 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 shared and owned_by_me on 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_files
  • canvas_get_file
  • canvas_get_turn_assets
  • canvas_duplicate_file
  • canvas_create_file
  • canvas_update_file
  • canvas_edit_file
  • canvas_delete_file
  • canvas_create_folder
  • canvas_delete_folder
  • canvas_list_templates
  • canvas_get_template
  • canvas_create_template
  • canvas_create_file_from_template
  • canvas_export_pdf
  • canvas_export_html
  • canvas_render_image
  • canvas_share_item
  • canvas_unshare_item
  • canvas_create_public_link
  • canvas_revoke_public_link
  • canvas_get_style_settings
  • canvas_update_style_settings

Behavior notes:

  • canvas_edit_file applies targeted old_string/new_string replacements to the stored HTML atomically (each old_string must match exactly once unless replace_all=true) and never re-applies the global Canvas style — it is the preferred tool for localized edits, while canvas_update_file remains the path for full rewrites.
  • canvas_get_turn_assets exposes 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 imply images_generate.
  • canvas_duplicate_file creates 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/canvasTitle override 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, and canvas_delete_file can resolve the active file from Canvas page context when path is omitted. Shared files publish activeFilePath=shared:<path>; the same canonical reference (or shared=true with a plain path) preserves collaborator read/write scope through the agent bridge. canvas_update_file is 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 pass expected_revision for 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, and canvas_create_template apply the global Canvas style settings to agent-authored HTML by default. Agents should keep use_canvas_style=true unless the user explicitly supplies or requests a custom style that must be preserved. canvas_get_style_settings / canvas_update_style_settings read and change those global style settings, which are edited in the app under Settings → Styleguide (/settings/styleguide; the former /settings/canvas-style path redirects there). canvas_get_style_settings additionally returns styleguide_assets — the workspace's uploaded brand-asset library (also listable via styleguide_list_assets) — so agents embed real brand marks via each asset's url instead 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 call canvas_create_file_from_template with invoice data to generate new invoices.
  • canvas_export_pdf renders 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_html saves the active or specified Canvas HTML file as a standalone .html Documents entry with generated images inlined. Agents prefer it over canvas_export_pdf when 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_link creates (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_link deactivates the link. Both are separate from instance-internal canvas_share_item/canvas_unshare_item.
  • canvas_render_image renders 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_item and canvas_unshare_item toggle instance-wide sharing for a file, folder, or template (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 expose shared and owned_by_me so 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_file before 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_generate with Canvas editing tools. User-supplied images take the separate canvas_get_turn_assets path and are not regenerated.

Configuration & limits

  • Storage: user-owned .html files 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 .html file 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/DELETE endpoints accept a ?shared=1 query 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/:path save 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 .html files; supports limit, search, and folder)
  • POST /files ({ title?, path?, folder?, content_html? }) creates a new Canvas file
  • GET /files/:path loads one Canvas file and its HTML
  • PUT /files/:path or PATCH /files/:path replaces one Canvas file
  • DELETE /files/:path deletes one Canvas file
  • GET /folders lists Canvas folders, including empty folders
  • POST /folders ({ path }) creates a subfolder
  • PUT /folders/:path or PATCH /folders/:path renames a folder path and keeps contained Canvas files under the new path
  • DELETE /folders/:path deletes a folder and all contained Canvas files/subfolders
  • GET /templates lists reusable Canvas templates
  • POST /templates creates a template from JSON or a multipart uploaded source document
  • GET /templates/:id loads one template, including HTML, fields, and source preview
  • PUT /templates/:id or PATCH /templates/:id updates a template
  • DELETE /templates/:id deletes a template
  • POST /templates/:id/files renders a template into a new Canvas .html file with data
  • POST /share ({ kind: "file" | "folder" | "template", path?, template_id? }) shares an item with every user in the instance
  • POST /unshare (same body) revokes a share; only the owner may unshare. Use path for file/folder and template_id for template.
  • GET /preview/:path serves one HTML file as a no-store preview response
  • GET /health

Additional app APIs:

  • POST /api/modules/canvas/export-pdf (see Export to PDF above; marked A4 overflow returns 422 with { code, overflows: [{ page, overflowMm }] })
  • POST /api/modules/canvas/export-html saves the canvas as a standalone .html Documents entry (see Export to HTML above)
  • GET/POST/DELETE /api/modules/canvas/public-share reads, 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.