# Research card stack scroll

Dark paper cards fly in every 12 frames along a bottom-right axis to stack up, only the topmost fully rendered while the rest blur and dim.

- Category: ui-entrance · Tags: shotcraft, remotion, ui-entrance
- Spec: 1920×1080 @ 30 fps · 5.3s (16:9)
- License: Apache-2.0 · Tier: free
- JSON: https://gimgs.net/motion/research-card-stack-scroll.json
- Kind: remotion
- Source (TSX): https://gimgs.net/motion/research-card-stack-scroll/template.html
- Repo: https://github.com/Vincentwei1021/video-shotcraft
- Credits: video-shotcraft (Vincent Wei) — https://github.com/Vincentwei1021/video-shotcraft
- Page: https://gimgs.net/motion/research-card-stack-scroll.html

## Params

_No params._

Default params (base64url for `?p=`): `e30`

## Prompt

## When to use

Conveying the sheer scale of "reading a huge volume of material/processing a mass of documents"; a capability shot for research, retrieval, or batch-processing products

## Intention

The point being made is "quantity," but dumping 13 cards on screen at once reads as a wall. Turn it into a pipeline instead: cards come in one at a time, each one genuinely gets read (the top card is always the one rendered in full), then sinks into the stack and blurs as the next one arrives. What the viewer feels is continuous, ongoing throughput, not a static pile. The background grid moving down at the same speed is the speed reference — without it, the pile would just read as "stuck in place and shrinking."

## Duration & energy

- Duration: About 4.8s (144f@30fps)
- Energy: Medium-high (constant high frequency, no burst but sustained pressure)

## Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)

## 意图
要说的是"数量"，但一次给 13 张卡会读成一堵墙。改成流水线：卡一张一张进，每张都被
读过（最上一张永远是全文渲染的那张），读完就沉进堆里变模糊。观众感受到的是持续不断
的吞吐量，而不是一个静态的堆。背景 grid 同速下移是速度参照——没有它，堆积会读作
"卡在原地缩小"。

## 动效核心
- 时间轴用真实帧号而非归一化 t：内部 `F=144`，每张卡的本地时间 `e = t*144 - i*12`，
  一切编排（入场、堆积、深度）都以 `PER=12` 帧为节拍单位写死
- 入场是 6 帧短促动作：`seg(clamp((e+6)/6), 0, 1, E.outCubic)`——注意起点是 `e=-6`，
  即卡在自己的节拍到达前 6 帧就开始飞，`translateY(-40→0)` + `scale(0.94→1)`
- 落位 squash：`e ∈ [0, 1.6)` 时 y 轴 scale 额外乘 0.97，只压 1.6 帧——短到读不出是
  变形，只读作"砸实了"
- 堆积漂移：落位后 `drift = e/12*30`，每个节拍向下 30px、向右 `XOFF=9`px，形成微微
  向右下的轴线；轴线的存在让 13 张卡不是同心叠放而是有厚度的一叠
- 深度衰减：`depth = min(1, drift/(30*3))`——三个节拍内衰减到底，`blur(depth*4)` +
  `brightness(1-depth*0.25)`；再往下 `(drift-30*3.2)/(30*1.6)` 把 opacity 拉到 0 回收
- 焦点唯一：`focus = floor(f/12)`，只有 `i === focus` 的卡显示 body（作者行 + 4 条摘要
  骨架），其余卡的 body 直接 `opacity:0` 只留标题——"正在读的那一张"永远只有一张
- 背景 grid：`translateY((f/12*30*S) % 24)`，位移量与卡的 drift 用同一个 `GAP=30`
  推导，所以 grid 与卡堆严格同速；对 24px 取模让它无缝循环

## 参数表
| 参数 | 典型值 | 调节手感 |
|------|--------|----------|
| 节拍 | PER=12 帧/张，13 张 | 12f 是"紧但看得清"的下限；<8f 标题来不及读，>20f 量级感垮掉变成逐张展示 |
| 入场行程 | 6 帧（outCubic），提前量 -6 帧 | 行程只有节拍的一半 → 每张在下一张来之前已经落定；行程 ≥ PER 时会有两张同时在飞 |
| 入场位移/缩放 | `translateY(-40→0)`、`scale 0.94→1` | 40px 相对 96px 卡高是小幅——卡是"落进去"不是"飞进来"；缩放差只有 0.06，再大就读作弹窗 |
| 落位压缩 | 1.6 帧，y 轴 ×0.97 | 3% 是刚好能感知的量；>6% 或时长 >3f 会看出橡皮变形 |
| 堆积轴线 | 每节拍 y+30px、x+9px | 9/30 的比值决定轴线斜度；x 归零会变成正下方同心叠压，厚度感消失 |
| 深度衰减 | `depth = drift/90`，blur 0→4px、brightness 1→0.75 | 90px（3 个节拍）内衰减完 → 画面里始终只有约 3 张是"半清晰"的；衰减距离拉长会让下方糊卡堆太厚，画面变脏 |
| 回收窗 | `drift > 96px` 起淡出，48px 内到 0 | 回收太早会看到卡在画面中央消失；太晚 13 张全在场，DOM 与 blur 开销都上去 |
| 内容坐标系 | 逻辑 420×250，整体 `scale(min(W/420, H/250))` | 所有像素值写在逻辑坐标系里，改画布尺寸不用重排；卡 296×96、字号 9.5px 都是逻辑值 |

## 已知坑
- 卡数与节拍是绑定的：`13 张 × 12 帧 = 156 帧 > F=144`，末两张在 t=1 时仍在入场途中，
  末帧不是干净的静态。要做定格结尾，把卡数压到 `F/PER - 1` 以内（12 帧节拍下 ≤11 张）
- `focus = floor(f/12)` 会超出卡数上界（f=144 时 focus=12，正好是最后一张）——加卡数
  或改节拍后要确认 focus 不会长期指向不存在的索引，否则出现"没有任何一张是清晰的"
- 全部时间常量都写死在 144 帧的假设上（`F=144`, `fr=f/F`）。改时长必须同时改 F，
  否则节拍会随时长伸缩，12 帧的紧凑感丢失
- 标题是 13 条真实感的论文标题占位、`preprint:24xx` 编号由索引生成，落地要换成项目
  真实文档标题；`rand(i*5+k)` 生成的摘要骨架条宽度是确定性伪随机，不要换成 Math.random
- 深色卡（`INK` 底 + `#2A2A2A` 描边）压在 `#FAFAFA` 浅底上是这套对比度的前提；卡色
  改浅后 `brightness(0.75)` 的深度衰减几乎看不出来，需要改用 opacity 或灰度衰减

## 参考实现
demos/ui-entrance/research-card-stack-scroll/
（ResearchCardStackScroll.tsx）

## Reference implementation (Remotion)

- demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx

The component imports shared fixtures from `demos/_fixtures` and helpers from `assets/lib` in the repo; SKILL.md there documents the render workflow.


## Flow

1. **Read the recipe**
   Prompt = when to use, intention, parameter table with typical values and how each one feels, known pitfalls. Treat values as calibrated starting points.
2. **Get the code** — tool: git
   `git clone https://github.com/Vincentwei1021/video-shotcraft && cd video-shotcraft && npm install`
3. **Register + render** — tool: remotion
   `npx remotion render <CompositionId> out.mp4   # component: demos/ui-entrance/research-card-stack-scroll/ResearchCardStackScroll.tsx`
4. **Or re-implement**
   Port the timing/easing from the recipe to HTML + WAAPI (gimgs motion contract) or any engine; keep the same segment windows and easing.

## Render

Clone https://github.com/Vincentwei1021/video-shotcraft (npm install). The component lives under demos/{category}/{name}/ and imports shared fixtures from demos/_fixtures and helpers from assets/lib. Copy it (with those imports) into a Remotion project, register a <Composition> with the template's width/height/fps/duration in Root.tsx, then `npx remotion render <CompositionId> out.mp4`. SKILL.md in the repo documents the full Claude Code / Codex workflow. The prompt below is the shot recipe (timing, easing, parameter table, pitfalls) — enough to re-implement the shot in HTML/WAAPI or another engine if you prefer.

## Contract

React/Remotion composition (TSX) from the open-source video-shotcraft library (Apache-2.0). It is not a browser-playable template: clone the repo, register the component in a Remotion project and render with `npx remotion render`. The recipe (prompt) describes timing, easing and parameters so you can also re-implement the shot in any engine.
