@digitalvibes/mood-board
v0.2.3
Published
A local, FigJam-like mood board canvas that stores its data in .dibe/ so AI coding agents can read it as a style reference.
Maintainers
Readme
@digitalvibes/mood-board
An endless notes-and-mood canvas that lives in your repo, so the AI agent working in that repo can read your design direction instead of guessing it.
Sketch a site the way you'd sketch it in FigJam — sticky notes, images, colour swatches, rough boxes, headlines — then group the pieces and say what each group is a reference for. Everything lands in .dibe/mood-board/ as JSON plus a Markdown brief.
- Zero build. Plain JavaScript shipped as-is — no bundler, no transpile, no lifecycle scripts. Nothing compiles on install, and it never touches your app's build.
- Zero dependencies. Node's standard library and a
<canvas>. - Framework agnostic. Next, Astro, Rails, a static site, an empty folder — it only cares about a directory.
npx @digitalvibes/mood-boardThat's it. The canvas opens at http://localhost:4321, and .dibe/mood-board/ appears in your project.
Install into a project
npm install --save-dev @digitalvibes/mood-boardTell your AI agents it exists:
npx dibe-mood-board docsThat inserts a short managed block into whichever agent instruction files you already have
(AGENTS.md, CLAUDE.md, .cursorrules, .windsurfrules,
.github/copilot-instructions.md), pointing them at the board. It only touches the text
between its own markers, so re-running it refreshes the block and leaves everything else
byte-for-byte alone. Use --check for a dry run. If you have no agent doc at all, it
creates AGENTS.md.
Add the start command:
// package.json
{
"scripts": {
"moodboard": "dibe-mood-board"
}
}npm run moodboardUsing the canvas
Drag an image file anywhere onto the canvas and it's copied into .dibe/mood-board/assets/ and placed where you dropped it. Paste works too, including screenshots straight from the clipboard, and dragging an image out of another browser tab.
| | | |---|---| | Double-click empty canvas | New sticky note | | N T R S I L | Note, text, box, swatch, image, link | | V / H / hold Space | Select / pan | | Scroll / ⌘+scroll | Pan / zoom | | ⌘G / ⇧⌘G | Group / ungroup selection | | ⇧1 / ⇧2 | Zoom to fit / to selection | | ⌘D, ⌘Z, ⌘[ ⌘] | Duplicate, undo, send back / bring forward |
Light and dark both ship; the toggle in the top bar cycles light → dark → system, and system follows your OS.
Everything autosaves. There is no save button.
Groups are the unit of meaning
A group is what turns a pile of references into something an agent can act on. Give it a name, and fill in intent — one line saying what it's a reference for: "the landing page hero", "empty states", "how our screenshots should look". That sentence is what makes the difference between an agent guessing and an agent knowing.
Select a group and hit Export PNG (or Export in the top bar for all of them) to render a snapshot into .dibe/mood-board/exports/. The Markdown brief links to it, so an agent that can see images gets the composition, not just the coordinates.
What your agent reads
.dibe/mood-board/
├── BOARD.md ← the brief: palette, type scale, every group, in reading order
├── board.json ← canonical data
├── AGENTS.md ← instructions telling an agent how to use the above
├── assets/ ← images you dropped
└── exports/ ← rendered group PNGsBOARD.md is regenerated on every save. Point your agent at it:
Read
.dibe/mood-board/BOARD.mdand build the hero section to match.
Or pipe it in directly:
npx dibe-mood-board read | pbcopyAGENTS.md is written for the agent, not for you — it explains the coordinate system, what each node type means, and how to edit the board safely.
It works in both directions
Your agent can edit board.json itself — adding swatches it derived from your CSS, filling in alt text, or proposing a layout. The canvas watches the file and picks up outside changes within a second, so if you have it open you'll see them appear. Writes are guarded by an ETag, so the canvas and an agent can't silently overwrite each other.
CLI
npx dibe-mood-board [command] [options]
start Open the canvas (default)
init Create .dibe/mood-board/ without starting the server
read Print the Markdown brief to stdout
json Print board.json to stdout
path Print the mood board directory
docs Add a pointer to this repo's agent docs
-p, --port <n> Port (default 4321, walks upward if taken)
-d, --dir <p> Project directory (default: cwd)
-n, --name <s> Board name when creating it
--no-open Don't launch a browser
--check With docs: report what would change, write nothing
--all With docs: create every known agent doc fileProgrammatic API
import { readBoard, readDigest, findGroup, palette, typeScale, imagePaths } from '@digitalvibes/mood-board'
const board = await readBoard()
findGroup(board, 'hero') // by id, name, slug or tag
palette(board) // [{ color: '#F2A93B', label: 'Amber', usage: 'primary button' }]
typeScale(board).heading[0] // largest heading on the board
imagePaths(board) // absolute paths, so you can open the images
await readDigest() // the same Markdown as BOARD.mdData model
Nodes carry absolute canvas coordinates, including nodes nested inside a group. Nesting means "these belong together"; the group's frame is the rectangle drawn behind them.
{
"version": 1,
"name": "Aperture — landing",
"groups": [
{
"id": "grp_ab12cd34ef",
"name": "Hero section",
"intent": "Reference for the landing page hero",
"tags": ["hero", "landing"],
"frame": { "x": 0, "y": 0, "width": 780, "height": 660 },
"exports": ["exports/hero-section.png"],
"nodes": [
{ "id": "tex_a1", "type": "text", "text": "Develop your ideas in the dark.",
"role": "heading", "fontFamily": "serif", "fontSize": 62,
"x": 44, "y": 60, "width": 560, "height": 140 },
{ "id": "swa_b2", "type": "swatch", "color": "#F2A93B",
"label": "Amber", "usage": "primary button",
"x": 44, "y": 320, "width": 120, "height": 150 }
]
}
],
"nodes": []
}| Type | For |
|---|---|
| text | Copy, with a role of heading / body / note / label |
| note | A sticky — your commentary, not copy to ship |
| image | A reference image, with alt and caption |
| swatch | A colour, with label and usage |
| shape | rect / ellipse / line for rough wireframe blocks |
| link | An external reference |
A text node's color is a hex or the literal "auto", which follows the viewer's
light/dark theme. Only an explicit hex is a deliberate colour choice — auto is not a
design token, and the agent docs say so.
A group may declare "surface": "#FFFFFF", meaning it is designed on that background. The
canvas paints it behind the group in either theme, so a light-mode design stays legible
when you're working in dark.
Unknown keys you (or an agent) add to a node are preserved across saves, so annotating is safe. Full JSON Schema.
Committing a board
board.json, BOARD.md and assets/ are worth committing — that's the design direction, and it's how the board reaches your teammates and their agents. exports/ is gitignored by default since it's reproducible from board.json.
Requirements
Node 20+. A Chromium or Safari-based browser for the canvas.
Licence
MIT
