concept-atlas-dense-explain 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Concept Atlas contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # concept-atlas-dense-explain
2
+
3
+ Compile semantic MDX into a standalone, interactive Concept Atlas HTML page. The
4
+ same workflow ships as an AI-agent skill, so an agent can generate, validate and
5
+ render a "dense explainer" without hand-writing any layout.
6
+
7
+ Two page shells share one component library:
8
+
9
+ - `atlas` — concept graph with node navigation (`ExplainPage` → `ConceptGraph` → `ConceptNode`)
10
+ - `scroll` — continuous document with an auto-built table of contents
11
+
12
+ ## CLI
13
+
14
+ ```bash
15
+ # Learn the components from a real, compilable reference
16
+ npx concept-atlas-dense-explain guide --mode atlas -o atlas-guide.mdx
17
+ npx concept-atlas-dense-explain guide --mode scroll -o scroll-guide.mdx
18
+
19
+ # Scaffold a document skeleton
20
+ npx concept-atlas-dense-explain create topic.mdx --mode atlas
21
+
22
+ # Validate structure before building
23
+ npx concept-atlas-dense-explain validate topic.mdx --mode atlas
24
+
25
+ # Compile to a standalone HTML file beside the MDX
26
+ npx concept-atlas-dense-explain topic.mdx --mode atlas
27
+ ```
28
+
29
+ `guide` and `create` refuse to overwrite an existing file unless `--force` is
30
+ passed. Use `-o` to choose the output path (a directory when passing several
31
+ inputs). Validation errors abort the build; `--no-validate` forces a knowingly
32
+ broken build.
33
+
34
+ Mermaid loads from a CDN at runtime by default (fast builds, needs network);
35
+ `--inline-mermaid` bakes it into the HTML for a fully offline single file, and
36
+ `--mermaid-cdn` overrides the CDN URL. Appearance defaults can be baked with
37
+ `--skin`, `--default-mode` and `--style`; readers can still switch in the UI.
38
+
39
+ Run `npx concept-atlas-dense-explain help` for the full flag list.
40
+
41
+ ## Links
42
+
43
+ - Repository: https://github.com/wurenrumian/concept-atlas
44
+ - Framework guide: [`docs/FRAMEWORK.md`](https://github.com/wurenrumian/concept-atlas/blob/main/docs/FRAMEWORK.md)
45
+ - Usage recipes: [`docs/USAGE.md`](https://github.com/wurenrumian/concept-atlas/blob/main/docs/USAGE.md)
46
+
47
+ ## License
48
+
49
+ MIT
package/bin/cli.mjs CHANGED
@@ -114,14 +114,14 @@ if (command === 'guide') {
114
114
  console.error(`Refusing to overwrite ${output}; pass --force to replace it.`);
115
115
  process.exit(1);
116
116
  }
117
- const source = path.join(templateRoot, 'guides', `${mode}-guide.mdx`);
117
+ const source = path.join(templateRoot, 'references', `${mode}-guide.mdx`);
118
118
  if (!(await exists(source))) {
119
119
  console.error(`Guide for mode "${mode}" is missing from the package.`);
120
120
  process.exit(1);
121
121
  }
122
122
  await mkdir(path.dirname(output), { recursive: true });
123
123
  await copyFile(source, output);
124
- const assetsSource = path.join(templateRoot, 'guides', 'assets');
124
+ const assetsSource = path.join(templateRoot, 'references', 'assets');
125
125
  const assetsTarget = path.join(path.dirname(output), 'assets');
126
126
  if (await exists(assetsSource) && path.resolve(assetsSource) !== path.resolve(assetsTarget) && (args.includes('--force') || !(await exists(assetsTarget)))) {
127
127
  await cp(assetsSource, assetsTarget, { recursive: true, force: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "concept-atlas-dense-explain",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Portable dense-explanation skill and MDX concept atlas template",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,7 +12,7 @@
12
12
  "files": [
13
13
  "bin",
14
14
  "template",
15
- "skill"
15
+ "packaged-skill"
16
16
  ],
17
17
  "dependencies": {
18
18
  "@mdx-js/rollup": "^3.0.1",
@@ -34,6 +34,18 @@
34
34
  "dense-explain",
35
35
  "concept-map"
36
36
  ],
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/wurenrumian/concept-atlas.git",
40
+ "directory": "packages/concept-atlas-dense-explain"
41
+ },
42
+ "homepage": "https://github.com/wurenrumian/concept-atlas#readme",
43
+ "bugs": {
44
+ "url": "https://github.com/wurenrumian/concept-atlas/issues"
45
+ },
46
+ "engines": {
47
+ "node": ">=18"
48
+ },
37
49
  "publishConfig": {
38
50
  "access": "public"
39
51
  },
@@ -1,21 +1,29 @@
1
1
  ---
2
2
  name: concept-atlas-dense-explain
3
- description: Turn a topic or an existing document into an interactive Concept Atlas explainer. Generate AI-editable MDX with the concept-atlas-dense-explain npm CLI, validate its structure, and compile standalone HTML with concept nodes, relation graphs, math (KaTeX), charts, figures, citations, and reading aids. Use when a technical explanation, concept map, layered knowledge page, dense explainer, or interactive teaching page is requested.
3
+ description: Turn a topic or an existing document into an interactive Concept Atlas explainer. Generate AI-editable MDX with the concept-atlas-dense-explain CLI, validate its structure, and compile standalone HTML with concept nodes, relation graphs, math (KaTeX), charts, figures, citations, and reading aids. Use when a technical explanation, concept map, layered knowledge page, dense explainer, or interactive teaching page is requested.
4
4
  ---
5
5
 
6
6
  # Concept Atlas Dense Explain
7
7
 
8
- Drive everything through the `concept-atlas-dense-explain` npm CLI. This skill is intentionally lightweight: do not copy implementation files from the skill directory or recreate the React/Vite app. If a command name is unclear, run `npx concept-atlas-dense-explain help`. If the user only wants the prompt/methodology and not files, still choose a shell and emit valid MDX; the CLI is needed only to compile.
8
+ Drive everything through the `concept-atlas-dense-explain` CLI, always via `npx`. Everything you need is in this file and the bundled `references/`; do not read the framework repository or installed package files, do not copy implementation files from the skill directory, and do not recreate the React/Vite app. If a command name is unclear, run `npx concept-atlas-dense-explain help`. If the user only wants the prompt/methodology and not files, still choose a shell and emit valid MDX; the CLI is needed only to validate and compile.
9
+
10
+ ## Running the CLI
11
+
12
+ Always invoke the CLI through `npx`, from any directory:
13
+
14
+ ```bash
15
+ npx concept-atlas-dense-explain <args>
16
+ ```
17
+
18
+ This is the only runner — there is nothing to look for. Do not search for a local binary, a repository checkout, or an installed copy, and do not run the framework's own `npm` scripts. The first call downloads the package from the npm registry; say so once, then continue.
9
19
 
10
20
  ## Workflow
11
21
 
12
22
  1. Choose one page shell: `atlas` (concept graph with node navigation) or `scroll` (continuous document). Recommend `atlas` when the reader drills into concepts or follows relations, `scroll` for linear argument, tutorials, and reports. The library is shared. If an `.mdx` already exists, detect its shell and work with it.
13
- 2. **Learn the components from the canonical guide before authoring.** Generate it for the chosen shell and read it:
14
- ```bash
15
- npx concept-atlas-dense-explain guide --mode atlas -o ./concept-atlas-atlas-guide.mdx
16
- npx concept-atlas-dense-explain guide --mode scroll -o ./concept-atlas-scroll-guide.mdx
17
- ```
18
- It is real, compilable MDX showing that shell's components and their exact props; search it for a component name instead of guessing. Delete it when done.
23
+ 2. **Learn the components from the bundled reference before authoring.** The only reference you need is the guide that ships with this skill:
24
+ - `references/atlas-guide.mdx` (atlas) or `references/scroll-guide.mdx` (scroll)
25
+ It is real, compilable MDX showing that shell's components and their exact props; search it for a component name instead of guessing, and do not look for component documentation anywhere else. Do not run `guide` for this.
26
+ Run `npx concept-atlas-dense-explain guide --mode <mode> -o <file>` only when you specifically need a project-local copy to compile beside the page, and delete that copy when done.
19
27
  3. Start from a skeleton when useful: `npx concept-atlas-dense-explain create <file>.mdx --mode atlas|scroll`. `create` and `guide` refuse to overwrite an existing file unless `--force` is passed.
20
28
  4. Write the semantic MDX into the user's `.mdx` file (see Authoring rules).
21
29
  5. Validate before rendering:
@@ -70,4 +78,4 @@ Drive everything through the `concept-atlas-dense-explain` npm CLI. This skill i
70
78
  - Every node has `title` + `summary`; every `Relation` has a `label`.
71
79
  - The HTML file exists at the reported path.
72
80
 
73
- If the CLI or npm registry is unavailable, report the blocker instead of copying the implementation into the skill.
81
+ If `npx` cannot reach the registry, report the blocker. Never copy implementation files into the skill directory.
@@ -1,42 +1,42 @@
1
- <!doctype html>
2
- <html lang="zh-CN">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3E📃%3C/text%3E%3C/svg%3E" />
7
- <title>Concept Atlas · 概念缩放式知识图谱</title>
8
- <script>
9
- (function () {
10
- var doc = document.documentElement;
11
- var stored = null;
12
- try { stored = JSON.parse(localStorage.getItem('concept_atlas_appearance') || 'null'); } catch (e) {}
13
- var legacy = localStorage.getItem('concept_atlas_theme');
14
- // Placeholders are replaced at build time when --skin/--default-mode
15
- // (or CONCEPT_ATLAS_* env vars) are configured; otherwise the runtime
16
- // fallbacks below keep the carrier defaults.
17
- var skin = '__ATLAS_DEFAULT_SKIN__';
18
- if (/^__.+__$/.test(skin)) skin = 'aurora';
19
- var mode = '__ATLAS_DEFAULT_MODE__';
20
- if (/^__.+__$/.test(mode)) mode = 'light';
21
- var style = '__ATLAS_DEFAULT_STYLE__';
22
- if (/^__.+__$/.test(style)) style = 'manuscript';
23
- if (stored && (stored.mode === 'light' || stored.mode === 'dark')) {
24
- mode = stored.mode;
25
- } else if (mode !== 'light' && mode !== 'dark') {
26
- mode = legacy === 'light' || legacy === 'dark' ? legacy : 'light';
27
- }
28
- doc.setAttribute('data-skin', stored && stored.skin ? stored.skin : skin);
29
- doc.setAttribute('data-theme', mode);
30
- doc.setAttribute('data-style', stored && stored.style ? stored.style : style);
31
- })();
32
- </script>
33
- <!-- Google Fonts for Academic / Editorial Knowledge style -->
34
- <link rel="preconnect" href="https://fonts.googleapis.com">
35
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
36
- <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Lora:ital,wght@0,500;0,600;0,700;1,400&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=Noto+Serif+SC:wght@500;600;700;900&display=swap" rel="stylesheet">
37
- </head>
38
- <body>
39
- <div id="root"></div>
40
- <script type="module" src="/src/main.jsx"></script>
41
- </body>
42
- </html>
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3E📃%3C/text%3E%3C/svg%3E" />
7
+ <title>Concept Atlas · 概念缩放式知识图谱</title>
8
+ <script>
9
+ (function () {
10
+ var doc = document.documentElement;
11
+ var stored = null;
12
+ try { stored = JSON.parse(localStorage.getItem('concept_atlas_appearance') || 'null'); } catch (e) {}
13
+ var legacy = localStorage.getItem('concept_atlas_theme');
14
+ // Placeholders are replaced at build time when --skin/--default-mode
15
+ // (or CONCEPT_ATLAS_* env vars) are configured; otherwise the runtime
16
+ // fallbacks below keep the carrier defaults.
17
+ var skin = '__ATLAS_DEFAULT_SKIN__';
18
+ if (/^__.+__$/.test(skin)) skin = 'aurora';
19
+ var mode = '__ATLAS_DEFAULT_MODE__';
20
+ if (/^__.+__$/.test(mode)) mode = 'light';
21
+ var style = '__ATLAS_DEFAULT_STYLE__';
22
+ if (/^__.+__$/.test(style)) style = 'manuscript';
23
+ if (stored && (stored.mode === 'light' || stored.mode === 'dark')) {
24
+ mode = stored.mode;
25
+ } else if (mode !== 'light' && mode !== 'dark') {
26
+ mode = legacy === 'light' || legacy === 'dark' ? legacy : 'light';
27
+ }
28
+ doc.setAttribute('data-skin', stored && stored.skin ? stored.skin : skin);
29
+ doc.setAttribute('data-theme', mode);
30
+ doc.setAttribute('data-style', stored && stored.style ? stored.style : style);
31
+ })();
32
+ </script>
33
+ <!-- Google Fonts for Academic / Editorial Knowledge style -->
34
+ <link rel="preconnect" href="https://fonts.googleapis.com">
35
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
36
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Lora:ital,wght@0,500;0,600;0,700;1,400&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=Noto+Serif+SC:wght@500;600;700;900&display=swap" rel="stylesheet">
37
+ </head>
38
+ <body>
39
+ <div id="root"></div>
40
+ <script type="module" src="/src/main.jsx"></script>
41
+ </body>
42
+ </html>
@@ -1,22 +1,5 @@
1
- {
2
- "name": "my-concept-atlas",
3
- "private": true,
4
- "version": "0.1.0",
5
- "type": "module",
6
- "scripts": { "dev": "vite", "validate": "node scripts/validate-content.mjs", "build": "npm run validate && node scripts/build.mjs", "clean:temp": "node scripts/clean-temp.mjs" },
7
- "dependencies": {
8
- "@mdx-js/rollup": "^3.0.1",
9
- "clsx": "^2.1.1",
10
- "d3": "^7.9.0",
11
- "katex": "^0.16.47",
12
- "lucide-react": "^0.475.0",
13
- "mermaid": "^11.17.2",
14
- "react": "^18.3.1",
15
- "react-dom": "^18.3.1"
16
- },
17
- "devDependencies": {
18
- "@vitejs/plugin-react": "^4.3.4",
19
- "vite": "^5.4.14",
20
- "vite-plugin-singlefile": "^2.1.0"
21
- }
22
- }
1
+ {
2
+ "name": "my-concept-atlas",
3
+ "private": true,
4
+ "type": "module"
5
+ }
@@ -0,0 +1,47 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 240" role="img" aria-label="Concept zoom levels">
3
+ <defs>
4
+ <linearGradient id="band" x1="0" y1="0" x2="1" y2="0">
5
+ <stop offset="0" stop-color="#6366f1" stop-opacity="0.9"/>
6
+ <stop offset="1" stop-color="#06b6d4" stop-opacity="0.75"/>
7
+ </linearGradient>
8
+ </defs>
9
+ <rect x="0" y="0" width="720" height="240" rx="14" fill="#0f172a"/>
10
+ <g fill="none" stroke="#334155" stroke-width="1">
11
+ <line x1="40" y1="176" x2="680" y2="176"/>
12
+ </g>
13
+ <g font-family="Segoe UI, Helvetica, Arial, sans-serif" fill="#e2e8f0" font-size="13">
14
+ <g>
15
+ <rect x="48" y="60" width="152" height="86" rx="8" fill="url(#band)"/>
16
+ <text x="124" y="96" text-anchor="middle" font-size="15" font-weight="700">L0</text>
17
+ <text x="124" y="118" text-anchor="middle" font-size="12">全局主题</text>
18
+ </g>
19
+ <g>
20
+ <rect x="236" y="76" width="152" height="70" rx="8" fill="#1e293b" stroke="#475569"/>
21
+ <text x="312" y="106" text-anchor="middle" font-size="15" font-weight="700">L1</text>
22
+ <text x="312" y="126" text-anchor="middle" font-size="12">主要分支</text>
23
+ </g>
24
+ <g>
25
+ <rect x="424" y="92" width="152" height="54" rx="8" fill="#1e293b" stroke="#475569"/>
26
+ <text x="500" y="115" text-anchor="middle" font-size="15" font-weight="700">L2</text>
27
+ <text x="500" y="134" text-anchor="middle" font-size="12">局部机制</text>
28
+ </g>
29
+ <g>
30
+ <rect x="612" y="96" width="0" height="0"/>
31
+ </g>
32
+ </g>
33
+ <g fill="#94a3b8" font-family="Segoe UI, Helvetica, Arial, sans-serif" font-size="11">
34
+ <text x="48" y="200">L3 实现细节与 L4 边界反例继续向右下钻</text>
35
+ </g>
36
+ <g fill="none" stroke="#64748b" stroke-width="1.5" marker-end="url(#arrow)">
37
+ </g>
38
+ <defs>
39
+ <marker id="arrow" markerWidth="8" markerHeight="8" refX="6" refY="3" orient="auto">
40
+ <path d="M0,0 L6,3 L0,6 Z" fill="#64748b"/>
41
+ </marker>
42
+ </defs>
43
+ <g fill="none" stroke="#64748b" stroke-width="1.5">
44
+ <line x1="200" y1="103" x2="232" y2="111" marker-end="url(#arrow)"/>
45
+ <line x1="388" y1="111" x2="420" y2="119" marker-end="url(#arrow)"/>
46
+ </g>
47
+ </svg>
@@ -0,0 +1,169 @@
1
+ <ExplainPage id="components-demo" title="Concept Atlas 组件展厅" summary="一页看懂框架提供的全部组件:从知识结构、语义内容到公式、图表、配图与引用。" layout="editorial" density="reading">
2
+ <ConceptGraph root="showroom">
3
+ <ConceptNode id="showroom" title="组件展厅:每个组件只承担一种表达职责" level="L0" input="知识内容与结构意图" output="可导航的概念页面与关系图" summary="组件不是装饰卡片,而是把定义、证据、模型、关系和布局分别交给最合适的语义工具。">
4
+ <Overview>本页专门展示框架能力。点击左侧或下方节点逐组查看组件效果,再切换右下角关系图观察它们如何组织成一套知识系统。</Overview>
5
+ <Definition>Concept Atlas 将 MDX 组件分为知识结构、内容语义、验证判断、经典模型、展示布局、关系可视化和扩展能力七个家族。</Definition>
6
+ <Input>主题、关键元素、证据、关系和布局意图。</Input>
7
+ <Output>节点探索页、全局关系图、可缩放 Mermaid 图、公式与图表以及可复用的模型表达。</Output>
8
+ <LearningObjectives items={['认识全部组件家族', '理解组件之间的职责边界', '选择合适组件编写自己的 MDX']} />
9
+ <KeyQuestion>我需要表达的是一个事实、一种关系,还是一种组织信息的结构?</KeyQuestion>
10
+ <Callout type="success" title="展厅导航">先看“知识结构”,再看“内容语义”和“经典模型”;最后打开“可视化与布局”和“扩展能力”,就能覆盖完整能力。</Callout>
11
+ <Children><ConceptRef id="structure-family" /><ConceptRef id="content-family" /><ConceptRef id="verification-family" /><ConceptRef id="concept-models" /><ConceptRef id="presentation-family" /><ConceptRef id="visual-family" /><ConceptRef id="extension-family" /></Children>
12
+ </ConceptNode>
13
+
14
+ <ConceptNode id="structure-family" title="知识结构组件:搭出可下钻的概念树" level="L1" parent="showroom" summary="页面、图谱、节点、子节点和跨节点关系共同构成导航骨架。">
15
+ <Definition>结构组件负责“有什么节点、节点如何归属、哪些概念彼此关联”,不负责替代节点内部的知识内容。</Definition>
16
+ <FrameworkModel title="结构组件家族" type="layers" elements={[{title:'ExplainPage',description:'页面元信息'},{title:'ConceptGraph',description:'图谱容器与根节点'},{title:'ConceptNode',description:'可下钻概念节点'},{title:'Children / ConceptRef',description:'树层级入口'},{title:'Relation',description:'跨分支语义边'}]} />
17
+ <Children><ConceptRef id="node-anatomy" /><ConceptRef id="relation-anatomy" /></Children>
18
+ </ConceptNode>
19
+ <ConceptNode id="node-anatomy" title="ConceptNode:一个节点承载一个可命名概念" level="L2" parent="structure-family" summary="节点用 id、title、level、parent、summary 和语义子组件描述一个认知单元。">
20
+ <Definition>ConceptNode 是所有内容的承载边界;L0 到 L4 分别对应全局概览、子系统、机制、实现细节和边界反例。</Definition>
21
+ <Example title="最小节点">`<ConceptNode id="idea" title="一个判断" level="L2" parent="root" summary="一句话结论">…</ConceptNode>`</Example>
22
+ <Glossary term="L0–L4">概念缩放层级,不是视觉字号等级。</Glossary>
23
+ </ConceptNode>
24
+ <ConceptNode id="relation-anatomy" title="Relation:把跨分支意义显式画出来" level="L2" parent="structure-family" summary="Relation 不改变树层级,而是表达前置、因果、产出、依赖和对比。">
25
+ <Definition>关系边使用白名单类型:prerequisite、causes、produces、uses、implements、contrasts、depends-on、exception-of、precedes。</Definition>
26
+ <RelationMap title="关系类型示例" items={[{from:'Definition',type:'implements',to:'ConceptNode',note:'内容具体化节点'},{from:'Evidence',type:'supports',to:'Claim',note:'由证据支撑判断'}]} />
27
+ <Boundary>不要用 Relation 表达 parent-child;父子边由 parent 和 Children 自动生成。</Boundary>
28
+ </ConceptNode>
29
+
30
+ <ConceptNode id="content-family" title="内容语义组件:让节点内容有明确职责" level="L1" parent="showroom" summary="不同语义组件分别回答是什么、怎么做、输入输出是什么以及边界在哪里。">
31
+ <Definition>内容组件将长段落拆为可识别的信息类型,NodeExplorer 会按语义将它们放入对应区域。</Definition>
32
+ <Stack gap="sm"><Definition>Definition:严格定义。</Definition><Mechanism>Mechanism:过程与因果。</Mechanism><Boundary>Boundary:限制与失效条件。</Boundary></Stack>
33
+ <Children><ConceptRef id="meaning-blocks" /><ConceptRef id="context-blocks" /></Children>
34
+ </ConceptNode>
35
+ <ConceptNode id="meaning-blocks" title="定义与机制:先说清楚是什么,再说如何发生" level="L2" parent="content-family" summary="Overview 建立直觉,Definition 收紧边界,Mechanism 解释过程。">
36
+ <Overview>Overview 适合首屏快速认知。</Overview>
37
+ <Definition>Definition 给出概念的必要特征。</Definition>
38
+ <Mechanism>Mechanism 解释输入如何经过状态变化产生输出。</Mechanism>
39
+ <Implementation language="javascript" title="Implementation 示例">const result = input.map(transform);</Implementation>
40
+ </ConceptNode>
41
+ <ConceptNode id="context-blocks" title="上下文组件:输入、输出、示例和术语补足理解" level="L2" parent="content-family" summary="Input、Output、Example、Counterexample、Prerequisite 和 Glossary 负责补全概念上下文。">
42
+ <Prerequisite>需要先理解“节点”和“关系”。</Prerequisite>
43
+ <Input>原始材料、问题和约束。</Input>
44
+ <Output>可验证的结论或下一步行动。</Output>
45
+ <Example title="正例">用具体案例说明抽象概念如何落地。</Example>
46
+ <Counterexample title="反例">指出看似相同但不满足定义的情况。</Counterexample>
47
+ <Glossary term="semantic">让术语拥有局部定义。</Glossary>
48
+ </ConceptNode>
49
+
50
+ <ConceptNode id="verification-family" title="验证与判断组件:让结论不止是漂亮话" level="L1" parent="showroom" summary="证据、不变量、故障模式、权衡和学习目标把内容连接到行动。">
51
+ <Definition>这一组组件专门呈现可检查的依据、稳定约束、风险、取舍和阅读目标。</Definition>
52
+ <Evidence command="npm run validate" observes="确认 MDX 节点数量、层级、关系类型与必需字段。" />
53
+ <Invariant title="组件契约">语义组件表达知识,模板负责布局;内容不直接写 CSS、坐标或 SVG。</Invariant>
54
+ <FailureMode symptom="页面看似完整但难以使用" cause="节点缺少摘要、边界或关系" evidence="检查节点是否只有一段泛化说明" remedy="补充证据与下钻入口" />
55
+ <Tradeoff title="信息密度与可读性" options={[{name:'展开细节',benefit:'证据更完整',cost:'首屏更长',when:'复杂机制'}, {name:'压缩摘要',benefit:'扫描更快',cost:'上下文较少',when:'总览节点'}]} />
56
+ <LearningObjectives items={['识别证据', '发现边界', '做出取舍']} />
57
+ </ConceptNode>
58
+
59
+ <ConceptNode id="concept-models" title="概念模型组件:把推理结构变成可读的形状" level="L1" parent="showroom" summary="五个模型组件分别表达并列、二维定位、变量关系、论证层级与收敛过程。">
60
+ <Definition>概念模型不是装饰图形。选择模型时先判断信息的组织关系,再选择能够让这层关系一眼可见的组件。</Definition>
61
+ <FrameworkModel title="FrameworkModel:并列要素" type="elements" elements={[{title:'问题',description:'明确要解释的对象'},{title:'机制',description:'说明变化如何发生'},{title:'证据',description:'给出可验证依据'}]} />
62
+ <MatrixModel title="MatrixModel:影响 / 成本" xLabel="实施成本" yLabel="预期影响" cells={[{title:'优先投入',description:'高影响 / 低成本',tone:'success'},{title:'审慎评估',description:'高影响 / 高成本',tone:'warn'},{title:'快速验证',description:'低影响 / 低成本'},{title:'暂缓处理',description:'低影响 / 高成本',tone:'danger'}]} />
63
+ <FormulaModel title="FormulaModel:用户价值" formula="用户价值 = 新体验 - 旧体验 - 替换成本" variables={[{symbol:'新体验',description:'方案带来的增量收益'},{symbol:'旧体验',description:'现有替代方案的价值'},{symbol:'替换成本',description:'学习、迁移与风险'}]} />
64
+ <PyramidModel title="PyramidModel:论证层级" levels={[{title:'结论',description:'需要读者带走的判断'},{title:'理由',description:'支撑判断的关键分组'},{title:'证据',description:'事实、数据与案例'}]} />
65
+ <FunnelModel title="FunnelModel:从输入到行动" steps={[{title:'收集',description:'汇集候选信息'},{title:'筛选',description:'排除不满足约束的项'},{title:'验证',description:'检查关键假设'},{title:'行动',description:'形成下一步决策'}]} />
66
+ <Children><ConceptRef id="framework-demo" /><ConceptRef id="matrix-demo" /><ConceptRef id="formula-demo" /><ConceptRef id="pyramid-funnel-demo" /></Children>
67
+ </ConceptNode>
68
+ <ConceptNode id="framework-demo" title="FrameworkModel:承载并列、阶段、层级与循环" level="L2" parent="concept-models" summary="一个组件通过 type 区分要素、阶段、层级和循环。">
69
+ <FrameworkModel title="PDCA 循环" type="cycle" elements={[{title:'Plan',description:'计划'},{title:'Do',description:'执行'},{title:'Check',description:'检查'},{title:'Act',description:'改进'}]} />
70
+ <Details summary="何时使用">当结构重点是元素数量和组织方式,而不是具体节点之间的关系时使用。</Details>
71
+ </ConceptNode>
72
+ <ConceptNode id="matrix-demo" title="MatrixModel:二维象限让优先级一眼可见" level="L2" parent="concept-models" summary="用 xLabel、yLabel 和 cells 描述两个维度及其组合。">
73
+ <MatrixModel title="影响 / 成本矩阵" xLabel="实施成本" yLabel="预期影响" cells={[{title:'优先投资',description:'高影响 / 低成本',tone:'success'},{title:'谨慎评估',description:'高影响 / 高成本',tone:'warn'},{title:'快速试验',description:'低影响 / 低成本'},{title:'暂缓',description:'低影响 / 高成本',tone:'danger'}]} />
74
+ <DecisionMatrix title="参数契约" headers={['参数','用途','形态']} rows={[['title','模型标题','string'],['cells','象限内容','array'],['tone','视觉提示','info / warn / danger']]} />
75
+ </ConceptNode>
76
+ <ConceptNode id="formula-demo" title="FormulaModel:把多变量关系压缩成一个判断" level="L2" parent="concept-models" summary="公式适合表达变量之间明确的加减乘除关系。">
77
+ <FormulaModel title="用户价值" formula="用户价值 = 新体验 − 旧体验 − 替换成本" variables={[{symbol:'新体验',description:'新方案带来的增量收益'},{symbol:'旧体验',description:'用户现有替代方案'},{symbol:'替换成本',description:'迁移与学习付出'}]} />
78
+ <NoteGrid notes={[{title:'优点',content:'关系直接'}, {title:'边界',content:'不替代真实测量'}]} />
79
+ </ConceptNode>
80
+ <ConceptNode id="pyramid-funnel-demo" title="PyramidModel 与 FunnelModel:分层和收敛是两种不同逻辑" level="L2" parent="concept-models" summary="金字塔从基础归纳到结论,漏斗从大量输入逐步筛选到行动。">
81
+ <PyramidModel title="金字塔论证" levels={[{title:'结论',description:'核心判断'},{title:'理由',description:'关键分组'},{title:'证据',description:'事实与案例'}]} />
82
+ <FunnelModel title="AIDA 漏斗" steps={[{title:'Attention',description:'注意'},{title:'Interest',description:'兴趣'},{title:'Desire',description:'欲望'},{title:'Action',description:'行动'}]} />
83
+ </ConceptNode>
84
+
85
+ <ConceptNode id="presentation-family" title="展示与布局组件:组织复杂内容的阅读节奏" level="L1" parent="showroom" summary="Compare、Flow、Timeline、Tabs、Grid 等组件负责并列、时序、折叠和空间组织。">
86
+ <Compare items={[{label:'流式阅读',rows:['信息密度','适用场景'],values:['高','定义与论证']},{label:'分栏对比',rows:['信息密度','适用场景'],values:['中','方案比较']}]} />
87
+ <Flow steps={['输入', '组织', '渲染', '验证']} />
88
+ <Timeline events={[{label:'T0',content:'定义目标'}, {label:'T1',content:'选择模型'}, {label:'T2',content:'验证结果'}]} />
89
+ <Children><ConceptRef id="layout-demo" /><ConceptRef id="compact-demo" /></Children>
90
+ </ConceptNode>
91
+ <ConceptNode id="layout-demo" title="布局原语:Stack、Grid、Split、Columns 让信息有秩序" level="L2" parent="presentation-family" summary="布局组件只表达空间意图,具体样式由模板统一接管。">
92
+ <Definition>布局原语表达信息之间的空间关系;它们负责组织内容,不负责改变内容本身的语义。</Definition>
93
+ <Columns><Split ratio="1fr 1fr"><Callout title="左列">结论与定义。</Callout><Callout title="右列">证据与边界。</Callout></Split></Columns>
94
+ <Grid columns="auto" gap="sm"><Insight title="局部判断">Grid 中的短信息。</Insight><Insight title="另一判断" tone="warn">不要混用职责。</Insight></Grid>
95
+ </ConceptNode>
96
+ <ConceptNode id="compact-demo" title="压缩阅读:Tabs、Details、Callout、Insight、NoteGrid" level="L2" parent="presentation-family" summary="这些组件适合把结论、提示、细节和短信息压缩在首屏。">
97
+ <Definition>压缩组件通过折叠、分组和短提示降低首屏负担,同时保留继续阅读所需的上下文。</Definition>
98
+ <Tabs items={[{label:'结论',content:'先展示最重要的判断。'},{label:'证据',content:'再展开可验证依据。'}]} />
99
+ <Details summary="展开更多">Details 将次要信息收起,避免首屏过载。</Details>
100
+ <Insight title="关键判断" tone="success">一个组件只承担一种信息组织方式。</Insight>
101
+ </ConceptNode>
102
+
103
+ <ConceptNode id="visual-family" title="关系与可视化组件:把结构变成可探索画布" level="L1" parent="showroom" summary="Mermaid、RelationMap、RelationPath、Insight 和 NoteGrid 让关系、路径和结论可视化。">
104
+ <Mermaid title="组件协作流" width="100%" height="220px" chart={`flowchart LR
105
+ A[MDX 内容] --> B[语义组件]
106
+ B --> C[数据模型]
107
+ C --> D[节点探索]
108
+ C --> E[关系图谱]
109
+ D --> F[可观察结论]
110
+ E --> F
111
+ style A fill:#172554,stroke:#38bdf8,color:#e0f2fe
112
+ style F fill:#14532d,stroke:#34d399,color:#ecfdf5`} />
113
+ <RelationPath title="阅读路径" steps={[{level:'L0',node:'组件展厅',note:'总览',tone:'info'},{level:'L1',node:'模型组件',note:'选择结构',tone:'success'},{level:'L2',node:'MatrixModel',note:'定位决策',tone:'warn'}]} />
114
+ <RelationMap title="可视化摘要" items={[{from:'MDX',type:'produces',to:'Graph',note:'生成关系图'},{from:'Node',type:'uses',to:'Mermaid',note:'展示局部流程'}]} />
115
+ </ConceptNode>
116
+
117
+ <ConceptNode id="extension-family" title="扩展能力:公式、图表、图片、代码与引用" level="L1" parent="showroom" summary="数学公式、数据图表、配图题注、代码块和参考文献五项能力,让讲解可以带上推导、数据、实现与出处。">
118
+ <Definition>扩展组件把文本之外的证据接进页面:Math/MathBlock 渲染数学、Chart 绘制数据、Figure 承载配图、CodeBlock 展示代码或命令、Cite/References 保留出处。</Definition>
119
+ <Children><ConceptRef id="math-demo" /><ConceptRef id="chart-demo" /><ConceptRef id="figure-demo" /><ConceptRef id="code-demo" /><ConceptRef id="citation-demo" /></Children>
120
+ </ConceptNode>
121
+
122
+ <ConceptNode id="math-demo" title="Math 与 MathBlock:把推导写进正文" level="L2" parent="extension-family" summary="Math 用于行内符号,MathBlock 用于独立公式并支持变量说明。">
123
+ <Definition>两者都用 KaTeX 渲染 LaTeX。行内用 Math,独立成块并需要解释变量时用 MathBlock。</Definition>
124
+ <Overview>例如信息量的定义 <Math>\log_2 N</Math> 表示 N 种等可能结果所需要的比特数。</Overview>
125
+ <MathBlock title="香农信息量" formula="I(x) = -\log_2 p(x)" variables={[{symbol:'p(x)',description:'事件 x 发生的概率'},{symbol:'I(x)',description:'观察 x 后获得的信息量,单位为比特'}]} />
126
+ <Boundary>公式是 LaTeX 字符串,不要在里面写 Markdown 或 HTML。</Boundary>
127
+ </ConceptNode>
128
+
129
+ <ConceptNode id="chart-demo" title="Chart:用同一数据切换三种图形" level="L2" parent="extension-family" summary="bar、line、pie 三种类型共享数据形状,按比较、趋势或占比选择。">
130
+ <Definition>Chart 接收 data(`{label, value}` 数组)或 series + labels,在 SVG 中绘制并跟随主题色。</Definition>
131
+ <Chart title="各阶段耗时" type="bar" unit="小时" data={[{label:'收集',value:6},{label:'分析',value:14},{label:'验证',value:9},{label:'落地',value:4}]} />
132
+ <Chart title="留存趋势" type="line" labels={['第1周','第2周','第3周','第4周']} series={[{name:'留存率',values:[100,72,58,49]}]} />
133
+ </ConceptNode>
134
+
135
+ <ConceptNode id="figure-demo" title="Figure:图片与题注一起出现" level="L2" parent="extension-family" summary="Figure 把图片、题注编号和说明绑定,构建时把本地图片内联进单文件。">
136
+ <Definition>相对路径的图片会在构建时转成 base64 内联,远程 URL 保持不变;label 提供“图 1”这样的编号。</Definition>
137
+ <Figure src="./assets/sample-diagram.svg" alt="概念缩放示意" label="图 1" caption="概念缩放:同一主题可以从 L0 全局逐层下钻到 L4 边界反例。" />
138
+ <Boundary>大图会显著增大单文件 HTML;截图类内容建议控制尺寸。</Boundary>
139
+ </ConceptNode>
140
+
141
+ <ConceptNode id="code-demo" title="CodeBlock:把命令、配置或伪代码放进正文" level="L2" parent="extension-family" summary="与绑定节点的 Implementation 不同,CodeBlock 可以出现在任何位置,并支持标题、题注、换行和行号。">
142
+ <Definition>CodeBlock 通过 code(或子内容)接收字符串,language 决定语言标记,title 与 caption 提供说明,lineNumbers 和 wrap 控制逐行讲解与长行折行。</Definition>
143
+ <CodeBlock language="bash" title="校验与构建" caption="命令行、伪代码或配置都可以用它承载,不依附于某个概念节点。" lineNumbers>{`npm run validate
144
+ npm run sync
145
+ npm run build`}</CodeBlock>
146
+ <CodeBlock language="javascript" title="语义优先" wrap>{`const explain = concept => concept.mechanism ?? concept.definition ?? concept.overview;`}</CodeBlock>
147
+ <Boundary>代码里的反引号、花括号请放在模板字符串中传入,避免被 MDX 当作表达式解析。</Boundary>
148
+ </ConceptNode>
149
+
150
+ <ConceptNode id="citation-demo" title="Cite 与 References:让结论可以追溯" level="L2" parent="extension-family" summary="行内用 Cite 标记引用,文末用 References 列出完整出处,编号自动对应。">
151
+ <Definition>Cite 的 id 与 References 条目的 id 对应,渲染时显示条目在列表中的序号,并链接到该条目。</Definition>
152
+ <Overview>信息密度的价值在于可验证性<Cite id="shannon1948" />,而可验证性依赖清晰的出处<Cite id="tufte1983" />。</Overview>
153
+ <Boundary>在 atlas 中,把 Cite 和 References 放在同一个节点内,否则未访问的节点里引用编号无法解析。</Boundary>
154
+ <References title="本节点引用" items={[{id:'shannon1948',authors:'Shannon, C. E.',year:'1948',title:'A Mathematical Theory of Communication',source:'Bell System Technical Journal'},{id:'tufte1983',authors:'Tufte, E. R.',year:'1983',title:'The Visual Display of Quantitative Information',source:'Graphics Press'}]} />
155
+ </ConceptNode>
156
+
157
+ <Relation from="structure-family" to="content-family" type="precedes" label="先搭骨架" />
158
+ <Relation from="content-family" to="verification-family" type="uses" label="补充证据" />
159
+ <Relation from="concept-models" to="presentation-family" type="implements" label="结构落地" />
160
+ <Relation from="verification-family" to="visual-family" type="produces" label="形成可见结论" />
161
+ <Relation from="visual-family" to="structure-family" type="depends-on" label="依赖图谱数据" />
162
+ <Relation from="extension-family" to="content-family" type="uses" label="补充证据形态" />
163
+ <Relation from="extension-family" to="verification-family" type="produces" label="提供可追溯依据" />
164
+ <Relation from="matrix-demo" to="formula-demo" type="contrasts" label="维度 vs 公式" />
165
+ <Relation from="pyramid-funnel-demo" to="framework-demo" type="contrasts" label="分层 vs 循环" />
166
+ <Relation from="math-demo" to="formula-demo" type="contrasts" label="LaTeX vs 纯文本公式" />
167
+ <Relation from="chart-demo" to="matrix-demo" type="contrasts" label="连续数据 vs 二维定位" />
168
+ </ConceptGraph>
169
+ </ExplainPage>
@@ -0,0 +1,138 @@
1
+ <ScrollDocument spacing="comfortable" fontSize="normal">
2
+ <ScrollHeader title="Concept Atlas 连续阅读指南" label="连续阅读 · 组件参考">同一套语义组件可以脱离图谱和节点面板,按传统文档流连续阅读。本页同时是一份可运行的组件参考:每一节演示一个组件家族,正文保持高信息密度,模型在需要比较、推导或收敛时占满可用宽度。</ScrollHeader>
3
+
4
+ <ScrollSection title="先识别推理结构">
5
+ <ScrollProse>模型不是内容的装饰。它们分别处理并列要素、二维定位、变量关系、论证层级和筛选过程。先确认关系形状,读者才能用最短路径验证结论。</ScrollProse>
6
+ <LearningObjectives items={['按关系形状选择组件', '把结论与证据分开表达', '让每个区块承担不同的认知任务']} />
7
+ <KeyQuestion>我这一节要表达的是一个事实、一种关系,还是一种组织信息的结构?</KeyQuestion>
8
+ <ScrollGrid columns="3">
9
+ <FrameworkModel title="对象" type="elements" elements={[{title:'系统',description:'明确正在判断什么'},{title:'边界',description:'确定讨论范围'}]} />
10
+ <FrameworkModel title="约束" type="elements" elements={[{title:'时间',description:'决策窗口与反馈周期'},{title:'资源',description:'人力、预算和技术限制'}]} />
11
+ <FrameworkModel title="证据" type="elements" elements={[{title:'行为',description:'真实使用与任务结果'},{title:'数据',description:'可重复检查的观察'}]} />
12
+ </ScrollGrid>
13
+ </ScrollSection>
14
+
15
+ <ScrollSection title="在二维关系中定位选择">
16
+ <ScrollProse>当候选方案同时受两个变量约束时,矩阵比线性列表更容易暴露优先级。</ScrollProse>
17
+ <ScrollGrid columns="2">
18
+ <MatrixModel title="影响 / 成本矩阵" xLabel="实施成本" yLabel="预期影响" cells={[{title:'优先投入',description:'高影响 / 低成本',tone:'success'},{title:'审慎评估',description:'高影响 / 高成本',tone:'warn'},{title:'快速验证',description:'低影响 / 低成本'},{title:'暂缓处理',description:'低影响 / 高成本',tone:'danger'}]} />
19
+ <Stack gap="md">
20
+ <Insight title="先做什么">优先验证高影响、低成本的选择,再为高成本方案准备证据。</Insight>
21
+ <Callout title="阅读判断">矩阵只帮助定位,不替代成本估算或影响验证。</Callout>
22
+ <NoteGrid notes={[{title:'输入',content:'候选方案与约束'},{title:'输出',content:'下一轮验证顺序'}]} />
23
+ </Stack>
24
+ </ScrollGrid>
25
+ </ScrollSection>
26
+
27
+ <ScrollSection title="把假设压缩为可讨论的关系">
28
+ <ScrollProse>公式适合表达变量之间明确的加减乘除关系;当关系涉及概率或增长时,用 MathBlock 保留推导。</ScrollProse>
29
+ <ScrollGrid columns="2">
30
+ <FormulaModel title="用户价值" formula="用户价值 = 新体验 - 旧体验 - 替换成本" variables={[{symbol:'新体验',description:'方案带来的增量收益'},{symbol:'旧体验',description:'现有替代方案的价值'},{symbol:'替换成本',description:'学习、迁移和风险'}]} />
31
+ <MathBlock title="复利增长" formula="V_t = V_0 \cdot (1 + r)^t" variables={[{symbol:'V_0',description:'初始价值'},{symbol:'r',description:'每期增长率'},{symbol:'t',description:'期数'}]} />
32
+ </ScrollGrid>
33
+ <ScrollProse>行内符号同样可用,例如年化收益约为 <Math formula="r_{\text{ann}} = (1 + r)^{12} - 1" />。</ScrollProse>
34
+ </ScrollSection>
35
+
36
+ <ScrollSection title="用图表观察趋势与占比">
37
+ <ScrollProse>当数据是连续的、有序的,图表比表格更快暴露趋势和分布。</ScrollProse>
38
+ <ScrollGrid columns="2">
39
+ <Chart title="各阶段耗时" type="bar" unit="小时" data={[{label:'收集',value:6},{label:'分析',value:14},{label:'验证',value:9},{label:'落地',value:4}]} />
40
+ <Chart title="时间去向" type="pie" data={[{label:'实现',value:45},{label:'调试',value:25},{label:'沟通',value:20},{label:'文档',value:10}]} />
41
+ </ScrollGrid>
42
+ <Chart title="四周留存趋势" type="line" labels={['第1周','第2周','第3周','第4周']} series={[{name:'留存率',values:[100,72,58,49]},{name:'活跃度',values:[100,64,52,40]}]} />
43
+ </ScrollSection>
44
+
45
+ <ScrollSection title="把命令与代码放进正文">
46
+ <ScrollProse>CodeBlock 承载命令行、配置或伪代码。它不依附于某个概念节点,可以出现在任何章节;需要逐行讲解时打开行号,长行过多时可以折行。</ScrollProse>
47
+ <CodeBlock language="bash" title="本地校验与预览" caption="CodeBlock 复用模板的代码表面,因此自动跟随当前皮肤与组件风格。" lineNumbers>{`npm run validate
48
+ npm run sync
49
+ npm run dev`}</CodeBlock>
50
+ <CodeBlock language="javascript" title="语义优先" wrap>{`const explain = concept => concept.mechanism ?? concept.definition ?? concept.overview;`}</CodeBlock>
51
+ </ScrollSection>
52
+
53
+ <ScrollSection title="组织证据,再收敛到行动">
54
+ <ScrollGrid columns="3">
55
+ <PyramidModel title="论证层级" levels={[{title:'结论',description:'读者需要带走的判断'},{title:'理由',description:'支撑判断的关键分组'},{title:'证据',description:'事实、数据与案例'}]} />
56
+ <FunnelModel title="决策过程" steps={[{title:'收集',description:'汇集候选信息'},{title:'筛选',description:'排除不满足约束的项'},{title:'验证',description:'检查关键假设'},{title:'行动',description:'形成下一步决策'}]} />
57
+ <Tradeoff title="输出质量" options={[{name:'压缩结论',benefit:'阅读快',cost:'上下文少',when:'总览'},{name:'保留证据',benefit:'可追溯',cost:'阅读长',when:'关键决策'}]} />
58
+ </ScrollGrid>
59
+ </ScrollSection>
60
+
61
+ <ScrollSection title="补充配图与出处">
62
+ <ScrollProse>配图和引用让讲解从断言变成可追溯的论述<Cite id="tufte1983" />。相对路径的图片会在构建时内联,输出仍是可离线打开的单文件。</ScrollProse>
63
+ <Figure src="./assets/sample-diagram.svg" alt="概念缩放示意" label="图 1" caption="概念缩放:同一主题可以从 L0 全局逐层下钻到 L4 边界反例。" />
64
+ <ScrollGrid columns="2">
65
+ <DecisionMatrix title="需要确认" headers={['变量','检查']} rows={[['新体验','是否改善核心任务'],['旧体验','能否满足需求'],['替换成本','迁移是否可接受']]} />
66
+ <Compare items={[{label:'连续阅读',rows:['信息密度','适用场景'],values:['高','按章节论证']},{label:'概念图谱',rows:['信息密度','适用场景'],values:['中','概念下钻']}]} />
67
+ </ScrollGrid>
68
+ </ScrollSection>
69
+
70
+ <ScrollSection title="保留可追溯性与验证入口">
71
+ <Evidence command="npm run validate" observes="确认内容结构完整,再把关键结论连接回原始证据。" />
72
+ <Invariant title="组件契约">语义组件表达知识,模板负责布局;内容不直接写 CSS、坐标或 SVG。</Invariant>
73
+ <FailureMode symptom="页面看似完整但难以使用" cause="节点缺少摘要、边界或关系" evidence="检查是否只有一段泛化说明" remedy="补充证据与下钻入口" />
74
+ <Insight title="核心原则">选择组件是为了让关系更容易被检验,不是为了把阅读页面做成一组不同样式的卡片。</Insight>
75
+ </ScrollSection>
76
+
77
+ <ScrollSection title="附录:折叠、布局与关系可视化">
78
+ <Tabs items={[{label:'结论',content:'先展示最重要的判断。'},{label:'证据',content:'再展开可验证依据。'}]} />
79
+ <Details summary="展开更多">Details 将次要信息收起,避免首屏过载。</Details>
80
+ <ScrollGrid columns="2">
81
+ <Flow steps={['输入', '组织', '渲染', '验证']} />
82
+ <Timeline events={[{label:'T0',content:'定义目标'},{label:'T1',content:'选择模型'},{label:'T2',content:'验证结果'}]} />
83
+ </ScrollGrid>
84
+ <Columns>
85
+ <Split ratio="1fr 1fr">
86
+ <Callout title="左列">结论与定义。</Callout>
87
+ <Callout title="右列">证据与边界。</Callout>
88
+ </Split>
89
+ </Columns>
90
+ <ScrollGrid columns="2">
91
+ <Mermaid title="组件协作流" width="100%" height="220px" chart={`flowchart LR
92
+ A[MDX 内容] --> B[语义组件]
93
+ B --> C[数据模型]
94
+ C --> D[节点探索]
95
+ C --> E[关系图谱]
96
+ style A fill:#172554,stroke:#38bdf8,color:#e0f2fe
97
+ style E fill:#14532d,stroke:#34d399,color:#ecfdf5`} />
98
+ <RelationPath title="阅读路径" steps={[{level:'L0',node:'总览',note:'建立直觉',tone:'info'},{level:'L1',node:'机制',note:'理解过程',tone:'success'},{level:'L2',node:'边界',note:'检查反例',tone:'warn'}]} />
99
+ </ScrollGrid>
100
+ <RelationMap title="关系速览" items={[{from:'MDX',type:'produces',to:'Graph',note:'生成关系图'},{from:'Node',type:'uses',to:'Mermaid',note:'展示局部流程'}]} />
101
+ </ScrollSection>
102
+
103
+ <ScrollSection title="附录:大图的框内适配与放大阅读">
104
+ <ScrollProse>较大的流程图会被等比收进框内,而不是画出边框。点击图面或标题栏的「放大阅读」可以打开全屏视图,用滚轮缩放、拖拽平移、Esc 关闭。</ScrollProse>
105
+ <Mermaid title="图谱生成管线" width="100%" height="360px" chart={`flowchart TD
106
+ S[MDX 源文件] --> P[解析与校验]
107
+ P --> G[概念图谱]
108
+ P --> F[图表与公式]
109
+ G --> D[节点探索]
110
+ G --> R[关系图谱]
111
+ D --> M[Mermaid 局部流程图]
112
+ R --> M
113
+ F --> M
114
+ M --> Z[框内自适应缩放]
115
+ Z --> O[点击放大阅读]
116
+ O --> W[拖拽平移]
117
+ O --> K[滚轮缩放]
118
+ O --> E[Esc 关闭]
119
+ style S fill:#172554,stroke:#38bdf8,color:#e0f2fe
120
+ style Z fill:#14532d,stroke:#34d399,color:#ecfdf5
121
+ style O fill:#78350f,stroke:#fbbf24,color:#fffbeb`} />
122
+ <ScrollGrid columns="2">
123
+ <Mermaid title="窄栏中的纵向长图" width="100%" height="220px" chart={`flowchart TD
124
+ A[读取] --> B[解析]
125
+ B --> C[建模]
126
+ C --> D[渲染]
127
+ D --> E[校验]
128
+ E --> F[发布]
129
+ F --> G[归档]
130
+ G --> H[复盘]`} />
131
+ <RelationPath title="阅读路径" steps={[{level:'L0',node:'总览',note:'建立直觉',tone:'info'},{level:'L1',node:'机制',note:'理解过程',tone:'success'},{level:'L2',node:'边界',note:'检查反例',tone:'warn'}]} />
132
+ </ScrollGrid>
133
+ </ScrollSection>
134
+
135
+ <ScrollSection title="参考文献">
136
+ <References title="本页引用" items={[{id:'tufte1983',authors:'Tufte, E. R.',year:'1983',title:'The Visual Display of Quantitative Information',source:'Graphics Press',note:'关于以图形压缩与呈现证据的经典论述。'}]} />
137
+ </ScrollSection>
138
+ </ScrollDocument>
@@ -1,158 +0,0 @@
1
- <ExplainPage id="compiler-runtime" title="程序如何变成一次可观察的运行" summary="从意图、工具链与操作系统契约出发,追踪程序如何获得身份、地址、时间与副作用。" layout="editorial" density="reading">
2
- <ConceptGraph root="execution-system">
3
- <ConceptNode id="execution-system" title="执行系统:从意图到副作用" level="L0" input="源码、工具链与机器" output="行为、资源变化与退出状态" summary="把编译与运行看成跨层契约,而不是只有编译器参与的流水线。">
4
- <Definition>“运行起来”同时意味着语义被解释、依赖被绑定、地址被授予、时间被调度、结果被暴露。任何一层契约破裂,都可能表现为构建失败、启动失败、性能退化或悄无声息的错误。</Definition>
5
- <Prerequisite>先掌握源代码、进程、虚拟地址和文件描述符四个概念。</Prerequisite>
6
- <LearningObjectives items={['区分构建、装载与执行阶段', '为每个阶段找到可验证证据', '从首个错误点缩小故障边界']} />
7
- <KeyQuestion>为什么“编译成功”仍然不能保证程序能启动?</KeyQuestion>
8
- <Input>源码快照、目标三元组、编译器版本、依赖锁文件、配置与凭据。</Input>
9
- <Output>可执行映像、进程地址空间、系统调用轨迹、标准输出与退出码。</Output>
10
- <Callout type="info" title="阅读地图">沿着“意图 → 表示 → 身份 → 地址 → 时间 → 副作用”下钻;每个节点都给出可观测证据,方便把概念变成排障动作。</Callout>
11
- <Tabs items={[{label:'工程视角',content:'可重复构建、发布产物、启动延迟与回滚。'},{label:'机器视角',content:'指令、页表、缓存一致性与异常入口。'},{label:'运维视角',content:'日志、指标、追踪、信号与资源上限。'}]} />
12
- <Children><ConceptRef id="intent" /><ConceptRef id="toolchain" /><ConceptRef id="identity" /><ConceptRef id="address-space" /><ConceptRef id="effects" /></Children>
13
- </ConceptNode>
14
-
15
- <ConceptNode id="intent" title="意图与源代码" level="L1" parent="execution-system" input="需求、算法与接口" output="工具链可消费的文本与资源" summary="源代码既是给人看的设计,也是后续每个阶段必须兑现的承诺。">
16
- <Definition>源文件、宏、生成代码和资源文件共同构成输入;真正的边界由构建系统决定,而不是某个文件扩展名。</Definition>
17
- <Input>版本提交、编译条件、代码生成器输出、环境变量和平台配置。</Input>
18
- <Output>确定的源快照与可追溯构建元数据。</Output>
19
- <Example title="同一提交却得到不同二进制">时间戳宏、未锁定依赖、随机临时目录或本地路径进入产物后,字节比较会失败;先固定输入,再讨论优化。</Example>
20
- <Glossary term="可重复构建">相同源快照、工具链和外部输入应产生等价产物;等价可以是字节相同,也可以是行为相同。</Glossary>
21
- <Children><ConceptRef id="preprocess" /><ConceptRef id="reproducibility" /></Children>
22
- </ConceptNode>
23
- <ConceptNode id="preprocess" title="预处理与语法树" level="L2" parent="intent" input="字符、宏与包含路径" output="Token 流、AST 与源位置" summary="工具链先决定哪些文本存在,以及它们如何组成结构。">
24
- <Definition>预处理器展开宏和条件分支;词法分析切分 Token;解析器建立 AST。源位置映射影响诊断、调试和覆盖率。</Definition>
25
- <Details summary="为什么一个括号错误会拖垮整份文件?">解析器需要在错误位置恢复;同步点不足时,后续 Token 会连锁误判。高质量诊断还要给出恢复后的上下文。</Details>
26
- <Example title="条件编译的隐藏分支">同一文件在 debug、asan、arm64 配置下可能拥有三棵不同 AST;只评审默认配置并不足够。</Example>
27
- <Children><ConceptRef id="semantic-contract" /><ConceptRef id="source-maps" /></Children>
28
- </ConceptNode>
29
- <ConceptNode id="semantic-contract" title="类型、借用与未定义行为" level="L3" parent="preprocess" input="AST、符号表与语言规则" output="带约束的 IR 或诊断" summary="语义阶段决定哪些操作被语言承诺,哪些被禁止或留给实现。">
30
- <Definition>类型检查验证值的形状与操作集合;所有权/借用还验证别名与生命周期。越过约束后,编译器可能基于“不会发生”进行变换。</Definition>
31
- <Callout type="warn" title="契约的反面">一次构建恰好得到的结果不是规范。越界、数据竞争或严格别名违规可能在换优化级别或 CPU 后改变表现。</Callout>
32
- <Glossary term="IR">连接语言语义与目标指令的中间表示,常包含控制流图、SSA 值和内存操作。</Glossary>
33
- </ConceptNode>
34
- <ConceptNode id="source-maps" title="调试信息与可观测映射" level="L3" parent="preprocess" input="AST、优化记录与路径" output="DWARF/PDB、行号表与符号名" summary="优化会改变指令顺序,调试信息把机器状态投影回源码概念。">
35
- <Definition>调试段不参与逻辑,却决定断点、栈回溯、性能采样和崩溃符号化的质量。</Definition>
36
- <Example title="发布包如何保留可诊断性">把符号拆到 symbol server,线上二进制只保留 build-id;收到地址后用同一 build-id 找回源位置。</Example>
37
- </ConceptNode>
38
- <ConceptNode id="reproducibility" title="可重复构建与供应链" level="L2" parent="intent" input="锁文件、工具链镜像与脚本" output="带来源证明的制品" summary="构建不仅要成功,还要能回答“由什么生成、是否被替换”。">
39
- <Definition>可重复性解决同样输入是否同样输出;来源证明解决输出由谁、何时、用什么生成。二者构成软件供应链的可审计性。</Definition>
40
- <Details summary="检查清单">固定编译器 digest、锁定依赖、清理时间与路径噪声、记录 SBOM、签名产物,并在隔离环境中二次构建。</Details>
41
- </ConceptNode>
42
-
43
- <ConceptNode id="toolchain" title="工具链:从 IR 到可装载文件" level="L1" parent="execution-system" input="IR、库接口与目标三元组" output="目标文件、共享库与可执行映像" summary="前端解释语义,中端减少工作,后端选择 ISA,链接器把名字变成地址。">
44
- <Definition>每一步都可能引入契约:调用约定、段权限、异常表、依赖版本和调试信息。</Definition>
45
- <Example title="查看每层产物">用 `-E` 保留预处理文本、`-S` 查看汇编、`-c` 生成目标文件,再用 `readelf -h -S -r` 或 `dumpbin` 检查头、段和重定位。</Example>
46
- <Children><ConceptRef id="optimization" /><ConceptRef id="linking" /><ConceptRef id="artifact-format" /></Children>
47
- </ConceptNode>
48
- <ConceptNode id="optimization" title="中间表示与优化" level="L2" parent="toolchain" input="控制流、数据流和别名信息" output="更少指令与更好局部性的计划" summary="优化是在已知前提下重排等价计算;收益和风险都来自这些前提。">
49
- <Definition>常见变换包括常量折叠、内联、循环变换、死代码删除、向量化和寄存器分配,依据 SSA、别名分析与成本模型。</Definition>
50
- <Input>优化级别、目标 CPU 特性、调试/剖析开关。</Input><Output>指令序列、栈布局、异常表与优化报告。</Output>
51
- <Callout type="success" title="性能问题的证据链">先用基准和采样确认热点,再查看优化报告与生成汇编;不要仅凭源代码缩进推断 CPU 路径。</Callout>
52
- <Evidence command="objdump -dr app.o" observes="检查生成指令与尚未解决的重定位。" />
53
- <Invariant title="优化不变量">在语言规则允许的前提下,优化前后的可观察行为必须等价。</Invariant>
54
- <Tradeoff title="调试构建还是发布构建" options={[{name:'调试构建', benefit:'符号完整、定位快', cost:'体积和运行开销更大', when:'开发与故障复现'}, {name:'发布构建', benefit:'性能和体积更优', cost:'诊断信息需要单独保存', when:'生产部署'}]} />
55
- </ConceptNode>
56
- <ConceptNode id="linking" title="符号解析与重定位" level="L2" parent="toolchain" input="目标文件、静态库、共享库" output="符号地址已确定的映像" summary="链接器把分散的名字变成地址,并选择哪些代码进入最终文件。">
57
- <Definition>符号表描述定义与引用;重定位记录此处需要填入哪个地址或偏移。动态链接把部分决定推迟到装载或首次调用。</Definition>
58
- <Details summary="链接失败如何定位">先确认符号存在,再确认名称修饰与 ABI,随后检查库顺序、架构和可见性,最后检查链接脚本与段布局。</Details>
59
- <FailureMode symptom="undefined reference" cause="符号未定义或 ABI 不匹配" evidence="nm -C、readelf -Ws" remedy="确认库版本、链接顺序与目标架构" />
60
- <Children><ConceptRef id="relocation" /><ConceptRef id="abi" /></Children>
61
- </ConceptNode>
62
- <ConceptNode id="relocation" title="重定位、PLT 与 GOT" level="L3" parent="linking" input="机器码中的占位引用" output="相对/绝对地址与延迟绑定入口" summary="位置无关代码把地址决定拆成两步:共享代码可复用,进程私有表在装载时修补。">
63
- <Definition>GOT 保存可变地址,PLT 提供调用跳板;懒绑定用首次调用成本换启动时间,安全加固会限制可写表。</Definition>
64
- <Example title="同一函数地址为何变化">ASLR 让模块基址随机化;相对偏移不变,但每次运行看到的绝对地址不同。</Example>
65
- </ConceptNode>
66
- <ConceptNode id="abi" title="ABI 与二进制兼容" level="L3" parent="linking" input="调用约定、数据布局与系统接口" output="可跨编译单元协作的边界" summary="源代码兼容不等于二进制兼容。">
67
- <Definition>ABI 规定参数位置、结构体对齐、异常传播和符号命名。编译器版本、标准库或字段变化都可能让双方解释不同字节。</Definition>
68
- <Glossary term="ODR">One Definition Rule:跨翻译单元的实体定义必须满足语言规则;违反时可能链接成功却产生未定义行为。</Glossary>
69
- <Children><ConceptRef id="abi-break" /></Children>
70
- </ConceptNode>
71
- <ConceptNode id="abi-break" title="ABI 破坏:能链接,不等于能调用" level="L4" parent="abi" input="不一致的结构体布局或调用约定" output="启动后崩溃、数据错位或静默损坏" summary="最危险的兼容性问题往往绕过链接器,在第一次真实调用后才显现。">
72
- <Callout type="danger" title="最小证据">记录双方编译器、目标三元组、sizeof/alignof、符号版本与调用栈;用二进制接口检查工具做发布门禁。</Callout>
73
- <Example title="字段追加的陷阱">旧库按 16 字节读取,新调用方按 24 字节传递;寄存器可能仍能完成调用,但后续字段会读到未初始化或越界数据。</Example>
74
- </ConceptNode>
75
- <ConceptNode id="artifact-format" title="ELF、PE 与段的形状" level="L2" parent="toolchain" input="代码、常量、可写数据和元信息" output="带入口点与权限的文件格式" summary="文件格式把字节分组为装载器可理解的段。">
76
- <Definition>节偏向链接与分析,段偏向装载与权限。代码通常可执行且只读,数据可能可读写;权限最终反映到页表。</Definition>
77
- <Example title="文件很小,内存却很大">.bss 只记录零填充大小,不占同等磁盘空间;装载器在内存中分配并清零它。</Example>
78
- </ConceptNode>
79
-
80
- <ConceptNode id="identity" title="进程身份与启动协议" level="L1" parent="execution-system" input="映像、argv、环境与权限" output="拥有 PID、凭据、句柄和入口栈的进程" summary="启动是内核与运行时共同建立一个可执行身份。">
81
- <Definition>内核创建地址空间和线程,装载器解析依赖,运行时初始化 TLS、构造器和库,最后跳转到入口函数。</Definition>
82
- <Input>工作目录、环境变量、标准流、用户/组凭据、能力与沙箱策略。</Input><Output>入口参数、初始栈、TLS 和可继承文件描述符。</Output>
83
- <Children><ConceptRef id="loader-protocol" /><ConceptRef id="startup-runtime" /></Children>
84
- </ConceptNode>
85
- <ConceptNode id="loader-protocol" title="装载器与地址空间布局" level="L2" parent="identity" input="文件头、段表与依赖路径" output="代码、数据、堆、栈和共享库映射" summary="装载器把文件视图翻译成进程虚拟地址空间。">
86
- <Definition>映射可按需分页;缺页时才从文件或交换区取页。ASLR、W^X、RELRO 会改变布局和可写范围。</Definition>
87
- <Details summary="启动失败的分层排查">格式错误看文件头,依赖缺失看搜索路径,权限错误看挂载与策略,段错误继续检查映射、栈和首个异常指令。</Details>
88
- <Children><ConceptRef id="page-tables" /><ConceptRef id="dynamic-loader" /></Children>
89
- </ConceptNode>
90
- <ConceptNode id="page-tables" title="页表、TLB 与缺页" level="L3" parent="loader-protocol" input="虚拟地址、权限位与物理页" output="缓存一致的地址翻译" summary="每次内存访问先通过翻译;TLB 命中与否直接改变延迟。">
91
- <Definition>页表把虚拟页映射到物理页并携带权限。TLB 缓存近期映射;缺页异常交给内核决定映射文件、分配零页还是终止进程。</Definition>
92
- <Example title="mmap 后为何没有立刻读盘">映射是承诺;真正访问某页时才触发 page fault,内核按需填充。</Example>
93
- <Children><ConceptRef id="fault-storm" /></Children>
94
- </ConceptNode>
95
- <ConceptNode id="fault-storm" title="缺页风暴与抖动" level="L4" parent="page-tables" input="工作集超过内存、随机访问或映射失配" output="大量 fault、低吞吐与尾延迟" summary="地址翻译正确并不代表性能健康;工作集与内存层级失配会让程序在换页上耗尽时间。">
96
- <Details summary="如何确认是内存层问题">同时观察 major/minor fault、TLB miss、I/O 等待和工作集大小;逐步缩小数据集或改变访问局部性,验证因果关系。</Details>
97
- </ConceptNode>
98
- <ConceptNode id="dynamic-loader" title="共享库与符号可见性" level="L3" parent="loader-protocol" input="依赖清单、搜索路径与版本符号" output="进程内可调用的共享对象" summary="动态装载器同时解决加载版本、符号选择和绑定时机。">
99
- <Callout type="warn" title="环境变量是隐形输入">LD_LIBRARY_PATH、PATH 或容器挂载差异会让同一二进制连接到不同实现;发布时记录解析后的依赖树。</Callout>
100
- </ConceptNode>
101
- <ConceptNode id="startup-runtime" title="语言运行时初始化" level="L2" parent="identity" input="入口栈、TLS、静态对象与运行库" output="可进入 main/async runtime 的状态" summary="main 之前已发生 TLS 建立、静态初始化、参数解析和线程池准备。">
102
- <Example title="初始化顺序陷阱">跨翻译单元的静态对象初始化顺序通常没有全局保证;把依赖移到显式初始化函数更稳妥。</Example>
103
- </ConceptNode>
104
-
105
- <ConceptNode id="address-space" title="时间、调度与内存模型" level="L1" parent="execution-system" input="线程、核心、时钟与同步原语" output="按某种顺序提交的指令与可见状态" summary="逻辑顺序要经过调度器、缓存和内存模型,才成为具体时间线。">
106
- <Definition>调度器分配运行机会;CPU 乱序执行隐藏延迟;缓存一致性传播写入;语言内存模型定义线程能观察到哪些顺序。</Definition>
107
- <Prerequisite>区分墙上时钟、单调时钟、CPU 周期以及 happens-before。</Prerequisite>
108
- <Children><ConceptRef id="scheduler" /><ConceptRef id="memory-order" /></Children>
109
- </ConceptNode>
110
- <ConceptNode id="scheduler" title="线程、抢占与系统调用" level="L2" parent="address-space" input="可运行线程、优先级与阻塞原因" output="上下文切换与系统调用返回值" summary="线程会因时间片、I/O 等待或显式让出而切换。">
111
- <Definition>上下文切换保存寄存器和栈指针;系统调用切到内核态并可能阻塞。调度延迟受 CPU 负载、锁、I/O 和 cgroup 配额共同影响。</Definition>
112
- <Details summary="解释一次长尾延迟">把请求拆成用户态运行、系统调用、运行队列等待、I/O 等待四段,用 tracing 或 perf 验证。</Details>
113
- </ConceptNode>
114
- <ConceptNode id="memory-order" title="缓存一致性与内存序" level="L3" parent="address-space" input="并发读写、原子操作和屏障" output="各线程可观察的值与顺序" summary="一致性协调单地址,内存序规定跨地址的可见性关系。">
115
- <Definition>release/acquire、seq_cst 把编译器与硬件重排纳入同一契约;volatile 表达设备/信号可见性,不能替代线程同步。</Definition>
116
- <Callout type="danger" title="数据竞争不是偶尔读旧值">未同步的冲突访问可能直接进入未定义行为;应使用原子、锁或消息传递建立 happens-before。</Callout>
117
- <Children><ConceptRef id="race-window" /></Children>
118
- </ConceptNode>
119
- <ConceptNode id="race-window" title="竞态窗口与不可复现" level="L4" parent="memory-order" input="缺失同步、不同核心速度与调度抖动" output="偶发错误、错误日志或状态回滚" summary="低概率并发错误会被优化、日志和重试机制放大或掩盖。">
120
- <Callout type="warn" title="复现策略">固定线程数和调度扰动,给共享状态加版本号,采集每次读写的因果链;不要用 sleep 当作同步原语。</Callout>
121
- </ConceptNode>
122
-
123
- <ConceptNode id="effects" title="副作用、故障与证据" level="L1" parent="execution-system" input="系统调用、外部服务与资源限制" output="I/O、信号、日志、指标、转储与退出码" summary="最终结果是一组外部可观察的状态变化,而不只是 return 值。">
124
- <Definition>文件、网络包、子进程、信号和退出码都属于副作用。诊断要把它们与版本、配置、硬件和时间关联。</Definition>
125
- <Input>文件系统、网络、时钟、随机源、资源配额和安全策略。</Input><Output>业务响应、审计日志、trace/span、core dump 与退出状态。</Output>
126
- <Callout type="info" title="从症状反推层级">构建错误多停在语义/链接层;启动即退多看装载/初始化;延迟与偶发崩溃优先检查并发、生命周期和资源耗尽。</Callout>
127
- <Children><ConceptRef id="observability" /><ConceptRef id="failure-analysis" /></Children>
128
- </ConceptNode>
129
- <ConceptNode id="observability" title="可观测性三角" level="L2" parent="effects" input="日志、指标与执行跨度" output="可关联的时间线与责任边界" summary="日志说发生了什么,指标说多频繁,追踪说在哪里变慢。">
130
- <Definition>为构建产物注入版本标识,为请求传播 trace-id,并把系统调用、调度和业务事件放到同一时间轴。</Definition>
131
- <Example title="一次崩溃的最小证据包">二进制 build-id、符号文件、argv/环境摘要、结构化日志、线程栈、核心转储和机器架构。</Example>
132
- </ConceptNode>
133
- <ConceptNode id="failure-analysis" title="故障树与最小复现" level="L3" parent="effects" input="症状、证据与可控变量" output="可验证假设、回归用例和修复边界" summary="把“程序不工作”拆成可证伪的层级假设。">
134
- <Definition>先确定失败发生在构建、装载、执行还是副作用提交;再固定输入、缩小依赖、记录首个错误点,最后转成自动化回归。</Definition>
135
- <Details summary="一个可执行的故障树">文件不存在→路径/权限;符号不存在→ABI/库版本;信号 11→地址/生命周期;结果偶发→并发/时间;性能长尾→调度/I/O/锁竞争。</Details>
136
- <Glossary term="首个错误点">时间线上最早改变不变量的事件;后续日志往往只是它造成的连锁反应。</Glossary>
137
- <Children><ConceptRef id="resource-exhaustion" /></Children>
138
- </ConceptNode>
139
- <ConceptNode id="resource-exhaustion" title="资源耗尽:失败发生在 return 之后" level="L4" parent="failure-analysis" input="文件描述符、线程、句柄、配额与连接池" output="ENOMEM、EMFILE、超时、拒绝服务" summary="程序逻辑正确也可能因外部资源账本归零而失败。">
140
- <Definition>把资源视为有所有者、有上限、有回收路径的状态机;每次分配都应能在指标中找到余额和释放证据。</Definition>
141
- <Example title="泄漏为何先表现为延迟">连接池逐渐耗尽后,请求先排队变慢,最终才以超时暴露;只监控错误率会错过早期信号。</Example>
142
- </ConceptNode>
143
-
144
- <Relation from="intent" to="toolchain" type="produces" label="提供语义输入" />
145
- <Relation from="toolchain" to="identity" type="precedes" label="交付可装载映像" />
146
- <Relation from="identity" to="address-space" type="precedes" label="建立进程与线程" />
147
- <Relation from="address-space" to="effects" type="causes" label="决定可观察顺序" />
148
- <Relation from="semantic-contract" to="optimization" type="depends-on" label="优化依赖语义前提" />
149
- <Relation from="linking" to="loader-protocol" type="precedes" label="段与依赖进入装载器" />
150
- <Relation from="page-tables" to="scheduler" type="depends-on" label="异常与调度相交" />
151
- <Relation from="memory-order" to="failure-analysis" type="causes" label="错误顺序制造偶发故障" />
152
- <Relation from="observability" to="reproducibility" type="depends-on" label="需要稳定制品身份" />
153
- <Relation from="abi-break" to="failure-analysis" type="exception-of" label="兼容性边界" />
154
- <Relation from="fault-storm" to="observability" type="causes" label="长尾指标暴露抖动" />
155
- <Relation from="race-window" to="failure-analysis" type="exception-of" label="并发边界" />
156
- <Relation from="resource-exhaustion" to="observability" type="causes" label="资源账本耗尽" />
157
- </ConceptGraph>
158
- </ExplainPage>
@@ -1,31 +0,0 @@
1
- <ScrollDocument>
2
- <ScrollHeader title="用概念模型组织一次技术判断">同一套语义组件可以脱离图谱和节点面板,按传统文档流连续阅读。正文保持高信息密度,模型在需要比较、推导或收敛时占满可用宽度。</ScrollHeader>
3
-
4
- <ScrollSection title="先识别推理结构">
5
- <ScrollProse>模型不是内容的装饰。它们分别处理并列要素、二维定位、变量关系、论证层级和筛选过程。先确认关系形状,读者才能用最短路径验证结论。</ScrollProse>
6
- <ScrollGrid columns="3">
7
- <FrameworkModel title="对象" type="elements" elements={[{title:'系统',description:'明确正在判断什么'},{title:'边界',description:'确定讨论范围'}]} />
8
- <FrameworkModel title="约束" type="elements" elements={[{title:'时间',description:'决策窗口与反馈周期'},{title:'资源',description:'人力、预算和技术限制'}]} />
9
- <FrameworkModel title="证据" type="elements" elements={[{title:'行为',description:'真实使用与任务结果'},{title:'数据',description:'可重复检查的观察'}]} />
10
- </ScrollGrid>
11
- </ScrollSection>
12
-
13
- <ScrollSection title="在二维关系中定位选择">
14
- <ScrollProse>当候选方案同时受两个变量约束时,矩阵比线性列表更容易暴露优先级。</ScrollProse>
15
- <ScrollGrid columns="2">
16
- <MatrixModel title="影响 / 成本矩阵" xLabel="实施成本" yLabel="预期影响" cells={[{title:'优先投入',description:'高影响 / 低成本',tone:'success'},{title:'审慎评估',description:'高影响 / 高成本',tone:'warn'},{title:'快速验证',description:'低影响 / 低成本'},{title:'暂缓处理',description:'低影响 / 高成本',tone:'danger'}]} />
17
- <Stack gap="md"><Insight title="先做什么">优先验证高影响、低成本的选择,再为高成本方案准备证据。</Insight><Callout title="阅读判断">矩阵只帮助定位,不替代成本估算或影响验证。</Callout><NoteGrid notes={[{title:'输入',content:'候选方案与约束'},{title:'输出',content:'下一轮验证顺序'}]} /></Stack>
18
- </ScrollGrid>
19
- </ScrollSection>
20
-
21
- <ScrollSection title="把假设压缩为可讨论的关系" wide>
22
- <ScrollGrid columns="3"><FormulaModel title="用户价值" formula="用户价值 = 新体验 - 旧体验 - 替换成本" variables={[{symbol:'新体验',description:'方案带来的增量收益'},{symbol:'旧体验',description:'现有替代方案的价值'},{symbol:'替换成本',description:'学习、迁移和风险'}]} /><DecisionMatrix title="需要确认" headers={['变量','检查']} rows={[['新体验','是否改善核心任务'],['旧体验','能否满足需求'],['替换成本','迁移是否可接受']]} /><FailureMode symptom="价值无法被感知" cause="只描述新功能,不解释替换路径" evidence="试用后仍回到旧方案" remedy="缩短迁移步骤并验证关键任务" /></ScrollGrid>
23
- </ScrollSection>
24
-
25
- <ScrollSection title="组织证据,再收敛到行动"><ScrollGrid columns="3"><PyramidModel title="论证层级" levels={[{title:'结论',description:'读者需要带走的判断'},{title:'理由',description:'支撑判断的关键分组'},{title:'证据',description:'事实、数据与案例'}]} /><FunnelModel title="决策过程" steps={[{title:'收集',description:'汇集候选信息'},{title:'筛选',description:'排除不满足约束的项'},{title:'验证',description:'检查关键假设'},{title:'行动',description:'形成下一步决策'}]} /><Tradeoff title="输出质量" options={[{name:'压缩结论',benefit:'阅读快',cost:'上下文少',when:'总览'},{name:'保留证据',benefit:'可追溯',cost:'阅读长',when:'关键决策'}]} /></ScrollGrid></ScrollSection>
26
-
27
- <ScrollSection title="保留可追溯性">
28
- <Evidence command="npm run validate" observes="确认内容结构完整,再把关键结论连接回原始证据。" />
29
- <Insight title="核心原则">选择组件是为了让关系更容易被检验,不是为了把阅读页面做成一组不同样式的卡片。</Insight>
30
- </ScrollSection>
31
- </ScrollDocument>
@@ -1,117 +0,0 @@
1
- import { build } from 'vite';
2
- import path from 'path';
3
- import fs from 'fs';
4
- import { fileURLToPath } from 'url';
5
- import { normalizeSkin, normalizeStyle } from '../src/model/skins.js';
6
- import { extractPageTitle, detectFeatures } from '../src/model/validate-content.js';
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
- const rootDir = path.resolve(__dirname, '..');
11
-
12
- /**
13
- * Mermaid is served from a CDN at runtime by default so its ~2100-module
14
- * transform stays out of the build. Set CONCEPT_ATLAS_INLINE_MERMAID=1 to bake
15
- * it back into the HTML for a fully offline single file; CONCEPT_ATLAS_MERMAID_CDN
16
- * overrides the CDN URL.
17
- */
18
- const INLINE_MERMAID = ['1', 'true', 'yes'].includes((process.env.CONCEPT_ATLAS_INLINE_MERMAID || '').toLowerCase());
19
- const MERMAID_CDN_URL = process.env.CONCEPT_ATLAS_MERMAID_CDN || '';
20
-
21
- /**
22
- * Optional compile-time appearance defaults, read from the environment and
23
- * forwarded as `define`s. The carrier HTML plugin replaces the placeholders
24
- * inside the anti-flash inline script only when these are configured.
25
- */
26
- function appearanceDefines() {
27
- const define = {};
28
- const skin = normalizeSkin(process.env.CONCEPT_ATLAS_SKIN || '');
29
- const mode = process.env.CONCEPT_ATLAS_DEFAULT_MODE;
30
- const style = normalizeStyle(process.env.CONCEPT_ATLAS_STYLE || '');
31
- if (skin) define.__ATLAS_DEFAULT_SKIN__ = JSON.stringify(skin);
32
- if (['dark', 'light', 'system'].includes(mode)) define.__ATLAS_DEFAULT_MODE__ = JSON.stringify(mode);
33
- if (style) define.__ATLAS_DEFAULT_STYLE__ = JSON.stringify(style);
34
- return define;
35
- }
36
-
37
- /**
38
- * The demo document mounted by each carrier. Unlike the npm template (which
39
- * aliases the user's MDX), the repository hardcodes its demos in main.jsx /
40
- * scroll-main.jsx, so the build reads them to derive the tab title and the set
41
- * of optional renderers actually needed.
42
- */
43
- function demoSourceFor(entry) {
44
- const demos = entry === 'scroll.html'
45
- ? ['content/scroll-reading-demo.mdx']
46
- : ['content/components-demo.mdx', 'content/compile-runtime.mdx'];
47
- const demo = demos.map(name => path.resolve(rootDir, name)).find(file => fs.existsSync(file));
48
- return demo ? { demo, source: fs.readFileSync(demo, 'utf8') } : null;
49
- }
50
-
51
- /**
52
- * Builds one standalone carrier HTML. `__ATLAS_FEATURES__` mirrors the CLI's
53
- * per-document stubbing so a demo that never uses <Math>/<Mermaid> skips the
54
- * KaTeX fonts and Mermaid module graph instead of bundling them unconditionally.
55
- */
56
- async function buildCarrier(entry, baseDefine) {
57
- const define = { ...baseDefine };
58
- const demo = demoSourceFor(entry);
59
- if (demo) {
60
- const title = extractPageTitle(demo.source);
61
- if (title) {
62
- define.__ATLAS_PAGE_TITLE__ = JSON.stringify(title);
63
- console.log(`🔖 ${entry} 标签页标题:${title}`);
64
- }
65
- const features = detectFeatures(demo.source);
66
- define.__ATLAS_FEATURES__ = JSON.stringify(features);
67
- if (features.mermaid) {
68
- define.__ATLAS_MERMAID_MODE__ = JSON.stringify(INLINE_MERMAID ? 'inline' : 'cdn');
69
- if (MERMAID_CDN_URL) define.__ATLAS_MERMAID_CDN_URL__ = JSON.stringify(MERMAID_CDN_URL);
70
- if (!INLINE_MERMAID) console.log(`🌐 ${entry} Mermaid 运行时从 CDN 加载(--inline-mermaid 可内联)`);
71
- }
72
- const dropped = [features.math ? null : 'KaTeX', features.mermaid ? null : 'Mermaid'].filter(Boolean);
73
- if (dropped.length) console.log(`⚡ ${entry} 省略未使用的渲染器:${dropped.join('、')}`);
74
- }
75
-
76
- await build({
77
- root: rootDir,
78
- define,
79
- build: {
80
- outDir: 'dist',
81
- // dist is cleared once up front; parallel carriers must not wipe each
82
- // other's output mid-build.
83
- emptyOutDir: false,
84
- rollupOptions: { input: path.resolve(rootDir, entry) },
85
- }
86
- });
87
- }
88
-
89
- async function runBuild() {
90
- console.log('🚀 开始构建 Concept Atlas 知识讲解页面...');
91
-
92
- try {
93
- // Clear dist once, then let every carrier write into it concurrently.
94
- const distDir = path.resolve(rootDir, 'dist');
95
- fs.rmSync(distDir, { recursive: true, force: true });
96
- fs.mkdirSync(distDir, { recursive: true });
97
-
98
- const mode = process.env.CONCEPT_ATLAS_MODE;
99
- const carriers = mode === 'atlas' ? ['index.html'] : mode === 'scroll' ? ['scroll.html'] : ['index.html', 'scroll.html'];
100
- const define = appearanceDefines();
101
- if (define.__ATLAS_DEFAULT_SKIN__ || define.__ATLAS_DEFAULT_MODE__) {
102
- console.log(`🎨 默认外观:skin=${define.__ATLAS_DEFAULT_SKIN__ || '(carrier 默认)'} mode=${define.__ATLAS_DEFAULT_MODE__ || '(carrier 默认)'}`);
103
- }
104
-
105
- // vite-plugin-singlefile supports one HTML input per build and emits no
106
- // shared assets, so the carriers are independent and build in parallel
107
- // instead of one full pass after another.
108
- await Promise.all(carriers.map(entry => buildCarrier(entry, define)));
109
-
110
- console.log(`✅ 构建成功!产物已生成到 ${carriers.map(entry => `dist/${entry}`).join(' 和 ')}。`);
111
- } catch (err) {
112
- console.error('❌ 构建失败:', err);
113
- process.exit(1);
114
- }
115
- }
116
-
117
- runBuild();
@@ -1,27 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
-
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = path.dirname(__filename);
7
- const rootDir = path.resolve(__dirname, '..');
8
- const tempDir = path.resolve(rootDir, 'tmp', 'dense-explain');
9
-
10
- function cleanTemp() {
11
- console.log(`🧹 检查并清理临时目录: ${tempDir}`);
12
- if (fs.existsSync(tempDir)) {
13
- const files = fs.readdirSync(tempDir);
14
- files.forEach(file => {
15
- const p = path.join(tempDir, file);
16
- if (fs.lstatSync(p).isFile()) {
17
- fs.unlinkSync(p);
18
- console.log(`已清理: ${file}`);
19
- }
20
- });
21
- console.log('✅ 临时解释任务产物清理完成。');
22
- } else {
23
- console.log('ℹ️ 临时目录不存在或无需清理。');
24
- }
25
- }
26
-
27
- cleanTemp();
@@ -1,44 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import { validateMdxSource, countBySeverity } from '../src/model/validate-content.js';
5
-
6
- const scriptDir = path.dirname(fileURLToPath(import.meta.url));
7
- const rootDir = path.resolve(scriptDir, '..');
8
- const args = process.argv.slice(2);
9
- const strict = args.includes('--strict');
10
- const explicit = args.filter(arg => !arg.startsWith('--'));
11
-
12
- const files = explicit.length
13
- ? explicit.map(file => path.resolve(file))
14
- : ['content/components-demo.mdx', 'content/compile-runtime.mdx', 'content/scroll-reading-demo.mdx']
15
- .map(file => path.join(rootDir, file));
16
-
17
- let errors = 0;
18
-
19
- for (const file of files) {
20
- if (!fs.existsSync(file)) {
21
- console.error(`missing file: ${file}`);
22
- errors += 1;
23
- continue;
24
- }
25
- const source = fs.readFileSync(file, 'utf8');
26
- const result = validateMdxSource(source, {
27
- filePath: file,
28
- strict,
29
- assetExists: spec => fs.existsSync(path.resolve(path.dirname(file), spec)),
30
- });
31
- const { error, warning } = countBySeverity(result.diagnostics);
32
- errors += error;
33
- console.log(`${path.relative(rootDir, file)} ${result.carrier || 'unknown'} errors=${error} warnings=${warning}`);
34
- for (const item of result.diagnostics) {
35
- const label = item.severity === 'error' ? 'error' : 'warn ';
36
- console.log(` ${label} ${item.line}:${item.column} ${item.code} ${item.message}`);
37
- }
38
- }
39
-
40
- if (errors) {
41
- console.error(`\nConcept Atlas content validation failed: ${errors} error(s).`);
42
- process.exit(1);
43
- }
44
- console.log('\nConcept Atlas content validation passed.');