{
  "slug": "edit-hook-moves",
  "title": "Edit hook moves",
  "tagline": "logo-sting-button end-hook — after the closing logo settles, a 12f easter egg suddenly cuts in before the final close, a trailer-style button ending.",
  "description": "logo-sting-button end-hook — after the closing logo settles, a 12f easter egg suddenly cuts in before the final close, a trailer-style button ending.",
  "category": "outro",
  "tags": [
    "shotcraft",
    "remotion",
    "outro"
  ],
  "tier": "free",
  "license": "Apache-2.0",
  "spec": {
    "width": 1920,
    "height": 1080,
    "fps": 30,
    "duration": 4.78,
    "aspect": "16:9"
  },
  "kind": "remotion",
  "params_schema": {
    "type": "object",
    "properties": {}
  },
  "default_params": {},
  "preview": {
    "poster": "https://gimgs.net/motion/media/edit-hook-moves/poster-ef78e50715c1.jpg",
    "video": "https://gimgs.net/motion/media/edit-hook-moves/video-9c2b19246648.mp4"
  },
  "variants": [
    {
      "key": "logo-sting-button",
      "label": "logo-sting-button · Logo sting button ending",
      "description": "logo-sting-button end-hook — after the closing logo settles, a 12f easter egg suddenly cuts in before the final close, a trailer-style button ending.",
      "use": "End credits; one more hit right after the main feature wraps up",
      "video": "https://gimgs.net/motion/media/edit-hook-moves/video-9c2b19246648.mp4",
      "poster": "https://gimgs.net/motion/media/edit-hook-moves/poster-ef78e50715c1.jpg"
    }
  ],
  "credits": {
    "author": "video-shotcraft (Vincent Wei)",
    "url": "https://github.com/Vincentwei1021/video-shotcraft"
  },
  "page_url": "https://gimgs.net/motion/edit-hook-moves.html",
  "json_url": "https://gimgs.net/motion/edit-hook-moves.json",
  "template_url": "https://gimgs.net/motion/edit-hook-moves/template.html",
  "play_url": null,
  "markdown_url": "https://gimgs.net/motion/edit-hook-moves.md",
  "updated_at": "2026-09-24T07:39:56.550Z",
  "prompt": "## When to use\n\nFor the closing wrap-up (≤1 per film).\n\n## Intention\n\nThe library's audio-visual cards all manage \"things on screen\"; this style manages **the rhetoric of the timeline itself** — a reversal at the ending: fade to black → logo fades in and settles (the audience thinks it's over) → a 12f UI close-up easter egg suddenly hard-cuts in → cut back to the logo for the close, a trailer-style button ending that leaves one last hook. It plays a joke on the audience's expectation that \"it's already over\".\n\n## Duration & energy\n\n- Duration: ~5s\n- Energy: Low → instant medium → low\n\n## Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)\n\n## 意图\n库内声画卡管的都是\"画面上的事\"；这一式管**时间线本身的修辞**——\n终点的反悔：收黑→logo 淡入定住（观众以为结束）→突然 12f UI 特写\n彩蛋硬切插入→切回 logo 收尾，预告片 button ending，留最后一个钩子。\n拿观众的\"已经结束了\"的预期开玩笑。\n\n## 单式选型\n| 式 | 做法 | 适用 |\n|----|------|------|\n| B logo-sting-button | 收黑 6f→logo 入场 10f（opacity+scale 0.96→1）→定住 30f→彩蛋 12f 硬切插入→切回 logo 真静止 ≥60f | 片尾；正片收束后再给一记 |\n\n## 参数表\n| 参数 | 典型值 | 调节手感 |\n|------|--------|----------|\n| 彩蛋时长 | 12f 级，内含 tick 圆点只亮第 4–5f（2f，条件挂载） | 长于 20f 就不是\"眨眼\"是一个镜头 |\n| 彩蛋构图 | 面板 translate+scale(2.4) 特写按钮行，平移量把 sidebar 完全推出画面 | 彩蛋里露出旧构图残边读作切错了 |\n| 像素级一致 | logo 段 interpolate 全 clamp 到终值，彩蛋前后 logo 共用同一分支渲染 | 硬切回来 logo 跳 1px 都读作抖动 |\n| 剪辑方式 | 全程硬切分支渲染（frame 区间 return 不同子树），无交叉溶解 | 节奏靠剪不靠淡；任何溶解都泄劲 |\n\n## 已知坑\n- demo 在灰阶/占位素材上调校通过——参数是调校起点非实战定稿，\n  首次实战须以真实素材回验\n- 全片 ≤1 次且只在片尾——中段用 button ending 变成故障，\n  观众以为片子坏了\n- 彩蛋内容必须是全片未见的新特写——复用旧镜头读作剪辑失误\n  不是钩子，命门\n\n## 参考实现\ndemos/outro/edit-hook-moves/\n（LogoStingButton.tsx）\n\n## Reference implementation (Remotion)\n\n- demos/outro/edit-hook-moves/LogoStingButton.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/outro/edit-hook-moves/LogoStingButton.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/outro/edit-hook-moves/LogoStingButton.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/outro/edit-hook-moves/LogoStingButton.tsx",
      "url": "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/outro/edit-hook-moves/LogoStingButton.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": 143,
    "repo": "https://github.com/Vincentwei1021/video-shotcraft",
    "files": [
      "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/outro/edit-hook-moves/LogoStingButton.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/outro/edit-hook-moves/LogoStingButton.tsx =====\n// logo-sting-button —— 收尾按钮镜头（button ending）\n// 上一镜收黑 → 黑场 → LOGO 入场定住（观众以为结束）→ 12f UI 特写彩蛋硬切 →\n// 硬切回黑底 LOGO 定格。节奏是全部：彩蛋段短促像眨眼。收尾真静止 ≥40f。\nimport React from 'react';\nimport { useCurrentFrame, interpolate, Easing } from 'remotion';\nimport { FakeDashboard } from '../../_fixtures/Fixtures';\n\n// 时间轴（30fps，共 142f）\nconst T = {\n  shotAEnd: 24,     // 0–24f 上一镜（B），f14–24 压暗到纯黑\n  darkenStart: 14,\n  blackEnd: 30,     // 24–30f 黑场 6f\n  logoInEnd: 40,    // 30–40f LOGO 入场 10f\n  holdEnd: 70,      // 40–70f 定住 30f（观众以为结束）\n  eggEnd: 82,       // 70–82f 彩蛋硬切 12f\n  total: 142,       // 82–142f 黑底 LOGO 真静止 60f\n};\n\nconst LogoLockup: React.FC<{ opacity: number; scale: number }> = ({ opacity, scale }) => (\n  <div style={{\n    width: 1920, height: 1080, background: '#000',\n    display: 'flex', alignItems: 'center', justifyContent: 'center',\n  }}>\n    <div style={{\n      display: 'flex', alignItems: 'center', gap: 44,\n      opacity, transform: `scale(${scale})`,\n    }}>\n      <div style={{\n        width: 120, height: 120, borderRadius: 28, background: '#fff',\n        display: 'flex', alignItems: 'center', justifyContent: 'center',\n      }}>\n        {/* 方块内一个黑色小标记，避免纯白块太空 */}\n        <div style={{ width: 44, height: 44, borderRadius: 12, background: '#000' }} />\n      </div>\n      <div style={{\n        fontFamily: 'Helvetica, Arial, sans-serif', fontWeight: 800,\n        fontSize: 90, color: '#fff', letterSpacing: 2,\n      }}>\n        ACME\n      </div>\n    </div>\n  </div>\n);\n\nexport const LogoStingButton: React.FC = () => {\n  const frame = useCurrentFrame();\n\n  // —— 段 1：上一镜（FakeDashboard B）压暗收黑 ——\n  if (frame < T.shotAEnd) {\n    const dark = interpolate(frame, [T.darkenStart, T.shotAEnd - 1], [0, 1], {\n      extrapolateLeft: 'clamp', extrapolateRight: 'clamp',\n      easing: Easing.in(Easing.cubic),\n    });\n    return (\n      <div style={{ width: 1920, height: 1080, background: '#000', position: 'relative', overflow: 'hidden' }}>\n        <FakeDashboard variant=\"B\" />\n        <div style={{ position: 'absolute', inset: 0, background: '#000', opacity: dark }} />\n      </div>\n    );\n  }\n\n  // —— 段 2：黑场 6f ——\n  if (frame < T.blackEnd) {\n    return <div style={{ width: 1920, height: 1080, background: '#000' }} />;\n  }\n\n  // —— 段 4：彩蛋硬切 12f（variant A 按钮区 2.4x 裁切 + 角落小圆点 tick 闪 2f）——\n  if (frame >= T.holdEnd && frame < T.eggEnd) {\n    const egg = frame - T.holdEnd; // 0..11\n    // tick 圆点：第 4–5f 亮 2f，像眨眼\n    const tickOn = egg >= 4 && egg < 6;\n    return (\n      <div style={{ width: 1920, height: 1080, background: '#ececea', position: 'relative', overflow: 'hidden' }}>\n        <div style={{\n          position: 'absolute', inset: 0,\n          // 2.4x 放大：把第 1 张卡片底部\"按钮行\"（头像圆+文字条）平移到画面中心\n          // 原坐标 (839, 531)（第 2 列卡片底部头像圆+文字条）→ 屏幕中心 (960, 540)\n          // 选中列卡片可把左侧深色 sidebar 完全推出画面，特写更纯粹\n          transform: 'translate(-1054px, -734px) scale(2.4)', transformOrigin: '0 0',\n        }}>\n          <FakeDashboard variant=\"A\" />\n        </div>\n        {tickOn && (\n          <div style={{\n            position: 'absolute', right: 90, bottom: 80,\n            width: 56, height: 56, borderRadius: 28, background: '#2f2f2f',\n            display: 'flex', alignItems: 'center', justifyContent: 'center',\n          }}>\n            <div style={{ width: 20, height: 20, borderRadius: 10, background: '#fff' }} />\n          </div>\n        )}\n      </div>\n    );\n  }\n\n  // —— 段 3 + 段 5：黑底 LOGO（入场 → 定住 → 彩蛋后定格收尾，真静止）——\n  const opacity = interpolate(frame, [T.blackEnd, T.logoInEnd], [0, 1], {\n    extrapolateLeft: 'clamp', extrapolateRight: 'clamp',\n    easing: Easing.out(Easing.cubic),\n  });\n  const scale = interpolate(frame, [T.blackEnd, T.logoInEnd], [0.96, 1], {\n    extrapolateLeft: 'clamp', extrapolateRight: 'clamp',\n    easing: Easing.out(Easing.cubic),\n  });\n  return <LogoLockup opacity={opacity} scale={scale} />;\n};\n\n\n"
}