Motion · Kết
Chuyển động móc câu kết
Móc câu kết logo-sting-button — sau khi logo cuối định hình, chèn đột ngột 12f trứng phục sinh rồi mới kết thúc, kiểu button ending của trailer.
Nguồn: video-shotcraft (Vincent Wei) ↗ · Apache-2.0 · Composition Remotion (React/TSX) — có video preview, không có player trong trình duyệt
Khi nào dùng
Dùng để khép lại đoạn kết (toàn phim ≤1 lần).
Ý đồ
Các thẻ hình-tiếng trong thư viện đều quản "chuyện trên màn hình"; kiểu này quản tu từ của chính dòng thời gian — sự lật ngược ở điểm kết: về đen → logo mờ hiện và định hình (khán giả tưởng đã hết) → bất ngờ cắt cứng chèn vào 12f cận cảnh UI trứng phục sinh → cắt về logo để kết, kiểu button ending của trailer, để lại một cú móc câu cuối cùng. Đùa với kỳ vọng "đã kết thúc rồi" của khán giả.
Thời lượng & năng lượng
- Thời lượng: ~5s
- Năng lượng: Thấp → trung bình tức thời → thấp
Công thức cảnh quay (bản gốc tiếng Trung — timing, easing, bảng tham số, lỗi hay gặp)
意图
库内声画卡管的都是"画面上的事";这一式管时间线本身的修辞—— 终点的反悔:收黑→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)
Mã nguồn tham chiếu (Remotion)
- demos/outro/edit-hook-moves/LogoStingButton.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/outro/edit-hook-moves/LogoStingButton.tsx
Component import fixture chung từ demos/_fixtures và helper từ assets/lib của repo; xem SKILL.md trong repo để biết quy trình render.
Mọi thứ trên trang này đều có bản máy đọc. Đưa agent link JSON, hoặc thêm MCP server gimgs rồi bảo nó tìm motion template.
- Tải JSON — trong đó có công thức cảnh quay (timing, easing, bảng tham số, lỗi hay gặp) và toàn bộ source TSX.
- Clone repo video-shotcraft; component import fixture chung từ demos/_fixtures và helper từ assets/lib.
- Đăng ký component thành <Composition> trong project Remotion rồi render bằng `npx remotion render`, hoặc dựng lại công thức bằng engine của bạn.
curl -s https://gimgs.net/motion/edit-hook-moves.jsongit clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/outro/edit-hook-moves/LogoStingButton.tsx
npx remotion render <CompositionId> out.mp4claude 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 "Chuyển động móc câu kết" (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).
// ===== 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} />;
};
- Read the recipePrompt = when to use, intention, parameter table with typical values and how each one feels, known pitfalls. Treat values as calibrated starting points.
- Get the codetool: git
git clone https://github.com/Vincentwei1021/video-shotcraft && cd video-shotcraft && npm install - Register + rendertool: remotion
npx remotion render <CompositionId> out.mp4 # component: demos/outro/edit-hook-moves/LogoStingButton.tsx - Or re-implementPort the timing/easing from the recipe to HTML + WAAPI (gimgs motion contract) or any engine; keep the same segment windows and easing.
| param | type | default | description |
|---|---|---|---|
| — | |||
Cùng danh mục

UI biến hình thành logo thương hiệu
Hai kiểu UI biến thành logo — icon-flip-bloom icon lật phẳng trục Y nở thành hình hoa mark + wordmark vào từng chữ, và input-morph-assemble ô nhập liệu co lại thành viên nang, ba hạt hình học tụ thành một cánh logo.

Kết phim kiểu phép trừ
Kết phim kiểu phép trừ — bấm Publish xong, toàn bộ UI trình soạn bốc hơi từng lớp lệch nhịp từ ngoài vào trong, chỉ còn lại nút vừa bấm trượt vào tâm màn hình phóng to, rồi mờ đi trao lại cho chữ hiệu định vị.

Outro ảnh nhóm ra mắt
Mọi yếu tố trong phim bay vào từ mọi hướng vây quanh wordmark chụp ảnh nhóm, dàn dựng như cảnh chốt của một sự kiện ra mắt.

Ba hàng đèn neon chạy chữ
Ba hàng đèn neon chạy chữ ngược chiều (BETTER/FASTER/STRONGER) cuộn vô tận, lần lượt sáng theo pha rồi mờ dần.