# PixelAlgo 单元编写规范（Conventions）

> 本文件是**每个模型单元的唯一权威规范**。人类贡献者与自动化生成（Workflow）都必须遵守。
> 黄金范例：[`models/01-linear-regression/`](../models/01-linear-regression/)

---

## 1. 单元目录结构（最小完备集）

```
models/NN-slug/
├── meta.json              # 元信息（门户与构建的数据源，必需）
├── README.md              # 完整文档（11 章节，必需）
├── index.html             # 可交互动画页（必需）
├── assets/
│   ├── viz.js             # 动画逻辑（必需）
│   ├── viz.css            # 单元专属样式（可选）
│   └── data.json          # 示例数据（可选）
└── code/
    ├── from_scratch.py    # 纯 NumPy 从零实现（必需，仅依赖 numpy）
    └── framework.py       # sklearn / PyTorch 对照（必需）
```

- `NN` = 两位学习序号（按推荐学习顺序递增，`01` 起）。
- `slug` = kebab-case 英文（如 `linear-regression`、`convolution-basics`）。
- 用 `python scripts/new_model.py <slug> <category> --title 中文标题` 生成骨架，再填充内容。
- 完成后必须通过：`python scripts/verify_unit.py <slug>`，零错误。

---

## 2. meta.json schema

```json
{
  "slug": "01-linear-regression",        // 必须与目录名一致
  "id": "linear-regression",              // 去 NN 前缀的 slug，作为跨单元引用键
  "title": "线性回归",                    // 中文标题
  "titleEn": "Linear Regression",         // 英文标题
  "category": "supervised-classic",       // 见 §3 类别枚举
  "difficulty": 1,                        // 1 入门 … 5 前沿
  "order": 1,                             // 全局学习序
  "prerequisites": [],                    // 依赖的 model id 列表（无则 []）
  "tags": ["回归", "梯度下降", "最小二乘"],
  "summary": "用一条直线拟合数据——一切机器学习的起点。",  // 一句话，≤40 字
  "viz": ["echarts", "canvas"],           // 本页用到的可视化技术子集
  "hasThree": false,                      // 是否用 Three.js（影响门户是否预加载）
  "status": "published",                  // published | wip | planned
  "estMinutes": 25                        // 预计学习时长
}
```

### 类别枚举（category）
| 值 | 含义 |
|---|---|
| `foundations` | 数学/优化基础 |
| `supervised-classic` | 经典监督学习 |
| `unsupervised` | 无监督学习 |
| `nn` | 神经网络基础 |
| `cnn` | 卷积神经网络 |
| `rnn` | 循环/序列 |
| `transformer` | Transformer & 大模型 |
| `generative` | 生成模型 |
| `graph` | 图网络 & 推荐 |
| `rl` | 强化学习 |

---

## 3. README.md 章节（11 节，固定顺序）

1. **标题行**：`# 中文标题` + 引用块（英文 · 类别 · 难度星标）
2. **一句话直觉**（TL;DR）
3. **生活类比**（1–2 句贴切比喻）
4. **数学原理**（KaTeX；模型/损失/更新式；推导只写关键步）
5. **算法步骤**（伪代码块）
6. **从零实现**（贴 `code/from_scratch.py` 核心片段，逐行注释关键行；链接完整文件）
7. **框架对照**（`code/framework.py` + 工业实现差异点评）
8. **可交互演示**（指向 `index.html`，说明能调什么、看什么）
9. **关键超参数**（表：参数 / 作用 / 调大调小现象）
10. **失败模式与陷阱**（真实踩坑经验）
11. **延伸阅读**（论文 / 博客 / 关联单元）

### 公式排版约定（KaTeX）
- 行内：README 里直接用 `$...$`（GitHub 渲染）；HTML 页用 `<span data-tex>...</span>`。
- 块级：HTML 用 `<div data-tex data-display>...</div>`（`katex-config.js` 自动渲染）。
- 反斜杠：HTML 里写 `\frac`、`\sum`（JS 字符串里无需双写）。

---

## 4. index.html 骨架约定

每个 `index.html` 必须：
- `<head>` 内**最早**执行 `document.documentElement.setAttribute('data-theme','dark')`，避免主题闪烁。
- 引入顺序（核心库本地化，避免 CDN 偶发失败）：
  1. `tailwindcss`（CDN，play 模式）
  2. `katex` css + js（CDN，defer）
  3. `echarts`（**本地** `../../assets/vendor/echarts.min.js`，defer；用 Three 时另加本地 `../../assets/vendor/three.min.js`）
  4. `../../assets/css/tokens.css` → `base.css` → `components.css`
- `<body>` 顺序：`.bg-atmos` → `.bg-grid` → `.topbar` → `<main>` → 脚本。
- 脚本顺序（**敏感**）：
  `theme.js` → `viz-core.js` → `echarts-theme.js` → `playground.js` → `katex-config.js` → `nav.js` → `assets/viz.js`（本单元）。
- 内容区用 `.lesson-layout`（左 TOC `[data-toc]` + 主 `[data-toc-root]`），章节用 `<section id="...">`。
- 全局相对路径：从 `models/NN-slug/index.html` 引全局资源用 `../../assets/...`。

> 脚手架 `new_model.py` 生成的 `index.html` 已是合规骨架，**勿破坏引用顺序**。

---

## 5. assets/viz.js 约定

```js
let chart, pg;
function redraw(state) { /* 依据 state 重绘 chart / canvas */ }
function init() {
  chart = PA_ECHARTS.init(document.getElementById('chart'));
  pg = PAPlayground.create({ controls: { /* 控件→state 映射 */ }, onChange: redraw });
  PAKatex.render();
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
```
- 全局可用：`PAViz`（CanvasAnim/linspace/clamp/palette…）、`PA_ECHARTS`（init/PALETTE）、`PAPlayground`、`PAKatex`、`PATheme`、`PANav`。
- 颜色**必须**取自 `PAViz.PALETTE` / `PAViz.palette(i)` 或 CSS 变量，不得硬编码他色。
- Canvas 动画继承 `PAViz.CanvasAnim`，重写 `draw(t, dt)`，用 `this.W/this.H/this.ctx`。
- 主题切换时：ECharts 由 `echarts-theme.js` 自动重绘；自写 Canvas 需订阅 `PATheme.onChange(theme=>redraw())`。
- **⚠ 初始化时序（常见坑，务必遵守）**：
  - `PAPlayground.create({onChange})` 在返回前会**首次触发** onChange，此时 `pg` 尚未赋值。**onChange 回调及其调用的函数里不要直接用 `pg.state`**——改用回调传入的 `state` 参数（或 `s = s || (pg && pg.state)` 兜底）。
  - `requestAnimationFrame` 动画循环访问数据前，先判断数据已初始化（如 `if (!myData) return;`），避免首帧在 init 完成前读到 null 而抛错、中断整个 init。

---

## 6. Python 双实现规范

### `code/from_scratch.py`（从零，教学白盒）
- **仅依赖 numpy**（不得 import torch/sklearn），确保任何环境可跑。
- 固定结构：构造示例数据 → 初始化参数 → 训练循环（前向/损失/梯度/更新）→ 打印对照真值。
- 关键行**逐行中文注释**（为什么这样算、对应哪个公式）。
- 训练循环打印进度（每 N 轮一次），结束时打印「真值 vs 拟合值」对照。
- 末尾 `if __name__ == "__main__": main()`，可 `python code/from_scratch.py` 独立运行。

### `code/framework.py`（框架对照）
- 监督/无监督模型用 **scikit-learn**；深度模型用 **PyTorch**。
- 简洁（10–40 行），凸显「工业实现 vs 从零」的差异。
- 输出结果应与 `from_scratch.py` **数值可比**（同数据、同真值），便于读者对照。
- 末尾 `if __name__ == "__main__": main()`。
- 顶部注释说明依赖与运行命令。

> Python 3.14 下若 torch 无 wheel，`framework.py` 顶部加保护：try import 失败则打印安装提示并退出，**不得让 import 报错中断**。

---

## 7. 可视化技术选择（meta.viz）

| 现象 | 首选技术 |
|---|---|
| 损失曲线、数据分布、决策边界（静态/低频更新） | **ECharts** |
| 算法过程（梯度流、卷积滑动、聚类迭代、扩散去噪） | **手写 Canvas**（`PAViz.CanvasAnim`） |
| 结构图（神经元、网络层、残差连接、树结构） | **手写 SVG**（静态或简单动效） |
| 参数空间、卷积体素、GNN 图结构 | **Three.js**（`hasThree:true`） |
| 数学公式 | **KaTeX**（`data-tex`） |

每单元 `viz` 数组如实声明用到的技术；门户据此决定卡片缩略与预加载策略。

---

## 8. 写作风格：去「AI 味」（强制）

AI 生成的技术文常被一眼识破：机翻腔、形容词堆砌、面面俱到却无重点、公式与正文脱节。规避要点：

- **第一人称「我们」**，像在带读者走一遍，而非说明书。
- **给具体数字**，不写「效果很好」——写「100 轮后 MSE 从 12.3 降到 0.8」。
- **每个公式配一句白话**：它衡量什么、为什么长这样。
- **讲取舍**：这个模型相对上一个，多了什么、付出了什么。
- **承认局限**：什么时候它会崩、为什么。
- **忌**：空洞排比、过度小标题、罗列一切变体、不必要的「首先/其次/最后」。
- 中文标点、半角与全角混用正确（代码/变量半角，中文全角）。

---

## 9. 质量检查清单（提交前）

- [ ] `meta.json` 字段齐全，`slug` 与目录名一致，`status` 已设
- [ ] README 11 节齐全，公式渲染正常，无 TODO 残留
- [ ] `index.html` 引用顺序正确，暗/亮主题都正常
- [ ] `viz.js` 颜色取自调色板，控件可交互且实时重绘
- [ ] `from_scratch.py` 仅依赖 numpy，能独立运行并打印真值对照
- [ ] `framework.py` 能运行（或优雅降级），结果与从零可比
- [ ] `python scripts/verify_unit.py <slug>` 零错误
- [ ] 浏览器打开页面，动画/公式/图表/滑块均正常
- [ ] 文档读起来像人写的（过 §8 自检）
