README file from
GithubWhy Prism?
- 🤖 Built for agents. Your agent writes a
```vizblock, renders the note from the command line and gets back errors with note line numbers plus a PNG snapshot. It fixes the block until the render is clean, with no copy-pasting screenshots back and forth. A ready-made skill teaches Claude Code and Codex how to do it. - 📒 Your notes are the data. Chart a Markdown table, the frontmatter of every note, your tasks, links and backlinks, or a CSV in your vault. Edit the note and the chart follows. Widgets can write back too: check off tasks, fill in a habit tracker, set a property.
- 🎨 Looks like it belongs. Blocks pick up your theme's colors and fonts, switch live between light and dark, size themselves and show up in PDF exports.
- 🔒 Safe by default. Every block runs in a sandboxed iframe with a strict CSP and no network access. Chart.js, D3, Mermaid, three.js and KaTeX are bundled, so everything works offline.
Install
From the community plugins (recommended)
- Open Settings → Community plugins → Browse and search for Prism.
- Select Install, then Enable.
- https://community.obsidian.md/plugins/prism-viz
With BRAT (for beta versions)
- Install and enable BRAT from the community plugins.
- Run BRAT: Add a beta plugin for testing and enter
floorianmb/prism-viz. - Enable Prism under Settings → Community plugins.
Manually
- Download
main.js,manifest.jsonandstyles.cssfrom the latest release. - Put them into
<your vault>/.obsidian/plugins/prism-viz/. - Reload Obsidian and enable Prism.
Just looking? Open the examples/ folder as a vault. It has a note for every feature.
Quickstart
Put a table in a note and add a chart below it. No code needed:
| Month | Notes | Tasks done |
| ----- | ----: | ---------: |
| Jan | 34 | 21 |
| Feb | 41 | 29 |
| Mar | 57 | 38 |
^stats
```viz chart title="My vault in Q1"
type: bar
source: ^stats
x: Month
```
Change a number in the table and the chart updates. Want more? A ```viz block takes any HTML, SVG and JavaScript, with the bundled libraries and a prism API for your notes:
```viz chart title="Notes by type"
<canvas id="c"></canvas>
<script>
prism.notes().then(notes => {
const counts = {};
for (const n of notes) { const t = n.frontmatter.type ?? "(none)"; counts[t] = (counts[t] || 0) + 1; }
new Chart(c, { type: "bar", data: { labels: Object.keys(counts), datasets: [{ data: Object.values(counts) }] },
options: { plugins: { legend: { display: false } } } });
});
</script>
```
Or start from a template: Prism: Insert starter (dashboard, architecture diagram, timeline, chart from frontmatter, chart from a table, formula).
Use it with Claude Code or Codex
-
Install the skill. Prism opens a page with the install command for your vault after you install or update it; open it again any time with Prism: Install agent skill. On macOS/Linux the command is:
d="$(mktemp -d)" && git clone --depth 1 https://github.com/floorianmb/prism-viz.git "$d" && node "$d/scripts/install-skill.mjs" --vault '/path/to/your/vault' && rm -rf "$d"This installs the newest skill. The page in Obsidian fills in your vault path and installs the skill of your Prism version (
git clone --branch <version>). Run it again after updating Prism; from 0.6.5 on, the skill tells you when it no longer matches the installed plugin.It copies
skill/to~/.claude/skills/prismand~/.codex/skills/prism(wherever those folders exist) and puts the render script into the vault's plugin folder (the community plugin download only containsmain.js,manifest.jsonandstyles.css). From a clone:npm run install-skill -- --vault '/path/to/your/vault'. For other agents, run Prism: Generate agent rules as well. It writesPRISM.mdand a snippet for yourCLAUDE.md/AGENTS.md. -
Ask for a visualization, e.g. "Add a dashboard of my reading list to Books.md".
-
The agent closes the loop on its own:
node .obsidian/plugins/prism-viz/scripts/prism-render.mjs "Books.md"Without Obsidian running,
prism-render.mjs --lint "Books.md"checks the note offline (YAML errors, unknown keys, missing tables and columns, script syntax errors) and prints the same JSON; exit0= ok,1= errors,4= file not found. It is static, so the agent lints first and renders for the snapshot. Seedocs/lint.md.The note renders invisibly in the running Obsidian app. The command prints JSON with every error (note line, origin, message) and the paths of the PNG snapshots, and exits with
0= ok,1= block errors,2= render failed,3= Obsidian not reachable. The agent fixes the block, looks at the snapshot and renders again until the result is clean.
If something breaks while you are reading, use Copy prompt for agent in the block's menu or error panel. It copies the location, the errors, the source and the render command, ready to paste.
Features
vizcode blocks (Live Preview and Reading view): HTML fragment or full document, rendered in an iframe viasrcdoc. Info line: library keywordschart,d3,mermaid,three, plusheight=N,title="…",id=name,raw,eager,notoolbar,source. All libraries are bundled intomain.js.- No-code charts: a
```viz chartblock may contain a YAML spec instead of HTML (type,source: ^table-id | table:<heading> | file.csv | notes,x,y,series,filter,aggregate,sort,stacked…). - Charts from frontmatter:
source: notesgives one row per note (title, every property, folder, modified, tags), narrowed withfolder:andtag:;aggregate: count | sum | avg | min | maxgroups them. "Notes per status" or "mood over time" in five lines of YAML. Seedocs/frontmatter-charts.md. - Charts from tasks:
source: tasksgives one row per task of your notes (text, done, due, done date, priority, tags, note): open tasks per project or tasks done per day without code. - Calendar heatmaps and maps:
type: calendarshows one cell per day (daily notes, habits, tasks done; a click opens the day's note),type: mapcolors the regions of a GeoJSON file from your vault. Seedocs/calendar-and-map.md. - Periods, goals, computed columns:
group: monthcounts or sums dates per day, week, month, quarter or year;goal: 40andlinesdraw reference lines;compute: { pace: "pages / days" }adds columns (charts and tables, noeval). Seedocs/periods-goals-compute.md. - KPI tiles, timelines, link graphs, flows:
type: kpi(big numbers, change to the last period, sparkline, goal bar),type: timeline(Gantt from tasks or notes),source: links+type: graph(the link network of your notes) andtype: sankey. Seedocs/new-chart-types.md. - Click to source: a click on a bar, point or segment of a chart without
selectopens the table row in the note, the note or the task's line behind it. Seedocs/cross-filter.md. - Cross-filter:
select: genreon a chart andfilter: { genre: $shared.genre }on a table or chart: a click on a bar filters the other blocks of the note. Seedocs/cross-filter.md. - Tables:
```viz tablerenders a searchable, sortable table with locale number formats, source links and confidence badges. - Formulas:
```viz mathrenders LaTeX with KaTeX (offline, fonts inlined, mhchem). - Mermaid that navigates:
A["[[Note]]"]labels open the note on click. - Bases: a "Prism chart" view for
.basefiles (Obsidian 1.10+): group by a property, count or aggregate a value, split into series, stacked, sorted; also as calendar and map. - HTML files:
![[file.html]]embeds use the same renderer, and.htmlfiles open in a Prism view. Options via<meta name="prism" content="chart height=400">,<!-- prism: … -->or![[file.html|height=400]]. - Page monitor:
```viz monitorshows RAM and CPU of the page it is on.
prism.note()returns the block's own note: frontmatter, headings, links, backlinks, tasks and typed Markdown tables (German number formats, units,–as empty).prism.onNoteChangefollows edits.prism.notes({ folder, tag, limit, sort, order, include })queries the vault (read-only path, title, tags, frontmatter, mtime).include: ["links", "backlinks", "headings", "tasks"]adds those per note, and tasks carry Tasks-plugin dates and priorities.prism.onNotesChangefires on changes.- Widgets that edit their note:
prism.edit.setTask,setCell,addRowandsetPropertychange the block's own note: habit trackers, checklists, boards, quick-entry forms. Each block asks once ("Allow edits"), changes in the editor can be undone with Cmd/Ctrl+Z, and other notes are never touched. Seedocs/note-edits.md. - Data files:
prism.data("folder/file.csv")reads CSV/TSV (row objects, column-wise typed), JSON/GeoJSON, YAML and TXT. Access is read-only and limited to the folders listed under Data folders in the settings (empty = off; notes and hidden files are never readable).prism.dataFiles(folder?)lists them,prism.onDataChange(cb)follows changes, andprism.parseCsv(text)parses inline CSV.
- Shared state:
prism.sharedis state shared by all blocks of a note.prism.state.bind/prism.shared.bindtwo-way bind form controls, so a slider in one block can drive charts in others. - Scrollytelling:
prism.onSection(cb)reports the heading the reader is at while scrolling. - Variants:
prism.variantsshows alternative views of the same content with a persisted switcher. - Building blocks:
prism.canvas(crisp canvas that follows its element),prism.animate(frame loop with real elapsed time that pauses off screen and respects reduced motion),prism.segmented(persisted segmented control) and the classes.toolbar,.stage,.hud,.chip,.icon-button,.caption. - Persisted state:
prism.state.get/set/deleteis stored in the plugin data, andlocalStorageis shimmed onto it. Give a blockid=nameto pin its state; without an id, the state moves along with the block when blocks above it are inserted, removed or edited. Seedocs/block-state.md.
- Render on demand:
obsidian://prism?render=<note path>[&id=…&snapshot=0&width=720&timeout=60]renders every viz block of a note (or an HTML file) invisibly in the running app and writes.prism/renders/<id>.jsonandlatest.json(status, errors with note lines, snapshot paths, and how much each block's snapshot changed since the last render). The CLIscripts/prism-render.mjswraps it.--all [folder]renders every note with viz blocks and prints a summary. On macOS Obsidian stays in the background. - Offline check:
prism-render.mjs --lint "<note>"(or--lint --all [folder]) finds spec and script errors without Obsidian. Seedocs/lint.md. - Errors in the editor: the lines that caused an error or warning are underlined in Live Preview and source mode, with the message at the end of the line. See
docs/editor-errors.md. - Error feedback:
window.onerror, unhandled rejections,console.error, CSP violations, Mermaid errors and timeouts show up as a badge and are written to<vault>/.prism/errors.jsonwith note path and line numbers. Optional PNG snapshots go to.prism/snapshots/. - Agent skill (
skill/):SKILL.mdwith the plan → write → render → fix workflow,design.mdwith the quality bar, andreference.mdwith the full API. Prism: Install agent skill shows the install command for your vault. - Gallery: Prism: Open gallery lists every viz block of the vault with its latest snapshot and render status. Render previews renders the missing ones.
- Theme bridge: Obsidian's CSS variables (colors, fonts, sizes, palette) are available inside the frame and update live on theme and light/dark changes. A default stylesheet and helper classes (
.card,.grid,.row,.kpi, …) are included; opt out withraw. Chart.js and Mermaid follow the theme automatically. - Auto-height via
ResizeObserver, cached per block so re-renders do not jump. - Pinch to zoom: pinch on the trackpad or touch screen to zoom into any block (up to 500 %, never below 100 %, no empty space around the content). Scrolling keeps scrolling the note; drag to move around while zoomed. See
docs/pinch-zoom.md. - Page previews: note links inside blocks show Obsidian's hover preview after a short rest on the link (Settings → Prism → Link preview delay, default 0.6 s;
prism.hoverNotefor canvas/SVG hit areas). Blocks know about fullscreen viaprism.displayMode. - PDF export: each block is rendered in the light theme and replaced by a static PNG.
- Baked images for Publish and GitHub: Prism: Bake blocks as images saves a PNG of every block of a note and links it below the block. Where Prism does not run (Obsidian Publish, GitHub, other apps), readers see the image; in Obsidian with Prism it stays hidden. See
docs/bake.md. - Block menu: one small ⋯ button opens show source, reload, fullscreen, PNG export, copy as PNG, record a 5 s WebM video, SVG export, CSV export (charts and tables without code: the numbers they show, in your language's number format), save as
.html, copy source / errors and Copy prompt for agent. In blocks with atitleit sits in the title row, so it never covers the content; otherwise it shows in the top right corner on hover. Reset zoom appears next to it while a block is zoomed.
- Sandbox:
sandbox="allow-scripts"(no same-origin, top navigation, popups, forms or modals) and the CSPdefault-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob:; font-src data:;plusbase-uri/form-action 'none'. Messages are accepted only from the block's own frame with a per-render token, and navigation away from the srcdoc is detected and reverted. - Network is off unless you allowlist domains. Online access is opt-in and off by default: API requests (
prism.http, requests wait for a click by default, approved per host) and Web pages (```viz webblocks, iframes). Turning either on shows the consequences and asks for confirmation. - Robustness: lazy rendering, loops in user scripts are stopped after 2 s of blocking, a ready/heartbeat watchdog with a Stop button, a crash guard that does not auto-run a block that froze Obsidian before, and full cleanup on unload.
The complete API is documented in skill/reference.md.
Settings
Default height, maximum auto height, theme sync, lazy rendering, error log, errors in the editor, blocks may edit their note, snapshots, data folders, network allowlist and online access.
Network use and privacy
Prism works offline and does not connect to the internet unless you turn that on yourself.
- No network by default. Chart.js, D3, Mermaid, three.js, KaTeX and html-to-image are bundled in
main.js. Nothing is downloaded at runtime, and the plugin never installs or updates code on its own. - No telemetry, no account, no ads. Prism has no server of its own and sends no usage data anywhere.
- Opt-in network access. Only these settings, all empty or off by default, let blocks reach the network. Which remote services are contacted depends entirely on the URLs and domains you put into your notes and settings:
- Network allowlist: blocks may load scripts, styles, images and fonts from, and send requests to, the domains you list here.
- Online access → API requests: blocks may call web APIs with
prism.httpthrough Obsidian'srequestUrl, to show live data. By default nothing is sent until you click Run requests below the block. The click approves only the hosts the bar names; a request to any other host asks again. Seedocs/online-access.md. - Online access → Web pages:
```viz webblocks and<iframe>s may show web pages inside a note.
- Code in your notes. A
```vizblock runs the HTML and JavaScript written in the note, in a sandboxed iframe (scripts only, strict CSP, no direct access to Obsidian or your vault, and no network beyond what you allow above). Only use blocks from sources you trust, as with any code you run. - Files. The plugin only works inside your vault. It reads data files from the folders you list under Data folders (read-only) and writes to
.prism/(error log, render results, snapshots), plus files you create on purpose (exports, baked images,PRISM.mdfrom Generate agent rules). A block changes its own note only throughprism.editand only after you clicked Allow edits for it (Settings → Prism → Blocks may edit their note turns this off). Only the install script for the agent skill (scripts/install-skill.mjs) writes outside a vault (~/.claude/skills,~/.codex/skills), and only when you run it yourself in a terminal; the plugin just shows the command. - Vault index. To answer
prism.notes()(names, tags, frontmatter, links, tasks), to list data files and to find blocks for the gallery and command-line renders, Prism goes through the file list of your vault. That metadata only goes to blocks in your own notes and never leaves Obsidian. - Clipboard. Prism writes to the clipboard only when you pick a copy action (copy as PNG, copy source or errors, copy prompt, embed link after an export). It never reads the clipboard, and blocks have no clipboard access.
- Local storage. Measured block heights and the crash guard use Obsidian's per-vault local storage; block state is saved in the plugin's
data.json. - Desktop only. The page monitor reads CPU and memory figures of Obsidian's own processes through Electron. These stay on your machine.
Development
npm install
npm run build # type-check, bundle the libraries and main.js, generate skill/reference.md
npm run dev # watch mode
npm test # unit tests (test/*.test.ts, Node's test runner; no Obsidian needed)
The runtime files are manifest.json, main.js and styles.css. Pushing a tag that matches the manifest version (e.g. 0.3.0) builds them and publishes a GitHub release.
Releasing. manifest.json holds the version; the build takes prism.version and the version in PRISM.md from it. For a release:
- Set the version in
manifest.jsonandpackage.json, runnpm install(updatespackage-lock.json) and add"<version>": "<minAppVersion>"toversions.json. - Add a
## <version> – <date>section toCHANGELOG.md; the release notes are taken from it. - Run
npm run check-versionandnpm test. The version check fails when any of these files disagree; CI and the release workflow run both. - Commit, then push a tag named exactly like the version.
main.ts plugin: code block processor, commands, notes query, exports, snapshots
src/frame.ts one rendered block: iframe lifecycle, message bridge, toolbar, errors, watchdogs
src/document.ts srcdoc builder (CSP, theme, base CSS, libraries) and line map
src/runtime/prelude.ts iframe runtime (window.prism), bundled to a string at build time
src/runtime/chartSpec.ts declarative chart spec → Chart.js config
src/runtime/table.ts interactive table for ```viz table / prism.table
src/runtime/periods.ts group: day | week | month | quarter | year (labels, gaps)
src/runtime/compute.ts compute: expression parser for computed columns (no eval)
src/runtime/kpi.ts type: kpi tiles
src/runtime/timeline.ts type: timeline (Gantt)
src/runtime/graph.ts type: graph (force layout of links)
src/runtime/sankey.ts type: sankey
src/runtime/trace.ts click to source: chart label → rows → note or table row
src/basesSpec.ts spec building for the Bases view (pure, tested)
src/lint.ts offline check of viz blocks (bundled to scripts/prism-lint.mjs)
src/noteInfo.ts note tables, headings and tasks for prism.note() / prism.notes({ include })
src/basesView.ts "Prism chart" view for Obsidian Bases
src/loopGuard.ts infinite-loop instrumentation (acorn)
src/theme.ts Obsidian theme → CSS variables
src/errorLog.ts .prism/errors.json
src/htmlFile.ts .html view and embeds
src/data.ts data file path resolution and allowlist
src/perf/ page monitor: block stats, Electron process metrics
src/online/ opt-in network access: settings + consent, prism.http, ```viz web blocks
scripts/prism-render.mjs CLI for agents (render a note, print JSON; --lint checks offline)
scripts/prism-lint.mjs generated from src/lint.ts by scripts/build-lint.mjs, imported by --lint
scripts/build-skill.mjs skill/reference.md from src/agentRules.ts (part of npm run build)
scripts/install-skill.mjs installs skill/ for Codex and Claude Code (+ prism-render.mjs into --vault)
scripts/test.mjs runs test/*.test.ts (bundled with esbuild, run with node --test)
test/ unit tests for the pure modules (document, note edits, charts, data paths, state)
examples/ example vault with a note per feature
docs/pinch-zoom.md how pinch zoom works (host transform, gesture messages, clamping)
docs/block-state.md how prism.state is keyed and moves along when blocks are inserted or removed
docs/online-access.md online access settings, per-host approval of requests, limits
docs/note-edits.md prism.edit: API, approval, how edits are applied
docs/frontmatter-charts.md source: notes / tasks and aggregate in declarative charts and tables
docs/calendar-and-map.md type: calendar and type: map (also in Bases)
docs/cross-filter.md select and $shared filters between blocks, click to source
docs/periods-goals-compute.md group, lines, goal, compute
docs/new-chart-types.md type: kpi, timeline, graph, sankey, source: links
docs/lint.md prism-render.mjs --lint
docs/editor-errors.md error marks in the editor
docs/bake.md baked images for Publish, GitHub and other apps
src/noteEdit.ts prism.edit: task/cell/row edits on note text, approval bar
src/editorErrors.ts CodeMirror decorations for block errors
src/bake.ts baked image lines and relative links
scripts/check-version.mjs checks that manifest, package, versions.json and changelog agree
Limits
errors.jsonreflects the last render, either when a block was visible in Obsidian or viaobsidian://prism?render=…. The render command needs the desktop app (it launches Obsidian if it is not running).![[file.html]]embeds use Obsidian's internal embed registry. If it is unavailable, embeds fall back to Reading view only.- PNG export and snapshots use html-to-image. WebGL canvases need
preserveDrawingBuffer: true, and export needs the block to be visible.
License
MIT, see LICENSE. Third-party licenses: THIRD_PARTY_LICENSES.txt.