Motion · Outro

Edit hook moves

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.

1920×108016:930 fps4.78s · 143 framesremotionLicense: Apache-2.0#shotcraft#remotion#outro

Source: video-shotcraft (Vincent Wei) ↗ · Apache-2.0 · Remotion composition (React/TSX) — preview video, no in-browser player

When to use

For the closing wrap-up (≤1 per film).

Intention

The 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".

Duration & energy

  • Duration: ~5s
  • Energy: Low → instant medium → low

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

意图

库内声画卡管的都是"画面上的事";这一式管时间线本身的修辞—— 终点的反悔:收黑→logo 淡入定住(观众以为结束)→突然 12f UI 特写 彩蛋硬切插入→切回 logo 收尾,预告片 button ending,留最后一个钩子。 拿观众的"已经结束了"的预期开玩笑。

单式选型

| 式 | 做法 | 适用 | |----|------|------| | B logo-sting-button | 收黑 6f→logo 入场 10f(opacity+scale 0.96→1)→定住 30f→彩蛋 12f 硬切插入→切回 logo 真静止 ≥60f | 片尾;正片收束后再给一记 |

参数表

| 参数 | 典型值 | 调节手感 | |------|--------|----------| | 彩蛋时长 | 12f 级,内含 tick 圆点只亮第 4–5f(2f,条件挂载) | 长于 20f 就不是"眨眼"是一个镜头 | | 彩蛋构图 | 面板 translate+scale(2.4) 特写按钮行,平移量把 sidebar 完全推出画面 | 彩蛋里露出旧构图残边读作切错了 | | 像素级一致 | logo 段 interpolate 全 clamp 到终值,彩蛋前后 logo 共用同一分支渲染 | 硬切回来 logo 跳 1px 都读作抖动 | | 剪辑方式 | 全程硬切分支渲染(frame 区间 return 不同子树),无交叉溶解 | 节奏靠剪不靠淡;任何溶解都泄劲 |

已知坑

  • demo 在灰阶/占位素材上调校通过——参数是调校起点非实战定稿,

首次实战须以真实素材回验

  • 全片 ≤1 次且只在片尾——中段用 button ending 变成故障,

观众以为片子坏了

  • 彩蛋内容必须是全片未见的新特写——复用旧镜头读作剪辑失误

不是钩子,命门

参考实现

demos/outro/edit-hook-moves/ (LogoStingButton.tsx)

Reference implementation (Remotion)

  • demos/outro/edit-hook-moves/LogoStingButton.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/outro/edit-hook-moves/LogoStingButton.tsx

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

Everything on this page is also machine-readable. Point your agent at the JSON, or add the gimgs MCP server and ask it to search motion templates.

  1. Fetch the JSON — it holds the shot recipe (timing, easing, parameter table, pitfalls) and the full TSX source.
  2. Clone the video-shotcraft repo; the component imports shared fixtures from demos/_fixtures and helpers from assets/lib.
  3. Register the component as a <Composition> in a Remotion project and render with `npx remotion render`, or re-implement the recipe in your own engine.
curl -s https://gimgs.net/motion/edit-hook-moves.json
git clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/outro/edit-hook-moves/LogoStingButton.tsx
npx remotion render <CompositionId> out.mp4
claude mcp add --transport http gimgs https://gimgs.net/mcp
# then: search_motion_templates / get_motion_template("edit-hook-moves")

Prompt

Use the video-shotcraft shot recipe "Edit hook moves" (Remotion composition, Apache-2.0) published on gimgs.net.
Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/edit-hook-moves.json
Raw TSX: https://gimgs.net/motion/edit-hook-moves/template.html
Repository: https://github.com/Vincentwei1021/video-shotcraft  (component: demos/outro/edit-hook-moves/LogoStingButton.tsx; imports demos/_fixtures and assets/lib)
Spec: 1920x1080, 30 fps, 4.78s

1. Read the JSON and follow its "prompt" section (when to use, intention, parameter table, known pitfalls).
2. Adapt it for: <describe what you want>.
3. Either clone the repo, register the component as a <Composition> in a Remotion project and run npx remotion render <CompositionId> out.mp4 — or re-implement the recipe in your own engine (HTML/WAAPI works: keep the same timing and easing).

JSON · Markdown · llms.txt

3,905 chars · Apache-2.0Open raw template ↗
// ===== demos/outro/edit-hook-moves/LogoStingButton.tsx =====
// logo-sting-button —— 收尾按钮镜头(button ending)
// 上一镜收黑 → 黑场 → LOGO 入场定住(观众以为结束)→ 12f UI 特写彩蛋硬切 →
// 硬切回黑底 LOGO 定格。节奏是全部:彩蛋段短促像眨眼。收尾真静止 ≥40f。
import React from 'react';
import { useCurrentFrame, interpolate, Easing } from 'remotion';
import { FakeDashboard } from '../../_fixtures/Fixtures';

// 时间轴(30fps,共 142f)
const T = {
  shotAEnd: 24,     // 0–24f 上一镜(B),f14–24 压暗到纯黑
  darkenStart: 14,
  blackEnd: 30,     // 24–30f 黑场 6f
  logoInEnd: 40,    // 30–40f LOGO 入场 10f
  holdEnd: 70,      // 40–70f 定住 30f(观众以为结束)
  eggEnd: 82,       // 70–82f 彩蛋硬切 12f
  total: 142,       // 82–142f 黑底 LOGO 真静止 60f
};

const LogoLockup: React.FC<{ opacity: number; scale: number }> = ({ opacity, scale }) => (
  <div style={{
    width: 1920, height: 1080, background: '#000',
    display: 'flex', alignItems: 'center', justifyContent: 'center',
  }}>
    <div style={{
      display: 'flex', alignItems: 'center', gap: 44,
      opacity, transform: `scale(${scale})`,
    }}>
      <div style={{
        width: 120, height: 120, borderRadius: 28, background: '#fff',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
      }}>
        {/* 方块内一个黑色小标记,避免纯白块太空 */}
        <div style={{ width: 44, height: 44, borderRadius: 12, background: '#000' }} />
      </div>
      <div style={{
        fontFamily: 'Helvetica, Arial, sans-serif', fontWeight: 800,
        fontSize: 90, color: '#fff', letterSpacing: 2,
      }}>
        ACME
      </div>
    </div>
  </div>
);

export const LogoStingButton: React.FC = () => {
  const frame = useCurrentFrame();

  // —— 段 1:上一镜(FakeDashboard B)压暗收黑 ——
  if (frame < T.shotAEnd) {
    const dark = interpolate(frame, [T.darkenStart, T.shotAEnd - 1], [0, 1], {
      extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
      easing: Easing.in(Easing.cubic),
    });
    return (
      <div style={{ width: 1920, height: 1080, background: '#000', position: 'relative', overflow: 'hidden' }}>
        <FakeDashboard variant="B" />
        <div style={{ position: 'absolute', inset: 0, background: '#000', opacity: dark }} />
      </div>
    );
  }

  // —— 段 2:黑场 6f ——
  if (frame < T.blackEnd) {
    return <div style={{ width: 1920, height: 1080, background: '#000' }} />;
  }

  // —— 段 4:彩蛋硬切 12f(variant A 按钮区 2.4x 裁切 + 角落小圆点 tick 闪 2f)——
  if (frame >= T.holdEnd && frame < T.eggEnd) {
    const egg = frame - T.holdEnd; // 0..11
    // tick 圆点:第 4–5f 亮 2f,像眨眼
    const tickOn = egg >= 4 && egg < 6;
    return (
      <div style={{ width: 1920, height: 1080, background: '#ececea', position: 'relative', overflow: 'hidden' }}>
        <div style={{
          position: 'absolute', inset: 0,
          // 2.4x 放大:把第 1 张卡片底部"按钮行"(头像圆+文字条)平移到画面中心
          // 原坐标 (839, 531)(第 2 列卡片底部头像圆+文字条)→ 屏幕中心 (960, 540)
          // 选中列卡片可把左侧深色 sidebar 完全推出画面,特写更纯粹
          transform: 'translate(-1054px, -734px) scale(2.4)', transformOrigin: '0 0',
        }}>
          <FakeDashboard variant="A" />
        </div>
        {tickOn && (
          <div style={{
            position: 'absolute', right: 90, bottom: 80,
            width: 56, height: 56, borderRadius: 28, background: '#2f2f2f',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}>
            <div style={{ width: 20, height: 20, borderRadius: 10, background: '#fff' }} />
          </div>
        )}
      </div>
    );
  }

  // —— 段 3 + 段 5:黑底 LOGO(入场 → 定住 → 彩蛋后定格收尾,真静止)——
  const opacity = interpolate(frame, [T.blackEnd, T.logoInEnd], [0, 1], {
    extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
    easing: Easing.out(Easing.cubic),
  });
  const scale = interpolate(frame, [T.blackEnd, T.logoInEnd], [0.96, 1], {
    extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
    easing: Easing.out(Easing.cubic),
  });
  return <LogoLockup opacity={opacity} scale={scale} />;
};


  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/outro/edit-hook-moves/LogoStingButton.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.
paramtypedefaultdescription
—

More in this category