DeepSeek Harness Hub
← 返回列表

remybroun/infographic

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
未验证

一个技能,将文档、数据集或主题转化为经过设计的视觉解说:一份可直接打印的 PDF,或一个连续滚动的页面,其 HTML…

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/8/31 · 已提供中文文档

一个 Claude Code 技能,可将文档或主题转化为经过设计的可视化讲解。52 种块形式、强制字数预算,以及会让构建失败的守卫。

综合分
30.2
GitHub 分
30.2
用户评分
★ Stars
3
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add remybroun/infographic
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/19(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

infographic

Represent the world.

一个技能,将文档、数据集或主题转化为经过设计的视觉解说:一份可直接打印的 PDF,或一个连续滚动的页面,其 HTML 即为交付物。

它不是图表库。它是一组约束,使模型产出图形文档,而不是一篇附带着图表的文章,而且其中大多数约束在构建失败时才会报错,而非仅作提示。

/infographic

安装

npx skills@latest add remybroun/infographic

这会将技能放到你的 agent 查找技能的位置,包括 Claude Code,而 npx skills update infographic 会拉取后续版本。默认安装到当前项目;添加 -g 可改为安装到所有项目。

或者手动完成同样的事,因为技能只是一个包含 SKILL.md 的目录,Claude Code 会在下一次会话时找到它:

git clone https://github.com/remybroun/infographic.git ~/.claude/skills/infographic

若要将克隆限定到单个项目,请改为克隆到 /.claude/skills/infographic。

验证

python3 scripts/ig.py selftest          # 423 assertions
python3 scripts/ig.py validate --all    # every theme through the colour checks
python3 scripts/ig.py selftest --render # also builds all six fixtures, to PDF
sh assets/build_gallery.sh              # rebuilds every image on this page

前三个是 CI 在每次推送时运行的命令,上面的徽章就是那次运行。第四个是下方图表的复现命令:本页上的每一张图片都是该技能的输出,一条命令即可从源码重新构建全部十三张。

它产出什么
左侧是一页填满正文的页面,标注为 2,086 词和一张图表。一个标有 budget 的箭头指向右侧,指向一页带有标题、条形图和两个简短标签的页面,标注为每页 150 词。

scripts/lib/density.py 中的词数预算在任何内容渲染之前运行,超出预算即为构建错误。这个数字并非随意设定:此技能的第 1 版发布了一份八页的解说文档,包含 2,086 词和一张图表,其中每一段单独来看都站得住脚。预算之所以存在,是因为在时间压力下,品味总是选择“再加一句澄清的话”。

它用来绘制的词汇

六个带标签的组,每组展示三个微型样本:用于数量的条形图、棒棒糖图和热力图;用于变化的折线图、斜率图和哑铃图;用于部分与整体的环形图、华夫图和份额条;用于结构的链、树和维恩图;用于图示的层、泳道和标签片;用于编辑的图块、标注和分隔线。

七个族系共 56 种块类型,外加 60 个别名,因此可以用日常词汇编写规格(pie → donut,waffle → unit,2x2 → quadrant,flow → process,2x2 → quadrant)。

这个数字是一张地图。在它下面是块本身渲染出来的样子:样本画廊 十张图版中的三张,该画廊绘制了此仓库拥有真实数据的全部 41 种形式。其中的每个数字都在构建时从仓库中读取,来自注册表、词数预算、五个随附的 fixture、linter 自身的检查以及 git log,因此它不会偏离它所记录的代码,其中也没有任何内容是凭空编造来补全图形的。

渲染出的六张数量图表:一张展示每个随附示例图形化程度的棒棒糖图,一张每个族系块数量的热力图,一张九个渲染目标可打印区域的条形图,一张图形块与文本块对比的分组柱状图,一张块与图形块的散点图,以及一张海报与滚动页面中族系使用情况的发散条形图。

渲染出的五个块:一个按相互覆盖顺序排列的五项原则金字塔,一个展示作者绘制的图形与内置块共有内容的维恩图,一个五条命令的流程,一个渲染、查看、发现、修复的循环,以及一个按主张是否需要数字和是否需要顺序来划分族系的象限图。

当目录中没有适合某个想法的形状时,你就自己画。figure 块接受作者编写的 SVG,并保留内置块的所有保证:必需的 alt、必需的数据孪生、拒绝颜色字面量,以及其标签计入预算。每个文档最多三个,因为如果没有上限,“画出目录中缺少的形状”就会变成“全部手绘”,一致性也就消失了。
渲染出的四个区块:一个从 56 种区块类型经由各家族到每个区块是绘制还是设置文本的桑基图,一个仓库的树状图,一幅由作者绘制的图,展示针对同一组事实的三个论点并高亮所选的那个,以及一张记分卡,列出每个主题通过的颜色检查,旁边是一个仪表,显示某个已交付示例展示了多少词汇量。

那张图上由作者绘制的图形是一个 figure。同一组事实上的三条主线
不是树(它们不划分任何东西),不是流程(它们是备选方案,不是
步骤),也不是象限(没有坐标轴)。要命名最接近的区块类型
需要一个“嗯,算是吧”,而这正是转而自行创作该形状的检验标准。

一份文档是如何制作出来的

步骤 1–6.5 是判断,无法自动化。7–11 大多可以。

1. 来源:阅读它,或 ig.py extract source.pdf
2. 读者与模式:谁读这个,他们是否具备这个概念,他们缺少
哪些词?
2.5. 简报:ig.py brief out/brief.json --new。从这里到
步骤 7 所决定的一切都放进这一个文件,别无他处
3. 三条主线:针对同一组事实的三个论点,然后选择一个
4. 目标:论文、海报、幻灯片,或连续滚动的页面
5. 场景:在打开
目录之前,这份文档靠哪些图像生存或死亡,并且其中任意两个都不能来自同一视角
6. 形式:每个剩余主张对应一个
6.5. 检查简报:ig.py brief out/brief.json --read,在画下任何一笔之前
7. 规格:一次一个章节,ig.py brief --order ,绘制两次,
两种构图都用 ig.py sketch 单独渲染
8. 主题:经过验证,绝不手工挑选
9. 渲染:ig.py render out/spec.json --out-dir out
10. 看一看:ig.py shoot out/doc.html。linter 从未看过。然后
ig.py blind out/doc.html,因为你无法阅读自己的文档。
11. 交付:规格、文档,以及它是如何制作的

有三种排序至关重要。解释先于论证,因为
一条主线是一个主张加上承载它的推理,而对于一个已经知道主题是什么的人来说,这就是一份文档的框架。先有三条主线
再选择其中一条,因为最先出现的论点几乎总是
机制。那是来源已经处于的形状,而且它很少是
读者真正关心的那个。还有先命名场景再打开目录,
因为一旦目录打开,问题就会悄然从这看起来像什么?
变成这 56 种形状中哪一种最接近?

解释,与论证相对

有三个版本,这项技能能为任何事实选择一种好形式,却
教不了任何东西,而原因是结构性的。它的第一个产物是一本事实
账本。它的第二个是一个主张,定义为读者到最后应当
相信的一句话。两者都是论证的框架,所以每份文档都以
其结论开篇并倒推,而这是为
已经了解这个主题的人。

{"meta": {"mode": "lesson", "ladder": [
{"says": "一个程序可以运行许多独立的公司网站。",
"introduces": ["application"], "at": "one-program"},
{"says": "网址就是告诉它你想要哪家公司的东西。",
"introduces": ["web address"], "at": "address-picks"}
]}}

梯子就是解释,在选定任何形式之前就写好的解释:梯级按照读者攀爬的顺序排列,每一级都标明它教哪些术语,以及它落在哪个块上。在教授某个术语的梯级之前,某个块中使用了该术语,就是一个构建错误。 这是这里唯一能看见内部人语域的检查。其他所有检查衡量的都是密度、形式或几何,而一份文档可以通过所有这些检查,却以一个读者还要再过四个块才会遇到的词开头。

每一级梯级上限为 24 个词,而这个上限正是关键。“在画任何东西之前,彻底反思如何解释这件事”正是产生这个技能所交付过的最差文档的指令。在绘图开始之前就完整写出的解释是一篇文章,而图片只是被加进来为它配图。

ig.py brief --read 会把骨架单独交给一个没有任何上下文的读者,在任何内容被渲染之前,这与 ig.py blind 在最后以一次重建的代价运行的测试相同。

构建拒绝渲染的内容

水平条形图显示在图形密度下每个文本字段允许的词数:图注文本 40,引语 26,标注 24,注释 18,副标题 16,标题 14,条目详情 12,图表标签 6。

三种失败会直接停止构建:违反词数预算、超过三幅手绘图形,以及绘图内部出现颜色字面量。其余则发出警告。

这些防护中的每一个都对应一份已经交付、本不该交付的具体文档:

| 防护 | 催生它的失败 |
|---|---|
| 词数预算,在代码中强制执行 | 版本 1 在八页中交付了 2,086 个词,却只带有一张图表 |
| 最多三幅手绘图形 | 版本 2 修正了词数,却把所有东西都手绘,失去了所有一致性 |
| 绘图中拒绝颜色字面量 | 手绘图形正是计算颜色最先出问题的地方 |
| 编写的表格计入预算 | 一个部分被重新打成三张表格,却作为干净内容通过;单元格被豁免了 |
| 标识符要计数,定义要必需 | 一个页面带有 30 个标识符,却没有定义块,并且通过了 |
| 图形形式与上一版本比较 | 一次重新生成返回的结果 93% 相同,而每一步都诚实地执行了 |
| kpi 行要对照文档来衡量 | 四个数字领起一个页面,而四个数字在更下面都得到了更好的解释 |
| invert 没有 bleed | 它翻转了墨色,却没有涂上底色,所以绘图会渲染成浅色叠浅色 |
| 在教授它的梯级之前就使用某个术语 | 一份解释性文档以分数和术语表开头,没有教会任何人任何东西,却通过了上面所有检查 |
这个模式值得直白地说出来,因为它反复出现:

当输出错误时,去寻找让错误做法变得最省事的激励,而不是去寻找缺失的规则。

linter 奖励散文,于是它得到了散文。目录框定了每一个想法,于是想法以目录的形状出现。表格单元格不受预算限制,于是段落变成了表格。六个词的标签上限让 skipped_bucket 比“收件人关闭了那个组”更省事,于是页面出来时只标着只有作者能读懂的标识符。

主题

default(中性编辑风)· iris(本家主题,陶土色与蓝色)· rentos(橄榄色编辑风,Instrument Serif)· mono(灰度,适合印刷)。

本页上的每一张图都是 iris,所以你看到的是一个主题在做它的全部工作,而且它与页面顶部的标志是同一个主题。它的页面是标志的奶油底色,它的强调色是标志的陶土色,它的两条顺序色阶都取自标志自身的两个色相角,在 OKLCH 中为 39.9° 和 251.1°。它的发散色阶从蓝色过渡到陶土色,这正是标志所基于的同一种反转。块标题使用展示字体,而其他地方一律使用无衬线字体;衬线字体按主题选择启用(type.block_title),因为一个展示字体就是其无衬线字体的主题从中得不到任何好处。

状态颜色来自主题,而不是来自主题之外。 good 是主题的绿色槽位,warning 是它的金色,而 serious 和 critical 是同一个深红色向下两级,这是诚实的,因为严重程度是有序的。上一个版本把 critical 放在色相 29°、强调色放在 40°,于是一个 DON'T 面板把自己涂成了本家颜色,而一个 good 绿色在主题中其他地方都不出现,于是一个对勾读起来像框架的界面元素。现在每个状态色相都至少与强调色相隔 36°。

八个分类槽位刻意不是品牌色。 一张图表需要八个可区分的身份,而一个品牌只有两个,所以强行让槽位使用品牌色相,正是“品牌安全”调色板最终变得难以阅读的原因。陶土色和蓝色领衔,其余六个是在三条规则下搜索出来的,而这三条规则是门禁本身无法检查的:最小 36° 的色相间隔,这样没有两个槽位会塌缩成一个色系;一个最大化任意位置最差配对而非最差相邻配对的目标;以及前三个槽位之间的明度分布,因为散点图会把它们并排放置。每条规则的存在都是因为搜索在没有它时出了问题。仅按相邻性评分时,它返回了四个橙色和四个蓝色。给定 32° 间隔时,它返回了两个相隔 33° 的深红色。两者都是合法的,因为超过第三个槽位后,门禁只测量相邻配对,而两者在图例中都没用。门禁是下限,不是目标。

第三条规则有一个值得写下来的上限,因为它是页面的属性,而不是搜索的属性。奶油底色使得任何彩色填充都无法在 L 0.65 以上达到 3:1 的对比度,而两个品牌槽位被固定在 L 0.590 和
L 0.441,所以第三个槽位大约有 0.06 的明度可以移动。更糟的是,你想从它那里得到的东西彼此冲突:一个高对比度的第三个槽位必须偏暗,这会让它在明度上靠近海军蓝,于是只剩色相能把它们区分开,而这恰恰是红色盲所剥夺的。有一个候选方案在页面上测得了舒适的 4.70:1,但对红色盲者来说,它与海军蓝之间只有无用的 7.5 ΔE。所以第三个槽位从浅色一侧取用,并且三色组合的色觉下限保持在 15 ΔE,以免退化。

其中有一项检查是这里新增的,之所以新增,是因为这个主题没能通过它。一条色阶本应在最暗处饱和度最高;最初的 iris 色阶用正弦函数驱动色度,而正弦在两端都为零,所以它的最后两级变成了中性灰,热力图读起来就像一张戴着颜色图例的灰度图。没有任何东西抓住它:序数门控衡量的是色相分布和明度单调性,而灰色没有色相可分布,渐变为灰色也仍然完全单调。现在门控要求色阶的暗半部分必须保有该色阶自身峰值色度的 40%。每个内置主题都通过了它(rentos 最接近,为 41%);3.3.0 中发布的那个色阶只保住了 9%。

所有四个主题都通过了可计算的色彩检查:对比度、类别分离度、色阶饱和度和色觉缺陷距离。iris 是唯一不需要豁免的;rentos 记录了一项豁免,因为品牌橄榄色测得的色度为 0.087,低于 0.10 的下限,而品牌色无法重新分级。新主题是一个 JSON 文件,不是代码。上方表格中的评分卡按主题统计检查项;mono 运行的检查更少,是因为灰度需要分离的类别槽位更少,而不是因为它得分更差。

python3 scripts/ig.py validate --all
python3 scripts/ig.py catalog --sheet out/sheet.pdf --theme mono

布局

SKILL.md              Claude 首先加载的内容
references/           每个决策一个文件;加载拥有该决策的那个文件
pipeline.md           十一个步骤
graphic-first.md      字数预算,以及为什么它是代码
scenes.md             决定哪些内容需要手绘
anti-patterns.md      发布前对照此文件检查每一份文档
teaching.md           阶梯,以及强制执行它的模式
catalog/              56 种块类型,按族分类
scripts/
ig.py                 CLI
build.py              规范 → HTML
check_document.py     检查器
lib/density.py        字数预算
lib/ladder.py         是否在解释某事物之前先解释了它所依赖的事物
lib/derivation.py     重新生成是否改变了任何内容
lib/leading_numbers.py  那个统计行是否承担了它的分量
fixtures/specs/       六个完整、可渲染的可用示例
GALLERY.md            该技能绘制的每一种形式,均已绘制
assets/
gen_readme.py         本页上的三张幻灯片
gen_gallery.py        十张样本表,来自本仓库自身的数据
build_gallery.sh      用一条命令重建这里的每一张图像
measure_blocks.py     每个块布局有多高,以便行可以配对
trim_png.py           裁掉栅格化页面末尾的空白

要求

Python 3.12+ 标准库,以及一个 Chromium 系浏览器用于渲染和
截图(如果找不到,请设置 CHROME_PATH)。poppler 在构建文档时是可选的,
它在那里读取 PDF 源文件并测量每页的墨水覆盖率;而在重建本页图像时则是必需的,
这些图像通过 pdftoppm 进行栅格化。无需 pip 安装,无需 npm,无需 matplotlib。

关于本页的说明

这里的每一张图像都是由该技能生成的。sh assets/build_gallery.sh 可以用一条命令
从源文件重建全部十三张。

三张宽图是来自 gen_readme.py 的 16:9 幻灯片,
它们被构建为分页目标,因为 README 图像是一个固定画框,而分页页面会填满它,
而不是留下滚动布局所留下的死列。样本页是 A4 纵向,这也是有意为之:
文本标签的尺寸以毫米为固定单位,因此页面宽度才决定了它在 GitHub 的列中
显示得有多大。A4 纵向会让 8pt 标签大约为 12px;
338mm 的幻灯片会让同一标签大约为 7px。

这些页面设置了 meta.spacing: "tight",它会一起缩放带边框块内部的内边距、行间距和
填充。只缩放间距读起来并不会更紧凑:两个带边框的图表由 pad + gap + pad 隔开,
而在默认值下这是 62px,其中间距占 26。tight 不是默认值,因为在一篇进行论证的
文档中,间距才是告诉读者一个想法已经结束的东西。

十一个流水线步骤和守卫表不是图像。有序列表和表格会原生渲染,
可搜索、可复制,并跟随你的主题。当一个想法具有空间性时,图像才值得占有一席之地。

这三张幻灯片是本仓库中唯一设置了 tables: false 的地方。
无障碍孪生内容是一个  元素,而在栅格图像内部,
那是一个没人能操作的控件,因此它原本会承载的值改为放在每个图旁边的正文中。
样本页则在 HTML 中保留它们的孪生内容。

仍有三件事是错的,而且没有一件是伪造的:

- 图像是浅色的,所以在深色模式下会刺眼。 要妥善修复这一点,
需要一个经过验证的深色主题,而这样的主题尚不存在。
- 图形构建报告了三个发现,并且没有抑制其中任何一个。 图库警告说,
它的 cycle 样本在 330px 的列中要求 380px,而它是对的;
样本页会把块排得比文档更紧。三帧 README 条带设置了 tables: false,
因此 no-table-view 会作为错误触发,而 sparse-pages 会作为警告触发。
这两项检查对于文档来说是正确的,但对于栅格图像帧来说是错误的,
因为在那种帧中, 孪生内容是一个没人能操作的控件。
这就是 assets/build_gallery.sh 中唯一一个 || true,原因就写在它旁边。
- rentos 主题的字体不在本仓库内。 它的 fonts_dir 指向一个同级的品牌目录,因此全新克隆的仓库会用 Georgia 和 Helvetica 渲染它,而不是 Instrument Serif 和 Inter。现在当声明的字体文件缺失时,构建会发出警告,而不是默默回退,但这些资源仍未随仓库一同提供。

工具无法做到的一件事

linter 检查的是结构。它从未看过一眼文档,也无法告诉你某个标签发生了冲突、某个箭头指向了空处、画错了图,或者论证没有站住脚。

ig.py shoot 的存在就是为了让你能亲自去看,而 ig.py sketch 则让查看一张图的成本只需两秒,而不是一次完整渲染——这正是精心挑选的构图与将就接受的构图之间的差别。

接下来还有一件你也做不到的事。这项技能的全部主张是:陌生人看一眼页面就能理解它,而作者恰恰是唯一不是陌生人的读者:你知道每个标签的含义,也知道页面本意要表达什么,所以你看到的是意图中的文档,而不是实际印出来的文档。ig.py blind 会为完全没有背景信息的读者打印一份简介。他们说这讲的是什么,它就是什么。

品牌

本页顶部的标志是 iris:一个从中间一分为二的圆盘,每一半都有一条有序的色彩渐变,两半以相反方向运行该渐变,因此圆盘沿自身轴线发生反转。它参照两幅 Hilma af Klint 的画作绘制:结构参照 The Swan(1915),填充参照 Series VIII Utgångsbild(1920)。

这种二元性由明度而非色相承载,这就是为什么单色版本并不是它的降级副本,也是为什么它在 16px 下依然清晰可读。它的八个渐变阶梯通过了这项技能要求每个主题都通过的同一个验证器,以 --ordinal 模式运行,因为渐变不是一组类别。

文件、使用规则以及确切的校验命令都在
branding/ 中。那里的一切都是生成的:
bash
python3 branding/gen_brand.py

许可证

MIT。参见 LICENSE。

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群