On this page
Neuron renders three kinds of user-authored surface documents, all stored as plain files in the workspace and all editable by hand (every surface has a Preview/Source toggle):
| File | Format | Renders as |
|---|---|---|
.html |
HTML + optional htmx attributes, inline CSS, and JavaScript | An isolated, offline HTML view tab (see htmx-views.md) |
.db |
JSON (schema + view state + rows) | Notion-style database (table / kanban board / card gallery) |
.canvas |
JSON Canvas (Obsidian-compatible) | Infinite spatial board |
index.html (+ neuron.app.json) |
HTML view + manifest inside a folder | A folder mini-app — the folder renders as one app instead of a file listing |
.neuron/layout.json |
JSON layout tree | The workspace shell layout |
HTMX views have their own architecture and threat model, documented in
htmx-views.md. This document covers the in-renderer surfaces
(.db, .canvas, the shell layout).
Embedding a database in MDX (<DbView>)
Notes render a .db inline with <DbView path="@Planner.db" table="tasks" view="board" />.
path is workspace-root-relative, prefixed with @; view is table
(default), board, or card. The component reads the file over the same
notes:read bridge as the DbSurface editor and re-reads on notes:changed, so
the embed tracks external edits live. It is read-only — the same URL
allowlist and the invalid/missing states apply; editing happens in the .db
tab. Code: src/renderer/components/DbView.tsx, wired into the MDX parser in
MDXPreview.tsx alongside <Badge>/<Callout>.
Removed: the earlier
.vwblock-view dashboards were replaced by HTMX views. Existing.vwfiles are left untouched on disk but are no longer listed or rendered; see the migration notes inexamples/demo-repo/building-htmx-views.mdx.
Folder mini-apps (index.html + neuron.app.json)
Any non-root folder that contains a neuron.app.json becomes a mini-app:
the sidebar collapses the folder into a single app entry instead of listing its
contents, and opening it renders the folder's index.html file. index.html is
an HTML view and neuron.app.json is its
manifest (the same schema as a view manifest — name, permissions,
allowedReadPaths/allowedWritePaths, networkPolicy). A manifest with no
permissions grants nothing, so a read-only app must list its read caps.
Mechanically a folder app reuses the entire HTMX-view pipeline (loopback server,
per-session token, sandboxed <webview>, capability-checked API) — it is just a
view whose entry point and manifest live inside the folder rather than as a
standalone .html + .neuron/manifests/ pair. The workspace root itself is
never treated as an app. See htmx-views.md for the view format,
API, permissions, and threat model; wiring is isViewPath/manifestPathFor in
src/main/htmx/index.ts and the sidebar's app-folder collapse in
src/renderer/components/Sidebar.tsx.
JSON Canvas (.canvas)
Neuron's canvas is spec-compatible with jsoncanvas.org
(Obsidian's format). Architecture, feature matrix, and compatibility contract:
json-canvas-enhancements.md.
Implementation code:
src/renderer/canvas/ (model, history, markdown) + surfaces/CanvasSurface.tsx.
Capabilities: pan/zoom (wheel, zoom controls, fit all/selection), text cards
with safe Markdown rendering, file cards (with missing-file badges), link and
group nodes, edge creation by dragging connector dots, edge labels, arrow
direction controls (default/both/none — spec fromEnd/toEnd), multi-select
(Shift-click, Shift-drag marquee), batch move/color/delete, align and
distribute, bring-to-front/send-to-back (spec array order = z), copy/cut/
paste/duplicate as standard JSON Canvas fragments (pasteable across canvases
and tools), snap-to-grid, undo/redo (Ctrl+Z / Ctrl+Shift+Z), context menus
on background/nodes/edges, and keyboard editing (arrows nudge, Shift for
bigger steps, Ctrl+A/C/X/V/D, Delete, Escape).
Compatibility guarantees: unknown top-level keys, unknown node/edge
properties, and unknown node types survive load→edit→save (nodes of foreign
types render as read-only "preserved as-is" cards). Standard fields are never
renamed or defaulted-into-existence; serialization is tab-indented like
Obsidian's. Recoverable parse problems (duplicate ids, bad geometry, dangling
edges) load with a warnings badge; unreadable files show the error and are
never rewritten. Deferred work is tracked in .claude/json-canvas-backlog.md.
Node styling (palette button or right-click → Style…) uses the versioned,
namespaced neuron extension — shape, border style/width, text alignment,
font size, opacity, and presets (idea/question/warning/decision):
{ "id": "n1", "type": "text", "x": 0, "y": 0, "width": 260, "height": 140,
"text": "# Idea", "color": "3",
"neuron": { "version": 1, "style": { "shape": "rounded", "borderStyle": "dashed", "preset": "idea" } } }
A node only gains a neuron object when a nonstandard property is changed,
and loses it again when the last one is cleared. Other JSON Canvas apps
simply ignore the extension and still show the standard card — presets write
the standard color field too, so the look degrades gracefully. Extensions
written by a newer Neuron (version > 1) are preserved untouched and never
edited by this version.
Rendering pipeline
- The renderer reads the file over the preload bridge (
notes:read); the file watcher (notes:changed) streams external edits in live. - Each surface parses its document defensively: size budget first, then format-specific validation. Invalid documents render an error state with a pointer to Source mode — they never crash and are never "fixed" silently.
- Every write goes back through the bridge (
notes:write), which performs an atomic write (temp file + rename) in the main process.
Error isolation
SurfaceBoundary wraps every open surface: a crashing view shows an inline
error and leaves the app shell, tabs, and Source mode fully usable.
Security model
The renderer runs with context isolation on and Node integration off; surfaces can only reach the world through the named preload methods. Within that, surface documents are treated as untrusted input — synced and shared workspaces mean the current user may not have written them.
Enforced by src/renderer/lib/view-security.ts (checked by
node tools/view-security.test.mjs):
- URL allowlist —
href/srcin.dblink cells and.canvaslink cards render onlyhttp:,https:, ormailto:URLs (≤ 2048 chars).javascript:,file:,data:, scheme-less, and protocol-relative URLs are dropped. Links open externally (target="_blank"+rel="noreferrer"). - Document budget —
.dband.canvasrefuse to parse documents over 2 MB instead of freezing the renderer.
Privileged operations are capability-shaped IPC handlers in the main process:
views:file reads workspace images for .canvas file nodes (path resolved
inside the active workspace only); notes:write performs workspace-confined
atomic writes. Surfaces cannot name arbitrary IPC channels, shell commands, or
filesystem paths outside the workspace.
Known limitations
- Table views are not virtualized; documents are capped at 2 MB, which keeps row counts in the low thousands. Add virtualization when a real workspace hits the ceiling.
- Board/gallery cards are read-only summaries; editing happens in table mode or by dragging cards between columns.