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
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const cameraSchema = z.object({ x: z.number(), y: z.number(), scale: z.number().positive() });
|
|
4
|
+
export const tourStopSchema = z.object({
|
|
5
|
+
target: z.union([z.strictObject({ nodeId: z.string().min(1) }), z.strictObject({ viewport: cameraSchema })]),
|
|
6
|
+
duration: z.number().nonnegative().max(3600).optional(),
|
|
7
|
+
easing: z.enum(['linear', 'ease-in-out', 'ease-out']).optional(),
|
|
8
|
+
padding: z.number().nonnegative().optional(),
|
|
9
|
+
pullback: z.number().min(0).max(4).optional(),
|
|
10
|
+
});
|
|
11
|
+
export const tourSchema = z.object({ stops: z.array(tourStopSchema).max(1000) });
|
|
12
|
+
export type Tour = z.infer<typeof tourSchema>;
|
|
13
|
+
export type TourStop = z.infer<typeof tourStopSchema>;
|
|
14
|
+
export type Camera = z.infer<typeof cameraSchema>;
|
|
15
|
+
export interface TourNode {
|
|
16
|
+
id: string;
|
|
17
|
+
type: string;
|
|
18
|
+
position: { x: number; y: number };
|
|
19
|
+
size: { width: number; height: number };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function derivedTour(nodes: TourNode[]): Tour {
|
|
23
|
+
return {
|
|
24
|
+
stops: nodes
|
|
25
|
+
.filter((n) => n.type === 'group')
|
|
26
|
+
.sort((a, b) => a.position.y - b.position.y || a.position.x - b.position.x || a.id.localeCompare(b.id))
|
|
27
|
+
.map((n) => ({ target: { nodeId: n.id } })),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function resolveStop(stop: TourStop, nodes: TourNode[], width: number, height: number): Camera {
|
|
32
|
+
if ('viewport' in stop.target) return stop.target.viewport;
|
|
33
|
+
const id = stop.target.nodeId;
|
|
34
|
+
const node = nodes.find((n) => n.id === id);
|
|
35
|
+
if (!node) throw new Error(`Tour target not found: ${id}`);
|
|
36
|
+
const padding = stop.padding ?? 40;
|
|
37
|
+
if (padding * 2 >= Math.min(width, height)) throw new Error('Tour padding exceeds viewport');
|
|
38
|
+
const scale = Math.min((width - padding * 2) / node.size.width, (height - padding * 2) / node.size.height);
|
|
39
|
+
return {
|
|
40
|
+
x: width / 2 - (node.position.x + node.size.width / 2) * scale,
|
|
41
|
+
y: height / 2 - (node.position.y + node.size.height / 2) * scale,
|
|
42
|
+
scale,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Interpolate world-space centres and log zoom; translations remain screen-space. */
|
|
47
|
+
export function interpolateCamera(
|
|
48
|
+
from: Camera,
|
|
49
|
+
to: Camera,
|
|
50
|
+
progress: number,
|
|
51
|
+
width: number,
|
|
52
|
+
height: number,
|
|
53
|
+
easing: TourStop['easing'] = 'ease-in-out',
|
|
54
|
+
pullback = 0,
|
|
55
|
+
): Camera {
|
|
56
|
+
const t = Math.max(0, Math.min(1, progress));
|
|
57
|
+
if (t === 0) return { ...from };
|
|
58
|
+
if (t === 1) return { ...to };
|
|
59
|
+
const e = easing === 'linear' ? t : easing === 'ease-out' ? 1 - (1 - t) ** 3 : t * t * (3 - 2 * t);
|
|
60
|
+
const scale = Math.exp(Math.log(from.scale) * (1 - e) + Math.log(to.scale) * e - pullback * Math.sin(Math.PI * e));
|
|
61
|
+
const cx = ((width / 2 - from.x) / from.scale) * (1 - e) + ((width / 2 - to.x) / to.scale) * e;
|
|
62
|
+
const cy = ((height / 2 - from.y) / from.scale) * (1 - e) + ((height / 2 - to.y) / to.scale) * e;
|
|
63
|
+
return { x: width / 2 - cx * scale, y: height / 2 - cy * scale, scale };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Each segment includes its endpoint; zero-duration stops take one frame. */
|
|
67
|
+
export function segmentFrameCount(duration: number, fps: number): number {
|
|
68
|
+
return Math.max(1, Math.ceil(duration * fps));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function* tourFrames(
|
|
72
|
+
tour: Tour,
|
|
73
|
+
initial: Camera,
|
|
74
|
+
nodes: TourNode[],
|
|
75
|
+
width: number,
|
|
76
|
+
height: number,
|
|
77
|
+
fps: number,
|
|
78
|
+
) {
|
|
79
|
+
let from = initial;
|
|
80
|
+
for (const stop of tour.stops) {
|
|
81
|
+
const to = resolveStop(stop, nodes, width, height);
|
|
82
|
+
const count = segmentFrameCount(stop.duration ?? 1, fps);
|
|
83
|
+
for (let i = 1; i <= count; i++)
|
|
84
|
+
yield interpolateCamera(from, to, i / count, width, height, stop.easing, stop.pullback);
|
|
85
|
+
from = to;
|
|
86
|
+
}
|
|
87
|
+
}
|