Motion · Transição
Page-turn transitions
Two full-page transitions: cube-rotate turns two pages like adjacent cube faces, and barn-door-split splits the old page open like doors.
Fonte: video-shotcraft (Vincent Wei) ↗ · Apache-2.0 · Composição Remotion (React/TSX) — vídeo de prévia, sem player no navegador
Variantes
两页贴立方体相邻面(rotateY 0/90° + translateZ W/2),场景层转 -90°;旧面转出压暗、新面转进变亮,45° 时两面夹一条暗棱
并列章节翻篇;产品两大功能区切换
旧页两个 960px overflow 容器对位拼合,同时向外 Easing.in(cubic) 滑出画外;裂缝内边缘亮线+投影,新页底层 scale 1.06→1 迎上
新旧交替:改版前后、方案 A→方案 B
When to use
Chapter-level page changes: a "turning the page" ritual between two parallel major sections; division of labor with the shot-transitions family (camera hand-off) — that's "the camera moves across," this is "the page itself is a physical object"
Intention
The shot-transitions six and transition-travel/hidden-cut all treat the page as a "scene" — the camera moves between scenes. This card treats the page as a physical object: it has thickness, weight, it can turn over and split apart. The physical-object metaphor carries more ceremony, suited to major chapter-level page changes (feature A wraps up → feature B begins) rather than small shot-to-shot hand-offs. A, the cube, is "spatially parallel" — the two pages are two faces of a box, implying a peer relationship; B, the barn door, is "the old one steps aside" — the old page tears open from the center and slides away while the new page rises up from below, implying replacement. Choose by semantics: use A for parallel page turns, B for old-to-new swaps.
Duration & energy
- Duration: Per style: establish 30f + transition 20–38f + settle ≥40f, about 4.4–4.7s
- Energy: Medium-high
Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)
意图
shot-transitions 六式和 transition-travel/hidden-cut 都把页面当"场景" ——相机在场景间移动。本卡把页面当实体:它有厚度、有重量、会翻面 会裂开。体块隐喻的仪式感更强,适合章节级大换页(功能 A 讲完→功能 B) 而非镜头级小交棒。A 立方体是"空间上并列"——两页是盒子的两面, 暗示同级关系;B 对开门是"旧的让位"——旧页从正中撕开滑走、新页 从底下迎上来,暗示取代关系。按语义选:并列翻篇用 A,新旧交替用 B。
两式选型
| 式 | 做法 | 适用 | |----|------|------| | A cube-rotate | 两页贴立方体相邻面(rotateY 0/90° + translateZ W/2),场景层转 -90°;旧面转出压暗、新面转进变亮,45° 时两面夹一条暗棱 | 并列章节翻篇;产品两大功能区切换 | | B barn-door-split | 旧页两个 960px overflow 容器对位拼合,同时向外 Easing.in(cubic) 滑出画外;裂缝内边缘亮线+投影,新页底层 scale 1.06→1 迎上 | 新旧交替:改版前后、方案 A→方案 B |
参数表
| 参数 | 典型值 | 调节手感 | |------|--------|----------| | A 结构命门 | 场景层 translateZ(−W/2) rotateY(θ) 把正面拉回 z=0 | 少了这层 hold 段页面尺度不对(被 perspective 推远) | | A 转速 | θ 0→−90° / 38f inOut cubic;中段叠 blur 1.5px 落定摘 | <28f 读不出体块感;>50f 读作慢慢挪 | | A 亮度对切 | 旧面 1→0.55、新面 0.55→1 + 接缝竖向渐变阴影 sin(pπ) | 无明暗对切两面读作同一张图在转 | | B 预告 | 裂前中缝 2px 细线闪现两次(18–22/25–29f) | 直接裂开观众没看到裂点在哪 | | B 滑出 | 各 translateX ∓980px / 20f Easing.in(cubic) 加速 | ease-out 滑出是"被推走",ease-in 才是"让位" | | B 撕裂边 | 内边缘 3px G.ink 亮线 + 8px 投影 | 无边线两半读作普通左右擦除 | | 收尾 | 新页落定真静止 ≥40f | R1 |
已知坑
- demo 在灰阶/占位素材上调校通过——参数是调校起点非实战定稿,
首次实战须以真实素材回验
- 一缝一式规矩同 shot-transitions;体块转场比镜头交棒更重,
全片 ≤2 次,连续两缝都用体块读作 PPT 翻页
- A 式官方
@remotion/transitionscube() 是付费件——本卡是 CSS 自实现,
backlog 已有"评估官方转场原语"待选项,若引入官方件可对照
- B 式两半必须对位拼合无缝(右半内层 translateX(−960px))——
静止时看出接缝就穿帮;真实截图注意奇数宽度取整
- 转场前后两页都要有 ≥30f 静止建立/收尾——两端都在动,体块感被
运动淹没
参考实现
demos/transition/page-turn-transitions/ (BarnDoorSplit.tsx / CubeRotate.tsx)
Reference implementation (Remotion)
- demos/transition/page-turn-transitions/BarnDoorSplit.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/transition/page-turn-transitions/BarnDoorSplit.tsx
- demos/transition/page-turn-transitions/CubeRotate.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/transition/page-turn-transitions/CubeRotate.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/page-turn-transitions.jsongit clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/transition/page-turn-transitions/BarnDoorSplit.tsx, demos/transition/page-turn-transitions/CubeRotate.tsx
npx remotion render <CompositionId> out.mp4claude mcp add --transport http gimgs https://gimgs.net/mcp
# then: search_motion_templates / get_motion_template("page-turn-transitions")Prompt
Use the video-shotcraft shot recipe "Page-turn transitions" (Remotion composition, Apache-2.0) published on gimgs.net. Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/page-turn-transitions.json Raw TSX: https://gimgs.net/motion/page-turn-transitions/template.html Repository: https://github.com/Vincentwei1021/video-shotcraft (component: demos/transition/page-turn-transitions/BarnDoorSplit.tsx, demos/transition/page-turn-transitions/CubeRotate.tsx; imports demos/_fixtures and assets/lib) Spec: 1920x1080, 30 fps, 4.72s 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/page-turn-transitions/BarnDoorSplit.tsx =====
// 对开门裂幕(barn-door-split-reveal)——剪映"开门式"转场。
// FakeDashboard A 从画面正中垂直裂成左右两半:两个 960×1080 overflow:hidden
// 容器各装一份完整 A(右半内层 translateX(-960) 对位拼合),同时向外加速滑
// 出画外,露出底层 FakeDashboard B 从 scale 1.06 轻推到 1.0 迎上来。
// 裂缝各自内边缘 2px G.ink 亮线 + 8px 投影强调"撕开"。
// 关键帧:0–30 静止展示 A(18–22 / 25–29 中缝细线两次闪现预告裂点)→
// 30–50 两半各 translateX ∓980(Easing.in cubic 加速滑出)→
// 30–55 底层 B scale 1.06→1.0(out cubic)→ 55–130 全静止(75f)。
import React from 'react';
import { useCurrentFrame, interpolate, Easing } from 'remotion';
import { G, FakeDashboard, TitleBlock } from '../../_fixtures/Fixtures';
export const BarnDoorSplit: React.FC = () => {
const frame = useCurrentFrame();
// 两半外滑位移:30–50f,0 → 980px,加速离场
const slide = interpolate(frame, [30, 50], [0, 980], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
easing: Easing.in(Easing.cubic),
});
// 底层 B:30–55f 从 1.06 轻推到 1.0 迎上来
const bScale = interpolate(frame, [30, 55], [1.06, 1.0], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
easing: Easing.out(Easing.cubic),
});
// 裂前预告:中缝细线两次闪现(帧确定的开关,无随机)
const crackFlash =
(frame >= 18 && frame < 22) || (frame >= 25 && frame < 29);
// 裂开后内边缘亮线 + 阴影常驻(随门一起滑出画外)
const tornEdge = frame >= 30;
const edgeLine = (side: 'left' | 'right'): React.CSSProperties => ({
position: 'absolute',
top: 0,
[side]: 0,
width: 3,
height: 1080,
background: G.ink,
boxShadow:
side === 'right'
? '-8px 0 14px rgba(0,0,0,0.4)'
: '8px 0 14px rgba(0,0,0,0.4)',
});
return (
<div
style={{
width: 1920,
height: 1080,
background: G.bg,
position: 'relative',
overflow: 'hidden',
}}
>
{/* 底层 FakeDashboard B:scale 1.06 → 1.0 迎上来 */}
<div
style={{
position: 'absolute',
left: 0,
top: 0,
width: 1920,
height: 1080,
transform: `scale(${bScale})`,
transformOrigin: '50% 50%',
}}
>
<FakeDashboard variant="B" />
</div>
{/* 左门:960×1080 视口,装完整 A 的左半 */}
<div
style={{
position: 'absolute',
left: 0,
top: 0,
width: 960,
height: 1080,
overflow: 'hidden',
transform: `translateX(${-slide}px)`,
}}
>
<div style={{ position: 'absolute', left: 0, top: 0, width: 1920, height: 1080 }}>
<FakeDashboard variant="A" />
</div>
{tornEdge && <div style={edgeLine('right')} />}
</div>
{/* 右门:960×1080 视口,内层 translateX(-960) 对位拼合 */}
<div
style={{
position: 'absolute',
left: 960,
top: 0,
width: 960,
height: 1080,
overflow: 'hidden',
transform: `translateX(${slide}px)`,
}}
>
<div
style={{
position: 'absolute',
left: 0,
top: 0,
width: 1920,
height: 1080,
transform: 'translateX(-960px)',
}}
>
<FakeDashboard variant="A" />
</div>
{tornEdge && <div style={edgeLine('left')} />}
</div>
{/* 裂点预告:中缝 2px 细线闪现两次 */}
{crackFlash && (
<div
style={{
position: 'absolute',
left: 959,
top: 0,
width: 2,
height: 1080,
background: G.ink,
}}
/>
)}
<div style={{ position: 'absolute', left: 120, top: 96 }}>
<TitleBlock text="BARN DOOR SPLIT" size={54} />
</div>
</div>
);
};
// ===== demos/transition/page-turn-transitions/CubeRotate.tsx =====
// 立方体空间翻转(cube-rotate)——cube transition 转场自实现。
// FakeDashboard A / B 各缩放 0.82 居中,当立方体相邻两面:perspective 1400px,
// 面宽 W=1920*0.82,两面各 rotateY(面角) translateZ(W/2),场景整体先
// translateZ(-W/2) 再 rotateY(θ)(把正面拉回 z=0,保证 hold 时精确 0.82 尺度)。
// 旧面 A 转出画面 brightness 1→0.55 压暗,新面 B 从 +90° 侧转入 0.55→1 亮起;
// 接缝两侧各一条竖向渐变阴影,随角度 sin(pπ) 加深再消失;转动中段叠 blur(1.5px),
// 落定摘掉(filter 条件挂载,保证收尾逐帧完全相同)。
// 关键帧:0–30 静止展示 A → 30–68 θ 0→-90°(inOut cubic)翻转 → 68–140 B 真静止 72f。
import React from 'react';
import { useCurrentFrame, interpolate, Easing } from 'remotion';
import { G, FakeDashboard, TitleBlock } from '../../_fixtures/Fixtures';
const S = 0.82;
const W = 1920 * S; // 面宽 = 立方体棱长
const H = 1080 * S;
// 单个立方体面:W×H 视口内放缩放 0.82 的整幅 dashboard
const Face: React.FC<{
variant: 'A' | 'B';
rot: number; // 面自身的 rotateY(A=0,B=90)
brightness: number;
seam: number; // 接缝阴影不透明度 0–1
seamSide: 'right' | 'left'; // 阴影贴在哪条竖边(即共享棱一侧)
}> = ({ variant, rot, brightness, seam, seamSide }) => (
<div
style={{
position: 'absolute',
width: W,
height: H,
overflow: 'hidden',
backfaceVisibility: 'hidden',
transform: `rotateY(${rot}deg) translateZ(${W / 2}px)`,
filter: `brightness(${brightness})`,
background: G.bg,
}}
>
<div style={{ transform: `scale(${S})`, transformOrigin: '0 0' }}>
<FakeDashboard variant={variant} />
</div>
{seam > 0.01 && (
<div
style={{
position: 'absolute',
top: 0,
[seamSide]: 0,
width: 150,
height: H,
opacity: seam,
background:
seamSide === 'right'
? 'linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,0.55))'
: 'linear-gradient(to left, rgba(0,0,0,0), rgba(0,0,0,0.55))',
}}
/>
)}
</div>
);
export const CubeRotate: React.FC = () => {
const frame = useCurrentFrame();
// 翻转进度:30–68f,inOut cubic;两端 clamp 保证 hold 段逐帧恒定
const p = interpolate(frame, [30, 68], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
easing: Easing.inOut(Easing.cubic),
});
const theta = -90 * p;
const brightA = 1 - 0.45 * p; // 旧面转出压暗 1→0.55
const brightB = 0.55 + 0.45 * p; // 新面转入亮起 0.55→1
const mid = Math.sin(p * Math.PI); // 0→1→0,45° 时最深
const seam = mid * 0.9;
const blur = mid * 1.5;
return (
<div style={{ width: 1920, height: 1080, background: G.bg, position: 'relative', overflow: 'hidden' }}>
{/* blur 外包一层:>0.02 才挂 filter,落定后收尾帧完全相同 */}
<div
style={{
position: 'absolute',
inset: 0,
filter: blur > 0.02 ? `blur(${blur}px)` : undefined,
}}
>
<div
style={{
position: 'absolute',
left: (1920 - W) / 2,
top: (1080 - H) / 2,
width: W,
height: H,
perspective: 1400,
}}
>
<div
style={{
position: 'absolute',
inset: 0,
transformStyle: 'preserve-3d',
transform: `translateZ(${-W / 2}px) rotateY(${theta}deg)`,
}}
>
{/* 面 A:正面出发,绕左而去;接缝棱在其右边 */}
<Face variant="A" rot={0} brightness={brightA} seam={seam} seamSide="right" />
{/* 面 B:从 +90° 侧面转进来;接缝棱在其左边 */}
<Face variant="B" rot={90} brightness={brightB} seam={seam} seamSide="left" />
</div>
</div>
</div>
<div style={{ position: 'absolute', left: 120, top: 60 }}>
<TitleBlock text="CUBE ROTATE" size={54} />
</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/transition/page-turn-transitions/BarnDoorSplit.tsx, demos/transition/page-turn-transitions/CubeRotate.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

White flash: logo simplifies
A colorful liquid-gradient wordmark holds with flowing light, then the frame flashes white and overexposes; a flat wordmark fades in on white and settles — one flash completes the downgrade to simplicity.

Geometric wipe transitions
Two geometric wipe transitions — clock-wipe, a radar-hand sweep changing the page, and blinds-slice, 12 vertical strips flipping in staggered waves.

Hidden-cut transitions
Three hidden-cut transitions — foreground occlusion invisible cut, versus-slam opener, and warm light-leak burn; the hard cut hides inside 1-3 frames of occlusion/impact/light peak, so the viewer never sees the scissors.

Travel-through transitions
Two travel-through transitions — shared-element homecoming and letter-cavity pass-through; the camera drills through a real element inside the frame to complete the scene change.