{
  "slug": "mosaic-reframe",
  "title": "Mosaic reframe",
  "tagline": "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.",
  "description": "12 tiles continuously morph among three layouts — a regular grid, a feature mosaic, and a diagonal waterfall — position and size each interpolating, with a sl",
  "category": "transition",
  "tags": [
    "shotcraft",
    "remotion",
    "transition"
  ],
  "tier": "free",
  "license": "Apache-2.0",
  "spec": {
    "width": 1920,
    "height": 1080,
    "fps": 30,
    "duration": 6.5,
    "aspect": "16:9"
  },
  "kind": "remotion",
  "params_schema": {
    "type": "object",
    "properties": {}
  },
  "default_params": {},
  "preview": {
    "poster": "https://gimgs.net/motion/media/mosaic-reframe/poster-968746a748f8.jpg",
    "video": "https://gimgs.net/motion/media/mosaic-reframe/video-67c12d282511.mp4"
  },
  "variants": [
    {
      "key": "mosaic-reframe",
      "label": "mosaic-reframe · Mosaic reframe",
      "description": "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.",
      "use": "",
      "video": "https://gimgs.net/motion/media/mosaic-reframe/video-67c12d282511.mp4",
      "poster": "https://gimgs.net/motion/media/mosaic-reframe/poster-968746a748f8.jpg"
    }
  ],
  "credits": {
    "author": "video-shotcraft (Vincent Wei)",
    "url": "https://github.com/Vincentwei1021/video-shotcraft"
  },
  "page_url": "https://gimgs.net/motion/mosaic-reframe.html",
  "json_url": "https://gimgs.net/motion/mosaic-reframe.json",
  "template_url": "https://gimgs.net/motion/mosaic-reframe/template.html",
  "play_url": null,
  "markdown_url": "https://gimgs.net/motion/mosaic-reframe.md",
  "updated_at": "2026-09-24T07:40:07.892Z",
  "prompt": "## When to use\n\nA showcase transition for \"the same content, several ways of looking at it\": layout-capability displays for portfolio/template-library/photo-album products.\n\n## Intention\n\nLet 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.\n\n## Duration & energy\n\n- Duration: About 6.0s (180f@30fps; appear 0–0.6s · A→B 1.6–2.5s · hold · B→C 3.7–4.8s)\n- Energy: Medium (continuous, flowing rearrangement, no peak, a composed mood)\n\n## Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)\n\n## 意图\n让观众看见\"布局本身在思考\"：同样 12 张内容，从整齐档案态（网格）变成有主次的策展态（feature mosaic），再变成有态度的动态态（对角瀑布）。三段排版是三种叙事语气，变形过程即产品能力。\n\n## 动效核心\n- 三套布局硬编码为坐标表：A=4×3 规则网格；B=6×4 单元格 mosaic（首片占 3×2 大位）；C=对角瀑布 `x=1+i*6.4, y=-7+i*7.6, rot=-15+i*3°` 递增旋转\n- 每片对 `x/y/w/h/rot` 五个通道**独立插值**（`acc` 按段查表 + smoothstep），不走 transform 整体缩放——宽高真实变化，圆角阴影不变形\n- 段窗口 A→B t=0.26–0.42、B→C t=0.62–0.80，之间留 ≥0.2 的 hold 读版面\n- 逐片微 stagger `i*0.007`（约每片错 2 帧）：重排像波浪扫过而非整版闪变\n- 开场逐片浮现：`i*0.012` 错峰 + scale 0.82→1 + opacity（outCubic），首片始终 zIndex 抬高（它是 mosaic 段的主图）\n\n## 参数表\n| 参数 | 典型值 | 调节手感 |\n|------|--------|----------|\n| 段窗口 | 每段变形 0.16–0.18，hold ≥0.2 | hold 是读版面的呼吸位，压缩到 <0.1 三段糊成一段 |\n| 微 stagger | 0.007/片（≈2 帧） | 0 = 整版机械闪变；>0.02 波浪太明显抢过版面本身 |\n| 瀑布参数 | 间距 6.4/7.6%，rot −15°+3°/片 | 旋转递增是\"串\"的灵魂；等角会退化成斜排网格 |\n| mosaic 大位 | 首片 3×2 单元格 | 换 slots 表可重排主次；保证有一块 ≥2×2 的锚点位 |\n| 浮现节奏 | 0.012/片 + 0.14 时长 | 12 片合计约 0.27 进完；作转场用时可砍掉浮现直接从 A 态起 |\n| 瓦片内容 | 渐变底 + 圆点 + 双信息条（占位） | 换真实截图/图片时保留 overflow:hidden 圆角容器，宽高插值不裁坏内容 |\n\n## 已知坑\n- 五通道独立插值意味着**不能**换成 `transform: scale`——宽高动画会引发子元素重排，占位内容用了百分比定位可自适应，换成真实图片要用 `object-fit: cover`\n- C 段瓦片有意越出画框（y 从 −7% 到 91%），画框裁切是构图的一部分，别加 padding \"修复\"\n- 三套坐标表都以 92% 内容区 + 4% 边距为基准，改画幅比例需整表重算\n- 段窗口与 stagger 叠加后末片 B→C 到 0.887 才结束，再加段落需压缩前段而不是顺延（保证 t=1 前全部落定）\n\n## 参考实现\ndemos/transition/mosaic-reframe/\n（MosaicReframe.tsx）\n\n## Reference implementation (Remotion)\n\n- demos/transition/mosaic-reframe/MosaicReframe.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/transition/mosaic-reframe/MosaicReframe.tsx\n\nThe component imports shared fixtures from `demos/_fixtures` and helpers from `assets/lib` in the repo; SKILL.md there documents the render workflow.\n",
  "flow": [
    {
      "step": "Read the recipe",
      "note": "Prompt = when to use, intention, parameter table with typical values and how each one feels, known pitfalls. Treat values as calibrated starting points."
    },
    {
      "step": "Get the code",
      "tool": "git",
      "cmd": "git clone https://github.com/Vincentwei1021/video-shotcraft && cd video-shotcraft && npm install"
    },
    {
      "step": "Register + render",
      "tool": "remotion",
      "cmd": "npx remotion render <CompositionId> out.mp4   # component: demos/transition/mosaic-reframe/MosaicReframe.tsx"
    },
    {
      "step": "Or re-implement",
      "note": "Port the timing/easing from the recipe to HTML + WAAPI (gimgs motion contract) or any engine; keep the same segment windows and easing."
    }
  ],
  "files": [
    {
      "path": "demos/transition/mosaic-reframe/MosaicReframe.tsx",
      "url": "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/transition/mosaic-reframe/MosaicReframe.tsx"
    }
  ],
  "contract": "React/Remotion composition (TSX) from the open-source video-shotcraft library (Apache-2.0). It is not a browser-playable template: clone the repo, register the component in a Remotion project and render with `npx remotion render`. The recipe (prompt) describes timing, easing and parameters so you can also re-implement the shot in any engine.",
  "render": {
    "engine": "remotion",
    "frames": 195,
    "repo": "https://github.com/Vincentwei1021/video-shotcraft",
    "files": [
      "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/transition/mosaic-reframe/MosaicReframe.tsx"
    ],
    "note": "Clone https://github.com/Vincentwei1021/video-shotcraft (npm install). The component lives under demos/{category}/{name}/ and imports shared fixtures from demos/_fixtures and helpers from assets/lib. Copy it (with those imports) into a Remotion project, register a <Composition> with the template's width/height/fps/duration in Root.tsx, then `npx remotion render <CompositionId> out.mp4`. SKILL.md in the repo documents the full Claude Code / Codex workflow. The prompt below is the shot recipe (timing, easing, parameter table, pitfalls) — enough to re-implement the shot in HTML/WAAPI or another engine if you prefer."
  },
  "source": "// ===== demos/transition/mosaic-reframe/MosaicReframe.tsx =====\n// mosaic-reframe — Mosaic Reframe 三段布局重排（motion-lab 定稿转原生 Remotion）\n// 12 张图片瓦片在三种排版间连续变形：4x3 规则网格 → 带一块 2x2 大图的 feature\n// mosaic → 对角线瀑布串（每片 -15°+i*3° 递增旋转）。位置与宽高各自独立插值，\n// 每片按 index 微 stagger，smoothstep 缓动，段间留 hold。\n// 设计坐标 480×270（DesignStage 等比放大），参数表数值以此坐标系标定。\nimport React from 'react';\nimport { DesignStage, E, lerp, rand, seg, useT } from '../../_fixtures/Motion';\n\nexport const MOSAIC_REFRAME_DURATION = 180; // 6000ms @30fps\n\n// smoothstep：段内缓动（原配方即用它替代 E 表）\nconst smooth = (x: number) => x * x * (3 - 2 * x);\n\ntype Box = { x: number; y: number; w: number; h: number; rot: number };\nconst KEYS = ['x', 'y', 'w', 'h', 'rot'] as const;\n\n// 累加式关键帧插值：各段进度独立过 ease 后按差值叠加，天然支持窗间 hold\nconst acc = (t: number, base: Box, kfs: { at: [number, number]; to: Box }[], ease: (x: number) => number): Box => {\n  const out: Box = { ...base };\n  let prev = base;\n  for (const kf of kfs) {\n    const u = seg(t, kf.at[0], kf.at[1], ease);\n    for (const k of KEYS) out[k] += u * (kf.to[k] - prev[k]);\n    prev = kf.to;\n  }\n  return out;\n};\n\n// ---- layout A: 4x3 规则网格 ----\nconst gw = (92 - 3 * 2) / 4, gh = (92 - 2 * 2) / 3;\nconst A: Box[] = Array.from({ length: 12 }, (_, i) => {\n  const c = i % 4, r = (i / 4) | 0;\n  return { x: 4 + c * (gw + 2), y: 4 + r * (gh + 2), w: gw, h: gh, rot: 0 };\n});\n\n// ---- layout B: feature mosaic（6x4 单元格，t0 占 3x2）----\nconst uw = (92 - 5 * 1.2) / 6, uh = (92 - 3 * 1.2) / 4;\nconst SLOTS: [number, number, number, number][] = [\n  [0, 0, 3, 2], [3, 0, 1, 1], [4, 0, 1, 1], [5, 0, 1, 1], [3, 1, 2, 1], [5, 1, 1, 1],\n  [0, 2, 1, 1], [1, 2, 2, 1], [3, 2, 1, 2], [4, 2, 2, 1], [0, 3, 3, 1], [4, 3, 2, 1],\n];\nconst B: Box[] = SLOTS.map(([c, r, cw, rh]) => ({\n  x: 4 + c * (uw + 1.2), y: 4 + r * (uh + 1.2),\n  w: cw * uw + (cw - 1) * 1.2, h: rh * uh + (rh - 1) * 1.2, rot: 0,\n}));\n\n// ---- layout C: 对角线瀑布串 ----\nconst C: Box[] = Array.from({ length: 12 }, (_, i) => ({\n  x: 1 + i * 6.4, y: -7 + i * 7.6, w: 23, h: 27, rot: -15 + i * 3,\n}));\n\nexport const MosaicReframe: React.FC = () => {\n  const t = useT();\n  return (\n    <DesignStage bg=\"#0a0b10\" raster=\"zoom\">\n      {A.map((base, i) => {\n        const hue = 198 + i * 13;\n        const st = i * 0.007; // ≈ index*2 帧微 stagger\n        const v = acc(t, base, [\n          { at: [0.26 + st, 0.42 + st], to: B[i] }, // A → B\n          { at: [0.62 + st, 0.80 + st], to: C[i] }, // hold 后 B → C\n        ], smooth);\n        const pop = seg(t, i * 0.012, i * 0.012 + 0.14, E.outCubic); // 开场逐片浮现\n        return (\n          <div\n            key={i}\n            style={{\n              position: 'absolute',\n              borderRadius: 7,\n              overflow: 'hidden',\n              background: `linear-gradient(${140 + i * 9}deg,hsl(${hue},58%,42%),hsl(${hue + 26},64%,20%))`,\n              boxShadow: `0 8px 22px rgba(0,0,0,.45),inset 0 0 0 1px hsla(${hue},70%,72%,.22)`,\n              left: `${v.x}%`,\n              top: `${v.y}%`,\n              width: `${v.w}%`,\n              height: `${v.h}%`,\n              transform: `rotate(${v.rot}deg) scale(${lerp(pop, 0.82, 1)})`,\n              opacity: pop,\n              zIndex: 10 + (i === 0 ? 5 : 0),\n            }}\n          >\n            {/* 占位\"图片\"内容：一枚圆点 + 两条信息条 */}\n            <div\n              style={{\n                position: 'absolute',\n                left: 9,\n                top: 9,\n                width: 9,\n                height: 9,\n                borderRadius: '50%',\n                background: `hsla(${hue + 40},90%,78%,.95)`,\n                boxShadow: `0 0 10px hsla(${hue + 40},90%,70%,.7)`,\n              }}\n            />\n            <div\n              style={{\n                position: 'absolute',\n                left: 9,\n                bottom: 16,\n                height: 5,\n                width: `${34 + rand(i) * 30}%`,\n                borderRadius: 3,\n                background: 'hsla(0,0%,100%,.6)',\n              }}\n            />\n            <div\n              style={{\n                position: 'absolute',\n                left: 9,\n                bottom: 8,\n                height: 4,\n                width: `${20 + rand(i + 7) * 24}%`,\n                borderRadius: 2,\n                background: 'hsla(0,0%,100%,.28)',\n              }}\n            />\n          </div>\n        );\n      })}\n    </DesignStage>\n  );\n};\n\n\n"
}