# Formation：可直接交给其他 Agent 的复现提示词

请实现一页可运行的 Formation 摄影作品集，保持下述视觉与交互。独立编写状态、布局和动画控制，不读取旧案例 JavaScript，不以 iframe 嵌入旧页面。允许 GSAP 用于详情的有限时间线；连续运动由一个 requestAnimationFrame 管理。交付 index.html、布局模块、控制器、详情模块及说明。

## 素材与画面

使用本目录 works.json 中的 16 件作品，保持顺序、图片、标题、分类、客户、年份、介绍。图片 URL 相对本目录解析；素材文件可以从仓库取得，不替换成占位图。浅色背景由 #fafafa 到 #eef0f2；深色模式 #121215 到 #09090b。正文 Geist，标签 Geist Mono。左上 Selected Works，右上四个布局按钮 Flat / Tilt / Ring / Gallery；移动端按钮在底部中央。底部显示 Scroll to explore 与当前作品计数。卡片圆角 12px、照片 object-fit:cover、柔和投影。舞台透视 1700px、中心为原点，不能用普通平面轮播代替。

设视口 W×H，S=min(W,H)，small=S<640，portrait=H>W；卡宽 small 时 clamp(.27S,80,118)，其他 clamp(.155S,128,196)，高 round(1.34×卡宽)。16 张卡使用向量 [x,y,z,rz,scale,opacity]，x/y 相对于视口中心。

## 四种布局的完整几何规则

- Flat：基础 scale 为 small?.42:.62。椭圆中心 y=H×(portrait?.015:.045)。limit=min(.3W,.38H)，rx=min(limit,W/2−.6卡宽)，ry=min(limit,H/2−.6卡高)。竖屏改为圆，半径 min(W/2−卡宽×scale/2−.12×卡高×scale−22, H/2−卡高×scale/2−中心y−22)。卡片不是等角排列：沿椭圆取 2048 段；每点切线 atan2(ry cosθ,−rx sinθ)，占用宽度=卡宽×scale×|cos切线|+卡高×scale×|sin切线|。求共同间隙 gap，使 Σ(段弧长/(相邻占用宽均值+gap))=16；二分48次，范围 [−.85min(缩放宽,缩放高),2(rx+ry)]。累积该容量，在整数 0…15 处反解角度。slot=正模(i+.004browse,16)，在两相邻角度间插值，跨末尾补2π。x=rx cosθ，y=ry sinθ+中心y；z=0，rz=7sin(3.1i+1.2)，opacity=1。
- Tilt：间距=卡宽×(small?1.12:1.5)，x=居中取模((i−8)间距+browse,16间距)。R=W×(small?1.5:1.2)，q=min(|x|,.98R)。y=−.05H+R−sqrt(R²−q²)，z=0，rz=asin(clamp(x/R,−1,1))×180/π×.65，scale=small?.92:1.18，opacity=clamp((.5−|x|/W)/.13,0,1)。循环接缝在屏幕外完成。
- Ring：θ=i/16×2π+.0016browse，r=.38min(W,H)，u=sinθ×r×(portrait?1.04:1.46)，d=cosθ×r，v=d sin63°。把(u,v)旋转−21°得到(x,y)；z=d cos63°；rz=u/r×(small?3:6)；scale=(small?.36:.6)+(d/r+1)/2×(small?.19:.42)，opacity=1。
- Gallery：θ=i/16×2π+.0042browse，d=cosθ；x=sinθ×W×(small?.46:.43)，y=d×H×(small?.16:.14)，z=d×(small?95:150)，rz=0；scale=(small?.72:1.42)×((small?.5:.66)+(d+1)/2×(small?.5:.34))；opacity=1。

桌面可展开调参面板：size .55…1.6 步长.01 默认1；radius .6…1.6 步长.01 默认1；rotate −40…40 步长1 默认0；push 0…380 步长5 默认0；pushStr 0…160 步长2 默认0。Reset 恢复默认。屏宽<640隐藏控制面板。radius乘布局xyz，size乘scale，rotate控制舞台Z旋转。

## 状态与连续运动

切布局时保存每张卡当前姿态，browse与速度归零。每张延迟 i/15×220ms，持续680ms，cubic-in-out 插值到新布局；时间步首帧16ms，后续上限50ms。切换中暂停浏览惯性。正常状态每帧以.12追随目标；Tilt 新旧x差大于W时直接换位，不能横穿屏幕回卷。

拖动每次 dx×2 加入 browse，同时记为速度。松手每帧 browse+=速度，速度×.92，小于.02归零。滚轮取绝对值更大的轴×1.6加入browse，清零惯性。按下至松开移动<6px时打开按下的卡片（无则取当前悬停卡片）。拖动、变形、详情期间禁用悬停。

指针带来舞台微倾斜，目标X=(pointerY/H−.5)×6°，Y=(pointerX/W−.5)×6°，每帧.06追随；离开回零。悬停使用屏幕矩形命中，候选opacity≥.5时选z最大者，hover以.055追随0/1，接近0至.001则归零。显示卡的z增加30hover，scale乘(1+.06hover)，图片自身scale=1+.26hover。

push半径内施加径向排斥，距离d时强度=(1−d/push)²×pushStr，XY位移每帧.2追随。卡片transform为 translate3d(x+pushX−卡宽/2,y+pushY−卡高/2,z+30hover) rotateZ(rz) scale(scale×(1+.06hover))；位置/旋转保留2位，缩放3位，透明度3位；z-index=1000+round(z)。当前计数取悬停项，否则取 |x|+|y|−z 最小项。

## 详情快门时间线

选中作品使用全屏同一张图片object-fit:cover。黑色 #050505 遮罩；上下两片各高51%的快门从屏幕边缘闭合。白色文案left6vw,bottom8vh,max-width760px；标题800字重、clamp(2.6rem,6.4vw,5.4rem)、行高.97；分类11.52px等宽；介绍16.8px/1.6,max-width46ch；显示客户与年份。

打开：快门scaleY 0→1，.6s power2.inOut；.62s时显示图片与遮罩，图片scale1.4→1持续2.2s power2.out；.7s时快门1→0持续1s power3.out；1.1s暗角淡入.7s；1.45s关闭按钮淡入.5s；1.62s文案y26→0、opacity0→1持续.7s power3.out。

关闭：文案淡出.28s；.05s快门闭合.6s；.66s隐藏图片、遮罩、暗角、关闭按钮；.74s快门重新打开.95s，然后退出详情状态。关闭按钮、Escape、背景点击均有效；切换状态时防止重入、清理旧时间线。

## 验收

桌面1440×1000、手机390×844，字体和图片加载完成后，在受控时钟下比较四种布局、滚轮350、桌面size1.3；卡片位置、旋转、缩放、透明度应一致。打开一张作品，确认标题与选中照片一致，Escape正确回到画廊；无横向溢出、无控制台错误。检查拖动、主题、重置和快速连续切换。离开页面清理事件/动画，后台暂停渲染，返回后恢复。

当前实现已验证：上述两种视口四布局、滚轮和尺寸状态的卡片transform/opacity与冻结基线完全一致，详情打开与关闭通过。验证脚本：`rewrite/scripts/check-formation.mjs`；截图与报告在 `artifacts/rewrite-validation/formation/`。

## 本地图片与中英文（2026-09-21 更新）

本轮已接入本地公开图片和中英双语。复现时同时遵循 [共享规范](../../shared/README.md)：沿用当前本地图片路径，使用共享词典与语言偏好（`zh` / `en`），覆盖动态内容、辅助标签和 Canvas 文字；不要恢复旧的远程图片链接。中文拆字标题应先翻译再拆分，并保持原有动画机制。图片来源与替换映射在共享规范中列出。
