diff --git a/.memory/worklog.json b/.memory/worklog.json
index 6d65dd6..ab90b86 100644
--- a/.memory/worklog.json
+++ b/.memory/worklog.json
@@ -1,12 +1,5 @@
{
"entries": [
- {
- "files_changed": 1,
- "hash": "ddaa795",
- "message": "docs: record sharp text layout deployment",
- "ts": "2026-05-20T19:20:47+08:00",
- "type": "commit"
- },
{
"files_changed": 1,
"message": "Codex 会话活跃 · 最近命令:codex · 分支 main · 1 项未提交变更 · 最近提交:docs: record sharp text layout deployment",
@@ -3194,6 +3187,13 @@
"message": "docs: codify marketing product baseline",
"hash": "3035efc",
"files_changed": 3
+ },
+ {
+ "ts": "2026-05-27T15:20:42+08:00",
+ "type": "commit",
+ "message": "auto-save 2026-05-27 15:20 (~3)",
+ "hash": "fdef7f7",
+ "files_changed": 3
}
]
}
diff --git a/web/canvas-app/src/stores/canvas.js b/web/canvas-app/src/stores/canvas.js
index 32c28ca..b2ceb72 100644
--- a/web/canvas-app/src/stores/canvas.js
+++ b/web/canvas-app/src/stores/canvas.js
@@ -36,6 +36,32 @@ let isRestoring = false
// Position change threshold for history | 位置变化阈值
const POSITION_THRESHOLD = 10
+const DEFAULT_NODE_DIMENSIONS = {
+ text: { width: 320, height: 220 },
+ image: { width: 320, height: 260 },
+ imageConfig: { width: 320, height: 280 },
+ video: { width: 320, height: 220 },
+ videoConfig: { width: 320, height: 260 },
+ llmConfig: { width: 360, height: 360 },
+ default: { width: 320, height: 240 }
+}
+
+const normalizeDimensions = (type, dimensions = {}) => {
+ const fallback = DEFAULT_NODE_DIMENSIONS[type] || DEFAULT_NODE_DIMENSIONS.default
+ const width = Number(dimensions.width)
+ const height = Number(dimensions.height)
+
+ return {
+ width: Number.isFinite(width) && width > 0 ? width : fallback.width,
+ height: Number.isFinite(height) && height > 0 ? height : fallback.height
+ }
+}
+
+const normalizeNodeForCanvas = (node) => ({
+ ...node,
+ dimensions: normalizeDimensions(node.type, node.dimensions)
+})
+
// Batch operation tracking | 批量操作跟踪
let isBatchOperation = false
let batchStartState = null
@@ -167,12 +193,14 @@ const checkSignificantChanges = (oldState, newState) => {
const createNode = (type, position, data = {}, rootProps = {}, now = Date.now()) => {
const id = getNodeId()
+ const { dimensions, ...nodeRootProps } = rootProps
return {
id,
type,
position,
- ...rootProps,
+ ...nodeRootProps,
+ dimensions: normalizeDimensions(type, dimensions),
data: {
...getDefaultNodeData(type),
...data,
@@ -416,7 +444,7 @@ export const loadProject = (projectId) => {
if (canvasData) {
// Restore nodes | 恢复节点
- nodes.value = canvasData.nodes || []
+ nodes.value = (canvasData.nodes || []).map(normalizeNodeForCanvas)
edges.value = canvasData.edges || []
canvasViewport.value = canvasData.viewport || { x: 100, y: 50, zoom: 0.8 }
diff --git a/web/canvas-app/src/views/Canvas.vue b/web/canvas-app/src/views/Canvas.vue
index 48fa230..f960004 100644
--- a/web/canvas-app/src/views/Canvas.vue
+++ b/web/canvas-app/src/views/Canvas.vue
@@ -52,6 +52,7 @@
:max-zoom="2"
:snap-to-grid="true"
:snap-grid="[20, 20]"
+ :only-render-visible-elements="true"
@connect="onConnect"
@node-click="onNodeClick"
@pane-click="onPaneClick"
@@ -61,7 +62,7 @@
>