Motion · Chữ & title card
Giải mã ký tự lỗi và rơi vật lý
Hai kiểu mở đầu tiêu đề — scramble-decode (đáp án mọc ra từ nhiễu) và letter-drop-physics (chữ rơi theo trọng lực, nảy, đứng vào vị trí), chọn theo tông giọng.
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
Biến thể
Toàn bộ chữ nhảy mã lỗi tốc độ cao rồi giữ, sau đó từ trái sang phải lần lượt khóa thành chữ thật, khoảnh khắc khóa có chớp đảo màu 2f, thanh tiến trình bên dưới chạy đồng bộ
Sản phẩm công nghệ/lập trình viên; cảm giác lý tính "đáp án nổi lên"
Chữ rơi lệch nhịp từ trên xuống, tăng tốc theo trọng lực với hai lần nảy giảm dần rồi đứng xiêu khi chạm đất, nhịp cuối cả nhóm đồng loạt đứng thẳng lại
Mở đầu tông nhẹ nhàng; phá băng tiêu đề "cảm giác sống động"
Khi nào dùng
Mở đầu tiêu đề lớn/thẻ chữ chương; loại trừ lẫn nhau với split-flap-title (bảng lật cơ khí) và document-typewriter-reveal (máy đánh chữ) cùng nhóm
Ý đồ
Mở đầu tiêu đề trong thư viện đã có máy đánh chữ (cảm giác tài liệu điềm tĩnh) và bảng lật cơ khí (cảm giác nghi thức cơ khí), hai kiểu này bổ sung thêm hai tính cách khác: A là cảm giác hacker terminal — chữ trước tiên là một mảng nhiễu tốc độ cao, "giải mã" từng chữ từ trái sang phải, khán giả nhìn đáp án mọc ra từ mã lỗi, hợp cho sản phẩm công nghệ xuất hiện tự tin; B là cảm giác hài vật lý — chữ rơi từ trên trời, đập đất nảy lên, đứng xiêu vẹo, nhịp cuối cả đội đứng ngay ngắn lại, hợp mở đầu phá băng tông nhẹ nhàng. Bốn kiểu mở đầu tiêu đề trong một phim dùng ≤2 kiểu (P4).
Thời lượng & năng lượng
- Thời lượng: Mỗi kiểu 4–5s (gồm giữ khung và đứng yên khi kết; đoạn động tác A khoảng 66f / B khoảng 106f)
- Năng lượng: Trung bình cao (A thiên lý tính dồn dập, B thiên hài hước vật lý)
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)
意图
标题入场库内已有打字机(沉稳文档感)和翻牌屏(机械仪式感),这两式补 另外两种性格:A 是终端黑客感——字符先是一片高速噪声,从左到右逐个 "解码"锁定,观众看着答案从乱码里长出来,适合技术产品的自信亮相; B 是物理喜剧感——字符从天而降、砸地弹跳、歪歪扭扭站定,最后一拍 集体立正归位,适合轻松调性的开场破冰。四种标题入场同片 ≤2 种(P4)。
两式选型
| 式 | 做法 | 适用 | |----|------|------| | A scramble-decode 乱码解码 | 全员字符高速跳乱码 hold,随后从左到右逐个锁定真字符,锁定瞬间反色闪 2f,底部进度条同步推进 | 技术/开发者产品;"答案浮出"的理性推进感 | | B letter-drop-physics 字符坠落 | 字符错峰从顶砸落,重力加速+两次衰减弹跳+落地歪斜站定,最后一拍全体齐整回正 | 轻松调性开场;"活物感"的标题破冰 |
参数表
| 参数 | 典型值 | 调节手感 | |------|--------|----------| | A 乱码期 | 0–20f 全员每 2f 跳一个随机字符(字符集 A–F/0–9/#$%&),字色 G.mid | 必须用等宽字体 + 固定 1ch 槽宽,比例字体每跳一下整行抖动 | | A 解码节拍 | 第 i 字符帧 20+i×6 锁定为真字符转深色;锁定后前 2f 反色闪(深底白字) | 6f/字是"逐个可辨"的下限;上限 10f,再慢读作卡住 | | A 伪随机 | CHARSET[floor(h(i*101+floor(f/2)*7+13)*len)],h = sin hash | 严禁 Math.random——跳动必须随帧确定,否则渲染不可复现 | | B 坠落 | 第 i 字符帧 10+i×5 起跳;y = −DROP + DROP·(t/24)²(重力)→ 4u(1−u) 抛物线弹跳 30% → 二跳 9% | 弹跳衰减比 30%/9% 是"有弹性但不闹"的甜点;三跳以上读作果冻 | | B 歪斜 | 落地瞬间 rotate 到 seed hash ±6° 并保持 | 歪角是"物理感"的一半;全体笔直落地读作普通位移入场 | | B 归位一拍 | 全员落定后(如帧 110)6f ease-out 集体 rotate→0 + scale 1.06→1 | 集体归位是句号——错峰归位会把"立正"的仪式感拆散 | | 收尾 | 两式动作完毕真静止 ≥20f | R1:静止期所有属性锁死(含 B 的歪角归零后) |
已知坑
- demo 在灰阶/占位素材上调校通过——参数是调校起点非实战定稿,
首次实战须以真实素材回验
- A 式是声音强依赖候选位:锁定的"嗒"声逐字钉帧(sound-design §4.5)
会让解码感翻倍;B 式落地砸声同理,无声版两式都还成立但少一半劲
- A 式字符集别混入与真字符太像的字形(如 O/0 连跳)——观众会误判已锁定
- B 式字符间不做真实碰撞(demo 为各字符独立轨迹)——字距排开即可;
想要"互相撞歪"需预烘焙轨迹,成本高收益薄
- 标题入场品类已四式(本卡两式 + split-flap-title + document-typewriter-reveal),
同片 ≤2 种,且都自带高注意力——别和其他高能量入场同帧抢戏
参考实现
demos/typography/type-entrance-moves/ (LetterDropPhysics.tsx / ScrambleDecode.tsx)
Mã nguồn tham chiếu (Remotion)
- demos/typography/type-entrance-moves/LetterDropPhysics.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/typography/type-entrance-moves/LetterDropPhysics.tsx
- demos/typography/type-entrance-moves/ScrambleDecode.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/typography/type-entrance-moves/ScrambleDecode.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/type-entrance-moves.jsongit clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/typography/type-entrance-moves/LetterDropPhysics.tsx, demos/typography/type-entrance-moves/ScrambleDecode.tsx
npx remotion render <CompositionId> out.mp4claude mcp add --transport http gimgs https://gimgs.net/mcp
# then: search_motion_templates / get_motion_template("type-entrance-moves")Prompt
Use the video-shotcraft shot recipe "Giải mã ký tự lỗi và rơi vật lý" (Remotion composition, Apache-2.0) published on gimgs.net. Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/type-entrance-moves.json Raw TSX: https://gimgs.net/motion/type-entrance-moves/template.html Repository: https://github.com/Vincentwei1021/video-shotcraft (component: demos/typography/type-entrance-moves/LetterDropPhysics.tsx, demos/typography/type-entrance-moves/ScrambleDecode.tsx; imports demos/_fixtures and assets/lib) Spec: 1920x1080, 30 fps, 4.39s 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/typography/type-entrance-moves/LetterDropPhysics.tsx =====
// 字符坠落堆积(letter-drop-physics)——FallingLetterAnimation。
// "GRAVITY" 7 字符各自绝对定位,第 i 字符从帧 10+i*5 起下落:
// ① 重力加速 y = D*(t/24)^2 掉 720px 到基线(地板线可见);
// ② 落地后 2 次衰减弹跳(高度 30% / 9%,抛物线 4u(1-u) 拼段),
// 落地瞬间 rotate 到 seed hash ±6° 小歪角并保持;
// ③ 帧 110 一拍:6f ease-out 全体齐整回正(rotate→0、偏移→0、scale 1.06→1),
// 帧 116–150 真静止(≥25f)收尾。
import React from 'react';
import { useCurrentFrame, Easing } from 'remotion';
import { G } from '../../_fixtures/Fixtures';
// 确定性伪随机
const h = (n: number) => {
const s = Math.sin(n * 127.3) * 43758.5453;
return s - Math.floor(s);
};
const WORD = 'GRAVITY';
const SLOT_W = 150; // 每字符槽宽
const FONT = 140;
const WORD_W = WORD.length * SLOT_W; // 1050
const LEFT = (1920 - WORD_W) / 2; // 435
const REST_TOP = 452; // 字符落定后的 top
const FLOOR_Y = REST_TOP + 152; // 地板线(视觉基线)
const DROP = 720; // 下落距离
const T_FALL = 24; // 落到基线用时
const T_B1 = 16; // 第一次弹跳时长(高 30%)
const T_B2 = 8; // 第二次弹跳时长(高 9%)
const SNAP = 110; // 齐整回正的一拍
const SNAP_DUR = 6;
const easeOutCubic = Easing.out(Easing.cubic);
const clamp01 = (x: number) => Math.min(1, Math.max(0, x));
// 单字符纵向位移(相对基线,负 = 在上方)
const dropY = (t: number): number => {
if (t <= 0) return -DROP;
if (t < T_FALL) return -DROP + DROP * (t / T_FALL) ** 2; // 重力加速
if (t < T_FALL + T_B1) {
const u = (t - T_FALL) / T_B1;
return -DROP * 0.3 * 4 * u * (1 - u); // 弹跳 1:30%
}
if (t < T_FALL + T_B1 + T_B2) {
const u = (t - T_FALL - T_B1) / T_B2;
return -DROP * 0.09 * 4 * u * (1 - u); // 弹跳 2:9%
}
return 0;
};
export const LetterDropPhysics: React.FC = () => {
const frame = useCurrentFrame();
// 帧 110 起的齐整回正进度
const snap = easeOutCubic(clamp01((frame - SNAP) / SNAP_DUR));
return (
<div style={{ width: 1920, height: 1080, background: G.bg, overflow: 'hidden', position: 'relative' }}>
{/* 地板线:字符落点的视觉基线 */}
<div style={{ position: 'absolute', left: LEFT - 60, top: FLOOR_Y, width: WORD_W + 120, height: 6, background: G.bar, borderRadius: 3 }} />
{WORD.split('').map((ch, i) => {
const start = 10 + i * 5;
const t = frame - start;
const y = dropY(t);
// 落地瞬间歪到 seed 小角度(±6°),落地前为 0
const tiltTarget = (h(i + 1) - 0.5) * 12;
const landP = clamp01((t - T_FALL) / 6);
const restJitter = (h(i + 11) - 0.5) * 10; // 落定后的 ±5px 竖向错位
// snap 一拍:歪角与错位齐整归零,scale 1.06→1 脉冲
const rot = tiltTarget * landP * (1 - snap);
const jitter = restJitter * landP * (1 - snap);
const scale = frame < SNAP ? 1 : 1 + 0.06 * (1 - snap);
return (
<div
key={i}
style={{
position: 'absolute',
left: LEFT + i * SLOT_W,
top: REST_TOP,
width: SLOT_W,
height: FONT,
display: 'flex',
alignItems: 'flex-end',
justifyContent: 'center',
transform: `translateY(${y + jitter}px) rotate(${rot}deg) scale(${scale})`,
transformOrigin: '50% 100%',
fontFamily: 'Helvetica, Arial, sans-serif',
fontWeight: 800,
fontSize: FONT,
lineHeight: 1,
color: G.ink,
}}
>
{ch}
</div>
);
})}
</div>
);
};
// ===== demos/typography/type-entrance-moves/ScrambleDecode.tsx =====
// 乱码解码字(scramble-decode)——终端黑客感文字入场。
// 标题 "DECODE SPEED" 每字符先高速跳随机字母/数字(每 2f 换一个,seed hash 取字符),
// 从左到右逐个锁定:第 i 个字符在帧 20+i*6 锁定为真字符,锁定瞬间该字符反色闪
// (G.ink 色块白字 2f)随即恢复。跳动期字符 G.mid,锁定后 G.ink。
// 关键帧:0–20f 全员乱跳 → 20–86f 从左到右逐个锁定 → 87–130f 完全静止收尾。
import React from 'react';
import { useCurrentFrame } from 'remotion';
import { G } from '../../_fixtures/Fixtures';
const TEXT = 'DECODE SPEED';
const CHARSET = 'ABCDEF0123456789#$%&';
const LOCK_START = 20; // 第 0 个字符锁定帧
const LOCK_STEP = 6; // 相邻字符锁定间隔
const FLASH_LEN = 2; // 锁定反色闪持续帧数
// 帧确定伪随机
const h = (n: number) => {
const s = Math.sin(n * 127.3) * 43758.5453;
return s - Math.floor(s);
};
export const ScrambleDecode: React.FC = () => {
const frame = useCurrentFrame();
const chars = TEXT.split('');
const lockedCount = chars.filter((c, i) => c === ' ' || frame >= LOCK_START + i * LOCK_STEP).length;
const allLocked = lockedCount === chars.length;
return (
<div
style={{
width: 1920,
height: 1080,
background: G.bg,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
gap: 48,
}}
>
<div
style={{
fontFamily: 'ui-monospace, Menlo, Monaco, monospace',
fontWeight: 800,
fontSize: 120,
letterSpacing: 2,
display: 'flex',
}}
>
{chars.map((ch, i) => {
if (ch === ' ') {
return <span key={i} style={{ display: 'inline-block', width: '0.7em' }} />;
}
const lockFrame = LOCK_START + i * LOCK_STEP;
const locked = frame >= lockFrame;
const flashing = locked && frame < lockFrame + FLASH_LEN;
// 跳动期:每 2 帧换一个伪随机字符
const tick = Math.floor(frame / 2);
const scrambleChar = CHARSET[Math.floor(h(i * 101 + tick * 7 + 13) * CHARSET.length)];
const shown = locked ? ch : scrambleChar;
return (
<span
key={i}
style={{
display: 'inline-block',
width: '1ch',
textAlign: 'center',
color: flashing ? G.card : locked ? G.ink : G.mid,
background: flashing ? G.ink : 'transparent',
}}
>
{shown}
</span>
);
})}
</div>
{/* 底部进度提示条:已锁定字符数比例,帮助读出"从左到右扫过"的推进感 */}
<div style={{ width: 900, height: 10, background: G.line, borderRadius: 5, overflow: 'hidden' }}>
<div
style={{
width: `${(lockedCount / chars.length) * 100}%`,
height: '100%',
background: allLocked ? G.ink : G.mid,
borderRadius: 5,
}}
/>
</div>
</div>
);
};
- 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/typography/type-entrance-moves/LetterDropPhysics.tsx, demos/typography/type-entrance-moves/ScrambleDecode.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

Ba từ tiếp sức bằng hình học
Ba từ lợi ích mỗi từ mang riêng một bộ hình học tiếp sức — vòng tròn nét đứt tự xoay thu nhỏ → ba vòng tròn nét liền mọc lên lần lượt → ánh kim sheen quét qua rồi thu về trắng thuần; mỗi từ mới viền nét rồi tô đầy.

Tiếp sức từ với cuộn phim trang
Cột trái các thẻ trang đen trắng cuộn theo bước, bên phải từ lớn chữ serif tiếp sức tại chỗ (danh từ cố định + động từ luân phiên) — chỉ khi đổi từ mới cuộn một bước, khớp chính xác điểm giữa thẻ trang hiện tại.

Cuộn từ dọc theo nhịp
Từ cuối câu đổi trên cuộn dọc, 3 lần đổi từ mỗi lần 0.55s, nhanh trước chậm sau kèm hơi overshoot; các dòng lân cận nhòe dọc và xám dần theo khoảng cách, từ ở giữa vừa đậu liền nhuộm từ xám sang màu nhấn.

Hai cách tiết lộ code song song
Cùng một khối code tô cú pháp được tiết lộ hai cách song song — trái: stagger cấp dòng mờ vào nổi lên 8px, phải: gõ từng ký tự nhưng giữ nguyên màu token gốc, con trỏ vuông #3a4468 đệm dưới ký tự hiện tại.