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.
  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 to PDF

The PDF action 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.

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_render_image
  • canvas_share_item
  • canvas_unshare_item
  • 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.
  • 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.
  • 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_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 API: POST /api/modules/canvas/export-pdf (see Export to PDF above; marked A4 overflow returns 422 with { code, overflows: [{ page, overflowMm }] }).

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.