dragooncjw 10 miesięcy temu
rodzic
commit
27033a821d
57 zmienionych plików z 1771 dodań i 469 usunięć
  1. 1 1
      apps/docs/src/en/_meta.json
  2. 21 6
      apps/docs/src/en/api/_meta.json
  3. 44 44
      apps/docs/src/en/api/common-apis.mdx
  4. 15 0
      apps/docs/src/en/api/components/editor-renderer.mdx
  5. 21 0
      apps/docs/src/en/api/components/fixed-layout-editor-provider.mdx
  6. 20 0
      apps/docs/src/en/api/components/fixed-layout-editor.mdx
  7. 21 0
      apps/docs/src/en/api/components/free-layout-editor-provider.mdx
  8. 18 0
      apps/docs/src/en/api/components/free-layout-editor.mdx
  9. 28 0
      apps/docs/src/en/api/components/workflow-node-renderer.mdx
  10. 8 0
      apps/docs/src/en/api/core/_meta.json
  11. 184 0
      apps/docs/src/en/api/core/flow-document.mdx
  12. 130 0
      apps/docs/src/en/api/core/flow-node-entity.mdx
  13. 99 0
      apps/docs/src/en/api/core/playground.mdx
  14. 86 0
      apps/docs/src/en/api/core/workflow-document.mdx
  15. 6 0
      apps/docs/src/en/api/core/workflow-line-entity.mdx
  16. 29 0
      apps/docs/src/en/api/core/workflow-lines-manager.mdx
  17. 21 0
      apps/docs/src/en/api/hooks/use-client-context.mdx
  18. 67 0
      apps/docs/src/en/api/hooks/use-node-render.mdx
  19. 70 0
      apps/docs/src/en/api/hooks/use-playground-tools.mdx
  20. 29 0
      apps/docs/src/en/api/hooks/use-refresh.mdx
  21. 57 0
      apps/docs/src/en/api/hooks/use-service.mdx
  22. 1 1
      apps/docs/src/en/api/plugins.mdx
  23. 5 0
      apps/docs/src/en/api/services/clipboard-service.mdx
  24. 11 0
      apps/docs/src/en/api/services/command-service.mdx
  25. 118 0
      apps/docs/src/en/api/services/flow-operation-service.mdx
  26. 49 0
      apps/docs/src/en/api/services/history-service.mdx
  27. 14 0
      apps/docs/src/en/api/services/selection-service.mdx
  28. 33 0
      apps/docs/src/en/api/utils/disposable-collection.mdx
  29. 21 0
      apps/docs/src/en/api/utils/disposable.mdx
  30. 42 0
      apps/docs/src/en/api/utils/emitter.mdx
  31. 73 0
      apps/docs/src/en/api/utils/get-node-form.mdx
  32. 1 1
      apps/docs/src/en/examples/_meta.json
  33. 11 11
      apps/docs/src/en/examples/fixed-layout/fixed-feature-overview.mdx
  34. 3 3
      apps/docs/src/en/examples/fixed-layout/fixed-layout-simple.mdx
  35. 6 6
      apps/docs/src/en/examples/free-layout/free-feature-overview.mdx
  36. 3 3
      apps/docs/src/en/examples/free-layout/free-layout-simple.mdx
  37. 1 1
      apps/docs/src/en/guide/_meta.json
  38. 0 10
      apps/docs/src/en/guide/advanced/_meta.json
  39. 70 65
      apps/docs/src/en/guide/advanced/form.mdx
  40. 75 76
      apps/docs/src/en/guide/advanced/history.mdx
  41. 1 1
      apps/docs/src/en/guide/advanced/interactive/minimap.mdx
  42. 18 4
      apps/docs/src/en/guide/advanced/interactive/shortcuts.mdx
  43. 11 10
      apps/docs/src/en/guide/advanced/variable.mdx
  44. 3 1
      apps/docs/src/en/guide/concepts/_meta.json
  45. 1 0
      apps/docs/src/en/guide/concepts/ecs.mdx
  46. 5 5
      apps/docs/src/en/guide/concepts/index.mdx
  47. 1 0
      apps/docs/src/en/guide/concepts/ioc.mdx
  48. 59 51
      apps/docs/src/en/guide/getting-started/create-fixed-layout-simple.mdx
  49. 43 38
      apps/docs/src/en/guide/getting-started/create-free-layout-simple.mdx
  50. 4 4
      apps/docs/src/en/guide/getting-started/install.mdx
  51. 1 8
      apps/docs/src/en/guide/index/_meta.json
  52. 33 34
      apps/docs/src/en/guide/index/canvas-engine/index.mdx
  53. 27 26
      apps/docs/src/en/guide/index/introduction.mdx
  54. 17 18
      apps/docs/src/en/guide/index/node-engine.mdx
  55. 16 24
      apps/docs/src/en/guide/index/variable-engine.mdx
  56. 15 13
      apps/docs/src/en/guide/introduction.mdx
  57. 4 4
      apps/docs/src/en/index.md

+ 1 - 1
apps/docs/src/en/_meta.json

@@ -15,7 +15,7 @@
     "activeMatch": "/api/"
   },
   {
-    "text": "APIs",
+    "text": "API Documentation",
     "link": "/auto-docs/",
     "activeMatch": "/auto-docs/"
   }

+ 21 - 6
apps/docs/src/en/api/_meta.json

@@ -2,16 +2,31 @@
   {
     "type": "file",
     "name": "index",
-    "label": "API 预览"
+    "label": "API Overview"
   },
   {
-    "type": "file",
-    "name": "common-apis",
-    "label": "常用 API"
+    "type": "dir",
+    "name": "core",
+    "label": "Core"
+  },
+  {
+    "type": "dir",
+    "name": "hooks",
+    "label": "Hooks"
+  },
+  {
+    "type": "dir",
+    "name": "components",
+    "label": "Components"
+  },
+  {
+    "type": "dir",
+    "name": "services",
+    "label": "Services"
   },
   {
     "type": "dir",
-    "name": "plugins",
-    "label": "插件"
+    "name": "utils",
+    "label": "Utils"
   }
 ]

+ 44 - 44
apps/docs/src/en/api/common-apis.mdx

@@ -1,102 +1,102 @@
-# 常用 API
+# Common APIs
 
-## FlowDocument (自动化布局文档数据)
+## FlowDocument (Automated Layout Document Data)
 
 ```ts
-// 通过 hook 获取,也可以通过ctx
+// Can be obtained through hook or ctx
 const doc = useService<FlowDocument>(FlowDocument)
 
-doc.fromJSON(data) // 加载数据
-doc.getAllNodes() // 获取所有节点
-doc.traverseDFS(node => {}) // 深度遍历节点
-doc.toJSON() // TODO 这里老版本的数据,还没优化,业务最好自己使用 traverseDFS 实现 json 转换
+doc.fromJSON(data) // Load data
+doc.getAllNodes() // Get all nodes
+doc.traverseDFS(node => {}) // Depth-first traversal of nodes
+doc.toJSON() // TODO This is the old version data, not yet optimized. Business logic should implement JSON conversion using traverseDFS
 
-doc.addFromNode(targetNode, json) // 插入到指定节点的后边
+doc.addFromNode(targetNode, json) // Insert after the specified node
 
-doc.onNodeCreate(({ node, data}) => {}) // 监听节点创建,data 为创建时候的json数据
-doc.onNodeDispose(({ node }) => {}) // 监听节点删除
+doc.onNodeCreate(({ node, data}) => {}) // Listen to node creation, data is the JSON data at creation time
+doc.onNodeDispose(({ node }) => {}) // Listen to node deletion
 ```
 
-## WorkflowDocument (自由连线布局文档数据) 继承自 FlowDocument
+## WorkflowDocument (Free Connection Layout Document Data) Inherits from FlowDocument
 
 ```ts
 const doc = useService<WorkflowDocument>(WorkflowDocument)
 
-doc.fromJSON(data) // 加载数据
-doc.toJSON() // 导出数据
-doc.getAllNodes() // 获取所有节点
-doc.linesManager.getAllLines() // 获取所有线条
+doc.fromJSON(data) // Load data
+doc.toJSON() // Export data
+doc.getAllNodes() // Get all nodes
+doc.linesManager.getAllLines() // Get all lines
 
-// 创建节点
+// Create node
 doc.createWorkflowNode({ id: nanoid(), type: 'xxx', data: {}, meta: { position: { x: 0, y: 0 } } })
-// 创建线条,from和to 为对应要连线的节点id, fromPort, toPort 如果为单个端口可以不指定
+// Create line, from and to are the node IDs to connect, fromPort and toPort can be omitted for single ports
 doc.linesManager.createLine({ from, to, fromPort, toPort })
 
-// 监听变化,这里会监听线条和节点等事件
+// Listen to changes, this will monitor events for lines and nodes
 doc.onContentChange((e) => {
 
 })
 ```
 
-## FlowNodeEntity(节点)
+## FlowNodeEntity (Node)
 
 ```ts
-node.flowNodeType // 当前节点的type类型
-node.transform.bounds // 获取节点的外围矩形框, 包含 x,y,width,height
-node.updateExtInfo({ title: 'xxx' }) // 设置扩展数据, 响应式会刷新节点
-node.getExtInfo<T>() // 获取扩展数据
-node.getNodeRegister() // 拿到当前节点的定义
+node.flowNodeType // Current node type
+node.transform.bounds // Get node's bounding rectangle, includes x,y,width,height
+node.updateExtInfo({ title: 'xxx' }) // Set extension data, reactive will refresh node
+node.getExtInfo<T>() // Get extension data
+node.getNodeRegister() // Get current node definition
 
-node.dispose() // 删除节点
+node.dispose() // Delete node
 
-// renderData 是 节点 ui相关数据
+// renderData is node UI-related data
 const renderData = node.renderData
-renderData.node // 当前节点的domNode
-renderData.expanded // 当前节点是否展开,可以设置
+renderData.node // Current node's DOM node
+renderData.expanded // Whether current node is expanded, can be set
 
-// 拿到所有上游输入和输出节点(自由连线布局)
+// Get all upstream input and output nodes (free connection layout)
 node.getData<WorkflowNodeLinesData>(WorkflowNodeLinesData).allInputNodes
 node.getData<WorkflowNodeLinesData>(WorkflowNodeLinesData).allOutputNodes
 ```
 
-## Playground (画布)
+## Playground (Canvas)
 
 ```ts
-// 通过 hook 获取,也可以通过ctx
+// Can be obtained through hook or ctx
 const playground = useService(Playground)
 
-// 滚动到指定的节点并居中
+// Scroll to specified node and center it
 ctx.playground.config.scrollToView({
    entities: [node]
-   scrollToCenter true
-   easing: true // 缓动动画
+   scrollToCenter: true
+   easing: true // Easing animation
 })
 
-// 滚动画布
+// Scroll canvas
 ctx.playground.config.scroll({
   scrollX: 0
   scrollY: 0
 })
 
-// 适配屏幕
+// Fit to screen
 ctx.playground.config.fitView(
-  doc.root.getData<FlowNodeTransformData>().bounds, // 需要居中的矩形框,这里拿节点根节点的大小代表最大的框
-  true, // 是否缓动
-  20, // padding,留出空白间距
+  doc.root.getData<FlowNodeTransformData>().bounds, // Rectangle to center, here using root node size to represent maximum frame
+  true, // Whether to use easing
+  20, // padding, leave blank spacing
 )
 
-// 缩放
+// Zoom
 ctx.playground.config.zoomin()
 ctx.playground.config.zoomout()
-ctx.playground.config.finalScale // 当前缩放比例
+ctx.playground.config.finalScale // Current zoom scale
 ```
 
-## SelectionService (选择器)
+## SelectionService (Selector)
 
 ```ts
 const selectionService = useService<SelectionService>()
 
-selection.selection // 返回当前选中的节点数组,也可以修改,如选中节点 seleciton.selection = [node]
+selection.selection // Returns currently selected node array, can also be modified, e.g., select node: selection.selection = [node]
 
-selection.onSelectionChanged(() => {}) // 监听变化
+selection.onSelectionChanged(() => {}) // Listen to changes
 ```

+ 15 - 0
apps/docs/src/en/api/components/editor-renderer.mdx

@@ -0,0 +1,15 @@
+# EditorRenderer
+
+Canvas rendering component, needs to be used with `FixedLayoutEditorProvider` or `FreeLayoutEditorProvider`
+
+```tsx pure
+function App() {
+  return (
+    <FixedLayoutEditorProvider {...editorProps}>
+      <EditorRenderer className="demo-editor" style={{ /* style */}}>
+        {/* If you provide children, this content will be placed below the canvas div */}
+      </EditorRenderer>
+    </FixedLayoutEditorProvider>
+  )
+}
+```

+ 21 - 0
apps/docs/src/en/api/components/fixed-layout-editor-provider.mdx

@@ -0,0 +1,21 @@
+# FixedLayoutEditorProvider
+
+Fixed layout canvas configuration, supports ref
+
+```tsx pure
+import { FixedLayoutEditorProvider, FixedLayoutPluginContext, EditorRenderer } from '@flowgram.ai/fixed-layout-editor'
+
+function App() {
+  const ref = useRef<FixedLayoutPluginContext | undefined>();
+
+  useEffect(() => {
+    console.log(ref.current.document.toJSON())
+  }, [])
+  return (
+    <FixedLayoutEditorProvider {...editorProps} ref={ref}>
+      <EditorRenderer className="demo-editor" />
+    </FixedLayoutEditorProvider>
+  )
+}
+
+```

+ 20 - 0
apps/docs/src/en/api/components/fixed-layout-editor.mdx

@@ -0,0 +1,20 @@
+# FixedLayoutEditor
+
+
+Fixed layout canvas, equivalent to the combination of `FixedLayoutEditorProvider` and `EditorRenderer`
+
+```tsx pure
+import { FixedLayoutEditor, FixedLayoutPluginContext } from '@flowgram.ai/fixed-layout-editor'
+
+function App() {
+  const ref = useRef<FixedLayoutPluginContext | undefined>();
+
+  useEffect(() => {
+    console.log(ref.current.document.toJSON())
+  }, [])
+
+  return (
+    <FixedLayoutEditor className="demo-editor" {...editorProps} ref={ref} />
+  )
+}
+```

+ 21 - 0
apps/docs/src/en/api/components/free-layout-editor-provider.mdx

@@ -0,0 +1,21 @@
+# FreeLayoutEditorProvider
+
+Free layout canvas configuration, supports ref
+
+```tsx pure
+import { FreeLayoutEditorProvider, FreeLayoutPluginContext, EditorRenderer } from '@flowgram.ai/free-layout-editor'
+
+function App() {
+  const ref = useRef<FreeLayoutPluginContext | undefined>();
+
+  useEffect(() => {
+    console.log(ref.current.document.toJSON())
+  }, [])
+  return (
+    <FreeLayoutEditorProvider {...editorProps} ref={ref}>
+      <EditorRenderer className="demo-editor" />
+    </FreeLayoutEditorProvider>
+  )
+}
+
+```

+ 18 - 0
apps/docs/src/en/api/components/free-layout-editor.mdx

@@ -0,0 +1,18 @@
+# FreeLayoutEditor
+
+Free layout canvas, equivalent to the combination of `FreeLayoutEditorProvider` and `EditorRenderer`
+
+```tsx pure
+import { FreeLayoutEditor, FreeLayoutPluginContext } from '@flowgram.ai/free-layout-editor'
+
+function App() {
+  const ref = useRef<FreeLayoutPluginContext | undefined>();
+
+  useEffect(() => {
+    console.log(ref.current.document.toJSON())
+  }, [])
+  return (
+    <FreeLayoutEditor className="demo-editor" {...editorProps} ref={ref} />
+  )
+}
+```

+ 28 - 0
apps/docs/src/en/api/components/workflow-node-renderer.mdx

@@ -0,0 +1,28 @@
+# WorkflowNodeRenderer(free)
+
+Free layout node container
+
+## Usage
+
+```tsx pure
+import { useNodeRender, WorkflowNodeRenderer } from '@flowgram.ai/free-layout-editor';
+
+export const BaseNode = () => {
+  /**
+   * Provide methods related to node rendering
+   */
+  const { form } = useNodeRender()
+  /**
+   * WorkflowNodeRenderer will add node drag events and port rendering, if you want to deeply customize it, you can refer to the source code of the component:
+   * https://github.com/coze-dev/flowgram.ai/blob/main/packages/client/free-layout-editor/src/components/workflow-node-renderer.tsx
+   */
+  return (
+    <WorkflowNodeRenderer className="demo-free-node" node={props.node}>
+      {
+        // Form rendering through formMeta generation
+        form?.render()
+      }
+    </WorkflowNodeRenderer>
+  )
+};
+```

+ 8 - 0
apps/docs/src/en/api/core/_meta.json

@@ -0,0 +1,8 @@
+[
+  "flow-document",
+  "flow-node-entity",
+  "workflow-document",
+  "workflow-lines-manager",
+  "workflow-line-entity",
+  "playground"
+]

+ 184 - 0
apps/docs/src/en/api/core/flow-document.mdx

@@ -0,0 +1,184 @@
+# FlowDocument
+
+Flow document (fixed layout), stores all node data of the process
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/document/classes/FlowDocument.html)
+
+```ts pure
+import { useClientContext } from '@flowgram.ai/fixed-layout-editor'
+
+const ctx = useClientContext();
+console.log(ctx.document)
+```
+
+:::danger
+The best way to operate nodes is through [ctx.operation](/api/services/flow-operation-service.html), so that it can be bound to redo/undo
+:::
+
+
+## root
+
+Get the root node of the canvas, all nodes are attached to the root node
+
+```ts pure
+console.log(ctx.document.root);
+```
+## getAllNodes
+
+Get all node data
+
+```ts pure
+const nodes = ctx.document.getAllNodes();
+```
+
+## getNode
+
+Get node by specified id
+
+```ts pure
+ctx.document.getNode('start')
+```
+
+## getNodeRegistry
+
+Get node definition, node definition can be extended according to business
+
+```ts pure
+const startNodeRegistry = ctx.document.getNodeRegistry<FlowNodeRegistry>('start')
+```
+
+## fromJSON/toJSON
+
+Import and export data
+
+```ts pure
+const json = ctx.document.toJSON();
+ctx.document.fromJSON(json);
+```
+
+## registerFlowNodes
+
+Register node configuration items, supports inheritance
+
+```ts pure
+const node1: FlowNodeRegistry = {
+  type: 'node1',
+  meta: {}
+}
+
+const node2: FlowNodeRegistry = {
+  type: 'node2',
+  extend: 'node1' // Inherit the configuration of node1
+}
+ctx.document.registerFlowNodes(node1, node2)
+```
+
+## addNode
+
+Add node
+
+```ts pure
+ctx.document.addNode({
+  id: 'node1',
+  type: 'start',
+  meta: {},
+  data: {},
+  parent: ctx.document.root // Can specify a parent node
+});
+
+```
+
+## addFromNode
+
+Add to the node after the specified node
+
+```ts pure
+ctx.document.addFromNode(
+ ctx.document.getNode('start'),
+ { id: 'node1', type: 'custom', data: {} }
+);
+
+```
+
+## addBlock
+
+Add a branch node to the specified node
+
+```ts pure
+
+ctx.document.addBlock(ctx.document.getNode('condition'), { id: 'if_1', type: 'block', data: {} })
+```
+
+## removeNode
+
+Delete node
+
+```ts pure
+ctx.document.removeNode('node1');
+```
+
+## onNodeCreate/onNodeUpdate/onNodeDispose
+
+Node creation/update/destruction event, returns the event's disposal function
+
+```tsx pure
+
+useEffect(() => {
+  const toDispose1 = ctx.document.onNodeCreate((node) => {
+    console.log('onNodeCreate', node);
+  });
+  const toDispose2 = ctx.document.onNodeUpdate((node) => {
+    console.log('onNodeUpdate', node);
+  });
+  const toDispose3 = ctx.document.onNodeDispose((node) => {
+    console.log('onNodeDispose', node);
+  });
+  return () => {
+    toDispose1.dispose()
+    toDispose2.dispose()
+    toDispose3.dispose()
+  }
+}, []);
+```
+## traverse
+
+Traverse all child nodes from the specified node, default root node
+
+```ts pure
+/**
+ *
+ * traverse all nodes, O(n)
+ *   R
+ *   |
+ *   +---1
+ *   |   |
+ *   |   +---1.1
+ *   |   |
+ *   |   +---1.2
+ *   |   |
+ *   |   +---1.3
+ *   |   |    |
+ *   |   |    +---1.3.1
+ *   |   |    |
+ *   |   |    +---1.3.2
+ *   |   |
+ *   |   +---1.4
+ *   |
+ *   +---2
+ *       |
+ *       +---2.1
+ *
+ *  sort: [1, 1.1, 1.2, 1.3, 1.3.1, 1.3.2, 1.4, 2, 2.1]
+ */
+ctx.document.traverse((node, depth, index) => {
+  console.log(node.id);
+}, ctx.document.root);
+```
+
+## toString
+
+Return a string snapshot of the node structure
+
+```ts pure
+console.log(ctx.document.toString())
+```

+ 130 - 0
apps/docs/src/en/api/core/flow-node-entity.mdx

@@ -0,0 +1,130 @@
+# FlowNodeEntity/WorkflowNodeEntity
+
+Node entity, `WorkflowNodeEntity` is the alias for the node used for free layout nodes, the node entity uses the [ECS](/flowgram.ai/guide/concepts/ECS.html) architecture, is `Entity`
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/document/classes/FlowNodeEntity-1.html)
+
+## Properties
+
+- id: `string` Node id
+- flowNodeType: `string` | `number` Node type
+- version `number` Node version, can be used to determine if the node state has been updated
+
+## Accessors
+
+- document: `FlowDocument | WorkflowDocument` Document link
+- bounds: `Rectangle` Get the node's x, y, width, height, equivalent to `transform.bounds`
+- blocks: `FlowNodeEntity[]` Get child nodes, including collapsed child nodes, equivalent to `collapsedChildren`
+- collapsedChildren: `FlowNodeEntity[]` Get child nodes, including collapsed child nodes
+- allCollapsedChildren: `FlowNodeEntity[]` Get all child nodes, including all collapsed child nodes
+- children: `FlowNodeEntity[]` Get child nodes, not including collapsed child nodes
+- pre: `FlowNodeEntity | undefined` Get the previous node
+- next: `FlowNodeEntity | undefined` Get the next node
+- parent: `FlowNodeEntity | undefined` Get the parent node
+- originParent: `FlowNodeEntity | undefined` Get the original parent node, this is used to find the entire virtual branch for the first node of the fixed layout branch (orderIcon)
+- allChildren: `FlowNodeEntity[]` Get all child nodes, not including collapsed child nodes
+- transform: [FlowNodeTransformData](https://coze-dev.github.io/flowgram.ai/auto-docs/document/classes/FlowNodeTransformData.html) Get the node's transform matrix data
+- renderData: [FlowNodeRenderData](https://coze-dev.github.io/flowgram.ai/auto-docs/document/classes/FlowNodeRenderData.html) Get the node's render data, including render status
+
+
+## Methods
+
+### getExtInfo
+
+Get the node's extended information, can be updated through `updateExtInfo`
+
+```
+node.getExtInfo<{ test: string }>()
+```
+
+### updateExtInfo
+
+Update extended data, update will not be recorded in `redo/undo`, if you need to record, please implement the [history](/flowgram.ai/guide/advanced/history.html) service
+
+```
+node.updateExtInfo<{ test: string }>({
+  test: 'test'
+})
+```
+
+### getNodeRegistry
+
+Get the node registry, equivalent to `ctx.document.getNodeRegistry(node.flowNodeType)`
+
+```ts pure
+const nodeRegistry = node.getNodeRegistry<FlowNodeRegistry>()
+```
+
+### getData
+
+Equivalent to getting the Component of Entity in the [ECS](/flowgram.ai/guide/concepts/ECS.html) architecture, currently built-in two core Components
+
+```ts pure
+node.getData(FlowNodeTransformData) // transform matrix data, including the node's x, y, width, height, etc.
+node.getData(FlowNodeRenderData) // node render data, including render status
+
+```
+
+### addData
+
+Equivalent to adding the Component of Entity in the [ECS](/flowgram.ai/guide/concepts/ECS.html) architecture
+
+```ts pure
+
+// Custom EntityData
+class CustomEntityData extends EntityData<{ key0: string }> {
+  static type = 'CustomEntityData';
+  getDefaultData() {
+    return {
+      key0: 'test'
+    }
+  }
+}
+
+// Add Entity Component
+node.addData(CustomEntityData)
+
+
+// Update Entity Component data
+node.getData(CustomEntityData).update({ key0: 'new value' })
+
+```
+
+### getService
+
+Node access [IOC](/flowgram.ai/guide/concepts/IOC.html) service
+
+```ts pure
+node.getService(SelectionService)
+```
+
+### dispose
+
+Node destruction from canvas
+
+### onDispose
+
+Node destruction event
+
+```ts pure
+useEffect(() => {
+  const toDispose = node.onDispose(() => {
+    console.log('Dispose node')
+  })
+  return () => toDispose.dispose()
+}, [node])
+```
+
+### toJSON
+
+Export node data
+
+:::note Node data basic structure:
+
+- id: `string` Node unique identifier, must be unique
+- meta: `object` Node ui configuration information, such as `position` information for free layout
+- type: `string | number` Node type, will correspond to `type` in `nodeRegistries`
+- data: `object` Node form data, business can customize
+- blocks: `array` Node branches, using `block` is closer to `Gramming`
+
+:::

+ 99 - 0
apps/docs/src/en/api/core/playground.mdx

@@ -0,0 +1,99 @@
+# Playground
+
+Canvas instance
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/core/classes/Playground.html)
+
+```ts pure
+const ctx = useClientContext()
+
+console.log(ctx.playground)
+
+```
+## config
+
+Canvas configuration, provides zoom, scroll, etc.
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/core/classes/PlaygroundConfigEntity.html)
+
+### Properties
+- zoom `number` Current zoom ratio
+- scrollData `{ scrollX: number, scrollY: number }` Current scroll position
+- readonlyOrDisabled `boolean` Whether the canvas is readonly or disabled
+- readonly
+- disabled
+
+
+### fitView
+
+Node fit canvas window, need to pass in the node's bounds
+
+```ts pure
+/**
+ * Fit size
+ * @param bounds {Rectangle} Target size
+ * @param easing {number} Whether to start animation, default is true
+ * @param padding {number} Boundary padding
+ */
+ctx.playground.config.fitView(ctx.document.root.bounds, true, 10)
+```
+
+### scrollToView
+
+Specify the node position and scroll to the canvas visible area, if the position is already in the visible area, it will not scroll unless `scrollToCenter` is forced to scroll
+
+```ts pure
+
+/**
+ * Detailed parameter description
+ * @param opts {PlaygroundConfigRevealOpts}
+**/
+interface PlaygroundConfigRevealOpts {
+  entities?: Entity[]
+  position?: PositionSchema // Scroll to the specified position and center
+  bounds?: Rectangle // Scroll bounds
+  scrollDelta?: PositionSchema
+  zoom?: number // Need to scale the ratio
+  easing?: boolean // Whether to start animation, default is true
+  easingDuration?: number // Default 500 ms
+  scrollToCenter?: boolean // Whether to force scroll to center
+}
+
+ctx.playground.config.scrollToView({
+  bounds: ctx.document.getNode('start').bounds,
+})
+```
+
+### zoomin
+
+Zoom In
+
+### zoomout
+
+Zoom Out
+
+### getPoseFromMouseEvent
+
+Convert browser mouse position to canvas coordinate system
+
+```ts pure
+
+const pos: { x: number, y: number } = ctx.playground.config.getPoseFromMouseEvent(domMouseEvent)
+
+```
+
+### scroll
+
+Scroll canvas, need to pass in the scroll position, and whether to smooth scroll, scroll time
+
+```ts pure
+ctx.playground.config.scroll({ scrollX: 100, scrollY: 100 }, true, 300)
+```
+
+### getViewport
+
+Get the current canvas viewport size
+
+```ts pure
+const viewport = ctx.playground.config.getViewport()
+```

+ 86 - 0
apps/docs/src/en/api/core/workflow-document.mdx

@@ -0,0 +1,86 @@
+# WorkflowDocument (free)
+
+Free layout document data, inherited from [FlowDocument](/flowgram.ai/api/core/flow-document.html)
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/free-layout-core/classes/WorkflowDocument.html)
+
+```ts pure
+import { useClientContext } from '@flowgram.ai/free-layout-editor'
+
+const ctx = useClientContext();
+console.log(ctx.document)
+```
+
+:::tip
+Due to historical reasons, all names with the `Workflow` prefix represent free layout
+:::
+
+## linesManager
+
+Free layout line management, see [WorkflowLinesManager](/api/core/workflow-lines-manager.html)
+
+## createWorkflowNodeByType
+
+Create a free layout node by node type
+
+```ts pure
+const node = ctx.document.createWorkflowNodeByType(
+ 'custom',
+  { x: 100, y: 100 },
+  {
+    id: 'xxxx',
+    data: {}
+  }
+)
+```
+
+## onContentChange
+
+Listen to the free layout canvas data change
+
+```ts pure
+
+export enum WorkflowContentChangeType {
+  /**
+   * Add node
+   */
+  ADD_NODE = 'ADD_NODE',
+  /**
+   * Delete node
+   */
+  DELETE_NODE = 'DELETE_NODE',
+  /**
+   * Move node
+   */
+  MOVE_NODE = 'MOVE_NODE',
+  /**
+   * Node data update (form engine data or extInfo data)
+   */
+  NODE_DATA_CHANGE = 'NODE_DATA_CHANGE',
+  /**
+   * Add line
+   */
+  ADD_LINE = 'ADD_LINE',
+  /**
+   * Delete line
+   */
+  DELETE_LINE = 'DELETE_LINE',
+  /**
+   * Node meta information change
+   */
+  META_CHANGE = 'META_CHANGE',
+}
+
+export interface WorkflowContentChangeEvent {
+  type: WorkflowContentChangeType;
+  /**
+   * The json data of the currently triggered element, toJSON needs to be triggered actively
+   */
+  toJSON: () => any;
+  /*
+   * The entity of the currently triggered event
+   */
+  entity: WorkflowNodeEntity | WorkflowLineEntity;
+}
+
+``

+ 6 - 0
apps/docs/src/en/api/core/workflow-line-entity.mdx

@@ -0,0 +1,6 @@
+# WorkflowLineEntity (free)
+
+Free layout line entity
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/free-layout-core/classes/WorkflowLineEntity.html)
+

+ 29 - 0
apps/docs/src/en/api/core/workflow-lines-manager.mdx

@@ -0,0 +1,29 @@
+# WorkflowLinesManager (free)
+
+Free layout line management, currently attached to the free layout document
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/free-layout-core/classes/WorkflowLinesManager.html)
+
+```
+import { useClientContext } from '@flowgram.ai/free-layout-editor'
+
+const ctx = useClientContext();
+console.log(ctx.document.linesManager)
+```
+
+## getAllLines
+
+Get all line entities
+
+```ts pure
+const allLines = ctx.document.linesManager.getAllLines()
+
+```
+
+## toJSON
+
+Export line data
+
+```ts pure
+const json = ctx.document.linesManager.toJSON()
+```

+ 21 - 0
apps/docs/src/en/api/hooks/use-client-context.mdx

@@ -0,0 +1,21 @@
+# useClientContext
+
+Provides access to the canvas context within React. Currently, there are some differences between fixed layout and free layout.
+
+## Fixed Layout
+
+- Return: [FixedLayoutPluginContext](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-layout-editor/interfaces/FixedLayoutPluginContext.html)
+
+```ts pure
+import { useClientContext } from '@flowgram.ai/fixed-layout-editor'
+const ctx = useClientContext()
+```
+
+## Free Layout
+
+- Return: [FreeLayoutPluginContext](https://coze-dev.github.io/flowgram.ai/auto-docs/free-layout-editor/interfaces/FreeLayoutPluginContext.html)
+
+```ts pure
+import { useClientContext } from '@flowgram.ai/free-layout-editor'
+const ctx = useClientContext()
+```

+ 67 - 0
apps/docs/src/en/api/hooks/use-node-render.mdx

@@ -0,0 +1,67 @@
+# useNodeRender
+
+Provides methods related to node rendering, and the form returned is equivalent to [getNodeForm](/api/utils/get-node-form.html)
+
+## Fixed Layout
+
+- Return: [NodeRenderReturnType](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-layout-editor/interfaces/NodeRenderReturnType.html)
+
+```tsx pure
+
+import { FlowNodeEntity, useNodeRender } from '@flowgram.ai/fixed-layout-editor';
+
+export const BaseNode = ({ node }: { node: FlowNodeEntity }) => {
+  /**
+   * Provides methods related to node rendering
+   */
+  const nodeRender = useNodeRender();
+  /**
+   * Only available when the node engine is enabled
+   */
+  const form = nodeRender.form;
+
+  return (
+    <div
+      className="demo-fixed-node"
+      /*
+       * Adding onMouseEnter to the fixed layout node is mainly to monitor the hover highlight of the branch line
+       **/
+      onMouseEnter={nodeRender.onMouseEnter}
+      onMouseLeave={nodeRender.onMouseLeave}
+      onMouseDown={e => {
+        // trigger drag node
+        nodeRender.startDrag(e);
+        e.stopPropagation();
+      }}
+      style={{
+        /**
+         * Used to precisely control the style of the branch node
+         * isBlockIcon: The header node of the entire condition branch
+         * isBlockOrderIcon: The first node of the branch
+         */
+        ...(nodeRender.isBlockOrderIcon || nodeRender.isBlockIcon ? { width: 260 } : {}),
+      }}
+    >
+      {form?.render()}
+    </div>
+  );
+};
+
+```
+
+## Free Layout
+
+- Return: [NodeRenderReturnType](https://coze-dev.github.io/flowgram.ai/auto-docs/free-layout-core/interfaces/NodeRenderReturnType.html)
+
+```tsx pure
+import { WorkflowNodeRenderer, useNodeRender } from '@flowgram.ai/free-layout-editor';
+export const BaseNode = () => {
+  const { form, node } = useNodeRender()
+  return (
+    <WorkflowNodeRenderer className="demo-free-node" node={node}>
+      {form?.render()}
+    </WorkflowNodeRenderer>
+  )
+}
+
+```

+ 70 - 0
apps/docs/src/en/api/hooks/use-playground-tools.mdx

@@ -0,0 +1,70 @@
+# usePlaygroundTools
+
+Canvas tool methods
+
+## Fixed Layout
+
+- Return: [PlaygroundTools](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-layout-editor/interfaces/PlaygroundTools.html)
+```tsx pure
+import { useEffect, useState } from 'react'
+import { usePlaygroundTools, useClientContext } from '@flowgram.ai/fixed-layout-editor';
+
+export function Tools() {
+  const { history } = useClientContext();
+  const tools = usePlaygroundTools();
+  const [canUndo, setCanUndo] = useState(false);
+  const [canRedo, setCanRedo] = useState(false);
+
+  useEffect(() => {
+    const disposable = history.undoRedoService.onChange(() => {
+      setCanUndo(history.canUndo());
+      setCanRedo(history.canRedo());
+    });
+    return () => disposable.dispose();
+  }, [history]);
+
+  return <div style={{ position: 'absolute', zIndex: 10, bottom: 16, left: 16, display: 'flex', gap: 8 }}>
+    <button onClick={() => tools.zoomin()}>ZoomIn</button>
+    <button onClick={() => tools.zoomout()}>ZoomOut</button>
+    <button onClick={() => tools.fitView()}>Fitview</button>
+    <button onClick={() => tools.changeLayout()}>ChangeLayout</button>
+    <button onClick={() => history.undo()} disabled={!canUndo}>Undo</button>
+    <button onClick={() => history.redo()} disabled={!canRedo}>Redo</button>
+    <span>{Math.floor(tools.zoom * 100)}%</span>
+  </div>
+}
+```
+
+
+## Free Layout
+
+- Return: [PlaygroundTools](https://coze-dev.github.io/flowgram.ai/auto-docs/free-layout-editor/interfaces/PlaygroundTools.html)
+
+```tsx pure
+import { usePlaygroundTools, useClientContext } from '@flowgram.ai/free-layout-editor';
+
+export function Tools() {
+  const { history } = useClientContext();
+  const tools = usePlaygroundTools();
+  const [canUndo, setCanUndo] = useState(false);
+  const [canRedo, setCanRedo] = useState(false);
+
+  useEffect(() => {
+    const disposable = history.undoRedoService.onChange(() => {
+      setCanUndo(history.canUndo());
+      setCanRedo(history.canRedo());
+    });
+    return () => disposable.dispose();
+  }, [history]);
+
+  return <div style={{ position: 'absolute', zIndex: 10, bottom: 16, left: 226, display: 'flex', gap: 8 }}>
+    <button onClick={() => tools.zoomin()}>ZoomIn</button>
+    <button onClick={() => tools.zoomout()}>ZoomOut</button>
+    <button onClick={() => tools.fitView()}>Fitview</button>
+    <button onClick={() => tools.autoLayout()}>AutoLayout</button>
+    <button onClick={() => history.undo()} disabled={!canUndo}>Undo</button>
+    <button onClick={() => history.redo()} disabled={!canRedo}>Redo</button>
+    <span>{Math.floor(tools.zoom * 100)}%</span>
+  </div>
+}
+```

+ 29 - 0
apps/docs/src/en/api/hooks/use-refresh.mdx

@@ -0,0 +1,29 @@
+# useRefresh
+
+## Source Code
+
+```ts
+import { useCallback, useState } from 'react';
+
+export function useRefresh(defaultValue?: any): (v?: any) => void {
+  const [, update] = useState<any>(defaultValue);
+  return useCallback((v?: any) => update(v !== undefined ? v : {}), []);
+}
+```
+
+## Usage
+
+```tsx pure
+import { useRefresh } from '@flowgram.ai/fixed-layout-editor';
+
+function Demo() {
+  const refresh = useRefresh();
+  return (
+    <div>
+      <button onClick={() => refresh()}>Refresh</button>
+    </div>
+  )
+}
+
+```
+

+ 57 - 0
apps/docs/src/en/api/hooks/use-service.mdx

@@ -0,0 +1,57 @@
+# useService
+
+Get all singleton modules of the underlying [IOC](/flowgram.ai/guide/concepts/IOC.html)
+
+```ts pure
+
+const playground = useService<Playground>(Playground)
+const flowDocument = useService<FlowDocument>(FlowDocument)
+const historyService = useService<HistoryService>(HistoryService)
+
+// Equivalent to
+const playground1 = useClientContext().playground
+
+// Equivalent to
+const playground3 = useClientContext().get<Playground>(Playground)
+
+```
+
+
+
+## Custom Service
+
+```tsx pure
+/**
+ *  inversify: https://github.com/inversify/InversifyJS
+ */
+import { injectable } from 'inversify'
+
+@injectable()
+class MyService {
+  // ...
+}
+
+import { useMemo } from 'react';
+import { type FixedLayoutProps } from '@flowgram.ai/fixed-layout-editor';
+
+function BaseNode() {
+  const mySerivce = useService<MyService>(MyService)
+}
+
+export function useEditorProps(
+): FixedLayoutProps {
+  return useMemo<FixedLayoutProps>(
+    () => ({
+      // ....other props
+      onBind: ({ bind }) => {
+        bind(MyService).toSelf().inSingletonScope()
+      },
+      materials: {
+        renderDefaultNode: BaseNode
+      }
+    }),
+    [],
+  );
+}
+
+```

+ 1 - 1
apps/docs/src/en/api/plugins.mdx

@@ -2,4 +2,4 @@
 overview: true
 overviewHeaders: [2]
 ---
-这里是官网 api 配置,demo 用。
+This is the official website api configuration, demo use.

+ 5 - 0
apps/docs/src/en/api/services/clipboard-service.mdx

@@ -0,0 +1,5 @@
+# ClipboardService
+
+Clipboard Service
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/core/interfaces/ClipboardService.html)

+ 11 - 0
apps/docs/src/en/api/services/command-service.mdx

@@ -0,0 +1,11 @@
+# CommandService
+
+Command Service, needs to be used with [Shortcuts](/flowgram.ai/guide/advanced/interactive/shortcuts.html)
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/command/interfaces/CommandService.html)
+
+
+```Usage
+
+ctx.get(CommandService).execCommand('selectAll')
+```

+ 118 - 0
apps/docs/src/en/api/services/flow-operation-service.mdx

@@ -0,0 +1,118 @@
+# FlowOperationService
+
+Node operation service, currently used for fixed layout, free layout can currently be operated directly through WorkflowDocument, and will be abstracted out as operation in the future
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-layout-editor/interfaces/FlowOperationService.html)
+
+```typescript pure
+const operationService = useService<FlowOperationService>(FlowOperationService)
+operationService.addNode({ id: 'xxx', type: 'custom', data: {} })
+
+// or
+const ctx = useClientContext();
+ctx.operation.addNode({ id: 'xxx', type: 'custom', data: {} })
+
+
+```
+
+## Interface
+
+```typescript pure
+
+export interface FlowOperationBaseService extends Disposable {
+  /**
+   * Execute operation
+   * @param operation Serializable operation
+   * @returns Operation return
+   */
+  apply(operation: FlowOperation): any;
+
+  /**
+   * Add node, if the node already exists, it will not be created repeatedly
+   * @param nodeJSON Node data
+   * @param config Configuration
+   * @returns Successfully added node
+   */
+  addNode(nodeJSON: FlowNodeJSON, config?: AddNodeConfig): FlowNodeEntity;
+
+  /**
+   * Add node based on a starting node
+   * @param fromNode Starting node
+   * @param nodeJSON Added node JSON
+   */
+  addFromNode(fromNode: FlowNodeEntityOrId, nodeJSON: FlowNodeJSON): FlowNodeEntity;
+
+  /**
+   * Delete node
+   * @param node Node
+   * @returns
+   */
+  deleteNode(node: FlowNodeEntityOrId): void;
+
+  /**
+   * Batch delete nodes
+   * @param nodes
+   */
+  deleteNodes(nodes: FlowNodeEntityOrId[]): void;
+
+  /**
+   * Add block (branch)
+   * @param target Target
+   * @param blockJSON Block data
+   * @param config Configuration
+   * @returns
+   */
+  addBlock(
+    target: FlowNodeEntityOrId,
+    blockJSON: FlowNodeJSON,
+    config?: AddBlockConfig,
+  ): FlowNodeEntity;
+
+  /**
+   * Move node
+   * @param node The node to be moved
+   * @param config Move node configuration
+   */
+  moveNode(node: FlowNodeEntityOrId, config?: MoveNodeConfig): void;
+
+  /**
+   * Drag node
+   * @param param0
+   * @returns
+   */
+  dragNodes({ dropNode, nodes }: { dropNode: FlowNodeEntity; nodes: FlowNodeEntity[] }): void;
+
+  /**
+   * Add node callback
+   */
+  onNodeAdd: Event<OnNodeAddEvent>;
+}
+
+export interface FlowOperationService extends FlowOperationBaseService {
+  /**
+   * Create group
+   * @param nodes Node list
+   */
+  createGroup(nodes: FlowNodeEntity[]): FlowNodeEntity | undefined;
+  /**
+   * Ungroup
+   * @param groupNode
+   */
+  ungroup(groupNode: FlowNodeEntity): void;
+  /**
+   * Start transaction
+   */
+  startTransaction(): void;
+  /**
+   * End transaction
+   */
+  endTransaction(): void;
+  /**
+   * Modify form data
+   * @param node Node
+   * @param path Property path
+   * @param value Value
+   */
+  setFormValue(node: FlowNodeEntityOrId, path: string, value: unknown): void;
+}
+```

+ 49 - 0
apps/docs/src/en/api/services/history-service.mdx

@@ -0,0 +1,49 @@
+## HistoryService
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-history-plugin/classes/HistoryService.html)
+
+## Redo/Undo
+
+```tsx pure
+import { useEffect, useState } from 'react'
+import { useClientContext } from '@flowgram.ai/fixed-layout-editor';
+
+export function Tools() {
+  const { history } = useClientContext();
+  const [canUndo, setCanUndo] = useState(false);
+  const [canRedo, setCanRedo] = useState(false);
+
+  useEffect(() => {
+    const disposable = history.undoRedoService.onChange(() => {
+      setCanUndo(history.canUndo());
+      setCanRedo(history.canRedo());
+    });
+    return () => disposable.dispose();
+  }, [history]);
+
+  return <div>
+    <button onClick={() => history.undo()} disabled={!canUndo}>Undo</button>
+    <button onClick={() => history.redo()} disabled={!canRedo}>Redo</button>
+  </div>
+}
+```
+
+## Render History
+
+```tsx pure
+import { useEffect } from 'react'
+import { useRefresh, useClientContext } from '@flowgram.ai/fixed-layout-editor'
+
+function HistoryListRender() {
+  const refresh = useRefresh()
+  const ctx = useClientContext()
+  useEffect(() => {
+    ctx.history.onApply(() => refresh())
+  }, [ctx])
+  return (
+    <div>
+      {ctx.history.historyManager.historyStack.items.map((record) => <HistoryOperations key={record.id} operations={record.operations} />)}
+    </div>
+  )
+}
+```

+ 14 - 0
apps/docs/src/en/api/services/selection-service.mdx

@@ -0,0 +1,14 @@
+# SelectionService
+
+Used to control selected nodes
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/core/classes/SelectionService.html)
+
+## Usage
+```tsx pure
+// Listen Selection Change
+ctx.selection.onSelectionChanged((nodes) => {
+})
+// Select All Nodes
+ctx.selection.selection = ctx.document.getAllNodes()
+```

+ 33 - 0
apps/docs/src/en/api/utils/disposable-collection.mdx

@@ -0,0 +1,33 @@
+# DisposableCollection
+
+## Usage
+
+
+```ts pure
+
+import { DisposableCollection, Disposable } from '@flowgram.ai/utils'
+const disposable1: Disposable = {
+  dispose() {
+    console.log(1)
+  },
+};
+const disposable2: Disposable = {
+  dispose() {
+    console.log(2)
+  },
+};
+const dc = new DisposableCollection();
+dc.onDispose(() => {
+  console.log('end')
+});
+
+dc.pushAll([disposable1, disposable2]);
+dc.dispose(); // Log: 1, 2, dispose end
+
+```
+
+## Source Code
+
+https://github.com/coze-dev/flowgram.ai/blob/main/packages/common/utils/src/disposable.ts
+
+

+ 21 - 0
apps/docs/src/en/api/utils/disposable.mdx

@@ -0,0 +1,21 @@
+# Disposable
+
+## Interface
+
+```ts
+/**
+ * An object that performs a cleanup operation when `.dispose()` is called.
+ *
+ * Some examples of how disposables are used:
+ *
+ * - An event listener that removes itself when `.dispose()` is called.
+ * - The return value from registering a provider. When `.dispose()` is called, the provider is unregistered.
+ */
+export interface Disposable {
+  dispose(): void;
+}
+```
+
+## Source Code
+
+https://github.com/coze-dev/flowgram.ai/blob/main/packages/common/utils/src/disposable.ts

+ 42 - 0
apps/docs/src/en/api/utils/emitter.mdx

@@ -0,0 +1,42 @@
+# Emitter
+
+Event module
+
+
+## Usage
+
+```tsx pure
+import { Emitter } from '@flowgram.ai/utils'
+
+class Doc {
+  private _content = ''
+  private _onContentChangeEmitter = new Emitter<string>()
+  readonly onContentChange = this._onContentChangeEmitter.event
+  setContent(content: string) {
+    this._content = content
+    this._onContentChangeEmitter.fire(content)
+  }
+  get content() {
+    return this._content
+  }
+}
+
+function App() {
+  const doc1 = useMemo(() => new Doc(), [])
+  const [content, updateContent] = useState(doc1.content)
+  useEffect(() => {
+    const toDispose = doc1.onContentChange((content) => {
+      updateContent(content)
+    })
+    return () => toDispose.dispose()
+  }, [doc1])
+  return <div>{content}</div>
+}
+
+
+```
+
+## Source Code
+
+https://github.com/coze-dev/flowgram.ai/blob/main/packages/common/utils/src/event.ts
+

+ 73 - 0
apps/docs/src/en/api/utils/get-node-form.mdx

@@ -0,0 +1,73 @@
+# getNodeForm
+
+Get the form capabilities of the node, needs to be enabled node engine
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/editor/functions/getNodeForm.html)
+
+
+## Usage
+
+```tsx pure
+
+function BaseNode({ node }) {
+  const form = getNodeForm(node);
+  console.log(form.getValueIn('title'))
+  return <div>{form?.render()}</div>
+}
+```
+
+## Return Inteface
+
+```ts pure
+
+export interface NodeFormProps<TValues> {
+  /**
+   * The initialValues of the form.
+   */
+  initialValues: TValues;
+  /**
+   * Form values. Returns a deep copy of the data in the store.
+   */
+  values: TValues;
+  /**
+   * Form state
+   */
+  state: FormState;
+  /**
+   * Get value in certain path
+   * @param name path
+   */
+  getValueIn<TValue = FieldValue>(name: FieldName): TValue;
+
+  /**
+   * Set value in certain path.
+   * It will trigger the re-rendering of the Field Component if a Field is related to this path
+   * @param name path
+   */
+  setValueIn<TValue>(name: FieldName, value: TValue): void;
+  /**
+   * Render form
+   */
+  render: () => React.ReactNode;
+  /**
+   * Form value change event
+   */
+  onFormValuesChange: Event<OnFormValuesChangePayload>;
+  /**
+   * Trigger form validate
+   */
+  validate: () => Promise<boolean>;
+  /**
+   * Form validate event
+   */
+  onValidate: Event<FormState>;
+  /**
+   * Form field value change event
+   */
+  onFormValueChangeIn<TValue = FieldValue, TFormValue = FieldValue>(
+    name: FieldName,
+    callback: (payload: onFormValueChangeInPayload<TValue, TFormValue>) => void
+  ): void;
+}
+```
+

+ 1 - 1
apps/docs/src/en/examples/_meta.json

@@ -2,7 +2,7 @@
   {
     "type": "file",
     "name": "index",
-    "label": "Examples"
+    "label": "Experience Environment"
   },
   {
     "type": "dir",

+ 11 - 11
apps/docs/src/en/examples/fixed-layout/fixed-feature-overview.mdx

@@ -3,27 +3,27 @@ outline: false
 ---
 
 
-# 最佳实践
+# Best Practices
 
 import { FixedFeatureOverview } from '../../../../components';
 
 <FixedFeatureOverview />
 
-## 安装
+## Installation
 
 ```bash
 npx @flowgram.ai/create-app@latest fixed-layout
 ```
 
-## 源码
+## Source Code
 
 https://github.com/coze-dev/flowgram.ai/tree/main/apps/demo-fixed-layout
 
-## 功能介绍
+## Feature Introduction
 
 <table className="rs-table">
   <tr>
-    <td>缩略图</td>
+    <td>Minimap</td>
     <td>
       <div className="rs-center">
         <img src="@/public/fixed-layout/minimap.gif"  />
@@ -31,7 +31,7 @@ https://github.com/coze-dev/flowgram.ai/tree/main/apps/demo-fixed-layout
     </td>
   </tr>
   <tr>
-    <td>撤销/重做</td>
+    <td>Undo/Redo</td>
     <td>
       <div className="rs-center">
         <img src="@/public/fixed-layout/redo-undo.gif"  />
@@ -39,7 +39,7 @@ https://github.com/coze-dev/flowgram.ai/tree/main/apps/demo-fixed-layout
     </td>
   </tr>
   <tr>
-    <td>复制/粘贴(支持快捷键)</td>
+    <td>Copy/Paste (Support Shortcut)</td>
     <td>
       <div className="rs-center">
         <img src="@/public/fixed-layout/copypaste.gif"  />
@@ -49,7 +49,7 @@ https://github.com/coze-dev/flowgram.ai/tree/main/apps/demo-fixed-layout
   <tr>
     <td>
       <div>
-        <div>框选 + 拖拽</div>
+        <div>Box Selection + Drag</div>
       </div>
     </td>
     <td>
@@ -62,7 +62,7 @@ https://github.com/coze-dev/flowgram.ai/tree/main/apps/demo-fixed-layout
   </tr>
   <tr>
     <td>
-      <div>水平/垂直布局切换</div>
+      <div>Horizontal/Vertical Layout Switch</div>
     </td>
     <td>
       <div className="rs-center">
@@ -72,7 +72,7 @@ https://github.com/coze-dev/flowgram.ai/tree/main/apps/demo-fixed-layout
   </tr>
   <tr>
     <td>
-      <div>分支折叠</div>
+      <div>Branch Fold</div>
     </td>
     <td>
       <div className="rs-center">
@@ -82,7 +82,7 @@ https://github.com/coze-dev/flowgram.ai/tree/main/apps/demo-fixed-layout
   </tr>
   <tr>
     <td>
-      <div>分组</div>
+      <div>Group</div>
     </td>
     <td>
       <div className="rs-center">

+ 3 - 3
apps/docs/src/en/examples/fixed-layout/fixed-layout-simple.mdx

@@ -3,18 +3,18 @@ outline: false
 ---
 
 
-# 基础用法
+# Basic Usage
 
 import { FixedLayoutSimplePreview } from '../../../../components';
 
 <FixedLayoutSimplePreview />
 
-## 安装
+## Installation
 
 ```bash
 npx @flowgram.ai/create-app@latest fixed-layout-simple
 ```
 
-## 源码
+## Source Code
 
 https://github.com/coze-dev/flowgram.ai/tree/main/apps/demo-fixed-layout-simple

+ 6 - 6
apps/docs/src/en/examples/free-layout/free-feature-overview.mdx

@@ -3,29 +3,29 @@ outline: false
 ---
 
 
-# 最佳实践
+# Best Practices
 
 import { FreeFeatureOverview } from '../../../../components';
 
 <FreeFeatureOverview />
 
-## 安装
+## Installation
 
 ```bash
 npx @flowgram.ai/create-app@latest free-layout
 ```
 
-## 源码
+## Source Code
 
 https://github.com/coze-dev/flowgram.ai/tree/main/apps/demo-free-layout
 
 
-## 功能介绍
+## Feature Introduction
 
 <table className="rs-table">
   <tr>
     <td>
-      自动整理
+      Auto Layout
     </td>
     <td>
       <div className="rs-center">
@@ -35,7 +35,7 @@ https://github.com/coze-dev/flowgram.ai/tree/main/apps/demo-free-layout
   </tr>
   <tr>
     <td>
-      吸附对齐 + 参考线
+      Snap + Reference Line
     </td>
     <td>
       <div className="rs-center">

+ 3 - 3
apps/docs/src/en/examples/free-layout/free-layout-simple.mdx

@@ -3,18 +3,18 @@ outline: false
 ---
 
 
-# 基础用法
+# Basic Usage
 
 import { FreeLayoutSimplePreview } from '../../../../components';
 
 <FreeLayoutSimplePreview />
 
-## 安装
+## Installation
 
 ```bash
 npx @flowgram.ai/create-app@latest free-layout-simple
 ```
 
-## 源码
+## Source Code
 
 https://github.com/coze-dev/flowgram.ai/tree/main/apps/demo-free-layout-simple

+ 1 - 1
apps/docs/src/en/guide/_meta.json

@@ -8,7 +8,7 @@
   {
     "type": "dir",
     "name": "advanced",
-    "label": "Advanced Guide"
+    "label": "Advanced"
   },
   {
     "type": "dir",

+ 0 - 10
apps/docs/src/en/guide/advanced/_meta.json

@@ -1,14 +1,4 @@
 [
-  {
-    "type": "dir",
-    "name": "fixed-layout",
-    "label": "Fixed Layout"
-  },
-  {
-    "type": "dir",
-    "name": "free-layout",
-    "label": "Free Layout"
-  },
   "form",
   "variable",
   "history",

+ 70 - 65
apps/docs/src/en/guide/advanced/form.mdx

@@ -1,25 +1,26 @@
-# Using Forms
+# Form
 
-## Configuration
+## Config
 
 ### Enable Node Engine
 
-The node engine needs to be enabled to use forms
+Node engine is required to use form
 
 ```tsx pure title="use-editor-props.ts"
+
 // EditorProps
 {
   nodeEngine: {
     /**
-     * Node engine must be enabled to use
+     * Node engine is required to use form
      */
     enable: true
     /**
-     * Component for rendering node internal errors
+     * The component to render when the node has an error
      */
     nodeErrorRender?: NodeErrorRender;
     /**
-     * Component for rendering when node has no content
+     * The component to render when the node has no content
      */
     nodePlaceholderRender?: NodePlaceholderRender;
   }
@@ -35,7 +36,7 @@ export const nodeRegistries: FlowNodeRegistry[] = [
   {
     type: 'start',
     /**
-     * Configure node form validation and rendering
+     * Configure the validation and rendering of the node form
      */
     formMeta: {
       validateTrigger: ValidateTrigger.onChange,
@@ -63,32 +64,35 @@ export const nodeRegistries: FlowNodeRegistry[] = [
     },
   }
 ]
+
 ```
 
-### Add Form to Node Rendering
+### Add form to node rendering
 
 ```tsx pure title="base-node.tsx"
+
 export const BaseNode = () => {
   /**
-   * Provides node rendering related methods
+   * Provide methods related to node rendering
    */
   const { form } = useNodeRender()
   return (
     <div className="demo-free-node" className={form?.state.invalid && "error"}>
       {
-        // Form rendering is generated through formMeta
+        // The form is rendered through formMeta
         form?.render()
       }
     </div>
   )
 };
+
 ```
 
 ## Field
 
-The Field rendering part supports three approaches as follows:
+The rendering part of Field, supports three writing methods, as follows:
 
-:::note `renderProps` parameters
+:::note `renderProps` parameter
 
 - field
 - fieldState
@@ -99,30 +103,31 @@ The Field rendering part supports three approaches as follows:
 ```tsx pure
 const render = () => (
   <div>
-    <Label> 1. Via children </Label>
-    // This approach is suitable for simple scenarios, Field will directly inject properties like value, onChange into the first level children component
+    <Label> 1. Through children </Label>
+    // This method is suitable for simple scenarios, Field will inject value onChange, etc. directly into the first layer of children components
     <Field name="c">
       <Input />
     </Field>
-    <Label> 2. Via Render Props </Label>
-    // This approach is suitable for complex scenarios, when the returned component has multiple nested levels, users can actively inject field properties into desired components
+    <Label> 2. Through Render Props  </Label>
+    // This method is suitable for complex scenarios, when the returned component has multiple layers of nesting, the user can actively inject the attributes of field into the desired component
     <Field name="a">
         {({ field, fieldState, formState }: FieldRenderProps<string>) => <div><Input {...field} /><Feedbacks errors={fieldState.errors}/></div>}
     </Field>
 
-    <Label> 3. Via render function prop</Label>
-    // This approach is similar to approach 2, but passed through props
+    <Label> 3. Through render function </Label>
+    // This method is similar to method 2, but the props are passed in
     <Field name="b" render={({ field }: FieldRenderProps<string>) => <Input {...field} />} />
   </div>
 );
 ```
 
-## FieldArray
 
-The following example demonstrates:
-1. Array syntax
-2. How to configure array item validation
-3. Display of array item errors
+## FiledArray
+
+The following example shows:
+1. The writing method of the array
+2. How to configure the validation of the array item
+3. How to display the error of the array item
 
 <div className="rs-center" >
   <img src="@/public/field-array.gif"  style={{ maxWidth: 600 }}/>
@@ -184,7 +189,7 @@ export const renderNodeWithArray = ({ form }: FormRenderProps<FormData>) => (
 export const arrayMeta: FormMeta = {
   render: renderNodeWithArray,
   validateTrigger: ValidateTrigger.onChange,
-  // Names in validation map support fuzzy matching
+  // The name in the validate map supports fuzzy matching
   validate: {
     ['arr.*']: () => 'array item error',
   },
@@ -195,7 +200,7 @@ export const arrayMeta: FormMeta = {
 
 ### Validation Configuration
 
-Validation logic is configured globally, declared through form item paths
+Validation logic is configured globally, and the validation logic is declared by the form item path
 
 <div className="rs-center" >
   <img src="@/public/form-validate.gif"  style={{ maxWidth: 600 }}/>
@@ -204,7 +209,7 @@ Validation logic is configured globally, declared through form item paths
 ```tsx pure
 export const renderValidateExample = ({ form }: FormRenderProps<FormData>) => (
   <>
-    <Label> a (maximum length is 5)</Label>
+    <Label> a (Maximum length is 5)</Label>
     <Field name="a">
       {({ field: { value, onChange }, fieldState }: FieldRenderProps<string>) => (
         <>
@@ -213,7 +218,7 @@ export const renderValidateExample = ({ form }: FormRenderProps<FormData>) => (
         </>
       )}
     </Field>
-    <Label> b (optional if a exists) </Label>
+    <Label> b (If a exists, b can be optional) </Label>
     <Field
       name="b"
       render={({ field: { value, onChange }, fieldState }: FieldRenderProps<string>) => (
@@ -228,76 +233,75 @@ export const renderValidateExample = ({ form }: FormRenderProps<FormData>) => (
 
 export const VALIDATE_EXAMPLE: FormMeta = {
   render: renderValidateExample,
-  // Configure validation timing
+  // Validation timing configuration
   validateTrigger: ValidateTrigger.onChange,
   validate: {
-    // Simply validate value
+    // Simply validate the value
     a: ({ value }) => (value.length > 5 ? 'Maximum length is 5' : undefined),
-    // Validation depends on other form item values
+    // Validate the value depends on the value of other form items
     b: ({ value, formValues }) => {
       if (formValues.a) {
         return undefined;
       } else {
-        return value ? 'undefined' : 'b is required when a exists';
+        return value ? 'undefined' : 'a exists when b is required';
       }
     },
-    // Validation depends on node or canvas information
+    // Validate the value depends on the node or canvas information
     c: ({ value, formValues, context }) => {
-      const { node, playgroundContext } = context;
-      // Logic omitted here
+      const { node playgroundContext } = context;
+      // The logic is omitted here
     },
   },
 };
 ```
-
 ### Validation Timing
 
 <table className="rs-table">
   <tr>
     <td>`ValidateTrigger.onChange`</td>
-    <td>Validate when form data changes (excluding initialization data)</td>
+    <td>Validate when the form data changes (does not include initial data)</td>
   </tr>
   <tr>
     <td>`ValidateTrigger.onBlur`</td>
-    <td>Validate when form item input control onBlur</td>
+    <td>Validate when the form item input control is onBlur</td>
   </tr>
 </table>
 
 ### Path Fuzzy Matching
 
-The paths (i.e., keys) in validation configuration support fuzzy matching, typically used in array scenarios, as shown in the following examples
+The path (key) of the validation configuration supports fuzzy matching, which is usually used in the array scenario, see the following example
 
 <div className="rs-red">
-  Note: * only represents drilling down one level
+  Note: * represents only one level of drilling down
 </div>
 
 <table className="rs-table">
   <tr>
     <td>`arr.*`</td>
-    <td>All first-level items under the `arr` field</td>
+    <td>`arr` field's all first-level sub-items</td>
   </tr>
   <tr>
     <td>`arr.x.*`</td>
-    <td>All first-level items under `arr.x`</td>
+    <td>`arr.x` all first-level sub-items</td>
   </tr>
   <tr>
     <td>`arr.*.x`</td>
-    <td>Item `x` under all first-level items of `arr`</td>
+    <td>`arr` all first-level sub-items' sub-items `x`</td>
   </tr>
 </table>
 
-## Side Effects
+## Side Effects (effect)
 
-### Effect Configuration
+### Side Effects Configuration
 
-The following example demonstrates:
+The following example shows:
 
-- How to configure effects for regular fields
-- How to configure effects for array fields in the following events:
-  - onValueChange
-  - onValueInit
-  - onArrayAppend
-  - onArrayDelete
+- How to configure the effect of a normal field
+- How to configure the effect of an array field on the following events
+- onValueChange
+- onValueInit
+- onArrayAppend
+- onArrayDelete
 
 <div className="rs-center" >
   <img src="@/public/form-effect.gif"  style={{ maxWidth: 600 }}/>
@@ -375,7 +379,7 @@ export const renderEffectExample = ({ form }: FormRenderProps<FormData>) => (
 
 export const EFFECT_V2: FormMeta = {
   render: renderEffectExample,
-  // effect configuration is a map with form item paths as keys and effect configurations as values
+  // The effect configuration is a map of the form item path to the effect configuration
   effect: {
     a: [
       createEffectOptions<Effect>(DataEvent.onValueChange, ({ value, prevValue }) => {
@@ -398,26 +402,27 @@ export const EFFECT_V2: FormMeta = {
   },
 };
 ```
-
-### Effect Events
+### Side Effects Event
 
 ```ts pure
 export enum DataEvent {
-  /* Triggered when value changes compared to initial value or previous value */
+  /* Triggered when the value is different from the initial value or the previous value */
   onValueChange = 'onValueChange',
   /**
-   * Triggered when initial value is set, trigger scenarios include:
-   * - When form has defaultValue configured, triggered during form initialization
-   * - When a form item has defaultValue configured and no initial value, defaultValue will be set and triggered
+   * Triggered when the initial value is set, the triggering scenarios are:
+   * - The form is configured with defaultValue, and the form is initialized
+   * - A form item is configured with defaultValue, and the form item is initialized without a value
    */
   onValueInit = 'onValueInit',
   /**
-   * Triggered for both value changes and initial value setting, can be considered as union of onValueChange and onValueInit
+   * Triggered when the initial value is set, the triggering scenarios are:
+   * - The form is configured with defaultValue, and the form is initialized
+   * - A form item is configured with defaultValue, and the form item is initialized without a value
    */
   onValueInitOrChange = 'onValueInitOrChange',
-  /* Not recommended, this event depends on FieldArray rendering, value events may not trigger when not rendering */
+  /* Not recommended, this event depends on FieldArray rendering, and the value event may not be triggered in the case of non-rendering */
   onArrayAppend = 'onArrayAppend',
-  /* Not recommended, this event depends on FieldArray rendering, value events may not trigger when not rendering */
+  /* Not recommended, this event depends on FieldArray rendering, and the value event may not be triggered in the case of non-rendering */
   onArrayDelete = 'onArrayDelete',
 }
 ```
@@ -425,7 +430,7 @@ export enum DataEvent {
 ### API
 
 ```ts pure
-// onValueChange and onValueInit effects follow this interface
+// The effect of onValueChange and onValueInit follows this interface
 export type Effect<TFieldValue = any, TFormValues = any> = (props: {
   value?: TFieldValue;
   prevValue?: TFieldValue;
@@ -449,9 +454,9 @@ export type ArrayDeleteEffect<TFieldValue = any, TFormValues = any> = (props: {
 }) => void;
 ```
 
-## Dependencies
+## Dynamic Dependencies
 
-Declare dependencies using deps
+Declare dependencies through deps
 
 ```tsx pure
 import * as React from 'react';
@@ -494,7 +499,7 @@ export const renderDynamicExample = ({ form }: FormRenderProps<FormData>) => (
           <></>
         )
       }
-      // Configure through deps which other form item values this form item's rendering depends on
+      // Configure the dependencies of the form item through deps
       deps={['isBatch']}
     />
   </>

+ 75 - 76
apps/docs/src/en/guide/advanced/history.mdx

@@ -1,109 +1,110 @@
 # History
 
-Undo/Redo is a plugin for FlowGram.AI, available in both @flowgram.ai/fixed-layout-editor and @flowgram.ai/free-layout-editor modes.
+Undo/Redo is a plugin of FlowGram.AI, which is provided in both @flowgram.ai/fixed-layout-editor and @flowgram.ai/free-layout-editor.
+
 
 ## 1. Quick Start
 
-### 1.1. Enable History
-Before using the Undo/Redo functionality, you need to import the editor. Here's an example using the fixed layout editor.
+### 1.1. Enable history
+Before using the Undo/Redo feature, you need to introduce the editor, using the fixed layout editor as an example.
 
-1. Add dependency in package.json
+1. Add dependencies in package.json
 ```tsx pure title="use-editor-props.tsx"
 export function useEditorProps() {
   return useMemo(
     () => ({
-      ...
       history: {
-        enable: true
+        enable: true,
+        enableChangeNode: true // Listen Node engine data change
       }
     })
   )
 }
 ```
 
-After enabling, you'll get the following capabilities:
+After enabling, you will get the following capabilities:
 
 <table className="rs-table">
   <tr>
-    <td>Overview</td>
+    <td>Introduction</td>
     <td>Description</td>
     <td>Free Layout</td>
     <td>Fixed Layout</td>
   </tr>
   <tr>
-    <td rowSpan={2}>Undo/Redo Shortcuts</td>
-    <td>Use Cmd/Ctrl + Z on canvas to trigger Undo</td>
+    <td rowSpan={2}>Undo/Redo Shortcut</td>
+    <td>Use Cmd/Ctrl + Z to trigger Undo</td>
     <td>✅</td>
     <td>✅</td>
   </tr>
   <tr>
-    <td>Use Cmd/Ctrl + Shift + Z on canvas to trigger Redo</td>
+    <td>Use Cmd/Ctrl + Shift + Z to trigger Redo</td>
     <td>✅</td>
     <td>✅</td>
   </tr>
   <tr>
-    <td rowSpan={7}>Canvas Node Operations Support Undo/Redo</td>
-    <td>Add/Delete Nodes</td>
+    <td rowSpan={7}>Canvas node operation supports undo/redo</td>
+    <td>Add/Delete node</td>
     <td>✅</td>
     <td>✅</td>
   </tr>
   <tr>
-    <td>Add/Delete Connections</td>
+    <td>Add/Delete line</td>
     <td>✅</td>
     <td>❌</td>
   </tr>
   <tr>
-    <td>Move Nodes</td>
+    <td>Move node</td>
     <td>✅</td>
     <td>✅</td>
   </tr>
   <tr>
-    <td>Add/Delete Branches</td>
+    <td>Add/Delete branch</td>
     <td>❌</td>
     <td>✅</td>
   </tr>
   <tr>
-    <td>Move Branches</td>
+    <td>Move branch</td>
     <td>❌</td>
     <td>✅</td>
   </tr>
   <tr>
-    <td>Add Groups</td>
+    <td>Add group</td>
     <td>❌</td>
     <td>✅</td>
   </tr>
   <tr>
-    <td>Ungroup</td>
+    <td>Cancel group</td>
     <td>❌</td>
     <td>✅</td>
   </tr>
   <tr>
-    <td rowSpan={2}>Canvas Batch Operations</td>
-    <td>Delete Nodes</td>
+    <td rowSpan={2}>Canvas batch operation</td>
+    <td>Delete node</td>
     <td>✅</td>
     <td>✅</td>
   </tr>
   <tr>
-    <td>Move Nodes</td>
+    <td>Move node</td>
     <td>✅</td>
     <td>✅</td>
   </tr>
+
 </table>
 
-### 1.2. Disable History
-If you don't want certain system-triggered data changes to be monitored by undo/redo, you can actively stop the history service, perform the operations, and then restart it.
+### 1.2. Disable history
+If some data changes triggered by the system do not want to be monitored by undo/redo, you can actively stop the history service and restart it after the data operation is completed
 
 ```tsx pure
 const { history } = useClientContext();
 history.stop()
-// Perform operations that you don't want to be captured
-// These changes won't be recorded in the operation stack
+// Do some operations that do not want to be captured, these changes will not be recorded in the operation stack
 ...
 history.start()
 ```
 
-### 1.3. Undo/Redo Implementation
-Generally, Undo/Redo will have two button entries in the interface. Clicking them triggers Undo and Redo, and the buttons themselves need to indicate whether Undo/Redo is possible.
+### 1.3. Undo/Redo Call
+Undo/Redo is generally provided with two button entries on the interface, clicking which can trigger Undo and Redo, and the buttons themselves need to have the status of whether Undo/Redo is possible.
 
 ```tsx pure
 export function useUndoRedo(): UndoRedo {
@@ -130,7 +131,7 @@ export function useUndoRedo(): UndoRedo {
 }
 ```
 
-## 2. Feature Extensions
+## 2. Extension Function
 ### 2.1. Operation Registration
 Operations are registered through operationMetas
 
@@ -147,33 +148,32 @@ history={{
   ]
 }}
 ```
-
-Core definition of `OperationMeta`:
-  - `type` is the unique identifier for the operation
-  - `inverse` is a function that returns the inverse operation of the current operation
+`OperationMeta` Core Definition:
+  - `type` is the unique identifier of the operation
+  - `inverse` is a function, which returns the inverse operation of the current operation
   - `apply` is the logic executed when the operation is triggered
 
 ```tsx pure
 export interface OperationMeta {
   /**
-   * Operation type (must be unique)
+   * Operation type, needs to be unique
    */
   type: string;
   /**
-   * Converts an operation into its inverse operation, e.g., insert to delete
-   * @param op operation
-   * @returns inverse operation
+   * Convert an operation to another inverse operation, such as insert to delete
+   * @param op Operation
+   * @returns Inverse operation
    */
   inverse: (op: Operation) => Operation;
   /**
    * Execute operation
-   * @param operation operation
+   * @param operation Operation
    */
   apply(operation: Operation, source: any): void | Promise<void>;
 }
 ```
 
-For example, to support Undo/Redo for adding and deleting nodes, you need to add two operations:
+Suppose I want to add a function to support Undo/Redo for adding and deleting nodes, I need to add two operations
 
 <div style={{marginTop: 16, display: 'flex', gap: 8 }}>
   <div>
@@ -206,16 +206,17 @@ For example, to support Undo/Redo for adding and deleting nodes, you need to add
   </div>
 </div>
 
-### 2.2. Operation Merging
-operationMeta supports shouldMerge to customize merging strategies for frequently triggered operations
+### 2.2. Operation Merge
+operationMeta supports shouldMerge to customize the merge strategy, if frequent operations can be merged
 
 :::warning shouldMerge returns
-- false means no merging
-- true means merge into one stack element
-- Operation means merge into one operation
+- Return false means not merged
+- Return true means merged into one operation stack element
+- Return Operation means merged into one operation
+
 :::
 
-The following example merges edits to the same field within 500ms:
+The following example is a merge of operations that edit the same field within 500ms
 
 ```tsx pure
 {
@@ -246,9 +247,9 @@ The following example merges edits to the same field within 500ms:
 ```
 
 ### 2.3. Operation Execution
-1. Single Operation Execution
+1. Single operation execution
 
-Triggered through pushOperation. Here's an example of how to trigger the previously defined operation in business logic:
+Trigger through pushOperation, the following example uses the operation defined in the business
 
 ```tsx pure
 function handleAddNode () {
@@ -263,9 +264,9 @@ function handleAddNode () {
 }
 ```
 
-2. Batch Execution
-All operations executed within a function called through transact will be merged into one stack element. During undo/redo, they will be executed together.
-Here's an example implementing batch deletion:
+2. Batch execution
+All operations executed in the function called by transact will be merged into one stack element, and will be executed together when undo/redo
+The following is an example of implementing a batch delete:
 
 ```tsx pure
 function deleteNodes(nodes: FlowNodeEntity[]) {
@@ -286,8 +287,8 @@ function deleteNodes(nodes: FlowNodeEntity[]) {
 
 ### 2.4. Undo/Redo
 1. Undo/Redo
-Execute history.undo method for undoing
-Execute history.redo method for redoing
+Undo execution history.undo method
+Redo execution history.redo method
 
 ```tsx pure
 function undo() {
@@ -301,10 +302,9 @@ function redo() {
 }
 ```
 
-2. Monitoring Undo/Redo
+2. Listen Undo/Redo
 Listen to the onChange event of undoRedoService.onChange
-Here's an example of routing to corresponding operation URIs (selecting corresponding nodes or form items) after undo/redo:
-
+The following is an example of triggering the uri of the corresponding operation after undo/redo (selecting the corresponding node or form item)
 ```tsx pure
 function listenHistoryChange() {
   const { history } = useClientContext();
@@ -326,27 +326,27 @@ function listenHistoryChange() {
 ```
 
 ### 2.5. Operation History
-1. View Refresh
-You can get the history records through HistoryStack.items and refresh the interface by monitoring the HistoryStack.onChange event
+1. View refresh
+You can get the history record through HistoryStack.items, and refresh the interface by listening to HistoryStack.onChange
 
 ```tsx pure
 import React from 'react';
 
 export function HistoryList() {
   const { historyStack } = useService<HistoryManager>(HistoryManager)
-  const { refresh } = useRefresh() 
+  const { refresh } = useRefresh()
   let items = historyManager.historyStack.items;
-  
+
   useEffect(() => {
       const disposable = historyStack.onChange(() => {
           refresh()
       ])
-      
+
       return () => {
           disposable.dispose()
       }
   }, [])
-  
+
   return (
       <ul>
         {items.map((item, index) => (
@@ -362,20 +362,19 @@ export function HistoryList() {
                 </Tooltip>
               ))}
             </div>
-         
+
           </li>
         ))}
       </ul>
   );
 }
 ```
-
 2. Persistence
 Persistence is implemented through the history-storage plugin
-- databaseName: Database name
-- resourceStorageLimit: Resource storage limit count
+- databaseName: database name
+- resourceStorageLimit: resource storage limit number
 
-After importing the @flowgram.ai/history-storage package, you can use this plugin:
+After introducing the @flowgram.ai/history-storage package, the plugin can be used
 
 ```tsx pure
 import { createHistoryStoragePlugin } from '@flowgram.ai/history-storage';
@@ -386,7 +385,7 @@ createHistoryStoragePlugin({
 }),
 ```
 
-Query database list using useStorageHistoryItems:
+Query the database list through useStorageHistoryItems
 
 ```tsx pure
 import {
@@ -400,16 +399,16 @@ export const HistoryList = () => {
     storage,
     uri.withoutQuery().toString(),
   );
-  
+
   return <>
     { JSON.stringify(items) }
-  </>  
+  </>
 }
 ```
 
 ## 3. API List
 ### 3.1. [OperationMeta](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-history-plugin/interfaces/OperationMeta.html)
-Operation metadata, used to define an operation
+OperationMeta, used to define an operation
 
 ### 3.2. [Operation](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-history-plugin/interfaces/Operation.html)
 Operation data, associated with OperationMeta through type
@@ -417,23 +416,23 @@ Operation data, associated with OperationMeta through type
 ### 3.3. [OperationService](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-history-plugin/classes/OperationService.html)
 
 [onApply](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-history-plugin/classes/OperationService.html#onapply)
-Use onApply to monitor triggered operations
+Use onApply to listen to a triggered operation
 
 ```tsx pure
 useService(OperationService).onApply((op: Operation) => {
     console.log(op)
-    // Execute your business logic here based on type
+    // Here you can execute your own business logic according to type
 })
 ```
 
 ### 3.4. [HistoryService](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-history-plugin/classes/HistoryService.html)
-Core API Service exposed by the History module
+The core API of the History module exposed Service
 
 ### 3.5. [UndoRedoService](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-history-plugin/classes/UndoRedoService.html)
-Service managing the UndoRedo stack
+The service that manages the UndoRedo stack
 
 ### 3.6. [HistoryStack](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-history-plugin/classes/HistoryStack.html)
-History stack, monitoring all push, undo, redo operations and recording them in the stack
+History stack, listen to all push undo redo operations, and record them in the stack
 
 ### 3.7. [HistoryDatabase](https://coze-dev.github.io/flowgram.ai/auto-docs/history-storage/classes/HistoryDatabase.html)
-Persistent database operations
+Persistence database operations

+ 1 - 1
apps/docs/src/en/guide/advanced/interactive/minimap.mdx

@@ -48,7 +48,7 @@ import { createMinimapPlugin } from '@flowgram.ai/minimap-plugin'
 
 ```tsx pure
 import { FlowMinimapService, MinimapRender } from '@flowgram.ai/minimap-plugin';
-import { useService } from '@flowgram.ai/editor'; //  free-layout-editor
+import { useService } from '@flowgram.ai/editor'; // or free-layout-editor
 
 
 export const Minimap = () => {

+ 18 - 4
apps/docs/src/en/guide/advanced/interactive/shortcuts.mdx

@@ -1,16 +1,17 @@
 # Shortcuts
 
-## Custom Shortcuts
+## Customize Shortcuts
 
 ```ts pure
 // Add to EditorProps
 {
-  shortcuts(shorcutsRegistry: ShortcutsRegistry, ctx) {
-      // Select all nodes when pressing command + a or ctrl + a
+  shortcuts(shorcutsRegistry, ctx) {
+      // Press command + a to select all nodes
       shorcutsRegistry.addHandlers({
         commandId: 'selectAll',
         shortcuts: ['meta a', 'ctrl a'],
-        execute() {
+        isEnabled: (...args) => true,
+        execute(...args) {
           const allNodes = ctx.document.getAllNodes();
           ctx.playground.selectionService.selection = allNodes;
         },
@@ -19,3 +20,16 @@
 }
 
 ```
+
+## Call Shortcuts by CommandService
+
+```ts pure
+const commandService = useService(CommandService)
+/**
+ * Call command service, args will be passed to execute and isEnabled
+ */
+commandService.executeCommand('selectAll', ...args)
+
+// OR
+ctx.get(CommandService).executeCommand('selectAll', ...args)
+```

+ 11 - 10
apps/docs/src/en/guide/advanced/variable.mdx

@@ -1,6 +1,6 @@
-# Using Variables
+# Use Variables
 
-## Enabling the Variable Engine
+## Enable Variable Engine
 
 ```tsx pure title="use-editor-props.ts"
 
@@ -8,7 +8,7 @@
 {
   variableEngine: {
     /**
-     * The variable engine must be enabled to use variables
+     * Need to enable the variable engine to use
      */
     enable: true
   }
@@ -17,7 +17,7 @@
 
 ## Node Output Variables
 
-### Setting Output Variables via FlowNodeVariableData
+### Set Output Variables through FlowNodeVariableData
 
 ```tsx pure title="variable-plugin.tsx"
 import {
@@ -85,9 +85,10 @@ flowDocument.onNodeCreate(({ node }) => {
 
 ```
 
-For more usage, see: [Class: FlowNodeVariableData](https://coze-dev.github.io/flowgram.ai/auto-docs/editor/classes/FlowNodeVariableData.html)
+More usage, see: [Class: FlowNodeVariableData](https://coze-dev.github.io/flowgram.ai/auto-docs/editor/classes/FlowNodeVariableData.html)
+
+### Set Output Variables through Form Effect
 
-### Setting Output Variables via Form Side Effects
 
 ```tsx pure title="node-registries.ts"
 import {
@@ -141,9 +142,9 @@ export const nodeRegistries: FlowNodeRegistry[] = [
 ```
 
 
-## Node Consumption of Variables
+## Node Consumes Variables
 
-### Retrieving the Variable List
+### Get Variable List
 
 ```tsx pure title="use-variable-tree.tsx"
 import {
@@ -166,7 +167,7 @@ return available.variables.map(renderVariable)
 
 ```
 
-### Drilling Down into Object Type Variables
+### Get Drilldown of Object Type Variable
 
 ```tsx pure title="use-variable-tree.tsx"
 import {
@@ -188,7 +189,7 @@ const renderVariable = (variable: BaseVariableField) => ({
 
 ```
 
-### Drilling Down into Array Type Variables
+### Get Drilldown of Array Type Variable
 
 ```tsx pure title="use-variable-tree.tsx"
 import {

+ 3 - 1
apps/docs/src/en/guide/concepts/_meta.json

@@ -1,5 +1,7 @@
 [
   "canvas-engine",
   "node-engine",
-  "variable-engine"
+  "variable-engine",
+  "ECS",
+  "IOC"
 ]

+ 1 - 0
apps/docs/src/en/guide/concepts/ecs.mdx

@@ -0,0 +1 @@
+# ECS

+ 5 - 5
apps/docs/src/en/guide/concepts/index.mdx

@@ -1,8 +1,8 @@
 # 概念
 
-![FlowGramAI 架构](@/public/canvas-engine.png)
+![FlowGramAI Architecture](@/public/canvas-engine.png)
 
-- CanvasEngine:画布引擎负责绘制“点-线”构成的图, 保障大规模节点时的流畅性
-- NodeEngine: 节点引擎提供 渲染、校验、数据修改等表单能力
-- VariableEngine: 变量引擎引入作用域模型, 抽象各业务场景的变量
-- Material: 物料库包含默认 ICON 等 UI, 业务接入后可覆盖扩展
+- CanvasEngine: Canvas engine is responsible for drawing the "point-line" diagram, ensuring the smoothness of large-scale nodes
+- NodeEngine: Node engine provides rendering, verification, data modification, etc. form capabilities
+- VariableEngine: Variable engine introduces a scope model, abstracts variables in various business scenarios
+- Material: Material library includes default ICONs, etc. UI, and can be extended after business access

+ 1 - 0
apps/docs/src/en/guide/concepts/ioc.mdx

@@ -0,0 +1 @@
+# IOC

+ 59 - 51
apps/docs/src/en/guide/getting-started/create-fixed-layout-simple.mdx

@@ -1,6 +1,7 @@
-# Create Fixed Layout Canvas
 
-This example can be installed via `npx @flowgram.ai/create-app@latest fixed-layout-simple`. For complete code and demo, see:
+# Create a Fixed Layout Canvas
+
+This case can be installed by `npx @flowgram.ai/create-app@latest fixed-layout-simple`, the complete code and effect are as follows:
 
 <div className="rs-tip">
   <a className="rs-link" href="/flowgram.ai/examples/fixed-layout/fixed-layout-simple.html">
@@ -8,18 +9,20 @@ This example can be installed via `npx @flowgram.ai/create-app@latest fixed-layo
   </a>
 </div>
 
+
 ### 1. Canvas Entry
 
-- `FixedLayoutEditorProvider`: Canvas configurator that generates react-context internally for child components to consume
-- `EditorRenderer`: The final rendered canvas that can be wrapped under other components for customizing canvas position
+- `FixedLayoutEditorProvider`: Canvas configurator, internally generates a react-context for consumption by child components
+- `EditorRenderer`: The final rendered canvas, can be wrapped in other components to customize the canvas position
 
 ```tsx pure title="app.tsx"
+
 import {
   FixedLayoutEditorProvider,
   EditorRenderer,
 } from '@flowgram.ai/fixed-layout-editor';
 
-import { useEditorProps } from './use-editor-props' // Detailed canvas props configuration
+import { useEditorProps } from './use-editor-props' // Canvas detailed props configuration
 import { Tools } from './tools' // Canvas tools
 
 function App() {
@@ -35,7 +38,7 @@ function App() {
 
 ### 2. Configure Canvas
 
-Canvas configuration is declarative, providing configurations for data, rendering, events, and plugins
+Canvas configuration uses declarative, providing data, rendering, event, plugin related configurations
 
 ```tsx pure title="use-editor-props.tsx"
 import { useMemo } from 'react';
@@ -43,7 +46,7 @@ import { type FixedLayoutProps } from '@flowgram.ai/fixed-layout-editor';
 import { defaultFixedSemiMaterials } from '@flowgram.ai/fixed-semi-materials';
 import { createMinimapPlugin } from '@flowgram.ai/minimap-plugin';
 
-import { intialData } from './initial-data' // Initialization data
+import { intialData } from './initial-data' // Initial data
 import { nodeRegistries } from './node-registries' // Node declaration configuration
 import { BaseNode } from './base-node' // Node rendering
 
@@ -52,16 +55,15 @@ export function useEditorProps(
   return useMemo<FixedLayoutProps>(
     () => ({
       /**
-       * Initialization data
+       * Initial data
        */
       initialData,
       /**
-       * Canvas node definitions
+       * Canvas node definition
        */
       nodeRegistries,
       /**
-       * UI components can be customized via key. Here provides a set of semi components for quick validation.
-       * For deep customization, refer to:
+       * Custom UI components can be defined by key, for example, add a button, here is a semi-component set for quick verification, if you need deep customization, refer to:
        * https://github.com/coze-dev/flowgram.ai/blob/main/packages/materials/fixed-semi-materials/src/components/index.tsx
        */
       materials: {
@@ -73,31 +75,31 @@ export function useEditorProps(
         renderDefaultNode: BaseNode, // Node rendering component
       },
       /**
-       * Node engine for rendering node forms
+       * Node engine, used to render node form
        */
       nodeEngine: {
         enable: true,
       },
       /**
-       * Canvas history record for controlling redo/undo
+       * Canvas history, used to control redo/undo
        */
       history: {
         enable: true,
-        enableChangeNode: true, // Monitor node form data changes
+        enableChangeNode: true, // Used to listen to node form data changes
       },
       /**
        * Canvas initialization callback
        */
       onInit: ctx => {
-        // For dynamic data loading, use the following method asynchronously
+        // If you want to dynamically load data, you can execute it asynchronously by the following method
         // ctx.docuemnt.fromJSON(initialData)
       },
       /**
-       * Callback when canvas first render completes
+       * Canvas first rendering completed callback
        */
       onAllLayersRendered: (ctx) => {},
       /**
-       * Canvas disposal callback
+       * Canvas destruction callback
        */
       onDispose: () => { },
       plugins: () => [
@@ -110,11 +112,13 @@ export function useEditorProps(
     [],
   );
 }
+
 ```
 
+
 ### 3. Configure Data
 
-Canvas document data uses a tree structure that supports nesting
+Canvas document data uses a tree structure, supports nesting
 
 :::note Document data basic structure:
 
@@ -124,11 +128,12 @@ Canvas document data uses a tree structure that supports nesting
 
 :::note Node data basic structure:
 
-- id: `string` Unique node identifier, must be unique
-- meta: `object` Node UI configuration information, like `position` info for free layout goes here
-- type: `string | number` Node type, corresponds to `type` in `nodeRegistries`
+
+- id: `string` Node unique identifier, must be unique
+- meta: `object` Node ui configuration information, such as free layout `position` information
+- type: `string | number` Node type, will correspond to `type` in `nodeRegistries`
 - data: `object` Node form data
-- blocks: `array` Node branches, using `block` is closer to `Gramming`
+- blocks: `array` Node branch, using `block` is more in line with `Gramming`
 
 :::
 
@@ -136,7 +141,7 @@ Canvas document data uses a tree structure that supports nesting
 import { FlowDocumentJSON } from '@flowgram.ai/fixed-layout-editor';
 
 /**
- * Configure flow data, data is in blocks nested format
+ * Configure workflow data, data is in the format of nested blocks
  */
 export const initialData: FlowDocumentJSON = {
   nodes: [
@@ -150,7 +155,7 @@ export const initialData: FlowDocumentJSON = {
       },
       blocks: [],
     },
-    // Condition node
+    // Branch node
     {
       id: 'condition_0',
       type: 'condition',
@@ -198,11 +203,12 @@ export const initialData: FlowDocumentJSON = {
     },
   ],
 };
+
 ```
 
-### 4. Declare Nodes
+### 4. Declare Node
 
-Node declaration can be used to determine node types and rendering methods
+Declare node can be used to determine the type and rendering method of the node
 
 ```tsx pure title="node-registries.tsx"
 import { FlowNodeRegistry, ValidateTrigger } from '@flowgram.ai/fixed-layout-editor';
@@ -217,30 +223,30 @@ export const nodeRegistries: FlowNodeRegistry[] = [
      */
     type: 'condition',
     /**
-     * Custom node extensions:
-     *  - loop: Extend as loop node
-     *  - start: Extend as start node
-     *  - dynamicSplit: Extend as branch node
-     *  - end: Extend as end node
-     *  - tryCatch: Extend as tryCatch node
-     *  - default: Extend as normal node (default)
+     * Custom node extension:
+     *  - loop: Extended to loop node
+     *  - start: Extended to start node
+     *  - dynamicSplit: Extended to branch node
+     *  - end: Extended to end node
+     *  - tryCatch: Extended to tryCatch node
+     *  - default: Extended to normal node (default)
      */
     extend: 'dynamicSplit',
     /**
      * Node configuration information
      */
     meta: {
-      // isStart: false, // Whether it's a start node
-      // isNodeEnd: false, // Whether it's an end node, no nodes can be added after end node
-      // draggable: false, // Whether draggable, start and end nodes cannot be dragged
-      // selectable: false, // Triggers and start nodes cannot be box-selected
+      // isStart: false, // Whether it is a start node
+      // isNodeEnd: false, // Whether it is an end node, the node after the end node cannot be added
+      // draggable: false, // Whether it can be dragged, such as the start node and the end node cannot be dragged
+      // selectable: false, // The trigger start node cannot be selected
       // deleteDisable: true, // Disable deletion
-      // copyDisable: true, // Disable copying
-      // addDisable: true, // Disable adding
+      // copyDisable: true, // Disable copy
+      // addDisable: true, // Disable addition
     },
     /**
-     * Configure node form validation and rendering
-     * Note: validate uses data and rendering separation to ensure nodes can validate data even without rendering
+     * Configure node form validation and rendering,
+     * Note: validate uses data and rendering separation, ensuring that even if the node is not rendered, the data can be validated
      */
     formMeta: {
       validateTrigger: ValidateTrigger.onChange,
@@ -263,22 +269,22 @@ export const nodeRegistries: FlowNodeRegistry[] = [
     },
   },
 ];
-```
 
-### 5. Render Nodes
+```
+### 5. Render Node
 
-Node rendering is used to add styles, events, and form rendering positions
+The rendering node is used to add styles, events, and form rendering positions
 
 ```tsx pure title="base-node.tsx"
 import { useNodeRender } from '@flowgram.ai/fixed-layout-editor';
 
 export const BaseNode = () => {
   /**
-   * Provides node rendering related methods
+   * Provides methods related to node rendering
    */
   const nodeRender = useNodeRender();
   /**
-   * Form can only be used when node engine is enabled
+   * Forms can only be used when the node engine is enabled
    */
   const form = nodeRender.form;
 
@@ -293,23 +299,25 @@ export const BaseNode = () => {
         e.stopPropagation();
       }}
       style={{
-        // BlockOrderIcon represents first node of branch, BlockIcon represents header node of entire condition
+        // BlockOrderIcon represents the first node of a branch, BlockIcon represents the header node of the entire condition
         ...(nodeRender.isBlockOrderIcon || nodeRender.isBlockIcon ? { width: 260 } : {}),
         outline: form?.state.invalid ? '1px solid red' : 'none', // Red border for form validation errors
       }}
     >
       {
-        // Form rendering generated through formMeta
+        // Form rendering is generated through formMeta
         form?.render()
       }
     </div>
   );
 };
+
 ```
 
+
 ### 6. Add Tools
 
-Tools are mainly used to control canvas zoom and other operations. Tools are collected in `usePlaygroundTools`, while `useClientContext` is used to get canvas context, which contains core modules like `history`
+Tools are mainly used to control canvas zooming and other operations. Tools are consolidated in `usePlaygroundTools`, while `useClientContext` is used to get the canvas context, which contains core modules such as `history`
 
 ```tsx pure title="tools.tsx"
 import { useEffect, useState } from 'react'
@@ -339,9 +347,9 @@ export function Tools() {
     <span>{Math.floor(tools.zoom * 100)}%</span>
   </div>
 }
-```
 
-### 7. Result
+```
+### 7. Effect
 
 import { FixedLayoutSimple } from '../../../../components';
 

+ 43 - 38
apps/docs/src/en/guide/getting-started/create-free-layout-simple.mdx

@@ -1,6 +1,6 @@
-# Creating a Free Layout Canvas
+# Create a Free Layout Canvas
 
-This example can be installed using `npx @flowgram.ai/create-app@latest free-layout-simple`. For complete code and demo, see:
+This case can be installed via `npx @flowgram.ai/create-app@latest free-layout-simple`. For complete code and effects, see:
 
 <div className="rs-tip">
   <a className="rs-link" href="/flowgram.ai/examples/free-layout/free-layout-simple.html">
@@ -10,10 +10,11 @@ This example can be installed using `npx @flowgram.ai/create-app@latest free-lay
 
 ### 1. Canvas Entry
 
-- `FreeLayoutEditorProvider`: Canvas configurator that generates a react-context for child components to consume
-- `EditorRenderer`: The final rendered canvas that can be wrapped under other components for customizing canvas position
+- `FreeLayoutEditorProvider`: Canvas configurator that generates react-context internally for child component consumption
+- `EditorRenderer`: The final rendered canvas that can be wrapped under other components for convenient canvas positioning
 
 ```tsx pure title="app.tsx"
+
 import {
   FreeLayoutEditorProvider,
   EditorRenderer,
@@ -35,23 +36,23 @@ function App() {
 
 ### 2. Configure Canvas
 
-Canvas configuration is declarative, providing data, rendering, events, and plugin-related configurations
+Canvas configuration is declarative, providing data, rendering, event, and plugin-related configurations
 
 ```tsx pure title="use-editor-props.tsx"
 import { useMemo } from 'react';
 import { type FixedLayoutProps } from '@flowgram.ai/free-layout-editor';
 import { createMinimapPlugin } from '@flowgram.ai/minimap-plugin';
 
-import { intialData } from './initial-data' // Initialization data
-import { nodeRegistries } from './node-registries' // Node declaration configuration
-import { BaseNode } from './base-node' // Node rendering
+import { intialData } from './initial-data' // 初始化数据
+import { nodeRegistries } from './node-registries' // 节点声明配置
+import { BaseNode } from './base-node' // 节点渲染
 
 export function useEditorProps(
 ): FixedLayoutProps {
   return useMemo<FixedLayoutProps>(
     () => ({
       /**
-       * Initialization data
+       * Initialize data
        */
       initialData,
       /**
@@ -65,31 +66,31 @@ export function useEditorProps(
         renderDefaultNode: BaseNode, // Node rendering component
       },
       /**
-       * Node engine for rendering node forms
+       * Node engine, used for rendering node forms
        */
       nodeEngine: {
         enable: true,
       },
       /**
-       * Canvas history for controlling redo/undo
+       * Canvas history record, used to control redo/undo
        */
       history: {
         enable: true,
-        enableChangeNode: true, // Monitor node form data changes
+        enableChangeNode: true, // Used to monitor node form data changes
       },
       /**
        * Canvas initialization callback
        */
       onInit: ctx => {
-        // For dynamic data loading, use the following method asynchronously
+        // If you need to load data dynamically, you can execute asynchronously using the following method
         // ctx.docuemnt.fromJSON(initialData)
       },
       /**
-       * Callback after first complete canvas render
+       * Callback when canvas first renders completely
        */
       onAllLayersRendered: (ctx) => {},
       /**
-       * Canvas disposal callback
+       * Canvas destruction callback
        */
       onDispose: () => { },
       plugins: () => [
@@ -102,11 +103,12 @@ export function useEditorProps(
     [],
   );
 }
+
 ```
 
 ### 3. Configure Data
 
-Canvas document data uses a tree structure that supports nesting
+Canvas document data uses a tree structure and supports nesting
 
 :::note Document Data Basic Structure:
 
@@ -117,23 +119,24 @@ Canvas document data uses a tree structure that supports nesting
 
 :::note Node Data Basic Structure:
 
-- id: `string` Unique node identifier
-- meta: `object` Node UI configuration info, such as free layout `position` information
+- id: `string` Unique node identifier, must ensure uniqueness
+- meta: `object` Node UI configuration information, such as free layout `position` information goes here
 - type: `string | number` Node type, corresponds to `type` in `nodeRegistries`
-- data: `object` Node form data, customizable by business
-- blocks: `array` Node branches, using `block` to align with `Gramming`
+- data: `object` Node form data, business can customize
+- blocks: `array` Node branches, using `block` is closer to `Gramming`
 
 :::
 
 :::note Edge Data Basic Structure:
 
-- sourceNodeID: `string` Start node ID
-- targetNodeID: `string` Target node ID
-- sourcePortID?: `string | number` Start port ID, defaults to node's default port if omitted
-- targetPortID?: `string | number` Target port ID, defaults to node's default port if omitted
+- sourceNodeID: `string` Start node id
+- targetNodeID: `string` Target node id
+- sourcePortID?: `string | number` Start port id, defaults to start node's default port if omitted
+- targetPortID?: `string | number` Target port id, defaults to target node's default port if omitted
 
 :::
 
+
 ```tsx pure title="initial-data.tsx"
 import { WorkflowJSON } from '@flowgram.ai/free-layout-editor';
 
@@ -184,11 +187,13 @@ export const initialData: WorkflowJSON = {
     },
   ],
 };
+
+
 ```
 
 ### 4. Declare Nodes
 
-Node declarations are used to determine node types and rendering methods
+Node declaration can be used to determine node types and rendering methods
 
 ```tsx pure title="node-registries.tsx"
 import { WorkflowNodeRegistry, ValidateTrigger } from '@flowgram.ai/free-layout-editor';
@@ -203,12 +208,12 @@ export const nodeRegistries: WorkflowNodeRegistry[] = [
       isStart: true, // Mark as start node
       deleteDisable: true, // Start node cannot be deleted
       copyDisable: true, // Start node cannot be copied
-      defaultPorts: [{ type: 'output' }], // Define input/output ports, start node only has output port
-      // dynamicPort: true, // For dynamic ports, will look for DOM elements with data-port-id and data-port-type attributes
+      defaultPorts: [{ type: 'output' }], // Used to define node input and output ports, start node only has output port
+      // dynamicPort: true, // Used for dynamic ports, will look for DOM elements with data-port-id and data-port-type attributes as ports
     },
     /**
-     * Configure node form validation and rendering
-     * Note: validate uses data and rendering separation to ensure validation even without rendering
+     * Configure node form validation and rendering,
+     * Note: validate uses data and rendering separation to ensure nodes can validate data even without rendering
      */
     formMeta: {
       validateTrigger: ValidateTrigger.onChange,
@@ -248,14 +253,14 @@ export const nodeRegistries: WorkflowNodeRegistry[] = [
     formMeta: {
       // ...
     },
-    defaultPorts: [{ type: 'output' }, { type: 'input' }], // Regular nodes have two ports
+    defaultPorts: [{ type: 'output' }, { type: 'input' }], // 普通节点有两个端口
   },
 ];
-```
 
+```
 ### 5. Render Nodes
 
-Node rendering is used to add styles, events, and form rendering positions
+Rendering nodes is used for adding styles, events, and form rendering positions
 
 ```tsx pure title="base-node.tsx"
 import { useNodeRender, WorkflowNodeRenderer } from '@flowgram.ai/free-layout-editor';
@@ -266,24 +271,25 @@ export const BaseNode = () => {
    */
   const { form } = useNodeRender()
   /**
-   * WorkflowNodeRenderer adds node drag events and port rendering
-   * For deep customization, see the component source code:
+   * WorkflowNodeRenderer will add node drag events and port rendering, for deep customization, 
+   * you can check the component source code at:
    * https://github.com/coze-dev/flowgram.ai/blob/main/packages/client/free-layout-editor/src/components/workflow-node-renderer.tsx
    */
   return (
     <WorkflowNodeRenderer className="demo-free-node" node={props.node}>
       {
-        // Form rendering generated through formMeta
+        // Form rendering is generated through formMeta
         form?.render()
       }
     </WorkflowNodeRenderer>
   )
 };
+
 ```
 
 ### 6. Add Tools
 
-Tools are mainly used to control canvas zoom and other operations. Tools are consolidated in `usePlaygroundTools`, while `useClientContext` is used to get canvas context containing core modules like `history`
+Tools are mainly used to control canvas zooming and other operations. Tools are consolidated in `usePlaygroundTools`, while `useClientContext` is used to get the canvas context, which contains core modules such as `history`
 
 ```tsx pure title="tools.tsx"
 import { useEffect, useState } from 'react'
@@ -314,8 +320,7 @@ export function Tools() {
   </div>
 }
 ```
-
-### 7. Result
+### 7. Effect
 
 import { FreeLayoutSimple } from '../../../../components';
 

+ 4 - 4
apps/docs/src/en/guide/getting-started/install.mdx

@@ -10,10 +10,10 @@ import { PackageManagerTabs } from '@theme';
 
 ```shell
 # Select demo
-- fixed-layout # Fixed layout best practices
-- free-layout # Free layout best practices
-- fixed-layout-simple # Fixed layout basic usage
-- free-layout-simple # Free layout basic usage
+- fixed-layout # Best practices for fixed layout
+- free-layout # Best practices for free layout
+- fixed-layout-simple # Basic usage of fixed layout
+- free-layout-simple # Basic usage of free layout
 
 ```
 

+ 1 - 8
apps/docs/src/en/guide/index/_meta.json

@@ -1,10 +1,3 @@
 [
-  "introduction",
-  {
-    "type": "dir",
-    "name": "canvas-engine",
-    "label": "CanvasEngine"
-  },
-  "node-engine",
-  "variable-engine"
+  "introduction"
 ]

+ 33 - 34
apps/docs/src/en/guide/index/canvas-engine/index.mdx

@@ -1,6 +1,6 @@
 # Core Modeling
 
-Playground provides an underlying coordinate system
+Playground provides a coordinate system at its foundation
 
 ```ts
 interface Playground {
@@ -8,33 +8,32 @@ interface Playground {
    scrollToView({
      entities?: Entity[] // Specified nodes
      easing?: boolean // Enable easing
-     bounds?: Reactangle // Specify target bbox position
-    }) // Smoothly scroll canvas to center on specific node
+     bounds?: Reactangle // Scroll to specific bbox position
+    }) // Make canvas scroll smoothly to a specific node and center it
    toReactComponent() // Render as React node
    readonly: boolean // Read-only mode
    config: PlaygroundConfigEntity // Contains canvas data like zoom, scroll etc.
 }
-// Hook for quick access
+// Quick access hook
 const playground = usePlayground()
 ```
 
 ## Layer
 
 :::warning P.S.
-- The rendering layer establishes its own coordinate system at the bottom layer, implementing simulated scrolling, zooming and other logic based on this system. Nodes also need to be transformed to this coordinate system when calculating viewport
-- Rendering is split into multiple layers (Layer) on canvas. The layered design is based on ECS data splitting concept, where different Layers only monitor their desired data and render independently without interference. Layer can be understood as ECS's System, i.e. where Entity data is ultimately consumed
-- Layer implements mobx-like observer reactive dynamic dependency collection, where data updates trigger autorun or render
-
+- The rendering layer establishes its own coordinate system at the bottom layer, implementing simulated scrolling, zooming and other logic based on this coordinate system. When calculating viewport, nodes also need to be transformed to this coordinate system
+- Rendering is split into multiple layers (Layer) on the canvas. The layered design is based on ECS data splitting concept. Different Layers only listen to the data they want and render independently without interference. Layer can be understood as the System in ECS, which is where Entity data is ultimately consumed
+- Layer implements observer reactive dynamic dependency collection similar to mobx, data updates will trigger autorun or render
 :::
 
-![Aspect-Oriented Programming](../assets/layer-uml.jpg)
+![Aspect Programming](../assets/layer-uml.jpg)
 
 - Layer lifecycle
 
 ```ts
 interface Layer {
     /**
-     * Triggered on initialization
+     * Triggered during initialization
      */
     onReady?(): void;
 
@@ -54,22 +53,22 @@ interface Layer {
     onBlur?(): void;
 
     /**
-     * Monitor zoom
+     * Listen to zoom changes
      */
     onZoom?(scale: number): void;
 
     /**
-     * Monitor scroll
+     * Listen to scroll changes
      */
     onScroll?(scroll: { scrollX: number; scrollY: number }): void;
 
     /**
-     * Triggered on viewport update
+     * Triggered when viewport updates
      */
     onViewportChange?(): void;
 
     /**
-     * readonly or disable state changes
+     * Triggered when readonly or disable state changes
      * @param state
      */
     onReadonlyOrDisabledChange?(state: { disabled: boolean; readonly: boolean }): void;
@@ -81,7 +80,7 @@ interface Layer {
 }
 ```
 
-Layer's positioning is actually similar to Unity game engine's [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html). Unity game engine's script extensions are all based on this, which can be considered the core design, also based on C#'s reflection capability for dependency injection
+Layer's positioning is actually similar to Unity game engine's [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html). Unity game engine's script extensions are all based on this, which can be considered the core design, and the underlying implementation is also based on C#'s Reflection dependency injection capability
 
 ```C#
 using System.Collections;
@@ -108,13 +107,13 @@ public class MyMonoBehavior : MonoBehaviour
 
 ```ts
 export class DemoLayer extends Layer {
-    // Injection of any inversify module
+    // Any inversify module injection
     @inject(FlowDocument) document: FlowDocument
-    // Monitor single Entity
+    // Observe single Entity
     @observeEntity(SomeEntity) entity: SomeEntity
-    // Monitor multiple Entities
+    // Observe multiple Entities
     @observeEntities(SomeEntity) entities: SomeEntity[]
-    // Monitor Entity data block (ECS - Component) changes
+    // Observe Entity data block (ECS - Component) changes
     @observeEntityDatas(SomeEntity, SomeEntityData) transforms: SomeEntityData[]
     autorun() {}
     render() {
@@ -124,11 +123,11 @@ export class DemoLayer extends Layer {
 ```
 
 ## FlowNodeEntity
-- Node is a tree, in free canvas mode, nodes are flat without child nodes
+- Nodes form a tree. In free canvas mode, nodes are flat without child nodes
 ```ts
-interface FlowNodeEntity {
-    id: string
-    children?: FlowNodeEntity[]
+inteface FlowNodeEntity {
+    id string
+    children: FlowNodeEntity[]
     pre?: FlowNodeEntity
     next?: FlowNodeEntity
     parent?: FlowNodeEntity
@@ -142,13 +141,13 @@ interface FlowNodeEntity {
 
 ```ts
 class FlowNodeTransformData {
-    localTransform: Matrix, // Relative offset, only relative to previous Sibling node offset in same Block
-    worldTransform: Matrix, // Absolute offset, accumulated offset relative to Parent and Sibling nodes
-    delta: Point // Center/left alignment offset, independent of Matrix, controlled by each node
+    localTransform: Matrix, // Relative offset, only relative to the previous Sibling node offset in the same Block
+    worldTransform: Matrix, // Absolute offset, relative to the accumulated offset of Parent and Sibling nodes
+    deltaPoint // Center/left alignment offset, independent from Matrix, controlled by each node itself
     getSize(): Size, // Calculated from own (independent node) or child branch node width/height spacing
     getBounds(): Rectangle // Calculated from worldMatrix and size, used for final rendering, this range can also be used to determine highlight selection area
-    inputPoint(): Point // Input point position, generally the center-top position of Block's first node (centered layout)
-    outputPoint(): Point // Output point position, default is node's center-bottom position, but for conditional branches, determined by specific logic like built-in end nodes
+    inputPoint(): Point // Input point position, generally the top center position of the first node in Block (centered layout)
+    outputPoint(): Point // Output point position, default is node's bottom center position, but for conditional branches, determined by built-in end node and specific logic
 }
 ```
 
@@ -156,21 +155,21 @@ class FlowNodeTransformData {
 
 ```ts
 class FlowNodeRenderData {
-  node: HTMLDivElement // Current node's DOM
-  expanded: boolean // Whether expanded
-  activated: boolean // Whether activated
-  hidden: boolean // Whether hidden
+  node: HTMLDivElement // Current node's DOM element
+  expandedboolean // Whether expanded
+  activated boolean // Whether activated
+  hidden boolean // Whether hidden
 }
 ```
 
 ## FlowDocument
 
 ```ts
-interface FlowDocument {
+interface FLowDocument {
     root: FlowNodeEntity // Canvas root node
     fromJSON(data): void // Import data
     toJSON(): FlowDocumentJSON // Export data
     addNode(type: string, meta: any): FlowNodeEntity // Add node
-    traverseDFS(fn: (node: FlowNodeEntity) => void, startNode = this.root) // Traverse
+    traveseDFS(fn: (node: flowNodeEntity) => void, startNode = this.root) // Traverse
 }
 ```

+ 27 - 26
apps/docs/src/en/guide/index/introduction.mdx

@@ -1,8 +1,8 @@
-# Question & Answer
-## Why not use ReactFlow
-- ReactFlow doesn't handle data modeling or provide layout algorithms. It only handles rendering, which means development costs remain high for complex features.
+# Frequently Asked Questions
+## Why Not Use ReactFlow
+- ReactFlow doesn't do data modeling or provide layout algorithms, it only handles rendering. Development complexity and labor costs remain high
 See: https://reactflow.dev/examples/nodes/custom-node
-- ReactFlow's interaction customization is costly. For example, it's difficult to select nodes when the canvas is zoomed out, and it doesn't support drag-and-drop reconnection of lines.
+- ReactFlow's interaction customization cost is high. As shown below, it's difficult to select points when the canvas is zoomed out, and it doesn't support drag-and-drop line reconnection
 <table>
   <tr>
     <td><img src="@/public/reactflow/reactflow-render.gif"/></td>
@@ -12,26 +12,26 @@ See: https://reactflow.dev/examples/nodes/custom-node
 
 ## ReactFlow Paid Features
 
-| Paid Features                    | Supported by FlowGramAI | Future Plans |
+| Paid Features                    | Supported by FlowGramAI | Future Plan |
 |----------------------------------|------------------------|--------------|
 | Grouping                         | Yes                    |              |
 | Redo/Undo                        | Yes                    |              |
 | Copy/Paste                       | Yes                    |              |
-| Help Lines                       | Yes                    |              |
+| HelpLines                        | Yes                    |              |
 | Custom Nodes and Shapes          | Yes                    |              |
 | Custom Lines                     | Yes                    |              |
 | AutoLayout                       | Yes                    |              |
 | ForceLayout                      | No                     | No           |
 | Expand/Collapse                  | Yes                    |              |
 | Collaborative                    | No                     | Yes          |
-| WorkflowBuilder (Fixed Layout Complete Example) | Yes     |              |
+| WorkflowBuilder (Complete Auto-layout Case) | Yes         |              |
 
-## Why IOC is Needed
+## Why Need IOC
 
 :::tip Key Concepts:
-- Inversion of Control (IOC): A design principle in object-oriented programming that reduces coupling between code modules. The most common implementation is Dependency Injection (DI)
-- Domain Logic: Also known as Business Logic, these are logic components related to specific product features
-- Aspect-Oriented Programming (AOP): The core design principle is to split software systems into common logic (cross-cutting, pervasive) and domain logic (vertical-cutting) aspects. Cross-cutting parts can be "consumed as needed" by all vertical-cutting parts
+- Inversion of Control: A design principle in object-oriented programming that reduces coupling between code modules. The most common form is Dependency Injection (DI)
+- Domain Logic: Also called Business Logic, these are logic related to specific product features
+- Aspect-Oriented Programming (AOP): The core design principle is to split software systems into common logic (cross-cutting, pervasive) and domain logic (vertical-cutting) aspects, where cross-cutting parts can be "consumed as needed" by all vertical-cutting parts
 
 :::
 
@@ -39,7 +39,7 @@ Before answering this question, let's understand aspect-oriented programming. AO
 
 ![Aspect-Oriented Programming](@/public/weaving.png)
 
-Ideal Aspect-Oriented Programming
+Ideal aspect-oriented programming
 
 ```ts
 - myAppliation provides business logic
@@ -87,19 +87,20 @@ bind(LifecycleContribution).toService(MyApplicationContributionImpl)
 ```
 
 :::warning IOC is a means of aspect-oriented programming. After introduction, underlying modules can expose interfaces for external registration, bringing benefits:
-- Implements microkernel + plugin design, enabling plugin modularity and on-demand consumption
-- Allows cleaner package separation, implementing feature-based package splitting
+- Implements microkernel + plugin design, enabling plugin pluggability and on-demand consumption
+- Allows for cleaner package separation, implementing feature-based package splitting
 :::
 
-## Why ECS is Needed
+## Why Need ECS
 
 :::warning ECS (Entity-Component-System)
-Suitable for decoupling large data objects, commonly used in games where each character (Entity) has extensive data that needs to be split into physics engine-related data, skin-related, character attributes, etc. (multiple Components) for consumption by different subsystems (Systems). Flow data structures are complex and well-suited for ECS decomposition.
+Suitable for decoupling large data objects, often used in games, where each character (Entity) in the game has very large data, which needs to be split into multiple components such as physical engine related data, skin related, role attributes, etc. (multiple Components), consumed by different subsystems (Systems). The data structure of the process is complex, which is very suitable for ECS for decomposition
+
 :::
 
 ![ECS](./assets/ecs.png)
 
-ReduxStore Pseudo Code
+ReduxStore pseudo code
 ```jsx pure
 const store = () => ({
   nodes: [{
@@ -118,14 +119,14 @@ function Playground() {
 }
 ```
 Advantages:
-- Simple to use with centralized data management
+- Centralized data management is simple to use
 
 Disadvantages:
-- Centralized data management cannot update precisely, leading to performance bottlenecks
-- Poor extensibility, adding new node data couples everything into one large JSON
+- Centralized data management cannot be precisely updated, leading to performance bottlenecks
+- Poor scalability, adding a new node data will couple to a large JSON
 
 ECS Solution
-Note:
+Notes:
 - NodeData corresponds to ECS - Component
 - Layer corresponds to ECS - System
 ```jsx pure
@@ -140,7 +141,7 @@ nodeEntities: Entity[] = []
 
 
 class Entity {
-id: string // Only ID without data
+id: string // Only id, no data
 getData: (dataId: string) => EntityData
 }
 
@@ -171,15 +172,15 @@ layers: [
   LinesLayer, // Line rendering
   NodePositionsLayer, // Position rendering
   NodeFormsLayer // Content rendering
-]
+]
 render() {
   return this.layers.map(layer => layer.render())
 }
 }
 ```
 Advantages:
-- Node data is separated for individual rendering control, enabling precise performance updates
-- Strong extensibility, adding new node data only requires adding XXXData + XXXLayer
+- Node data is split separately for control rendering, performance can be done precisely updated
+- Strong scalability, adding a new node data, then adding a XXXData + XXXLayer
 
 Disadvantages:
-- Has a learning curve
+- There is a learning cost

+ 17 - 18
apps/docs/src/en/guide/index/node-engine.mdx

@@ -1,31 +1,30 @@
-# NodeEngine
+# Node Engine
 
-NodeEngine is a framework for writing flow node logic. It allows businesses to focus on their own rendering and data logic without having to worry about the underlying APIs of the canvas and nodes interconnections. At the same time, NodeEngine has precipitated the best node writing paradigm, helping businesses solve various problems that may arise in flow business, such as data logic and rendering coupling.
-
-NodeEngine is optional. If you don't have any of the following complex node logic, you can choose not to enable NodeEngine and maintain the data and rendering logic by yourself. Complex node logic such as: 1) nodes can be validated or trigger data side effects without rendering; 2) rich nodes interconnections; 3) redo/undo; and so on.
+The Node Engine is a framework for writing flow node logic, allowing businesses to focus on their own rendering and data logic without concerning themselves with underlying canvas and node interaction APIs. Meanwhile, the node engine has established the best node writing paradigms, helping businesses solve various issues that may arise in flow business, such as coupling between data logic and rendering.
+The node engine is optional. If you don't have these complex node logic requirements, you can choose not to enable the node engine and maintain node data and rendering yourself. Complex node logic includes: 1) Nodes can validate or trigger data side effects without rendering; 2) Rich node interactions; 3) Redo/undo; etc.
 
 # Basic Concepts
 
-**FlowNodeEntity**
+FlowNodeEntity
 Flow node model.
 
-**FlowNodeRegistry**
+FlowNodeRegistry
 Static configuration of flow nodes.
 
-**FormMeta**
-Static configuration of the node engine. Configured in the `formMeta` field of FlowNodeRegistry.
+FormMeta
+Static configuration of the node engine. Configured in the formMeta field of FlowNodeRegistry.
 
-**Form**
-It maintains the node's data, and provides rendering, validation, side effects, and other capabilities. And `FormModel` provides a bunch of data manipulation apis .
+Form
+Forms in the node engine. It maintains node data and provides rendering, validation, side effects, and other capabilities. Its FormModel provides access to and modification of node data and triggers validation capabilities.
 
-**Field**
-A rendering field in a node form. Note that Form has already provided the data layer logic, Field is more of a rendering layer model, it only exists after the form field is rendered.
+Field
+A rendering field in the node form. Note that Form already provides data layer logic, Field is more of a rendering layer model that only exists after form field rendering.
 
-**validate**
-Form validation. Including individual field validation as well as overall form validation.
+validate
+Form validation. Usually includes validation for individual fields and overall form validation.
 
-**effect**
-Side effects of form data. Usually refers to triggering specific logic when certain events occur in the form data. For example, if the data of a certain field changes, some information needs to be synchronized to a certain store, this can be called an effect.
+effect
+Form data side effects. Usually refers to specific logic triggered when form data experiences certain events. For example, when a field's data changes and needs to synchronize information to a store, this can be called an effect.
 
-**FormPlugin**
-Form plugin can be configured in formMeta, plugins can perform a series of deep operations on the form. For example, variable plugin.
+FormPlugin
+Form plugins. Can be configured in formMeta, plugins can perform a series of deep operations on forms. Such as variable plugins.

+ 16 - 24
apps/docs/src/en/guide/index/variable-engine.mdx

@@ -5,57 +5,50 @@
 ### Architecture Layers
 
 :::warning Architecture Layers
-The variable engine design follows the DIP (Dependency Inversion Principle) principle, divided into three layers based on code stability, abstraction level, and proximity to business:
-- Variable Abstract Layer: The highest level of abstraction and most stable part in the variable architecture
+The variable engine design follows the DIP (Dependency Inversion Principle) and is divided into three layers based on code stability, abstraction level, and proximity to business:
+- Variable Abstract Layer: The highest level of abstraction and most stable code in the variable architecture
 - Variable Implementation Layer: The more volatile part of the variable architecture, typically requiring adjustments between different business needs
 - Variable Business Layer: The Facade provided to business in the variable architecture, interacting with canvas engine and node engine
-
 :::
 
 ![Architecture Layer Diagram](./assets/variable-engine-structure.png)
 
-
 ### Terminology
 
 #### 🌟 Scope
 :::warning ⭐️⭐️⭐️ Definition:
 A conventional space where variable declarations and consumption are described through AST
-- Conventional space: The space is entirely defined by business needs
-  - In low-code design mode, it can be a node, a component, a right panel...
+- Conventional space: The space is entirely defined by business
+  - In low-code design state, it can be a node, a component, a right panel...
   - In code, it can be a Statement, a code block, a function, a file...
-
 :::
 
-What constitutes a scope's space? This can be defined by different business needs.
-
+What is the scope space? It can be defined by different businesses.
 
 #### 🌟 Abstract Syntax Tree (AST)
 
 :::warning Definition:
-⭐️⭐️⭐️ A protocol that combines AST nodes in a tree structure to implement explicit/implicit CRUD operations on variable information
-- AST Node: Reactive protocol nodes in the AST
+⭐️⭐️⭐️ A protocol that combines AST nodes in tree form to achieve explicit/implicit CRUD of variable information
+- AST nodes: Reactive protocol nodes in AST
 - Explicit CRUD, e.g.: Business explicitly sets a variable's type
 - Implicit CRUD, e.g.: Business declares a variable, and its type is automatically inferred from initialization parameters
-
 :::
 
-:::warning Variable information in scopes - variables, types, expressions, structures, etc. - are essentially combinations of AST nodes
+:::warning Variables, types, expressions, structures, and other variable information in the scope are essentially combinations of AST nodes
 - Variable -> VariableDeclaration node
 - Expression -> Expression node
 - Type -> TypeNode node
 - Structure -> StructDeclaration node
-
 :::
 
-Reference: https://ts-ast-viewer.com/
+Reference link: https://ts-ast-viewer.com/
 
 #### Variable
 
 :::warning Definition:
 An AST node used to declare new variables, using a unique identifier to point to a value that changes within a specific set range
-- Value changing within a specific set range: The variable's value must be within the range described by its variable type
-- Unique identifier: Variables must have a unique Key value
-
+- Value changing within a specific set range: The variable's value must be within the range described by the variable type
+- Unique identifier: The variable must have a unique Key value
 :::
 
 [Variables in JavaScript, unique Key + pointing to a changing value](./assets/variable-code.png)
@@ -63,10 +56,10 @@ An AST node used to declare new variables, using a unique identifier to point to
 #### Variable Type
 
 :::warning Definition:
-⭐️⭐️⭐️ An AST node used to constrain a variable, where the constrained variable's value can only change within a predetermined set range
+⭐️⭐️⭐️ An AST node used to constrain a variable, where the constrained variable value can only change within a predetermined set range
 - A variable can be bound to a variable type
-
 :::
+
 <table>
   <tr>
     <td><img src="./assets/variable-type1.png"/></td>
@@ -74,13 +67,12 @@ An AST node used to declare new variables, using a unique identifier to point to
   </tr>
 </table>
 
-### Visual Understanding of Variable Engine
+### Visual Understanding of the Variable Engine
 
-:::warning Imagine a variable engine world where:
-- Each scope defines a "country"
+:::warning Imagine a variable engine world like this:
+- Define countries through individual scopes
 - Each country contains three main citizens: declarations, types, and expressions
 - Countries communicate with each other through scope chains
-
 :::
 
 ![Illustration](./assets/varaible-zone.png)

+ 15 - 13
apps/docs/src/en/guide/introduction.mdx

@@ -1,15 +1,17 @@
 # Introduction
 
-FlowGram is a node-based workflow building engine that helps developers quickly create workflows in either fixed layout or free connection layout modes. It provides a set of interaction best practices and is particularly suitable for visual workflows with clear inputs and outputs.
+FlowGram is a node-based flow building engine that helps developers quickly create workflows in either fixed layout or free connection layout modes, providing a set of interactive best practices. It's particularly suitable for visual workflows with clear inputs and outputs.
 
-In the current AI boom, we are also focusing on how to empower workflows with AI capabilities, hence the AI suffix in our name.
+In today's AI-driven era, we are focusing more on how to empower workflows with AI, hence the AI suffix in our name.
 
 <div className="rs-highlight">
-  FlowGram = Flow + Program, suggesting that workflows are like programs, with Condition, Loop, and even TryCatch nodes.
+  FlowGram = Flow + Program, suggesting that flows are like programs, with Condition, Loop, and even TryCatch nodes.
 </div>
 
+
 ## Official Demo
 
+
 <div style={{marginTop: 16, display: 'flex', gap: 8 }}>
   <div>
     <div>
@@ -18,7 +20,7 @@ In the current AI boom, we are also focusing on how to empower workflows with AI
       </a>
     </div>
     <div className="rs-tip" style={{ height: 54 }}>
-      Fixed layout with nodes that can be dragged to specified positions, featuring compound nodes for branches, loops, and more
+      Fixed layout with nodes/branches supporting specified position drag and drop, offering compound nodes like branches and loops
     </div>
     <div>
       <img src="@/public/fixed-layout/fixed-layout-demo.gif"/>
@@ -31,7 +33,7 @@ In the current AI boom, we are also focusing on how to empower workflows with AI
       </a>
     </div>
     <div className="rs-tip" style={{ height: 54 }}>
-      Free layout where nodes can be moved anywhere and connected through free-form lines
+      Free layout where nodes can be moved to any position and connected through free connections
     </div>
     <div>
       <img src="@/public/free-layout/free-layout-demo.gif"/>
@@ -41,14 +43,14 @@ In the current AI boom, we are also focusing on how to empower workflows with AI
 
 ## Interactive Experience
 
-We provide a set of interaction best practices for smooth workflow operations
+Providing a set of interactive best practices for smoother workflow operations
 
 <table className="rs-table">
   <tr>
     <td>Motion Transitions</td>
     <td>
       <p>
-        Motion animations in web applications trace back to Material Design, which suggests that element changes in width, height, or position need a transition process. The canvas engine separates the drawing of lines and nodes, significantly reducing the cost of implementing motion transitions.
+        Motion animations in web applications can be traced back to Material Design, which suggests that element changes in width, height, or position need a transition process. The canvas engine separates the drawing of lines and nodes, greatly reducing the cost of implementing motion transitions
       </p>
       <div className="rs-center">
         <img src="@/public/common/motion.gif" />
@@ -59,7 +61,7 @@ We provide a set of interaction best practices for smooth workflow operations
     <td>Touchpad Gesture Zoom + Space Key Canvas Drag</td>
     <td>
       <p>
-        Gestures refer to Mac touchpad two-finger spread/pinch for canvas zoom in/out, or holding space to drag the canvas, inspired by Sketch and Figma interactions
+        Gestures refer to Mac touchpad two-finger spread/pinch for canvas zoom in/out, or holding space to drag the canvas, interactions inspired by Sketch and Figma
       </p>
       <div className="rs-center">
         <img src="@/public/common/touch-pad.gif"  />
@@ -83,7 +85,7 @@ We provide a set of interaction best practices for smooth workflow operations
     </td>
   </tr>
   <tr>
-    <td>Copy/Paste (with shortcuts)</td>
+    <td>Copy/Paste (Shortcut Support)</td>
     <td>
       <div className="rs-center">
         <img src="@/public/fixed-layout/copypaste.gif"  />
@@ -93,7 +95,7 @@ We provide a set of interaction best practices for smooth workflow operations
   <tr>
     <td>
       <div>
-        <div>Box Selection + Drag</div>
+        <div>Box Selection + Drag and Drop</div>
         <div>(Fixed)</div>
       </div>
     </td>
@@ -173,7 +175,7 @@ We provide a set of interaction best practices for smooth workflow operations
   </tr>
 </table>
 
-## Live Applications
+## Online Applications
 
 <div style={{marginTop: 16, display: 'flex', gap: 8 }}>
   <div>
@@ -188,7 +190,7 @@ We provide a set of interaction best practices for smooth workflow operations
   </div>
   <div>
     <a className="rs-link" href="https://www.feishu.cn/hc/zh-CN/articles/908751305974-%E4%BB%80%E4%B9%88%E6%98%AF%E5%A4%9A%E7%BB%B4%E8%A1%A8%E6%A0%BC%E5%B7%A5%E4%BD%9C%E6%B5%81" target="_blank" >
-      Lark Bitable Workflow
+      Lark Multi-dimensional Table Workflow
     </a>
     <div>
       <img src="@/public/ref-bitable.png"/>
@@ -196,7 +198,7 @@ We provide a set of interaction best practices for smooth workflow operations
   </div>
   <div>
     <a className="rs-link" href="https://ae.feishu.cn/hc/zh-CN/articles/120610822514" target="_blank" >
-      Feishu aPaaS Workflow
+      Feishu Low-code Platform Workflow
     </a>
     <div>
       <img src="@/public/ref-apaas.png"/>

+ 4 - 4
apps/docs/src/en/index.md

@@ -3,8 +3,8 @@ pageType: home
 
 hero:
   name: FlowGram.AI
-  text: Plugin-based build process engine
-  tagline: High-performance, scalable, customizable
+  text: Build Flow Engine with Plugins
+  tagline: High Performance, Scalable, Customizable
   actions:
     - theme: brand
       text: Quick Start
@@ -19,10 +19,10 @@ features:
   - title: Coze
     details: <div class="rspress-doc" style="height&#58 180px; min-height&#58 0px"><img class="medium-zoom-image" style="border-radius&#58 8px;height&#58 180px;" src="https://coze-dev.github.io/flowgram.ai/ref-coze.png"/></div>
     icon: 🏃🏻‍♀️
-  - title: Feishu aPaaS
+  - title: Feishu Low-Code Platform Workflow
     details: <div class="rspress-doc" style="height&#58 180px; min-height&#58 0px"><img class="medium-zoom-image" style="border-radius&#58 8px;height&#58 180px;" src="https://coze-dev.github.io/flowgram.ai/ref-apaas.png"/></div>
     icon: 📦
-  - title: Lark BiTable
+  - title: Feishu Bitable
     details: <div class="rspress-doc" style="height&#58 180px; min-height&#58 0px"><img class="medium-zoom-image" style="border-radius&#58 8px;height&#58 180px;" src="https://coze-dev.github.io/flowgram.ai/ref-bitable.png"/></div>
     icon: 🎨
 ---