Native canvas pages

What this demonstrates

@quartz-community/canvas-page is a page-type plugin, not a transformer: it takes a file that is not Markdown at all — vault/experiments/sandbox-tour.canvas, a JSON Canvas 1.0 document — and emits an HTML route for it, complete with the site’s layout.

The canvas in this vault is a real diagram of the sandbox: the isolation boundary, the build pipeline, and file nodes pointing at actual pages of this site.

Open it: Sandbox Tour canvas

Configuration used

  - source: "@quartz-community/canvas-page"
    enabled: true
    options:
      enableInteraction: true
      initialZoom: 0.55
      minZoom: 0.1
      maxZoom: 4
    order: 50

initialZoom: 0.55 is a sandbox deviation from the upstream default of 1: the tour canvas is ~1240 units wide, so opening at just over half scale shows the whole isolation boundary without the reader having to zoom out first.

The layout is also specialised for this page type:

layout:
  byPageType:
    canvas:
      exclude:
        - table-of-contents
      positions:
        right: []

A canvas has no headings, so a table of contents would render empty; dropping the right sidebar entirely gives the canvas the full content column.

Content used

The canvas source is standard JSON. Three node kinds and labelled edges:

{
  "nodes": [
    { "id": "group-boundary", "type": "group", "x": -40, "y": 240,
      "width": 1240, "height": 420, "color": "1", "label": "Isolation boundary" },
    { "id": "shared", "type": "text", "x": 0, "y": 290, "width": 360, "height": 240,
      "color": "1", "text": "## Shared engine\n\n`/home/loca/dev/quartz/quartz`" },
    { "id": "page-config", "type": "file", "file": "config/index.md",
      "x": 320, "y": 1250, "width": 280, "height": 100, "color": "2" },
    { "id": "spec-link", "type": "link", "url": "https://jsoncanvas.org/spec/1.0/",
      "x": 960, "y": 1400, "width": 200, "height": 100, "color": "5" }
  ],
  "edges": [
    { "id": "e-shared-sandbox", "fromNode": "shared", "fromSide": "right",
      "toNode": "sandbox-engine", "toSide": "left",
      "label": "no shared state", "color": "1" }
  ]
}

Note what each node type costs the build: text nodes are rendered as Markdown at build time, file nodes become internal links (with popover previews, since enablePopovers is on), and link nodes become external anchors.

What the rendered output proves

The canvas route emits real HTML — a canvas container element with one positioned node element per JSON node, the text nodes’ Markdown already converted to HTML, an SVG layer for the edges, and a <title> from the file name. The interaction layer (pan and zoom) is client-side, but the content is server-rendered: with JavaScript disabled the nodes and their text are still in the document.

The route also proves the byPageType override applied: the canvas page has no table-of-contents element and no right sidebar, while this Markdown page has both.

safe_for_shared_engine

true — page-type plugins only claim files with their own extension, so a vault with no .canvas files emits exactly the same routes as before.