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. - 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 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_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_render_imagecanvas_share_itemcanvas_unshare_itemcanvas_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.- 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.- 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_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 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.
