# 《鹈鹕测试》 The Pelican Test

> 一部约 **2:17** 的代码动画短片：一只鹈鹕骑着自行车，沿一条贯穿全片的路，依次穿过 20 个时代、
> 地域、艺术风格各异的版块；每过一道画框就换一种画风。全部画面由 JavaScript 逐帧画成
> ——没有一张外部图片、没有一帧外部视频、没有一段外部音频。

- 规格：1920×1080 · 120 BPM · 137s（2:17）· 60fps（30fps 对比版可另渲）
- 技术栈：p5.js 2.x（P2D）+ p5.brush 2.x（可选，离屏 WEBGL）+ Puppeteer 逐帧 + ffmpeg + Web Audio
- 每个画面都是纯函数 `renderAt(t)`：可实时拖动预览，也可逐帧导出成片

## 现在做到哪了（阶段状态）

| 阶段 | 内容 | 状态 |
|---|---|---|
| 1 骨架 | 工具包 / 节拍 / 木偶 / 路面 / 相机 / Intro 字幕 / 20 个占位版块 / Outro 拉远 / 逐帧导出与接触表 | ✅ 已完成（无声版灰模已出片） |
| 2 精做 3 格 | 撒哈拉岩画、宋代山水、竖屏短视频 | ⬜ 未开始 |
| 3 其余 17 格 | 美术简报 + 子代理 4–5 格一批并行 | ⬜ 未开始 |
| 4 音乐 | 20 套乐器 + 共用主旋律，实时版与离线版对拍 | ⬜ 未开始 |
| 5 打磨出片 | 转场细化、HUD、调色、混音、成片 | ⬜ 未开始 |

## 快速开始

```bash
npm install                      # p5 / p5.brush / puppeteer-core
bash tools/fetch-fonts.sh        # 下载 Noto Serif/Sans SC（OFL-1.1）；网络不稳加 --proxy http://127.0.0.1:7890
npm run preview                  # http://127.0.0.1:5173/ —— 播放条 / 拖动 / 当前版块名
```

逐帧导出与检查：

```bash
npm run shot                     # 单帧静帧 → out/shot.png
npm run sheet                    # 接触表（一段时间的 12 帧拼图）→ out/sheet_scene01.png
npm run thumbs                   # 给 Outro 展墙烤 20 张缩略图 → public/thumbs/
npm run render                   # 全片 60fps 渲染到 frames/（10 个页面并行，约 90 秒 / 8220 帧）
npm run compare                  # 同一段 30fps vs 60fps 对比 + 上下对照 mp4
```

合成成片（骨架期无音轨）：

```bash
ffmpeg -y -framerate 60 -i frames/grey60/f_%06d.jpg -c:v libx264 -pix_fmt yuv420p \
       -crf 20 -movflags +faststart out/greybox_60fps.mp4
```

## 结构

```
public/index.html          预览页（播放条 + 帧渲染模式 ?render=1）
public/fonts/              Noto Serif/Sans SC（OFL-1.1，tools/fetch-fonts.sh 下载）
public/vendor/             p5.min.js（LGPL-2.1）、p5.brush.js（MIT）
src/beat/timeline.js       节拍与时间轴：段落表、转场窗口、脚踏相位、量化
src/kit/index.js           坐标/相机/颜色/文字/噪声/暗角 等共用工具
src/road/index.js          那条路：GROUND_Y、SPEED、视差、虚线相位、推近、定格
src/rig/index.js           鹈鹕+自行车的参数化骨骼木偶（pose / silhouette / drawRig）
src/scenes/meta.js         20 个版块元信息（中文名/英文名/年代/色板）
src/scenes/intro.js        开场纸张 + 纪录片字幕
src/scenes/placeholder.js  骨架期的占位版块（阶段 2/3 会被真美术替换）
src/scenes/outro.js        7×3 展墙 + 第 21 格空席位新闻发布会
src/main/index.js          p5 实例、调度、穿画框转场、标题卡、预览播放器
tools/                     render / shot / sheet / bake-thumbs / compare-fps / fetch-fonts
briefs/STYLE.md            20 个版块共用的美术契约（先读这个再写场景）
```

## 时间表

```
Intro       0.0 –   5.0s   2.5 小节   字幕落强拍，鹈鹕骑入第 1 版块
Scene k     5+6(k-1) – 5+6k           各 3 小节：进场 → 梗/高光（可定格）→ 骑向下一道画框
Outro     125.0 – 137.0s   6 小节     展墙 → 推第 21 格 → 空椅子 → 车铃定格
```

20 个版块：撒哈拉岩画 · 埃及壁画 · 汉画像石拓片 · 唐代白描 · 宋代山水 · 清明上河图 · 玛雅抄本 ·
莫卧儿细密画 · 八大山人写意 · 爪哇皮影戏 · 浮世绘 · 星月夜 · 呐喊 · 诺斯费拉图 · 示波器矢量图 ·
8-bit 像素游戏 · 早期聊天窗口 · 蒸汽波 · 竖屏短视频 · 代码美学。

## 许可

- 代码：待定（尚未选择开源许可）。
- 影片、封面、渲染帧、音频：作者保留所有权利。
- 第三方组件与字体：见 `THIRD_PARTY_NOTICES.md`。
