Repository navigation
Tags: programmingWTF/FlyBrain
Tags
v0.3.1 —— 噪声流可复现性、评测台自包含、游戏性逐 tick 对账 在 v0.3.0 之后继续追查"网页服务端均分偏低",挖出并修掉三个真问题: 1. **噪声走全局 RNG → 同种子也飞得完全不同。** 同种子、喂完全相同的驱动,两个进程的脑膜电位最大差 **0.674**。 改成每个脑独占 rng/tgen 后:**0.000000,逐 tick 一致**。 代价:历史分数不再逐位可复现(留了 `--legacy-noise` 开关做 A/B), README 如实记录了实测数字(新 31.05 / 旧 43.65 / 历史 100.80)。 结论层面完好:cut / shuffled 依旧 **1.00 ± 0.00、0 次拍翅**。 2. **评测台不再需要 51.5 MB 的连接组源数据。** `looming.resolve()` 原来无条件读 feather(按设计不入库), 于是干净的克隆根本跑不了评测台 —— 而仓库里本来就有预烤的 `key_*`。 已验证预烤与 feather 逐元素完全一致。 3. **`deque(maxlen=5)` vs `recent` 空列表起步** —— 窗口计数的起点不同, 一旦某 tick DNp01 发放 2 次就开始分叉。 新增 `scripts/verify_server_vs_bench.py`(同种子逐 tick 端到端对账) 与 `scripts/verify_server_gameplay.py`(可复现地量服务端得分)。 三个 bug 都是前者发现的 —— 靠猜是猜不出来的。 至此,网页与评测台**跑的是同一条控制回路**,且由脚本守着。
v0.3.0 —— 游戏仿真搬到服务端(恒定速度)
网页版从"速度随 HTTP 往返抖动"变成**恒定 50 步/秒、严格 1:1、60fps 流畅**。
指标 v0.2.1(前端自跑) v0.3.0(服务端锁步)
仿真速率 14~32 步/秒(抖) 50.0 步/秒(恒定,偏差 +0.1%)
渲染帧率 与游戏速度耦合 60.0 fps,与游戏速度无关
决策与物理 靠队列近似配对 同一进程内严格 1:1
网络抖动影响 直接改变游戏速度 只影响画面新鲜度
服务端 `GameWorld`(物理 + 碰撞 + 关卡生成)+ 一个固定 50 Hz 的锁步线程:
每 tick 在同一进程、同一把锁里完成
「按当前世界算驱动 → 走一个脑 tick → 用 DNp01 的发放决定拍不拍 → 走一步物理」。
节拍由**墙钟差值**决定,所以线程被调度得忽快忽慢也不影响游戏速度。
前端只做两件事:按自己的帧率取状态(`GET /api/game/state`,约 400 字节)、
在两次状态之间插值渲染。`app.js` 46 KB → 38.5 KB。
前端试过四种驱动方式,全部失败并都有实测;根因是**浏览器没有可用的可信节拍**:
setTimeout(4) → 29.8 次/s(被压到 ~33ms)
requestAnimationFrame → 28.2 次/s(后台会被完全暂停)
· scripts/verify_server_physics.py —— 服务端 GameWorld vs 评测台 World
逐 tick 对账(60 局 × ≤3000 tick,全部死亡,覆盖碰撞路径):逐 tick 等价
· demo/verify_server_collision.js —— 服务端判定 vs 前端画法,逐像素(12410 个 y,0/0)
· demo/verify_page.js —— 浏览器验收 + 服务端速率是否恒定,自带进程清理
其中第一个当场抓到真 bug:拍翅冷却原本被我塞进 GameWorld,
而评测台的 `World.step(flap)` 是无条件的(冷却由 harness 管),vy 差了 23.6。
· 3D 脑图:`viz_spike`/`lit_spike`/`eff` 原来来自前端自己那次 /api/step,
仿真搬走后面板会**不报错地变空**。现在由状态端点一起发回。
· `--asset`:默认改成 `spiking_full`,并加启动硬门 ——
传不含 LC4/LPLC2/DNp01 的资产会直接拒绝启动并说明原因
(原来是不报错地"分数恒 0",还会先抛一个跟根因无关的 IndexError)。
删掉 `scripts/flappy_page_parity.py`(它继承评测台的 World,
所以"比值 1.0"没有验证力 —— 一个自己和自己比的校验器)、
`demo/measure_rates.js`、`demo/verify_collision_pixels.js`(均已被取代);
文档全面更新(README / demo/README / DEPLOY / check_all.bat)。
v0.2.1 —— 服务端仿真重构前的检查点
这是"浏览器侧仿真"路线的最后一个可用状态。已验证:
帧率 27.3 fps 物理 32.1 步/秒 脑 tick 32.1/秒 ← 严格 1:1
pend 积压 0 脑忙跳过 0 过 19 根管子 / 0 死亡
在页面内直接测量浏览器定时器,得到硬约束:
setTimeout(4) → 29.8 次/s(被压到 ~33ms)
requestAnimationFrame → 28.2 次/s
浏览器把定时器压到约 30 Hz,代码层面绕不过去。而 HTTP 往返中位 60ms
(p90 86ms、最快 4ms,差十几倍)—— 于是"每步物理该配多少时间"时多时少,
表现就是用户报的**时快时慢**。
试过并失败的方案(都已回退,不留死代码):
· 固定节拍 + 决策队列预取(队列会周期性见底)
· 大批量预取(一次 20 tick)→ 决策陈旧 → 鸟撞地
· 预取与消费写在同一 await 链 → 一次往返把消费一起阻塞
· 依赖 rAF 续命 → 无头/后台页签下 rAF 完全暂停,仿真冻住
把游戏仿真搬到服务端:脑与物理在**同一个进程内**按 1:1 跑固定 50 Hz,
HTTP 只用来取状态,延迟不再进入游戏时钟。服务端已有完整的 Python 物理
(scripts/flappy_bench.py 的 World),且验证过与页面几何一致。
v0.2.0 —— 自包含 + 可部署的已知可用状态 相对 v0.1.0 的主要变化: · **仓库自包含**:新增 scripts/bake_coords.py,把 51.5 MB 的 manifest 预烤成 1.6 MB 的 data/coords.npz(含每个神经元的解剖坐标、556 个关键神经元坐标、 关键群与逐侧索引)。于是运行期不再需要 manifest.json,也不再需要 13.5 MB 的 细胞类型表 —— 启动从"解析大 JSON 几十秒"降到 **4.7 s**。 · **运行必需的 3 个资产入库**(共 49.9 MB): data/spiking_full.npz / spiking_full.json / coords.npz 前端 three.js 也进仓库(demo/vendor/three.module.js,1.3 MB) · **资产缺失时优雅降级**,不再启动即崩(缺 manifest 只让 3D 脑图点云为空) · **跨平台**:打开浏览器从 Windows 专有的 `cmd /c start` 改成 webbrowser.open() · **.gitattributes** 锁死行尾,保护 .npz 等二进制资产(本机 core.autocrlf=true, 猜错会让 Linux clone 下来的文件报废) · **文档**:DEPLOY.md(systemd/验收清单/排障表/Linux 适用性验证)、 DEPLOY_PROMPT.md(可复制给服务器 Agent 的提示词)、 scripts/verify_clone.py(clone 后自检) 实测:启动 4.7 s、内存 483 MB、/api/step 中位 27 ms、 浏览器 36 s 内 score=12 dead=0 无异常。 已知未解决:页面得分仍低于离线评测台(浏览器喂不动 144k 神经元的脑)。
FlyBrain v0.1.0 —— 首个公开版本
把真实果蝇全脑连接组(FlyWire FAFB v783,144,837 神经元 / 15,023,799 突触)
当成一个**冻结的、零可学参数的神经网络**来驱动小游戏。
**全部 13.9 万神经元的 WebGL 全脑渲染**
· node fetch_all_skeletons.mjs → 下载全部骨架(~6 GB,可断点续传,无需 token)
· node build_brain_asset.mjs --out data/brain → 两遍流式编译成紧凑二进制
· node serve.mjs → 本地服务 + 自动开浏览器
· node validate_brain_asset.mjs → 偏移/对齐/计数逐神经元深校验
**Flappy 演示(本项目主线)**:flyflappy/demo/
· 脑完全冻结、零可学参数;拍翅只来自 LC4 / LPLC2 → DNp01 的逼近逃逸反射
· 输入是把"缺口相对鸟的高低"映射到 LC4 腹侧/背侧半群 + LPLC2 角尺寸通道
· 输出只读 DNp01(巨型纤维两细胞)的发放,过阈值就拍一次翅
· 神经消融证据:real 108.33 / cut 0.00 / shuffled 0.00(评测台 100 局)
**离线评测台** flyflappy/scripts/flappy_bench.py —— 与页面同一套物理与判定,
用于可复现地量分数、做消融、查死因。
游戏里"看着撞上了却不判失败"这个 bug 查了很久,根因是**像素与坐标混用**。
现在判定由**逐像素**对账定出:
y - BIRD_R <= p.top + BIRD_R || y + BIRD_R >= p.top + GAP - BIRD_R - 1
依据:fillRect(y,h) 覆盖像素 y…y+h-1(闭区间);上管覆盖像素 [0, top+R]、
下管覆盖 [top+GAP-R-1, …];鸟圆周覆盖 [ceil(y-R), floor(y+R)];两组有交集即视觉重叠。
demo/verify_collision_pixels.js 读 app.js 里的真代码逐像素守着
("只画不判"与"只判不画"都必须为 0)。
· 页面主循环在慢机器/无头浏览器下抗性不足:渲染慢会导致物理步进被拖住
· 页面得分仍低于评测台(浏览器喂不动 144k 神经元的脑,实测 14~20 tick/s,需 50 才 1:1)
· 连接组数据、环境、编译产物均未入库(见 .gitignore,可用上面的脚本重新生成)
· 暂无 LICENSE(默认保留所有权利)