Motion · Chuyển cảnh
Chuyển cảnh nét vẽ dẫn đường
Thanh tiến trình của cảnh A kéo dài ra khỏi khung hình, máy quay lia theo nét, nét bẻ góc giữa chừng để đóng khung thẻ của cảnh B, không có một lần cắt cảnh nào.
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
Giữa hai cảnh có quan hệ hình học (thanh tiến trình → khung thẻ, gạch chân → trục biểu đồ); vị trí chuyển cảnh đặc trưng của một video, kiểu relay hình học ở đầu phim Catch Me If You Can.
Ý đồ
Ba nhóm chuyển cảnh trong thư viện đều trả lời câu hỏi "cảnh đổi thế nào"; đáp án của thẻ này là về căn bản không đổi — một nét vẽ dẫn bạn đi qua. Thanh tiến trình đầy xong, đầu mút kéo dài thành một đường dài bắn ra khỏi mép thẻ, máy quay lia theo nét vào thế giới mới, nét bẻ góc vuông giữa chừng để đóng khung thẻ của cảnh B, khung khép lại, nội dung mờ hiện vào — mắt khán giả từ đầu đến cuối không rời khỏi nét vẽ đó. Tính liên tục hình học tự nó chính là chuyển cảnh. Khác với match-cut: đó là căn chỉnh hình dạng hai bên điểm cắt — vẫn là một lần cắt; đây là vẽ liên tục — không có cắt cảnh. Nét vẽ cần một logic kể chuyện cho danh tính của nó, một nét vẽ vô cớ chỉ là trang trí.
Thời lượng & năng lượng
- Thời lượng: ~5.3s (thanh tiến trình đầy + lia 60f + đóng khung + nội dung mờ hiện + giữ hình 36f)
- Năng lượng: Trung bình
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)
意图
转场库三大族(穿越/藏切/体块)都在回答"场景怎么换";本卡的回答是 根本不换——一条线牵着你走过去。进度条走满后末端延伸成长线冲出 卡缘,镜头跟着线横移 1920px 进入新世界,线在移动中拐直角围出 B 场景 的卡框,框闭合、内容淡入,从头到尾观众的眼睛没离开过这条线。图形 连续性本身就是转场。与 match-cut 的区别:那是切点两侧形状对位—— 终究还是切;这是连续绘制——没有切。线的身份要有叙事逻辑(进度条 "走完了"所以延伸出去),无来由的线只是装饰。
动效核心
- 3840 宽世界容器 translateX 当镜头,34–94f 移 1920px,
Easing.inOut(cubic)
- 一条手写折线 path(进度条 560 + 冲出段 + 直角 + 560×330 矩形框,
总长 3980)全程 dasharray/dashoffset evolve,分段驱动 drawn 长度
- 命门:横移段 drawn = 1100 + cam,线生长与镜头位移同速——笔头
钉在画面 x≈1500 偏右,永不出画也永不落后;一旦失速,观众跟丢线 就等于跟丢了转场
- 笔头 r=11 墨点随线走,框闭合后 112–118f 线性消散并条件卸载
(摘罩判例);B 内容 124f 前淡入完,124–160f 真静止 36f
参数表
| 参数 | 典型值 | 调节手感 | |------|--------|----------| | 线体 | 6px ink 实线 | 太细横移中读丢;虚线读作未完成态 | | 横移配比 | 1920px / 60f(32px/f) | 更远的横移等比拉长时长,别提速——>40px/f 笔头开始拖影跟丢 | | 笔头位置 | 画面 x≈1500(约 78% 处偏右) | 居中读作"线追镜头";贴边一颤就出画 | | 拐角 | 直角硬拐,不倒圆 | 圆角软拐丢掉制图感,Saul Bass 味就没了 | | 框闭合 | 闭合帧起 B 内容再淡入 | 框没闭合内容先出,线的悬念白搭 | | 收尾 | 淡入完 ≥36f 真静止 | 笔头墨点必须条件卸载,残留即毁静止 |
已知坑
- demo 在灰阶/占位素材上调校通过——参数是调校起点非实战定稿,
首次实战须以真实素材回验
- 与 draw-svg-trace 的关系:那是元素级描边点名(线属于元素),这是
场景级线条接力(线属于镜头)——同片可共存,但线的语义要一致: 同为 ink 6px 手绘感,或同为几何硬线,混用读作两套美术
- 全片 ≤1 次——这是招牌转场不是常规转场,第二次出现魔法就穿帮
- 起点必须是已有图形构件的自然延伸(进度条走满、下划线画完),
凭空起线读作屏保
- 声音:线生长一声持续笔擦、框闭合一声轻叩(sound-design §4.5)
参考实现
demos/transition/line-carry-transition/ (LineCarryTransition.tsx)
Mã nguồn tham chiếu (Remotion)
- demos/transition/line-carry-transition/LineCarryTransition.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/transition/line-carry-transition/LineCarryTransition.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/line-carry-transition.jsongit clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/transition/line-carry-transition/LineCarryTransition.tsx
npx remotion render <CompositionId> out.mp4claude mcp add --transport http gimgs https://gimgs.net/mcp
# then: search_motion_templates / get_motion_template("line-carry-transition")Prompt
Use the video-shotcraft shot recipe "Chuyển cảnh nét vẽ dẫn đường" (Remotion composition, Apache-2.0) published on gimgs.net. Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/line-carry-transition.json Raw TSX: https://gimgs.net/motion/line-carry-transition/template.html Repository: https://github.com/Vincentwei1021/video-shotcraft (component: demos/transition/line-carry-transition/LineCarryTransition.tsx; imports demos/_fixtures and assets/lib) Spec: 1920x1080, 30 fps, 5.38s 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/transition/line-carry-transition/LineCarryTransition.tsx =====
// line-carry-transition|线条接力横移转场(Catch Me If You Can 图形接力)
// 世界宽 3840(A 左半 / B 右半)。0–24f 卡 A 底部 6px ink 进度条走满;
// 24–34f 进度条末端延伸成横线冲出卡右缘;34–94f 镜头整体左移 1920px
// (Easing.inOut(cubic),60f),线与镜头同速延伸,笔头始终在画面偏右;
// 94–112f 线拐直角围出 560×330 卡框(一条 path 全程 evolve,dashoffset 生长);
// 112–124f 框闭合后 B 卡内容淡入 12f。124–160f 真静止 36f ≥ 35f。
// 帧确定,无随机;笔头墨点 118f 起条件卸载(摘罩判例)。
import React from 'react';
import { AbsoluteFill, useCurrentFrame, interpolate, Easing } from 'remotion';
import { G, Card, TitleBlock } from '../../_fixtures/Fixtures';
// ---- 世界几何(一条折线:进度条 + 横线 + 直角 + 矩形框)----
// M 400,705 → 2600,705(进度 560 + 冲出 1640)→ 上 2600,375 → 右 3160,375
// → 下 3160,705 → 左回 2600,705 闭合。总长 2200+330+560+330+560 = 3980。
const PATH = 'M 400 705 L 2600 705 L 2600 375 L 3160 375 L 3160 705 L 2600 705';
const SEGS: Array<[number, number, number, number, number]> = [
[400, 705, 2600, 705, 2200],
[2600, 705, 2600, 375, 330],
[2600, 375, 3160, 375, 560],
[3160, 375, 3160, 705, 330],
[3160, 705, 2600, 705, 560],
];
const TOTAL = 3980;
// 笔头坐标:按已画长度沿折线取点
const tipAt = (drawn: number): [number, number] => {
let d = Math.max(0, Math.min(drawn, TOTAL));
for (const [x1, y1, x2, y2, len] of SEGS) {
if (d <= len) {
const t = d / len;
return [x1 + (x2 - x1) * t, y1 + (y2 - y1) * t];
}
d -= len;
}
return [2600, 705];
};
export const LineCarryTransition: React.FC = () => {
const frame = useCurrentFrame();
// 镜头:34–94f 左移 1920px,inOut cubic
const cam = interpolate(frame, [34, 94], [0, 1920], {
easing: Easing.inOut(Easing.cubic),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
// 已画长度:三段接力(进度条 → 冲出 → 与镜头同速 → 收框)
let drawn: number;
if (frame < 24) {
drawn = interpolate(frame, [0, 24], [0, 560], {
easing: Easing.out(Easing.cubic),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
} else if (frame < 34) {
drawn = interpolate(frame, [24, 34], [560, 1100], {
extrapolateRight: 'clamp',
});
} else if (frame < 94) {
drawn = 1100 + cam; // 与镜头同速延伸,笔头稳在画面偏右
} else {
drawn = interpolate(frame, [94, 112], [3020, TOTAL], {
easing: Easing.out(Easing.cubic),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
}
// B 卡内容:框闭合(112f)后淡入 12f
const contentOpacity = interpolate(frame, [112, 124], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
// 笔头墨点:全程随笔走,112–118f 线性消散,118f 起条件卸载
const tipMounted = frame < 118;
const tipOpacity = interpolate(frame, [112, 118], [1, 0], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
const [tx, ty] = tipAt(drawn);
return (
<AbsoluteFill style={{ background: G.bg, overflow: 'hidden' }}>
{/* 世界容器:3840 宽,整体横移 = 镜头跟线走 */}
<div
style={{
position: 'absolute',
width: 3840,
height: 1080,
transform: `translateX(${-cam}px)`,
}}
>
{/* B 半世界底色略浅,卖出"新世界" */}
<div style={{ position: 'absolute', left: 1920, top: 0, width: 1920, height: 1080, background: G.panel }} />
{/* 场景 A:标题 + 卡 + 进度条轨道(ink 填充即 path 本体) */}
<div style={{ position: 'absolute', left: 400, top: 250 }}>
<TitleBlock text="Scene A" size={56} />
</div>
<Card w={560} h={330} seed={2} style={{ position: 'absolute', left: 400, top: 350 }} />
<div style={{ position: 'absolute', left: 400, top: 702, width: 560, height: 6, borderRadius: 3, background: G.line }} />
{/* 一条线全程 evolve:dasharray/dashoffset 生长 */}
<svg width={3840} height={1080} style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
<path
d={PATH}
fill="none"
stroke={G.ink}
strokeWidth={6}
strokeLinecap="round"
strokeLinejoin="round"
strokeDasharray={TOTAL}
strokeDashoffset={TOTAL - drawn}
/>
{tipMounted && <circle cx={tx} cy={ty} r={11} fill={G.ink} opacity={tipOpacity} />}
</svg>
{/* 场景 B:框(2600,375–3160,705)由线画成,内容淡入 */}
<div
style={{
position: 'absolute',
left: 2600,
top: 375,
width: 560,
height: 330,
boxSizing: 'border-box',
padding: 26,
display: 'flex',
flexDirection: 'column',
gap: 14,
opacity: contentOpacity,
}}
>
<div style={{ height: 18, width: '58%', background: G.bar, borderRadius: 9 }} />
<div style={{ height: 11, width: '86%', background: G.line, borderRadius: 5 }} />
<div style={{ height: 11, width: '72%', background: G.line, borderRadius: 5 }} />
<div style={{ height: 11, width: '64%', background: G.line, borderRadius: 5 }} />
<div style={{ marginTop: 'auto', display: 'flex', gap: 10, alignItems: 'center' }}>
<div style={{ width: 30, height: 30, borderRadius: 15, background: G.mid }} />
<div style={{ height: 11, width: 90, background: G.line, borderRadius: 5 }} />
</div>
</div>
<div style={{ position: 'absolute', left: 2600, top: 275, opacity: contentOpacity }}>
<TitleBlock text="Scene B" size={56} />
</div>
</div>
</AbsoluteFill>
);
};
- 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/transition/line-carry-transition/LineCarryTransition.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

Chớp trắng: logo giản lược
Chữ hiệu gradient lỏng nhiều màu đứng yên chảy sáng, màn hình chớp trắng cháy sáng một nhịp, chữ hiệu phiên bản phẳng trên nền trắng mờ vào định hình — một lần chớp trắng hoàn tất bước giản lược chất liệu.

Chuyển cảnh quét hình học
Hai kiểu chuyển cảnh quét hình học — clock-wipe kim đồng hồ radar quét đổi trang và blinds-slice 12 dải dọc lật lệch nhịp thành sóng.

Chuyển cảnh giấu điểm cắt
Ba kiểu chuyển cảnh giấu điểm cắt — che khuất tiền cảnh cắt vô hình, đối đầu va chạm mở màn, và cháy sáng rò rỉ ánh sáng ấm; cắt cứng giấu trong 1-3 khung che khuất/va chạm/đỉnh sáng, khán giả không thấy kéo cắt.

Chuyển cảnh xuyên qua
Hai kiểu chuyển cảnh xuyên qua — trở về vị trí bằng phần tử chung và xuyên khoang chữ, máy quay khoan xuyên phần tử thực trong khung hình để hoàn tất đổi cảnh.