{
  "slug": "quad-split-parallel-scenes",
  "title": "Quad split parallel scenes",
  "tagline": "A hard-cut 2×2 grid runs four micro-scenes in parallel, with key beats staggered 3–6 frames apart for an information barrage.",
  "description": "A hard-cut 2×2 grid runs four micro-scenes in parallel, with key beats staggered 3–6 frames apart for an information barrage.",
  "category": "rhythm",
  "tags": [
    "shotcraft",
    "remotion",
    "rhythm"
  ],
  "tier": "free",
  "license": "Apache-2.0",
  "spec": {
    "width": 1920,
    "height": 1080,
    "fps": 30,
    "duration": 2.6,
    "aspect": "16:9"
  },
  "kind": "remotion",
  "params_schema": {
    "type": "object",
    "properties": {}
  },
  "default_params": {},
  "preview": {
    "poster": "https://gimgs.net/motion/media/quad-split-parallel-scenes/poster-ce47550b8aad.jpg",
    "video": "https://gimgs.net/motion/media/quad-split-parallel-scenes/video-881e6cd3f93b.mp4"
  },
  "variants": [
    {
      "key": "quad-split-parallel-scenes",
      "label": "quad-split-parallel-scenes",
      "description": "The frame hard-cuts into a 2×2 grid, each of the four quadrants running its own micro-scene in parallel (typing, fast push, word-by-word, an interaction chain), with key beats staggered 3–6 frames apart to create an information barrage.",
      "use": "",
      "video": "https://gimgs.net/motion/media/quad-split-parallel-scenes/video-881e6cd3f93b.mp4",
      "poster": "https://gimgs.net/motion/media/quad-split-parallel-scenes/poster-ce47550b8aad.jpg"
    }
  ],
  "credits": {
    "author": "video-shotcraft (Vincent Wei)",
    "url": "https://github.com/Vincentwei1021/video-shotcraft"
  },
  "page_url": "https://gimgs.net/motion/quad-split-parallel-scenes.html",
  "json_url": "https://gimgs.net/motion/quad-split-parallel-scenes.json",
  "template_url": "https://gimgs.net/motion/quad-split-parallel-scenes/template.html",
  "play_url": null,
  "markdown_url": "https://gimgs.net/motion/quad-split-parallel-scenes.md",
  "updated_at": "2026-09-24T07:40:16.014Z",
  "prompt": "## When to use\n\nA rhythm section for \"lots of features happening at once\" montage; the density peak of a trailer's mid-section\n\n## Intention\n\nReplace sequential display with parallel density: four things happen in front of the viewer at once, too fast to read each one in detail, but every 3–6 frames one quadrant \"moves\" — pinning the scan rhythm firmly in place. This is a technique card: the content inside the panels is entirely swappable, the staggered-beat arrangement is the recipe.\n\n## Duration & energy\n\n- Duration: About 2.1s (63f@30fps, no transitions throughout)\n- Energy: High (four parallel lines + staggered-beat impact, a standard spot for a BGM chorus)\n\n## Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)\n\n## 意图\n用并行密度替代顺序展示：四件事同时在眼前发生，观众来不及逐一细读，但每 3–6 帧就有一个象限\"动一下\"——扫视节奏被牢牢钉住。这是手法卡：格内内容全部可替换，错拍编排才是配方。\n\n## 动效核心\n- 四象限独立场景（内容为示例）：TL 迷你浏览器逐字符打字 + 6 个 tab 依次 outBack 弹入 + 全程 inQuad 慢推 1→1.45；TR mono 打字 + t=0.42–0.54 whip 急推 scale 1→2.1（带 sin 包络 blur 4px）；BL 三词按 0.24/0.46/0.56 逐词 outBack 弹入；BR 五步交互链（pill 滑入→光标贝塞尔巡游→点击缩放→改写文字→卡片弹出）\n- **错拍是灵魂**：TL tab 从 0.08 起每 0.13 一枚、TR 急推 0.42、BL 三词 0.24/0.46/0.56、BR 点击 0.42/0.74——任意相邻事件间隔 3–6 帧，永远有东西在动但从不齐动\n- 两处打字机光标闪烁频率错开（16 帧周期 vs 14 帧周期 +5 相位），避免同闪\n- BR 光标走两段二次贝塞尔（`qBez`）巡游，点击瞬间 `sin(π)` 缩放 0.7 回弹\n- 四格底色深浅交替（#c3c6cc/#f2f1ef/#e7e6e3/#b8bcc3）保证格线可读，无需描边\n\n## 参数表\n| 参数 | 典型值 | 调节手感 |\n|------|--------|----------|\n| 错拍间隔 | 相邻事件 3–6 帧 | <2 帧读作同拍（齐动=呆板）；>8 帧密度散掉，轰炸感消失 |\n| TL 慢推 | inQuad 1→1.45，origin 50% 78% | 全程缓慢加速的\"底噪运动\"，让静格也不静；>1.6 会裁掉 tab 行 |\n| TR 急推 | 0.42–0.54，scale 2.1 + blur 峰值 4px | 这是全卡最重的一拍，压 BGM 重音；blur 包络必须 sin（进出对称）|\n| 打字速度 | TXT1 25 字符 / 0.02–0.95 | 换文案保持字符数近似，否则打字节奏与其他象限错拍关系漂移 |\n| BR 交互链 | 滑入 0.12→巡游 0.3→点击 0.42→打字 0.46→二段巡游 0.62→点击 0.74→卡片 0.8 | 五步环环相扣，改任何一步需顺延后续；卡片 outBack 弹出是链尾重音 |\n| 底色 | 中性灰阶四档交替 | 换项目主题色时保持相邻格明度差 ≥15%，否则格线感消失 |\n\n## 已知坑\n- 这是手法卡：四格内容整体可换（产品截图/录屏/其他动效卡），但**错拍表必须重排**——新内容的关键帧继承原时刻表，否则四格变四个独立视频拼贴\n- 2.1s 是密度上限时长，拉长到 3s+ 时每象限需加第二轮事件，否则后半段\"没东西动\"\n- 光标闪烁走 `floor(t*63)` 帧计算，改 dur 后重新核对两个光标的错相位\n- 四格同时打字/同时弹入是最常见的退化写法——检查方式：逐帧过一遍，任何一帧不应有两个象限同时发生\"重事件\"\n\n## 参考实现\ndemos/rhythm/quad-split-parallel-scenes/\n（QuadSplitParallelScenes.tsx）\n\n## Reference implementation (Remotion)\n\n- demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.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/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.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/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx",
      "url": "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.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": 78,
    "repo": "https://github.com/Vincentwei1021/video-shotcraft",
    "files": [
      "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.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/rhythm/quad-split-parallel-scenes/QuadSplitParallelScenes.tsx =====\n// quad-split-parallel-scenes — Quad Split 四宫并行蒙太奇（motion-lab 定稿转原生 Remotion）\n// 手法卡：画面硬切成 2×2 四宫格，四个象限并行跑各自独立的微场景（格内内容可任意替换，\n// 此处仅为示例）：TL 迷你浏览器打字 + 标签堆积 + 慢推，TR mono 打字 + whip 急推，\n// BL 三词逐个弹入，BR pill 滑入 → 光标贝塞尔飞行点击 → 卡片弹出。\n// 关键节拍互相错开 3-6 帧、全程无转场，靠并行密度制造信息轰炸。\n// 设计坐标 480×270（DesignStage 等比放大），参数以此坐标系标定。\nimport React from 'react';\nimport { DesignStage, E, lerp, seg, useT } from '../../_fixtures/Motion';\n\nexport const QUAD_SPLIT_PARALLEL_SCENES_DURATION = 63; // 2100ms @30fps\n\nconst ACCENT = '#7c5cff';\nconst ACCENT_SOFT = '#c9bcff';\nconst F = 'system-ui,-apple-system,sans-serif';\n// 四宫格底色走中性灰阶（深浅交替保证格线可读），需要主题色时换成项目色板\nconst BGS = ['#c3c6cc', '#f2f1ef', '#e7e6e3', '#b8bcc3'];\nconst TRAFFIC = ['#ff5f57', '#febc2e', '#28c840'];\nconst TABNAMES = ['Tab One', 'Tab Two', 'Tab Three', 'Tab Four', 'Tab Five', 'Tab Six'];\nconst TXT1 = 'Placeholder headline text';\nconst TXT2 = 'and a second line of copy';\nconst WORDS = ['One', 'clear', 'message'];\n\n// 二次贝塞尔取点（BR 象限光标飞行路径，坐标单位 %）\nconst qBez = (a: number[], b: number[], c: number[], t: number): [number, number] => {\n  const u = 1 - t;\n  return [\n    u * u * a[0] + 2 * u * t * b[0] + t * t * c[0],\n    u * u * a[1] + 2 * u * t * b[1] + t * t * c[1],\n  ];\n};\n\n// TL —— 迷你浏览器：逐字符打字 + tab outBack 弹入 + 全程 inQuad 慢推\nconst QuadTL: React.FC<{ t: number; frame: number }> = ({ t, frame }) => {\n  const n1 = Math.floor(seg(t, 0.02, 0.95) * TXT1.length);\n  return (\n    <div\n      style={{\n        position: 'absolute',\n        left: '10%',\n        top: '22%',\n        width: '80%',\n        height: '60%',\n        background: '#fff',\n        borderRadius: 10,\n        boxShadow: '0 8px 24px rgba(20,40,80,.25)',\n        fontFamily: F,\n        transform: `scale(${lerp(E.inQuad(t), 1, 1.45)})`,\n        transformOrigin: '50% 78%',\n      }}\n    >\n      <div style={{ display: 'flex', alignItems: 'center', gap: 5, padding: '8px 10px 4px' }}>\n        {TRAFFIC.map((c) => (\n          <i key={c} style={{ width: 7, height: 7, borderRadius: '50%', background: c }} />\n        ))}\n        <div style={{ display: 'flex', flex: 1, gap: 3, marginLeft: 6, minWidth: 0 }}>\n          {TABNAMES.map((n, i) => {\n            const k = seg(t, 0.08 + i * 0.13, 0.08 + i * 0.13 + 0.09, E.outBack);\n            return (\n              <div\n                key={n}\n                style={{\n                  flex: 1,\n                  minWidth: 0,\n                  overflow: 'hidden',\n                  whiteSpace: 'nowrap',\n                  fontSize: 8,\n                  color: '#555',\n                  background: '#e8eaee',\n                  borderRadius: '5px 5px 0 0',\n                  padding: '2px 5px',\n                  transform: `scale(${k})`,\n                }}\n              >\n                {n}\n              </div>\n            );\n          })}\n        </div>\n      </div>\n      <div\n        style={{\n          margin: '6px 10px',\n          height: 22,\n          borderRadius: 11,\n          background: '#f0f2f5',\n          display: 'flex',\n          alignItems: 'center',\n          padding: '0 10px',\n          fontSize: 10,\n          color: '#333',\n        }}\n      >\n        <b style={{ color: '#8a8f98', marginRight: 6 }}>◆</b>\n        <span>{TXT1.slice(0, n1)}</span>\n        {/* 光标按帧闪烁：16 帧一个周期 */}\n        <i style={{ width: 1, height: 12, background: '#333', marginLeft: 1, opacity: frame % 16 < 8 ? 1 : 0 }} />\n      </div>\n    </div>\n  );\n};\n\n// TR —— mono 打字 + whip 急推（错拍：0.42-0.54，推近时带运动模糊）\nconst QuadTR: React.FC<{ t: number; frame: number }> = ({ t, frame }) => {\n  const n2 = Math.floor(seg(t, 0.06, 0.9) * TXT2.length);\n  const zip = seg(t, 0.42, 0.54, E.inOutCubic);\n  return (\n    <div\n      style={{\n        position: 'absolute',\n        inset: 0,\n        fontFamily: '\"SF Mono\",Menlo,monospace',\n        transform: `scale(${lerp(zip, 1, 2.1)})`,\n        transformOrigin: '46% 42%',\n        filter: `blur(${Math.sin(zip * Math.PI) * 4}px)`,\n      }}\n    >\n      <div\n        style={{\n          position: 'absolute',\n          left: '12%',\n          top: '24%',\n          width: '76%',\n          background: '#fbf8f1',\n          borderRadius: 8,\n          boxShadow: '0 6px 20px rgba(0,0,0,.12)',\n          padding: '8px 12px 14px',\n          // 原渲染无全局 border-box：76% 是内容宽，padding 外扩（Remotion 注入\n          // 了 * { box-sizing:border-box }，显式还原 content-box 才对得上原片）\n          boxSizing: 'content-box',\n        }}\n      >\n        <div style={{ display: 'flex', gap: 4, marginBottom: 6 }}>\n          {TRAFFIC.map((c) => (\n            <i key={c} style={{ width: 6, height: 6, borderRadius: '50%', background: c }} />\n          ))}\n        </div>\n        <div style={{ fontSize: 8, color: '#8a8f98', marginBottom: 5 }}>✦ Section label ›</div>\n        <div style={{ fontSize: 11, color: '#111' }}>\n          <span>{TXT2.slice(0, n2)}</span>\n          {/* 光标错拍闪烁：与 TL 相位差 5 帧、周期 14 帧 */}\n          <span style={{ opacity: (frame + 5) % 14 < 7 ? 1 : 0 }}>_</span>\n        </div>\n      </div>\n    </div>\n  );\n};\n\n// BL —— 三词逐个 outBack 弹入（0.24 / 0.46 / 0.56，与其他象限错开）\nconst QuadBL: React.FC<{ t: number }> = ({ t }) => (\n  <div\n    style={{\n      position: 'absolute',\n      inset: 0,\n      display: 'flex',\n      alignItems: 'center',\n      justifyContent: 'center',\n      gap: 7,\n      fontFamily: F,\n      fontWeight: 800,\n      fontSize: 19,\n      color: '#1a1a1a',\n    }}\n  >\n    {WORDS.map((w, i) => {\n      const k = seg(t, [0.24, 0.46, 0.56][i], [0.24, 0.46, 0.56][i] + 0.1, E.outBack);\n      return (\n        <span\n          key={w}\n          style={{\n            transform: `scale(${k}) translateY(${(1 - k) * 8}px)`,\n            opacity: Math.min(1, k * 2),\n          }}\n        >\n          {w}\n        </span>\n      );\n    })}\n  </div>\n);\n\n// BR —— 五步交互：pill 滑入 → 光标贝塞尔飞行 → 点击缩放 → 打字回复 → 卡片弹出\nconst QuadBR: React.FC<{ t: number }> = ({ t }) => {\n  const slide = seg(t, 0.12, 0.3, E.outBack);\n  const m1 = seg(t, 0.3, 0.42, E.inOutCubic);\n  const m2 = seg(t, 0.62, 0.74, E.inOutCubic);\n  // 光标路径：先飞向 pill，再二段飞向发送键\n  const p = m2 > 0 ? qBez([44, 66], [66, 52], [82, 68], m2) : qBez([88, 30], [50, 40], [44, 66], m1);\n  const c1 = seg(t, 0.42, 0.47);\n  const c2 = seg(t, 0.74, 0.79);\n  const n4 = Math.floor(seg(t, 0.46, 0.62) * 9);\n  const pop = seg(t, 0.8, 0.88, E.outBack);\n  return (\n    <div style={{ position: 'absolute', inset: 0, fontFamily: F }}>\n      {/* 评论卡片：点击发送后弹出 */}\n      <div\n        style={{\n          position: 'absolute',\n          left: '12%',\n          bottom: '46%',\n          width: '66%',\n          background: 'rgba(255,255,255,.92)',\n          borderRadius: 8,\n          padding: '6px 9px',\n          boxSizing: 'content-box', // 同上：66% 为内容宽\n          fontSize: 8,\n          color: '#222',\n          transform: `scale(${pop})`,\n          transformOrigin: '20% 100%',\n          boxShadow: '0 5px 16px rgba(20,40,90,.25)',\n        }}\n      >\n        <b>You · just now</b>\n        <br />\n        All good!\n      </div>\n      {/* 输入 pill：从右侧滑入 */}\n      <div\n        style={{\n          position: 'absolute',\n          left: '8%',\n          bottom: '26%',\n          width: '84%',\n          height: 26,\n          borderRadius: 13,\n          background: 'rgba(255,255,255,.55)',\n          backdropFilter: 'blur(6px)',\n          display: 'flex',\n          alignItems: 'center',\n          padding: '0 8px',\n          boxSizing: 'content-box', // 同上：84% 为内容宽\n          gap: 6,\n          fontSize: 8,\n          boxShadow: '0 4px 14px rgba(20,40,90,.2)',\n          transform: `translateX(${(1 - slide) * 120}%)`,\n          marginBottom: -pop * 4,\n        }}\n      >\n        <span style={{ background: ACCENT, color: '#fff', borderRadius: 8, padding: '1px 5px' }}>00:00</span>\n        <span style={{ flex: 1, color: t < 0.44 ? '#666' : '#111' }}>\n          {t < 0.44 ? 'Leave your comment...' : 'All good!'.slice(0, n4)}\n        </span>\n        <span style={{ color: n4 >= 9 ? ACCENT : ACCENT_SOFT }}>➤</span>\n      </div>\n      {/* 光标圆点：两段点击各缩一次 */}\n      <div\n        style={{\n          position: 'absolute',\n          width: 9,\n          height: 9,\n          borderRadius: '50%',\n          background: '#fff',\n          border: '1.5px solid #333',\n          zIndex: 5,\n          boxShadow: '0 1px 4px rgba(0,0,0,.3)',\n          left: `${p[0]}%`,\n          top: `${p[1]}%`,\n          transform: `scale(${1 - Math.sin(c1 * Math.PI) * 0.3 - Math.sin(c2 * Math.PI) * 0.3})`,\n        }}\n      />\n    </div>\n  );\n};\n\nexport const QuadSplitParallelScenes: React.FC = () => {\n  const t = useT();\n  const frame = Math.floor(t * 63); // dur 2100ms @30fps\n  const scenes = [\n    <QuadTL key={0} t={t} frame={frame} />,\n    <QuadTR key={1} t={t} frame={frame} />,\n    <QuadBL key={2} t={t} />,\n    <QuadBR key={3} t={t} />,\n  ];\n  return (\n    <DesignStage bg=\"#000\" raster=\"zoom\">\n      {scenes.map((scene, i) => (\n        <div\n          key={i}\n          style={{\n            position: 'absolute',\n            left: `${(i % 2) * 50}%`,\n            top: `${(i >> 1) * 50}%`,\n            width: '50%',\n            height: '50%',\n            overflow: 'hidden',\n            background: BGS[i],\n          }}\n        >\n          {scene}\n        </div>\n      ))}\n    </DesignStage>\n  );\n};\n\n\n"
}