study-kanban
Convert any learning input — a URL link, a topic/goal description, or pasted learning material — into a
self-contained, standalone HTML study-kanban board whose visual style is a 1:1 match with the fixed
visual spec below (blue-gradient header, collapsible sidebar, progress ring, type-tag legend, stage-pill
toolbar, horizontally-scrolling columns of knowledge-point cards).
The board ALWAYS uses a fixed 5-stage framework (入门 → 基础 → 进阶 → 实战 → 精通). Every knowledge point
is explained in plain language (a "通俗讲解" field) so a complete beginner can understand it. The content
aims to be comprehensive — covering prerequisites through advanced topics with no gaps — so a learner can
go from zero to mastery along one coherent path.
When to use
- The user supplies a single URL (official site, docs page, tutorial, spec, learning material) and asks
to turn it into a kanban / learning board. - The user supplies a topic or goal description (e.g. "我要学习 Python 爬虫做数据分析") with no source
material — the skill first gathers reference material in priority order (官网 → 高质量社区/论坛 → 用户
参考图/资料), compiles it, then builds the learning path from that consolidated corpus with verified links. - The user supplies pasted learning material (notes / a tutorial / a bullet outline) and wants it
reorganized into a staged, beginner-friendly kanban. - The user asks to "generate a study kanban", "convert this doc into a board", "整理一个学习路线", or
referencesstudy-kanbanexplicitly. - The desired output is an independent HTML file that can be opened by double-click or lightly published,
NOT just data injected into another project.
What this skill provides
template/— a config-driven, per-topic data-file kanban template (HTML + css/style.css +
js/manifest.js + js/data/<topic-id>.js + js/app.js) whose visuals follow the fixed visual spec below.
Board data is split into ONE independent data file per topic underjs/data/, registered in
js/manifest.js, and lazy-loaded — only the data of the topic you select is downloaded. It renders
ONE board when the input is a single topic, and MULTIPLE switchable boards (left-side menu per topic)
when the input names several topics.- This SKILL.md — the workflow that drives input → structured data → independent HTML.
Design principles to preserve (fixed visual spec)
Visual spec (IMPORTANT): the design tokens, tag rendering, and layout enumerated in this section are
the single 1:1 visual reference for this skill. Any change to template/ (HTML/CSS/JS) MUST keep
the generated board visually identical to this spec — do not diverge the design tokens, tag rendering,
or layout described here.
Keep these exact visual tokens so the generated board is indistinguishable in style:
- Background
#f5f7fa; primary blue#3b82f6; gradients: header135deg #1e3a5f→#2563eb→#3b82f6,
sidebar180deg #1e3a5f→#1e40af→#2563eb. - Column: width
220px, top3pxstage-color border (--col-color). - Card:
min-height: 210px, fields = checkbox+title, type tag, description, 通俗讲解 (new),
验收标准 (left-border block), "查看文档 →" link. - Card interaction: clicking anywhere on the card (not just the checkbox) toggles its done state,
saves progress, and syncs the matching left-menu link. The checkbox is a visual indicator only. - Four type tags (keep their colors even if a subset is used). Rendering style matches the visual spec
exactly: light background + dark text (NOT solid fill) — so a tag reads as e.g.
reading= bg#dbeafe/ text#2563eb,hands-on= bg#ccfbf1/ text#0d9488,
practice= bg#ede9fe/ text#7c3aed,mastery= bg#fef3c7/ text#b45309.
Do NOT change tag rendering to solid-fill. - Progress ring:
conic-gradientwhite over translucent; glassmorphism pill container. - Stage pills in toolbar; legend row; one-click 全选 / 重置 buttons; collapsible sidebar.
Note: 全选 / 重置 buttons operate on the currently visible board only (in a multi-board layout they
do NOT affect the other boards' checkboxes). - Legend: the four type labels render as the SAME light-bg/dark-text chips as the card tags (1:1 with
the card-tag chip style —.legend-tag), NOT solid color dots.
Fixed 5-stage framework (MANDATORY)
Every board uses exactly these five stages, in this order, with these ids/titles/subtitles/colors.
Do NOT add, remove, reorder, or rename stages. Map the material's content into these five buckets —
when a topic has little to say at a given stage, still keep the column but fill it with the minimal
prerequisite / foundation knowledge a beginner needs there.
[
{ id: 1, title: "入门", subtitle: "零基础起步 · 建立认知", color: "#3b82f6" },
{ id: 2, title: "基础", subtitle: "核心概念与工具 · 打地基", color: "#14b8a6" },
{ id: 3, title: "进阶", subtitle: "深入原理与技巧 · 提升", color: "#8b5cf6" },
{ id: 4, title: "实战", subtitle: "真实项目演练 · 应用", color: "#f59e0b" },
{ id: 5, title: "精通", subtitle: "优化与扩展 · 融会贯通", color: "#ec4899" }
]
Stage intent (use as a guide when distributing items):
- 入门 — 让零基础也能迈出第一步:这是什么、能解决什么问题、学之前要准备什么(环境/账号/前置知识)、
最小可行路径(跑通第一个 hello world / 看到第一个效果)。多用生活化比喻,避免一上来就堆术语。 - 基础 — 核心概念与日常工具:关键术语与心智模型、最常用语法/API/命令、基础工程结构/配置、如何运行与调试。
- 进阶 — 原理与技巧:内部机制、常见模式、性能/可读性相关的写法、典型坑与排查方法。
- 实战 — 真实项目演练:从需求拆解到完整实现,至少 1 个可运行项目,覆盖真实场景中的综合用法。
- 精通 — 优化与扩展:性能调优、最佳实践、生态/框架扩展、源码/原理深挖、可进阶的方向。
Knowledge-point item shape (updated)
Each item MUST use this exact field shape. The new explain field is required for beginner
friendliness — do not omit it.
{
title: "知识点标题", // short, imperative or noun phrase
type: "reading" | "hands-on" | "practice" | "mastery", // pick the best fit
desc: "一句话描述学习者将理解或做到什么",
explain: "用大白话解释:这是什么、为什么这样、怎么上手(面向零基础,最好带一个生活化比喻)", // 新增,必填
criteria: "可观察、可验收的标准(学习者做到什么算掌握)",
link: "https://... 该知识点对应的原文锚点,尽量用原链接" // 可选;为空时卡片不显示「查看文档 →」,左侧菜单该知识点渲染为不可跳转的静态项
// 协议约束:`link` 必须是 http(s) 绝对链接(以 https:// 或 http:// 开头)。
// 相对路径、file://、或任何其他协议会被模板的 safeLink 过滤为 "#" 而不渲染链接,请勿使用。
// 可用性约束(MANDATORY):`link` 必须是已验证「能打开 + 内容确实覆盖该知识点」的 URL,
// 不能是打不开(404/需登录/空页/错误页)或内容无关的链接。无法验证时宁可留空(见「Link verification」)。
}
Type selection guide (adaptive — use the subset that fits the material):
- reading : 阅读理解 — read/docs, build认知.
- hands-on : 动手实操 — follow steps, do it once.
- practice : 练习巩固 — complete independently.
- mastery : 综合应用 — real scenario drill.
- Template fallback: if an item.type is missing or not one of the four values, the template renders it
as reading (tag + label) so the card never breaks. Still, always supply a valid type.
Comprehensiveness rules (no gaps)
Before finalizing, verify the board covers ALL of the following for the given topic. If any is missing
and relevant, add the corresponding items (prefer putting them in the matching stage):
- 概念定义 — what it is, what problem it solves, when to use vs. not use (usually 入门).
- 前置准备 — environment, accounts, tools, required prior knowledge (入门).
- 核心概念 / 心智模型 — the mental model a beginner must hold (基础).
- 最常用的语法 / API / 命令 — the daily 80% (基础).
- 工程结构与配置 — how a real project is laid out and configured (基础).
- 运行与调试 — how to run it and how to read/fix errors (基础/进阶).
- 原理与内部机制 — why it works under the hood (进阶).
- 典型坑与排查清单 — the mistakes beginners actually make (进阶).
- 至少一个完整可运行项目 — end-to-end from requirement to deploy (实战).
- 性能 / 优化 / 最佳实践 / 生态扩展 — going beyond "it works" (精通).
If the user supplied pasted material only, you may keep link empty or point to a sensible official
doc, but still FILL every stage with the prerequisite/foundation knowledge the material omits, so the
path is complete for a beginner. Never leave a stage empty. Regardless of input type, every emitted link
must pass "Link verification" — an empty link is always acceptable, a dead/irrelevant one is not.
Workflow
Follow these steps in order whenever the skill is triggered.
Step 1 — Identify the input type & topic count
Inspect the user's input:
- If it starts with
http://orhttps://(a single valid URL), treat it as a link input → go to
Step 2a. Note: a link input is always a single topic (one board). - Otherwise treat it as text input (a topic/goal description OR pasted learning material) → go to Step 2b.
Multi-topic detection (text input only). If the text describes MORE THAN ONE learning subject, split
them into separate topics. Split the text by scanning for ANY of the following separators (Chinese words,
Chinese punctuation, and ASCII symbols are all valid — the user may write "a和b"、"a+b"、"a/b"、"a,b"、
"a、b"、"a,b"、"a|b"、"a&b"、"a and b" or even just "a b", and all must be recognized):
- Chinese connectives: 和、与、以及、及、跟、同 (e.g. "sqlserver 和 oracle"、"Python 与 SQL").
- Chinese punctuation: 顿号 "、"、中文逗号 "," (e.g. "Python、Java"、"Python,Java").
- ASCII symbols: 半角逗号 ","、加号 "+"、斜杠 "/"、竖线 "|"、连接符 "&" (e.g. "a+b"、"a/b"、"a,b").
- English word: "and" (e.g. "Python and SQL").
- Whitespace juxtaposition: two clearly independent subjects separated only by spaces (e.g. "sqlserver
oracle"); split only when each side is a complete, standalone subject.
After splitting, TRIM each fragment; a fragment becomes ONE board only if it is a complete, independent
subject (e.g. a named technology, language, or tool — "sqlserver", "oracle", "Python", "Java").
Special cases — do NOT split on a separator that is part of a term:
- "+" inside "C++" is part of the language name, not a separator: "C++" → 1 board, "C++ 和 Python" → 2 boards.
- "/" inside a versioned/proper name such as "HTTP/2" or "Vue3/TS" is NOT a separator unless each side is
itself independently learnable.
- A hyphen "-" is a separator only when both sides are complete, independent subjects (e.g. "sqlserver-oracle"
→ 2 boards); do not split hyphenated single terms like "machine-learning".
Examples:
- "我想学习 sqlserver 和 oracle" → 2 topics → 2 boards (sqlserver, oracle).
- "我想同时学 Python+SQL" → 2 topics → 2 boards (python, sql).
- "帮我做 Vue/React 学习看板" → 2 topics → 2 boards (vue, react).
- "深度学习,机器学习" → 2 topics → 2 boards (deep-learning, machine-learning).
- "我想学 Python 爬虫做数据分析" → 1 topic (the phrase is one coherent goal) → 1 board.
- When ambiguous (one subject with sub-parts vs. multiple subjects), treat them as multiple subjects only
if each can stand alone as a full learning path; otherwise keep one board. Do NOT ask unless truly
ambiguous — prefer producing the multiple boards.
If the user gave multiple links, generate one board per link (one output folder each) or merge them into
the 5-stage framework when they belong to one curriculum — ask only if ambiguous.
If the user gave both a link and some text, prefer the link as the primary source and use the text as
scope/context, then still apply the fixed 5-stage framework.
Step 2a — Fetch & extract (link input)
Call WebFetch on the URL with a fetchInfo such as:
"Extract the learning content as an ordered outline. Identify the main modules/chapters/sections and,
under each, the concrete knowledge points or tasks a learner should master. For each knowledge point
capture: a short title, what the learner should understand or be able to do (description), a plain-language
explanation a complete beginner would understand (with an everyday analogy if possible), a concrete
observable acceptance criterion, and the most relevant source anchor/URL within the page."
The anchors you extract go into link ONLY after the "Link verification" step below (a sub-page anchor of a
given URL may be dead even when the main page opens — verify each one you actually emit).
Step 2b — Parse text (text input)
Read the user's text:
- Pasted material (notes / tutorial / outline): treat it as the primary source. Reorganize it into the
5-stage framework, and FILL any stage the material leaves thin with the prerequisite/foundation knowledge
a beginner needs there.linkmay be empty or point to a verified official doc. - Topic/goal description (e.g. "我要学习 Python 爬虫做数据分析"): DO NOT build the whole path from
memory alone. Gather reference material FIRST in this mandatory priority order, compile it, and only
then structure the board (see "Source gathering" below):
1. 官网 / 官方文档 — WebSearch for the topic's official site (e.g. "<主题> 官网", "<topic> official
site / docs"), then WebFetch the docs / getting-started page to obtain the canonical module structure
and key terms.
2. 高质量社区 / 论坛 / 用户提供的资料 — WebSearch for authoritative community content (official doc
portals, MDN-style references, well-known forums such as Stack Overflow, high-star GitHub repos, or
the topic's official community); prefer recent, widely-used, maintainer/community-verified pages.
If the user attached reference images (学习路线图 / 截图) or pasted material, treat them as
the most authoritative input and use them to confirm or override the web-gathered outline.
3. 汇总 — merge everything into one consolidated material corpus: canonical module list + concrete
knowledge points + at least one reliable, verified URL per point. Build the boards from THIS corpus,
not from unverified memory. (Your own knowledge may fill gaps the sources omit, but the content and
links must trace back to the compiled material.)
Source gathering (priority order — MANDATORY for topic/goal input)
Whenever the user says something like "我要学习XX" / "我想学XX" (a topic with no URL attached), gather
reference material in EXACTLY this priority:
- 官网 / 官方文档 — the canonical structure, terminology, and getting-started flow come from here.
- 高质量社区 / 论坛 — community-recommended tutorials, best practices, common pitfalls (the 进阶/实战/
精通 stages are usually enriched here). - 用户输入的参考图片或提供的资料 — user-provided screenshots / roadmaps / pasted notes are the
strongest signal for what the user actually wants; align the board to them.
Gather until each stage bucket of the fixed 5-stage framework has at least one source (official preferred),
then compile/summarize before outputting: only after the material is consolidated do you write the
boards. Never jump straight from the user's one-liner to final cards with links you have not sourced.
Link verification (MANDATORY — applies to ALL inputs, all stages)
Every non-empty link you emit MUST satisfy ALL of the following, otherwise leave the field EMPTY (the card
then shows no "查看文档 →" — an empty link is always better than a dead one):
- It really opens — valid
https:///http://absolute URL. If you are not 100% sure, WebFetch it to
confirm it does not 404, redirect to a login wall, or return an empty/error page. - It actually covers that knowledge point — the page's content genuinely explains the item's topic (not
just a passing mention). The more specific the anchor the better (e.g. point to the exact doc section for
"数组遍历" rather than the library homepage). - No junk links — do NOT use search-result tracker URLs, short-link services, login-required pages,
known-dead pages, or unverifiable AI-generated aggregator pages. Prefer stable official domains and
long-lived community classics. - No invented URLs — never write a URL from memory without verifying it. If you cannot verify, omit.
- Protocol — only
http(s)absolute links; relative paths /file:/// other protocols are filtered by
the template to#and must not be used.
Step 3 — Structure into boards (each = fixed 5 stages)
For a single topic, you produce ONE board. For multiple topics, you produce ONE board PER topic.
Each board is an independent object with its own id (kebab-case slug), title, subtitle, and stages,
and in the final output each board lives in its OWN data file js/data/<id>.js (see Step 4).
For every board, map its knowledge points into exactly the five stages from the Fixed 5-stage framework
section. Assign each item a type; write desc (one sentence) and a required explain (plain language,
beginner-friendly, with an analogy where helpful); write an observable criteria; set link ONLY to a verified, useful URL
per the "Link verification" section above (for text/topic input, link comes from the consolidated
material corpus — prefer the official doc for the core concepts and the community source for 进阶/实战/精通
items; never emit an unverified link).
Board object:
{
id: "sqlserver", // kebab-case slug, used for DOM id + localStorage key prefix
title: "SQL Server 学习路线", // shown as the top-level left menu label
icon: "🗄️", // 可选:左侧一级菜单前的小图标(emoji 或单字符),缺省回退 📘
subtitle: "从入门到精通 · 5 阶段、N 个知识点",
stages: [
{
id: 1, // MUST be 1..5 per the fixed framework
title: "入门", // MUST match the fixed framework title for this id
subtitle: "零基础起步 · 建立认知", // MUST match the fixed framework subtitle for this id
color: "#3b82f6", // MUST match the fixed framework color for this id
items: [ /* item objects */ ]
}
/* ... stages 2..5 ... */
]
}
The left-side menu is generated from these boards automatically by js/app.js:
- One top-level menu per board (label = board.title, e.g. "SQL Server"), prefixed with an icon
(board.icon or the 📘 fallback). Each top-level menu has a clickable header.
- Under each top-level menu, its 5 stage groups (入门 / 基础 / 进阶 / 实战 / 精通) are rendered, each
listing its knowledge-point links; clicking a link with item.link opens it in a new tab, and a link with
no item.link renders as a non-clickable static item (no href="#" jump).
- Collapse / expand: clicking a top-level menu header switches the right side to that board's kanban
and expands that menu group; clicking the ▾ arrow (inside the header) folds/expands only that group
without switching boards. By default only the first board's group is expanded and the rest are collapsed —
at most one group is expanded at a time. (All handled by the template — you only need to supply the
manifest entries + data files.)
- Lazy loading: the menu (built from the manifest) appears immediately; a topic's stage links and board
appear after its js/data/<id>.js is fetched on first selection. Expanding a collapsed menu whose topic
was never opened also triggers the load, so the links are available without switching boards.
- A knowledge-point link mirrors its card's done state: when the card is completed, the menu link shows a
green check + strikethrough and stays in sync on board switch / 全选 / 重置.
Step 4 — Generate the standalone board (per-topic data files + manifest)
- Copy
template/to the output directory. Default output dir (relative to the skill, kept outside the
skill itself so it is not re-packaged):study-kanban/output/<slug>/where<slug>is a short
kebab-case name derived from the (primary) topic/title (e.g.python-crawler). For multi-topic input,
if a single output folder is used, the<slug>may be a combined name (e.g.sqlserver-oracle). If
the user specified a path, use it. - Create ONE data file per topic under
js/data/, namedjs/data/<id>.js. Each file registers its
board object on the global map:
js window.BOARDS_DATA = window.BOARDS_DATA || {}; window.BOARDS_DATA["<id>"] = { /* board object from Step 3 */ };
Single topic → ONE file (e.g.js/data/sqlserver.js); N topics → N files. Do NOT put multiple boards
into a singledata.js— the per-topic split is the intended architecture (lazy-loaded). - Register every topic in
js/manifest.js: replace the placeholder line
window.BOARD_MANIFEST = __BOARD_MANIFEST__;with an array of manifest entries, ONE per topic:
js window.BOARD_MANIFEST = [ { id: "sqlserver", title: "SQL Server 学习路线", icon: "🗄️", subtitle: "从入门到精通 · 5 阶段、10 个知识点,零基础也能学会", data: "js/data/sqlserver.js" }, // ... one entry per topic; `data` MUST match js/data/<id>.js ];
Thedatapath is whatjs/app.jslazy-loads when that topic is selected — it MUST point to the file
created in step 2, andidMUST match the data file'swindow.BOARDS_DATA["<id>"]. - Replace the HTML placeholders (these seed the header for the FIRST board; switching menus updates them
dynamically viajs/app.js):
-<title>__BOARD_TITLE__</title>
-.header-left h1text →__BOARD_TITLE__
-.header-left ptext →__BOARD_SUBTITLE__(e.g. "从入门到精通 · 5 个阶段、N 个知识点,零基础也能学会").
Use the first board's title/subtitle and total item count across all boards (or just the first board)
when fillingN. - Keep
css/style.cssandjs/app.jsuntouched (they render all boards from the manifest + data files,
including theexplainfield, the left menu, and lazy loading). Optionally delete
js/data/_README.txt(a template-only note; harmless to keep).
Step 5 — Report
Tell the user the absolute path of the generated index.html and a one-line summary (stages count,
items count, source type — link or text). Mention it can be opened directly or lightly published.
Template placeholder reference
js/manifest.js: the only injection point is the manifest array placeholder
window.BOARD_MANIFEST = __BOARD_MANIFEST__;— replace it with an array of manifest entries, ONE per
topic (see Step 4). Each entry is{ id, title, icon, subtitle, data }wheredatapoints to that
topic's data file (js/data/<id>.js). The manifest is what the left-side menu is built from — it is
loaded eagerly withindex.html, so the menu is visible before any topic data arrives.js/data/<id>.js: ONE file per topic. Each defines the board object (see Step 3) registered on the
global map aswindow.BOARDS_DATA["<id>"] = { id, title, icon, subtitle, stages }.idandstages
follow the fixed 5-stage framework; eachitemmay include anexplainstring, rendered as a
plain-language block betweendescand验收标准. These files are loaded lazily: the first time a
topic is selected,js/app.jsinjects a<script src="js/data/<id>.js">and registers it — the page
stays lightweight when a topic is never opened.template/index.html: replace__BOARD_TITLE__(appears in<title>and.header-left h1) and
__BOARD_SUBTITLE__(.header-left p). The#boardsContainerand the left#menuGroupsContainer
are rendered byjs/app.jsfrom the manifest + loaded data — do NOT hardcode board markup into the HTML.
Constraints / notes
- The output must be fully self-contained (no dependency on any external project folder); it opens by
double-clickingindex.html. - IMPORTANT — template is "unfilled" by default. The template's
js/manifest.jscontains
window.BOARD_MANIFEST = __BOARD_MANIFEST__;,js/data/holds only a_README.txt(no real topic
data), andindex.htmlcontains__BOARD_TITLE__/__BOARD_SUBTITLE__placeholders. If these are
NOT replaced before opening, the page shows literal placeholder text and the board is blank (the
__BOARD_MANIFEST__line is a JS syntax error until injected). The generation flow in Step 4 MUST
replace the manifest placeholder AND create one data file per topic; only then is the board valid. The
committedtemplate/folder is intentionally in this unfilled state — never "fix" it by hardcoding
sample data into the template itself. - Lazy-loaded per-topic data files are the intended architecture. Never put all boards back into a
singledata.js; keep ONE file per topic injs/data/and register each topic injs/manifest.js.
This keeps generation incremental (adding a topic = one new data file + one manifest entry) and keeps
the page light (only the selected topic's data is fetched). - Multi-board progress is isolated per board and survives browser restart. Each board's progress is stored
under keystudy_kanban_progress_<board.id>. Primary store islocalStorage; when it is unavailable (e.g.
file://in private mode / restricted browsers), the template transparently falls back to the OPFS (Origin
Private File System), which persists across sessions on Chromiumfile://. The app auto-loads saved progress on
open. If neither store is available, a non-blocking notice is shown and progress is kept in-memory for the session. - ALWAYS use exactly the fixed 5 stages (入门/基础/进阶/实战/精通) inside EACH board. When the input has
multiple topics, DO create multiple boards (one per topic) — this is now the intended behavior. Never
fold two distinct subjects into one board's five stages. - Preserve the card field structure exactly (now with
explain); only the content and granularity
are adaptive.
Maintenance convention (template ↔ example must stay in sync)
template/ is the golden reference. output/_example/ is a filled, runnable demo generated from it:
its js/manifest.js (real topic list) and js/data/sqlserver.js + js/data/python.js (real per-topic
data) are the ONLY files that should differ from the template. template/js/app.js and
template/css/style.css are shared verbatim with output/_example/ (byte-identical). index.html
is shared except for the title/subtitle: the template keeps __BOARD_TITLE__ / __BOARD_SUBTITLE__
placeholders while the example substitutes real text — when re-syncing index.html from the template,
restore the example's real title/subtitle afterwards. Whenever template/js/app.js or
template/css/style.css changes, copy them into output/_example/ byte-for-byte (keep the example's
manifest.js and js/data/ intact). This prevents the example from silently drifting out of date and
no longer representing real output.
Critical: TYPE_LABELS lives only in js/app.js
const TYPE_LABELS = {...} is declared at the top of js/app.js and is the single source of truth in
both the template and the example. Data files (js/data/<id>.js) and js/manifest.js do NOT declare it.
When re-syncing output/_example/js/app.js from template/js/app.js, copy it verbatim — there is no
duplicate declaration to delete.