Files
workbuddy_skills/product-planning/assets/diagram-design/assets/example-bump-dark.html
T
admin 8160f91559 技能库同步:另一台机的 2026-10-16 包 + element-picker 入包 + 工具归拢到技能级 assets/
product-planning(同步 26 改 65 新)
- 目录约定:docs/pm/<项目>/ ⇒ <工作区>/项目/<产品slug>/ 为产品根,下分 产品规划/ 与 产品原型/{designs,pages}
- ④段骨架六节 ⇒ 七节(新增「原型地址」;后两节改「页面导航」「原型状态取值」)
- ③段新增真机组件库;结案「源站只有暗色主题」,tokens.css(亮色)标为不可用于生产
- ③段改版规则反转为「一个产品只用一套原型、只留当前态」;②段新增 产品规划模板.md(表头唯一定义处)
- scripts:产品根定位重写(含 .registry/current-project 指针),新增 check_terms.py 与 selftest_product_root.py

session-mechanism(同步 3 改 2 新)
- references/06-技能优化规程.md 新增 §5「要求落在生成时看得见的面上」,总表 16 ⇒ 17 条;SKILL.md 同步
- scripts/collabctl.py 取回 _find_board() 候选定位(旧版写死 scripts/board.py,而看板已搬进 boards/会话看板/ ⇒ 旧版本就是坏的)

element-picker(新装)
- 按用户口径作「独立功能加入 product-planning」,非独立全局技能
- 修掉它自身三处路径漂移(技能根写法 ⇒ 同目录;README 两处旧落点;剪贴板示例文案与代码对齐)

工具归拢到技能级 assets/
- diagram-design / design-capture / element-picker / video-capture 从各段 assets/ 移到技能包 assets/
- 新增红线:本包有两处 assets/(技能级工具箱 vs 段内资产),引工具一律写「技能级 assets/<工具名>/」
- 路径口径由两类改三类(技能级工具箱 / 本段自带资产 / 同根技能)

不入库(磁盘保留)
- design-system-tiaoyue 整个目录(用户 2026-10-16 令):git rm -r --cached + .gitignore,理由=14 MB 且可 CDP 重采;
  已在 ③段 SKILL.md 注明「取仓后这一层是空的属正常,用自带套需另取或重采」
- element-picker 的运行期存档 marks/(服务自己会建目录)
2026-10-16 23:13:33 +08:00

143 lines
13 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Package rank by quarter · Bump chart</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #2d3142;
--color-ink: #f5f5f5;
--color-muted: #bfc0c0;
--color-accent: #f08a59;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body { font-family: var(--font-sans); background: var(--color-paper); color: var(--color-ink); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 3rem 2rem; }
.frame { max-width: 1200px; width: 100%; }
.eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.15; margin-bottom: 1.5rem; }
svg { width: 100%; min-width: 760px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Bump chart · Diagram Design</p>
<h1>The default everyone stopped choosing</h1>
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="bump-dark-title bump-dark-desc">
<title id="bump-dark-title">The default everyone stopped choosing</title>
<desc id="bump-dark-desc">Bump chart ranking six internal packages by weekly downloads across four quarters; legacy-http slides from first to sixth while fetch-kit takes the top rank in the second quarter and keeps it.</desc>
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(245,245,245,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#2d3142"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Rank is ORDINAL: every vertex sits exactly on a rank row, y = 88 + 56 x
(rank - 1), and every snapshot's ranks are a permutation of 1..6.
scripts/verify-bump.py enforces both against the ranks each series
declares - there is no tolerance, because rank has no fractions. -->
<text transform="rotate(-90 24 228)" x="24" y="228" fill="#bfc0c0" font-size="7" font-family="'Geist Mono', monospace" letter-spacing="0.14em" text-anchor="middle">RANK BY WEEKLY DOWNLOADS · 1 = MOST</text>
<!-- One axis rule per snapshot. No gridlines: the dots are the readable
positions and each series prints its first and last rank. -->
<line x1="320" y1="64" x2="320" y2="392" stroke="rgba(245,245,245,0.25)" stroke-width="1"/>
<text data-axis="0" data-state="Q1" x="320" y="416" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.14em" text-anchor="middle">Q1</text>
<line x1="440" y1="64" x2="440" y2="392" stroke="rgba(245,245,245,0.25)" stroke-width="1"/>
<text data-axis="1" data-state="Q2" x="440" y="416" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.14em" text-anchor="middle">Q2</text>
<line x1="560" y1="64" x2="560" y2="392" stroke="rgba(245,245,245,0.25)" stroke-width="1"/>
<text data-axis="2" data-state="Q3" x="560" y="416" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.14em" text-anchor="middle">Q3</text>
<line x1="680" y1="64" x2="680" y2="392" stroke="rgba(245,245,245,0.25)" stroke-width="1"/>
<text data-axis="3" data-state="Q4" x="680" y="416" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.14em" text-anchor="middle">Q4</text>
<!-- Straight segments between adjacent snapshots - never splines, which
invent a trajectory between ranks that were only measured quarterly.
Ramp ordered by Q1 rank: opacity records the opening order. -->
<path data-series="authx" data-ranks="2,3,3,2" d="M320,144 L440,200 L560,200 L680,144" fill="none" stroke="rgba(245,245,245,0.80)" stroke-width="1.2"/>
<circle cx="320" cy="144" r="3" fill="rgba(245,245,245,0.80)"/>
<circle cx="440" cy="200" r="3" fill="rgba(245,245,245,0.80)"/>
<circle cx="560" cy="200" r="3" fill="rgba(245,245,245,0.80)"/>
<circle cx="680" cy="144" r="3" fill="rgba(245,245,245,0.80)"/>
<text data-series="authx" data-end="first" data-role="name" x="272" y="147.5" fill="#f5f5f5" font-size="11" font-weight="500" font-family="'Geist', sans-serif" text-anchor="end">authx</text>
<text data-series="authx" data-end="first" data-role="rank" x="304" y="147.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end">#2</text>
<text data-series="authx" data-end="last" data-role="rank" x="696" y="147.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace">#2</text>
<text data-series="authx" data-end="last" data-role="name" x="728" y="147.5" fill="#f5f5f5" font-size="11" font-weight="500" font-family="'Geist', sans-serif">authx</text>
<path data-series="fetch-kit" data-ranks="3,1,1,1" d="M320,200 L440,88 L560,88 L680,88" fill="none" stroke="rgba(245,245,245,0.75)" stroke-width="1.2"/>
<circle cx="320" cy="200" r="3" fill="rgba(245,245,245,0.75)"/>
<circle cx="440" cy="88" r="3" fill="rgba(245,245,245,0.75)"/>
<circle cx="560" cy="88" r="3" fill="rgba(245,245,245,0.75)"/>
<circle cx="680" cy="88" r="3" fill="rgba(245,245,245,0.75)"/>
<text data-series="fetch-kit" data-end="first" data-role="name" x="272" y="203.5" fill="#f5f5f5" font-size="11" font-weight="500" font-family="'Geist', sans-serif" text-anchor="end">fetch-kit</text>
<text data-series="fetch-kit" data-end="first" data-role="rank" x="304" y="203.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end">#3</text>
<text data-series="fetch-kit" data-end="last" data-role="rank" x="696" y="91.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace">#1</text>
<text data-series="fetch-kit" data-end="last" data-role="name" x="728" y="91.5" fill="#f5f5f5" font-size="11" font-weight="500" font-family="'Geist', sans-serif">fetch-kit</text>
<path data-series="queuelib" data-ranks="4,5,5,4" d="M320,256 L440,312 L560,312 L680,256" fill="none" stroke="rgba(245,245,245,0.70)" stroke-width="1.2"/>
<circle cx="320" cy="256" r="3" fill="rgba(245,245,245,0.70)"/>
<circle cx="440" cy="312" r="3" fill="rgba(245,245,245,0.70)"/>
<circle cx="560" cy="312" r="3" fill="rgba(245,245,245,0.70)"/>
<circle cx="680" cy="256" r="3" fill="rgba(245,245,245,0.70)"/>
<text data-series="queuelib" data-end="first" data-role="name" x="272" y="259.5" fill="#f5f5f5" font-size="11" font-weight="500" font-family="'Geist', sans-serif" text-anchor="end">queuelib</text>
<text data-series="queuelib" data-end="first" data-role="rank" x="304" y="259.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end">#4</text>
<text data-series="queuelib" data-end="last" data-role="rank" x="696" y="259.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace">#4</text>
<text data-series="queuelib" data-end="last" data-role="name" x="728" y="259.5" fill="#f5f5f5" font-size="11" font-weight="500" font-family="'Geist', sans-serif">queuelib</text>
<path data-series="logfmt" data-ranks="5,4,2,3" d="M320,312 L440,256 L560,144 L680,200" fill="none" stroke="rgba(245,245,245,0.66)" stroke-width="1.2"/>
<circle cx="320" cy="312" r="3" fill="rgba(245,245,245,0.66)"/>
<circle cx="440" cy="256" r="3" fill="rgba(245,245,245,0.66)"/>
<circle cx="560" cy="144" r="3" fill="rgba(245,245,245,0.66)"/>
<circle cx="680" cy="200" r="3" fill="rgba(245,245,245,0.66)"/>
<text data-series="logfmt" data-end="first" data-role="name" x="272" y="315.5" fill="#f5f5f5" font-size="11" font-weight="500" font-family="'Geist', sans-serif" text-anchor="end">logfmt</text>
<text data-series="logfmt" data-end="first" data-role="rank" x="304" y="315.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end">#5</text>
<text data-series="logfmt" data-end="last" data-role="rank" x="696" y="203.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace">#3</text>
<text data-series="logfmt" data-end="last" data-role="name" x="728" y="203.5" fill="#f5f5f5" font-size="11" font-weight="500" font-family="'Geist', sans-serif">logfmt</text>
<path data-series="schema-gen" data-ranks="6,6,6,5" d="M320,368 L440,368 L560,368 L680,312" fill="none" stroke="rgba(245,245,245,0.62)" stroke-width="1.2"/>
<circle cx="320" cy="368" r="3" fill="rgba(245,245,245,0.62)"/>
<circle cx="440" cy="368" r="3" fill="rgba(245,245,245,0.62)"/>
<circle cx="560" cy="368" r="3" fill="rgba(245,245,245,0.62)"/>
<circle cx="680" cy="312" r="3" fill="rgba(245,245,245,0.62)"/>
<text data-series="schema-gen" data-end="first" data-role="name" x="272" y="371.5" fill="#f5f5f5" font-size="11" font-weight="500" font-family="'Geist', sans-serif" text-anchor="end">schema-gen</text>
<text data-series="schema-gen" data-end="first" data-role="rank" x="304" y="371.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end">#6</text>
<text data-series="schema-gen" data-end="last" data-role="rank" x="696" y="315.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace">#5</text>
<text data-series="schema-gen" data-end="last" data-role="name" x="728" y="315.5" fill="#f5f5f5" font-size="11" font-weight="500" font-family="'Geist', sans-serif">schema-gen</text>
<!-- legacy-http FOCAL - and it is the series that FELL. The accent marks the
editorially focal line, never the winner. Focus is carried by stroke
weight, not tone, for the reason the slopegraph section gives: the
accent measures 2.86:1 on light paper. Drawn last so its descent
crosses over, not under, the lines it overtakes downward. -->
<path data-series="legacy-http" data-ranks="1,2,4,6" d="M320,88 L440,144 L560,256 L680,368" fill="none" stroke="#f08a59" stroke-width="2.4"/>
<circle cx="320" cy="88" r="4" fill="#f08a59"/>
<circle cx="440" cy="144" r="4" fill="#f08a59"/>
<circle cx="560" cy="256" r="4" fill="#f08a59"/>
<circle cx="680" cy="368" r="4" fill="#f08a59"/>
<text data-series="legacy-http" data-end="first" data-role="name" x="272" y="91.5" fill="#f5f5f5" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="end">legacy-http</text>
<text data-series="legacy-http" data-end="first" data-role="rank" x="304" y="91.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end">#1</text>
<text data-series="legacy-http" data-end="last" data-role="rank" x="696" y="371.5" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace">#6</text>
<text data-series="legacy-http" data-end="last" data-role="name" x="728" y="371.5" fill="#f5f5f5" font-size="11" font-weight="600" font-family="'Geist', sans-serif">legacy-http</text>
<!-- Legend -->
<line x1="40" y1="462" x2="960" y2="462" stroke="rgba(245,245,245,0.10)" stroke-width="0.8"/>
<text x="40" y="478" fill="#bfc0c0" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<text x="960" y="478" fill="#bfc0c0" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.06em" text-anchor="end">RANKED BY WEEKLY DOWNLOADS, TIES KEEP PRIOR ORDER · SAME MEASURE EVERY QUARTER · ILLUSTRATIVE FIGURES, NOT A MEASURED REGISTRY</text>
<line x1="40" y1="492" x2="64" y2="492" stroke="#f08a59" stroke-width="2.4"/>
<circle cx="52" cy="492" r="4" fill="#f08a59"/>
<text x="72" y="496" fill="#bfc0c0" font-size="8.5" font-family="'Geist', sans-serif">legacy-http · focal, first to sixth in a year</text>
<line x1="320" y1="492" x2="344" y2="492" stroke="rgba(245,245,245,0.80)" stroke-width="1.2"/>
<circle cx="332" cy="492" r="3" fill="rgba(245,245,245,0.80)"/>
<text x="352" y="496" fill="#bfc0c0" font-size="8.5" font-family="'Geist', sans-serif">Other packages · opacity records the Q1 order</text>
</svg>
</div>
</body>
</html>