# 彩色流体实验台

## 原始提示词

见 [完整原始输入](prompt.md)。本轮为模型 minimax-m3-1-flash-preview、档位 max 在测试分支执行任务正文 v1。

## 运行方式

入口为本目录 `index.html`，单文件、零依赖、无 CDN。需要支持 WebGL 的浏览器；不支持时会显示明确的错误说明而不是黑屏。

## 实现要点

- 完整的 GPU 流体求解链路：涡量 → 散度 → 压力 Jacobi 迭代 → 梯度减除（速度投影）→ 速度平流 → 染料平流，每帧真实执行。
- 双缓冲 FBO 管理速度场与染料场；压力场、散度场、涡量场为单缓冲。
- 着色器统一使用 GLSL ES 1.00，同时兼容 WebGL2 与 WebGL1；半浮点（RGBA16F）优先，不支持时回退 RGBA8。
- 拖动注入：splat 同时写入速度（动量）与染料（颜色）。
- 控制项：染料颜色（8 色板 + 自定义取色）、注入力度、染料消散、速度消散、压力迭代次数、模拟分辨率、渲染像素比。
- 「清空」只清染料场而保留速度场，方便观察扩散；「重置参数」会重建全部缓冲。
- 分辨率 / 像素比变化时先 `deleteTexture` + `deleteFramebuffer` 再重建，避免 GPU 资源泄漏。
- 处理 `webglcontextlost` / `webglcontextrestored`：丢失时停止渲染并提示，恢复时重新编译全部着色器与重建缓冲。

## 验证记录

- 在画布上合成一段连续拖动后，染料沿拖动方向扩散、卷曲并与随机注入的一团混色，说明平流与投影都在工作。
- 暂停后画布像素不再变化，继续后恢复演化。
- 「清空」后染料消失而速度场仍在，短暂等待仍能看到残留流场把后续染料拉成条带。
- 调整压力迭代次数与消散参数后，画面演化速度明显不同。
- 窗口尺寸变化后模拟与触摸坐标仍然正确。
- 软件 WebGL（SwiftShader）环境下无上下文丢失，运行状态面板显示 WebGL 2 与实时帧率。

## 复盘

**做得好的**：没有用「粒子轨迹 + 渐隐画布」糊弄流体，正文要求的平流、散度、压力迭代、投影四步都真实存在，且参数（压力迭代、消散）确实改变计算结果；上下文丢失/恢复与 GPU 资源释放也做了显式处理。

**不足**：
1. 初始版本 `destroyDouble(undefined)` 会抛异常导致页面全黑——这是启动路径上的低级错误，说明缺少「空状态也能启动」的验证。
2. 注入力度滑块的换算曾经写错（压力迭代被当成百分比归零），修正后才生效；映射规则缺少自检。
3. 「速度场能量」这一栏没有实现却出现在界面上，属于死控件；后来换成注入次数与模拟时长。
4. WebGL1 回退路径只用 RGBA8，速度场精度会明显下降，界面没有提示这一差异。
5. 没有 vorticity confinement 的强度参数（写死 26），想调涡旋只能改代码。

## 十轮评审改进记录

本轮由模型 MiniMax M3.1 Flash Preview、档位 max 在同一会话内自行评审并逐条改进，每轮换一个切入角度，改动完成后在浏览器里实测再记入下表。历史输入与历史产物未被覆盖。

- **第  1 轮**：模拟分辨率变化时若画布尺寸未变就不会重建缓冲，参数看起来无效；已改为分辨率调整强制重建。
- **第  1 轮**：显示着色器的随机抖动每帧都在叠加，导致暂停后画面并非真正静止；已改为仅在运行时抖动。
- **第  3 轮**：染料笔触过宽且浓度不足，画面偏灰；已收紧 splat 半径并提高染料写入强度。
- **第 1 轮**：求解器工作台——新增模拟步数、压力迭代累计、单帧 CPU 提交耗时、缓冲总量、累计注入动量五项真实读数，并加了「自检」面板逐项核对画布像素、模拟网格、染料网格与滑杆配置。原本设计的 GPU 归约探针（速度场折半到 1×1 后 readPixels）被移除：实测 ANGLE + SwiftShader 上即使最简单的 1×1 FBO，drawArrays 后立刻 readPixels 也只返回清屏值（独立最小用例复现，读回 0,0,0,0），与其显示一个看似精确的假读数，不如只显示真实量。
- **第 2 轮**：注入参数解耦——注入半径、染料浓度、涡度强度原本分别是写死的 0.0015、写死的 1.45 和写死的 26，现在各自独立成滑杆并暴露到 config；同时修正注入半径滑杆的映射（原来最大只能到 0.00021，永远够不到原先写死的 0.0015）与涡度滑杆缺少 scale=1 导致读数被除以 100 的问题。
- **第 3 轮**：重建模拟缓冲时保留原有流场——拖动模拟分辨率或渲染像素比时，先用拷贝着色器把速度场与染料场重采样到新尺寸再释放旧缓冲，而不是整块清零。面板在缓冲区明确标注「已保留原场」。
- **第 4 轮**：帧率自适应质量——连续 2 秒低于 24 fps 自动降一档模拟分辨率与压力迭代，连续 6 秒高于 50 fps 升回；带滞回计数避免在阈值附近来回闪。手动拖动分辨率或像素比滑杆会自动退出自动档，并同步滑杆位置。
- **第 5 轮**：键盘操作与无障碍——空格暂停、R 清空、S 随机注入、P 保存 PNG，方向键给画布中心注入动量；结果写入 aria-live 区域；画布可聚焦并声明 role/aria-label；补齐 focus-visible 焦点环。同时修正一处死代码：能力检测写成了两次 !supportLinearFloat，而算出来的 supportLinear 从未被使用，现在真正用它参与判定。
- **第 6 轮**：注入计数即时刷新——原先只在每秒一次的帧率窗口里更新注入次数，读数最多滞后 1 秒，看起来像「没注入」；改为注入时直接更新。
- **第 7 轮**：容器自适应与嵌入——改用 ResizeObserver 监听画布宿主的尺寸变化而不是只听 window 的 resize（本站会把该页面以 iframe 嵌入对比页，容器宽度与窗口宽度无关）；窄栏时参数面板折叠为可滚动抽屉；390px 宽度下无水平溢出。
- **第 8 轮**：预设场景与参数持久化——新增「细雨飘落 / 海浪涌动 / 墨滴入水 / 喷泉涡旋」四组预设，每组把注入力度、注入半径、染料浓度、涡度与两个耗散系数一起调整，对应肉眼可辨的流态；参数存入 localStorage，刷新后恢复上次手感，选中项与参数保持一致。
- **第 9 轮**：求解管线分层——把 step() 里 60 多行连续的 bind/uniform/blit 拆成 8 个具名 pass（涡度、涡量约束、散度、压力初值、压力求解、梯度投影、速度对流、染料对流）并由 runPasses 按序调用，求解顺序一眼可见。
- **第 10 轮**：语义与文档对齐——「清空染料」与「重置参数」两条路径在提示文案里明确区分（前者保留速度场、后者速度场一并清零）；新增可折叠的「求解方法与单位说明」，写清 Stam 稳定流体 + 压力投影的每一步、速度的量纲、dt 上限的原因、两个耗散系数不同的换算式，以及读数口径。

以上每条改动也登记在本目录 `run.json` 的 `changes` 字段，可与本表逐条对照。

## 轮次归并与批次汇总

本次后续导入是同一轮测试的更新结果，现已合并到此前归档的实验记录，不另建第 4 轮。普通主题沿用第 3 轮记录；蓝皮书 v1/v2 沿用各自已有的记录 ID。

- 本批：11 个主题案例、12 条实验记录（蓝皮书含 v1/v2）。
- Max 五小时额度累计消耗：108%（此前 44% + 本次 64%）。
- 累计耗时：2h 8m 32s（57m 10s + 1h 11m 22s）。
- 累计 Token：156M。
- 执行备注：自我审查十轮。以上额度消耗、耗时和 Token 为批次口径，不拆分到单案例。

<!-- archive:start -->
## 当前归档信息（自动生成）

- 实验 ID：`fluid-simulation--minimax-m3-1-flash-preview-max-r03`
- 模型：MiniMax M3.1 Flash Preview；推理档位：max
- 执行模式：按原任务执行；备注：自我审查十轮
- 类型：single-html；预览：static；网络：offline
- [完整原始输入快照](prompt.md) · [主题与其他版本](../../../../topic.html?id=fluid-simulation)
- 输入记录：完整原始输入，等同于主题任务正文 v1（未增删），保存于本目录 prompt.md。
- 工具：Claude Code。Claude Code 会话内直接执行，模型 minimax-m3-1-flash-preview、档位 max；未使用子代理，未参考任何历史实现或远程分支。
- 运行方式：浏览器直接打开本目录入口；CDN/外部素材需要联网。
- 费用记录：MiniMax 批次合计 108 %（Max 订阅套餐五小时额度）（12 个案例；批次 minimax-m3-1-flash-preview-max-2026-10-14；未记录单案例费用）
- [实验台入口](../../../../demos/fluid-simulation/runs/minimax-m3-1-flash-preview-max-r03/index.html)

### 部署适配记录

- 第  1 轮：模拟分辨率变化时若画布尺寸未变就不会重建缓冲，参数看起来无效；已改为分辨率调整强制重建。
- 第  1 轮：显示着色器的随机抖动每帧都在叠加，导致暂停后画面并非真正静止；已改为仅在运行时抖动。
- 第  3 轮：染料笔触过宽且浓度不足，画面偏灰；已收紧 splat 半径并提高染料写入强度。
- 第 1 轮：求解器工作台——新增模拟步数、压力迭代累计、单帧 CPU 提交耗时、缓冲总量、累计注入动量五项真实读数，并加了「自检」面板逐项核对画布像素、模拟网格、染料网格与滑杆配置。原本设计的 GPU 归约探针（速度场折半到 1×1 后 readPixels）被移除：实测 ANGLE + SwiftShader 上即使最简单的 1×1 FBO，drawArrays 后立刻 readPixels 也只返回清屏值（独立最小用例复现，读回 0,0,0,0），与其显示一个看似精确的假读数，不如只显示真实量。
- 第 2 轮：注入参数解耦——注入半径、染料浓度、涡度强度原本分别是写死的 0.0015、写死的 1.45 和写死的 26，现在各自独立成滑杆并暴露到 config；同时修正注入半径滑杆的映射（原来最大只能到 0.00021，永远够不到原先写死的 0.0015）与涡度滑杆缺少 scale=1 导致读数被除以 100 的问题。
- 第 3 轮：重建模拟缓冲时保留原有流场——拖动模拟分辨率或渲染像素比时，先用拷贝着色器把速度场与染料场重采样到新尺寸再释放旧缓冲，而不是整块清零。面板在缓冲区明确标注「已保留原场」。
- 第 4 轮：帧率自适应质量——连续 2 秒低于 24 fps 自动降一档模拟分辨率与压力迭代，连续 6 秒高于 50 fps 升回；带滞回计数避免在阈值附近来回闪。手动拖动分辨率或像素比滑杆会自动退出自动档，并同步滑杆位置。
- 第 5 轮：键盘操作与无障碍——空格暂停、R 清空、S 随机注入、P 保存 PNG，方向键给画布中心注入动量；结果写入 aria-live 区域；画布可聚焦并声明 role/aria-label；补齐 focus-visible 焦点环。同时修正一处死代码：能力检测写成了两次 !supportLinearFloat，而算出来的 supportLinear 从未被使用，现在真正用它参与判定。
- 第 6 轮：注入计数即时刷新——原先只在每秒一次的帧率窗口里更新注入次数，读数最多滞后 1 秒，看起来像「没注入」；改为注入时直接更新。
- 第 7 轮：容器自适应与嵌入——改用 ResizeObserver 监听画布宿主的尺寸变化而不是只听 window 的 resize（本站会把该页面以 iframe 嵌入对比页，容器宽度与窗口宽度无关）；窄栏时参数面板折叠为可滚动抽屉；390px 宽度下无水平溢出。
- 第 8 轮：预设场景与参数持久化——新增「细雨飘落 / 海浪涌动 / 墨滴入水 / 喷泉涡旋」四组预设，每组把注入力度、注入半径、染料浓度、涡度与两个耗散系数一起调整，对应肉眼可辨的流态；参数存入 localStorage，刷新后恢复上次手感，选中项与参数保持一致。
- 第 9 轮：求解管线分层——把 step() 里 60 多行连续的 bind/uniform/blit 拆成 8 个具名 pass（涡度、涡量约束、散度、压力初值、压力求解、梯度投影、速度对流、染料对流）并由 runPasses 按序调用，求解顺序一眼可见。
- 第 10 轮：语义与文档对齐——「清空染料」与「重置参数」两条路径在提示文案里明确区分（前者保留速度场、后者速度场一并清零）；新增可折叠的「求解方法与单位说明」，写清 Stam 稳定流体 + 压力投影的每一步、速度的量纲、dt 上限的原因、两个耗散系数不同的换算式，以及读数口径。
- 同轮更新归档：测试分支后续更新的完整产物、执行记录和文档已并入本条实验记录，不另建新轮次。来源：F:/dev/ai-coding-demo-test（model-test-base）/demos/fluid-simulation/runs/minimax-m3-1-flash-preview-max-r01。
- 维护者于 2026-10-22 按 v3 对本轮桌面、手机及补充状态逐图重评并绑定 captures 证据；旧截图和 v2 评分见 catalog/score-reviews/2026-10-21-v3-source.json。未重跑模型或改写实验源码，截图不证明完整功能、算法、手势或性能。
<!-- archive:end -->
