# Design Teardowns 设计与实现说明

## 实现范围

本说明对应 `teardowns/index.html`、`_gallery/beamline.js`、`beamline-3d.js`、`beamline.css` 与 canonical `catalogue.js`。产品行为见 [PRODUCT](PRODUCT.md)，交付状态和验证记录统一见 [README](README.md#验证与交付)。

## 构图与视觉语言

光束线用同一台仪器表达 Capture、Measure、Reconstruct、Verify、Archive 五步研究流程。左侧是标题、方法说明与拆解入口，中间是带预览的仪器，右侧是有界案例档案库面板，下方是五阶段导航。五座等距固定三维门架对应五阶段流程，数量不随案例档案库增长。

桌面组合画布铺满视口，三维相机与 DOM 控件按视口重新构图；紧凑布局保留独立的手机和平板断点。`experience` 高度为 460svh，`stage` 为固定在视口的 100svh 区域，页面根元素与 body 使用 `overscroll-behavior: none` 关闭系统边界回弹，弹窗保留独立滚动。常规最小高度为 480px，手机为 560px；短横屏取消最小高度约束，将五阶段导航保留在视口内。

当前 CSS 的主要色值：

| 角色          | 值        |
| ------------- | --------- |
| 背景          | `#050912` |
| 主文字        | `#f3f6f2` |
| 次文字        | `#aebbc0` |
| 弱文字        | `#7f929b` |
| 结构线        | `#42505a` |
| 状态与焦点    | `#8bffb0` |
| Measured 图例 | `#f2544d` |
| Inferred 图例 | `#48d7d3` |

字体从本地加载：Oswald 用于主标题与站名，IBM Plex Mono 400 通过 CSS 别名 Plex 用于导航、数据和卡片文字，GallerySerif 使用 `GallerySerifSC-400.woff2`，按仓库说明对应 Noto Serif SC 子集，并以 Songti SC 和通用 serif 回退。许可路径见 [NOTICE](NOTICE)。

## 三维世界与渲染边界

运行时是本地 `vendor/three.min.js`，其 `REVISION` 为 160。一个 `WebGLRenderer` 渲染主光束线；程序另建环境烘焙和全屏后处理用的辅助 scene。

主世界包含挤出的倒角金属门架、实例化螺钉与轨枕、轨道、124 节输送带、滚轮、发射器、台车、纸面预览、玻璃和网格、三维准星、灯光及光束。金属使用 `MeshStandardMaterial`、程序生成的纹理及 PMREM 环境反射；场景有阴影和雾，HDR render target 经亮部提取、模糊与合成输出 bloom。环境贴图由程序里的照明面生成，主世界没有使用静态照片作建筑底板。

这里的实时「物理世界」指几何、基于物理的材质、光照、遮挡与射线求交。轨道运动是进度插值，没有质量、刚体、重力、摩擦或碰撞动力学求解。光束从发射器孔径指向准星，对预览背板和门架做射线求交后截断到首个不透明命中；该光学示意也不是完整光线追踪模拟。

预览使用当前选中案例档案库的 hero 图（按案例目录约定优先取 `screenshots/hero.jpg`，否则取 `assets/actual-hero.jpg`，失败时回退案例档案库封面），加载后绘入 CanvasTexture，并经灰度处理。右侧卡片先在首页选择案例，三维预览、标题、类型和 View teardown 入口同步更新；点击三维预览的射线拾取会触发当前拆解入口。键盘使用的 `#specimen-access` 是投影到预览中心的 DOM 链接；图像、网格和准星本体都在 Three.js 中。

## 五阶段运动

原生滚动距离归一化后只更新 `targetProgress`；站点链接把目标设为目的站，并应用 `navigation.maxSpeed` 限速。唯一的运动控制器维护 `progress` 与 `velocity`，在 `tick()` 中以秒为单位、用 `response = 38` 的临界阻尼解析式跟随目标，并处理方向反转和到站收敛。`setStage(progress)` 同时更新读数、导航状态和三维场景，行程中保留最近实际到达的工位，经过或抵达下一工位后才更新阶段文字，避免中点提前切章。原生滚动结束后保留输入位置，不自动回拉或归位；只有点击工位执行精确停靠，新输入可立即接管。场景按该进度插值，不再叠加另一条行程缓动；鼠标视差的独立阻尼不参与台车行程。

五个工位等距固定，停靠点直接由各门架的实际挤出几何中心生成，台车按这五个位置在 z 方向插值，总行程为 44 个世界单位。`travel = carriageZ - stops[0]` 同时驱动 124 节实例化输送带；节距为 0.62，带节循环回到轨道另一端。滚轮角度按 `travel / 0.23` 更新，反向行程会反转。相机使用相对预览的固定构图偏移跟随，校准停靠点后仍保持预览在画面中的位置；紧凑布局按 world scale 换算跟随距离。预览和输送带由同一位移推进，没有另一个独立计时动画。

预览角度、网格显隐、准星显隐、红青参考层间距及各门架灯光由同一进度决定。灰度预览在纹理生成时已处理，红青参考层是研究方法示意，不计算像素差。

桌面鼠标视差采用按帧间时间计算的阻尼；滚轮、触摸、指针按下或相关导航键可接管站点导航，后续滚动继续提供目标。页面不可见时取消待渲染帧；通常按状态变化请求渲染，只在鼠标视差尚未收敛时继续请求帧，没有持续空闲摆动。

## 一个归档面板

canonical `catalogue.js` 当前包含 **20** 项。初始 `featured.js` 固定顺序为 `shopify-editions,pear,shopify-editions-spring26,moonshot,comet,latrix`，每项由 canonical 全字段派生。生成与检查命令、数量同步的维护方式见 [README](README.md#维护案例档案库)。

`ensureCatalogue()` 通过动态 script 加载 `_gallery/catalogue.js`，缓存已加载数据和进行中的 Promise。打开 Archive 弹窗，或操作搜索、分类、排序、分页会触发加载；滚动到第五阶段只改变站点。失败会清理加载 Promise，并提供可重试错误状态。

`renderArchive()` 先用六项 featured 展示初始展览。完整目录加载后，Curated order 仍按 featured 的 slug 顺序取 canonical 中的六项，再追加 catalogue 中其余项目，保留其原序；元数据始终取自 canonical。默认第一页因此在初始加载、完整目录载入及面板展开之间保持一致。标题排序是单独选项，按标题字母顺序排列全部匹配项。

搜索覆盖标题、中文标题、简介、类型和类别，分类及搜索变化重置到第一页。`pageSize = 6`，只为当前页创建结果节点，页码最多五个；20 项无筛选时为 6、6、6、2 四页。首页长度固定，完整目录数据的下载量、内存和筛选计算仍随案例档案库增长。

原位 `#archive-panel` 与弹窗内的面板是同一个元素。打开时将它移入 `#archive-slot`，关闭时通过原位置的注释锚点放回；query、category、sort、page 都由同一控制器持有。使用原生 dialog，支持关闭按钮、对话框外点击、初始焦点与关闭后焦点回归。

桌面原位面板采用三列两行，平板原位面板与手机弹窗采用两列三行，每页最多六项。Latrix 与 EasyCode 的类型分别采用 canonical 的 `Web · Digital identity` 和 `Web · Learning product`，研究依据见 README 表格。

## 响应式、减弱动态与静态 fallback

| 条件                                            | 当前代码行为                                                                             |
| ----------------------------------------------- | ---------------------------------------------------------------------------------------- |
| 宽度超过 1200px 且宽高比至少 1.25               | 桌面等比构图，三维相机视角 32°，允许轻微鼠标视差。                                       |
| 宽度不超过 1200px 或宽高比低于 1.25             | 紧凑布局与相机，视角 38°，关闭鼠标视差；平板案例档案库以两列三行展示。                         |
| 紧凑布局且高度不超过 760px                      | 隐藏原位案例档案库，使用 Archive 弹窗。                                                        |
| 高度不超过 560px                                | 横屏重排标题、入口及五阶段导航，弹窗内滚动保留卡片完整尺寸。                               |
| 宽度不超过 600px                                | 手机相机视角 43°，隐藏原位案例档案库，通过 Archive 弹窗展示两列三行结果。                      |
| 减弱动态                                        | 关闭 CSS 动画和过渡，导航直接到站，三维进度按五阶段取整；按变化重绘，没有固定低帧率循环。  |
| 初始化失败、预览图像加载失败或 WebGL 上下文丢失 | 隐藏 canvas 与投影入口，显示可点击的 Latrix 静态封面；控制器可运行时仍可使用方法和案例档案库。 |
| JavaScript 完全禁用                             | 显示四个研究直链与外部仓库目录，不提供完整本地检索。                                     |

渲染分辨率设置桌面 1.7、紧凑布局 1.5 的像素比上限，并按约四百万绘图像素缩减；像素比另有 0.75 下限，因此任意视口下并非硬性像素预算。页面还提供可见焦点、搜索与筛选标签、当前站点状态、结果播报及更高对比度媒体查询。

WebGL 上下文恢复后重新生成环境贴图与绘图尺寸；丢失期间的窗口变化不会把隐藏画布的零尺寸写入渲染器。预览图片未完成时保持静态入口，完成后恢复场景。

## 软件渲染兼容

通过真实 WebGL renderer 名称识别 SwiftShader、llvmpipe 等软件后端。软件模式保留真实几何、纹理、五阶段移动与拾取，限制绘制预算为 196,608 像素，关闭多重采样、HDR 光晕、阴影和环境贴图预计算，使用漫反射材质并预编译着色器，降低逐像素开销。硬件模式保持原有构图、材质与后处理配置。此选择不依赖测试环境或 URL 开关；诊断记录 renderer 名称与实际 profile。
