| name | lieflat-charts |
|---|---|
| description | 一套模板驱动的单色数据可视化 skill,严格从 Lupi、Basics、Glance 与 Interactive gallery 的真实实现生成 HTML 图表;默认优先 Lupi Editorial 与 Lupi Basics,无合适模板时才使用 Glance。 |
Lieflat Charts — 图表品味法典
Lieflat Charts 是一套遵循 Agent Skills 格式的单色数据可视化 skill,专注于把数据图表做成有编辑感、能阅读、能组成完整页面的视觉内容。它由 moxt 与 Codex 协同制作,支持 Lupi 编辑叙事型、Glance 快速判断型、Basics 基础编辑型和 Interactive 交互大图。用户给你数据和场合,你产出一个无需构建、双击可打开的单文件 HTML,改数据只需要动顶部一个数组。纯 SVG 图可离线运行;使用 Chart.js、ECharts 或在线字体的图,在未内联依赖时需要联网。默认必须先从 Lupi Editorial 和 Lupi Basics 中选型;只有两者都没有合适模板,或用户明确要求 Glance / dashboard / 三秒快读时,才允许使用 Glance。
怎么查一张图的参考代码:catalog 查到图型 → 打开对应 gallery 文件 → 按卡内标题找到 <div class="card"> 块看结构 → 在 <script> 里搜同名 // ════ 注释块拿渲染代码。不要整页照抄——gallery 是多卡合页,交付给用户的永远是按第九节骨架组装的单图文件。
目标用户是非程序员(写作者、运营、做 PPT 的人)。他们说人话("帮我把这季度转化画一下,发公众号用"),不说图型名。你的职责是把人话翻译成正确的图,而且好看到能直接发出去。
零、模板优先硬约束
以下规则不是建议,违反任意一条都必须返工:
- 必须从仓库模板生成。 每张成品图先在
catalog.md锁定图型编号,再打开对应 gallery 的真实实现:Lupi 使用templates/lupi-gallery.html,基础型使用templates/basics-gallery.html,Glance 使用templates/glance-gallery.html,交互大图使用templates/big-*.html。 - 必须沿用所选模板的代码骨架。 从卡内标题对应的
<div class="card">和同名// ════ 图型名 ════注释块出发,保留其核心 SVG / Canvas / ECharts 结构、数据编码方式、比例关系和动画节奏。允许替换数据、标题、旁注、来源与必要布局;禁止脱离模板另画一张“看起来差不多”的图,禁止拼接多个模板造混合图型,禁止退回图表库默认样式。 - 默认选型顺序固定。 先完整比较 Lupi Editorial(L1–L15),再比较 Lupi Basics(F1–F12)。只要其中存在能诚实承载数据、容纳标签且可读的模板,就必须从这两组中选择。
- Glance 是默认降级方案,不是并列首选。 只有 Lupi Editorial 与 Lupi Basics 都不适配,或用户明确要求 Glance、dashboard、监控、周报、三秒快读时,才使用 Glance。降级前必须写明 Lupi / Basics 不适配的具体原因。
- 库外新造是最后手段。 Lupi、Basics、Glance 和交互模板都无法承载时,才能走第六节翻译流程;新图仍必须继承最接近 gallery 模板的视觉语法和代码结构。
一、工作流程(每次请求都走这六步)
- 判数据形状。 别问用户要什么图,看他的数据长什么样:几个类目的比较?带时间的序列?占比?带正负?多对一归属?网络?逐条记录的分布?形状是选图的主键。
- 先审计 Lupi 与 Basics。 按数据形状扫描所有能承接它的 Lupi Editorial(L1–L15)与 Lupi Basics(F1–F12)候选。至少比较 3 个候选;如果不足 3 个,就列出全部候选。比较语义契合、单位诚实、标签容纳、阅读速度、叙事张力和本批次是否重复。
- 必要时才检查 Glance。 只有 Lupi 与 Basics 候选全部失败,或用户明确要求 Glance / dashboard / 监控 / 周报 / 三秒快读,才扫描 Glance(G1–G18)。选择 Glance 时记录为什么 Lupi 与 Basics 无法承载,不得只写“Glance 更直观”。
- 锁定真实模板,再组织整页。 每张图必须记录体系、图型编号、gallery 文件和卡内标题,并以该卡的真实结构与渲染代码为骨架。禁止先想好“这一页要讲六件事”,再临时发明图型;整页叙事只能在模板锁定之后组织。
- 按图数规则组成批次。 一张图只承担一个独立结论;去掉重复结论后,再按第 1.1 节的默认区间决定数量。模板需要全局分配:不重复、不堆同一种轮廓、不为了凑数硬加图。
- 按模板渲染并自检(第零、二、三、八节)。逐项核对成品是否仍能对应到所选 gallery 实现;不能因为改数据而换掉模板的核心几何、编码或动效。库外图型走翻译流程(第六节)。
1.1 图数规则
图的数量由独立结论数决定,不由“有多少数据列”决定,也不固定要求 5 张或 6 张:
| 请求类型 | 默认成品数量 | 规则 |
|---|---|---|
| 单个问题 / 单张表 / 一个指标 | 1 | 只交付最强的一张,不为了展示模板而扩展 |
| 两到三个明确结论 | 2–3 | 每张图承担一个不同结论,可共享同一数据源 |
| 一篇文章、论文或完整案例 | 4–6 | 覆盖总览、构成、比较、关系或变化等不同数据形状 |
| 用户明确要求数量 | 按用户要求 | 仍然删除重复图;不足以支撑时说明并少做 |
- 默认单页上限为 6 张;超过 6 张就拆成多页或按章节交付。
- 候选方案、Glance/Lupi 对照稿不计入最终图数;它们是选择过程,不是成品批次。
- 一页多图至少保留一个总览结论,其余图必须提供新的比较维度、关系、时间变化或细节证据。
- 如果两个图表达同一个结论,只保留阅读场合更合适、数据契约更诚实的一张。
二、Mono 语法 · 硬规则(违反即返工)
引用 mono-tokens.js(开源分发时把内容内联进 HTML)。与 token 冲突的取值一律以 token 为准。
颜色
- 只有纸灰
#F0EFEB和炭黑#1C1C1A两极,中间 7 级灰阶 ladder。没有彩色。 - 明度即数据:最重要 = 最黑(暗卡上反转为最亮)。多系列按重要性沿 ladder 分配,不按顺序随便拿。
- 一律实心:不透明材质、不发光、不渐变滤镜、无阴影。质感全靠明度对比和形状。唯一例外:叠加型图(Radial Patchwork)里透明度本身编码密度——那是数据,不是装饰。
- 暗卡(
.card.dark)只给两种图:必须暗底衬托的形(花瓣、发光感丝线/网络)。默认浅卡;每屏(4 卡)最多 1 张暗卡。
排版
- Inter 全家。标题 700 / 图内数值 800 / 轴标签 600。卡片结构固定四件套:结论式标题(h2)+ 副标题(图例和时间范围写在这里,用
·分隔)+ 图 + 来源行(全大写、加字距)。 - 标题写结论不写图型名:"Revenue by plan" 可以,"柱状图" 不行;更好的是带判断的:"Where we gained, where we bled"。
- SVG 最小字号:半宽卡 6.5px、通栏 5.5px。装不下的信息改 hover 出,不许缩小字号硬塞。
形状
- 卡片圆角 24px,无边框无阴影,靠留白分卡。柱端胶囊圆角(竖柱圆上端、横柱圆外端)。
- 柱状图不断轴。 柱的契约是长度∝数值,断轴毁契约。极端值场景的正确做法:①让极端值冲天(最诚实)②主图+放大镜小图 ③撕柱不撕轴(明说画不下)。
- 花瓣皮(粗黑缝+圆角扇瓣)只适用等分或近似等分的径向图。宽窄悬殊的扇区会相互遮蔽,降低可读性。
动画
- 入场动画默认开,
quarticOut快进快停,不弹跳(波浪入场可用 elasticOut)。点阵 stagger 8–15ms/个,条形 80–130ms/根。 - 统一 reveal 机制:滚入视野才播 + 点击重播(用 token 里的
obsReveal,带 timer 清理)。 - 必须带
prefers-reduced-motion降级(token 的 CSS 已含)。 - 动画不可优于结构:一个效果如果需要发明新布局才能安放,不配存在(effectScatter 教训)。
数据
- 演示数据用 token 的
rnd(i,k)确定性伪随机,禁用Math.random()——刷新必须长一样。 - 数值和视觉严格成正比。面积编码用
Math.sqrt(v)换算半径,不许拿数值直接当半径。
三、两个风格系的分工
同一份 mono 色板下有两种世界观,选哪个看场合和读者愿意花几秒:
| Glance 系(18 张) | Lupi 系(细读,15 张) | |
|---|---|---|
| 基本单元 | 形状(粗柱、大弧、色块) | 记录(一个点 = 一条数据) |
| 线条 | 2px+,理直气壮 | 0.5–0.7px 发丝 |
| 聚合 | 提前聚合好,给结论 | 拒绝聚合,摊开原材料 |
| 读法 | 扫一眼(<10s) | 凑近读(30s+) |
| 场合 | 周报、dashboard、随手贴 | 年报、对外故事页、海报 |
| 引擎 | Chart.js / ECharts | 手写 SVG |
默认策略:Lupi Editorial → Lupi Basics → Glance。 没有明确场合时,禁止默认 Glance。放年报、公众号长文、海报、开源 README、作品集时先选 Lupi Editorial;数据较少或适合熟悉图型时再选 Lupi Basics。只有前两组都没有合适模板,或用户明确要 dashboard、监控、周报、三秒快读时,才进入 Glance 候选池。
全量候选审计不是“把所有图都做一遍”。 先用数据形状筛出能编码同一本体的候选,再把候选分成:
- 语义合适:每个点、线、面、串珠背后都有真实单位或明确聚合口径。
- 视觉合适:标签装得下,密度足够,读者能按预期时间读完。
- 叙事合适:图形本身能承载这批数据要讲的判断,而不只是把数字摆出来。
最终选择是三项的交集,不是“哪个模板文件最容易复制”。默认审计先在 Lupi Editorial 与 Lupi Basics 内完成;只有两组都失败才扩展到 Glance。若同一批要做多张图,再对候选做一次全局分配:模板不重复,形状轮换,最多一张暗卡,避免整页变成六张相似的环或横条。
数据少(只有几个百分比)不等于只能 Glance。 Lupi 化的正道是单位分解:把聚合数摊回可数单位(1 点 = 1 人 / 1 百分点),密度来自单位而不是记录数。单位含义写进副标题,只摊诚实单位(占比加总 100 → 100 个点),不编造不存在的个体记录。取整时如果加总不足 100(如 49.0+27.4+13.9+5.0+3.2 → 98),在底注写明「另外 N 人被四舍五入吃掉了」,不凑假单位。
小数据走 Lupi 的路径优先级(经多轮案例验证):
- 先全量扫描,再选代码骨架——基础型组 F1–F12(
templates/basics-gallery.html)是稀疏数据的 Lupi 词汇:柱/折线/面积/环形/横条/分组/堆叠/散点/瀑布/热力/进度/哑铃;编辑型 L1–L15 则提供逐记录、单位分解、关系与旁注语法。不要因为basics-gallery.html里有现成代码就直接选 F 图。 - 用最接近本体的模板起步——多选题百分比优先比较 L15、F5、L2;100% 构成优先比较 L14、L5、F4、G4;漏斗优先比较 L13、F1/F5 的降级表达。选择依据是数据编码方式,不是文件顺序。
- 库里真没有对应形状才新造,且新造必须从 gallery 现有语法延伸(发丝 tick、确定性 rnd 抖动、paint-order 光晕、全大写注记),不引入库外参照——“Lupi 风”指 gallery 那批图的视觉语法,不是 Giorgia Lupi 本人的手绘风。
- 新造的小数据图要配满环境结构层:gallery 好看有一半靠无数据的家具(账本纸横线、虚线导轨、rim 刻度、每 10 单位的立柱网格、旁注引线)。数据层诚实稀疏,密度预算花在家具上。只画数据 + 一根底线的小数据图必然寒酸。
同一批产出(一页多图)里模板不重复。 15 张 Lupi 系够轮换;同一数据能被多个模板承接时,选这一批里还没用过的。
四、图型决策树(数据形状 → 候选)
编号对应 catalog.md。这些只是候选召回表,箭头和书写顺序不代表优先级。实际选择必须遵守:先检查全部 Lupi Editorial 与 Lupi Basics 候选,确认无合适模板后,才允许采用 Glance 候选。
- 少类目比较(≤8) → G3 Chunky Bars ⇄ 竖排 F1 Rung Bars / 横排 F5 Tick Rows ⇄ L2 Dot Cascade(⚠️ cascade 类目名竖排,仅当名称 ≤4 字或短缩写时可用;中文长类目换 F5/L5/L12)
- 多选题百分比(各项独立 0–100,加总可超 100) → G3 Chunky Bars ⇄ L15 Ballot Tally
- 多类目分布(30–60 根) → G12 Stagger Wave
- 带正负的分类数值 → G10 Diverging Bar
- 占比 / 100% 构成 → G4 Dot Waffle ⇄ L14 Hundred Field ⇄ F4 Tick Donut(饼图的默认替代);近似等分且要门面 → G2 Petal Rose;占比×强度双编码 → G13 Big Slice;按类堆叠 → F7 Stacked Rungs
- 两时点对比(前后 / 今昔) → 类目级(≤6 类)→ F12 Dumbbell Queue(横向,串珠 = 真单位)⇄ F6 Paired Rungs(并肩双梯);只有 2–4 条序列要画趋势线 → Glance chunky slope(粗线、大数、结论进标题)。交叉过多的斜率图会显著降低可读性,不要为了 Lupi 化增加装饰结构。
- 日序列(≤30 天,带区间) → G1 Range Capsules ⇄ 逐日读数 F2 Hairline Line ⇄(90 天级、要肌理)L3 Barcode Lollipop;30–60 天看形态 → F3 Hairline Area
- 累计增长 → G18 Draw-in + Counter
- 双序列因果(投入 vs 产出) → G8 Rainfall
- 实时数据 → G17 Dynamic Stream
- 排名随时间变 → G16 Bar Race
- 星期×小时×量 → G14 Single Axis ⇄ F10 Dot Heat
- 瀑布 / 增减分解(≤6 级) → F9 Rung Waterfall
- 单值进度(0–100%) → F11 Tick Gauge ⇄ G18 Draw-in + Counter
- 二维散点(≤20 点) → F8 Plumb Scatter;几百点分布 → G15 Jitter Strip
- 分组分布、逐条记录 → G15 Jitter Strip
- 分类×分类+量(矩阵) → 轻(≤100 格)L4 Arc Matrix ⇄ 重(大跨度、要旁注)L9 Bubble Almanac
- 多对一归属 → 造型强 L5 Radial Convergence ⇄ 带名单 L12 Type Colonnade
- 漏斗 / 分阶段递减 → L13 Hourglass Stream
- 层级结构 → G7 Tree LR
- 事件序列生命史 → L11 Trend Lineage
- 多实体出生时间+现状 → L1 Launch Fan
- 逐事件时刻分布(一天内) → L10 Radial Patchwork
- 双极量表(两端都合法) → L7 Brand Spectrum。注意和单极打分(雷达)区分:单极用 ECharts 原生雷达
- 网络 → ≤15 节点 G6/G11 小图;>15 或要查数 → B1 环形 / B2 力导向;多段路径流向 → B3 Threads
- 多组×网格(要装饰感) → L8 Dotty Matrix;要读数 → 摊平用 G14
- 同一实体集多维度轮播(演示) → G9 Scatter Morph
五、交互三问(决定静态还是可交互)
按顺序问:
- 这根线/点背后有没有一条真实记录? 没有(纯肌理装饰,如 Cluster Field 的辐条、Hourglass 的淌线)→ 禁止加交互,给没有内容的元素加 hover 是欺骗。
- 有记录 → 不点能不能读出来? 元素 <50 且两端有标注(如 Colonnade)→ 静态够用,hover 是锦上添花。
- 元素 >50 根或多段路径(如 Threads)→ 必须 hover/pin,否则只是氛围图。交互实现参考
templates/big-threads.html:可见线下垫 9px 透明孪生线当热区,hover 单线亮整条路径、hover 标签拉整束、点击钉住。
六、库外图型 · 翻译流程
用户要的图不在 48 张里(或发来一张参考图)时,不是做不了,是现场造句。流程四步,第一步不许跳:
- 先回答本体:这个图型编码了什么?每个视觉通道(位置/长度/角度/面积/明度/密度)分别对应哪个数据维度?答不出来就问用户拿数据结构。抄形不抄魂 = 白做(pictorial bar 曾把"符号计数"错做成"树长高",返工)。
- 找最近的亲戚:在 catalog 里找数据形状最像的一张当起点,继承它的布局骨架和动画节奏。
- 用 token 造句:色板、字体、圆角、动画参数全部从
mono-tokens.js拿,不许发明新颜色新字号。产出必须和库里的图"一眼一家人"。 - 过第二节硬规则和第八节自检,和库内图同一标准。
参考图翻译的附加规则:识别参考图属于哪个流派(Glance or 编辑部),编辑部风格的密度、旁注、手绘感(blob)是本体的一部分,别做收敛了——almanac 曾因"不敢挤"返工。
七、什么时候说不
敢拒绝比什么都接更可信。以下情况不做,并给替代:
- 断轴柱状图 → 拒绝,给三个诚实方案(冲天 / 放大镜 / 撕柱不撕轴)。
- 彩色 / 发光 / 玻璃拟态 / 3D → 不属于 Mono。用户坚持要彩色,说明他要的不是这个 skill,直说。
- 地图类(choropleth、轨迹图)→ 库里没有地理管线,老实说做不了,别硬画走样的。
- 给纯装饰元素加交互(第五节第 1 问)→ 拒绝并解释。
- 雷达图重构 → 不重构,用 ECharts 原生雷达 + Mono token 换肤(实测过:展示场景里"认得出的图型"有价值)。
- 数据太少撑不起所选图型(如 3 个节点要力导向)→ 降级到更简单的图并说明。
八、交付前自检清单
- 数值和视觉成正比?(面积用了 sqrt?柱没断轴?)
- 色板全部来自 token?数一遍,出现任何非 ladder 颜色即返工。
- 标签会不会重叠?(barcode 教训:邻近峰值标签要强制最小间距)
- 最小字号踩线没有?(半宽 6.5 / 通栏 5.5)
- 演示数据是
rnd确定性的?刷新两次长得一样? - reveal 正常?(滚入播、点击重播、timer 不叠加、reduced-motion 降级在)
node --check过语法(把<script>内容抽出来查)。- 卡片四件套齐全?标题是结论不是图型名?
- 副标题把图例说清了?(读者不看代码只看这一行)
- 是否完成全量候选审计?至少写下 3 个候选和淘汰理由,而不是只记录“采用了哪个模板”。
- 如果是一页多图,模板是否全局分配过?有没有相似轮廓重复、暗卡过量、所有图都变成同一种径向图?
- 每张图是否记录了图型编号、gallery 文件和卡内标题?成品的核心结构是否确实来自该模板,而不是重新发明?
- 如果使用 Glance,是否写明 Lupi Editorial 与 Lupi Basics 为什么都不适配?如果没有,返工回到 Lupi / Basics。
- 最后一问:这张图放回所选 gallery 的对应卡片旁边,是不是同一个模板家族,而不只是“风格有点像”?
九、单文件模板骨架
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Mono — {图名}</title>
<!-- 需要 ECharts 时: -->
<script src="https://cdn.jsdelivr.net/npm/echarts@6/dist/echarts.min.js"></script>
<!-- 需要 Chart.js 时(G1 / G3): -->
<!-- <script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"></script> -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="{MONO.FONT.link}" rel="stylesheet">
<style>/* 内联 MONO.CARD_CSS */</style>
</head>
<body>
<div class="grid2">
<div class="card"><!-- 或 card dark / card wide -->
<h2>{结论式标题}</h2>
<div class="sub">{说明} · {图例} · {时间范围}</div>
<!-- 图容器按引擎三选一: -->
<div class="ch" id="ch"></div><!-- ECharts -->
<!-- 手写 SVG: <svg id="ch" viewBox="0 0 400 320"></svg> -->
<!-- Chart.js(G1/G3): <div class="wrap"><canvas id="ch"></canvas></div>,配 .wrap{position:relative;height:320px} -->
<!-- ⚠️ Chart.js 必须挂 <canvas>,套 <div class="ch"> 会报 can't acquire context -->
<div class="src">{图型名} · {系列} · {数据来源}</div>
</div>
</div>
<script>
// 内联 mono-tokens.js 全文
// ── 数据(用户只需要改这里)──
const DATA = [ /* ... */ ];
// ── 渲染 ──
MONO.obsReveal('ch', el => { /* ... */ });
</script>
</body>
</html>
