pmx-canvas 0.6.3 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/Readme.md +27 -6
- package/dist/canvas/global.css +90 -4
- package/dist/canvas/index.js +93 -91
- package/dist/canvas/mermaid-entry.js +258 -258
- package/dist/types/cli/agent.d.ts +1 -0
- package/dist/types/cli/commands/record.d.ts +12 -0
- package/dist/types/client/canvas/FeedbackDialog.d.ts +4 -0
- package/dist/types/client/canvas/Presentation.d.ts +13 -0
- package/dist/types/client/canvas/use-node-drag.d.ts +2 -1
- package/dist/types/client/nodes/McpAppNode.d.ts +24 -1
- package/dist/types/client/state/presentation.d.ts +3 -0
- package/dist/types/client/types.d.ts +1 -1
- package/dist/types/json-render/catalog.d.ts +2 -2
- package/dist/types/json-render/server.d.ts +2 -0
- package/dist/types/server/canvas-db.d.ts +2 -0
- package/dist/types/server/canvas-operations.d.ts +22 -0
- package/dist/types/server/canvas-schema.d.ts +1 -0
- package/dist/types/server/canvas-state.d.ts +6 -0
- package/dist/types/server/canvas-validation.d.ts +3 -0
- package/dist/types/server/html-surface.d.ts +1 -1
- package/dist/types/server/index.d.ts +4 -0
- package/dist/types/server/operations/ops/app.d.ts +2 -0
- package/dist/types/server/operations/ops/json-render.d.ts +2 -0
- package/dist/types/server/operations/ops/nodes.d.ts +3 -1
- package/dist/types/server/web-artifacts.d.ts +3 -0
- package/dist/types/shared/tour.d.ts +72 -0
- package/docs/cli.md +96 -2
- package/docs/http-api.md +79 -4
- package/docs/mcp.md +25 -1
- package/docs/node-types.md +123 -1
- package/docs/product-context-vision-2026-09.md +1 -1
- package/docs/product-vision-2026-09.md +135 -42
- package/docs/product-vision-review-2026-09.md +277 -0
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +19 -4
- package/skills/pmx-canvas/evals/evals.json +46 -0
- package/skills/pmx-canvas/references/full-reference.md +1 -1
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +4 -4
- package/src/cli/agent.ts +5 -0
- package/src/cli/commands/nodes.ts +10 -0
- package/src/cli/commands/record.ts +218 -0
- package/src/cli/index.ts +2 -0
- package/src/client/App.tsx +7 -1
- package/src/client/canvas/AgentPresenceLayer.tsx +1 -1
- package/src/client/canvas/CanvasNode.tsx +8 -0
- package/src/client/canvas/FeedbackDialog.tsx +86 -0
- package/src/client/canvas/IntentLayer.tsx +9 -2
- package/src/client/canvas/Presentation.tsx +108 -0
- package/src/client/canvas/ToolRail.tsx +225 -189
- package/src/client/canvas/TopBar.tsx +28 -2
- package/src/client/canvas/use-node-drag.ts +8 -3
- package/src/client/mermaid-entry.ts +39 -0
- package/src/client/nodes/HtmlNode.tsx +12 -13
- package/src/client/nodes/McpAppNode.tsx +105 -13
- package/src/client/nodes/MermaidNode.tsx +3 -2
- package/src/client/state/intent-store.ts +5 -1
- package/src/client/state/presentation.ts +7 -0
- package/src/client/state/session-store.ts +3 -0
- package/src/client/state/sse-bridge.ts +3 -0
- package/src/client/theme/global.css +90 -4
- package/src/json-render/server.ts +29 -0
- package/src/server/agent-presence.ts +15 -9
- package/src/server/canvas-db.ts +15 -0
- package/src/server/canvas-operations.ts +115 -22
- package/src/server/canvas-schema.ts +10 -0
- package/src/server/canvas-state.ts +39 -4
- package/src/server/canvas-validation.ts +9 -1
- package/src/server/demo-state.json +11 -7
- package/src/server/html-primitives.ts +199 -91
- package/src/server/html-surface.ts +8 -3
- package/src/server/index.ts +12 -0
- package/src/server/operations/composites.ts +3 -1
- package/src/server/operations/ops/app.ts +10 -0
- package/src/server/operations/ops/batch.ts +12 -3
- package/src/server/operations/ops/groups.ts +14 -7
- package/src/server/operations/ops/json-render.ts +37 -5
- package/src/server/operations/ops/nodes.ts +42 -16
- package/src/server/operations/ops/viewport.ts +32 -0
- package/src/server/operations/registry.ts +6 -0
- package/src/server/scope-fence.ts +1 -1
- package/src/server/server.ts +9 -6
- package/src/server/web-artifacts.ts +9 -2
- package/src/server/workboard.ts +3 -3
- package/src/shared/tour.ts +87 -0
package/docs/http-api.md
CHANGED
|
@@ -9,6 +9,40 @@ bodies are treated as an empty request. As of 0.4.0 every error response is a
|
|
|
9
9
|
JSON envelope of that same shape (`{ ok: false, error }`, status unchanged) —
|
|
10
10
|
no plain-text errors remain.
|
|
11
11
|
|
|
12
|
+
Node-create responses include `sizeAdjustment` when a frame dimension was
|
|
13
|
+
defaulted or raised to its node type's readability floor. It contains the
|
|
14
|
+
`requested` dimensions (`null` when omitted), the final `applied` dimensions,
|
|
15
|
+
and a `reason` (`defaulted`, `clamped-to-minimum`, or
|
|
16
|
+
`defaulted-and-clamped-to-minimum`; groups also use `fit-to-children`). `strictSize: true`
|
|
17
|
+
still bypasses the readability clamp, but omitted dimensions are reported as
|
|
18
|
+
defaulted. MCP create actions return the same size report.
|
|
19
|
+
Updates preserve explicit dimensions without applying creation floors; their
|
|
20
|
+
returned node `size` is the applied size. Omitted update dimensions retain the
|
|
21
|
+
existing size and are not reported as defaulted adjustments.
|
|
22
|
+
|
|
23
|
+
Both group-create routes report defaults or final child-derived dimensions, including
|
|
24
|
+
when children override supplied width/height because x/y were omitted. Explicit manual
|
|
25
|
+
frames retain their existing semantics. Group child replacement reports `fit-to-children`
|
|
26
|
+
when it changes the frame; `group.add` reports the previous frame as `requested` and
|
|
27
|
+
the final frame as `applied`. Reports survive compact/full MCP and batch responses.
|
|
28
|
+
External MCP app creation and web-artifact builds that open a node report their default
|
|
29
|
+
frames too; reusing an existing app node or building without opening does not report a
|
|
30
|
+
creation default. These reports describe the synchronous operation, not later browser
|
|
31
|
+
content auto-height or indirect parent-group reflow after editing a child.
|
|
32
|
+
|
|
33
|
+
## Board tours
|
|
34
|
+
|
|
35
|
+
- `GET /api/canvas/tour` → `{ tour: { stops: [...] }, derived: boolean }`.
|
|
36
|
+
- `POST /api/canvas/tour` with `{ "tour": { "stops": [...] } }` persists the tour;
|
|
37
|
+
`{ "tour": null }` resets to derived group reading order. Returns `{ "ok": true }`.
|
|
38
|
+
- `GET /api/canvas/state` includes optional `tour`. Tour writes broadcast a layout
|
|
39
|
+
update and are included in snapshots/undo. They are board-wide writes under a scope fence.
|
|
40
|
+
|
|
41
|
+
The [tour model and recording walkthrough](cli.md#tour-and-presentation) describes
|
|
42
|
+
targets, duration, easing, padding, and pullback. Open `/workbench?present=1` to hide
|
|
43
|
+
chrome; camera movement is local to that viewer. Recording writes local files via
|
|
44
|
+
the CLI, not an HTTP job endpoint.
|
|
45
|
+
|
|
12
46
|
## Canvas state
|
|
13
47
|
|
|
14
48
|
```bash
|
|
@@ -35,6 +69,10 @@ curl -X POST http://localhost:4313/api/canvas/json-render \
|
|
|
35
69
|
-H "Content-Type: application/json" \
|
|
36
70
|
-d '{"title":"Panel","nodeHeight":280,"spec":{"root":"card","elements":{"card":{"type":"Card","props":{"title":"Live"},"children":[]}}}}'
|
|
37
71
|
|
|
72
|
+
# For graph nodes, `height` is the chart's plot height, not the node frame.
|
|
73
|
+
# Set the frame with `nodeHeight` (`heightPx` in the SDK). A graph request that
|
|
74
|
+
# supplies only `height` gets the default frame height and a response warning.
|
|
75
|
+
|
|
38
76
|
# Validate an HTML primitive without creating a node
|
|
39
77
|
curl -X POST http://localhost:4313/api/canvas/schema/validate \
|
|
40
78
|
-H "Content-Type: application/json" \
|
|
@@ -70,6 +108,11 @@ A node creation request must resolve a `type` — pass it in the body (`{ "type"
|
|
|
70
108
|
... }`) or as a `?type=` query param. An empty / type-less body returns `400`
|
|
71
109
|
rather than silently creating a markdown node.
|
|
72
110
|
|
|
111
|
+
Mermaid nodes accept `data: { "fit": "contain" | "none" }` on both
|
|
112
|
+
`POST /api/canvas/node` and `PATCH /api/canvas/node/:id`. The default, `contain`,
|
|
113
|
+
shrinks overflowing diagrams without changing aspect ratio; `none` keeps 100%
|
|
114
|
+
with scrolling. [Mermaid sizing and readability](node-types.md#mermaid-nodes).
|
|
115
|
+
|
|
73
116
|
### File node content and bytes
|
|
74
117
|
|
|
75
118
|
A `file` node reads its file server-side. Text is stored on the node as
|
|
@@ -145,6 +188,31 @@ curl -X DELETE http://localhost:4313/api/canvas/annotation/ann-123
|
|
|
145
188
|
Agent-readable context reports annotation IDs, targets, and bounds. Use WebView
|
|
146
189
|
inspection or screenshots when the drawn shape matters.
|
|
147
190
|
|
|
191
|
+
## Viewport
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Set the camera transform (screen = world * scale + {x,y})
|
|
195
|
+
curl -X POST http://localhost:4313/api/canvas/viewport \
|
|
196
|
+
-H "Content-Type: application/json" \
|
|
197
|
+
-d '{"x":64,"y":96,"scale":0.8}'
|
|
198
|
+
|
|
199
|
+
# Fit selected nodes (omit nodeIds to fit the whole canvas)
|
|
200
|
+
curl -X POST http://localhost:4313/api/canvas/fit \
|
|
201
|
+
-H "Content-Type: application/json" \
|
|
202
|
+
-d '{"nodeIds":["node-1"],"width":1200,"height":700}'
|
|
203
|
+
|
|
204
|
+
# Focus without moving the camera
|
|
205
|
+
curl -X POST http://localhost:4313/api/canvas/focus \
|
|
206
|
+
-H "Content-Type: application/json" \
|
|
207
|
+
-d '{"id":"node-1","noPan":true}'
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Viewport `x`/`y`, fit `width`/`height`, and fit padding are interpreted against
|
|
211
|
+
the **canvas area**, excluding the tool rail, top bar, and other surrounding
|
|
212
|
+
page chrome—not the full browser window. Camera, fit, and focus-only requests
|
|
213
|
+
do not create or refresh agent writer presence. Use the explicit presence API
|
|
214
|
+
when an agent should publish a cursor or `focusNodeId`.
|
|
215
|
+
|
|
148
216
|
## Pins
|
|
149
217
|
|
|
150
218
|
```bash
|
|
@@ -341,13 +409,20 @@ When that session ends (`attached: false`, `session-end`, or the idle expiry)
|
|
|
341
409
|
the stream carries one `agent-session-ended` frame:
|
|
342
410
|
|
|
343
411
|
```json
|
|
344
|
-
{ "label": "Copilot", "
|
|
412
|
+
{ "label": "Copilot", "parentAgentId": null, "endedAt": "…", "endedBy": "agent",
|
|
413
|
+
"unchanged": false, "counts": { "items": 4, "done": 3, "cancelled": 1, "rejected": 0, "held": 0 },
|
|
345
414
|
"snapshot": { "id": "…", "name": "Before session · Copilot · 14:00" } }
|
|
346
415
|
```
|
|
347
416
|
|
|
348
|
-
`items`/`done` count the work items on the board;
|
|
349
|
-
|
|
350
|
-
empty at attach
|
|
417
|
+
`items`/`done` count the work items on the board; cancelled items, rejected
|
|
418
|
+
gates, and held gates have separate counts. `snapshot` is null when the board was
|
|
419
|
+
empty at attach or unchanged at end (the redundant snapshot is removed).
|
|
420
|
+
The browser shows a receipt only for a changed top-level session: `unchanged: true`
|
|
421
|
+
and worker endings (`parentAgentId` set) never open or replace a popup. An empty
|
|
422
|
+
board that stays empty is unchanged too. This only filters the popup: session-end
|
|
423
|
+
events, timeline records, and changed-session snapshots remain available.
|
|
424
|
+
There is at most one receipt, replaced by the next qualifying ending and kept until
|
|
425
|
+
dismissed so restore/diff actions do not disappear on a timer. Its *View
|
|
351
426
|
diff* is `GET /api/canvas/snapshots/<id>/diff` against that snapshot, and
|
|
352
427
|
restoring the snapshot undoes the session. Adapters should end their session
|
|
353
428
|
explicitly so the human gets the receipt promptly rather than after the idle
|
package/docs/mcp.md
CHANGED
|
@@ -13,6 +13,15 @@ nodes in the browser, agents are notified immediately.
|
|
|
13
13
|
> snapshot standalones — each step per [`api-stability.md`](api-stability.md)'s
|
|
14
14
|
> deprecate-one-minor-before-removal rule. **Prefer the composites.**
|
|
15
15
|
|
|
16
|
+
## Board tours
|
|
17
|
+
|
|
18
|
+
`canvas_view { action: "get-tour" }` returns `{ tour, derived }`, using group
|
|
19
|
+
reading order when there is no saved tour. `canvas_view { action: "set-tour",
|
|
20
|
+
tour: { stops: [...] } }` persists an ordered tour; `tour: null` resets it.
|
|
21
|
+
See the [tour model and CLI walkthrough](cli.md#tour-and-presentation) for stop
|
|
22
|
+
fields. Recording is a local CLI operation; no remote recording/file-writing
|
|
23
|
+
tool is added.
|
|
24
|
+
|
|
16
25
|
## Connect
|
|
17
26
|
|
|
18
27
|
Add to your agent's MCP config:
|
|
@@ -42,7 +51,7 @@ its `action` to the same operation the legacy tool used, so results are identica
|
|
|
42
51
|
| `canvas_edge` | `add` · `update` · `remove` | `canvas_add_edge`, `canvas_update_edge`, `canvas_remove_edge` |
|
|
43
52
|
| `canvas_group` | `create` · `add` · `ungroup` | `canvas_create_group`, `canvas_group_nodes`, `canvas_ungroup` |
|
|
44
53
|
| `canvas_history` | `undo` · `redo` | `canvas_undo`, `canvas_redo` |
|
|
45
|
-
| `canvas_view` | `arrange` · `focus` · `fit` · `clear` · `remove-annotation` | `canvas_arrange`, `canvas_focus_node`, `canvas_fit_view`, `canvas_clear`, `canvas_remove_annotation` |
|
|
54
|
+
| `canvas_view` | `arrange` · `focus` · `fit` · `clear` · `remove-annotation` · `get-tour` · `set-tour` | `canvas_arrange`, `canvas_focus_node`, `canvas_fit_view`, `canvas_clear`, `canvas_remove_annotation` |
|
|
46
55
|
| `canvas_query` | `search` · `layout` · `validate` | `canvas_search`, `canvas_get_layout`, `canvas_validate` |
|
|
47
56
|
| `canvas_webview` | `status` · `start` · `stop` · `resize` · `evaluate` | `canvas_webview_status`, `canvas_webview_start`, `canvas_webview_stop`, `canvas_resize`, `canvas_evaluate` |
|
|
48
57
|
| `canvas_app` | `open-mcp-app` · `diagram` · `build-artifact` | `canvas_open_mcp_app`, `canvas_add_diagram`, `canvas_build_web_artifact` |
|
|
@@ -54,6 +63,11 @@ its `action` to the same operation the legacy tool used, so results are identica
|
|
|
54
63
|
| `canvas_intent` | `signal` · `update` · `clear` | _(new — Ghost Cursor of Intent; no legacy standalone tool)_ |
|
|
55
64
|
| `canvas_snapshot` | `save` · `list` · `restore` · `delete` · `gc` · `diff` | `canvas_snapshot` (legacy save tool), `canvas_list_snapshots`, `canvas_restore`, `canvas_delete_snapshot`, `canvas_gc_snapshots`, `canvas_diff` — removed in v0.4.0 after one deprecated minor |
|
|
56
65
|
|
|
66
|
+
For Mermaid nodes, `canvas_node` actions `add` and `update` accept
|
|
67
|
+
`data: { fit: "contain" | "none" }`. Contain is the default, shrinking overflow
|
|
68
|
+
uniformly; none keeps 100% with scrolling. Use Open as site for 100% without
|
|
69
|
+
changing the node setting. [Sizing and readability](node-types.md#mermaid-nodes).
|
|
70
|
+
|
|
57
71
|
### `canvas_intent` — Ghost Cursor of Intent
|
|
58
72
|
|
|
59
73
|
Announce the spatial move you are **about** to make so the canvas paints a faint
|
|
@@ -92,6 +106,16 @@ fixing `node.update`'s `formatResult` to surface a FAILED refresh as `isError` +
|
|
|
92
106
|
fold completed in v0.4.0: `canvas_snapshot { action: "save" | "list" | "restore" |
|
|
93
107
|
"delete" | "gc" | "diff" }` replaced the 6 deprecated snapshot standalones.
|
|
94
108
|
|
|
109
|
+
### Viewport coordinates
|
|
110
|
+
|
|
111
|
+
`canvas_view { action: "focus" | "fit" }` controls the camera without counting
|
|
112
|
+
as a writer operation or refreshing agent presence. Viewport translation uses
|
|
113
|
+
screen-space canvas-area coordinates (`screen = world * scale + viewport`). Fit
|
|
114
|
+
dimensions and padding likewise refer to the canvas area after excluding the
|
|
115
|
+
tool rail, top bar, and surrounding page chrome—not the full browser window.
|
|
116
|
+
Use `canvas_ax_state { action: "set-presence", cursor, focusNodeId }` when the
|
|
117
|
+
agent intends to publish its own cursor or attention target.
|
|
118
|
+
|
|
95
119
|
## Standalone tools
|
|
96
120
|
|
|
97
121
|
6 tools that intentionally stay outside the composites — folding them would
|
package/docs/node-types.md
CHANGED
|
@@ -26,6 +26,17 @@ see [MCP tools](mcp.md), [HTTP API](http-api.md), and [SDK](sdk.md).
|
|
|
26
26
|
| `web-artifact` | Bundled React/Tailwind artifact (full single-file app) |
|
|
27
27
|
| `group` | Spatial container/frame around other nodes |
|
|
28
28
|
|
|
29
|
+
Creation applies per-type frame defaults and readability minimums. When a
|
|
30
|
+
dimension is defaulted or clamped, HTTP and MCP create responses include a
|
|
31
|
+
`sizeAdjustment` with requested and applied dimensions plus the reason.
|
|
32
|
+
`strictSize: true` bypasses minimum-size clamping; it does not change defaults
|
|
33
|
+
for omitted dimensions.
|
|
34
|
+
|
|
35
|
+
For `graph` nodes, `height` controls the chart plot inside the viewer.
|
|
36
|
+
`nodeHeight` controls the canvas node frame (`heightPx` is the SDK alias). If
|
|
37
|
+
only `height` is supplied, the frame keeps its default height and the create
|
|
38
|
+
response warns about the distinction.
|
|
39
|
+
|
|
29
40
|
Thread node types `prompt` and `response` exist internally for agent
|
|
30
41
|
conversation rendering and are not created through public APIs.
|
|
31
42
|
|
|
@@ -64,6 +75,34 @@ different type by extension:
|
|
|
64
75
|
- **Text files over 2 MB** render truncated with a banner saying so, so a huge
|
|
65
76
|
log can never exhaust memory.
|
|
66
77
|
|
|
78
|
+
## Mermaid nodes
|
|
79
|
+
|
|
80
|
+
Mermaid diagrams default to `data.fit: "contain"`: when the diagram overflows
|
|
81
|
+
the available body, it shrinks uniformly until the entire diagram fits. Small
|
|
82
|
+
diagrams stay at 100%; aspect ratio, labels, and edges are preserved, in both
|
|
83
|
+
dark and light themes. Resizing a card or expanding it recalculates the fit.
|
|
84
|
+
`strictSize` keeps the requested node geometry while the diagram fits inside it;
|
|
85
|
+
ordinary cards retain their grow-only automatic sizing.
|
|
86
|
+
|
|
87
|
+
Fitting a large diagram makes its text smaller. Use **Expand** for more space,
|
|
88
|
+
or **Open as site** for a 100% natural-size diagram with scrolling. Set
|
|
89
|
+
`data.fit: "none"` to use that natural-size, scrollable view inside the card too.
|
|
90
|
+
This setting is independent of the canvas camera's **Fit view** action.
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
canvas_node({ action: 'add', type: 'mermaid', content: 'flowchart TD; A-->B-->C-->D',
|
|
94
|
+
width: 920, height: 870, strictSize: true, data: { fit: 'contain' } })
|
|
95
|
+
canvas_node({ action: 'update', id: 'node-id', data: { fit: 'none' } })
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
HTTP uses the same `data` object in `POST /api/canvas/node` and
|
|
99
|
+
`PATCH /api/canvas/node/:id`. CLI creation and updates expose `--fit`:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pmx-canvas node add --type mermaid --content 'flowchart TD; A-->B-->C-->D' --fit contain --width 920 --height 870 --strict-size
|
|
103
|
+
pmx-canvas node update node-id --fit none
|
|
104
|
+
```
|
|
105
|
+
|
|
67
106
|
## Image nodes
|
|
68
107
|
|
|
69
108
|
Image nodes display local paths, remote URLs, and data URIs. File-backed and
|
|
@@ -137,7 +176,7 @@ with the server's transport, tool name, and arguments.
|
|
|
137
176
|
|
|
138
177
|
`json-render` nodes turn structured JSON specs into rendered UI panels
|
|
139
178
|
(dashboards, tables, forms, cards) without writing HTML. PMX Canvas ships the
|
|
140
|
-
[`@json-render/*`](https://www.npmjs.com/package/@json-render/core) runtime
|
|
179
|
+
[`@json-render/*`](https://www.npmjs.com/package/@json-render/core) 0.21.0 runtime
|
|
141
180
|
and component catalog (core + react + shadcn).
|
|
142
181
|
|
|
143
182
|
```ts
|
|
@@ -158,6 +197,56 @@ canvas_render({
|
|
|
158
197
|
`outline`. Older saved specs using `label` or status variants such as
|
|
159
198
|
`success`/`warning` are normalized during validation.
|
|
160
199
|
|
|
200
|
+
Specs preserve top-level `state` and element-level `repeat`, `watch`, and
|
|
201
|
+
`slots`. Use `$bindState` with JSON Pointer paths for editable form values;
|
|
202
|
+
`$state` only reads a value. Nested repeats can use `statePath: { "$item": "tasks" }`
|
|
203
|
+
to iterate the current item's tasks. Watchers run after changes, not on mount.
|
|
204
|
+
|
|
205
|
+
**Seed form values through bindings, not literal `value` props.** In shadcn
|
|
206
|
+
0.21, `Input`, `Textarea`, `Select`, `Radio`, `Slider`, `ToggleGroup`, and
|
|
207
|
+
`Tabs` ignore an unbound `value`; `ButtonGroup` ignores unbound `selected`.
|
|
208
|
+
This includes read-only `$state` expressions. PMX returns a `warnings` array
|
|
209
|
+
from `POST /api/canvas/json-render`, `POST /api/canvas/schema/validate`, and
|
|
210
|
+
`canvas_render` actions `add-json-render` and `validate`. Warnings name the
|
|
211
|
+
element/property; they do not reject or rewrite the spec. PMX does not invent
|
|
212
|
+
state paths because repeated controls and existing actions may need distinct
|
|
213
|
+
or deliberately shared state.
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"root": "postcode",
|
|
218
|
+
"state": { "form": { "postcode": "nw1 6xe" } },
|
|
219
|
+
"elements": {
|
|
220
|
+
"postcode": {
|
|
221
|
+
"type": "Input",
|
|
222
|
+
"props": {
|
|
223
|
+
"label": "Postcode",
|
|
224
|
+
"name": "postcode",
|
|
225
|
+
"value": { "$bindState": "/form/postcode" }
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Inside repeats, use `$bindItem` with seeded item data. `Checkbox`/`Switch`
|
|
233
|
+
honor literal `checked`, `Toggle` honors literal `pressed`, and `Tabs` honors
|
|
234
|
+
`defaultValue` for an uncontrolled initial tab. `Pagination` reads `page`
|
|
235
|
+
directly; `DropdownMenu.value` is an output binding for selection, not a
|
|
236
|
+
displayed selection. These do not require the same ignored-value warning.
|
|
237
|
+
Use two-way bindings whenever edits or form checks must participate in state.
|
|
238
|
+
|
|
239
|
+
Cards keep their body in `children` and accept
|
|
240
|
+
`slots: { header: ['headingId'], footer: ['actionsId'] }`. Slot IDs reference
|
|
241
|
+
entries in `elements`; a custom header replaces the title and description props.
|
|
242
|
+
See the bundled [json-render guide](../skills/json-render-mcp/SKILL.md)
|
|
243
|
+
for a complete state-bound form with watchers and footer actions.
|
|
244
|
+
|
|
245
|
+
Form edits are viewer-local, not saved into the stored spec. Reloading the iframe
|
|
246
|
+
or updating its spec (including streaming patches) resets that state. Finish
|
|
247
|
+
streaming before collecting input, and persist important changes through an
|
|
248
|
+
explicit server interaction.
|
|
249
|
+
|
|
161
250
|
Elements may carry an `on` map (`on.press`, `on.change`, …) binding events to
|
|
162
251
|
actions (`{ action, params }`) — built-in actions (`setState`, `pushState`, …) or
|
|
163
252
|
host-provided handlers. PMX wires AX handlers named after interaction types, so a
|
|
@@ -185,9 +274,35 @@ source + per-viewer nonce + node id) and submits it server-side; `json-render` /
|
|
|
185
274
|
`graph` viewers are sandboxed surfaces, so caller-supplied `nodeIds` are clamped
|
|
186
275
|
to the node's own id. See the [MCP reference](mcp.md#node-interactions-capability-gated).
|
|
187
276
|
|
|
277
|
+
AX handlers are fire-and-forget: `onSuccess` means local dispatch completed,
|
|
278
|
+
not that the server accepted the operation. Confirm acceptance through AX state
|
|
279
|
+
or timeline before showing a saved state or clearing a draft. The built-in
|
|
280
|
+
`validateForm` action returns without calling `onSuccess`; do not chain submission
|
|
281
|
+
through that callback.
|
|
282
|
+
|
|
188
283
|
Use `canvas_render { action: "describe-schema" }` / `canvas_render { action:
|
|
189
284
|
"validate" }` to introspect the component catalog before building a spec.
|
|
190
285
|
|
|
286
|
+
### Automatic sizing of authored iframe cards
|
|
287
|
+
|
|
288
|
+
HTML (except presentation decks), Mermaid, JSON-render, graph, and web-artifact
|
|
289
|
+
cards can grow as their rendered content changes. This changes node geometry;
|
|
290
|
+
**Fit view** only changes the camera. Height measurements include title-bar and
|
|
291
|
+
body padding, grow only up to 1400px, and never change the width. Content beyond
|
|
292
|
+
that limit may still scroll; this is not a general shrink-to-content action.
|
|
293
|
+
|
|
294
|
+
Fitting waits for local or remote human grabs to end. A growing ungrouped,
|
|
295
|
+
screen-unpinned card moves downward if needed to leave a 24px gap from neighboring
|
|
296
|
+
cards, without moving those neighbors. A relocation records one undo step for
|
|
297
|
+
both size and position; height-only adjustments do not add undo entries.
|
|
298
|
+
Grouped or screen-pinned cards retain their positions. Collapsed cards and cards
|
|
299
|
+
marked `strictSize` or `userResized` are not automatically resized. Hosted MCP
|
|
300
|
+
apps and webpage viewers do not use this authored-content fitting behavior.
|
|
301
|
+
|
|
302
|
+
Read the settled node geometry after mounting rather than treating requested
|
|
303
|
+
dimensions as final. Prefer targeted node reads or the CLI's projected layout
|
|
304
|
+
fields over fetching full content merely to check spacing.
|
|
305
|
+
|
|
191
306
|
## HTML nodes
|
|
192
307
|
|
|
193
308
|
`html` nodes render a normal self-contained HTML/JS document in a sandboxed iframe.
|
|
@@ -235,6 +350,13 @@ component gallery, interaction prototype, flowchart, SVG illustration set,
|
|
|
235
350
|
presentation, explainer, status report, incident report, triage board, config
|
|
236
351
|
editor, or prompt tuner.
|
|
237
352
|
|
|
353
|
+
Omitted fields may use the template's examples. Explicit empty arrays, empty
|
|
354
|
+
strings, or `null` mean “show nothing”: the field's section, heading, and
|
|
355
|
+
dependent controls are omitted rather than replaced with sample content.
|
|
356
|
+
Other populated or omitted fields keep their normal behavior. Empty `slides`
|
|
357
|
+
or flow `steps` also omit navigation/run controls; an AX board's live task
|
|
358
|
+
controls remain available when only its optional note is empty.
|
|
359
|
+
|
|
238
360
|
Two kinds are **live AX control surfaces** rather than static documents, and are
|
|
239
361
|
the only primitives created with AX enabled:
|
|
240
362
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Vision extension: boards, personal wiki, and workspace context
|
|
2
2
|
|
|
3
|
-
**Status:** Proposed for discussion, not an implementation commitment.
|
|
3
|
+
**Status:** Proposed for discussion, not an implementation commitment. **Superseded in part, 2026-09-23:** the maintainer decided that boards are the wiki and that the destination is "share this board" ([vision, move 0 and Part 3](product-vision-2026-09.md); reasoning in the [review](product-vision-review-2026-09.md#design-sketch-boards-are-the-wiki)). The separate entity and revision store, the personal wiki as its own surface, and working-versus-confirmed machinery are not planned; boards, cards and the journal play those roles. Still in force: the publication and audience rules and the threat-model corrections, which apply when sharing reaches a second writer (Part 3), and the validation experiment, run on linked boards instead of a wiki.
|
|
4
4
|
**Date:** 2026-09-06
|
|
5
5
|
**Companions:** [Product review](product-review-2026-09.md), [product vision](product-vision-2026-09.md).
|
|
6
6
|
**Request:** Review the existing vision and explore hosted users building their own wiki by describing their work, with their boards contributing context, and cross-cutting organizational context shared within a workspace. Reuse the logic of the personal/context-frame projects inside pmx-canvas's own store rather than depend on an external wiki.
|