Motion · Nhịp & montage

Ngắt nhịp điệu

Hai kiểu ngắt nhịp: jump-cut-punch-in đẩy máy cắt nhảy ba bậc, và strobe-black-frames chớp khung hình đen.

1920×108016:930 fps4.54s · 136 frameremotionGiấy phép: Apache-2.0#shotcraft#remotion#rhythm

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ể

jump-cut-punch-in
transform-origin ghim vào tâm mục tiêu, scale nhảy bậc qua ba mức (không có tween), mỗi lần nhảy kèm rung nhấn đậm 2f làm tick.
Tiến sát chỉ số cốt lõi từng bậc; kiểu ghim mắt phong cách phim tài liệu
strobe-black-frames
Khung hình đen toàn màn hình chớp theo bảng số khung hình định sẵn (mỗi lần 2f, khoảng cách thu hẹp từ 8f xuống 3f), lần chớp cuối mở ra là cắt cứng phóng to an vị luôn.
Đếm ngược tích áp lực trước cao trào cao nhất toàn phim

Khi nào dùng

Dùng chính "phá vỡ tính liên tục" làm bộ đếm nhịp: đẩy máy giật cục (B), tiến sát nghẹt thở (C); bổ trợ cho beat-cut-moves (sắp xếp điểm cắt) và montage-rhythm (nhịp thở đoạn phim)

Ý đồ

Các thẻ nhịp điệu khác trong kho đều lo "cắt thế nào, cắt dày đến đâu"; hai kiểu này lo ngắt thế nào — người xem mong đợi sự liên tục, còn ta cố tình phá vỡ nó, cách phá vỡ chính là thông điệp. B ngắt về không gian — cùng một bố cục nhảy ba lần không có chuyển tiếp (1x→1.6x→2.6x), cú giật kiểu jump-cut của Godard, mang cảm giác ra lệnh "nhìn đây, gần hơn nữa, chính là nó" rõ hơn một cú đẩy máy liền mạch; C ngắt về sự tồn tại — hình ảnh và màu đen thuần túy chớp xen kẽ với khoảng cách ngày càng ngắn lại, một cuộc đếm ngược nghẹt thở trước cao trào. Chọn theo mục đích: buộc tập trung vào một chỉ số dùng B, tích áp lực trước cao trào dùng C.

Thời lượng & năng lượng

  • Thời lượng: B ~4.5s / C ~4.5s
  • Năng lượng: B Trung bình / C Cao

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)

意图

库内节奏卡管的都是"怎么切、切多密";这两式管怎么断——观众预期 连续,你偏打断,打断方式即表达:B 是空间断——同构图三次无补间跳大 (1x→1.6x→2.6x),戈达尔跳切的顿挫,比连续推近更有"看这里、再近点、 就是它"的指令感;C 是存在断——画面与纯黑交替频闪且间隔收紧, 高潮前的窒息倒数。选型:强制聚焦指标用 B,高潮前蓄压用 C。

两式选型

| 式 | 做法 | 适用 | |----|------|------| | B jump-cut-punch-in | transform-origin 钉目标中心,三档 scale 阶梯跳变(零补间),每跳 2f 加深脉冲当 tick | 逐级逼近核心指标;纪录片式盯住 | | C strobe-black-frames | 全屏黑帧按写死帧号表闪现(每次 2f,间隔 8f→3f 收敛),末闪掀开即硬切放大落定 | 全片最高潮前的倒数蓄压 |

参数表

| 参数 | 典型值 | 调节手感 | |------|--------|----------| | B 跳挡 | 1.0→1.6→2.6,各 hold ≥35f | 挡差 <1.5× 读作画面抖了一下 | | B tick | 跳变帧起 2f brightness 0.92 全画面脉冲 | 无 tick 的跳切读作丢帧 | | C 帧号表 | [40,48,55,61,66,70,73,76,79] 各 2f 纯黑 | 间隔必须收敛;等距频闪只是闪没有"逼近" | | C 落锤 | 末闪掀开一帧到位 scale 1.35 + 2f 加深脉冲 | 掀开后还在原构图,频闪就白憋了 | | 收尾 | B 末挡 ≥45f / C 硬切后 ≥50f 真静止 | 打断系事后 hold 从重给 |

已知坑

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

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

  • 两式与 speed-ramp-freeze 都动"时间轴",同一镜头只能有一个时间

操纵者

  • C 式光敏警示:频闪画面需注意光敏性癫痫观众提示;且必须配乐

渐强同步(无声频闪读作信号故障),全片 ≤1 次

  • B 式三挡构图必须同 origin(钉死目标中心)——每挡重新构图就是

三个镜头,不是跳切

  • 声音强依赖:B 每跳一声 tick、C 每闪一声打点(sound-design §4.5)

参考实现

demos/rhythm/rhythm-interrupt-moves/ (JumpCutPunchIn.tsx / StrobeBlackFrames.tsx)

Mã nguồn tham chiếu (Remotion)

  • demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx
  • demos/rhythm/rhythm-interrupt-moves/StrobeBlackFrames.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/rhythm/rhythm-interrupt-moves/StrobeBlackFrames.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.

  1. 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.
  2. Clone repo video-shotcraft; component import fixture chung từ demos/_fixtures và helper từ assets/lib.
  3. Đă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/rhythm-interrupt-moves.json
git clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx, demos/rhythm/rhythm-interrupt-moves/StrobeBlackFrames.tsx
npx remotion render <CompositionId> out.mp4
claude mcp add --transport http gimgs https://gimgs.net/mcp
# then: search_motion_templates / get_motion_template("rhythm-interrupt-moves")

Prompt

Use the video-shotcraft shot recipe "Ngắt nhịp điệu" (Remotion composition, Apache-2.0) published on gimgs.net.
Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/rhythm-interrupt-moves.json
Raw TSX: https://gimgs.net/motion/rhythm-interrupt-moves/template.html
Repository: https://github.com/Vincentwei1021/video-shotcraft  (component: demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx, demos/rhythm/rhythm-interrupt-moves/StrobeBlackFrames.tsx; imports demos/_fixtures and assets/lib)
Spec: 1920x1080, 30 fps, 4.54s

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

5,283 chars · Apache-2.0Mở template gốc ↗
// ===== demos/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx =====
// 三级跳切推近(jump-cut-punch-in)——节奏剪辑|戈达尔跳切/纪录片 punch-in。
// FakeDashboard A 固定构图,transform-origin 钉在第 2 行中间卡中心
// (1070px, 817px)。三次无补间硬切逐级放大:刻意零 interpolate,
// 切换帧一帧到位。每次跳切帧叠 2f 整画面 brightness 0.92 加深脉冲当 tick。
// 关键帧:0–34 scale 1.0 hold → 帧 35 直跳 1.6(35–36 加深脉冲)→ hold →
// 帧 70 直跳 2.6(70–71 加深脉冲)→ 72–134 全静止(63f ≥45f)。
import React from 'react';
import { useCurrentFrame } from 'remotion';
import { G, FakeDashboard, TitleBlock } from '../../_fixtures/Fixtures';

// 目标卡片(3×2 网格第 2 行中间卡)几何:
// 侧栏 220 + 内边距 36;卡宽 (1920-220-72-56)/3 = 524.67,卡高 (1080-72-72-28)/2 = 454
const CARD_L = 220 + 36 + 524.67 + 28; // ≈808.67
const CARD_T = 72 + 36 + 454 + 28; // 590
const CARD_W = 524.67;
const CARD_H = 454;
const ORIGIN_X = CARD_L + CARD_W / 2; // ≈1071
const ORIGIN_Y = CARD_T + CARD_H / 2; // 817

// 三级硬切:零补间,帧 35 / 帧 70 一帧到位
const scaleAt = (f: number): number => (f < 35 ? 1.0 : f < 70 ? 1.6 : 2.6);

// 跳切帧 2f 加深脉冲(整画面 brightness 0.92)
const pulseAt = (f: number): number =>
  (f >= 35 && f <= 36) || (f >= 70 && f <= 71) ? 0.92 : 1;

export const JumpCutPunchIn: React.FC = () => {
  const frame = useCurrentFrame();
  const s = scaleAt(frame);
  const b = pulseAt(frame);

  return (
    <div
      style={{
        width: 1920,
        height: 1080,
        background: G.bg,
        position: 'relative',
        overflow: 'hidden',
        filter: `brightness(${b})`,
      }}
    >
      <div
        style={{
          position: 'absolute',
          inset: 0,
          transform: `scale(${s})`,
          transformOrigin: `${ORIGIN_X}px ${ORIGIN_Y}px`,
        }}
      >
        <FakeDashboard variant="A" />
        {/* 目标卡片标记:随构图一起缩放,提示 punch-in 落点 */}
        <div
          style={{
            position: 'absolute',
            left: CARD_L - 10,
            top: CARD_T - 10,
            width: CARD_W + 20,
            height: CARD_H + 20,
            border: `3px dashed ${G.mid}`,
            borderRadius: 20,
            boxSizing: 'border-box',
          }}
        />
      </div>
      {/* 标签不随缩放,固定左上角 */}
      <div style={{ position: 'absolute', left: 260, top: 20 }}>
        <TitleBlock text="JUMP CUT PUNCH-IN" size={54} />
      </div>
    </div>
  );
};


// ===== demos/rhythm/rhythm-interrupt-moves/StrobeBlackFrames.tsx =====
// 频闪黑帧(strobe-black-frames)——节奏剪辑|VJ strobe / 剪映闪黑。
// FakeDashboard A 全程缓慢推近蓄张力(scale 1.0→1.05,Easing.in(quad),
// 越到后段越快)。40–80f 频闪窗:全屏纯黑 #0c0c0c 按写死帧号表闪现,
// 每次持续 2f,间隔从 8f 收敛到 3f,窒息感逐渐逼近。最后一闪盖住 79–80,
// 帧 81 掀开时构图已硬切到 scale 1.35 对准第 2 行中间卡(零补间一帧到位),
// 叠 2f brightness 0.88 加深脉冲当落锤。
// 关键帧:0–78 推近 1.0→~1.05 → 黑闪 [40,48,55,61,66,70,73,76,79](各 2f)→
// 79–80 全黑 → 帧 81 硬切 scale 1.35(81–82 加深脉冲)→ 83–134 全静止(52f ≥50f)。
// 光敏警示:实战建议配乐渐强使用。
import React from 'react';
import { useCurrentFrame, interpolate, Easing } from 'remotion';
import { G, FakeDashboard, TitleBlock } from '../../_fixtures/Fixtures';

// punch-in 落点:3×2 网格第 2 行中间卡中心(同 JumpCutPunchIn 几何)
// 侧栏 220 + 内边距 36;卡宽 (1920-220-72-56)/3 ≈ 524.67,卡高 (1080-72-72-28)/2 = 454
const CARD_L = 220 + 36 + 524.67 + 28; // ≈808.67
const CARD_T = 72 + 36 + 454 + 28; // 590
const CARD_W = 524.67;
const CARD_H = 454;
const ORIGIN_X = CARD_L + CARD_W / 2; // ≈1071
const ORIGIN_Y = CARD_T + CARD_H / 2; // 817

// 黑闪帧号表(写死):间隔 8→7→6→5→4→3→3→3,每次持续 2f(f0 与 f0+1)
const FLASHES = [40, 48, 55, 61, 66, 70, 73, 76, 79];

const isBlack = (f: number): boolean =>
  FLASHES.some((f0) => f >= f0 && f <= f0 + 1);

// 帧 81 前缓慢推近(Easing.in 蓄力),81 起零补间硬切 1.35 定住
const scaleAt = (f: number): number =>
  f < 81
    ? interpolate(f, [0, 80], [1.0, 1.05], {
        extrapolateLeft: 'clamp',
        extrapolateRight: 'clamp',
        easing: Easing.in(Easing.quad),
      })
    : 1.35;

// 落锤:81–82 两帧整画面加深脉冲
const pulseAt = (f: number): number => (f >= 81 && f <= 82 ? 0.88 : 1);

export const StrobeBlackFrames: React.FC = () => {
  const frame = useCurrentFrame();
  const s = scaleAt(frame);
  const b = pulseAt(frame);
  const black = isBlack(frame);

  return (
    <div
      style={{
        width: 1920,
        height: 1080,
        background: G.bg,
        position: 'relative',
        overflow: 'hidden',
        filter: `brightness(${b})`,
      }}
    >
      <div
        style={{
          position: 'absolute',
          inset: 0,
          transform: `scale(${s})`,
          transformOrigin: `${ORIGIN_X}px ${ORIGIN_Y}px`,
        }}
      >
        <FakeDashboard variant="A" />
        {/* 落点卡片标记:随构图一起缩放,提示硬切对准的核心卡 */}
        <div
          style={{
            position: 'absolute',
            left: CARD_L - 10,
            top: CARD_T - 10,
            width: CARD_W + 20,
            height: CARD_H + 20,
            border: `3px dashed ${G.mid}`,
            borderRadius: 20,
            boxSizing: 'border-box',
          }}
        />
      </div>
      {/* 标签不随缩放,固定顶栏位置 */}
      <div style={{ position: 'absolute', left: 260, top: 20 }}>
        <TitleBlock text="STROBE BLACK FRAMES" size={54} />
      </div>
      {/* 全屏黑闪层:盖住一切(含标签),每次 2f */}
      {black && (
        <div
          style={{
            position: 'absolute',
            inset: 0,
            background: '#0c0c0c',
            zIndex: 10,
          }}
        />
      )}
    </div>
  );
};


  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/rhythm/rhythm-interrupt-moves/JumpCutPunchIn.tsx, demos/rhythm/rhythm-interrupt-moves/StrobeBlackFrames.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
—

Cùng danh mục