# Drag Gallery · 独立复现提示词

以下提示词配合本目录 `products.json` 和指定图片使用；无需阅读原案例的实现代码。目标是精确复现本仓库冻结的 Drag Gallery。

---

用原生 HTML/CSS/JavaScript 与本地 GSAP 创建一页可甩动、弹簧吸附的运动鞋展示。以1440×1000和390×844为验收尺寸。分别组织参数、纯布局计算、运动状态、DOM呈现、输入和入场编排，不得通过 iframe 包装旧页面。

## 内容、素材和排版

- 附件 `products.json` 含3款鞋完整数据；按顺序循环填充8张卡，保留价格、原价、折扣、评分和评价数。图片根目录 `../../drag-gallery/`，对应 assets/shoe-1.png、shoe-2.png、shoe-3.png；图片cover，不能换图。
- 页面背景 #fafafa，字色 #14140f；橙色强调 #fb923c，折扣文字 #c2570b。中央背景径向淡橙：中心rgba(251,146,60,.10)，40%处.04，80%处背景色。
- 正文 Geist，标题 Playfair Display 500。全局行高1.5。页面min-height:100vh、flex纵向居中、小屏顶部padding96px，>=768px为112px，横向裁切。
- 顶部居中 `Running · Spring`，两侧40px细线及橙色小星；10px字距.22em。下面 `Wake the road.`，clamp(2rem,5vw,3.8rem)/1.05，字距-.02em，上间距16px。
- 描述逐字：`Eight silhouettes built for first miles, last splits, and everything in between. Foam that returns what you give it. Drag to find your pair.` 最大宽460px，13px/1.6，桌面14px。头部与轨道间距桌面56px、小屏40px。
- 卡下信息：Sneakers、星形评分、括号评价数；商品名桌面22px、小屏20px、Playfair/1.25；售价26px、原价12px删除线、折扣10px。下方 Add to bag 黑色胶囊及 View details 文字箭头，再下面 In stock绿点、Free shipping、30-day returns。按钮保留演示语义，不新增购买或详情弹窗。
- 信息距轨道桌面36px、小屏28px。最下面箭头及 Drag or swipe，距信息桌面56px、小屏40px、底部48px。

## 布局与空间公式

卡宽按视口分段：<480=180；<640=210；<768=240；<1024=260；其余280。高=宽×1.2，spacing=宽×.42。轨道高度=卡高+40；卡片均以轨道中心为原点，负半宽/半高margin。

令轨道 position 为浮点卡位，第 i 张相对 offset=i−position，循环折回[-4,4]附近。a=abs(offset)。每卡有独立入场标量 enter∈[0,1]：
- translateX=offset×spacing×enter；
- rotate=offset×5°×enter；
- targetScale=max(.4,1−.22a)，scale=.3+(targetScale−.3)×enter；
- 入场结束前 a>2 隐藏；结束后 a>3 隐藏；a>=2 的可见卡为幽灵框。
- 普通卡opacity=enter；幽灵opacity=max(0,1−(a−2))×enter。
- 普通z-index=round((3−a)×10)，幽灵为0。只有非幽灵且a<.6可命中。
- 普通照片遮暗alpha=min(.45,.225a)；橙色2.5px聚焦描边alpha=max(0,1−2.5a)。圆角24px。幽灵不显示照片、阴影和聚焦环，仅显示黑色40%的1px轮廓。
- 卡片阴影：0 8px 32px黑12%与0 2px 8px黑6%；内部有1px黑6%描边和底部柔暗。

额外画两个固定候补位，宽高为卡片的.56倍、圆角13.44px、黑色45%遮罩。位置±2×spacing，旋转±10°，z-index1。左边显示floor(position)−2，右边ceil(position)+2对应的循环商品。

## 运动与输入

集中维护 position、velocity、dragging。每个60Hz帧在未拖动时：
1. position+=velocity；velocity*=.92。
2. 若|velocity|<.15，则velocity=(velocity+.08×(round(position)−position))×.75。
3. 若|velocity|<.0005则归零，且距离整数<.01时position归整。

横拖每像素使position减少.004；最近一次位移乘.004后除以间隔毫秒再乘−16作为速度；松手velocity=估计速度×1.1。按下清零速度。移动总量|dx|+|dy|>8才锁方向，|dx|>1.2|dy|锁横向，竖向交给页面滚动。支持鼠标、触屏和pointercancel。

滚轮取绝对值较大的deltaX或deltaY，绝对值<=2忽略；其余阻止默认，position+=delta×.003，velocity=delta×.001。商品信息每帧跟随 round(position) 的模8结果，只在索引变化时换文字。

一个rAF拥有卡片持续变换和运动状态。入场动画仅改变enter和独立文字层，不能与rAF争写卡片transform。隐藏标签页暂停，销毁时清理。

## 入场时间轴

整体延迟.25秒。头部从opacity0、y24、scale.96、blur5px开始，按.1秒错峰，以.9秒power4.out到正常状态。

卡片最初enter0。中心卡从时间轴.3秒开始、.7秒展开；距中心r>=1的卡在.7+(r−1)×.07秒开始、.75秒展开；全用power4.out。左右候补位从opacity0/scale.3，在.77秒开始.75秒进入。信息从opacity0/y18/blur6px，在.7+.08×索引秒开始.85秒进入。整段时间轴完成后才启用a>=2的幽灵规则。

## 验收与禁止改动

对照首屏、入场中间帧、鼠标横拖、滚轮、释放后吸附以及手机竖向滚动。确认3款商品会循环出现，文字与焦点一致，幽灵框只在规定范围出现，候补位永不随轨道漂移。检查1440/390px无横向溢出和脚本错误。保留所有原文、图片、断点、层级和运动数值，不添加自动轮播、弹窗、额外导航或改配色。输出完整源码、截图和验证记录。

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

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