📄 文书档案 · 浑天 产品产生的全过程

浑天 v0.1 — 产品产生的全过程

从一个取色器,到太阳系轨道模拟。这不是计划出来的,是一步步走出来的。

起点:取色器

一切始于一个简单的需求——从参考照片中读取色值。

`color-block-tool.html`:上传图片,按行/列读取像素颜色,支持 36×64 和 72×128 两种精度。输出的色值表用于游戏场景的色彩标定。

没有人计划要做一个球面渲染器。取色器就是取色器。

第一步:天空渲染器

从取色器拿到色值后,需要把颜色画到画布上。第一个渲染器是天空——`sky-renderer.js`。

做法很直接:每行一个线性渐变,加上横向亮度偏移。135行代码。天空就是从地平线到天顶的颜色渐变,没什么花哨的。

但这里埋下了一个架构基因:渲染器管"怎么画",配置管"画在哪"。这个基因贯穿了后续所有开发。

第二步:道路渲染器

`road-renderer.js`,40行。梯形道路,路径加渐变一次 fill。最简单的渲染器,但解决了一个具体问题——透视感。

第三个:地面渲染器——踩坑

`ground-renderer.js`。这个踩了大坑。

错误方案:纵向锚点(7色)+ 横向 cells(取1行)50% 混合。两套系统各丢一半对比度,画面发灰。

正确方案:把 7×36 cells 当 2D 贴图,双线性插值同时采样两个方向。113行。

教训:不要用两套独立的系统各管一半然后混合,要用一套系统同时管两个方向。 这个教训后来在球面渲染里反复出现——一个维度的问题不要拆成两个半维度来解决。

还有一个 parseMD 的坑:`startsWith('行 ')` 只匹配行1-9,行10+没有空格。改成 `/^行\s*\d/` 解决。

透视标定

`perspective.js`,225行。从路的收敛参数反推灭点、缩放函数、梯度。

坐标系:X 0→9, Y 0→16(底→顶),单位cm,9:16照片实测。

这一步把"照片只是找规则的参考,目标是程序化生成不依赖照片"确立为原则。

物理学归约:从取色到物理原语

用户从6个锚点出发,一路走到物理学基本原语:

球面渲染器 Phase 1:球体

`sphere-renderer.js` 从这里开始。Canvas 2D ImageData 逐像素,540×540。

三原语对应:

交互:拖拽旋转、光源调节、环境光、自动旋转。星空预渲染缓冲。

踩坑:`starBuf` 必须存为 `ImageData` 对象(非 `Uint8ClampedArray`),`putImageData` 才能接受;地表视图读像素要加 `.data`。

Phase 2:三层架构

从"一个球"升级为"一个有岁差的行星系统":

- C层(耦合参数空间):axialTilt / eccentricity / precessionRate 联动

- B层(岁差进动):ascNode 慢变,周期25771年

- A层(观测尺度锁死):dt→0,岁差可忽略

三层不是三个功能,是三个时间尺度。C层管参数关系,B层管地质尺度的慢变,A层管人类观测尺度看到的东西。

这一步是整个项目的架构核心——用层级嵌套管理不同时间尺度,而不是把所有东西塞进一个方程。

Phase 3:太阳系尺度

观测角度(orbitViewAngle)

用户提出:"俯视角本身就不应该在这个尺度看得到,调整成平地视角,自然呈现一条线。这是观测误差与观测角度共同作用本身的真实。"

实现:通过 `cos(观测角度)` 缩放轨道平面Y坐标。0°为俯瞰黄道面(完整椭圆),90°为平地视角(轨道压成水平线)。连续可调。

全天体

用户:"能把另外的行星加全么?金水地火土木海天冥王星,还有哈雷彗星。"

实现:`solarBodies` 数组,10个天体,全部使用真实轨道参数(半长轴、偏心率、周期)。新增通用 `_ellipsePos(nuDeg, a, e)` 函数,原 `_orbitPos` 委托调用。

各天体按真实周期独立运动——水星88天一圈,海王星165年一圈。同一时间轴上放一起,内圈疯转外圈纹丝不动。这是开普勒第三定律最直观的视觉呈现。

缩放(orbitZoom)

用户发现外行星超出画布。问能不能改画布尺寸。

计算后发现:显示海王星轨道需要画布高度10400px,不现实。

改为缩放滑块,0.05×~20×。最小改动解决多尺度显示问题。缩放到最低可以看到天王星,但内行星和太阳挤压在最中间——"这本身就是观察到海王星轨道尺度的前置条件下的观测实际"。

对数缩放(e域入口)

用户在讨论中提出:e 和 π 还没有统一进体系内。欧拉恒等式 `e^(iπ)+1=0` 统一了 e、i、π、1、-1。

实现:对数缩放模式,径向距离用 `ln(r+1)/r` 压缩,保持角度不变。开启后同一视图可显示水星到海王星所有天体。

这是 e 正式进入系统的入口。不是重写轨道方程,是在显示层加一个数学变换。

月球:不加

讨论了是否加月球。结论:不加。

在太阳系尺度下月球轨道仅0.4px,不可见。如果加进去,那个转速会形成视觉残留——本身就是一道环。月球属于地月系统视图的范畴,不在太阳系俯瞰视图里。

关键设计决策记录

| 决策 | 选择 | 理由 |

|------|------|------|

| 画布尺寸 | 不改,加缩放 | 显示海王星需10400px,不现实 |

| 天体运动 | 各按真实周期独立 | 开普勒第三定律的诚实呈现 |

| 对数缩放 | 显示层变换,不动轨道力学 | e是观测工具,不是物理量 |

| 月球 | 不加 | 0.4px不可见,属于另一视图 |

| 观测角度 | cos投影Y坐标 | 真实观测几何 |

| 美化 | 拒绝 | 诚实模拟哲学 |

用户的自我发现

在整个过程中,用户确认了一件事:

被计算机带回数学,被物理推到门口看了一眼,但确认物理不是目的地。
真正的方向是系统架构——结构化、层级嵌套、全局可控。
每次最兴奋的时刻是"搭出一个结构",不是"算出一个结果"。

球面渲染器的 C/B/A 三层架构就是证据。物理是素材,系统设计才是目的。

文件演化时间线

| 时间 | 文件 | 事件 |

|------|------|------|

| 早期 | color-block-tool.html | 取色器,一切的起点 |

| 早期 | sky-renderer.js (135行) | 天空渐变渲染 |

| 早期 | road-renderer.js (40行) | 梯形道路 |

| 早期 | ground-renderer.js (113行) | 地面双线性插值,踩坑后重写 |

| 早期 | perspective.js (225行) | 透视标定 |

| 2026-07-05 | sphere-renderer.js (544行) | 球面渲染器 Phase 1→2→3 |

| 2026-07-05 | sphere-lab.html (303行) | 交互控制面板 |

---

_2026-07-05 立此存照_

—— 人与AI协作记录 ——