Motion · Transition

Mosaic reframe

12 tiles continuously morph among three layouts — a regular grid, a feature mosaic, and a diagonal waterfall — position and size each interpolating, with a slight per-tile stagger and a hold between segments.

1920×108016:930 fps6.5s · 195 framesremotionLicense: Apache-2.0#shotcraft#remotion#transition

Source: video-shotcraft (Vincent Wei) ↗ · Apache-2.0 · Remotion composition (React/TSX) — preview video, no in-browser player

When to use

A showcase transition for "the same content, several ways of looking at it": layout-capability displays for portfolio/template-library/photo-album products.

Intention

Let the audience watch "the layout itself thinking": the same 12 pieces of content move from an orderly archival state (grid), to a curated state with hierarchy (feature mosaic), to a state with attitude and motion (diagonal waterfall). The three layouts are three narrative tones, and the morphing itself demonstrates the product's capability.

Duration & energy

  • Duration: About 6.0s (180f@30fps; appear 0–0.6s · A→B 1.6–2.5s · hold · B→C 3.7–4.8s)
  • Energy: Medium (continuous, flowing rearrangement, no peak, a composed mood)

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

意图

让观众看见"布局本身在思考":同样 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)

Reference implementation (Remotion)

  • demos/transition/mosaic-reframe/MosaicReframe.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/transition/mosaic-reframe/MosaicReframe.tsx

The component imports shared fixtures from demos/_fixtures and helpers from assets/lib in the repo; SKILL.md there documents the render workflow.

Everything on this page is also machine-readable. Point your agent at the JSON, or add the gimgs MCP server and ask it to search motion templates.

  1. Fetch the JSON — it holds the shot recipe (timing, easing, parameter table, pitfalls) and the full TSX source.
  2. Clone the video-shotcraft repo; the component imports shared fixtures from demos/_fixtures and helpers from assets/lib.
  3. Register the component as a <Composition> in a Remotion project and render with `npx remotion render`, or re-implement the recipe in your own engine.
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 "Mosaic reframe" (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.0Open raw template ↗
// ===== 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
—

More in this category