{
  "slug": "riso-print-hits",
  "title": "Riso print hits",
  "tagline": "Two Riso-print misregistration hits: a single split-and-snap impact, and a rhythmic version that compounds beat by beat.",
  "description": "Two Riso-print misregistration hits: a single split-and-snap impact, and a rhythmic version that compounds beat by beat.",
  "category": "effects",
  "tags": [
    "shotcraft",
    "remotion",
    "effects",
    "typography",
    "rhythm"
  ],
  "tier": "free",
  "license": "Apache-2.0",
  "spec": {
    "width": 1920,
    "height": 1080,
    "fps": 30,
    "duration": 4.05,
    "aspect": "16:9"
  },
  "kind": "remotion",
  "params_schema": {
    "type": "object",
    "properties": {}
  },
  "default_params": {},
  "preview": {
    "poster": "https://gimgs.net/motion/media/riso-print-hits/poster-4a32bea21826.jpg",
    "video": "https://gimgs.net/motion/media/riso-print-hits/video-b6722f7672c7.mp4"
  },
  "variants": [
    {
      "key": "misregistration-hit",
      "label": "misregistration-hit · Single hit",
      "description": "The title slams in and freezes over 8f, splitting into two plates offset ~32px in opposite directions, decaying and oscillating for 44f before a hard cut snaps them into register with a scale pulse.",
      "use": "A stamp-of-impact used 1-2 times in the whole film; the landing instant for a title/large text",
      "video": "https://gimgs.net/motion/media/riso-print-hits/video-b6722f7672c7.mp4",
      "poster": "https://gimgs.net/motion/media/riso-print-hits/poster-4a32bea21826.jpg"
    },
    {
      "key": "beat-pump",
      "label": "beat-pump · Rhythm pump",
      "description": "One beat every 24f: the whole frame snap-jumps to 1.08 scale with an exponential fall-back, plus the title's plate misregistration compounding beat by beat at 8/14/22/32px before snapping into register.",
      "use": "A music beat-hit section; a build-up of repeated hits that \"gets harder every time\"",
      "video": "https://gimgs.net/motion/media/riso-print-hits/video-e0780245dd9a.mp4",
      "poster": "https://gimgs.net/motion/media/riso-print-hits/poster-beat-pump-fd508a66e862.jpg"
    }
  ],
  "credits": {
    "author": "video-shotcraft (Vincent Wei)",
    "url": "https://github.com/Vincentwei1021/video-shotcraft"
  },
  "page_url": "https://gimgs.net/motion/riso-print-hits.html",
  "json_url": "https://gimgs.net/motion/riso-print-hits.json",
  "template_url": "https://gimgs.net/motion/riso-print-hits/template.html",
  "play_url": null,
  "markdown_url": "https://gimgs.net/motion/riso-print-hits.md",
  "updated_at": "2026-09-24T07:40:18.317Z",
  "prompt": "## When to use\n\nHit emphasis for titles/cards, a paper-and-ink take on the \"glitch flash\"; A for a single climax hit, B for repeated hits in a rhythm section\n\n## Intention\n\nRGB chromatic-aberration glitch (part of impact-feedback style C) is a screen-native language that clashes with a paper-and-ink tonality. These two styles are the print-based equivalent: the element splits into light-gray and dark-ink single-color print plates (a multiply ink feel rather than a screen glow feel), like a risograph print that's out of register, shaking a few times before snapping \"clack\" into register — the same impact, but with the medium fully swapped to ink on paper. A is a single hit: the impact freezes and splits the plates, the shake decays, then a hard cut snaps them into register, stamping one hit; B is its rhythmic form: every beat the whole frame jumps 8% and the title splits its plates, the misregistration compounding with each beat — getting harder every time, a visual bass drum for a beat-driven section. Same technical root (decaying-oscillation two-plate misregistration), choose single-hit or repeated-hit.\n\n## Duration & energy\n\n- Duration: A 4s (single hit); B 4.7s (four beats)\n- Energy: High\n\n## Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)\n\n## 意图\nRGB 色散故障闪（impact-feedback C 式的一部分）是荧光屏语言，与纸墨\n调性相克。这两式给出印刷版平替：元素裂成浅灰/深墨两份单色印版\n（multiply 油墨感而非 screen 荧光感），像 risograph 没对准版，抖几下\n\"啪\"地套准——同样的冲击力，介质想象完全换成纸上油墨。A 是单发：\n撞停瞬间裂版、震荡衰减、硬切套准，给一次命中盖章；B 是它的节奏化：\n每个鼓点整画面跳大 8% + 标题裂版，错位逐拍加码，越打越狠——\n卡点段的视觉低音鼓。同技术根（衰减震荡的双版错位），单发/连打二选一。\n\n## 两式选型\n| 式 | 做法 | 适用 |\n|----|------|------|\n| A misregistration-hit 单发 | 标题 8f 撞入撞停，裂两版反向错 ~32px，44f 衰减震荡后硬切套准 + scale 脉冲 | 全片 1–2 次的命中盖章；标题/大字的到位一瞬 |\n| B beat-pump 节拍泵 | 每 24f 一拍：整画面瞬跳 1.08 指数回落 + 标题错版逐拍 8/14/22/32px 加码套准 | 音乐卡点段；\"越打越狠\"的蓄力连打 |\n\n## 参数表\n| 参数 | 典型值 | 调节手感 |\n|------|--------|----------|\n| 双版 | 浅灰版（G.mid）+ 深墨版（G.ink），`mix-blend-mode: multiply`，位移反向 | multiply 叠出的重影灰阶就是\"油墨没对准\"；screen 叠加立刻变荧光故障 |\n| A 错位包络 | `offset = A·cos(2πt/18)·exp(-t/60)`，A=(16,7)px 两版反向；帧 72 硬切归零 | 命门：套准是**硬切跳变**不是渐收——衰减到 ~14px 残余时啪地归零才有\"啪\"；纯渐收读不出套准一拍 |\n| A 撞入 | 8f Easing.in(cubic) 从画外撞停，命中帧即裂版 | 裂版必须与撞停同帧——晚 2f 就读作两件事 |\n| A 套准脉冲 | 归零帧 4f scale 1.03→1 | 盖章的一拍；省略则套准无重量 |\n| B 泵 | `scale = 1 + 0.08·exp(-t/3)`（t=0 即满值、一帧到位无渐入），14f 窗口外精确归 1 | 瞬跳是\"顿推\"本体——加渐入就成了普通 zoom 呼吸 |\n| B 错版加码 | AMP 逐拍 4/7/11/16px（单版，双版反向即总分离 8/14/22/32px），`AMP·cos(2πt/6)·exp(-t/3)` 12f 窗口 | 逐次加码是命门（同 hit-counter 判例）：四拍一样大读不出\"越打越狠\" |\n| B 作用域 | scale 作用整画面容器，错版只作用标题 | 整画面全裂读作故障而非印刷 |\n| B 节拍参照物 | 底部节拍刻度点，命中闪深常驻 | 静音预览环境的节拍可读性 |\n| 收尾 | A 套准后 ≥40f / B 末拍归零后 ≥20f 真静止 | R1 |\n\n## 已知坑\n- demo 在灰阶/占位素材上调校通过——参数是调校起点非实战定稿，\n  首次实战须以真实素材回验\n- **错位幅度可感性判例（本批实渲）**：词汇表原案 ±5px 在 1920 宽画面\n  正常速度下肉眼几乎不可见——单版 16px/总分离 32px 起步才可感；\n  幅度存疑时做极端版给用户看（可感性优先）\n- 两式与 impact-feedback C（负片冲击帧）语义重叠——纸墨调性片子用本卡、\n  游戏/动漫调性用 C 式，同片不并用（P4）\n- B 式是声音强依赖：命中帧必须钉鼓点（sound-design §4.5）；无音轨\n  段落读作画面抽搐\n- A 式错位方向一横一纵混合（x 为主 y 少量）更像没对准版；纯横向读作\n  左右晃动\n- B 式四拍后必须接足量 hold（≥24f）——连打完不还呼吸，观众的耳朵还\n  在等第五拍\n\n## 参考实现\ndemos/effects/riso-print-hits/\n（RisoBeatPump.tsx / RisoMisregistrationHit.tsx）\n\n## Reference implementation (Remotion)\n\n- demos/effects/riso-print-hits/RisoBeatPump.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/effects/riso-print-hits/RisoBeatPump.tsx\n- demos/effects/riso-print-hits/RisoMisregistrationHit.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/effects/riso-print-hits/RisoMisregistrationHit.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/effects/riso-print-hits/RisoBeatPump.tsx, demos/effects/riso-print-hits/RisoMisregistrationHit.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/effects/riso-print-hits/RisoBeatPump.tsx",
      "url": "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/effects/riso-print-hits/RisoBeatPump.tsx"
    },
    {
      "path": "demos/effects/riso-print-hits/RisoMisregistrationHit.tsx",
      "url": "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/effects/riso-print-hits/RisoMisregistrationHit.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": 122,
    "repo": "https://github.com/Vincentwei1021/video-shotcraft",
    "files": [
      "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/effects/riso-print-hits/RisoBeatPump.tsx",
      "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/effects/riso-print-hits/RisoMisregistrationHit.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/effects/riso-print-hits/RisoBeatPump.tsx =====\n// 套印节拍泵（riso-beat-pump）——beat-punch-in（卡点顿推）× riso-misregistration-hit\n// （套印错位）的组合节奏。节拍帧 [30,54,78,102]（每 24f 一拍），每命中帧：\n// ① 整画面 scale 一帧瞬跳 1.08（无渐入），14f 内按 exp(-t/3) 指数衰减回 1；\n// ② 标题裂成 G.mid/G.ink 双色印版 multiply 错位，初始错位逐拍加码 4/7/11/16px\n//    （每版反向 → 总分离 8/14/22/32px），12f 衰减余弦震荡收敛套准；\n// ③ 底部对应节拍刻度点闪深并常驻。结构：0–29f hold；30–115f 四拍；116–139f 真静止。\nimport React from 'react';\nimport { useCurrentFrame } from 'remotion';\nimport { G, Card, TitleBlock } from '../../_fixtures/Fixtures';\n\nconst HITS = [30, 54, 78, 102]; // 节拍命中帧\nconst AMP = [4, 7, 11, 16]; // 每拍单版初始错位（px），逐拍加码\nconst PUMP_WIN = 14; // scale 泵窗口：14f 后精确归 1（保证结尾真静止）\nconst SPLIT_WIN = 12; // 错位窗口：12f 后精确归 0（余量 <0.4px，硬切套准）\n\n// 与 TitleBlock 同字形的单色印版（错位需要可调色副本）\nconst Plate: React.FC<{ color: string; dx: number; dy: number }> = ({ color, dx, dy }) => (\n  <div\n    style={{\n      position: 'absolute',\n      inset: 0,\n      display: 'flex',\n      alignItems: 'center',\n      justifyContent: 'center',\n      transform: `translate(${dx}px, ${dy}px)`,\n      mixBlendMode: 'multiply',\n    }}\n  >\n    <div\n      style={{\n        fontFamily: 'Helvetica, Arial, sans-serif',\n        fontWeight: 800,\n        fontSize: 160,\n        color,\n        letterSpacing: -1,\n        whiteSpace: 'nowrap',\n      }}\n    >\n      ON THE BEAT\n    </div>\n  </div>\n);\n\nexport const RisoBeatPump: React.FC = () => {\n  const frame = useCurrentFrame();\n\n  // 找最近一次已命中的节拍（24f 间隔 > 14f 窗口，永远只有一拍在作用）\n  let beatIdx = -1;\n  for (let i = 0; i < HITS.length; i++) {\n    if (frame >= HITS[i]) beatIdx = i;\n  }\n  const t = beatIdx >= 0 ? frame - HITS[beatIdx] : Infinity;\n\n  // ① 整画面泵：命中帧一帧到位 1.08（t=0 即满值，无渐入），指数衰减回 1\n  const pump = t < PUMP_WIN ? 1 + 0.08 * Math.exp(-t / 3) : 1;\n\n  // ② 标题错位：衰减余弦震荡（周期 6f 抖两下），窗口外精确 0 = 套准\n  const split = t < SPLIT_WIN;\n  const m = split ? Math.cos((2 * Math.PI * t) / 6) * Math.exp(-t / 3) : 0;\n  const dx = beatIdx >= 0 ? AMP[beatIdx] * m : 0;\n  const dy = dx * 0.45; // y 少量，更像没对准版\n\n  return (\n    <div\n      style={{\n        width: 1920,\n        height: 1080,\n        background: G.bg,\n        position: 'relative',\n        overflow: 'hidden',\n      }}\n    >\n      {/* 整画面容器：scale 泵作用在全部内容上 */}\n      <div\n        style={{\n          position: 'absolute',\n          inset: 0,\n          transform: `scale(${pump})`,\n          transformOrigin: 'center center',\n        }}\n      >\n        {/* 标题区：正体 / 双版错位互斥切换 */}\n        <div style={{ position: 'absolute', left: 0, right: 0, top: 0, height: 660 }}>\n          {!split && (\n            <div\n              style={{\n                position: 'absolute',\n                inset: 0,\n                display: 'flex',\n                alignItems: 'center',\n                justifyContent: 'center',\n              }}\n            >\n              <TitleBlock text=\"ON THE BEAT\" size={160} />\n            </div>\n          )}\n          {split && (\n            <>\n              <Plate color={G.mid} dx={-dx} dy={dy} />\n              <Plate color={G.ink} dx={dx} dy={-dy} />\n            </>\n          )}\n        </div>\n\n        {/* 底下一排 3 张小卡 */}\n        <div\n          style={{\n            position: 'absolute',\n            left: 0,\n            right: 0,\n            top: 660,\n            display: 'flex',\n            justifyContent: 'center',\n            gap: 44,\n          }}\n        >\n          <Card w={330} h={200} seed={2} />\n          <Card w={330} h={200} seed={5} />\n          <Card w={330} h={200} seed={8} />\n        </div>\n\n        {/* 节拍刻度：命中即闪深（8f 缩放脉冲 1.8→1）并常驻深色 */}\n        <div\n          style={{\n            position: 'absolute',\n            left: 0,\n            right: 0,\n            top: 950,\n            display: 'flex',\n            justifyContent: 'center',\n            gap: 60,\n          }}\n        >\n          {HITS.map((hit, i) => {\n            const dt = frame - hit;\n            const on = dt >= 0;\n            const s = on && dt < 8 ? 1 + 0.8 * (1 - dt / 8) : 1;\n            return (\n              <div\n                key={i}\n                style={{\n                  width: 22,\n                  height: 22,\n                  borderRadius: 11,\n                  background: on ? G.ink : G.bar,\n                  transform: `scale(${s})`,\n                }}\n              />\n            );\n          })}\n        </div>\n      </div>\n    </div>\n  );\n};\n\n\n// ===== demos/effects/riso-print-hits/RisoMisregistrationHit.tsx =====\n// 套印错位冲击帧（riso-misregistration-hit）——标题撞停瞬间裂成两份单色\"印版\"\n// （浅灰琥珀版 G.mid + 深墨版 G.ink，mix-blend-mode: multiply 叠加），像 riso 印刷\n// 没对准版；两版反向错位（x 为主 y 少量）做衰减震荡 offset = A*cos(ωt)*exp(-t/τ)\n// 抖两下，帧 72 啪地硬切回单一正体（套准合一），带 4f scale 1.03→1 脉冲收束。\n// 结构：0–19f 空场 hold（只有底部装饰线）；20–28f 标题从右画外 Easing.in(cubic)\n// 撞入屏心（帧 28 命中）；28–71f 双版错位震荡；72–75f 套准脉冲；76–119f 真静止 44f。\nimport React from 'react';\nimport { useCurrentFrame, interpolate, Easing } from 'remotion';\nimport { G, TitleBlock } from '../../_fixtures/Fixtures';\n\nconst HIT = 28; // 撞停命中帧\nconst SNAP = 72; // 套准合一帧\nconst AX = 16; // 单版 x 错位振幅（两版反向 → 总分离 ~32px，肉眼明显）\nconst AY = 7; // 单版 y 错位振幅（少量，更像没对准版）\nconst OMEGA = (2 * Math.PI) / 18; // 震荡周期 18f，44f 内抖两下半\nconst TAU = 60; // 缓衰减：帧 72 前仍余 ~14px 总分离，被\"啪地\"硬切归零\n\n// 与 TitleBlock 同字形的可调色标题（错位印版需要单色副本）\nconst Plate: React.FC<{ color: string; dx: number; dy: number }> = ({ color, dx, dy }) => (\n  <div\n    style={{\n      position: 'absolute',\n      inset: 0,\n      display: 'flex',\n      alignItems: 'center',\n      justifyContent: 'center',\n      transform: `translate(${dx}px, ${dy}px)`,\n      mixBlendMode: 'multiply',\n    }}\n  >\n    <div\n      style={{\n        fontFamily: 'Helvetica, Arial, sans-serif',\n        fontWeight: 800,\n        fontSize: 200,\n        color,\n        letterSpacing: -1,\n        whiteSpace: 'nowrap',\n      }}\n    >\n      IMPACT\n    </div>\n  </div>\n);\n\nexport const RisoMisregistrationHit: React.FC = () => {\n  const frame = useCurrentFrame();\n\n  // 阶段判定\n  const entering = frame >= 20 && frame < HIT; // 撞入\n  const split = frame >= HIT && frame < SNAP; // 双版错位震荡\n  const showSingle = frame < HIT || frame >= SNAP; // 正体（画外/撞入/套准后）\n\n  // 撞入位移：右画外 1400px → 0，8f Easing.in(cubic)（加速撞停）\n  const slideX = interpolate(frame, [20, HIT], [1400, 0], {\n    easing: Easing.in(Easing.cubic),\n    extrapolateLeft: 'clamp',\n    extrapolateRight: 'clamp',\n  });\n\n  // 错位震荡包络：t 自命中起，衰减余弦（帧 72 前仍有可见残余，硬切归零成\"啪\"）\n  const t = frame - HIT;\n  const m = split ? Math.cos(OMEGA * t) * Math.exp(-t / TAU) : 0;\n  const dx = AX * m;\n  const dy = AY * m;\n\n  // 套准合一脉冲：帧 72 起 4f scale 1.03 → 1，之后精确 1（保证结尾真静止）\n  const pulse =\n    frame >= SNAP && frame < SNAP + 4 ? 1 + 0.03 * (1 - (frame - SNAP) / 4) : 1;\n\n  return (\n    <div\n      style={{\n        width: 1920,\n        height: 1080,\n        background: G.bg,\n        position: 'relative',\n        overflow: 'hidden',\n      }}\n    >\n      {/* 底部装饰线：全程静止的布景锚点 */}\n      <div\n        style={{\n          position: 'absolute',\n          left: 510,\n          top: 740,\n          width: 900,\n          height: 6,\n          borderRadius: 3,\n          background: G.bar,\n        }}\n      />\n\n      {/* 正体：画外等待 / 撞入 / 套准后（撞入前 frame<20 时在画外，视觉等同空场） */}\n      {showSingle && (\n        <div\n          style={{\n            position: 'absolute',\n            inset: 0,\n            display: 'flex',\n            alignItems: 'center',\n            justifyContent: 'center',\n            transform: `translateX(${entering || frame < 20 ? slideX : 0}px) scale(${pulse})`,\n            transformOrigin: 'center center',\n          }}\n        >\n          <TitleBlock text=\"IMPACT\" size={200} />\n        </div>\n      )}\n\n      {/* 双版错位：浅灰版与深墨版反向偏移，multiply 叠加出\"重影套印\" */}\n      {split && (\n        <>\n          <Plate color={G.mid} dx={-dx} dy={dy} />\n          <Plate color={G.ink} dx={dx} dy={-dy} />\n        </>\n      )}\n    </div>\n  );\n};\n\n\n"
}