87 hand-built SVG figures in the anthropic-design language — for engineering docs, kernel & hardware work, product walkthroughs, and slide decks. Every figure follows the diagram-craft contract: sized to its content, ≥2 semantic hues, solid color dots, readable at every label. Copy any of them straight into your page. 87 张手工 SVG 图,覆盖工程文档、内核与硬件、产品演示、演讲汇报四类场合。每张都按 diagram-craft 工艺合约执行:画布贴内容、每图 ≥ 2 个语义色、实心色点、所有标签可读。点 Copy SVG 即可直接用进你的页面。
Architecture, flows, sequences, git history, states, deployment — one hue per layer or category, orange reserved for the focus, color always on solid dots and bars rather than flooded fills. 架构、流程、时序、git 历史、状态机、部署拓扑——一层一个色相,橙色只给焦点;颜色落在实心色点和色条上,不做大面积满填。
templates/diagrams/architecture.svg.
四层系统图。每层是 16-20% tint 容器加 4px 色条,节点是白卡加实心类别色点。模板:templates/diagrams/architecture.svg。
templates/diagrams/flow.svg.
带编号徽章的流水线,决策菱形是全图唯一的强调 tint 色块,失败回流走图下方灰虚线。模板:templates/diagrams/flow.svg。
templates/diagrams/railroad.svg.
唯一的规则:从起点环走到终点环,走得通的路径就是合法的——所以图上不需要任何条件标签。三种形状把活全干了:上方绕过 = 可省略、下方回环 = 可重复、并排分支 = 三选一;而在文法记号里,这三件事分别由方括号、花括号和竖线承担,长得都一样。它输在递归:记号一行就说清「term 里含 expr」,图只能指回上面那条轨。模板:templates/diagrams/railroad.svg。
The diagrams an embedded engineer actually draws: function control flow with error lanes, register bit fields, SoC blocks, bus waveforms, build chains, scheduler timelines. Real names, real offsets — copy and swap the content. 嵌入式工程师真正天天画的图:带错误车道的函数控制流、寄存器位域、SoC 框图、总线波形、编译链、调度时间线。真实的名字和偏移——复制后换内容即可。
return 0. Every diamond's yes branch drops straight down into the error lane, which is an unwind ladder read right to left — a request_irq failure enters at err_unmap and falls through err_free to err_out, while a kzalloc failure enters at err_out and returns immediately. The ladder's arrows point against the happy path because unwinding runs backwards. Vertical template: templates/diagrams/function-flowchart.svg.
驱动 probe() 横向排布:徽章 1 kzalloc、2 ioremap、3 request_irq,然后 return 0。每个菱形的 yes 分支垂直落进下方错误车道;车道是一把从右往左读的解绑梯 —— request_irq 失败从 err_unmap 进,依次落到 err_free、err_out;kzalloc 失败直接从 err_out 进、立刻返回。梯子的箭头与主路径反向,因为解绑就是倒着走。纵向模板:templates/diagrams/function-flowchart.svg。
templates/diagrams/register-bitfield.svg.
32 位控制寄存器拆两行:字段用 tint 跨格加实心顶条,保留位留白,访问权限 chip 和复位值放在数据手册该放的位置。协议帧格式同样适用。模板:templates/diagrams/register-bitfield.svg。
templates/diagrams/soc-block.svg.
子系统是 tint 分区,互连是中性脊柱——绝不画成饱和色带。唯一的橙色路径从 CPU 经 NoC 到 DDR,每个分区的内部连线用自己的色相。模板:templates/diagrams/soc-block.svg。
memcpy. The two strips are never merged: the same DRAM is 0x80_0000_0000 to the host and 0x18_0000_0000 to the device. Segment widths are not to scale. Template: templates/diagrams/interconnect-map.svg.
上半是拓扑,下半是每个视角各一条地址空间,中间那条虚线的落点就是这张图的结论:CPU 核用一条普通 store 就写得到斜纹那一段,指针可以直接递过去,不用 memcpy。两条带永不合并——同一块 DRAM 在 host 眼里是 0x80_0000_0000,在设备眼里是 0x18_0000_0000。段宽不按比例。模板:templates/diagrams/interconnect-map.svg。
templates/diagrams/protocol-stack.svg.
上面三条灰虚线是约定,不是线 —— 没有任何东西把 TLP 从一侧的传输层直接送到另一侧。全图唯一一条横向实线,是最底下那根 lane。跟着 ①→⑧ 读:字节在发送侧一层层下去,过一次线,再在接收侧一层层上来。协议分析仪只能挂在 lane 上、挂不到传输层,原因就在这张图里。模板:templates/diagrams/protocol-stack.svg。
4 GiB inside a region and three readings stay open (start, end, size). Symbol names sit in ink pills, literal constants in orange mono ones: TOLUD is a name, 0xC000_0000 is only what it happens to equal on this board. The orange line is the whole point: the gigabyte shadowed by the MMIO hole comes back above TOUUD — same DRAM, a second address. Heights are not to scale; low addresses at the bottom. Template: templates/diagrams/address-map.svg.
每条边界各拉一条引线,因为边界是一个地址、区域是一段范围 —— 把 4 GiB 写在某段中间,起点 / 终点 / 大小三种读法都成立。符号名走墨色药丸,字面常量走橙色等宽药丸:TOLUD 是名字,0xC000_0000 只是它在这块板上恰好等于多少。橙线是这张图的全部理由:被 MMIO 空洞盖住的那 1 GiB,在 TOUUD 之上重新露面 —— 同一块 DRAM,第二个门牌号。高度不按比例,低地址在下。模板:templates/diagrams/address-map.svg。
<g> at a time. Template: templates/diagrams/glyphs.svg.
一个圆角矩形能代表任何东西,所以它单独出现时什么也没说。这里每个字形都是一个意义固定的名词:梳齿承诺"深度有限、按序进出",尺状刻度承诺"这是被序列化的字节",骑在边界上的小标签承诺"这个接口属于这块 die"。在没有那样东西的地方画上它,就是在图上写了一句假话 —— 比画个方框糟得多。厂商 logo 一律不进:写型号文字,文件才改得动。用的时候复制一个 <g>。模板:templates/diagrams/glyphs.svg。
templates/diagrams/hw-timing-waveform.svg.
逻辑分析仪视角的 SPI 传输:一信号一行,片选承担橙色焦点,数据格里是真实 hex,建立/保持箭头标注关键边沿。模板:templates/diagrams/hw-timing-waveform.svg。
templates/diagrams/build-pipeline.svg.
内核编译从 .config 到可启动镜像:工具与产物沿橙色主链交替,设备树分支以金色汇入,最终交付物用焦点卡。模板:templates/diagrams/build-pipeline.svg。
templates/diagrams/sched-timeline.svg.
三条 CPU 泳道,ftrace 风格:任务块跨核保持同色,IRQ 抢占是唯一的橙色标记,迁移箭头画出负载均衡的动作。模板:templates/diagrams/sched-timeline.svg。
templates/diagrams/algorithm-ringbuffer.svg.
kfifo 环形缓冲画成直线阵列:占用格用 tint,in/out 用实心指针标记,回绕只画一条安静的箭头并写明掩码技巧。模板:templates/diagrams/algorithm-ringbuffer.svg。
templates/diagrams/soc-dataflow.svg.
没有 GPU 的显示通路,画成封装剖面:虚线以外是另一颗芯片。配置和数据故意画成两根不同的线——金色虚线是 APB,每帧 4 个字节;橙色实线是 AXI,每帧 8.3 MB。橙线从 p2 口进内存,那是 DDR 控制器给最高优先级的一个口,因为扫描输出等不了。模板:templates/diagrams/soc-dataflow.svg。
templates/diagrams/gpu-dataflow.svg.
同一块 DDR,多一个总线主设备。GPU 画成敞开的,好让人把它的 tile buffer(2 KiB)和 L2(256 KiB)跟一帧 8.3 MB 放在一起看——里面根本没地方装。七个徽章全部落在同一条地址条上,这就是整张图要说的:GPU 不是数据去的地方,它是第二个往内存里发地址的主设备。模板:templates/diagrams/gpu-dataflow.svg。
templates/diagrams/vram-dataflow.svg.
上一张图的对照:台式机显卡有自己的显存,于是有两条地址条、中间一根线,拷贝是真的。看清是谁在搬——徽章 ③ 是显卡自己的 SDMA 引擎在通过 PCIe 读主机内存,不是 CPU 把字节推出去。徽章 ② 那步最容易看漏:把页面锁住不让换出、再通过 GART 映射,就让它们变得可读,而一个字节都没搬——这也是左边两排装的是同一批页面的原因。图上每个符号名都是主线内核里的真名。模板:templates/diagrams/vram-dataflow.svg。
templates/diagrams/glyphs-memory.svg.
第二张构件表,管的是内存和地址怎么画。地址条给一段空间命名,边界值用黑药丸挂在条外——值属于边界,不属于哪一段。斜纹带是一扇窗,它不存东西,往那儿读会落到另一个空间去。页帧阵列一格一页,状态于是变成一眼看得见的图案。橙色 COPY 块是这张表上唯一一个「说了一句话」而不只是「一个形状」的构件:画上它就等于断言字节真的动了;不画,就等于说没动。模板:templates/diagrams/glyphs-memory.svg。
soc-block: not what is inside the chip, but what the chip talks to and over which interface. The DRAM and the panel are drawn as the parts they are — a green module with gold fingers and a notch, a sheet of glass with a driver IC and a flex cable — because a labelled rectangle makes you read before you recognise. Every link carries a black pill naming the interface, which is the part that carries information; the line itself carries none. Badges separate the two wires a pixel actually travels from the ones that only ever carry boot code or control bytes. Template: templates/diagrams/platform-block.svg.
soc-block 的板级对应:那张画片内有什么,这张画芯片跟外面的什么器件相连、走哪种接口。内存和屏按真实外形画——绿色模组带金手指和缺口,一片玻璃带驱动 IC 和排线——因为标了字的方框要先读才认得出。每条连线上骑一个黑药丸写接口名,那才是带信息的部分,线本身不带。编号把像素真正走的那两根线,跟只走引导代码或控制字节的线分开。模板:templates/diagrams/platform-block.svg。
address-map draws one space; this draws several, stacked, with dashed leaders joining the same block of content where it appears in each. That stacking is the whole point: “the device sees a different address” is impossible to show on one bar. A translation box sits between each pair of layers and names who does the translating. The closing line is the one to keep: a pointer alone is never enough, because it is only meaningful together with the space it came from. Template: templates/diagrams/address-spaces.svg.
address-map 画一个空间,这张画好几个空间叠起来,用竖虚线把同一块内容在各层的位置连上。叠起来正是关键:「设备看到的地址不一样」这件事,在一条地址条上根本画不出来。每两层之间放一个翻译盒,写清是谁做的翻译。要记住的是图脚那句:光有一个指针永远不够,它只有连同它所属的那个空间一起说,才有意义。模板:templates/diagrams/address-spaces.svg。
templates/diagrams/copy-vs-share.svg.
上下两半用完全相同的坐标,只差一处。上半在地址条的两段之间放了一个橙色 COPY 块,于是同一张图存了两遍;下半两条箭头落在同一段上,全图找不到一点橙色。之所以要这么画,是因为文字定不了这件事——「交给它」「发过去」「上传」对两种情况都说得通。读者学会这张图,就拿到了一个能用在别处的判断依据:没有橙块,就没有拷贝。模板:templates/diagrams/copy-vs-share.svg。
prefers-reduced-motion — so it halts for readers who ask for less motion, halts under html[data-motion-freeze], and halts in every screenshot, which keeps captures byte-identical between runs. All three were tested, not assumed. Template: templates/diagrams/dataflow-animated.svg.
这张图动,是因为动作本身带着一条信息——只有这种情况才允许动。流动的线是硬件一直在走的通路:每一帧、每一行,只要屏亮着就没停过。静止的线则是发生一次就完了:徽章 ② 是软件每帧唯一的那次寄存器写,它被刻意画成全图唯一不动的箭头。静态图说不出这个区别——两者都只是一根带箭头的线。动画用 CSS 写而不用 SMIL 也是刻意的,因为只有 CSS 认 prefers-reduced-motion:读者要求减少动效时它会停,页面加 html[data-motion-freeze] 时会停,截图时也会停,于是每次截出来的图逐字节相同。这三条都实测过,不是想当然。模板:templates/diagrams/dataflow-animated.svg。
templates/diagrams/page-flip.svg.
同一张底图画两遍,中间隔着 vsync。两半的地址条逐字节相同——两块缓冲,位置一样、大小一样。变的只有寄存器里的值,以及那条蓝色流动线拐弯的位置。拐点右移,就是整个「翻页」。线在流,是因为扫描输出从来没停过读;翻页改的只是它从哪儿读。两半用完全相同的坐标是刻意的:只留一处差别给眼睛找,而那一处差别的大小,就是这件事真实的大小。模板:templates/diagrams/page-flip.svg。
templates/diagrams/gpu-memory-flow.svg.
每条连线都是会流动的虚线,虚线段朝数据走的方向走——于是「方向」不再是要读出来的东西,而是看得见的东西。两头都传的连线画成上下两条反向流动,而不是一条双箭头线:一条线上的虚线只能朝一个方向走,画成双箭头等于在最容易误解的地方写「方向不明」。顺着箭头看,没有一条线从一个主设备连到另一个主设备——没有谁把东西交给谁,它们只是在同一批地址上碰面。模板:templates/diagrams/gpu-memory-flow.svg。
templates/diagrams/vram-copy-flow.svg.
独立显卡那种情况,画成方向不会读错的样子。那根线画成两条反向流动的:请求从显卡去主机内存,数据反向回来。请求发起在显卡这边,所以这次拷贝是拉不是推——发起方是显卡自己的搬运引擎,不是处理器。这跟片上系统是同一条规则:谁要数据谁发读请求,变的只是内存的块数。画成一条双箭头线就会含糊,而含糊正是误解住的地方。模板:templates/diagrams/vram-copy-flow.svg。
templates/diagrams/arm64-display-path.svg.
一颗 ARM64 手机芯片上一帧的全程,画成上下两行加中间一条内存。上面的往里写,下面的往外读,没有一根箭头从一个模块直接连到另一个模块。把内存画成横贯全图的一条、而不是流水线上的一站,正是这张图的用意:模块之间不传帧,它们只是轮流去碰同一批地址。每根线都标了总线类型和每帧多少字节。停 ⑥ 是那条内存,也是全程唯一装得下一整帧的地方;上面的 ①—⑤ 都在往里写,下面的 ⑦—⑩ 都在往外读。模板:templates/diagrams/arm64-display-path.svg。
templates/diagrams/what-is-a-frame.svg.
把一个关于大小的论证画出来而不是说出来。一帧变成一把 660 像素的尺子,片上每一块存储再按同一比例画在下面:L2 是 33 像素,显示控制器的行缓冲 8 像素,GPU 的 tile 缓冲 1 像素。下面一条把这三个放大 12 倍,否则根本看不见。同样这些数字列成表格,读者点点头就翻过去了;尺子不给这个机会。模板:templates/diagrams/what-is-a-frame.svg。
templates/diagrams/gpu-tile-render.svg.
GPU 怎么画一帧它装不下的东西。屏幕是 10 125 个小格,一格的光栅化、深度测试、混合全在片上的 tile 缓冲里做完,只有做完的那一格才写出去。下面对比的是立即模式:三层重叠就是每像素六次外部访存。分块是个带宽决策不是算力决策——这也是它先出现在手机上的原因。图里 ②③④ 三步全在片上做完,只有 ⑤ 碰了一次内存——这一格的全部访存就是那一次。模板:templates/diagrams/gpu-tile-render.svg。
templates/diagrams/display-controller-inside.svg.
六个硬件窗口各用自己的取数 DMA 从内存里拉自己那一层;选择器可以把任一层送到任一个槽;一个混合器在像素路过时把它们叠好。叠好的结果一个字节都没回内存,直接以像素流出芯片。结构照的是厂商自己写进驱动头部注释的那张框图——这比我推测「显示控制器里大概有什么」要可靠得多。模板:templates/diagrams/display-controller-inside.svg。
templates/diagrams/buffer-roles.svg.
三帧并排,两个矩形在每一列都画在完全相同的坐标上。地址只在行首标一次而不是每列一份,这件事本身就是论点:三列画的是同两块内存。变的只有颜色。坐标不动是刻意的——它只留一处差别给眼睛找,而那处差别是角色,不是位置。模板:templates/diagrams/buffer-roles.svg。
templates/diagrams/dsi-panel-inside.svg.
整条通路上唯一一处信号形态真的变了的地方:片内是 24 根并行线,出芯片是四对差分线上的串行比特,进屏又变回并行——源极驱动握着一整行子像素,栅极驱动决定 2400 行里哪一行接收它。只有一根线是朝回走的:TE 信号,屏反过来告诉芯片「我刚扫完一遍」。顺 ①②③ 看是串行化,④ 是屏里那颗把包解回并行的芯片,⑤⑥ 才是真正去点亮玻璃的两组驱动。模板:templates/diagrams/dsi-panel-inside.svg。
templates/diagrams/bus-tenants.svg.
共用一块内存的代价——这一组里其他每张图都把它当成免费的。六个主设备按同一把带宽尺子排开,一条深度有限的请求队列,一个按误了会有什么后果而不是按到达顺序服务的内存控制器。不对称正是重点:GPU 晚了掉一帧没人看得出来,扫描输出晚了行缓冲会空,而像素时钟不会等。模板:templates/diagrams/bus-tenants.svg。
templates/diagrams/display-vocabulary.svg.
术语表的地图。每个词挂在它所属的那个硬件下面,而有四个词底下什么都不挂——vsync、翻页、撕裂、欠载 是时刻不是地方。把这四个单拎出来正是这张图存在的理由:在框图上找一个时刻,是能把自己困住很久的一种找法。模板:templates/diagrams/display-vocabulary.svg。
templates/diagrams/display-triage.svg.
把同一组图倒过来读,变成一个排查顺序。每一行形状相同:症状、它其实是哪个机制在报警、先查哪一站、别先查哪里。第四列比前三列值钱——查显示问题最常见的浪费是从通路最末端开始,因为最后那几个寄存器最好读,而它们恰恰最不可能出错。模板:templates/diagrams/display-triage.svg。
templates/diagrams/cross-section.svg.
剖面图只有在读者知道「从哪儿切的」时才成立,所以平面图上要画剖切线,还要画两个箭头说明你朝哪边看。十二层里没有一层塞得下文字,于是名字一律用引线引到外面。TFT 玻璃上那个虚线框用两条线连到放大面板,不是一条——一条读起来是「指向某处的箭头」,两条才读成「这一块,放大」。真正的内容是放大面板本身:显示用的公共电极和触摸用的发射电极是同一片金属,所以显示侧一停,触摸跟着停,而触摸寄存器读回来全是正常值。模板:templates/diagrams/cross-section.svg。
templates/diagrams/exploded-view.svg.
剖面图能说清谁挨着谁,但说不了「先装哪个」和「还拆不拆得下来」——而这两件事才决定一块板子能不能修。所以所有件挂在同一根直轴上、间距相等;编号走的是装配顺序,不是从上到下 —— ① 基板、② 中介层、③ die、④ 填胶加盖、⑤ 最后整颗上板。边框把剩下的话说完:实线表示还能拆开,虚线表示胶固化或焊料回流之后就回不去了。左边那张成品缩略图不是装饰,没有它,右边只是一列矩形。模板:templates/diagrams/exploded-view.svg。
templates/diagrams/debug-map.svg.
一张不说「怎么看里面」的架构图,只让读者知道系统长什么样,还是不知道该敲什么。这张把具体路径钉在每张卡下面,药丸按后果上色:绿色只读,金色会改硬件或内核状态——这个区别在凌晨两点、在别人的板子上最要命。左边那一列才是真正的入口,因为没人是捧着方块图进调试现场的,进来时手里拿的是一个现象。模板:templates/diagrams/debug-map.svg。
templates/diagrams/magnitude-ruler.svg.
十二个数字跨了 1.5 亿倍,线性刻度放不下——底下那条小图就是硬放的结果,十一个点叠在同一个位置上。对数轴放得下,代价是一条义务:必须在图上写明「等距 = 十倍」,否则读者会不出声地把每一段都读小十倍。下面那排「换成人类尺度」的卡片,才是让这把尺子变成论据的东西。「慢十万倍」是一句话,「一秒 对 一百九十三天」是一张图。模板:templates/diagrams/magnitude-ruler.svg。
templates/diagrams/pinout.svg.
两样东西必须同时在页面上:按实物排布画出来的那一排焊盘,和「每一根是什么」的表。光有表,没法拿实物对着核;光有排布图,读者不知道每根是什么。差分对用一个括号括起来,而不是并排两行表格——一对被读成两根独立的脚,就会被当成两根独立的脚去布线。橙色那个框是整张图存在的理由:左右取决于你从哪一面看,所以不写清「从哪面看」、不标 1 脚的引脚图,是不能用的。模板:templates/diagrams/pinout.svg。
templates/diagrams/abstraction-ladder.svg.
任何技术页面都靠抽象运转,而每个抽象都是有人决定不再画里面的那个盒子。这个决定通常是隐形的:读者遇到那个三角形时它已经关着了,然后在第一个不按常理出牌的变体上卡住。三格就能补上——每一格打开上一格交过来的那个符号,而每个折起来的符号都带着自己的晶体管数,所以这条阶梯从不隐藏一层抽象的价钱。三级是实际的上限,再多读者就跟丢了「谁装着谁」。模板:templates/diagrams/abstraction-ladder.svg。
templates/diagrams/state-triptych.svg.
展示三个状态的常规做法是画三张图,常规结果是读者把电路重新找了三遍,却始终没注意到到底哪里变了。改成把每一个坐标都锁死:眼睛没有东西要重新解析,唯一还在动的就是那个差别。这里颜色承担了全部论证,所以它的含义对整张图只定义一次——在几格之间会变的图例,比没有图例更糟。三格从左到右还读成一个故事,而不是一份清单。模板:templates/diagrams/state-triptych.svg。
templates/diagrams/process-steps.svg.
六张独立的图,会让读者在每一格里重新找一次这个零件,到第三格他已经不再对比了。锁死坐标,这一排就不再是图片:眼睛不动,变化在动。然后只把这一步新增的东西描出来,读一步的代价就从「对比」降成「看一眼」。从 ① 读到 ⑥,读的是同一个零件被造出来,不是六个零件被介绍一遍。每格下面那行——这个零件还救不救得回来——是工序图通常会省掉的,也正是排期真正取决于的那一行。模板:templates/diagrams/process-steps.svg。
templates/diagrams/scale-ladder.svg.
一条放大链,每一跳都要三样东西:一个虚线框说明下一格看的是哪一块、两条线把这个框带进下一格、以及一个真实尺寸,好让「放大三倍」和「放大五十倍」区分得开。底下那把尺子不是装饰——四格在页面上等距排开,在现实里差得很远,没有尺子,排版自己就在宣称那个错误的比例。两条线这个约定,跟剖面图挂放大面板用的是同一个。模板:templates/diagrams/scale-ladder.svg。
templates/diagrams/see-inside.svg.
「把里面画出来」不是一种画法。切开答的是谁挨着谁、多厚,代价是只看得到那一刀所在的平面;透视答的是里面有几个、怎么摆,代价是重叠处会糊;拆开答的是什么顺序、还拆不拆得开,代价是真实的相邻关系没了。三种里最该少用的是透视——它是唯一一种失败得很安静的。模板:templates/diagrams/see-inside.svg。
templates/diagrams/highlight-in-place.svg.
密图每一步重画一次,读者每一格都要重新找,到第三格已经不再仔细看了。坐标全锁死、其余全中性,只让一行或一个单元站出来。第一格那个虚线框干的是另一半活:把一个抽象名词钉在物理结构上——这就是读者对「页」这个词点头,和真知道它在哪,之间的区别。模板:templates/diagrams/highlight-in-place.svg。
templates/diagrams/isometric-stack.svg.
正视图能说清每一层的厚度,却说不了那两颗芯片是并排还是前后。等距两样都能说,条件有四条:用真正的变换而不是随手画的斜边、每个标注保持正立、三个面用同一 hue 的三档平涂而不是假打光、以及必须有一条尺寸线——因为在这种投影里看起来一样大的两个面,实际可能差一倍。当初值得禁的从来不是投影,是投影阴影、透视和拿渐变冒充光源。模板:templates/diagrams/isometric-stack.svg。
Seven figures for the two things hardware and kernel work keeps asking for: what the silicon looks like inside, and what the code's data actually points at. Each one carries a rule you cannot see in a block diagram — a device card pinned to its own address window, a tile joined at its ring stop, an arrow that leaves the exact field holding the pointer. 七张图,画硬件和内核工作里反复要画的两样东西:芯片里面长什么样,代码里的数据到底指向哪。每一张都带一条方块图看不见的规矩——设备卡钉在自己的地址窗口上、瓦片挂在自己的站点上、箭头从真正持有指针的那一行出发。
templates/diagrams/system-topology.svg.
PCIe 树和物理地址空间画在同一张图里。每根线标接口宽度和总线号,每张设备卡标 BDF 和 BAR 大小,虚线引线从卡落到地址条上属于它的那一段。拆成两张图,读者就得自己在脑子里做这个映射——而出错的恰恰是这一步。模板:templates/diagrams/system-topology.svg。
templates/diagrams/die-floorplan.svg.
二十块瓦片,每块是一个核加它自己那片缓存,瓦片之间跑互连轨,交叉点就是站点。瓦片挂在自己的站点上、不是连在轨边上——一次访问的延迟取决于跳了几站,靠的就是这个区别。徽章 1–3 追一次未命中一路走到内存控制器。模板:templates/diagrams/die-floorplan.svg。
templates/diagrams/datapath.svg.
四路组相联查找画到器件一级:地址拆分、译码器选中一组、四个比较器同时比、匹配线一边驱动多路选择器一边进或门抬起 HIT。way 1 的 valid 是 0,它的比较器永远不会成立——故意留死这一路,valid 位才讲得清。徽章 A–E。模板:templates/diagrams/datapath.svg。
templates/diagrams/packet-encap.svg.
同一个报文走过三层,画在一把 8 px/字节的标尺上,所以每根条的宽度就是它的字节数。两条竖虚线钉住最初那 80 字节:下层加的东西一律长在外面,绝不进到里面。窄到装不下标签的字段用括线引到边上写,不缩字号。模板:templates/diagrams/packet-encap.svg。
templates/diagrams/terminal-annotated.svg.
十四行真实的 PCI 枚举输出,只加标注、一个字符不改。五个徽章把行钉到右栏说明;高亮块画在文字下面,位置由字符下标算出来——每行都用 textLength 锁死了字符步进。讲的事:一个 256 MiB 的 BAR 挂在 firmware 只给了 1 MiB 的桥窗口后面,接着就是 -12。正常的 nvme 那几行是故意留在画面里的。模板:templates/diagrams/terminal-annotated.svg。
templates/diagrams/struct-graph.svg.
task_struct → mm_struct → maple tree → 三个 VMA,每根箭头从真正持有指针的那一行出发,落在目标卡片的标题栏上。起点精确到字段、终点是整个对象——这个不对称就是重点。兄弟对象只详画一个,其余只留区分它们的那几行。字段名对过 v6.6 的 include/linux/mm_types.h。模板:templates/diagrams/struct-graph.svg。
templates/diagrams/bus-fabric.svg.
主设备在轨上方、从设备在下方,桥再往下接一条更窄的轨和它自己的外设。每条引下线用斜杠加数字标位宽,轨上写跑在它上面的通道名。一次读事务去程实线、回程虚线,离轨 12 px——8 px 时实测糊进轨里看不见。图脚明写:轨是一种画法,不是拓扑论断。模板:templates/diagrams/bus-fabric.svg。
Six figures for the two questions that follow every kernel bug: who calls whom across which boundary, and when did it actually run. Three draw structure — the kind of every edge, the place a stack stops being a call chain, the core everyone else waits on. Three draw time — the gap between raising work and running it, the deadline a frame has to beat, the order a panel has to be woken in. 六张图,回答内核问题后面永远跟着的两问:谁隔着什么边界调用了谁,以及它到底什么时候跑的。三张画结构——每条边是哪一种、栈从哪里起不再是调用链、大家在等哪个核。三张画时间——把活扔出去到它真跑之间的间隙、一帧要赶的 deadline、屏必须按什么顺序唤醒。
templates/diagrams/call-graph.svg.
三个驱动,每条边按种类画:细实线是同栈直接调用,空心箭头表示目标是运行时才定的结构体成员,金色虚线是换了执行上下文的异步交接,闪电是硬件事件,点线是完成通知往回走。结论在图脚:grep 只找得到黑色实线那几条。模板:templates/diagrams/call-graph.svg。
templates/diagrams/call-stack.svg.
九帧 oops backtrace,中间横着一条断层线。线以下是 kworker 骨架,那不是调用链——`process_one_work` 调用的是队列里排到的任何东西。你真正要找的调用者早些时候在别的上下文里跑了 `queue_work()`,它被画成旁边一张虚线幽灵卡,因为它根本不在这张栈上。模板:templates/diagrams/call-stack.svg。
file:line where it is called, right-aligned in its own column and joined to its card by leader dots; the level with no line to give says why instead, with no dots. The dashed card is the call someone deleted, and everything under it is dimmed because it no longer runs. The dark cards are read from the files at those lines by the generator, not retyped — so return 1 cannot quietly become return 0 on the way into the figure. The grey arrow at the bottom is where that value lands. Generated from design-review/references/callsites/build-manifest/figure.chain; template: templates/diagrams/call-site-locator.svg.
两条彼此不调用的链,画成能看见它们之间那道耦合。每一层右边是它被调用的那一行的 file:line,单独成一列、用引导点线连回卡片;给不出行号的那一层就直说为什么,不画点线。虚线框是被人删掉的那次调用,它下面的全部变灰,因为已经不会跑了。深色卡里的原文是生成器按行号从文件里读出来的,不是手抄 —— return 1 不可能在进图的路上悄悄变成 return 0。最下面那道灰箭头是这个返回值落到了哪一层。源:design-review/references/callsites/build-manifest/figure.chain;模板:templates/diagrams/call-site-locator.svg。
templates/diagrams/runtime-timeline.svg.
一次 DMA 完成依次走过硬中断、软中断、kworker 和用户线程,共用一根微秒轴。轴下三条括线给数字:中断到 handler 8 µs,raise 到 tasklet 跑起来 6 µs,`queue_work()` 到 worker 真跑 65 µs。workqueue 不是「慢一点的 tasklet」,是晚一个数量级——worker 就是个普通线程,要排队等调度。模板:templates/diagrams/runtime-timeline.svg。
templates/diagrams/frame-pipeline.svg.
六条硬件泳道铺在一个帧周期上,下面同轴画 vsync 和 TE。内存那条拆成两根小条,因为它同时在服务两边——GPU 在写后台缓冲、扫描输出在读前台缓冲——GPU 一忙扫描输出就 underrun,原因就是这个争用。徽章 1 vsync 中断锁住帧缓冲地址,2 GPU 发出 fence,3 翻页入队,4 扫描输出结束,5 下一个 vsync 让后台缓冲上台。越过徽章 5,面板就重复上一帧。模板:templates/diagrams/frame-pipeline.svg。
templates/diagrams/multicore-calls.svg.
四条 CPU 泳道共用一根微秒轴。CPU 0 拿着自旋锁、向其余核发 IPI,然后等每一个应答。CPU 3 有一段长时间关中断,它的应答最晚到,于是 CPU 0 阻塞多久由它说了算。应答箭头必须画出来:只画扇出读作发完就走,画上应答才成为一次等待。模板:templates/diagrams/multicore-calls.svg。
templates/diagrams/power-sequence.svg.
电源轨、时钟、复位、链路状态、初始化命令、背光,按事件排而不按线性时间——约束跨了四个数量级,按真实比例画的话 10 µs 那段复位脉冲是 0 像素。括线带着不等号给真实数字,顶上那条横条说明每一段归哪个面板回调管。下电是严格逆序,每一步都要,包括那些等待。模板:templates/diagrams/power-sequence.svg。
templates/diagrams/flame-graph.svg.
一个方块有两个维度,大多数图只花掉一个。同一份采样在这里画了两遍:画成调用关系图,每个方块的宽度由名字长度决定;画成火焰图,宽度就是采样占比。横轴不是时间——相邻两块并没有先后关系,把它从左往右当时间线读,是这类图第一号误读。又高又细的塔是一条几乎不花时间的深调用链,而它恰恰最先抓住眼睛。模板:templates/diagrams/flame-graph.svg。
templates/diagrams/queue-pressure.svg.
三个负载下的三条队列,下面那条曲线是第三格为什么长那样的原因。从 50% 忙到 80% 忙,等待变成四倍;从 80% 到 95%,在此之上再乘五倍。轴是线性的,体验不是——而这恰恰是只画队列说不出来的事。这条形状的前提是单服务台、随机到达,真实系统有突发,弯得更早——把它当坏消息的下限,别当估计值。模板:templates/diagrams/queue-pressure.svg。
Window skeletons are the highest-yield figures: a browser frame, a terminal, a phone. Real labels beat gray placeholder bars — give the mock one orange action and let everything else stay quiet. 窗口骨架是性价比最高的图:浏览器框、终端、手机框。真实文字标签比灰色占位条更可信——给 mock 一个橙色动作,其余保持安静。
A slide gets one idea per figure: a big number, a single highlighted bar, a roadmap with today marked. Charts default to soft blue; orange appears once, where you want the room to look. 一页幻灯片一个观点:大数字、单根高亮柱、标出"今天"的路线图。图表默认柔蓝;橙色只出现一次,落在你想让全场看的地方。
templates/diagrams/hierarchy.svg.
编排树:一个协调者,每类 worker 一个色相,icon tile 替代裸盒子。换掉标签就是一张组织架构图。模板:templates/diagrams/hierarchy.svg。
templates/diagrams/cheatsheet.svg.
十二个读者可能带着来的问题,每个指向回答它的那种图。这个形式的意义在它背后那道检验:把一张图截下来,发给一个没读过这个页面的人,看他能不能据此做事。大多数图过不了,因为页面一直在悄悄替它们提供四样东西——标题、一句话说它答什么、带日期的出处、以及边界。一张要自己出门的卡,这四样得自己带上。模板:templates/diagrams/cheatsheet.svg。
Ten figures for documents that explain how a tool decides: which gate stops which path, which check catches which failure, where a reading goes stale, what a wildcard swallowed. They came out of rewriting a sixteen-page design document where none of the existing types fit. Each one answers a question that a table or a flowchart leaves the reader to work out by hand. 十张图,给「讲一个工具怎么判断」的文档用:哪道关卡拦下哪条路、哪道检查抓哪种问题、一个读数在哪一刻就旧了、通配符到底吞掉了什么。它们是整改一套 16 页设计文档时画出来的——那时图库里没有合适的画法。每一张回答的,都是表格或流程图会留给读者自己去一行行对的那个问题。
templates/diagrams/path-gates.svg.
五条路通向同一张表,路上横着四道关卡。每道关卡在每条路上只用四种记号:实心条是真拒绝;虚框是会跑但放行(只报警、策略处在审计模式);灰字是这条路它根本看不见。碰到第一根实心条之后那条线就变淡;一根实心条都没碰到的那条路,带着颜色一直走到表。对照表也装得下这些格子,但读者得把每一行自己串起来才知道停在哪——这里停在哪,就是线变样的地方。做成步进图时,第 k 步装上第 1 到 k 道关卡,所有步从同一张表生成,默认显示四道都装上那一步。模板:templates/diagrams/path-gates.svg。
templates/diagrams/coverage-dots.svg.
竖着是六种会出的问题,横着是四道检查。实心点是会让发布失败;灰色胶囊是只打印、不判失败;× 是故意不给这道检查;空白是没人看。右边一列直接说出每一行的形状:第 1、3、4、5 行各自只靠一道检查;第 6 行谁都抓不到——那不是图画漏了,是下一道该写的检查。第 4 行看着有两道检查,其实单元测试那道只打印、不判失败。再竖着读每一列:没有两列长得一样,所以没有哪一道是多余的。模板:templates/diagrams/coverage-dots.svg。
templates/diagrams/where-when-grid.svg.
横带是地方——扫描读的是什么、真正在跑的是什么;竖列是时刻——构建那一刻、之后几周、重扫这一刻。构建时打出来的那个数,画成盖在它所依据的那两行上的一个戳;编号徽章钉在每种失效真实发生的那一格。徽章 1 在构建那一刻就已经成立,只是落在扫描根本没读的那一行;徽章 2 不需要任何人动手,等着就会发生。重扫那一列读的是另外两行,照样漏掉徽章 4。模板:templates/diagrams/where-when-grid.svg。
*, and draws the wildcard cell as wide as what it swallowed: one segment in a segment glob, three in a string glob. Part B points a tool at a sub-directory: everything left of the dashed cut is gone, and a rule that names a segment over there quietly stops matching — the file it was written to exclude syncs. Template: templates/diagrams/segment-align.svg.
路径一段一格,每一行里同一段都在同一个横坐标上,眼睛比的是列,不是两串字。上半张把同一条规则放进两种 * 语义里,通配那一格画成它吞掉的那么宽:按段匹配只吞一段,按字符串匹配吞三段。下半张把工具指向一个子目录:虚线那一刀左边的全部没了,规则里落在刀左边的那一段一失效,整条规则就不声不响地不再命中——它本来要排除的文件照样被同步出去。模板:templates/diagrams/segment-align.svg。
templates/diagrams/verdict-tree.svg.
同一种画法的两个变体。A:左边是等宽字体的目录树,右边每个判定方一列;两方判得不一样的那一行整行变色——同样两行忽略规则,git 和 docker build 理解得不一样,其中一处差别把一个密钥文件送进了构建上下文。B:从一个不存在的路径往上找,找到第一个还在的祖先,先在那一层问两个问题,再决定这条记录是不是真没了:一个空的挂载点会让它下面的一切看起来都被删了。模板:templates/diagrams/verdict-tree.svg。
templates/diagrams/count-flow.svg.
竖条高度就是条数(每条 6 px),所以每一次分流在图上都得加得起来:31 = 19 + 12,12 = 9 + 3。半透明的带子把每一份带到它去的地方。从第 3 步伸出来的那根虚线细支后面没有带子——那 2 条新发现根本不在这一批里,少的这条带子正是要说的话:复测一张延后清单,清单会变短,也会变长。左边的自测画成卡片、不画成竖条:940 条测试全绿不是「发现了几条」,按比例画出来就等于宣称它是。模板:templates/diagrams/count-flow.svg。
templates/diagrams/leaf-groups.svg.
同一个检查「给不出答案」的十种情况,按出错的地方分成四支,不串在一条主路径上——这里本来就没有主路径。每片叶子写四样:哪种情况、结局取决于哪一个事实、结局(色点)、代价(灰字)。底部横框是唯一一条跨分支的对比:A1 和 A4 失败的方式一模一样,却倒向相反两边,因为把健康检查拦下,本身就是一次停机。模板:templates/diagrams/leaf-groups.svg。
/ci/web, because the cd inside the parentheses ended at the closing bracket. The last row changes one input, and only the two cells that depend on it go dark. Template: templates/diagrams/text-steps.svg.
CI 任务里的一行命令走五步加工,每一段在每一行里都钉在同一列:看一步只要往下看一格,不用把整行重新读一遍。深底的格子是这一步改了的,右边一列是这一步留下、带给后面几段的状态。步骤 C 是默认值生效的地方;步骤 E 给出原始那行里从没写出来的答案——npm 在 /ci/web 里跑,因为括号里的 cd 到右括号就失效了。最后一行只换一个输入,只有依赖它的两格变深。模板:templates/diagrams/text-steps.svg。
templates/diagrams/pipeline-exits.svg.
一行一行横着读:这一步、它在什么条件下能把这次发布拦下、是哪一次事故把它逼出来的。五个出口共用一列,「什么能拦下发布」就成了一列能一眼扫完的东西;步骤 C 不往出口列里送任何东西,因为它只改写、不拦。事故列下面那张虚线卡说明了三列为什么要一行对一行:旁边没有步骤的事故还没解决,旁边没有事故的步骤可以考虑删掉。底部三格结局兼当图例。模板:templates/diagrams/pipeline-exits.svg。
<g data-basemap="query-flow"> so a check can pull it out of every page and compare the bytes. Template: templates/diagrams/dim-spotlight.svg.
三页共用一份逐字节相同的底图,这是第 2 页。不给当前那一块上色,而是给其余部分盖一层跟背景同色、半透明的遮罩,在这一页讲的那块上挖一个洞,再用墨色虚线框圈住洞口。不引入新颜色,底图一个字节都不动——几页之间唯一不同的就是洞开在哪。底图那一段包在 <g data-basemap="query-flow"> 里,检查才能按名字从每一页取出来逐字节比对。模板:templates/diagrams/dim-spotlight.svg。