03 · Netbook:可视化交互网页规格
轨道 A 的产品规格。目标不是"做一个交互网百科",而是让读者在动手过程中建立正确的心理模型:计算是局部的图重写;复制/擦除是结构;并发是独立 redex 的集合;Agent 是带协议的 cell。
3.1 受众与场景
| Persona | 背景 | 来 Netbook 想解决什么 | 成功信号 |
|---|---|---|---|
| CS 学生 | 学过 λ 演算/数据结构 | 听说交互网是最优归约的基础,但论文看不懂 | 能独立构造并解释一张网;能说明为什么共享能省工作 |
| PL 研究者/工程师 | 写编译器/运行时 | 想快速验证一个编码/规则 | 能在 sandbox 里编辑规则、导出 trace |
| AI 工程师 | 用 LangGraph/AutoGen | 想知道"以图为语义"的 Agent 编排有什么不同 | 能搭一个 3 Agent 网,看懂消息/成本/重放 |
| 教师 | 讲计算理论/函数式编程 | 需要可演示的课堂材料 | 能投影、能离线、能分享 permalink |
非目标:不服务"只想看结论"的读者;不替代论文;不做视频课程。
3.2 学习路径与章节
三种模式:
- Learn:按章引导,锁定部分交互,有检查点。
- Play:自由 sandbox,所有 Agent/规则开放,可导入导出。
- Lab:实验性章节(最优归约对比、并发调度、Agent 成本),允许改参数/跑基准。
章节表
| # | 标题 | 核心概念 | 交互组件 | 章末挑战 |
|---|---|---|---|---|
| 0 | 计算的另一种写法 | 重写系统、局部性 | 字符串重写器 → 图重写器 | 用 3 条规则把 SKK 归约到范式 |
| 1 | Agent、端口、线 | cell、principal/aux、wire、interface | 拖拽搭建第一张网 | 给定额度,搭出指定接口的网 |
| 2 | 活跃对与规则 | active pair、点火、局部重写 | 规则播放器 + "预测下一步" | 补全一条规则,使网到达指定范式 |
| 3 | 三个组合子就够了 | γ/δ/ε、湮灭/交换/擦除、通用性 | 组合子实验室(随机网 + 单步) | 用 γ/δ/ε 实现布尔 XOR |
| 4 | 把 λ 算进来 | 抽象/应用/变量、β 归约 | λ→网 编译器 + 左右对照 | 编译并归约一个 Church numeral |
| 5 | 共享与最优 | 复制、共享图、Lévy 最优、括号 | naive vs sharing 双跑 + 计数 | 让 fib(10) 的交互数下降 ≥ 5× |
| 6 | 类型与线性 | 线性逻辑、proof net、极化 | 线性检查器 + "能否复制这根线" | 修一张违反线性的网 |
| 7 | 并发与调度 | redex 图、独立集、work stealing | N worker 调度可视化 + 合流检查 | 在 4 worker 下达到接近关键路径的下界 |
| 8 | 从网到 Agent | 状态 cell、消息、工具、effect、预算 | 3 Agent 流水线(mock LLM)+ 成本表 | 加一个 Critic,使质量分 ≥ 阈值且预算不超 |
| 9 | 自己造一个网 | 综合 | 自由 sandbox + 挑战库 | 提交一个可复现的网/规则包 |
每章结构统一:
- Hook(1 段):一个反直觉的问题/现象。
- Concept(2–4 段 + 图):最小必要定义。
- Play(核心交互):读者必须动手才能继续。
- Explain(1–2 段):把刚才的操作映射回定义。
- Quiz(2–3 题):即时反馈,错的选项解释为什么错。
- Deep dive(可选折叠):论文引用、形式定义、边界情况。
章节设计要点
- 第 0 章不出现"交互网"这个词:先让读者体验"重写";第 1 章才命名。
- 第 1 章先限制为树:避免一开始就遇到环/共享;第 3 章再引入一般图。
- 第 2 章必须让读者"预测":看规则 → 预测结果 → 点火验证;预测错误时高亮差异。
- 第 3 章用"三规则"闭环:每个规则至少手动点火 3 次,直到形成直觉。
- 第 4 章不教完整 Lamping:先给简化编码(LAM/APP/SUP/DUP),把括号/最优留到第 5 章。
- 第 5 章的对比必须用同一台引擎、同一输入:只改共享策略,显示交互数/最大并行度/时间。
- 第 6 章用"能否复制"作为钩子:让读者亲手制造一个违反线性的网,看到类型错误。
- 第 7 章把调度器做成可拖拽的:读者可以把 redex 拖到不同 worker,观察关键路径。
- 第 8 章用 mock LLM:默认离线、确定性;可选 BYO key(经代理),并显示 token/成本。
- 第 9 章提供 6–8 个挑战:排序网、加法器、布尔电路、map/reduce、会话协议、监督树。
3.3 核心交互组件
3.3.1 Net Canvas
功能:
- 平移/缩放(触控板、滚轮、触屏)。
- 拖拽 cell;拖动端口拉线;吸附到最近合法端口;非法连接给出原因(类型不匹配/已占用/方向错误)。
- 选中、框选、删除(连带擦除/悬空线处理)、复制子网(自动重命名端口)。
- 自动布局:小图用分层(Sugiyama),大图/有环用力导向;可 pin 住节点。
- 高亮:hover 显示 cell 类型/端口类型;选中显示可达子网;活跃对脉冲高亮。
- 规则点火动画:LHS 高亮 → ghost 残影 → 新 cell 展开 → 线重接;可调速度/关闭。
- 时间旅行:底部 slider,拖到任意 step;显示该步的 before/after diff。
实现:
- PixiJS 8(WebGL)渲染 cell/线/动画;SVG 覆盖层负责可访问性与文本。
- 自研布局(不引入 React Flow):端口级连接、活跃对高亮、几千节点性能。
- 场景图分层:background grid → wires → cells → ports → overlays → labels。
- 线的绘制:三次贝塞尔;端口切线方向由端口角度决定;避免穿过 cell(简单避障)。
- LOD:缩放 < 0.4 时只画点/线;> 0.8 显示标签;> 1.2 显示端口名。
3.3.2 Rule Player
- 显示当前活跃对、匹配的规则、变量绑定。
- 按钮:Step、Step over(一次把一个 agent 的所有交互跑完)、Run、Pause、Reset。
- 速度:0.25×–8×;可单步到下一个"有趣"事件(规则类型变化/共享节点出现)。
- 断点:按 agent 类型、规则名、交互数、是否产生 δ/ε。
- "为什么"面板:解释这条规则为什么匹配(类型/端口/标签),以及点火后哪些线被重接。
3.3.3 λ → Net 编译器
- 输入:无类型 λ 项(支持 named terms、Church numerals、let、if)。
- 输出:网 + 逐步 β 归约对照。
- 左侧 λ 项高亮当前 redex;右侧网高亮对应活跃对。
- 支持 call-by-name / call-by-need / 最优(Lamping 简化版)三种策略切换。
- 显示:交互数、β 步数、共享节点数、最大并行度。
- 错误:自由变量、非终止(fuel 用完)给出友好提示。
3.3.4 Sharing Lab
- 同一程序两栏:naive(无共享)vs sharing(δ 节点)。
- 实时计数器:交互数、分配 cell 数、峰值内存、最大并行度、关键路径。
- 预设:fib、Church exponentiation、列表 map、树遍历。
- "解释这一差距":点击计数展开,显示哪些子网被共享/复制。
3.3.5 Concurrency Lab
- 可调 worker 数(1–16)、调度策略(FIFO/随机/关键路径优先)。
- 可视化:每个 worker 的队列、偷取事件、活跃对颜色。
- 指标:makespan、总交互数、并行效率、idle 时间。
- 合流检查:不同调度跑同一程序,比较最终网 hash;不一致则红色警告(应只发生在 effect 章节)。
3.3.6 Agent Lab
- 画布上预置 agent cell:
Researcher、Critic、Writer、Tool(search)、LLM。 - 消息是网上的 token;拖拽/连线构建流水线。
- 运行:mock LLM(内置 5 个确定性响应)或 BYO key(经本地代理;key 不落库)。
- 面板:消息时间线、每个 agent 的 state、token/成本、重放按钮。
- 挑战:在预算内达到质量阈值;加一个 supervisor 处理 tool 失败。
3.3.7 Sandbox
- 完整编辑器:自定义 agent(名称/端口/状态)、规则(图形化或文本)、初始网。
- 文本模式:直接写 Netbook IR(JSON 或简化 DSL),与图形双向同步。
- 导入/导出:JSON、PNG、SVG、分享链接。
- 校验:类型/线性/端口匹配;错误定位到图元素。
- 性能保护:cell 上限(如 20k)、交互上限(fuel)、Web Worker 中运行。
3.3.8 Quiz
- 题型:单选、多选、排序(归约步骤)、连线(端口→类型)、预测(下一步图)。
- 反馈:不只对错,显示"你的答案会导致哪条规则/哪根线出错"。
- 进度:localStorage;可选账号(v2)。
3.4 视觉与动效规范
| 元素 | 规范 |
|---|---|
| Agent | 圆形/圆角矩形,直径 44–56px;principal port 用实心三角/凹槽标识;aux 用小圆点 |
| 颜色 | γ 蓝、δ 绿、ε 灰、用户 agent 用色板(色盲安全);活跃对用琥珀色脉冲 |
| 线 | 2px,选中 4px;高亮时加外发光;不同数据类型可用虚线/颜色(可选) |
| 动画 | 点火 240ms ease-out;ghost 120ms;新节点 180ms scale-in;支持 prefers-reduced-motion |
| 字体 | 正文 Atkinson Hyperlegible / 思源黑体;代码 JetBrains Mono |
| 布局 | 左侧课程导航(可折叠),中间画布,右侧解释/检查器;移动端上下堆叠 |
| 深色模式 | 默认跟随系统;画布颜色对比度 ≥ 4.5:1 |
3.5 技术架构
Astro 7 (static) + islands
├── Svelte 5 components
│ ├── LessonShell / MDX renderer
│ ├── NetCanvas (PixiJS 8)
│ ├── RulePlayer / Timeline
│ ├── LambdaEditor (CodeMirror 6)
│ ├── Quiz / Progress
│ └── AgentLab
├── ain-wasm (Rust → wasm-bindgen)
│ ├── Net IR / reducer / trace
│ ├── λ parser + encoder
│ └── layout hints / metrics
├── MDX content (zh/en)
├── KaTeX (inline math)
└── Service Worker (offline)
选择理由:
- Astro:内容为主、islands 按需加载;首屏轻;适合 MDX 课程。
- Svelte 5:细粒度响应式,画布 UI 状态简单;与 Astro islands 成熟。
- PixiJS:WebGL 批渲染,几千 cell 稳定 60fps;比 SVG/DOM 更适合动画。
- Rust/WASM:与生产运行时同一内核;性能足够;可离线。
- 不用 React Flow:端口级交互、规则动画、性能都不匹配;自研成本可控。
- MDX + 结构化 lesson JSON:散文与交互分离;交互状态可序列化/测试。
状态管理
- WASM 侧:网状态、归约、trace、指标;暴露
step(),runUntil(),snapshot(),restore()。 - Svelte 侧:UI 状态(选中、缩放、面板、进度);用 runes(
$state/$derived)。 - URL:lesson id + step + 压缩后的网快照(lz-string);刷新可恢复。
- 持久化:IndexedDB 存 sandbox 草稿;localStorage 存进度。
内容管线
content/zh/ch03.mdx
content/en/ch03.mdx
content/lessons/ch03.json # 交互组件配置、初始网、挑战、quiz
│
▼ build-time validation (Zod + golden traces)
dist/ 静态页面 + wasm + assets
- 每个交互组件由
lesson.json驱动;MDX 只负责叙述与嵌入。 - 构建时跑
golden trace:初始网 + 规则 → 期望的 step 序列/最终 hash;不一致则构建失败。 - 引用检查:每个"事实性"段落带
source字段;缺失则 lint 警告。
3.6 数据模型
type PortRef = { cell: CellId; port: number };
type Cell = {
id: CellId;
type: string; // "gamma" | "delta" | "epsilon" | "user:Planner" ...
state?: unknown; // 用户 agent 的状态(JSON)
label?: number; // δ/γ 标签
x: number; y: number; // 布局
pinned?: boolean;
};
type Wire = { a: PortRef; b: PortRef };
type NetSnapshot = {
cells: Cell[];
wires: Wire[];
free: PortRef[];
meta?: { fuel: number; step: number; hash: string };
};
type Step = {
index: number;
redex: [CellId, CellId];
rule: string;
before: NetSnapshot;
after: NetSnapshot;
bindings: Record<string, unknown>;
metrics: { interactions: number; cells: number; maxParallelism?: number };
effect?: EffectEvent;
};
type Trace = {
version: 1;
program: string;
initial: NetSnapshot;
steps: Step[];
finalHash: string;
};
type Lesson = {
id: string;
chapter: number;
locale: "zh" | "en";
title: string;
objectives: string[];
blocks: Block[];
quiz: QuizItem[];
sources: SourceRef[];
};
type Block =
| { type: "prose"; md: string }
| { type: "net"; initial: NetSnapshot; rules: string[]; goal?: Goal }
| { type: "sandbox"; limits: { cells: number; fuel: number } }
| { type: "compare"; program: string; strategies: Strategy[] }
| { type: "agentLab"; scenario: string; budget?: Budget };
Trace 是唯一事实来源:动画、计数器、分享、测试都从它派生。
3.7 内容正确性与测试
- 参考实现:
ain-core的朴素解释器(Rust)作为 oracle;WASM 是同一代码的编译产物。 - Golden traces:每个章节的初始网/规则 → 期望 trace(step 数、最终 hash、关键中间态)。
- 属性测试:
- 随机网 + 随机规则 → 不同归约顺序得到同一范式(纯子集)。
- 编码/解码 λ 项 → 归约结果与参考 λ 解释器一致。
- 线性检查器:随机网 → 违反线性的网必须被拒绝。
- 规则覆盖:γ/δ/ε 的 4 类规则 × 端口排列组合,逐一快照测试。
- 内容审校:每章至少一位外部审校(PL/数学背景);引用可点击;术语表统一。
- 可访问性测试:axe-core + 键盘走查;画布提供文本描述("当前有 3 个活跃对...")。
3.8 性能与可访问性预算
| 指标 | 目标 |
|---|---|
| 首屏 HTML+CSS+JS(不含 WASM) | < 300KB gzip |
| WASM | < 600KB gzip |
| TTI(M1 MBA / 4G 模拟) | < 2.5s |
| 2,000 cells / 5,000 wires | ≥ 55fps(M1) |
| 单步延迟 | < 16ms(P95) |
| 内存(10k cells) | < 200MB |
| 离线 | 全部课程 + sandbox 可用 |
| WCAG | AA;画布有键盘替代;动画可关闭 |
3.9 MVP 与 v1 范围
MVP(M1,约 6 周)
- 第 1–3 章 + sandbox(组合子)。
- Net Canvas(拖拽/连接/点火/单步/重置)。
- WASM 引擎(γ/δ/ε + 用户二元 cell)。
- 中/英各 1 套文案;部署到 Cloudflare Pages。
- Golden trace 测试 + 规则覆盖测试。
v1(M5,约 6 个月)
- 第 0–8 章 + 第 9 章挑战库。
- λ 编译器 + Sharing Lab + Concurrency Lab + Agent Lab(mock)。
- 时间旅行、断点、permalink、离线、深色模式、移动端。
- 外部审校 + 可访问性审计。
- 可选的"课堂模式"(教师锁定章节/隐藏答案)。
3.10 风险与缓解
| 风险 | 缓解 |
|---|---|
| 范围膨胀(变成通用图编辑器) | 只做教学需要的交互;sandbox 功能按章节递进解锁 |
| 数学/规则错误 | 参考实现 + golden trace + 外部审校;每个规则有出处 |
| 动画性能 | PixiJS + LOD + Web Worker;超过阈值切换"简化渲染" |
| 内容枯燥 | 每章先给反直觉问题;动手优先于定义;挑战即时反馈 |
| LLM 成本/隐私 | 默认 mock;BYO key 只存内存;代理不记录 prompt |
| 移动端体验 | 画布手势优先;关键交互提供按钮替代;不追求完整编辑 |
3.11 与轨道 B 的接口
ain-wasm的 API 即 Netbook 的引擎 API;文档在specs/wasm-api.md。- Trace 格式即生产调试器的格式;Netbook 的"时间旅行"复用于
aind的 trace viewer。 - 第 8 章的 Agent 示例用 Ainet Flow 的语义(mock 运行时),确保概念一致。
- 第 9 章的挑战可以作为
examples/的测试用例。
3.12 M1 实现状态(2026-11)
已落地(apps/netbook):
- 第 1–3 章 + Sandbox,数据驱动(
src/lib/lessons.ts),不是 MDX;内容与交互分离的边界保留。 - PixiJS 画布:渲染、拖拽 cell、端口连线、点击已连接端口断开、缩放/平移、选中/删除。
- 确定性力导向布局(
src/lib/layout.ts);拖拽位置保留;分享链接包含布局。 - Step/Run/Reset、活跃对高亮、点火 flash、trace chips + 右侧 trace 列表。
- 任务校验:基于当前网、交互数、累计规则集(
rulesSeen)。 - Undo/Redo(按网快照);permalink(URL hash,base64 JSON)。
- Golden trace:
crates/ain-core/tests/golden.rs锁定 M1 两个 demo 的最终 hash。
与规格的差异 / 顺延:
- 规格写"MDX + lesson JSON";M1 先用
lessons.ts+ Astro 单页,M2 再引入 MDX 内容管线。 - 规格写"分层布局";M1 用力导向,分层留到 M2(小图效果已够)。
- 时间旅行/断点/速度控制、规则编辑器、英文文案顺延到 M2。
- 自由端口仍是 cell 端口;接口保持(free-standing endpoint)在 M2 修。