{
  "slug": "crash-zoom-punch",
  "title": "Crash Zoom Punch",
  "tagline": "A wide shot crash-zooms to a target close-up in one beat (6f), landing either with a bounce overshoot (elastic) or a hard stop with screen shake (weighty).",
  "description": "A wide shot crash-zooms to a target close-up in one beat (6f), landing either with a bounce overshoot (elastic) or a hard stop with screen shake (weighty).",
  "category": "camera",
  "tags": [
    "shotcraft",
    "remotion",
    "camera",
    "effects"
  ],
  "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/crash-zoom-punch/poster-7c58015bf91d.jpg",
    "video": "https://gimgs.net/motion/media/crash-zoom-punch/video-041ee7c5ccab.mp4"
  },
  "variants": [
    {
      "key": "crash-zoom-punch",
      "label": "crash-zoom-punch",
      "description": "A wide shot crash-zooms to a target close-up in one beat (6f), landing either with a bounce overshoot (elastic) or a hard stop with screen shake (weighty).",
      "use": "",
      "video": "https://gimgs.net/motion/media/crash-zoom-punch/video-041ee7c5ccab.mp4",
      "poster": "https://gimgs.net/motion/media/crash-zoom-punch/poster-7c58015bf91d.jpg"
    }
  ],
  "credits": {
    "author": "video-shotcraft (Vincent Wei)",
    "url": "https://github.com/Vincentwei1021/video-shotcraft"
  },
  "page_url": "https://gimgs.net/motion/crash-zoom-punch.html",
  "json_url": "https://gimgs.net/motion/crash-zoom-punch.json",
  "template_url": "https://gimgs.net/motion/crash-zoom-punch/template.html",
  "play_url": null,
  "markdown_url": "https://gimgs.net/motion/crash-zoom-punch.md",
  "updated_at": "2026-09-24T07:39:52.937Z",
  "prompt": "## When to use\n\nA \"calling out\" shot for feature segments — snapping the viewer's eye onto a target card/module in one beat; use the hard-stop version for emphasis.\n\n## Intention\n\nA slow push-in (spotlight-hero-card) says \"please look\"; a crash zoom says \"look at this!\" — going from wide to close-up in a single beat leaves the eye no choice. The landing has two textures to pick from: a bounce-back is elastic (\"look at this\"), a hard stop with screen shake is weighty (\"this is it\") — choose by emphasis level.\n\n## Duration & energy\n\n- Duration: About 0.5s of motion plus hold before/after (motion 6–11f, pre-hold ≥30f to establish the wide shot, post-hold ≥45f to read the close-up).\n- Energy: High (instantaneous impact, not sustained high energy).\n\n## Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)\n\n## 意图\n慢推近（spotlight-hero-card）是\"请看\"，急推是\"看这个！\"——一拍之内\n从全景砸到特写，视线没有选择余地。落位质感分两款：回弹是弹性\n（\"看这个\"），撞停震屏是重量（\"就是它\"），按强调级选。\n\n## 动效核心\n- zoom 6f ease-in 急加速（如 1→2.6），cx/cy 同步 ease-in 收敛到目标中心\n- 回弹款：zoom 过冲后 5f 回收 3–6%（2.6→2.45）\n- 撞停款：到位帧起机位高频抖 + 指数衰减（amp 14px、τ≈1.8f、6f 收干），\n  不回弹\n- `<CameraMotionBlur shutterAngle={200} samples={20}>` **只包急推段**\n  （撞停震屏段保持清晰抖动）；采样按\"回波间距 ≤ 字高\"配（轮 A 判例）\n\n## 参数表\n| 参数 | 典型值 | 调节手感 |\n|------|--------|----------|\n| 急推时长 | 6f（4–8f） | >10f 读作普通推近，冲击感消失 |\n| 目标 zoom | 2.4–2.8 | 终点构图以目标卡占画面 60–75% 为准 |\n| 回弹幅度 | zoom 的 3–6% | 过大读作弹簧玩具 |\n| 震屏包络 | 14px·e^(−t/1.8) | 幅度须过肉眼阈值（可感性判例），>20px 读作故障 |\n\n## 已知坑\n- 终点必须是高清纹理槽位（card4-hires 级）——急推后全程特写它，\n  低倍截图糊字（Q2）；终点先按 Q2 的高分辨率栅格化技法处理\n- 两款别混用：回弹后再震屏读作穿帮；一支片急推 ≤2 次（P4 手法去重精神）\n- 参数经占位素材调校转正，非实战定稿，首次实战后回验\n\n## 参考实现\ndemos/camera/crash-zoom-punch/\n（CrashImpactReal.tsx / CrashZoomReal.tsx）\n\n## Reference implementation (Remotion)\n\n- demos/camera/crash-zoom-punch/CrashImpactReal.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/camera/crash-zoom-punch/CrashImpactReal.tsx\n- demos/camera/crash-zoom-punch/CrashZoomReal.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/camera/crash-zoom-punch/CrashZoomReal.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/camera/crash-zoom-punch/CrashImpactReal.tsx, demos/camera/crash-zoom-punch/CrashZoomReal.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/camera/crash-zoom-punch/CrashImpactReal.tsx",
      "url": "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/camera/crash-zoom-punch/CrashImpactReal.tsx"
    },
    {
      "path": "demos/camera/crash-zoom-punch/CrashZoomReal.tsx",
      "url": "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/camera/crash-zoom-punch/CrashZoomReal.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/camera/crash-zoom-punch/CrashImpactReal.tsx",
      "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/camera/crash-zoom-punch/CrashZoomReal.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/camera/crash-zoom-punch/CrashImpactReal.tsx =====\n// crash-impact 急推撞停——同 crash-zoom 的急推，到位瞬间不回弹而是\n// 撞停震屏：高频抖 + 指数衰减 6f，然后真静止。对比点：重量感 vs 弹性感。\nimport { AbsoluteFill, Img, interpolate, staticFile, useCurrentFrame, Easing } from 'remotion';\nimport { CameraMotionBlur } from '@remotion/motion-blur';\nimport layout from '../../_textures/live-layout.json';\n\nexport const CRASHIMPACT_DUR = 120;\n\nconst TARGET = { cx: 960, cy: 772 };\nconst VIEW_Y = 180;\nconst HIT = 46;\n\nconst Scene: React.FC = () => {\n  const frame = useCurrentFrame();\n  const zoom = interpolate(frame, [40, HIT], [1, 2.5], {\n    extrapolateLeft: 'clamp', extrapolateRight: 'clamp',\n    easing: Easing.bezier(0.55, 0, 0.7, 1),\n  });\n  const cx = interpolate(frame, [40, HIT], [960, TARGET.cx], {\n    extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.in(Easing.quad),\n  });\n  const cy = interpolate(frame, [40, HIT], [VIEW_Y + 540, TARGET.cy], {\n    extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.in(Easing.quad),\n  });\n  // 撞停震屏：amp 14px 指数衰减 ~6f 收干（可感幅度，参考轮 #2 可感档）\n  const since = frame - HIT;\n  const env = since >= 0 ? 14 * Math.exp(-since / 1.8) : 0;\n  const sx = env * Math.sin(since * 3.3);\n  const sy = env * 0.7 * Math.sin(since * 4.1 + 0.9);\n  return (\n    <AbsoluteFill style={{ backgroundColor: '#f9f6f1', overflow: 'hidden' }}>\n      <div\n        style={{\n          position: 'absolute', width: 1920, height: layout.projects.pageH,\n          transform: `translate(${960 - cx * zoom + sx}px, ${540 - cy * zoom + sy}px) scale(${zoom})`,\n          transformOrigin: '0 0',\n        }}\n      >\n        <Img src={staticFile('textures/live/projects-full.png')} style={{ position: 'absolute', width: 1920 }} />\n        <Img\n          src={staticFile('textures/live/card4-hires.png')}\n          style={{\n            position: 'absolute',\n            left: layout.projects.cards[3].x, top: layout.projects.cards[3].y,\n            width: layout.projects.cards[3].w, height: layout.projects.cards[3].h,\n          }}\n        />\n      </div>\n    </AbsoluteFill>\n  );\n};\n\nexport const CrashImpactReal: React.FC = () => {\n  const frame = useCurrentFrame();\n  // blur 只包急推段；撞停震屏段保持清晰抖动\n  return frame >= 38 && frame <= HIT ? (\n    <CameraMotionBlur shutterAngle={200} samples={20}>\n      <Scene />\n    </CameraMotionBlur>\n  ) : (\n    <Scene />\n  );\n};\n\n\n// ===== demos/camera/crash-zoom-punch/CrashZoomReal.tsx =====\n// crash-zoom 急推——真实 projects 页全景一拍推到 card4（高清纹理槽位）。\n// 节拍：0–40 全景 hold → 40–46 急推 6f（ease-in，峰值放大 2.6x）→\n// 46–51 过冲回弹（2.6→2.45）→ 51–120 特写 hold 真静止。\n// blur 只包 40–46 急推段（轮 A 规律：极速段 samples 20）。\nimport { AbsoluteFill, Img, interpolate, staticFile, useCurrentFrame, Easing } from 'remotion';\nimport { CameraMotionBlur } from '@remotion/motion-blur';\nimport layout from '../../_textures/live-layout.json';\n\nexport const CRASHZOOM_DUR = 120;\n\n// card4 中心（页面空间）：x=781+357/2≈960, y=616+312/2=772\nconst TARGET = { cx: 960, cy: 772 };\nconst VIEW_Y = 180; // 全景观察窗顶（页面 y）\n\nconst Scene: React.FC = () => {\n  const frame = useCurrentFrame();\n  const zoom = interpolate(frame, [40, 46, 51], [1, 2.6, 2.45], {\n    extrapolateLeft: 'clamp', extrapolateRight: 'clamp',\n    easing: Easing.bezier(0.55, 0, 0.7, 1),\n  });\n  const cx = interpolate(frame, [40, 46], [960, TARGET.cx], {\n    extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.in(Easing.quad),\n  });\n  const cy = interpolate(frame, [40, 46], [VIEW_Y + 540, TARGET.cy], {\n    extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.in(Easing.quad),\n  });\n  return (\n    <AbsoluteFill style={{ backgroundColor: '#f9f6f1', overflow: 'hidden' }}>\n      <div\n        style={{\n          position: 'absolute', width: 1920, height: layout.projects.pageH,\n          transform: `translate(${960 - cx * zoom}px, ${540 - cy * zoom}px) scale(${zoom})`,\n          transformOrigin: '0 0',\n        }}\n      >\n        <Img src={staticFile('textures/live/projects-full.png')} style={{ position: 'absolute', width: 1920 }} />\n        {/* 高清目标卡覆盖原位，放大后文字仍锐（Q2） */}\n        <Img\n          src={staticFile('textures/live/card4-hires.png')}\n          style={{\n            position: 'absolute',\n            left: layout.projects.cards[3].x, top: layout.projects.cards[3].y,\n            width: layout.projects.cards[3].w, height: layout.projects.cards[3].h,\n          }}\n        />\n      </div>\n    </AbsoluteFill>\n  );\n};\n\nexport const CrashZoomReal: React.FC = () => {\n  const frame = useCurrentFrame();\n  return frame >= 38 && frame <= 48 ? (\n    <CameraMotionBlur shutterAngle={200} samples={20}>\n      <Scene />\n    </CameraMotionBlur>\n  ) : (\n    <Scene />\n  );\n};\n\n\n"
}