news 2026/9/15 21:18:08

CocoIndex 文档站内联 SVG 图解开发指南:基于 Astro 组件的形状语义化图表体系

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CocoIndex 文档站内联 SVG 图解开发指南:基于 Astro 组件的形状语义化图表体系

CocoIndex 文档站内联 SVG 图解开发指南:基于 Astro 组件的形状语义化图表体系

【免费下载链接】cocoindexIncremental engine for long horizon agents 🌟 Star if you like it!项目地址: https://gitcode.com/GitHub_Trending/co/cocoindex

本指南以dev/agent-skills/cocoindex-diagrams/SKILL.md及其配套参考文档为骨架,系统讲解 CocoIndex 文档站(docs/)内联 SVG 图解体系的完整开发方法论:从形状语义化的组件原语、调色板与共享样式,到"先布局、后组合、再预览验证"的标准工作流,以及多年迭代沉淀下来的常见陷阱。读完你将掌握在.mdx文档页中创建、编辑与评审高一致性技术图解的完整实战技能,并能直接复用到仓库中任意docs/src/content/docs/**文档页。

一、为什么文档图解要"组件化"而不是静态 SVG

CocoIndex 文档站的全部图解(任何位于docs/src/content/docs/**下的页面内嵌图)都以 Astro 组件形式编写,统一放在docs/src/components/diagrams/目录下。这个目录是文档图解的唯一事实来源(single source of truth)——早期由设计工具(Excalidraw、Figma、Sketch 等)导出的静态.svg文件(位于/public/img/**/*.svg)已被视为遗留资产,会随着组件化替换逐渐删除,不再继续编辑。

静态 SVG 的三个致命问题,正是组件化方案的动机(依据docs/src/components/diagrams/README.md):

  • 编辑需要往返设计工具:SVG 是"不透明"的产物,改一处布局就要重新走一遍工具链;
  • 无共享样式:每个图各自为政,颜色、线宽、字体漂移;
  • 难以评审:二进制式的大段坐标数据让 git diff 失去可读性。

组件化图解则免费获得四重收益:

收益说明
单一调色板(CSS 变量)改一处变量,全局生效
CSS:hover驱动的动画零 JS、SSR 友好,静态页面保持安静
组件边界处类型化 props标签、状态、高亮等以强类型接口暴露
可读的 diffgit 评审流畅,符合 README.md 中"模型来自cocoindex.github.io首页内联 SVG"的实践

docs/astro.config.mjs中通过@astrojs/mdx集成让 Astro 组件可以在.mdx中原生导入使用,这是整个体系能够落地的工程基础。

二、形状语义:以"含义"而非"外观"选择原语

图解体系的核心原则是shape carries meaning——形状本身传达语义,选原语要依据元素"是什么",而不是"看起来顺眼"。全部内联 SVG 由一组形状语义原语(primitives)组合而成,它们共享同一套调色板与样式(docs/src/components/diagrams/diagrams.css)。

2.1 基础形状原语

形状语义含义原语组件
尖角矩形数据(文件、chunk、行)DataBox
圆角矩形子系统 / 逻辑(Split、Embed、Drive Folder、Vector Database 等)LogicBox(支持memoized+statusprops 与插槽)
奶油色带表头容器一个 Processing Component(承载其他元素)ProcessingComponent(插槽使用局部坐标系;支持memoized+status
桃色带表头容器一个 CocoIndex App(承载其他元素)AppContainer(插槽使用局部坐标系)
子弹形(左侧平直、右侧圆角)目标状态(vector、输出文件、数据库行)TargetBullet
动画虚线带箭头流转 / 因果(A 产生 B、A 变换为 B)FlowArrow
静态虚线无箭头绑定 / 身份(X 绑定于 Y)Connector

这里有一个反直觉但重要的设计决策:所有非容器逻辑框(源、目标、数据、子弹形)共用同一种中性奶油色 + 酒红色填充与描边,语义区分完全由形状承担,而不是颜色。只有 App 容器保留桃色调用于视觉分组(dg-box--app),见 diagrams.css 中.dg-box.dg-box--component的注释。

2.2 正交标注:状态、缓存徽标与高亮

在原语之上,有一套与形状正交(orthogonal,可叠加在任意形状上)的标注体系,用于表达"这次运行中发生了什么":

Prop取值视觉表现
statenewupdatedremovedchangedidle(默认)掌绿色 / 金色 / 粉色 / 细粉色填充;removed的标签带删除线并弱化,hover 时显示原生deleted工具提示;状态级联通过直接子代 CSS 组合器阻止(详见陷阱节)
statuscache-readyrefreshing左上角徽标:缓存命中显示"对勾书写动画"(hover 触发),缓存未命中显示"旋转箭头"(hover 触发);两者在state="removed"时自动抑制
highlighttrue粗掌绿色描边,表示"当前文字正在讨论的元素"
memoizedtrue(作用于LogicBox/ProcessingComponent右上角酒红色备忘缎带,表示该函数/组件被 memo 化

memoized缎带、cache-ready徽标、refreshing徽标三个角标的精确位置与尺寸由原语自身内部计算——调用方只需传递容器参考角(MemoMark传右上角、StatusBadge传左上角),彻底消灭了散落各处的魔法数字偏移(magic-number insets),详见陷阱节。

2.3ShapeGroup基座:所有形状原语的公共底座

DataBoxLogicBoxTargetBulletProcessingComponent四个形状原语全部组合在一个共享基座ShapeGroup之上(ShapeGroup.astro),它集中处理了每个原语都会重复的公共关注点:

  • 外层<g transform="translate(x y)">与基础 class;
  • 状态修饰类 + 高亮修饰类的组合(dg-state-*dg-highlight);
  • state="removed"时的原生<title>deleted</title>工具提示;
  • 可选的StatusBadge(左上)与MemoMark(右上)徽标,且当state="removed"自动同时抑制——已删除的东西既没有缓存状态也没有可备忘的内容。

从 ShapeGroup.astro 源码可见其 props 接口与实现逻辑:

type State = 'idle' | 'new' | 'updated' | 'changed' | 'removed'; type Status = 'cache-ready' | 'refreshing';

当你需要新增一个形状原语时,必须组合在ShapeGroup之上,而不是从零重写外层<g>、状态类、<title>与徽标逻辑。参考 README.md 给出的标准写法:

--- import ShapeGroup from './ShapeGroup.astro'; // ... --- <ShapeGroup x={x} y={y} w={w} baseClass="dg-myshape" state={state} highlight={highlight} memoized={memoized} status={status}> <rect class="dg-box" x="0" y="0" width={w} height={h} rx="8" /> <foreignObject ...><div class="dg-fo-label">{label}</div></foreignObject> </ShapeGroup>

2.4 目录结构

docs/src/components/diagrams/ ├── README.md # 本体系权威参考 ├── diagrams.css # 调色板变量、共享类、@keyframes 动画 ├── primitives/ │ ├── DiagramFrame.astro # 外层 <svg> 包装(viewBox、aria 标签) │ ├── ShapeGroup.astro # 形状原语共享基座 │ ├── DataBox.astro # 尖角矩形 —— 数据 │ ├── LogicBox.astro # 圆角矩形 —— 子系统 / 逻辑 │ ├── TargetBullet.astro # 子弹形 —— 目标状态 │ ├── ProcessingComponent.astro # 圆角容器,插槽使用局部坐标 │ ├── AppContainer.astro # 桃色容器,CocoIndex App │ ├── MemoMark.astro # memo 角标(经 `memoized` prop) │ ├── StatusBadge.astro # cache-ready / refreshing 角标(经 `status` prop) │ ├── FlowArrow.astro # 动画虚线箭头 │ └── Connector.astro # 静态绑定线(无箭头) └── concepts/ ├── AppOverview.astro # Source → App → Target state(core_concepts 页) ├── AppExample.astro # PDF → markdown 总览(共享) ├── AppDef.astro # App 绑定主函数与参数(quickstart 页) ├── ComponentPerFile.astro # Drive → 逐文件 PC(Convert → a.md)→ Drive ├── FileProcess.astro # ComponentPerFile 的薄包装 + highlight ├── ComponentsFanout.astro # ComponentPerFile 的薄包装 + highlight ├── MountVsUseMount.astro └── ComponentWithChunks.astro # Drive → App(PC→Split→chunks→Embed→vectors) → VDB # 接受 `memoized` 与 `scenario` props

三、标准创作流程:六步走

第 1 步:先读参考材料

动手前首先通读权威参考 README.md(形状词汇、调色板变量、共享 CSS 类、动画约定、目录布局、MDX 嵌入模式),再结合本 Skill 自带的三个会话级参考:

  • workflow.md —— 预览循环(headless Chrome + base-path 陷阱)、如何裁剪与查看输出、重建纪律;
  • pitfalls.md —— 反复消耗迭代轮次的陷阱记录;
  • layout-patterns.md —— 布局惯用法(水平箭头、对称内边距、紧凑性、绑定 vs 箭头)。

浏览即可,不必背诵——设计时随时回查。

第 2 步:先设计布局,再写代码

任何非平凡图解都以.astro文件顶部的一段命名常量配置块开始,用具体数字勾勒位置。偏好绝对坐标 + 按内容定尺寸的viewBox,盒子尺寸与列偏移使用命名常量。

核心纪律是:容器尺寸由内容推导,而不是反过来。从内部宽度、间距、内边距出发计算:

APP_W = sum(cols) + (n-1) * GAP + 2 * APP_PAD_X

下游兄弟元素(Target System、右侧 Drive Folder 等)引用APP.x + APP_W,绝不硬编码 x 坐标;垂直方向同理——选取行中心点使得 top-pad == bottom-pad。这样迭代时四个方向的留白始终保持平衡。完整惯用法见 layout-patterns.md 的 "Balanced padding on all sides"。

标准配置块示例(出自 layout-patterns.md):

--- const VB_W = 980, VB_H = 380; const TOP_Y = 30, TOP_H = 330; const DRIVE = { x: 20, y: TOP_Y, w: 110, h: TOP_H }; const APP = { x: 160, y: TOP_Y, w: 664, h: TOP_H }; const VDB = { x: 844, y: TOP_Y, w: 110, h: TOP_H }; const PC_W = 510, PC_H = 128; const ROW1_CY = 130, ROW2_CY = 268; // ... ---

改一个常量即可让整图重新流动,无需在 JSX 里大海捞针。

正确与错误的容器宽度推导对比(layout-patterns.md):

错误做法——猜测容器宽度再往里塞内容:

const APP = { x: 140, y: TOP_Y, w: 700, h: TOP_H }; // 猜的 const FILE_DX = 24; const PC_DX = FILE_DX + FILE_W + 34; const PC_W = 360; // 右内边距:700 - (PC_DX + PC_W) = 256,远大于左侧 24

正确做法——由内容反推容器宽度:

const APP_PAD_X = 24; const FILE_W = 62; const PC_W = 360; const FILE_TO_PC_GAP = 34; const APP_W = FILE_W + FILE_TO_PC_GAP + PC_W + APP_PAD_X * 2; // APP_W = 484。左内边距 24 = 右内边距 24,由构造保证。 const APP = { x: 140, y: TOP_Y, w: APP_W, h: TOP_H }; const DRIVE_R = { x: APP.x + APP_W + 20, y: TOP_Y, w: 100, h: TOP_H };

对于水平内容行,通用公式为:

[pad_x] col1 [gap] col2 [gap] … coln [pad_x] container_w = sum(cols) + (n-1) * gap + 2 * pad_x

由构造保证左右相等;增删列也无需重新调参。垂直方向同理:单行内容垂直居中(content_y_top = (container_h - content_h) / 2);多行时选择ROW1_CY/ROW2_CY使首行顶部留白等于末行底部留白。注意容器自带约 28px 高的表头标签会占用顶部可用空间,要么计入"顶部内边距",要么让内容行保持在它下方。

第 3 步:用形状语义原语组合

严格按 2.1 节的语义表挑选原语。两个易混场景要分清:

  • 绑定 vs 流转:Drive Folder → 文件是绑定(文件本就来自该目录),用Connector;文件 → Processing Component 是流转(PC 处理该文件),用FlowArrow;Split → chunk、chunk → Embed、Embed → vector 均为流转,用FlowArrow;vector → Vector Database 是绑定(向量本就写入该库),用Connector
  • 两套坐标系:外层布局(Drive、App、Vector Database 之间的连线)用绝对坐标;ProcessingComponent/AppContainer的插槽内子元素以容器左上角为 (0,0) 使用局部坐标。任何视觉上要穿出容器的元素(如 vector → Vector Database 的绑定线)必须在容器标签之外用绝对坐标绘制。典型行循环(出自 layout-patterns.md):
{rows.map((row) => ( <g> {/* 绝对坐标:外层布局 */} <Connector d={`M ${DRIVE.x + DRIVE.w} ${row.rowCY} L ${FILE_X} ${row.rowCY}`} /> <DataBox x={FILE_X} y={row.rowCY - FILE_H/2} ... /> <FlowArrow d={`M ${FILE_X + FILE_W} ${row.rowCY} L ${PC_X} ${row.rowCY}`} /> <ProcessingComponent x={PC_X} y={row.pcY} w={PC_W} h={PC_H} memoized={true}> {/* 局部坐标:PC 内部,(0,0) = 容器左上角 */} <LogicBox x={PC_PAD} y={(PC_H - SPLIT_H)/2} ... /> {/* ... */} </ProcessingComponent> {/* 绝对坐标:从 PC 穿出到外部目标 */} {chunkCYs.map((cy) => ( <Connector d={`M ${PC_X + VECT_DX + VECT_W} ${cy} L ${VDB.x} ${cy}`} dashed={true} /> ))} </g> ))}

为可读性,源码中把外部空间与内部空间的代码块在视觉上分区。行中心ROW_CY先行定义,再由此推导文件 y、chunk y、embed y 等子元素位置——上下平移整行只需改一个常量。

第 4 步:用 foreignObject 渲染标签

所有带标签的原语(DataBoxLogicBoxProcessingComponentTargetBullet)都使用<foreignObject>内嵌 flex 居中的<div class="dg-fo-label">,让浏览器自动按盒子宽度换行。调用方只需传label="..."绝不要手动预拆分换行

CSS 侧(diagrams.css 的.dg-fo-label)通过display: flex+align-items: center+justify-content: center实现垂直水平双向居中,overflow-wrap: break-word+white-space: pre-line支持自动换行与\n显式换行。标签溢出时,正确做法是加宽盒子或缩短文案,而不是手工切行。

第 5 步:预览验证,看到再交付

"构建通过了"绝不是图解完成的证据。图解是视觉产物,代码层面永远看不到标签重叠、整行变暗、箭头样式错误这类小问题。必须运行预览脚本渲染成 PNG 亲眼确认(可用Read工具读回截图自查)。

scripts/preview.sh <docs-slug> # 示例:scripts/preview.sh programming_guide/core_concepts

该脚本(preview.sh)依次完成:

  1. docs/内执行npm run build构建 Astro 站点;
  2. docs/dist/rsync 镜像到临时目录下的docs/子目录(base path 关键步骤,见下文陷阱);
  3. 杀掉 8765 端口上的残留服务,在下一个空闲端口重新启动python3 -m http.server
  4. 用无头 Chrome(--headless=new)以1400x5200、scale 1 截取整页;
  5. 保存整页 PNG + 可选的裁剪图;
  6. 打印输出路径。

脚本还支持可选的裁剪参数定位图中目标区域:

scripts/preview.sh programming_guide/core_concepts 3300 600

整页截图通常很高,需要裁剪定位具体图解(workflow.md):

magick /tmp/dg-preview/full.png -crop 1400x500+0+3300 /tmp/dg-preview/crop.png

目标不在裁剪区内就调整 y 偏移(如+2500+3500+4000);需要细查布局时紧贴裁剪并裁掉周边正文。预览产物统一写入/tmp/dg-preview/,下次运行自动清理;端口卡死时可用lsof -ti:8765 | xargs kill -9释放。

第 6 步:依据视觉反馈迭代

任何非平凡图解都预期需要 2–4 轮预览循环——首轮渲染几乎必然暴露代码检查看不到的问题(标签与图标重叠、透明度异常、颜色漂移、箭头指向错误)。预算好迭代轮次,不要试图一次成型。只有不影响布局的纯文本/标签修正(如改错别字)可以跳过预览;凡是涉及坐标、形状选择或新原语的改动都必须预览。

四、动画纪律与无障碍

所有图解默认静止(idle by default),动效一律藏在.dg-root:hover之后,与首页模式一致,让静态页面保持安静(diagrams.css):

动画触发机制
dg-flow虚线箭头漂移root hoverstroke-dashoffset从 18 → 0 循环
dg-pulse脉冲圆点root hover缩放 1 → 1.6、透明度 1 → 0.55
dg-state-{new,updated,removed}边框脉冲root hover共享dg-delta-pulse:线宽 2.2 ↔ 4.2
dg-status-badge--ok对勾书写root hoverdg-check-draw:~0.6s 从左到右书写、保持 ~1.2s、复位循环
dg-status-badge--refresh箭头旋转root hoverdg-spin1.6s 线性无限旋转

新增@keyframes规则时,必须同时在diagrams.css底部的@media (prefers-reduced-motion: reduce)块中登记为animation: none !important,且.dg-step在此媒体查询下强制opacity: 1。所有动画不应引入运行时 JS——图解默认零 JS;只有确实需要 hover 之外交互(scrubber、点击分步)的极少数情况才允许将该图单独做成 React island,并复用相同的 SVG 原语,绝不为一帧 hover 动画加载整棵 React 树。

无障碍方面,DiagramFrame接受titledescprops,渲染为<svg>的子<title>/<desc>,并通过aria-labelledby/aria-describedby关联;role="img"已内置。state="removed"时原生<title>deleted</title>提供 hover 工具提示。

五、调色板与共享 CSS 类

调色板取自docs/src/styles/globals.css(与品牌规范一致),图解内禁止硬编码 hex 值,一律使用 CSS 变量:

CSS 变量Hex用途
--coral#BE5133流转箭头、桃色容器、refreshing徽标
--peach#E59A63App / Processing Component 填充(着色)
--palm#27E62Bnew状态、cache-ready徽标、highlight
--pink#FB6A76removed/changed状态、指纹失效
--maroon#532638主描边、MemoMark填充
--maroon-ink#2A121B正文墨色
--cream#FCF3D8默认填充、徽标内标记
--dg-gold#D4A835updated状态(图解局部变量,定义在.dg-root上避免泄漏)
--paper#FBF6E8图解背景

常用共享 CSS 类速查(完整定义见 diagrams.css):

  • dg-root—— 最外层<svg>包装,:hover规则的容器;
  • dg-box—— 基础描边矩形/路径(奶油 + 酒红),线宽 1.4;
  • dg-box--component/dg-box--app—— 桃色着色的组件 / App 容器(coral 描边);
  • dg-box--muted—— 淡虚线"外框示意"容器;
  • dg-label/dg-fo-label—— SVG 文本 / foreignObject HTML 标签;
  • dg-state-{new,updated,removed,changed}—— 增量状态(直接子代作用域);
  • dg-status-badge--ok/--refresh—— 状态徽标变体;
  • dg-highlight—— 粗掌绿描边("当前讨论元素");
  • dg-flow/dg-connector—— 流转箭头 / 静态绑定线;
  • dg-pulse—— 脉冲圆点;
  • dg-step-N(N=1–6)—— 渐进揭示的错峰延迟(0s 起每级 +0.15s)。

六、Delta 状态与缓存徽标的深层语义

6.1 Delta 状态(state prop)

state表达"本次运行中该元素发生了什么",由ShapeGroup以 wrapper<g>上的类应用。所有增量状态共享同一套运动词汇——.dg-root:hover上的边框脉冲:

state填充 / 描边标签处理hover 工具提示用途
idle(默认)奶油 + 酒红正常未变化
new掌绿色正常本次运行新增
updated金色正常本次运行原地变更
removed粉色删除线 + 弱化deleted本次运行删除
changed细粉描边(无填充脉冲)正常指纹传播信号(仅用于指纹传播类图解)

关键工程约束:状态规则必须使用直接子代组合器(> .dg-box),绝不能写成后代选择器。如果容器(如pcState="updated"的 ProcessingComponent)上的状态类向下级联,内部的每一个嵌套.dg-box(chunks、embeds、vectors)都会被染成金色。每个形状原语在自己的 wrapper<g>上各自持有状态,互不污染。同时,为了在着色的父容器背景下依然可读,所有 delta 状态的stroke-width提升到 2.2,hover 时dg-delta-pulse进一步推到 4.2。

6.2 缓存状态徽标(status prop)

status作用于LogicBox/ProcessingComponent,标注某元素在本次运行中的 memo 化行为:

  • cache-ready—— 掌绿圆盘 + 奶油色对勾;hover 时对勾从左到右"手写"绘制(stroke-dasharray 书写动画,约 0.6s),保持约 1.2s 后复位进入下一循环,语义是"已验证新鲜";
  • refreshing—— 珊瑚色圆盘 + 奶油色环形箭头;hover 时箭头持续旋转(1.6s 线性无限),语义是"缓存未命中,正在重新执行"。

两者在state="removed"时同时抑制(已删除的东西没有活动缓存状态)。徽标位于左上角,同时被顶边与左边平分,与右上角的MemoMark互为镜像。statestatus可正交组合:memo 化函数正在重跑 →status="refreshing";命中缓存 →status="cache-ready"

6.3 scenario 模式:多状态图解的"内容是数据"

ComponentWithChunks(ComponentWithChunks.astro)接受scenario?: Scenarioprop 描述逐行 / 逐 chunk 的覆盖。不要为每个"如果…会怎样"的场景创建一个.astro包装器——场景是内容(哪个文件变了?哪个 embed 命中了缓存?),不是可复用组件。场景直接内联在.mdx中、紧跟描述它的正文旁,让"我在展示什么"与"我在说什么"保持在一起,避免未来编辑漂移:

<ComponentWithChunks memoized={true} scenario={{ rows: [ { file: 'a.md', pcStatus: 'cache-ready', chunks: [ { label: 'chunk1', vectorLabel: 'vector1', embedStatus: 'cache-ready' }, { label: 'chunk2', vectorLabel: 'vector2', embedStatus: 'cache-ready' }, ] }, { file: 'b.md', fileState: 'updated', pcStatus: 'refreshing', pcState: 'updated', chunks: [ { label: 'chunk3', vectorLabel: 'vector3', embedStatus: 'cache-ready' }, { label: 'chunk4', vectorLabel: 'vector4', state: 'removed' }, { label: 'chunk5', vectorLabel: 'vector5', state: 'new' }, ] }, ]}} />

ComponentWithChunks的类型化场景 schema 定义了RowEntryfilefileStatepcStatuspcStatesplitStatechunks)与ChunkEntrylabelvectorLabelstateembedStatus),且实现了pcState="removed"时 chunk 状态级联为removed的继承逻辑(见其effectiveChunks计算),保证删除语义一致。无scenario时默认渲染两文件基线:a.md → chunk1/chunk2 → vector1/vector2、b.md → chunk3/chunk4 → vector3/vector4,全部idle

七、在 .mdx 页面中嵌入图解

.mdx页面中从站点根目录使用绝对导入路径,保证任意文档深度下均可解析:

--- title: Core Concepts --- import ComponentWithChunks from '/src/components/diagrams/concepts/ComponentWithChunks.astro'; ## Processing Component <ComponentWithChunks />

Astro 原生支持.mdx中的组件导入(经@astrojs/mdx,见 astro.config.mjs)。绝对路径以/src/...为根,跨深度稳定。

八、高频陷阱实录(来自真实迭代教训)

dev/agent-skills/cocoindex-diagrams/references/pitfalls.md记录了构建当前图解集时反复消耗迭代轮次的陷阱。以下是完整清单与修复要点:

1. 所有盒子渲染为纯黑症状:截图里图解全是黑色矩形,文字隐约可见但所有填充都是黑色。 原因:文档站配置了base: '/docs'(astro.config.mjs),构建后的 HTML 引用/docs/_astro/*.css下的 CSS;若在dist/直接起python3 -m http.server,CSS 会以/_astro/...路径返回 404。样式表缺失时var(--cream)var(--coral)等全部未定义,SVGfill回退为黑色。 修复:从包含docs/子目录(符号链接或dist/副本)的父目录提供服务,使/docs/_astro/...可解析。scripts/preview.sh已自动处理(rsync 到docs/子目录)。这是服务端问题,不是图解代码问题。

2. 行 / 内容以 35% 透明度变暗原因:dg-step+dg-step-N类专为渐进揭示叙事设计(如三面板"步骤 1 → 2 → 3"),默认透明度 0.35、仅 hover 时点亮。误用在本应静态全显的并行行上,就会整体变暗。 修复:从包裹行的<g>上移除dg-step;仅当有意做 hover 驱动揭示时才使用。

3. 标签溢出 / 窄盒内被裁剪原因:早期版本用 SVG<text>,不换行;手工切行(lines={['Split into', 'chunks']})笨拙。 修复:所有带标签原语改用<foreignObject>+ flex 居中<div class="dg-fo-label">,浏览器按盒宽自动换行,只需传label="..."

4. 魔法数字偏移散落各处原因:<MemoMark x={PC_X + 14} y={row.pcY + 4} size={12} />这类调用点内联不同偏移与尺寸,与容器尺寸隐形耦合。 修复:原语自持内嵌偏移与尺寸,调用方只传容器参考角(MemoMark传右上角);原语内部做translate(x - INSET_X - w, y)ProcessingComponent的表头与 memo 标记同理由容器原语自行定位。

5. 源 / 目标颜色意外分化原因:早期LogicBoxvariant="source"/variant="target"不同填充,源自不适用于文档图解的首页旧约定。 修复:所有非容器逻辑框统一中性奶油 + 酒红;语义区分由形状承担(TargetBullet的子弹形本身就与LogicBox不同),只有 App 容器保留桃色调。

6. 不同高度的箭头打错目标原因:所有箭头都指向目标盒的唯一 y 中心,导致多条箭头交叉。 修复:保持箭头水平——每条箭头在源元素的 y 坐标处射向目标左边缘。前提是目标足够高能容纳多条水平入口。

7. 绑定线上出现箭头原因:到处用FlowArrow,使绑定显得像因果流转。 修复:绑定用Connector(静态虚线无箭头),FlowArrow只用于因果流转。

8. MemoMark 实心黑、视觉过重修复:用珊瑚色描边 + 半透明珊瑚填充(fill: color-mix(in oklab, var(--coral) 22%, transparent)),在任意背景下可读且贴合品牌配色。

9. 容器内不对称内边距原因:把APP.w/APP.h硬编码成整数再往里塞内容,剩余空间全落在右 / 下侧。 修复:按第 2 步公式由内容推导容器尺寸;下游兄弟引用APP.x + APP_W

10. 容器状态类级联污染子元素原因:状态 CSS 写成后代选择器.dg-state-updated .dg-box。 修复:改用直接子代组合器.dg-state-updated > .dg-box。每个基于ShapeGroup的原语有自己的 wrapper<g>、自己的状态类、自己的直接子代.dg-box

11. 有状态容器内的新状态视觉不突出原因:默认线宽 1.4 的彩色状态描边在着色父背景下太细。 修复:dg-state-*规则统一把stroke-width提到 2.2,hover 的dg-delta-pulse推到 4.2。

12. 常驻动画干扰静态页面原因:旋转图标(refresh 徽标)在无人观看时也一直转。 修复:diagrams.css中每个动画默认静止、仅.dg-root:hover激活(dg-flowdg-pulsedg-delta-pulsedg-spindg-check-draw全部如此);新动画一律同规则门控,并在prefers-reduced-motion覆盖块登记。

13. 不看就报告完成症状:"构建成功了,图解完成",随后用户截图暴露重叠 / 黑盒 / 变暗内容。 修复:报告前必跑scripts/preview.shReadPNG。干净的npm run build只证明 Astro 组件能编译,不证明渲染正确。

九、创作纪律清单

  • 形状承载含义:按语义选原语,而非"看起来合适";
  • 禁止手动切行:标签溢出就加宽盒子或缩短文案;
  • 外层绝对坐标、插槽局部坐标ProcessingComponent的插槽以 (0,0) = 容器左上角渲染子元素;
  • 流转箭头统一用色:默认珊瑚色;variant="palm"/"muted"仅在语义需要时使用;
  • 绑定保持安静Connector(静态、虚线、无箭头)表示"X 绑定于 Y";
  • 四边内边距全平衡:容器内左 == 右、上 == 下,宽度高度由内容推导,下游兄弟引用推导出的宽度;
  • 优先紧凑:图解应在文档列宽(约 720px)下可读,仅在视觉叙事需要时才拉伸;maxWidth多在 720–960 之间;行距小到同族感而非割裂感;
  • dg-step只用于静态内容之外:默认 35% 透明度仅 hover 点亮,专用于渐进揭示叙事;
  • 所有动画默认静止:flow-drift、delta-pulse、check-draw、refresh-spin 一律.dg-root:hover门控;新增@keyframes必须在diagrams.css底部prefers-reduced-motion块登记;
  • 状态规则用直接子代组合器.dg-state-X > .dg-box,禁止级联;
  • 新形状原语组合在ShapeGroup:wrapper<g>、状态/高亮类、<title>deleted</title>工具提示、MemoMark/StatusBadge徽标(含 removed 抑制)全部由它接管,绝不重实现;
  • 多状态图解用scenarioprop:场景内联在 MDX 正文旁,不创建每场景一个.astro包装器;
  • 单图内联标记尽量精简:每个图解的内联 SVG 标记控制在约 30 行以内,超长就把重复分组提炼成原语(依据 README.md)。

十、启动模板

dev/agent-skills/cocoindex-diagrams/assets/starter.astro提供了一个最小的形状语义图解骨架(config-first 布局、带局部坐标插槽的ProcessingComponent、水平箭头、绑定连接线各一),复制到docs/src/components/diagrams/concepts/MyDiagram.astro后按需调整即可,无需从零起笔。模板中DiagramFrametitle/descprops 应填写面向辅助技术的有意义描述,viewBoxmaxWidth依据内容推导。

至此,从形状语义原语、状态/缓存标注体系、布局惯用法、动画纪律到预览验证闭环与陷阱防御,CocoIndex 文档图解的完整开发方法论已经贯通。遵循本指南,新图解通常可在 2–4 轮预览内达到与既有图解一致的视觉质量与语义精度。

【免费下载链接】cocoindexIncremental engine for long horizon agents 🌟 Star if you like it!项目地址: https://gitcode.com/GitHub_Trending/co/cocoindex

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 21:14:42

AI编程规范:构建可审计的人机协作契约

1. 这不是写给AI看的“说明书”&#xff0c;而是给团队留下的技术契约“项目中新增给AI制定的代码规范”——看到这个标题&#xff0c;第一反应不是“又一个AI工具配置文档”&#xff0c;而是&#xff1a;谁在用&#xff1f;用在哪&#xff1f;出了问题谁兜底&#xff1f;我带过…

作者头像 李华
网站建设 2026/9/15 21:13:46

扩散语言模型实战:从one-hot扩散到可控文本生成

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 21:06:23

Simulink二自由度车辆模型构建与应用

1. 项目背景与核心价值在车辆动力学研究中&#xff0c;二自由度模型是最基础也是最重要的分析工具之一。它能够有效反映车辆在横向和横摆两个自由度上的运动特性&#xff0c;而质心侧偏角和横摆角速度则是评估车辆操纵稳定性的关键指标。通过Simulink搭建这个模型&#xff0c;我…

作者头像 李华
网站建设 2026/9/15 21:04:57

CPython如何将SIGPIPE信号转为BrokenPipeError异常

1. 这不是你的代码错了&#xff0c;是 CPython 在“悄悄关窗”你写了个简单的管道操作&#xff1a;echo "hello" | python3 -c "import sys; print(sys.stdin.read().strip().upper())"&#xff0c;一切正常&#xff1b;但换成head -n1 | python3 -c "…

作者头像 李华