{
  "slug": "smear-multiples",
  "title": "Smear-frame afterimages",
  "tagline": "Afterimage smear — a card drags 4 crisp, countable clones while panning fast, merging into one on landing; an animated take on motion blur.",
  "description": "Afterimage smear — a card drags 4 crisp, countable clones while panning fast, merging into one on landing; an animated take on motion blur.",
  "category": "rhythm",
  "tags": [
    "shotcraft",
    "remotion",
    "rhythm",
    "effects"
  ],
  "tier": "free",
  "license": "Apache-2.0",
  "spec": {
    "width": 1920,
    "height": 1080,
    "fps": 30,
    "duration": 4.39,
    "aspect": "16:9"
  },
  "kind": "remotion",
  "params_schema": {
    "type": "object",
    "properties": {}
  },
  "default_params": {},
  "preview": {
    "poster": "https://gimgs.net/motion/media/smear-multiples/poster-21701175971f.jpg",
    "video": "https://gimgs.net/motion/media/smear-multiples/video-439fb947fa9b.mp4"
  },
  "variants": [
    {
      "key": "smear-multiples",
      "label": "smear-multiples",
      "description": "Afterimage smear — a card drags 4 crisp, countable semi-transparent clone copies while panning fast, merging into one on landing; an animated take on motion blur",
      "use": "",
      "video": "https://gimgs.net/motion/media/smear-multiples/video-439fb947fa9b.mp4",
      "poster": "https://gimgs.net/motion/media/smear-multiples/poster-21701175971f.jpg"
    }
  ],
  "credits": {
    "author": "video-shotcraft (Vincent Wei)",
    "url": "https://github.com/Vincentwei1021/video-shotcraft"
  },
  "page_url": "https://gimgs.net/motion/smear-multiples.html",
  "json_url": "https://gimgs.net/motion/smear-multiples.json",
  "template_url": "https://gimgs.net/motion/smear-multiples/template.html",
  "play_url": null,
  "markdown_url": "https://gimgs.net/motion/smear-multiples.md",
  "updated_at": "2026-09-24T07:40:22.283Z",
  "prompt": "## When to use\n\nFor fast-moving elements when you want a \"comic-strip sense of speed\" rather than a \"photographic blur\"; pick either this or CameraMotionBlur, not both\n\n## Intention\n\nThe library's standard answer for fast-motion speed is CameraMotionBlur (a photographic metaphor: shutter drag, continuous blur). This card gives a second answer, the anime smear-frame tradition: the afterimage is **discrete, crisp, and countable** — full copies. The viewer can count 4 cards and read it as \"so fast it left clones\" rather than \"so fast it blurred.\" The two have completely different temperaments: blur is live-action-grade texture, smears are comic-grade fun; pick one per move — stacking both reads as a render error. Smears also have a practical edge: content inside the afterimages stays legible, good for scenes where \"the thing that's moving is itself the information.\"\n\n## Duration & energy\n\n- Duration: Element-level technique (12f move + 8f converge-and-settle, riding on top of the move)\n- Energy: Medium-high\n\n## Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)\n\n## 意图\n快速位移的速度感库内标准答案是 CameraMotionBlur（摄影隐喻：快门拖影，\n连续的糊）。本卡给第二个答案，动漫演出的 smear frame 传统：残像是\n**离散、清晰、可数的**完整副本——观众能数出 4 张卡，读作\"快到留下\n分身\"而非\"快到糊掉\"。两者气质完全不同：blur 是实拍级质感，分身是\n漫画级趣味；同一次位移二选一，叠用读作渲染错误。分身式还有一个\n实用优势：残像里内容仍可辨，适合\"移动的东西本身是信息\"的场景。\n\n## 动效核心\n- 位置写成纯函数 `posAt(f)`（如 12f inOut cubic 到过冲点 + 6f 回弹）；\n  第 k 个分身直接求 `posAt(frame − k·2)`——同一条插值换帧号求值，\n  天然帧独立可算（disney 延迟采样拖拽层级的同一模式；模式已沉为\n  assets/lib/helpers/motion.ts velocityAt/lagged）\n- 分身 opacity 0.45/0.30/0.18/0.09 递减，是完整元素副本（不拉伸不变形）\n- 速度门限：`v = posAt(f) − posAt(f−1)`，v>25px/f 才渲染分身，\n  用 [25,60] 线性渐入避免分身瞬间跳出——低速段无残像是\"快才有分身\"\n  的语义完整性\n- 落位合拢：cv∈[0,1]（3f），分身延迟乘 (1−cv) 收缩到 0 + opacity 压零\n  ——分身们\"追上\"本体的一瞬即落位重音，配合 3% 过冲回弹\n\n## 参数表\n| 参数 | 典型值 | 调节手感 |\n|------|--------|----------|\n| 分身数/间隔 | 4 个 / 各差 2f | >5 个读作队伍；间隔 >3f 断成跳帧 |\n| 移动速度 | ~900px/12f（峰值 ~100px/f） | 慢移动不配分身（门限管住）；快过 3f/程分身来不及被看见 |\n| 合拢窗口 | 落位前 3f 内收干 | 分身残留到落位后读作重影故障 |\n| 收尾 | 落位回弹后真静止 ≥20f | R1 |\n\n## 已知坑\n- demo 在灰阶/占位素材上调校通过——参数是调校起点非实战定稿，\n  首次实战须以真实素材回验\n- 与 CameraMotionBlur 同一次位移**互斥**；同片不同镜头可以各用（一次\n  漫画式一次摄影式反而立体），但同类位移统一用一种（P4 一致性）\n- 分身是\"清晰完整副本\"——加 blur、拉伸、变形都会滑向另一个手法\n  （轴向拉伸在词汇表另案），保持可数是本卡的身份\n- 深底浅卡对比度下分身层次才读得开；同色系底上 0.09 那档会消失，\n  可减为 3 个分身重配 0.5/0.3/0.15\n\n## 参考实现\ndemos/rhythm/smear-multiples/\n（SmearMultiples.tsx）\n\n## Reference implementation (Remotion)\n\n- demos/rhythm/smear-multiples/SmearMultiples.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/rhythm/smear-multiples/SmearMultiples.tsx\n\nThe component imports shared fixtures from `demos/_fixtures` and helpers from `assets/lib` in the repo; SKILL.md there documents the render workflow.\n",
  "flow": [
    {
      "step": "Read the recipe",
      "note": "Prompt = when to use, intention, parameter table with typical values and how each one feels, known pitfalls. Treat values as calibrated starting points."
    },
    {
      "step": "Get the code",
      "tool": "git",
      "cmd": "git clone https://github.com/Vincentwei1021/video-shotcraft && cd video-shotcraft && npm install"
    },
    {
      "step": "Register + render",
      "tool": "remotion",
      "cmd": "npx remotion render <CompositionId> out.mp4   # component: demos/rhythm/smear-multiples/SmearMultiples.tsx"
    },
    {
      "step": "Or re-implement",
      "note": "Port the timing/easing from the recipe to HTML + WAAPI (gimgs motion contract) or any engine; keep the same segment windows and easing."
    }
  ],
  "files": [
    {
      "path": "demos/rhythm/smear-multiples/SmearMultiples.tsx",
      "url": "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/rhythm/smear-multiples/SmearMultiples.tsx"
    }
  ],
  "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.",
  "render": {
    "engine": "remotion",
    "frames": 132,
    "repo": "https://github.com/Vincentwei1021/video-shotcraft",
    "files": [
      "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/rhythm/smear-multiples/SmearMultiples.tsx"
    ],
    "note": "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."
  },
  "source": "// ===== demos/rhythm/smear-multiples/SmearMultiples.tsx =====\n// 残像分身（smear-multiples）——smear frame 多重残像。\n// 卡片高速横移时身后拖 4 个\"可数\"的半透明完整分身（各取当前帧减 k*2 帧\n// 时刻的位置，同一条插值函数换帧号求值，天然帧确定），与运动模糊的连续糊\n// 相区别。分身仅在本体速度 >25px/f 时可见（速度 = 相邻帧位置差）。\n// 关键帧：0–25 左槽 hold → 25–37 横移 900px（inOut cubic，带 3% 过冲）→\n// 35–38 分身延迟收缩至 0 合拢进本体 + opacity 归零 → 37–43 过冲回弹 → 43–130 全静止。\nimport React from 'react';\nimport { useCurrentFrame, interpolate, Easing } from 'remotion';\nimport { G, Card, TitleBlock } from '../../_fixtures/Fixtures';\n\nconst X0 = 240; // 左槽卡片左边缘\nconst X1 = 1140; // 右槽卡片左边缘（横移 900px）\nconst OVER = 27; // 3% 过冲\nconst Y = 380; // 卡片顶边（垂直居中 1080-320）\n\n// 本体位置：25–37 高速横移到过冲点，37–43 回弹落座，之后恒定 → 帧确定\nconst posAt = (f: number): number =>\n  f < 37\n    ? interpolate(f, [25, 37], [X0, X1 + OVER], {\n        extrapolateLeft: 'clamp',\n        extrapolateRight: 'clamp',\n        easing: Easing.inOut(Easing.cubic),\n      })\n    : interpolate(f, [37, 43], [X1 + OVER, X1], {\n        extrapolateLeft: 'clamp',\n        extrapolateRight: 'clamp',\n        easing: Easing.out(Easing.cubic),\n      });\n\nconst Slot: React.FC<{ x: number }> = ({ x }) => (\n  <div\n    style={{\n      position: 'absolute',\n      left: x - 20,\n      top: Y - 20,\n      width: 520,\n      height: 360,\n      border: `3px dashed ${G.bar}`,\n      borderRadius: 20,\n      boxSizing: 'border-box',\n    }}\n  />\n);\n\nexport const SmearMultiples: React.FC = () => {\n  const frame = useCurrentFrame();\n  const bodyX = posAt(frame);\n  // 本体速度 = 相邻帧位置差；>25px/f 才渲染分身\n  const speed = Math.abs(posAt(frame) - posAt(frame - 1));\n  const speedGate = interpolate(speed, [25, 60], [0, 1], {\n    extrapolateLeft: 'clamp',\n    extrapolateRight: 'clamp',\n  });\n  // 落位合拢：35–38 三帧内分身延迟收缩到 0（位置滑向本体）+ 不透明度归零\n  const cv = interpolate(frame, [35, 38], [0, 1], {\n    extrapolateLeft: 'clamp',\n    extrapolateRight: 'clamp',\n    easing: Easing.out(Easing.quad),\n  });\n  const convergeFade = frame >= 35 ? 1 - cv : 0;\n\n  const ghostOps = [0.45, 0.3, 0.18, 0.09];\n\n  return (\n    <div style={{ width: 1920, height: 1080, background: G.bg, position: 'relative', overflow: 'hidden' }}>\n      <div style={{ position: 'absolute', left: 120, top: 96 }}>\n        <TitleBlock text=\"SMEAR MULTIPLES\" size={54} />\n      </div>\n      <Slot x={X0} />\n      <Slot x={X1} />\n      {/* 4 个分身：第 k 个取 frame - k*2 帧时刻的位置；合拢期延迟×(1-cv) 收缩到 0 */}\n      {ghostOps.map((baseOp, i) => {\n        const k = i + 1;\n        const gx = posAt(frame - k * 2 * (1 - cv));\n        const op = baseOp * Math.max(speedGate, convergeFade);\n        if (op <= 0.001) return null;\n        return (\n          <div key={k} style={{ position: 'absolute', left: gx, top: Y, opacity: op }}>\n            <Card w={480} h={320} seed={5} />\n          </div>\n        );\n      })}\n      <div style={{ position: 'absolute', left: bodyX, top: Y }}>\n        <Card w={480} h={320} seed={5} />\n      </div>\n    </div>\n  );\n};\n\n\n"
}