Motion · Ritmo
Quad split parallel scenes
A hard-cut 2×2 grid runs four micro-scenes in parallel, with key beats staggered 3–6 frames apart for an information barrage.
Fonte: video-shotcraft (Vincent Wei) ↗ · Apache-2.0 · Composição Remotion (React/TSX) — vídeo de prévia, sem player no navegador
When to use
A rhythm section for "lots of features happening at once" montage; the density peak of a trailer's mid-section
Intention
Replace sequential display with parallel density: four things happen in front of the viewer at once, too fast to read each one in detail, but every 3–6 frames one quadrant "moves" — pinning the scan rhythm firmly in place. This is a technique card: the content inside the panels is entirely swappable, the staggered-beat arrangement is the recipe.
Duration & energy
- Duration: About 2.1s (63f@30fps, no transitions throughout)
- Energy: High (four parallel lines + staggered-beat impact, a standard spot for a BGM chorus)
Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)
意图
用并行密度替代顺序展示:四件事同时在眼前发生,观众来不及逐一细读,但每 3–6 帧就有一个象限"动一下"——扫视节奏被牢牢钉住。这是手法卡:格内内容全部可替换,错拍编排才是配方。
动效核心
- 四象限独立场景(内容为示例):TL 迷你浏览器逐字符打字 + 6 个 tab 依次 outBack 弹入 + 全程 inQuad 慢推 1→1.45;TR mono 打字 + t=0.42–0.54 whip 急推 scale 1→2.1(带 sin 包络 blur 4px);BL 三词按 0.24/0.46/0.56 逐词 outBack 弹入;BR 五步交互链(pill 滑入→光标贝塞尔巡游→点击缩放→改写文字→卡片弹出)
- 错拍是灵魂:TL tab 从 0.08 起每 0.13 一枚、TR 急推 0.42、BL 三词 0.24/0.46/0.56、BR 点击 0.42/0.74——任意相邻事件间隔 3–6 帧,永远有东西在动但从不齐动
- 两处打字机光标闪烁频率错开(16 帧周期 vs 14 帧周期 +5 相位),避免同闪
- BR 光标走两段二次贝塞尔(
qBez)巡游,点击瞬间sin(π)缩放 0.7 回弹 - 四格底色深浅交替(#c3c6cc/#f2f1ef/#e7e6e3/#b8bcc3)保证格线可读,无需描边
参数表
| 参数 | 典型值 | 调节手感 | |------|--------|----------| | 错拍间隔 | 相邻事件 3–6 帧 | <2 帧读作同拍(齐动=呆板);>8 帧密度散掉,轰炸感消失 | | TL 慢推 | inQuad 1→1.45,origin 50% 78% | 全程缓慢加速的"底噪运动",让静格也不静;>1.6 会裁掉 tab 行 | | TR 急推 | 0.42–0.54,scale 2.1 + blur 峰值 4px | 这是全卡最重的一拍,压 BGM 重音;blur 包络必须 sin(进出对称)| | 打字速度 | TXT1 25 字符 / 0.02–0.95 | 换文案保持字符数近似,否则打字节奏与其他象限错拍关系漂移 | | BR 交互链 | 滑入 0.12→巡游 0.3→点击 0.42→打字 0.46→二段巡游 0.62→点击 0.74→卡片 0.8 | 五步环环相扣,改任何一步需顺延后续;卡片 outBack 弹出是链尾重音 | | 底色 | 中性灰阶四档交替 | 换项目主题色时保持相邻格明度差 ≥15%,否则格线感消失 |
已知坑
- 这是手法卡:四格内容整体可换(产品截图/录屏/其他动效卡),但错拍表必须重排——新内容的关键帧继承原时刻表,否则四格变四个独立视频拼贴
- 2.1s 是密度上限时长,拉长到 3s+ 时每象限需加第二轮事件,否则后半段"没东西动"
- 光标闪烁走
floor(t*63)帧计算,改 dur 后重新核对两个光标的错相位 - 四格同时打字/同时弹入是最常见的退化写法——检查方式:逐帧过一遍,任何一帧不应有两个象限同时发生"重事件"
参考实现
demos/rhythm/quad-split-parallel-scenes/ (QuadSplitParallelScenes.tsx)
Reference implementation (Remotion)
- demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx
The component imports shared fixtures from demos/_fixtures and helpers from assets/lib in the repo; SKILL.md there documents the render workflow.
Tudo nesta página também é legível por máquina. Aponte seu agente para o JSON ou adicione o servidor MCP do gimgs e peça para buscar templates de motion.
- Baixe o JSON — contém a receita do plano (timing, easing, tabela de parâmetros, armadilhas) e o código TSX completo.
- Clone o repositório video-shotcraft; o componente importa fixtures de demos/_fixtures e helpers de assets/lib.
- Registre o componente como <Composition> em um projeto Remotion e renderize com `npx remotion render`, ou reimplemente a receita no seu próprio engine.
curl -s https://gimgs.net/motion/quad-split-parallel-scenes.jsongit clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx
npx remotion render <CompositionId> out.mp4claude mcp add --transport http gimgs https://gimgs.net/mcp
# then: search_motion_templates / get_motion_template("quad-split-parallel-scenes")Prompt
Use the video-shotcraft shot recipe "Quad split parallel scenes" (Remotion composition, Apache-2.0) published on gimgs.net. Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/quad-split-parallel-scenes.json Raw TSX: https://gimgs.net/motion/quad-split-parallel-scenes/template.html Repository: https://github.com/Vincentwei1021/video-shotcraft (component: demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx; imports demos/_fixtures and assets/lib) Spec: 1920x1080, 30 fps, 2.6s 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/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx =====
// quad-split-parallel-scenes — Quad Split 四宫并行蒙太奇(motion-lab 定稿转原生 Remotion)
// 手法卡:画面硬切成 2×2 四宫格,四个象限并行跑各自独立的微场景(格内内容可任意替换,
// 此处仅为示例):TL 迷你浏览器打字 + 标签堆积 + 慢推,TR mono 打字 + whip 急推,
// BL 三词逐个弹入,BR pill 滑入 → 光标贝塞尔飞行点击 → 卡片弹出。
// 关键节拍互相错开 3-6 帧、全程无转场,靠并行密度制造信息轰炸。
// 设计坐标 480×270(DesignStage 等比放大),参数以此坐标系标定。
import React from 'react';
import { DesignStage, E, lerp, seg, useT } from '../../_fixtures/Motion';
export const QUAD_SPLIT_PARALLEL_SCENES_DURATION = 63; // 2100ms @30fps
const ACCENT = '#7c5cff';
const ACCENT_SOFT = '#c9bcff';
const F = 'system-ui,-apple-system,sans-serif';
// 四宫格底色走中性灰阶(深浅交替保证格线可读),需要主题色时换成项目色板
const BGS = ['#c3c6cc', '#f2f1ef', '#e7e6e3', '#b8bcc3'];
const TRAFFIC = ['#ff5f57', '#febc2e', '#28c840'];
const TABNAMES = ['Tab One', 'Tab Two', 'Tab Three', 'Tab Four', 'Tab Five', 'Tab Six'];
const TXT1 = 'Placeholder headline text';
const TXT2 = 'and a second line of copy';
const WORDS = ['One', 'clear', 'message'];
// 二次贝塞尔取点(BR 象限光标飞行路径,坐标单位 %)
const qBez = (a: number[], b: number[], c: number[], t: number): [number, number] => {
const u = 1 - t;
return [
u * u * a[0] + 2 * u * t * b[0] + t * t * c[0],
u * u * a[1] + 2 * u * t * b[1] + t * t * c[1],
];
};
// TL —— 迷你浏览器:逐字符打字 + tab outBack 弹入 + 全程 inQuad 慢推
const QuadTL: React.FC<{ t: number; frame: number }> = ({ t, frame }) => {
const n1 = Math.floor(seg(t, 0.02, 0.95) * TXT1.length);
return (
<div
style={{
position: 'absolute',
left: '10%',
top: '22%',
width: '80%',
height: '60%',
background: '#fff',
borderRadius: 10,
boxShadow: '0 8px 24px rgba(20,40,80,.25)',
fontFamily: F,
transform: `scale(${lerp(E.inQuad(t), 1, 1.45)})`,
transformOrigin: '50% 78%',
}}
>
<div style={{ display: 'flex', alignItems: 'center', gap: 5, padding: '8px 10px 4px' }}>
{TRAFFIC.map((c) => (
<i key={c} style={{ width: 7, height: 7, borderRadius: '50%', background: c }} />
))}
<div style={{ display: 'flex', flex: 1, gap: 3, marginLeft: 6, minWidth: 0 }}>
{TABNAMES.map((n, i) => {
const k = seg(t, 0.08 + i * 0.13, 0.08 + i * 0.13 + 0.09, E.outBack);
return (
<div
key={n}
style={{
flex: 1,
minWidth: 0,
overflow: 'hidden',
whiteSpace: 'nowrap',
fontSize: 8,
color: '#555',
background: '#e8eaee',
borderRadius: '5px 5px 0 0',
padding: '2px 5px',
transform: `scale(${k})`,
}}
>
{n}
</div>
);
})}
</div>
</div>
<div
style={{
margin: '6px 10px',
height: 22,
borderRadius: 11,
background: '#f0f2f5',
display: 'flex',
alignItems: 'center',
padding: '0 10px',
fontSize: 10,
color: '#333',
}}
>
<b style={{ color: '#8a8f98', marginRight: 6 }}>◆</b>
<span>{TXT1.slice(0, n1)}</span>
{/* 光标按帧闪烁:16 帧一个周期 */}
<i style={{ width: 1, height: 12, background: '#333', marginLeft: 1, opacity: frame % 16 < 8 ? 1 : 0 }} />
</div>
</div>
);
};
// TR —— mono 打字 + whip 急推(错拍:0.42-0.54,推近时带运动模糊)
const QuadTR: React.FC<{ t: number; frame: number }> = ({ t, frame }) => {
const n2 = Math.floor(seg(t, 0.06, 0.9) * TXT2.length);
const zip = seg(t, 0.42, 0.54, E.inOutCubic);
return (
<div
style={{
position: 'absolute',
inset: 0,
fontFamily: '"SF Mono",Menlo,monospace',
transform: `scale(${lerp(zip, 1, 2.1)})`,
transformOrigin: '46% 42%',
filter: `blur(${Math.sin(zip * Math.PI) * 4}px)`,
}}
>
<div
style={{
position: 'absolute',
left: '12%',
top: '24%',
width: '76%',
background: '#fbf8f1',
borderRadius: 8,
boxShadow: '0 6px 20px rgba(0,0,0,.12)',
padding: '8px 12px 14px',
// 原渲染无全局 border-box:76% 是内容宽,padding 外扩(Remotion 注入
// 了 * { box-sizing:border-box },显式还原 content-box 才对得上原片)
boxSizing: 'content-box',
}}
>
<div style={{ display: 'flex', gap: 4, marginBottom: 6 }}>
{TRAFFIC.map((c) => (
<i key={c} style={{ width: 6, height: 6, borderRadius: '50%', background: c }} />
))}
</div>
<div style={{ fontSize: 8, color: '#8a8f98', marginBottom: 5 }}>✦ Section label ›</div>
<div style={{ fontSize: 11, color: '#111' }}>
<span>{TXT2.slice(0, n2)}</span>
{/* 光标错拍闪烁:与 TL 相位差 5 帧、周期 14 帧 */}
<span style={{ opacity: (frame + 5) % 14 < 7 ? 1 : 0 }}>_</span>
</div>
</div>
</div>
);
};
// BL —— 三词逐个 outBack 弹入(0.24 / 0.46 / 0.56,与其他象限错开)
const QuadBL: React.FC<{ t: number }> = ({ t }) => (
<div
style={{
position: 'absolute',
inset: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: 7,
fontFamily: F,
fontWeight: 800,
fontSize: 19,
color: '#1a1a1a',
}}
>
{WORDS.map((w, i) => {
const k = seg(t, [0.24, 0.46, 0.56][i], [0.24, 0.46, 0.56][i] + 0.1, E.outBack);
return (
<span
key={w}
style={{
transform: `scale(${k}) translateY(${(1 - k) * 8}px)`,
opacity: Math.min(1, k * 2),
}}
>
{w}
</span>
);
})}
</div>
);
// BR —— 五步交互:pill 滑入 → 光标贝塞尔飞行 → 点击缩放 → 打字回复 → 卡片弹出
const QuadBR: React.FC<{ t: number }> = ({ t }) => {
const slide = seg(t, 0.12, 0.3, E.outBack);
const m1 = seg(t, 0.3, 0.42, E.inOutCubic);
const m2 = seg(t, 0.62, 0.74, E.inOutCubic);
// 光标路径:先飞向 pill,再二段飞向发送键
const p = m2 > 0 ? qBez([44, 66], [66, 52], [82, 68], m2) : qBez([88, 30], [50, 40], [44, 66], m1);
const c1 = seg(t, 0.42, 0.47);
const c2 = seg(t, 0.74, 0.79);
const n4 = Math.floor(seg(t, 0.46, 0.62) * 9);
const pop = seg(t, 0.8, 0.88, E.outBack);
return (
<div style={{ position: 'absolute', inset: 0, fontFamily: F }}>
{/* 评论卡片:点击发送后弹出 */}
<div
style={{
position: 'absolute',
left: '12%',
bottom: '46%',
width: '66%',
background: 'rgba(255,255,255,.92)',
borderRadius: 8,
padding: '6px 9px',
boxSizing: 'content-box', // 同上:66% 为内容宽
fontSize: 8,
color: '#222',
transform: `scale(${pop})`,
transformOrigin: '20% 100%',
boxShadow: '0 5px 16px rgba(20,40,90,.25)',
}}
>
<b>You · just now</b>
<br />
All good!
</div>
{/* 输入 pill:从右侧滑入 */}
<div
style={{
position: 'absolute',
left: '8%',
bottom: '26%',
width: '84%',
height: 26,
borderRadius: 13,
background: 'rgba(255,255,255,.55)',
backdropFilter: 'blur(6px)',
display: 'flex',
alignItems: 'center',
padding: '0 8px',
boxSizing: 'content-box', // 同上:84% 为内容宽
gap: 6,
fontSize: 8,
boxShadow: '0 4px 14px rgba(20,40,90,.2)',
transform: `translateX(${(1 - slide) * 120}%)`,
marginBottom: -pop * 4,
}}
>
<span style={{ background: ACCENT, color: '#fff', borderRadius: 8, padding: '1px 5px' }}>00:00</span>
<span style={{ flex: 1, color: t < 0.44 ? '#666' : '#111' }}>
{t < 0.44 ? 'Leave your comment...' : 'All good!'.slice(0, n4)}
</span>
<span style={{ color: n4 >= 9 ? ACCENT : ACCENT_SOFT }}>➤</span>
</div>
{/* 光标圆点:两段点击各缩一次 */}
<div
style={{
position: 'absolute',
width: 9,
height: 9,
borderRadius: '50%',
background: '#fff',
border: '1.5px solid #333',
zIndex: 5,
boxShadow: '0 1px 4px rgba(0,0,0,.3)',
left: `${p[0]}%`,
top: `${p[1]}%`,
transform: `scale(${1 - Math.sin(c1 * Math.PI) * 0.3 - Math.sin(c2 * Math.PI) * 0.3})`,
}}
/>
</div>
);
};
export const QuadSplitParallelScenes: React.FC = () => {
const t = useT();
const frame = Math.floor(t * 63); // dur 2100ms @30fps
const scenes = [
<QuadTL key={0} t={t} frame={frame} />,
<QuadTR key={1} t={t} frame={frame} />,
<QuadBL key={2} t={t} />,
<QuadBR key={3} t={t} />,
];
return (
<DesignStage bg="#000" raster="zoom">
{scenes.map((scene, i) => (
<div
key={i}
style={{
position: 'absolute',
left: `${(i % 2) * 50}%`,
top: `${(i >> 1) * 50}%`,
width: '50%',
height: '50%',
overflow: 'hidden',
background: BGS[i],
}}
>
{scene}
</div>
))}
</DesignStage>
);
};
- 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/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.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 |
|---|---|---|---|
| — | |||
Mais nesta categoria

Trailer grammar: three beats
Three trailer-grammar moves — trailer-bumper, a fast-cut hook up front; card-footage-cadence, text cards interleaved with dialogue footage; smash-cut, a slam into stillness.

Speed ramp and freeze-annotate
Two frame-remap pacing moves — speed-ramp (fast → 0.2x gaze → fast) and freeze-annotate (flowing → freeze with a circled callout → unfreeze).

Spectrum-morph underline
Spectrum UI morph — the title underline splits into vertical bars that pulse like a spectrum for two bars, then closes back into a straight line; music visualization living inside the UI.

Smear-frame afterimages
Afterimage smear — a card drags 4 crisp, countable clones while panning fast, merging into one on landing; an animated take on motion blur.