pmx-canvas 0.6.4 → 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 +19 -0
- package/Readme.md +7 -1
- package/dist/canvas/global.css +58 -4
- package/dist/canvas/index.js +92 -92
- 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/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 +89 -0
- package/docs/http-api.md +79 -4
- package/docs/mcp.md +25 -1
- package/docs/node-types.md +80 -0
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +10 -2
- 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/IntentLayer.tsx +9 -2
- package/src/client/canvas/Presentation.tsx +108 -0
- 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 +58 -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
|
@@ -21,6 +21,7 @@ import './commands/history.js';
|
|
|
21
21
|
import './commands/ax.js';
|
|
22
22
|
import './commands/pump.js';
|
|
23
23
|
import './commands/webview.js';
|
|
24
|
+
import './commands/record.js';
|
|
24
25
|
import './commands/apps.js';
|
|
25
26
|
import './commands/copilot.js';
|
|
26
27
|
import './commands/skills.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function parseRecordOptions(flags: Record<string, string | boolean>): {
|
|
2
|
+
theme: "dark" | "light" | "high-contrast" | "midnight" | "sepia" | "arctic" | "ember" | "forest" | "volt" | undefined;
|
|
3
|
+
present: boolean;
|
|
4
|
+
tourFile: string | undefined;
|
|
5
|
+
chromePath: string | undefined;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
fps: number;
|
|
9
|
+
mode: "realtime" | "deterministic";
|
|
10
|
+
output: string;
|
|
11
|
+
duration?: number | undefined;
|
|
12
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Camera } from '../../shared/tour.js';
|
|
2
|
+
import { canvasArea } from './canvas-area';
|
|
3
|
+
declare global {
|
|
4
|
+
interface Window {
|
|
5
|
+
pmxCapture?: {
|
|
6
|
+
ready: () => boolean;
|
|
7
|
+
area: typeof canvasArea;
|
|
8
|
+
camera: () => Camera;
|
|
9
|
+
frame: (camera: Camera) => Promise<Camera>;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export declare function Presentation(): import("preact/jsx-runtime").JSX.Element | null;
|
|
@@ -5,11 +5,12 @@ interface NodeDragOptions {
|
|
|
5
5
|
viewport: Signal<ViewportState>;
|
|
6
6
|
onMove: (id: string, x: number, y: number) => void;
|
|
7
7
|
onDragEnd: () => void;
|
|
8
|
+
onClick?: () => void;
|
|
8
9
|
}
|
|
9
10
|
/**
|
|
10
11
|
* Hook for dragging canvas nodes by their title bar.
|
|
11
12
|
* Converts screen-space pointer delta to canvas-space position delta
|
|
12
13
|
* (accounting for current viewport scale).
|
|
13
14
|
*/
|
|
14
|
-
export declare function useNodeDrag({ nodeId, viewport, onMove, onDragEnd }: NodeDragOptions): (e: PointerEvent, currentX: number, currentY: number) => void;
|
|
15
|
+
export declare function useNodeDrag({ nodeId, viewport, onMove, onDragEnd, onClick }: NodeDragOptions): (e: PointerEvent, currentX: number, currentY: number) => void;
|
|
15
16
|
export {};
|
|
@@ -1,6 +1,29 @@
|
|
|
1
|
+
import type { RefObject } from 'preact';
|
|
1
2
|
import type { CanvasNodeState } from '../types';
|
|
2
3
|
export declare function isSameOriginFrameDocumentUrl(url: string, origin?: string): boolean;
|
|
4
|
+
type ViewerFrameSource = {
|
|
5
|
+
src?: string;
|
|
6
|
+
srcdoc?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Keep the last painted viewer in front while its replacement navigates. Viewer
|
|
10
|
+
* specs are immutable documents, so updates normally change `?v=` and reload the
|
|
11
|
+
* iframe; putting the new document in a hidden sibling avoids exposing Chromium's
|
|
12
|
+
* white navigation paint. Two animation frames after load gives the new document
|
|
13
|
+
* a composited paint before the old one is removed.
|
|
14
|
+
*/
|
|
15
|
+
export declare function RefreshingViewerFrame({ source, iframeRef, onLoad, title, className, sandbox, allow, tabIndex, }: {
|
|
16
|
+
source: ViewerFrameSource;
|
|
17
|
+
iframeRef: RefObject<HTMLIFrameElement>;
|
|
18
|
+
onLoad: () => void;
|
|
19
|
+
title: string;
|
|
20
|
+
className?: string;
|
|
21
|
+
sandbox?: string;
|
|
22
|
+
allow?: string;
|
|
23
|
+
tabIndex?: number;
|
|
24
|
+
}): import("preact").JSX.Element;
|
|
3
25
|
export declare function McpAppNode({ node, expanded }: {
|
|
4
26
|
node: CanvasNodeState;
|
|
5
27
|
expanded?: boolean;
|
|
6
|
-
}): import("preact
|
|
28
|
+
}): import("preact").JSX.Element;
|
|
29
|
+
export {};
|
|
@@ -54,7 +54,7 @@ export type AnnotationTool = 'pen' | 'eraser' | 'text' | null;
|
|
|
54
54
|
export type ConnectionStatus = 'connecting' | 'connected' | 'disconnected';
|
|
55
55
|
export declare const TYPE_LABELS: Record<CanvasNodeState['type'], string>;
|
|
56
56
|
/** Node types that support the full-viewport expand/focus overlay. */
|
|
57
|
-
export declare const EXPANDABLE_TYPES: Set<"html" | "markdown" | "mcp-app" | "webpage" | "json-render" | "graph" | "prompt" | "response" | "status" | "context" | "ledger" | "trace" | "
|
|
57
|
+
export declare const EXPANDABLE_TYPES: Set<"file" | "group" | "html" | "markdown" | "mcp-app" | "webpage" | "json-render" | "graph" | "prompt" | "response" | "status" | "context" | "ledger" | "trace" | "diff" | "mermaid" | "image">;
|
|
58
58
|
export declare const EXCALIDRAW_SERVER_NAME = "Excalidraw";
|
|
59
59
|
export declare const EXCALIDRAW_CREATE_VIEW_TOOL = "create_view";
|
|
60
60
|
export declare function isExcalidrawNode(node: CanvasNodeState): boolean;
|
|
@@ -474,10 +474,10 @@ export declare const allComponentDefinitions: {
|
|
|
474
474
|
text: z.ZodString;
|
|
475
475
|
variant: z.ZodNullable<z.ZodEnum<{
|
|
476
476
|
error: "error";
|
|
477
|
+
success: "success";
|
|
478
|
+
default: "default";
|
|
477
479
|
info: "info";
|
|
478
480
|
warning: "warning";
|
|
479
|
-
default: "default";
|
|
480
|
-
success: "success";
|
|
481
481
|
secondary: "secondary";
|
|
482
482
|
destructive: "destructive";
|
|
483
483
|
outline: "outline";
|
|
@@ -65,6 +65,8 @@ export declare const GRAPH_NODE_SIZE: {
|
|
|
65
65
|
export type GraphChartType = 'LineChart' | 'BarChart' | 'PieChart' | 'AreaChart' | 'ScatterChart' | 'RadarChart' | 'StackedBarChart' | 'ComposedChart' | 'Sparkline' | 'DotPlot' | 'BulletChart' | 'Slopegraph';
|
|
66
66
|
export declare function inferJsonRenderNodeTitle(spec: JsonRenderSpec, fallback?: string): string;
|
|
67
67
|
export declare function normalizeAndValidateJsonRenderSpec(spec: unknown): JsonRenderSpec;
|
|
68
|
+
/** shadcn 0.21 ignores these props unless the renderer supplies a two-way binding. */
|
|
69
|
+
export declare function jsonRenderFormWarnings(spec: JsonRenderSpec): string[];
|
|
68
70
|
export declare function normalizeGraphType(value: string): GraphChartType;
|
|
69
71
|
export declare function buildGraphSpec(input: GraphNodeInput): JsonRenderSpec;
|
|
70
72
|
export declare function buildGraphConfig(input: GraphNodeInput): Record<string, unknown>;
|
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
* WAL-mode persistence. Replaces the previous JSON file-based approach.
|
|
6
6
|
*/
|
|
7
7
|
import { Database } from 'bun:sqlite';
|
|
8
|
+
import { type Tour } from '../shared/tour.js';
|
|
8
9
|
import { type CanvasThemeName } from '../shared/themes.js';
|
|
9
10
|
import type { CanvasAnnotation, CanvasEdge, CanvasNodeState, CanvasSnapshot, CanvasSnapshotListOptions, ViewportState } from './canvas-state.js';
|
|
10
11
|
import { type PmxAxState, type PmxAxEvent, type PmxAxEvidence, type PmxAxSteeringMessage, type PmxAxHostCapability, type PmxAxTimelineSummary } from './ax-state.js';
|
|
11
12
|
export type CanvasTheme = CanvasThemeName;
|
|
12
13
|
export declare function normalizeCanvasTheme(value: unknown, fallback?: CanvasTheme): CanvasTheme;
|
|
13
14
|
export interface PersistedCanvasState {
|
|
15
|
+
tour?: Tour;
|
|
14
16
|
version: number;
|
|
15
17
|
theme?: CanvasTheme;
|
|
16
18
|
viewport: ViewportState;
|
|
@@ -73,6 +73,21 @@ export declare const LEDGER_NODE_DEFAULT_SIZE: {
|
|
|
73
73
|
width: number;
|
|
74
74
|
height: number;
|
|
75
75
|
};
|
|
76
|
+
export interface CanvasSizeAdjustment {
|
|
77
|
+
requested: {
|
|
78
|
+
width: number | null;
|
|
79
|
+
height: number | null;
|
|
80
|
+
};
|
|
81
|
+
applied: {
|
|
82
|
+
width: number;
|
|
83
|
+
height: number;
|
|
84
|
+
};
|
|
85
|
+
reason: 'defaulted' | 'clamped-to-minimum' | 'defaulted-and-clamped-to-minimum' | 'fit-to-children';
|
|
86
|
+
}
|
|
87
|
+
export declare function describeCreateSize(requestedWidth: number | undefined, requestedHeight: number | undefined, resolvedWidth: number, resolvedHeight: number, applied: {
|
|
88
|
+
width: number;
|
|
89
|
+
height: number;
|
|
90
|
+
}): CanvasSizeAdjustment | undefined;
|
|
76
91
|
interface CanvasCreateGroupInput {
|
|
77
92
|
title?: string;
|
|
78
93
|
childIds?: string[];
|
|
@@ -146,6 +161,7 @@ export declare function addCanvasNode(input: CanvasAddNodeInput): {
|
|
|
146
161
|
id: string;
|
|
147
162
|
node: CanvasNodeState;
|
|
148
163
|
needsCodeGraphRecompute: boolean;
|
|
164
|
+
sizeAdjustment?: CanvasSizeAdjustment;
|
|
149
165
|
};
|
|
150
166
|
export declare function resolveCanvasNode(nodeRef: CanvasNodeLookupInput): {
|
|
151
167
|
ok: true;
|
|
@@ -213,11 +229,13 @@ export declare function removeCanvasEdge(id: string): {
|
|
|
213
229
|
export declare function createCanvasGroup(input: CanvasCreateGroupInput): {
|
|
214
230
|
id: string;
|
|
215
231
|
node: CanvasNodeState;
|
|
232
|
+
sizeAdjustment?: CanvasSizeAdjustment;
|
|
216
233
|
};
|
|
217
234
|
export declare function groupCanvasNodes(groupId: string, childIds: string[], options?: {
|
|
218
235
|
childLayout?: CanvasArrangeMode;
|
|
219
236
|
}): {
|
|
220
237
|
ok: boolean;
|
|
238
|
+
sizeAdjustment?: CanvasSizeAdjustment;
|
|
221
239
|
};
|
|
222
240
|
export declare function ungroupCanvasNodes(groupId: string): {
|
|
223
241
|
ok: boolean;
|
|
@@ -230,6 +248,8 @@ export declare function createCanvasJsonRenderNode(input: JsonRenderNodeInput):
|
|
|
230
248
|
url: string;
|
|
231
249
|
spec: JsonRenderSpec;
|
|
232
250
|
node: CanvasNodeState;
|
|
251
|
+
warnings: string[];
|
|
252
|
+
sizeAdjustment?: CanvasSizeAdjustment;
|
|
233
253
|
};
|
|
234
254
|
/**
|
|
235
255
|
* Create an empty streaming json-render node. Unlike createCanvasJsonRenderNode
|
|
@@ -248,6 +268,7 @@ export declare function createCanvasStreamingJsonRenderNode(input: {
|
|
|
248
268
|
url: string;
|
|
249
269
|
spec: JsonRenderSpec;
|
|
250
270
|
node: CanvasNodeState;
|
|
271
|
+
sizeAdjustment?: CanvasSizeAdjustment;
|
|
251
272
|
};
|
|
252
273
|
/**
|
|
253
274
|
* Apply a batch of SpecStream patches to an existing json-render node, bumping
|
|
@@ -269,6 +290,7 @@ export declare function createCanvasGraphNode(input: GraphNodeInput): {
|
|
|
269
290
|
url: string;
|
|
270
291
|
spec: JsonRenderSpec;
|
|
271
292
|
node: CanvasNodeState;
|
|
293
|
+
sizeAdjustment?: CanvasSizeAdjustment;
|
|
272
294
|
};
|
|
273
295
|
export declare function setClientViewportSize(width: unknown, height: unknown): void;
|
|
274
296
|
export declare function getClientViewportSize(): {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* `.pmx-canvas-snapshots/`, loose blob files) are no longer imported as of 0.4.0 —
|
|
12
12
|
* the one-shot boot migration into SQLite was retired.
|
|
13
13
|
*/
|
|
14
|
+
import { type Tour } from '../shared/tour.js';
|
|
14
15
|
import { type PersistedCanvasState, type CanvasTheme, type AxTimelineQuery } from './canvas-db.js';
|
|
15
16
|
import { type PmxAxActivityKind, type PmxAxElicitation, type PmxAxModeRequest, type PmxAxMode, type PmxAxCommandDescriptor, type PmxAxPolicy, type PmxAxFocusState, type PmxAxSource, type PmxAxState, type PmxAxWorkItem, type PmxAxWorkItemStatus, type PmxAxApprovalGate, type PmxAxReviewAnnotation, type PmxAxReviewKind, type PmxAxReviewSeverity, type PmxAxReviewStatus, type PmxAxReviewAnchorType, type PmxAxReviewRegion, type PmxAxEvent, type PmxAxEventKind, type PmxAxEvidence, type PmxAxEvidenceKind, type PmxAxSteeringMessage, type PmxAxHostCapability, type PmxAxTimelineSummary } from './ax-state.js';
|
|
16
17
|
export declare const PMX_CANVAS_DIR = ".pmx-canvas";
|
|
@@ -102,6 +103,7 @@ export interface CanvasAnnotation {
|
|
|
102
103
|
createdAt: string;
|
|
103
104
|
}
|
|
104
105
|
export interface CanvasLayout {
|
|
106
|
+
tour?: Tour;
|
|
105
107
|
viewport: ViewportState;
|
|
106
108
|
theme: CanvasTheme;
|
|
107
109
|
nodes: CanvasNodeState[];
|
|
@@ -140,6 +142,7 @@ declare class CanvasStateManager {
|
|
|
140
142
|
private edges;
|
|
141
143
|
private annotations;
|
|
142
144
|
private _viewport;
|
|
145
|
+
private _tour;
|
|
143
146
|
private _theme;
|
|
144
147
|
private _contextPinnedNodeIds;
|
|
145
148
|
private _workspaceRoot;
|
|
@@ -236,6 +239,7 @@ declare class CanvasStateManager {
|
|
|
236
239
|
nodes: CanvasNodeState[];
|
|
237
240
|
edges: CanvasEdge[];
|
|
238
241
|
annotations: CanvasAnnotation[];
|
|
242
|
+
tour?: Tour;
|
|
239
243
|
} | null;
|
|
240
244
|
/** Delete a snapshot. */
|
|
241
245
|
renameSnapshot(id: string, name: string): boolean;
|
|
@@ -261,6 +265,8 @@ declare class CanvasStateManager {
|
|
|
261
265
|
private removeEdgesForNode;
|
|
262
266
|
getLayout(): CanvasLayout;
|
|
263
267
|
getLayoutForPersistence(): CanvasLayout;
|
|
268
|
+
getTour(): Tour | undefined;
|
|
269
|
+
setTour(tour: Tour | null): void;
|
|
264
270
|
applyUpdates(updates: CanvasNodeUpdate[], options?: ApplyUpdatesOptions): {
|
|
265
271
|
applied: number;
|
|
266
272
|
skipped: number;
|
|
@@ -26,6 +26,8 @@ export interface CanvasValidationResult {
|
|
|
26
26
|
collisions: CanvasValidationPair[];
|
|
27
27
|
containments: CanvasContainmentIssue[];
|
|
28
28
|
containmentViolations: CanvasContainmentIssue[];
|
|
29
|
+
/** Group frames overlapping nodes that are not members (advisory). */
|
|
30
|
+
groupFrameOverlaps: CanvasValidationPair[];
|
|
29
31
|
missingEdgeEndpoints: Array<{
|
|
30
32
|
edgeId: string;
|
|
31
33
|
from: string;
|
|
@@ -39,6 +41,7 @@ export interface CanvasValidationResult {
|
|
|
39
41
|
collisions: number;
|
|
40
42
|
containments: number;
|
|
41
43
|
containmentViolations: number;
|
|
44
|
+
groupFrameOverlaps: number;
|
|
42
45
|
missingEdgeEndpoints: number;
|
|
43
46
|
sizeWarnings: number;
|
|
44
47
|
};
|
|
@@ -60,7 +60,7 @@ export declare function buildContentHeightReporter(frameToken: string): string;
|
|
|
60
60
|
* of the main SPA bundle). Escaping is mandatory: the source is arbitrary node
|
|
61
61
|
* data and must not be parsed as markup.
|
|
62
62
|
*/
|
|
63
|
-
export declare function buildMermaidSurfaceHtml(source: string, inlineEntry?: string | null): string;
|
|
63
|
+
export declare function buildMermaidSurfaceHtml(source: string, inlineEntry?: string | null, fit?: 'contain' | 'none', frameToken?: string): string;
|
|
64
64
|
export interface HtmlSurfaceOptions {
|
|
65
65
|
theme: SurfaceTheme;
|
|
66
66
|
/**
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { type Tour } from '../shared/tour.js';
|
|
3
|
+
export type { Tour, TourStop } from '../shared/tour.js';
|
|
2
4
|
import type { AgentPhase, AgentPresence, AgentPresenceSnapshot } from '../shared/agent-presence.js';
|
|
3
5
|
import { canvasState } from './canvas-state.js';
|
|
4
6
|
import type { CanvasAnnotation, CanvasNodeState, CanvasEdge, CanvasLayout } from './canvas-state.js';
|
|
@@ -140,6 +142,8 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
140
142
|
ungroupNodes(groupId: string, options?: {
|
|
141
143
|
intentId?: string;
|
|
142
144
|
}): boolean;
|
|
145
|
+
getTour(): Tour;
|
|
146
|
+
setTour(tour: Tour | null): void;
|
|
143
147
|
clear(): void;
|
|
144
148
|
arrange(layout?: 'grid' | 'column' | 'flow'): void;
|
|
145
149
|
focusNode(id: string, options?: {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CanvasSizeAdjustment } from '../../canvas-operations.js';
|
|
1
2
|
import { type ExternalMcpTransportConfig } from '../../mcp-app-runtime.js';
|
|
2
3
|
import { type Operation, type OperationContext } from '../types.js';
|
|
3
4
|
export interface OpenMcpAppCoreInput {
|
|
@@ -20,6 +21,7 @@ export interface OpenMcpAppCoreResult {
|
|
|
20
21
|
toolCallId: string;
|
|
21
22
|
sessionId: string;
|
|
22
23
|
resourceUri: string;
|
|
24
|
+
sizeAdjustment?: CanvasSizeAdjustment;
|
|
23
25
|
}
|
|
24
26
|
/**
|
|
25
27
|
* Open an external MCP app: connect + call + read resource (openExternalMcpApp),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CanvasSizeAdjustment } from '../../canvas-operations.js';
|
|
1
2
|
import { type Operation } from '../types.js';
|
|
2
3
|
/** Legacy server.ts parseGraphPayloadData: a graph dataset must be an array of records. */
|
|
3
4
|
export declare function parseGraphPayloadData(value: unknown): Array<Record<string, unknown>> | null;
|
|
@@ -21,6 +22,7 @@ export interface StreamJsonRenderResult {
|
|
|
21
22
|
specVersion: number;
|
|
22
23
|
elementCount: number;
|
|
23
24
|
streamStatus: 'open' | 'closed';
|
|
25
|
+
sizeAdjustment?: CanvasSizeAdjustment;
|
|
24
26
|
}
|
|
25
27
|
/**
|
|
26
28
|
* Create-or-append core for streaming json-render nodes (the SDK's
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CanvasLayout, type CanvasNodeState } from '../../canvas-state.js';
|
|
2
|
+
import { type CanvasSizeAdjustment } from '../../canvas-operations.js';
|
|
2
3
|
import { type Operation } from '../types.js';
|
|
3
4
|
export declare const NODE_TYPES: readonly ["markdown", "status", "context", "ledger", "trace", "file", "diff", "mermaid", "image", "mcp-app", "webpage", "html", "group"];
|
|
4
5
|
/** Per-type default node frame size (formerly copy-pasted ladders). */
|
|
@@ -30,7 +31,7 @@ export declare function agentSafeFullLayoutPayload(layout: CanvasLayout): Record
|
|
|
30
31
|
* agents using either key (or a cached schema) work — matching the
|
|
31
32
|
* external-app / web-artifact responses that already return both.
|
|
32
33
|
*/
|
|
33
|
-
export declare function createdNodePayloadFromNode(node: CanvasNodeState, options?: Record<string, unknown>): Record<string, unknown>;
|
|
34
|
+
export declare function createdNodePayloadFromNode(node: CanvasNodeState, options?: Record<string, unknown>, extras?: Record<string, unknown>): Record<string, unknown>;
|
|
34
35
|
/**
|
|
35
36
|
* Create a basic (non-webpage / non-group / non-primitive) node. Union of the
|
|
36
37
|
* legacy handleCanvasAddNode generic branch; the SDK passes fileMode 'path',
|
|
@@ -41,6 +42,7 @@ export declare function createBasicCanvasNode(body: Record<string, unknown>, opt
|
|
|
41
42
|
}): {
|
|
42
43
|
node: CanvasNodeState;
|
|
43
44
|
needsCodeGraphRecompute: boolean;
|
|
45
|
+
sizeAdjustment?: CanvasSizeAdjustment;
|
|
44
46
|
};
|
|
45
47
|
/**
|
|
46
48
|
* Build a node patch with the full HTTP superset semantics (webpage
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CanvasSizeAdjustment } from './canvas-operations.js';
|
|
1
2
|
export interface WebArtifactBuildInput {
|
|
2
3
|
title: string;
|
|
3
4
|
appTsx: string;
|
|
@@ -41,11 +42,13 @@ export interface WebArtifactSourceContext {
|
|
|
41
42
|
export interface WebArtifactCanvasOpenResult {
|
|
42
43
|
nodeId: string;
|
|
43
44
|
url: string;
|
|
45
|
+
sizeAdjustment: CanvasSizeAdjustment;
|
|
44
46
|
}
|
|
45
47
|
export interface WebArtifactCanvasBuildResult extends WebArtifactBuildOutput {
|
|
46
48
|
openedInCanvas: boolean;
|
|
47
49
|
nodeId?: string;
|
|
48
50
|
url?: string;
|
|
51
|
+
sizeAdjustment?: CanvasSizeAdjustment;
|
|
49
52
|
startedAt: string;
|
|
50
53
|
completedAt: string;
|
|
51
54
|
durationMs: number;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const cameraSchema: z.ZodObject<{
|
|
3
|
+
x: z.ZodNumber;
|
|
4
|
+
y: z.ZodNumber;
|
|
5
|
+
scale: z.ZodNumber;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
export declare const tourStopSchema: z.ZodObject<{
|
|
8
|
+
target: z.ZodUnion<readonly [z.ZodObject<{
|
|
9
|
+
nodeId: z.ZodString;
|
|
10
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
11
|
+
viewport: z.ZodObject<{
|
|
12
|
+
x: z.ZodNumber;
|
|
13
|
+
y: z.ZodNumber;
|
|
14
|
+
scale: z.ZodNumber;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
}, z.core.$strict>]>;
|
|
17
|
+
duration: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
easing: z.ZodOptional<z.ZodEnum<{
|
|
19
|
+
linear: "linear";
|
|
20
|
+
"ease-in-out": "ease-in-out";
|
|
21
|
+
"ease-out": "ease-out";
|
|
22
|
+
}>>;
|
|
23
|
+
padding: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
pullback: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
export declare const tourSchema: z.ZodObject<{
|
|
27
|
+
stops: z.ZodArray<z.ZodObject<{
|
|
28
|
+
target: z.ZodUnion<readonly [z.ZodObject<{
|
|
29
|
+
nodeId: z.ZodString;
|
|
30
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
31
|
+
viewport: z.ZodObject<{
|
|
32
|
+
x: z.ZodNumber;
|
|
33
|
+
y: z.ZodNumber;
|
|
34
|
+
scale: z.ZodNumber;
|
|
35
|
+
}, z.core.$strip>;
|
|
36
|
+
}, z.core.$strict>]>;
|
|
37
|
+
duration: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
easing: z.ZodOptional<z.ZodEnum<{
|
|
39
|
+
linear: "linear";
|
|
40
|
+
"ease-in-out": "ease-in-out";
|
|
41
|
+
"ease-out": "ease-out";
|
|
42
|
+
}>>;
|
|
43
|
+
padding: z.ZodOptional<z.ZodNumber>;
|
|
44
|
+
pullback: z.ZodOptional<z.ZodNumber>;
|
|
45
|
+
}, z.core.$strip>>;
|
|
46
|
+
}, z.core.$strip>;
|
|
47
|
+
export type Tour = z.infer<typeof tourSchema>;
|
|
48
|
+
export type TourStop = z.infer<typeof tourStopSchema>;
|
|
49
|
+
export type Camera = z.infer<typeof cameraSchema>;
|
|
50
|
+
export interface TourNode {
|
|
51
|
+
id: string;
|
|
52
|
+
type: string;
|
|
53
|
+
position: {
|
|
54
|
+
x: number;
|
|
55
|
+
y: number;
|
|
56
|
+
};
|
|
57
|
+
size: {
|
|
58
|
+
width: number;
|
|
59
|
+
height: number;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export declare function derivedTour(nodes: TourNode[]): Tour;
|
|
63
|
+
export declare function resolveStop(stop: TourStop, nodes: TourNode[], width: number, height: number): Camera;
|
|
64
|
+
/** Interpolate world-space centres and log zoom; translations remain screen-space. */
|
|
65
|
+
export declare function interpolateCamera(from: Camera, to: Camera, progress: number, width: number, height: number, easing?: TourStop['easing'], pullback?: number): Camera;
|
|
66
|
+
/** Each segment includes its endpoint; zero-duration stops take one frame. */
|
|
67
|
+
export declare function segmentFrameCount(duration: number, fps: number): number;
|
|
68
|
+
export declare function tourFrames(tour: Tour, initial: Camera, nodes: TourNode[], width: number, height: number, fps: number): Generator<{
|
|
69
|
+
x: number;
|
|
70
|
+
y: number;
|
|
71
|
+
scale: number;
|
|
72
|
+
}, void, unknown>;
|
package/docs/cli.md
CHANGED
|
@@ -13,6 +13,91 @@ pmx-canvas node list --port 4750 # target a non-default dae
|
|
|
13
13
|
pmx-canvas --server-url http://127.0.0.1:4750 status # same, by URL
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
## Tour and presentation
|
|
17
|
+
|
|
18
|
+
This is the small tour slice of the [vision's “board is the presentation”](product-vision-2026-09.md#12-tours-the-board-is-the-presentation-m):
|
|
19
|
+
the existing cards remain the content, rather than being rebuilt as a separate deck.
|
|
20
|
+
The same stops and camera interpolation drive interactive presentation and optional capture.
|
|
21
|
+
A visual stop editor and carrying tours into static exports/share links are not implemented here.
|
|
22
|
+
|
|
23
|
+
Click **Present** in the top bar, or open `/workbench?present=1` for a chrome-free
|
|
24
|
+
embedded/capture view. Right/Down/Space advances, Left/Up goes back, Esc exits.
|
|
25
|
+
The camera is local to the viewer; board content continues updating over SSE.
|
|
26
|
+
Stops do not auto-advance. Missing targets show an error and can be skipped.
|
|
27
|
+
|
|
28
|
+
Save this as `tour.json` (replace the IDs with IDs from `pmx-canvas node list`):
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"stops": [
|
|
33
|
+
{ "target": { "nodeId": "overview-group" }, "duration": 1.5, "padding": 60 },
|
|
34
|
+
{ "target": { "nodeId": "detail-note" }, "duration": 2, "easing": "ease-in-out", "pullback": 0.7 },
|
|
35
|
+
{ "target": { "viewport": { "x": 80, "y": 100, "scale": 0.5 } }, "duration": 1 }
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pmx-canvas tour set --file tour.json
|
|
42
|
+
pmx-canvas tour get
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
A stop targets either a node ID (including a group ID) or an explicit viewport.
|
|
46
|
+
Viewport translation is screen-space: `screen = world * scale + offset`.
|
|
47
|
+
`duration` is transition time in seconds (default 1, zero jumps); `padding` is
|
|
48
|
+
screen pixels around a target (default 40). Easing is `linear`, `ease-in-out`
|
|
49
|
+
(default), or `ease-out`. Zoom interpolates logarithmically about the moving
|
|
50
|
+
world-space centre. `pullback` (0–4, default 0) subtracts a sinusoidal log-zoom
|
|
51
|
+
offset mid-move without changing endpoints. Tours allow at most 1000 stops.
|
|
52
|
+
|
|
53
|
+
Tours persist with the board and snapshots, participate in undo, and clear with
|
|
54
|
+
the board. A file containing `null` resets the tour: when none is saved, groups
|
|
55
|
+
are sorted by y, then x, then ID. A saved empty `stops` array deliberately has no
|
|
56
|
+
stops. SDK: `canvas.setTour(tourOrNull)` / `canvas.getTour()`.
|
|
57
|
+
|
|
58
|
+
### Optional capture of the same tour
|
|
59
|
+
|
|
60
|
+
`record` is an optional local utility, not a second presentation model. It reads
|
|
61
|
+
the saved/derived tour, or the identical tour JSON supplied with `--tour-file`.
|
|
62
|
+
Start the server first. Capture launches its own Bun.WebView Chrome session;
|
|
63
|
+
it does not replace a server automation session or move other viewers' cameras.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Capture the saved/derived board tour
|
|
67
|
+
pmx-canvas record --mode deterministic --present --fps 30 --resolution 1920x1080 --output tour.mp4
|
|
68
|
+
|
|
69
|
+
# Try the same tour model from a file without changing the saved tour
|
|
70
|
+
pmx-canvas record --mode deterministic --tour-file tour.json --present --output frames
|
|
71
|
+
|
|
72
|
+
# Alternatively, sample the live presentation while agents update the board
|
|
73
|
+
pmx-canvas record --duration 10 --present --theme light --output activity.mp4
|
|
74
|
+
|
|
75
|
+
# Keep recording until SIGINT (Ctrl+C) or SIGTERM, then encode
|
|
76
|
+
pmx-canvas record --stop-on-signal --output live.mp4
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Options: `--mode realtime|deterministic` (default realtime), `--resolution WIDTHxHEIGHT`
|
|
80
|
+
(default 1280x720), `--fps` (1–120, default 30), `--theme`, `--present`,
|
|
81
|
+
`--duration SECONDS` or `--stop-on-signal` for realtime, `--tour-file FILE`
|
|
82
|
+
for deterministic mode, `--chrome-path PATH`, and required `--output PATH`.
|
|
83
|
+
Global `--port` / `--server-url` work here too. Existing output paths are refused.
|
|
84
|
+
|
|
85
|
+
An `.mp4` output uses ffmpeg/H.264; any other path is a PNG sequence directory.
|
|
86
|
+
Frames and `recording.json` are retained at `<output>.frames` even after video
|
|
87
|
+
encoding. If ffmpeg is missing, the command clearly reports the PNG fallback
|
|
88
|
+
and returns that directory. Encoding failures retain frames and exit nonzero.
|
|
89
|
+
|
|
90
|
+
Deterministic mode resolves target geometry once and writes
|
|
91
|
+
`max(1, ceil(duration × fps))` frames per stop, including each endpoint. It sets
|
|
92
|
+
the camera, waits for two animation frames, checks the applied camera, then
|
|
93
|
+
captures. Duplicate a target to hold it. This makes **camera timing** deterministic,
|
|
94
|
+
not animated iframe content, fonts loaded later, network assets, or concurrent
|
|
95
|
+
board edits. Realtime mode samples the live board; slow captures repeat frames
|
|
96
|
+
to preserve wall-clock speed, with the repeated-frame count in `recording.json`.
|
|
97
|
+
Capture has no audio. Chrome and a Bun runtime with WebView support are required.
|
|
98
|
+
Recording is a local CLI/file operation, not a remote HTTP/MCP file-writing API;
|
|
99
|
+
HTTP/MCP manage tours and retain their existing screenshot/automation surfaces.
|
|
100
|
+
|
|
16
101
|
## pump — reactive steering for CLI agents
|
|
17
102
|
|
|
18
103
|
`pmx-canvas pump` turns any CLI agent (Codex, Amp, a script) into a steerable
|
|
@@ -99,6 +184,10 @@ pmx-canvas node update <node-id> --width 840 --height 620
|
|
|
99
184
|
pmx-canvas node update <node-id> --title "Renamed" --full
|
|
100
185
|
```
|
|
101
186
|
|
|
187
|
+
Mermaid `node add` and `node update` accept `--fit contain|none`, stored as
|
|
188
|
+
`data.fit`. Contain is the default and shrinks only overflowing diagrams;
|
|
189
|
+
none keeps 100% with scrolling. [Sizing and readability](node-types.md#mermaid-nodes).
|
|
190
|
+
|
|
102
191
|
`--from-search` / `--to-search` must each resolve to exactly one node — broad
|
|
103
192
|
queries fail rather than guess. Use the full visible title.
|
|
104
193
|
|