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

请独立实现 Riffle：22张方形商品卡在滚动中经过 Fanned arch / Collapse / Cascade / Pinwheel / Tumble / Coverflow 六种阵型。允许GSAP做详情淡入，布局、输入、渲染需自行实现；不加载旧案例JS，不用iframe。按数据、纯布局函数、交互状态、渲染循环、详情控制拆模块。

## 数据与静态画面

读取本目录 items.json，按顺序保留22件商品的title、artist、description、image、price、specs。图片URL相对本目录；全部使用仓库对应照片，不能替换。全屏、禁止浏览器滚动、stage touch-action:none；背景radial-gradient(80% 70% at 50% 12%,#f4f5f8,#e6e8ef 45%,#d3d7e2)。正文Geist、辅助Geist Mono、详情标题Playfair Display。左上32px/28px，12px/1.5等宽、字距.32em的RIFFLE；下一行9px的♪ THE 2026 LIBRARY。底部26px中央10px等宽SCROLL、字距.2em、opacity.4，其下1×28px竖线。进度与阶段名称在DOM更新但视觉隐藏。

deck定位left50%,top calc(50% + 34px)，perspective1400px、preserve-3d。方卡宽C：W<700为clamp(.3W,104,150)，其他clamp(.2min(W,H),92,188)。margin-left/top=−C/2，圆角10px。图片object-fit:cover，filter saturate(.9) contrast(1.06) brightness(.97)。阴影0 2px 5px #00073、0 30px 60px −16px #000a8、内高光0 1px 0 #ffffff24。gloss覆盖inset−20% −40%，100°白色渐变带。

定义N=22，i=0…21，t=i/21，mix(a,b,t)=a+(b−a)t，随机h(n)=fract(43758.5453sin(12.9898n+78.233))。每姿态为[x,y,z,rx,ry,rz,s,o]。

## 六个姿态

1. Fanned arch：θ=mix(228,−48,t)°，R=.33min(W,H)，narrow=W<900，shrink=narrow?.8:1，margin=C×shrink×.56；x=cosθ×min(1.18R,(W/2−margin−16)/1.06)，y=−sinθ×R，z=mix(120,−150,t)，rx0，ry=mix(8,−8,t)，rz=mix(−16,16,t)，s=mix(shrink,narrow?.42:.46,t)，o1。
2. Collapse：x=.04W+(h(i)−.5)10，y=.03H+(h(i+9)−.5)10，z=−1.4i，rx/ry0，rz=(h(i+3)−.5)6，s=i0?.78:.72，o1。
3. Cascade：x=.2W−iW×.04，y=.18H−iH×.044，z=−42i，rx8，ry−16，rz−4，s=mix(1,.74,t)，o=i<12?1:mix(1,.4,(i−12)/9)。
4. Pinwheel：R=min(W,H)×(W<700?.42:.37)，θ=360i/22°；x=Rcosθ,y=Rsinθ,z0,rx/ry0,rz=θ+90,s=W<700?.34:.5,o1。
5. Tumble：W<900时排四列；rows=ceil(22/4)，row=floor(i/4)，inRow=min(4,22−4row)，pad=.06W，top=34+.05H，bottom=.05H，cell=min((W−2pad)/4,(H−top−bottom)/rows)。x=(i mod4−(inRow−1)/2)cell，y=(top−bottom)/2+(row−(rows−1)/2)cell，z/rx/ry0，rz=偶数i?2.2:−2.2，s=.82cell/C，o1。
   W≥900时使用球面投影与避让：R=.38min(W,H)，k=i+.5，φ=acos(1−2k/22)，θ=π(1+sqrt5)k，front=sinφsinθ，z=frontR，p=1400/(1400−z)，screenX=sinφcosθ×R×1.6p，screenY=cosφ×Rp，size=.8Cp。最多300轮同步松弛：每对a,b，need=(sizeA+sizeB)/2×1.06，overX=need−|dx|，overY=need−|dy|；二者正时沿重叠较少轴分别给两点施加±over/2，正负依dx/dy方向。整轮累计后各点移动累计量×.5。边界half=.8C×1.12/2，limitX=W/2−half−16，limitY=H/2−34−half−16，移动后clamp到边界。无重叠提前退出。最终x=screenX/p,y=screenY/p,z不变，rx/ry/rz0,s.8,o=front≥0?1:mix(1,.66,−front)。只在尺寸变化时重新求解。
6. Coverflow：rel=i−offset，a=|rel|；x=rel×(W<700?.62W:2.28C)，y0,z=−140a，rx/rz0,ry=clamp(−26rel,−54,54)。s=W<700?max(.5,2.3−.85a):max(.6,2−.25a)；o=a>3?0:a≤1?1:clamp(1−(a−1)×.5)。

## 滚动变形与输入

progress和target初始0，每帧progress+=(target−progress)×.09。progress<.8时segment=clamp(floor(progress/.16),0,4)，local=clamp((progress−.16segment)/.16)，q=clamp((local−.12)/.76)，eased=q³(q(6q−15)+10)，v=clamp(1.22eased−i/21×.22)，weight=cubicInOut(v)，然后在segment与segment+1的八个姿态分量之间线性插值。后一姿态若Coverflow，offset固定0；progress≥.8后才用实时offset。

垂直滚轮target+=deltaY×.00055并clamp0…1；如果target≥.8且|deltaX|>|deltaY|，改为velocity+=deltaX×.0025。方向键右/下target+=.16，左/上−=.16。拖动记录每事件dx及总|dx|：progress≥.78时offset−=dx×.012，velocity=−dx×.012；更早时target−=dx×.0006。松手不拖动时每帧offset+=velocity，velocity*=.9；progress≥.78且|velocity|<.02则velocity+=(round(offset)−offset)×.12，再velocity*=.7；offset限制[−1,22]。移动总量<6px的松手点击命中卡，打开详情。

悬停以elementFromPoint取得卡序号，拖动或详情时清除；progress≥.78时被悬停卡scale×1.06。卡transform按 translate3d→rotateX→rotateY→rotateZ→scale；位置旋转2位，scale/opacity3位，z-index=round(2000+z)。gloss横向translateX=42×clamp(ry/54,−1,1)%保留1位，opacity=.08+.26|该比例|保留3位。

progress≥.78时底部12%中央显示round(offset)夹至0…21的商品title（20px/500）和artist（10px等宽、.22em）；更早opacity0。隐藏的stageName和progress同步更新为最邻近阵型，progress≥.8则第6项。

## 商品详情

全屏黑底#101010、z200；商品图铺满object-fit:cover，底部渐变黑色遮罩0%黑实、16%黑.73、40%黑.2、64%透明。文案left48px,bottom56px,width min(720px,65vw)；类别10px等宽、.24em；标题Playfair400 clamp(40px,7.2vw,104px)/.95、字距−.035em；介绍14px/1.6,max540；三列规格max480，顶部细线；价格固定right48,bottom56。手机≤767文案left24,bottom28,width calc(100%−48px),maxheight75%,overflowauto；标题48px、介绍12px、规格11px，价格改为普通文档流。右上24px处44px圆形关闭按钮。

打开：scrim opacity0→1 .3s；shot scale.86,opacity0,rotateY18→1/1/0，.7s power3.out；copy子元素opacity0,y16→1/0，delay.15,duration.5,stagger.06,power3.out。关闭/Escape：panel opacity0,scale.97，.25s power2.in；.04s背景淡出.28s；结束恢复panel并关闭。详情期间禁止改变滚动目标与拖动。

## 验收

桌面1440×1000和手机390×844，初始阵型、每按一次右键并等待3200ms的六阵型、末段横滚300的姿态与商品标题应一致；检查中间进度卡片逐张变形，无NaN或错序。点击前景商品，内容匹配，Escape返回、无溢出和控制台异常。提供截图与受控时钟检查。事件用可清理的生命周期，后台暂停、恢复后继续。

当前实现两种视口的六阵型、末段浏览与详情的transform/opacity/gloss均通过冻结基线精确对照。验证：`rewrite/scripts/check-riffle.mjs`；报告/截图：`artifacts/rewrite-validation/riffle/`。

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

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