Motion · Chuyển cảnh

Ghép lại bố cục mosaic

12 ô mosaic biến hình liên tục giữa ba kiểu bố cục — lưới đều, feature mosaic, và thác chéo — vị trí và kích thước mỗi ô đều nội suy riêng, lệch nhịp nhẹ từng ô, giữa các đoạn có giữ hình.

1920×108016:930 fps6.5s · 195 frameremotionGiấy phép: Apache-2.0#shotcraft#remotion#transition

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

Khi nào dùng

Chuyển cảnh trưng bày kiểu "cùng một lô nội dung, nhiều cách nhìn khác nhau": thể hiện năng lực bố cục cho sản phẩm portfolio/thư viện mẫu/album ảnh.

Ý đồ

Cho khán giả thấy "chính bố cục đang suy nghĩ": cùng 12 nội dung, từ trạng thái lưu trữ ngay ngắn (lưới), biến thành trạng thái tuyển chọn có chính có phụ (feature mosaic), rồi thành trạng thái động có cá tính (thác chéo). Ba kiểu bố cục là ba giọng điệu kể chuyện, quá trình biến hình chính là năng lực sản phẩm.

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

  • Thời lượng: Khoảng 6.0s (180f@30fps; xuất hiện 0–0.6s · A→B 1.6–2.5s · giữ hình · B→C 3.7–4.8s)
  • Năng lượng: Trung bình (sắp xếp lại liên tục, mượt, không đỉnh điểm, khí chất điềm đạm)

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)

意图

让观众看见"布局本身在思考":同样 12 张内容,从整齐档案态(网格)变成有主次的策展态(feature mosaic),再变成有态度的动态态(对角瀑布)。三段排版是三种叙事语气,变形过程即产品能力。

动效核心

  • 三套布局硬编码为坐标表:A=4×3 规则网格;B=6×4 单元格 mosaic(首片占 3×2 大位);C=对角瀑布 x=1+i*6.4, y=-7+i*7.6, rot=-15+i*3° 递增旋转
  • 每片对 x/y/w/h/rot 五个通道独立插值(acc 按段查表 + smoothstep),不走 transform 整体缩放——宽高真实变化,圆角阴影不变形
  • 段窗口 A→B t=0.26–0.42、B→C t=0.62–0.80,之间留 ≥0.2 的 hold 读版面
  • 逐片微 stagger i*0.007(约每片错 2 帧):重排像波浪扫过而非整版闪变
  • 开场逐片浮现:i*0.012 错峰 + scale 0.82→1 + opacity(outCubic),首片始终 zIndex 抬高(它是 mosaic 段的主图)

参数表

| 参数 | 典型值 | 调节手感 | |------|--------|----------| | 段窗口 | 每段变形 0.16–0.18,hold ≥0.2 | hold 是读版面的呼吸位,压缩到 <0.1 三段糊成一段 | | 微 stagger | 0.007/片(≈2 帧) | 0 = 整版机械闪变;>0.02 波浪太明显抢过版面本身 | | 瀑布参数 | 间距 6.4/7.6%,rot −15°+3°/片 | 旋转递增是"串"的灵魂;等角会退化成斜排网格 | | mosaic 大位 | 首片 3×2 单元格 | 换 slots 表可重排主次;保证有一块 ≥2×2 的锚点位 | | 浮现节奏 | 0.012/片 + 0.14 时长 | 12 片合计约 0.27 进完;作转场用时可砍掉浮现直接从 A 态起 | | 瓦片内容 | 渐变底 + 圆点 + 双信息条(占位) | 换真实截图/图片时保留 overflow:hidden 圆角容器,宽高插值不裁坏内容 |

已知坑

  • 五通道独立插值意味着不能换成 transform: scale——宽高动画会引发子元素重排,占位内容用了百分比定位可自适应,换成真实图片要用 object-fit: cover
  • C 段瓦片有意越出画框(y 从 −7% 到 91%),画框裁切是构图的一部分,别加 padding "修复"
  • 三套坐标表都以 92% 内容区 + 4% 边距为基准,改画幅比例需整表重算
  • 段窗口与 stagger 叠加后末片 B→C 到 0.887 才结束,再加段落需压缩前段而不是顺延(保证 t=1 前全部落定)

参考实现

demos/transition/mosaic-reframe/ (MosaicReframe.tsx)

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

  • demos/transition/mosaic-reframe/MosaicReframe.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/transition/mosaic-reframe/MosaicReframe.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/mosaic-reframe.json
git clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/transition/mosaic-reframe/MosaicReframe.tsx
npx remotion render <CompositionId> out.mp4
claude mcp add --transport http gimgs https://gimgs.net/mcp
# then: search_motion_templates / get_motion_template("mosaic-reframe")

Prompt

Use the video-shotcraft shot recipe "Ghép lại bố cục mosaic" (Remotion composition, Apache-2.0) published on gimgs.net.
Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/mosaic-reframe.json
Raw TSX: https://gimgs.net/motion/mosaic-reframe/template.html
Repository: https://github.com/Vincentwei1021/video-shotcraft  (component: demos/transition/mosaic-reframe/MosaicReframe.tsx; imports demos/_fixtures and assets/lib)
Spec: 1920x1080, 30 fps, 6.5s

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

4,343 chars · Apache-2.0Mở template gốc ↗
// ===== demos/transition/mosaic-reframe/MosaicReframe.tsx =====
// mosaic-reframe — Mosaic Reframe 三段布局重排(motion-lab 定稿转原生 Remotion)
// 12 张图片瓦片在三种排版间连续变形:4x3 规则网格 → 带一块 2x2 大图的 feature
// mosaic → 对角线瀑布串(每片 -15°+i*3° 递增旋转)。位置与宽高各自独立插值,
// 每片按 index 微 stagger,smoothstep 缓动,段间留 hold。
// 设计坐标 480×270(DesignStage 等比放大),参数表数值以此坐标系标定。
import React from 'react';
import { DesignStage, E, lerp, rand, seg, useT } from '../../_fixtures/Motion';

export const MOSAIC_REFRAME_DURATION = 180; // 6000ms @30fps

// smoothstep:段内缓动(原配方即用它替代 E 表)
const smooth = (x: number) => x * x * (3 - 2 * x);

type Box = { x: number; y: number; w: number; h: number; rot: number };
const KEYS = ['x', 'y', 'w', 'h', 'rot'] as const;

// 累加式关键帧插值:各段进度独立过 ease 后按差值叠加,天然支持窗间 hold
const acc = (t: number, base: Box, kfs: { at: [number, number]; to: Box }[], ease: (x: number) => number): Box => {
  const out: Box = { ...base };
  let prev = base;
  for (const kf of kfs) {
    const u = seg(t, kf.at[0], kf.at[1], ease);
    for (const k of KEYS) out[k] += u * (kf.to[k] - prev[k]);
    prev = kf.to;
  }
  return out;
};

// ---- layout A: 4x3 规则网格 ----
const gw = (92 - 3 * 2) / 4, gh = (92 - 2 * 2) / 3;
const A: Box[] = Array.from({ length: 12 }, (_, i) => {
  const c = i % 4, r = (i / 4) | 0;
  return { x: 4 + c * (gw + 2), y: 4 + r * (gh + 2), w: gw, h: gh, rot: 0 };
});

// ---- layout B: feature mosaic(6x4 单元格,t0 占 3x2)----
const uw = (92 - 5 * 1.2) / 6, uh = (92 - 3 * 1.2) / 4;
const SLOTS: [number, number, number, number][] = [
  [0, 0, 3, 2], [3, 0, 1, 1], [4, 0, 1, 1], [5, 0, 1, 1], [3, 1, 2, 1], [5, 1, 1, 1],
  [0, 2, 1, 1], [1, 2, 2, 1], [3, 2, 1, 2], [4, 2, 2, 1], [0, 3, 3, 1], [4, 3, 2, 1],
];
const B: Box[] = SLOTS.map(([c, r, cw, rh]) => ({
  x: 4 + c * (uw + 1.2), y: 4 + r * (uh + 1.2),
  w: cw * uw + (cw - 1) * 1.2, h: rh * uh + (rh - 1) * 1.2, rot: 0,
}));

// ---- layout C: 对角线瀑布串 ----
const C: Box[] = Array.from({ length: 12 }, (_, i) => ({
  x: 1 + i * 6.4, y: -7 + i * 7.6, w: 23, h: 27, rot: -15 + i * 3,
}));

export const MosaicReframe: React.FC = () => {
  const t = useT();
  return (
    <DesignStage bg="#0a0b10" raster="zoom">
      {A.map((base, i) => {
        const hue = 198 + i * 13;
        const st = i * 0.007; // ≈ index*2 帧微 stagger
        const v = acc(t, base, [
          { at: [0.26 + st, 0.42 + st], to: B[i] }, // A → B
          { at: [0.62 + st, 0.80 + st], to: C[i] }, // hold 后 B → C
        ], smooth);
        const pop = seg(t, i * 0.012, i * 0.012 + 0.14, E.outCubic); // 开场逐片浮现
        return (
          <div
            key={i}
            style={{
              position: 'absolute',
              borderRadius: 7,
              overflow: 'hidden',
              background: `linear-gradient(${140 + i * 9}deg,hsl(${hue},58%,42%),hsl(${hue + 26},64%,20%))`,
              boxShadow: `0 8px 22px rgba(0,0,0,.45),inset 0 0 0 1px hsla(${hue},70%,72%,.22)`,
              left: `${v.x}%`,
              top: `${v.y}%`,
              width: `${v.w}%`,
              height: `${v.h}%`,
              transform: `rotate(${v.rot}deg) scale(${lerp(pop, 0.82, 1)})`,
              opacity: pop,
              zIndex: 10 + (i === 0 ? 5 : 0),
            }}
          >
            {/* 占位"图片"内容:一枚圆点 + 两条信息条 */}
            <div
              style={{
                position: 'absolute',
                left: 9,
                top: 9,
                width: 9,
                height: 9,
                borderRadius: '50%',
                background: `hsla(${hue + 40},90%,78%,.95)`,
                boxShadow: `0 0 10px hsla(${hue + 40},90%,70%,.7)`,
              }}
            />
            <div
              style={{
                position: 'absolute',
                left: 9,
                bottom: 16,
                height: 5,
                width: `${34 + rand(i) * 30}%`,
                borderRadius: 3,
                background: 'hsla(0,0%,100%,.6)',
              }}
            />
            <div
              style={{
                position: 'absolute',
                left: 9,
                bottom: 8,
                height: 4,
                width: `${20 + rand(i + 7) * 24}%`,
                borderRadius: 2,
                background: 'hsla(0,0%,100%,.28)',
              }}
            />
          </div>
        );
      })}
    </DesignStage>
  );
};


  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/mosaic-reframe/MosaicReframe.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