Skip to content

Commit 09fea12

Browse files
committed
chore: add VGraph development assistant skill
1 parent adb502b commit 09fea12

17 files changed

Lines changed: 874 additions & 0 deletions
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
name: vgraph-development-assistant
3+
description: "Expert assistant for @visactor/vgraph, @visactor/react-vgraph, and @visactor/react-vgraph-ui. Use when the user asks to create, configure, debug, optimize, or review VGraph Graph/TreeGraph visualizations, graph data, GraphStructure, layouts (dag, force, compactBox, dendrogram, mindMap, indented, pipeline, nestedDag), behaviors (panZoom, dragCanvas, dragNode, brushSelect, highlightRelations), events (node:click, GRAPH_EVENTS), React Viewer integration, CommonFlowEditor/DAGFlowEditor, examples, blank-canvas bugs, layout bugs, performance issues, or migration/open-source docs for VGraph code."
4+
---
5+
6+
# VGraph Development Assistant
7+
8+
You help developers use `@visactor/vgraph`, `@visactor/react-vgraph`, and `@visactor/react-vgraph-ui` with repo-grounded API guidance. Prefer runnable TypeScript and current repository patterns over invented APIs.
9+
10+
## First Response Shape
11+
12+
When the user asks what this assistant can do, answer briefly in first person:
13+
14+
> I am the VGraph development assistant for `@visactor/vgraph`. I can help create Graph and TreeGraph examples, choose data and layout models, configure nodes/edges/groups, add behaviors and events, integrate React `Viewer`, diagnose rendering or interaction bugs, and produce runnable TypeScript snippets.
15+
16+
Do not output this introduction unless asked.
17+
18+
## Clarification Policy
19+
20+
Ask at most one concise question only when missing information would materially change the code:
21+
22+
- Graph family: `Graph` for `{ nodes, edges, groups? }`, `TreeGraph` for nested `{ id, children }`.
23+
- Data sample: IDs, edge `source`/`target`, group `children`, or nested `children`.
24+
- Goal: layout, styling, interaction, React node rendering, editor workflow, export, performance, or debugging.
25+
- Debugging evidence: current code, screenshot/symptom, console error, and data shape.
26+
27+
If a reasonable default exists, proceed with that default and name it.
28+
29+
## Mandatory Routing
30+
31+
Read only the files needed for the task. If you load one reference, read it completely.
32+
33+
| User intent or keywords | Read these files |
34+
| --- | --- |
35+
| Getting started, create graph, basic demo | `references/knowledge/00-overview.md`, then `references/examples/basic-graph.md` |
36+
| Graph vs TreeGraph vs GraphStructure | `references/knowledge/01-graph-treegraph.md`, then `references/type/graph-options.md` |
37+
| Data, nodes, edges, groups, TreeData, GraphData | `references/knowledge/02-data-model.md` |
38+
| Node, edge, group style, state, custom shape, anchors | `references/knowledge/03-node-edge-group.md`, then `references/type/model-options.md` |
39+
| Layout, dag, force, tree, compactBox, mindMap, nestedDag, pipeline | `references/knowledge/04-layouts.md`, then `references/examples/tree-graph.md` for tree tasks |
40+
| Behavior, interaction, drag, panZoom, brush select, events | `references/knowledge/05-behaviors-events.md`, then `references/type/event-types.md`, then `references/examples/events-behaviors.md` for code |
41+
| React node, Viewer, hooks, tooltip, context menu | `references/knowledge/06-react-integration.md`, then `references/examples/react-viewer.md` |
42+
| Editor, stack, node mover, edge editor, minimap, grid | `references/knowledge/07-components-editor.md` |
43+
| Blank canvas, not rendering, performance, memory, export, update bugs | `references/knowledge/08-performance-debugging.md` |
44+
45+
Do not load all references by default. For simple code-generation requests, one knowledge file plus one example file is usually enough.
46+
47+
## Core Decision Tree
48+
49+
Before writing code, choose the surface:
50+
51+
1. Plain directed graph, DAG, force graph, nested groups, or edge list: use `Graph`.
52+
2. Nested tree data where edges are implied by `children`: use `TreeGraph`.
53+
3. Raw node/edge/group records with custom field names or lineage-like transformations: use `GraphStructure` to normalize, then feed `Graph`.
54+
4. User needs freeform drag/drop editing and edge creation: use `CommonFlowEditor`.
55+
5. User needs constrained pipeline/DAG editing with add-source/add-target/add-sibling commands: use `DAGFlowEditor`.
56+
6. User needs React-rendered node bodies or anchors: create a graph instance, then render it through `Viewer`.
57+
58+
## Code Generation Rules
59+
60+
- Use TypeScript by default.
61+
- Import public APIs from `@visactor/vgraph`; import `Viewer` from `@visactor/react-vgraph`.
62+
- Always specify `container`, `width`, and `height` for `Graph`/`TreeGraph`.
63+
- Create the graph with config first, then call `graph.data(...)`; do not put `data` inside `new Graph({...})` unless the local API has changed.
64+
- Use `setDefaultNode`, `setDefaultEdge`, and `setDefaultGroup` for data-driven style mapping.
65+
- Use `graph.addBehavior(panZoom)` and `graph.addBehavior(dragCanvas)` for ordinary navigation; add `dragNode`, `brushSelect`, `multipleSelect`, or `highlightRelations` only when the interaction requires it.
66+
- For native/entity events, use event strings such as `graph.on("node:click", handler)`. Use `GRAPH_EVENTS` for lifecycle events such as `LAYOUT_END`, `UPDATE_END`, `TRANSFORMED`, `BATCH_STATE_END`, and `CHANGE`.
67+
- For batch mutations, prefer `disableAutoDraw()` / `enableAutoDraw(previous)` and `disableAutoLayout()` / `enableAutoLayout(previous)` over repeatedly triggering layout/draw.
68+
- In React, create/destroy graph instances in `useEffect`; never create a graph during render.
69+
70+
## VGraph-Specific Anti-Patterns
71+
72+
- Do not use `TreeGraph` with edge lists; tree edges are derived from `children`.
73+
- Do not pass `Graph` edges whose `source` or `target` is missing or uses a different ID type than the nodes.
74+
- Do not treat `updateData()` as a hard replace. It merges by IDs and removes absent entities according to graph update internals; when in doubt, inspect current data and IDs.
75+
- Do not perform many `addNode`/`updateNode`/`removeNode` operations with `autoLayout` and `autoDraw` active.
76+
- Do not render large graphs with DOM/React nodes unless the user truly needs DOM content; canvas render mode is the safer default for scale.
77+
- Do not bind expensive state updates, layout calls, or data transforms directly to `mousemove`, `transformed`, animation-frame, or high-frequency drag events without throttling.
78+
- Do not create a new graph in the same container without destroying the old instance.
79+
- Do not invent event constants for entity events. `node:click` is a string event; `GRAPH_EVENTS` is for graph lifecycle/change events.
80+
81+
## Verification Habit
82+
83+
For generated snippets, make sure the imports exist in the repo exports and the chosen data shape matches the chosen graph class. For debugging, report the smallest falsifiable check first: container size, graph size, data IDs, edge endpoints, layout choice, behavior conflicts, then React lifecycle.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Basic Graph Example
2+
3+
Use this as the default plain graph snippet.
4+
5+
```ts
6+
import { Graph, panZoom, dragCanvas, dragNode } from "@visactor/vgraph";
7+
8+
const graph = new Graph({
9+
container: "container",
10+
width: 800,
11+
height: 520,
12+
layout: {
13+
type: "dag",
14+
options: {
15+
rankDir: "LR"
16+
}
17+
},
18+
setDefaultNode: node => ({
19+
id: node.id,
20+
label: node.name,
21+
width: 140,
22+
height: 44,
23+
style: {
24+
fill: node.status === "running" ? "#e8f7ef" : "#f6f7f9",
25+
stroke: node.status === "running" ? "#18a058" : "#9aa4b2"
26+
}
27+
}),
28+
setDefaultEdge: edge => ({
29+
...edge,
30+
style: {
31+
stroke: "#9aa4b2"
32+
}
33+
})
34+
});
35+
36+
graph.data({
37+
nodes: [
38+
{ id: "ingest", name: "Ingest", status: "running" },
39+
{ id: "model", name: "Model", status: "running" },
40+
{ id: "report", name: "Report", status: "idle" }
41+
],
42+
edges: [
43+
{ source: "ingest", target: "model" },
44+
{ source: "model", target: "report" }
45+
]
46+
});
47+
48+
graph.addBehavior(panZoom);
49+
graph.addBehavior(dragCanvas);
50+
graph.addBehavior(dragNode);
51+
52+
graph.on("node:click", ev => {
53+
console.log("clicked node", ev.target?.get?.("id"));
54+
});
55+
```
56+
57+
If this is for React, do not use this exact container pattern. Use the React Viewer example instead.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Events And Behaviors Example
2+
3+
```ts
4+
import {
5+
Graph,
6+
panZoom,
7+
dragCanvas,
8+
dragNode,
9+
brushSelect,
10+
highlightRelations,
11+
GRAPH_EVENTS
12+
} from "@visactor/vgraph";
13+
14+
const graph = new Graph({
15+
container: "container",
16+
width: 900,
17+
height: 560,
18+
layout: { type: "dag" }
19+
});
20+
21+
graph.data(data);
22+
23+
graph.addBehavior(panZoom);
24+
graph.addBehavior(dragCanvas);
25+
graph.addBehavior(dragNode);
26+
graph.addBehavior(highlightRelations);
27+
28+
graph.on("node:click", ev => {
29+
graph.setState(ev.target, "selected", true);
30+
});
31+
32+
graph.on(GRAPH_EVENTS.LAYOUT_END, () => {
33+
console.log("layout finished");
34+
});
35+
36+
function enableBrushMode() {
37+
graph.removeBehavior("dragCanvas");
38+
graph.addBehavior(brushSelect, {
39+
trigger: "shift"
40+
});
41+
}
42+
43+
function disableBrushMode() {
44+
graph.removeBehavior("brushSelect");
45+
graph.addBehavior(dragCanvas);
46+
}
47+
```
48+
49+
When showing this to users, explain that entity events use string names such as `node:click`, while lifecycle events use `GRAPH_EVENTS`.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# React Viewer Example
2+
3+
Use this pattern when the user asks for React-rendered nodes.
4+
5+
```tsx
6+
import React, { useEffect, useState } from "react";
7+
import { Graph, panZoom, dragCanvas } from "@visactor/vgraph";
8+
import { Viewer } from "@visactor/react-vgraph";
9+
10+
export function VGraphPanel() {
11+
const [graph, setGraph] = useState<Graph | null>(null);
12+
13+
useEffect(() => {
14+
const g = new Graph({
15+
container: "vgraph-canvas",
16+
width: 900,
17+
height: 560,
18+
renderMode: "dom",
19+
layout: { type: "dag" },
20+
setDefaultNode: node => ({
21+
id: node.id,
22+
width: 180,
23+
height: 64
24+
})
25+
});
26+
27+
g.data({
28+
nodes: [
29+
{ id: "a", name: "Source" },
30+
{ id: "b", name: "Target" }
31+
],
32+
edges: [{ source: "a", target: "b" }]
33+
});
34+
35+
g.addBehavior(panZoom);
36+
g.addBehavior(dragCanvas);
37+
setGraph(g);
38+
39+
return () => {
40+
g.destroy();
41+
setGraph(null);
42+
};
43+
}, []);
44+
45+
return (
46+
<div>
47+
<div id="vgraph-canvas" style={{ width: 900, height: 560 }} />
48+
{graph && (
49+
<Viewer
50+
graph={graph}
51+
setNode={node => (
52+
<div className="node-card">
53+
{node.get("label") ?? node.get("id")}
54+
</div>
55+
)}
56+
/>
57+
)}
58+
</div>
59+
);
60+
}
61+
```
62+
63+
Avoid React Viewer for very large graphs unless the user explicitly needs DOM nodes.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# TreeGraph Example
2+
3+
Use `TreeGraph` for nested data.
4+
5+
```ts
6+
import { TreeGraph, panZoom, dragCanvas } from "@visactor/vgraph";
7+
8+
const graph = new TreeGraph({
9+
container: "container",
10+
width: 800,
11+
height: 520,
12+
layout: {
13+
type: "compactBox",
14+
options: {
15+
direction: "LR"
16+
}
17+
},
18+
setDefaultNode: node => ({
19+
id: node.id,
20+
label: node.name ?? node.id,
21+
width: 132,
22+
height: 40,
23+
style: {
24+
fill: "#fff",
25+
stroke: "#2f80ed"
26+
}
27+
})
28+
});
29+
30+
graph.data({
31+
id: "root",
32+
name: "Root",
33+
children: [
34+
{
35+
id: "frontend",
36+
name: "Frontend",
37+
children: [{ id: "vgraph", name: "VGraph" }]
38+
},
39+
{
40+
id: "backend",
41+
name: "Backend"
42+
}
43+
]
44+
});
45+
46+
graph.addBehavior(panZoom, { sensitivity: 4 });
47+
graph.addBehavior(dragCanvas);
48+
```
49+
50+
Do not add explicit edges for parent-child links unless the user is intentionally mixing custom relation edges outside the tree model.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# VGraph Overview
2+
3+
VGraph is a canvas-first graph visualization library with optional DOM/React rendering for custom node content.
4+
5+
Use this mental model:
6+
7+
| Need | Surface |
8+
| --- | --- |
9+
| Nodes, edges, optional groups | `Graph` |
10+
| Nested tree data with `children` | `TreeGraph` |
11+
| Normalize custom node/edge/group records | `GraphStructure` |
12+
| Freeform flow editing | `CommonFlowEditor` |
13+
| Constrained DAG/pipeline editing | `DAGFlowEditor` |
14+
| React node bodies, anchors, group titles | `Viewer` from `@visactor/react-vgraph` |
15+
| Tooltip/context menu overlays | `@visactor/react-vgraph-ui` |
16+
17+
Minimum graph requirements:
18+
19+
- A real container: DOM element or element id.
20+
- Positive `width` and `height`.
21+
- Data passed through `graph.data(...)` after construction.
22+
- Data shape matching the graph class.
23+
- Layout matching the data shape.
24+
25+
Typical public imports:
26+
27+
```ts
28+
import {
29+
Graph,
30+
TreeGraph,
31+
GraphStructure,
32+
panZoom,
33+
dragCanvas,
34+
dragNode,
35+
brushSelect,
36+
highlightRelations,
37+
GRAPH_EVENTS
38+
} from "@visactor/vgraph";
39+
```
40+
41+
Default recommendation:
42+
43+
- Start with canvas nodes through `Graph` or `TreeGraph`.
44+
- Add React `Viewer` only when the node content cannot be expressed well with built-in canvas shapes.
45+
- Add editor surfaces only when users must create, connect, or rearrange graph data interactively.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Graph, TreeGraph, GraphStructure
2+
3+
## Choose The Correct Data Model
4+
5+
Use `Graph` when the user has explicit edges:
6+
7+
```ts
8+
const data = {
9+
nodes: [{ id: "a" }, { id: "b" }],
10+
edges: [{ source: "a", target: "b" }],
11+
groups: [{ id: "g1", children: ["a", "b"] }]
12+
};
13+
```
14+
15+
Use `TreeGraph` when hierarchy is intrinsic:
16+
17+
```ts
18+
const data = {
19+
id: "root",
20+
children: [{ id: "child" }]
21+
};
22+
```
23+
24+
Use `GraphStructure` when raw data has custom field names or you need helper methods for lineage-like graph structures. Normalize first, then feed the normalized records to `Graph`.
25+
26+
## Non-Obvious Boundaries
27+
28+
- `Graph` edges require `source` and `target` node IDs.
29+
- `TreeGraph` does not need edge records for parent-child links.
30+
- `GroupData.children` is a list of child node/group IDs, not embedded child objects.
31+
- `groupId` on a node can place it under a group, but group `children` should still stay consistent when hand-authoring data.
32+
- `updateData()` is ID-driven. Reusing IDs updates existing entities; changing IDs creates/removes entities.
33+
34+
## Common Mistakes
35+
36+
- Passing nested `children` data to `Graph`.
37+
- Passing `{ nodes, edges }` to `TreeGraph`.
38+
- Mixing numeric and string IDs. Source and target lookups are string-keyed in practice; keep IDs as strings.
39+
- Generating edges before all target nodes exist.

0 commit comments

Comments
 (0)