Motion · Transição

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.

1920×108016:930 fps4.05s · 122 quadrosremotionLicença: Apache-2.0#shotcraft#remotion#transition

Fonte: video-shotcraft (Vincent Wei) ↗ · Apache-2.0 · Composição Remotion (React/TSX) — vídeo de prévia, sem player no navegador

Variantes

invisible-cutinvisible-cut 前景遮挡隐形切
一张超画幅卡片带重运动模糊贴脸横扫,糊满全屏的遮挡帧内背景 A→B 硬切,卡片飞出观众以为还是同一镜
想让换景完全无痕的页面→页面;伪"一条 take"的主力款
versus-slamversus-slam 对撞开屏
左右两半屏带斜切边从画外加速对冲撞合,撞击帧白闪+震屏+VS 盖章,切点就是撞击本身
对比/对阵语义的开屏或章节头(新旧方案、双产品、before/after)
light-leak-burnlight-leak-burn 琥珀漏光
三团琥珀柔光沿对角线斜扫,光峰帧吞掉旧页约七成时硬切新页,光退散时新页已就位
想要暖调/胶片味的章节过渡;比白闪柔、有方向、有温度

When to use

When two shots need a "seamless scene change" or a "ceremonial reveal" at the join (a technique card, chosen from the same tier as the six shot-transitions moves)

Intention

Same family as shot-transitions style A, flash-cut: flash-cut covers a hard cut with one layer of white flash; these three swap in three different "decoys" — a sweeping foreground card (A), a collision-impact frame (B), a light leak climbing to its peak (C). The shared principle is magician's misdirection: the viewer's eyes get pulled away by a big motion/bright flash for those 1-3 frames while the hard cut happens, and when they refocus the scene has already changed, all "without ever seeing the scissors." flash-cut is the plainest version; pick A for a sense of direction, B for ceremony, C for warmth.

Duration & energy

  • Duration: n/a (a technique card; each style's frame count is in its parameter table, drawn from the neighboring shots' budget)
  • Energy: n/a (a technique card, doesn't occupy an energy slot)

Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)

意图

与 shot-transitions A 式 flash-cut 同族:flash-cut 用一层白闪盖住硬切, 这三式换了三种"障眼物"——扫过的前景卡片(A)、对撞的撞击帧(B)、 爬到顶峰的漏光(C)。共同原理是魔术误导:观众的眼睛被大动作/强光 吸走的那 1-3 帧里完成硬切,回过神来景已经换了,全程"看不见剪刀"。 flash-cut 是最素的一款;要方向感选 A,要仪式感选 B,要温度选 C。

三式选型

| 式 | 做法 | 适用接缝 | |----|------|----------| | A invisible-cut 前景遮挡隐形切 | 一张超画幅卡片带重运动模糊贴脸横扫,糊满全屏的遮挡帧内背景 A→B 硬切,卡片飞出观众以为还是同一镜 | 想让换景完全无痕的页面→页面;伪"一条 take"的主力款 | | B versus-slam 对撞开屏 | 左右两半屏带斜切边从画外加速对冲撞合,撞击帧白闪+震屏+VS 盖章,切点就是撞击本身 | 对比/对阵语义的开屏或章节头(新旧方案、双产品、before/after)| | C light-leak-burn 暖色漏光 | 三团暖色柔光沿对角线斜扫,光峰帧吞掉旧页约七成时硬切新页,光退散时新页已就位 | 想要暖调/胶片味的章节过渡;比白闪柔、有方向、有温度 |

参数表

| 参数 | 典型值 | 调节手感 | |------|--------|----------| | A 横扫 | 卡片 1600x1000 再 scale(1.6),x 从 -2200→2600 共 14f,bezier(0.3,0,0.7,1);切点在扫掠中点全遮帧(demo 里 f47) | 中点必须覆盖 -280..2280 糊满 1920 画幅;两端完全出画 | | A 糊感 | 全场包 <CameraMotionBlur shutterAngle={300} samples={12}> + 卡片自身 blur(8px)/skewX(-v·0.018°) + 4 层手动残影(opacity 0.35→0.07、blur 14px、间隔 0.55f) | 三层糊叠出"贴脸呼啸";只靠 CameraMotionBlur 糊不满遮挡窗口 | | A 带风推挤 | 背景 ±40px:切前 A 被拖向扫掠方向(ease-in),切后 B 从反侧 13f 回稳(ease-out) | 卖"同一镜被风带了一下"的错觉,是无痕感的一半功劳 | | B 斜缝几何 | clip-path polygon 斜边约 78°(缝顶 x=1075→缝底 x=845);两半屏从 ±1200px 以 ease-in(cubic) 10f 对冲到位 | ease-in 加速才有"砸"感;垂直缝读作 PPT 分屏 | | B 撞击三件套 | 撞击帧同发:白闪 0.9→0 共 3f + 整机 shake 12px·e^(−t/1.6) 约 5f 收干 + VS 字块 scale 1.6→1 back(2.6) overshoot 6f 压出 | 三件必须同帧起跑,错开一帧就散;震屏幅度须过肉眼阈值(可感性判例)| | C 光层 | 3 团径向渐变(#f6c878/#e8a44a/#d98a2b,直径 1500/1950/2400px,blur 90px,mixBlendMode screen)沿右上→左下扫约 70f | 光团偏移沿扫掠方向拖尾排布,避免完美同心的"手电筒感" | | C 光强包络 | ease-in 爬升 27f(蓄力)→ 峰值帧藏切 → ease-out 收敛 43f(余温);峰值叠 8% 全屏暖罩 + 近白热核(opacity=intensity²) | 爬升慢收敛快会读作故障闪光;热核只在临近峰值烧起来 | | C 冲淡 | 峰值时页面 filter:contrast 降 45%、brightness 抬 35% | 这是"烧穿"感的来源——光只叠不冲淡,读作贴了张贴纸 |

已知坑

  • demo 在灰阶/占位素材上调校通过——参数是调校起点非实战定稿,

首次实战须以真实素材回验

  • C 式是 Q4 光效判例解封后首个入库光效手法——严守 Q4 三约束:

单点使用(一支片一处,不群发)、正常速度回放自检好看才算过、 光效服务切点而非装饰;与 flash-cut 同片混用算两次光效藏切

  • A 式遮挡物必须真的全遮:demo 里 1600x1000 的卡要 scale(1.6) 才盖满

1920 画幅——换素材尺寸后先逐帧检查切点帧有没有露出背景边缘, 露一条缝整个魔术就穿帮

  • B 式 VS 字块语义仅适配"对比/对阵"内容——没有两方对峙关系时

别当通用转场用;去掉 VS 只留对撞则退化为一款斜缝 wipe,语义要求同降

  • 转场不叠加(规矩同 shot-transitions):一个接缝只用一式;

这三式与六式同层选型,同片同类接缝别既用 flash-cut 又用 C 式

  • 分镜表阶段就逐接缝标注(写进"关键动效"列),帧预算从相邻镜头划(R3)

参考实现

demos/transition/transition-hidden-cut/ (InvisibleCut.tsx / LightLeakBurn.tsx / VersusSlam.tsx)

Reference implementation (Remotion)

  • demos/transition/transition-hidden-cut/InvisibleCut.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/transition/transition-hidden-cut/InvisibleCut.tsx
  • demos/transition/transition-hidden-cut/LightLeakBurn.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/transition/transition-hidden-cut/LightLeakBurn.tsx
  • demos/transition/transition-hidden-cut/VersusSlam.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/transition/transition-hidden-cut/VersusSlam.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.

  1. Baixe o JSON — contém a receita do plano (timing, easing, tabela de parâmetros, armadilhas) e o código TSX completo.
  2. Clone o repositório video-shotcraft; o componente importa fixtures de demos/_fixtures e helpers de assets/lib.
  3. 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/transition-hidden-cut.json
git clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/transition/transition-hidden-cut/InvisibleCut.tsx, demos/transition/transition-hidden-cut/LightLeakBurn.tsx, demos/transition/transition-hidden-cut/VersusSlam.tsx
npx remotion render <CompositionId> out.mp4
claude mcp add --transport http gimgs https://gimgs.net/mcp
# then: search_motion_templates / get_motion_template("transition-hidden-cut")

Prompt

Use the video-shotcraft shot recipe "Hidden-cut 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/transition-hidden-cut.json
Raw TSX: https://gimgs.net/motion/transition-hidden-cut/template.html
Repository: https://github.com/Vincentwei1021/video-shotcraft  (component: demos/transition/transition-hidden-cut/InvisibleCut.tsx, demos/transition/transition-hidden-cut/LightLeakBurn.tsx, demos/transition/transition-hidden-cut/VersusSlam.tsx; imports demos/_fixtures and assets/lib)
Spec: 1920x1080, 30 fps, 4.05s

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).

JSON · Markdown · llms.txt

10,954 chars · Apache-2.0Abrir template bruto ↗
// ===== demos/transition/transition-hidden-cut/InvisibleCut.tsx =====
import React from 'react';
import { AbsoluteFill, Easing, interpolate, useCurrentFrame } from 'remotion';
import { CameraMotionBlur } from '@remotion/motion-blur';
import { FakeDashboard, Card, G } from '../../_fixtures/Fixtures';

// invisible-cut:前景遮挡隐形切——一张放大到超出画幅的卡片带重运动模糊
// 从左侧贴脸扫过,糊满屏幕的瞬间背景从 A 无痕换成 B,卡片飞出右侧时
// 观众以为还是同一镜。(invisible-cut + foreground-occlusion-swipe)
const SW_START = 40; // 卡片入场
const SW_END = 54; // 卡片出场(14f 横扫)
const CUT = 47; // 硬切点:扫掠中点,卡片完全糊满画面的那一帧

// 卡片中扫掠曲线上的水平位置(容器 left,未缩放坐标)
const xAt = (f: number) =>
  // 卡片 scale(1.6) 后半宽 1280:起点右缘 -120 / 终点左缘 2120,均完全出画;
  // 中点 f47 覆盖 -280..2280,糊满整个 1920 画幅
  interpolate(f, [SW_START, SW_END], [-2200, 2600], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
    easing: Easing.bezier(0.3, 0, 0.7, 1),
  });

const Scene: React.FC = () => {
  const frame = useCurrentFrame();
  const x = xAt(frame);
  // 瞬时速度(px/帧),驱动斜切与残影强度
  const v = xAt(frame + 0.5) - xAt(frame - 0.5);
  const sweeping = frame > SW_START - 2 && frame < SW_END + 3;
  // 背景被"带风"轻推:A 被拖向左,切成 B 后从右侧回稳——卖同一镜错觉
  const shove =
    frame < CUT
      ? interpolate(frame, [SW_START, CUT], [0, -40], {
          extrapolateLeft: 'clamp',
          extrapolateRight: 'clamp',
          easing: Easing.in(Easing.quad),
        })
      : interpolate(frame, [CUT, CUT + 13], [40, 0], {
          extrapolateLeft: 'clamp',
          extrapolateRight: 'clamp',
          easing: Easing.out(Easing.cubic),
        });
  return (
    <AbsoluteFill style={{ background: G.bg, overflow: 'hidden' }}>
      {/* 背景层:硬切藏在遮挡帧内 */}
      <div style={{ position: 'absolute', inset: 0, transform: `translateX(${shove}px)` }}>
        {frame < CUT ? <FakeDashboard variant="A" /> : <FakeDashboard variant="B" />}
      </div>
      {/* 手动残影:4 层拖尾(在主卡身后),保证遮挡窗口糊满全屏 */}
      {sweeping &&
        [4, 3, 2, 1].map((i) => (
          <div
            key={i}
            style={{
              position: 'absolute',
              left: xAt(frame - i * 0.55),
              top: 40,
              width: 1600,
              height: 1000,
              transform: 'scale(1.6)',
              opacity: [0, 0.35, 0.22, 0.13, 0.07][i],
              filter: 'blur(14px)',
            }}
          >
            <Card w={1600} h={1000} seed={9} style={{ width: '100%', height: '100%' }} />
          </div>
        ))}
      {/* 主卡:1600x1000 放大 1.6 倍(2560x1600 超出画幅),自带 blur 加强糊感 */}
      {sweeping && (
        <div
          style={{
            position: 'absolute',
            left: x,
            top: 40,
            width: 1600,
            height: 1000,
            transform: `scale(1.6) skewX(${-v * 0.018}deg)`,
            filter: 'blur(8px)',
            boxShadow: '0 24px 80px rgba(0,0,0,0.3)',
            borderRadius: 20,
          }}
        >
          <Card w={1600} h={1000} seed={9} style={{ width: '100%', height: '100%' }} />
        </div>
      )}
    </AbsoluteFill>
  );
};

export const InvisibleCut: React.FC = () => (
  <CameraMotionBlur shutterAngle={300} samples={12}>
    <Scene />
  </CameraMotionBlur>
);


// ===== demos/transition/transition-hidden-cut/LightLeakBurn.tsx =====
import React from 'react';
import { AbsoluteFill, Easing, interpolate, useCurrentFrame } from 'remotion';
import { FakeDashboard, TitleBlock, G } from '../../_fixtures/Fixtures';

// light-leak-burn〔转场〕:一团琥珀橙柔光从右上角斜扫入画,亮度顶峰时
// 吞掉旧画面约七成(高光溢出、对比度被冲淡),光峰帧后切新页藏切点,
// 光退散时新页已在光下就位——比白闪柔、有方向、有温度。
// 节拍:0–25 建立旧页 hold;25–52 光斜扫入、爬向峰值;52 峰值帧切页;
// 52–95 光沿对角线退出、强度衰减;95–130 新页静止 hold。

const PEAK = 52; // 光峰帧 = 藏切点

export const LightLeakBurn: React.FC = () => {
  const frame = useCurrentFrame();

  // 光团沿对角线的位移进度:右上外 → 左下外,贯穿 25–95
  const sweep = interpolate(frame, [25, 95], [0, 1], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
    easing: Easing.bezier(0.4, 0, 0.3, 1),
  });

  // 光强包络:25–PEAK 爬升(ease-in 有蓄力感),PEAK–95 收敛(ease-out 余温)
  const rise = interpolate(frame, [25, PEAK], [0, 1], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
    easing: Easing.in(Easing.quad),
  });
  const fall = interpolate(frame, [PEAK, 95], [1, 0], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
    easing: Easing.out(Easing.cubic),
  });
  const intensity = frame <= PEAK ? rise : fall;

  // 光团中心:从画面右上外侧斜扫到左下外侧(有方向的漏光)
  const cx = interpolate(sweep, [0, 1], [2350, -650]);
  const cy = interpolate(sweep, [0, 1], [-500, 1500]);

  // 三团琥珀光的偏移与直径(seed 正弦哈希做微差,避免完美同心)
  const blobs = [0, 1, 2].map((i) => {
    const j1 = (Math.sin(i * 127.3) * 43758) % 1; // -1..1 小数
    const j2 = (Math.sin(i * 311.7) * 27183) % 1;
    return {
      dx: i * 260 - 260 + j1 * 90, // 沿扫掠方向拖尾排布
      dy: i * 200 - 200 + j2 * 70,
      d: 1500 + i * 450, // 直径 1500 / 1950 / 2400
      color: ['#f6c878', '#e8a44a', '#d98a2b'][i],
      alpha: [0.95, 0.8, 0.55][i],
    };
  });

  // 峰值时页面被光冲淡:对比度降、亮度抬(旧页被"烧穿"的感觉)
  const pageFilter = `contrast(${1 - intensity * 0.45}) brightness(${1 + intensity * 0.35})`;

  // 全屏暖色罩:峰值时约 8%
  const warmWash = intensity * 0.08;

  return (
    <AbsoluteFill style={{ background: G.bg, overflow: 'hidden' }}>
      {/* 页面层:光峰帧前是旧页(网格),之后是新页(列表+标题)——切点藏在最亮处 */}
      <AbsoluteFill style={{ filter: pageFilter }}>
        {frame <= PEAK ? (
          <FakeDashboard variant="A" />
        ) : (
          <>
            <FakeDashboard variant="B" />
            <div style={{ position: 'absolute', left: 288, top: 132 }}>
              <TitleBlock text="Next Page" size={64} />
            </div>
          </>
        )}
      </AbsoluteFill>

      {/* 全屏暖色罩:峰值 8%,让高光溢出带温度 */}
      <AbsoluteFill
        style={{
          background: '#e8a44a',
          opacity: warmWash,
          mixBlendMode: 'screen',
          pointerEvents: 'none',
        }}
      />

      {/* 琥珀漏光层:3 团大直径径向渐变,blur 90px,screen 叠加,沿对角线扫过 */}
      <AbsoluteFill style={{ pointerEvents: 'none' }}>
        {blobs.map((b, i) => (
          <div
            key={i}
            style={{
              position: 'absolute',
              left: cx + b.dx - b.d / 2,
              top: cy + b.dy - b.d / 2,
              width: b.d,
              height: b.d,
              borderRadius: '50%',
              background: `radial-gradient(circle, ${b.color} 0%, ${b.color}cc 30%, transparent 68%)`,
              filter: 'blur(90px)',
              mixBlendMode: 'screen',
              opacity: b.alpha * intensity,
            }}
          />
        ))}
        {/* 峰值核心过曝:光心一小团接近白的热核,峰值帧吞掉约七成画面 */}
        <div
          style={{
            position: 'absolute',
            left: cx - 550,
            top: cy - 550,
            width: 1100,
            height: 1100,
            borderRadius: '50%',
            background: 'radial-gradient(circle, #fff3dd 0%, #f6c878aa 45%, transparent 70%)',
            filter: 'blur(80px)',
            mixBlendMode: 'screen',
            opacity: intensity * intensity, // 只在临近峰值时才烧起来
          }}
        />
      </AbsoluteFill>
    </AbsoluteFill>
  );
};


// ===== demos/transition/transition-hidden-cut/VersusSlam.tsx =====
import React from 'react';
import { AbsoluteFill, Easing, interpolate, useCurrentFrame } from 'remotion';
import { FakeDashboard, TitleBlock, G } from '../../_fixtures/Fixtures';

// versus-slam 对撞开屏:左右两个半屏画面(带 78° 斜切边)从画外加速对冲,
// 沿斜缝砰地撞合;撞击帧白闪 + 整机震屏指数衰减 + "VS" 字块盖章压出,结尾静止 hold。
const IMPACT = 30; // 撞击帧(前 20f 建立 hold + 10f ease-in 对冲)

// 斜缝几何:78° 斜边 → 1080 高度上水平偏移 1080/tan(78°) ≈ 230px,中线 x=960 ±115
const SEAM_TOP_X = 1075; // 缝顶端 x
const SEAM_BOT_X = 845; // 缝底端 x
// CSS 旋转顺时针为正:缝顶端偏右(1075 > 845)→ 正角度 ≈ +12°
const SEAM_DEG = (Math.atan2(SEAM_TOP_X - SEAM_BOT_X, 1080) * 180) / Math.PI;

export const VersusSlam: React.FC = () => {
  const frame = useCurrentFrame();

  // 两半屏对冲:ease-in 加速,10f 从 ±1200px 冲到位
  const leftX = interpolate(frame, [20, IMPACT], [-1200, 0], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
    easing: Easing.in(Easing.cubic),
  });
  const rightX = -leftX;

  // 撞击帧起:整机震屏 12px 指数衰减(约 5f 收干)
  const since = frame - IMPACT;
  const env = since >= 0 ? 12 * Math.exp(-since / 1.6) : 0;
  const shakeX = env * Math.sin(since * 3.4);
  const shakeY = env * 0.6 * Math.sin(since * 4.1 + 0.7);

  // 白闪:撞击帧 0.9 → 0,3f 收掉
  const flash = interpolate(frame, [IMPACT, IMPACT + 3], [0.9, 0], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
  });

  // "VS" 盖章:scale 1.6 → 1 带 back overshoot,6f 压出
  const vsScale = interpolate(frame, [IMPACT, IMPACT + 6], [1.6, 1], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
    easing: Easing.out(Easing.back(2.6)),
  });
  const vsOpacity = interpolate(frame, [IMPACT, IMPACT + 2], [0, 1], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
  });

  const impacted = frame >= IMPACT;

  return (
    <AbsoluteFill style={{ background: G.bg, overflow: 'hidden' }}>
      <div style={{ position: 'absolute', inset: 0, transform: `translate(${shakeX}px, ${shakeY}px)` }}>
        {/* 建立段的斜缝虚线预示(撞合后被实缝替代) */}
        {!impacted && (
          <svg width={1920} height={1080} style={{ position: 'absolute', inset: 0 }}>
            <line
              x1={SEAM_TOP_X} y1={0} x2={SEAM_BOT_X} y2={1080}
              stroke={G.bar} strokeWidth={4} strokeDasharray="18 16"
            />
          </svg>
        )}
        {/* 左半屏:FakeDashboard A 裁左半,斜边 78° */}
        <div style={{
          position: 'absolute', inset: 0,
          transform: `translateX(${leftX}px)`,
          clipPath: `polygon(0px 0px, ${SEAM_TOP_X}px 0px, ${SEAM_BOT_X}px 1080px, 0px 1080px)`,
        }}>
          <FakeDashboard variant="A" />
        </div>
        {/* 右半屏:FakeDashboard B 裁右半 */}
        <div style={{
          position: 'absolute', inset: 0,
          transform: `translateX(${rightX}px)`,
          clipPath: `polygon(${SEAM_TOP_X}px 0px, 1920px 0px, 1920px 1080px, ${SEAM_BOT_X}px 1080px)`,
        }}>
          <FakeDashboard variant="B" />
        </div>
        {/* 撞合后的实体斜缝条 */}
        {impacted && (
          <div style={{
            position: 'absolute', left: 960 - 6, top: 540 - 700,
            width: 12, height: 1400, background: G.ink,
            transform: `rotate(${SEAM_DEG}deg)`,
          }} />
        )}
        {/* "VS" 字块盖章:贴缝、随缝倾斜 */}
        {impacted && (
          <div style={{
            position: 'absolute', left: 960, top: 540,
            transform: `translate(-50%, -50%) rotate(${SEAM_DEG}deg) scale(${vsScale})`,
            opacity: vsOpacity,
            background: G.card, border: `6px solid ${G.ink}`, borderRadius: 20,
            padding: '18px 46px', boxShadow: '0 18px 60px rgba(0,0,0,0.35)',
          }}>
            <TitleBlock text="VS" size={140} />
          </div>
        )}
      </div>
      {/* 撞击白闪(不随震屏位移) */}
      <AbsoluteFill style={{ background: '#ffffff', opacity: flash, pointerEvents: 'none' }} />
    </AbsoluteFill>
  );
};


  1. Read the recipe
    Prompt = when to use, intention, parameter table with typical values and how each one feels, known pitfalls. Treat values as calibrated starting points.
  2. Get the code
    tool: git
    git clone https://github.com/Vincentwei1021/video-shotcraft && cd video-shotcraft && npm install
  3. Register + render
    tool: remotion
    npx remotion render <CompositionId> out.mp4 # component: demos/transition/transition-hidden-cut/InvisibleCut.tsx, demos/transition/transition-hidden-cut/LightLeakBurn.tsx, demos/transition/transition-hidden-cut/VersusSlam.tsx
  4. Or re-implement
    Port the timing/easing from the recipe to HTML + WAAPI (gimgs motion contract) or any engine; keep the same segment windows and easing.
paramtypedefaultdescription
—

Mais nesta categoria