> ## Documentation Index
> Fetch the complete documentation index at: /llms.txt
> Use this file to discover all available pages before exploring further.

# Rounded Media Grid

> N-up rounded-corner media grid (2-up, 3-up, 4-up, 3x2, hero plus two): per-cell inside-scale framing, staggered box-in entrance, slow settle

# Rounded Media Grid

N-up rounded-corner media grid (2-up, 3-up, 4-up, 3x2, hero plus two): per-cell inside-scale framing, staggered box-in entrance, slow settle

**Rounded Media Grid**

```html mk-placeholder-grid.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
    <style>
      *,
      *::before,
      *::after {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      body {
        background: transparent;
        overflow: hidden;
      }
      #mk-pg-root {
        /* ---- mk tokens: override in the host to re-skin the family ---- */
        --mk-font: "Inter", -apple-system, sans-serif;
        --mk-ink-dim: #6e6e73;
        --mk-paper: #ffffff;
        --mk-blob-1: #ff7ac8;
        --mk-blob-2: #45d6c8;
        --mk-accent-dark: #7d5cff;
        --mk-blob-1-soft: #ffd3ec;
        --mk-blob-2-soft: #d9fff8;
        --mk-accent-dark-soft: #cabdff;
        --mk-well-warm: #ffb86b;
        --mk-well-warm-soft: #ffe3c2;
        --mk-well-sky: #5cb8ff;
        --mk-well-sky-soft: #cfe9ff;
        --mk-well-rose: #ff8f8f;
        --mk-well-rose-soft: #ffd6d6;
        --mk-well-num: rgba(255, 255, 255, 0.9);
        --mk-radius-card: 40px;
        --mk-shadow: 0 24px 64px rgba(0, 0, 0, 0.16);

        position: relative;
        width: 1920px;
        height: 1080px;
        overflow: hidden;
        background: transparent; /* pair with mk-background beneath for the gradient backdrop */
      }
      .mk-pg-cell {
        position: absolute;
        border-radius: var(--mk-radius-card);
        overflow: hidden;
        background: var(--mk-paper);
        box-shadow: var(--mk-shadow);
      }
      .mk-pg-media {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        object-fit: cover;
      }
      /* empty drop-zone well: soft gradient + index numeral */
      .mk-pg-well {
        position: absolute;
        inset: 0;
        display: flex;
        align-items: center;
        justify-content: center;
      }
      .mk-pg-well-num {
        font-family: var(--mk-font);
        font-weight: 600;
        font-size: 88px;
        letter-spacing: -0.02em;
        color: var(--mk-well-num);
      }
    </style>
  </head>
  <body>
    <div
      id="mk-pg-root"
      data-composition-id="mk-placeholder-grid"
      data-start="0"
      data-duration="8"
      data-width="1920"
      data-height="1080"
    >
      <div id="mk-pg-grid"></div>
      <div
        id="mk-pg-drv"
        class="clip"
        data-start="0"
        data-duration="8"
        data-track-index="0"
        style="position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none"
      ></div>
    </div>
    <script>
      (function () {
        window.__timelines = window.__timelines || {};

        /* ---- published parameters (inspector-style CONFIG) ---- */
        var CONFIG = {
          // no scheme param — scheme-agnostic; re-skin via the --mk-* tokens
          layout: "1+2", // "2up" | "3up" | "4up" | "3x2" | "1+2" (hero left + two stacked)
          margin: 120, // outer margin, px
          gap: 40, // px between cells
          radius: 40, // cell corner radius (rounded-edge look)
          // One entry per cell (in layout order). src: image path, or null for a
          // styled drop-zone well. insideScale: media scale inside the mask —
          // an "inside scale" convention (1 = cover-fit).
          cells: [
            { src: null, insideScale: 1 },
            { src: null, insideScale: 1 },
            { src: null, insideScale: 1 },
          ],
          kenBurns: true, // slow media settle inside the mask
          stagger: 0.15, // "box, box, box" entrance
          animationIn: true,
          animationOut: true,
        };

        /* decorative fills for empty wells (cycled) */
        var WELL_FILLS = [
          "linear-gradient(135deg, var(--mk-blob-1) 0%, var(--mk-blob-1-soft) 100%)",
          "linear-gradient(135deg, var(--mk-blob-2) 0%, var(--mk-blob-2-soft) 100%)",
          "linear-gradient(135deg, var(--mk-accent-dark) 0%, var(--mk-accent-dark-soft) 100%)",
          "linear-gradient(135deg, var(--mk-well-warm) 0%, var(--mk-well-warm-soft) 100%)",
          "linear-gradient(135deg, var(--mk-well-sky) 0%, var(--mk-well-sky-soft) 100%)",
          "linear-gradient(135deg, var(--mk-well-rose) 0%, var(--mk-well-rose-soft) 100%)",
        ];

        var W = 1920,
          H = 1080,
          DUR = 8;

        function rects(layout, m, g) {
          var iw = W - 2 * m,
            ih = H - 2 * m;
          function grid(cols, rows) {
            var cw = (iw - (cols - 1) * g) / cols,
              ch = (ih - (rows - 1) * g) / rows,
              out = [];
            for (var r = 0; r < rows; r++)
              for (var c = 0; c < cols; c++)
                out.push({ x: m + c * (cw + g), y: m + r * (ch + g), w: cw, h: ch });
            return out;
          }
          if (layout === "2up") return grid(2, 1);
          if (layout === "3up") return grid(3, 1);
          if (layout === "4up") return grid(2, 2);
          if (layout === "3x2") return grid(3, 2);
          /* "1+2": hero left (58%), two stacked right */
          var w1 = Math.round((iw - g) * 0.58),
            w2 = iw - g - w1,
            h2 = (ih - g) / 2;
          return [
            { x: m, y: m, w: w1, h: ih },
            { x: m + w1 + g, y: m, w: w2, h: h2 },
            { x: m + w1 + g, y: m + h2 + g, w: w2, h: h2 },
          ];
        }

        var root = document.getElementById("mk-pg-root");
        var grid = document.getElementById("mk-pg-grid");
        var R = rects(CONFIG.layout, CONFIG.margin, CONFIG.gap);

        var cells = [],
          medias = [];
        R.forEach(function (r, i) {
          var conf = CONFIG.cells[i] || {};
          var cell = document.createElement("div");
          cell.id = "mk-pg-cell-" + i;
          cell.className = "mk-pg-cell";
          cell.style.left = r.x + "px";
          cell.style.top = r.y + "px";
          cell.style.width = r.w + "px";
          cell.style.height = r.h + "px";
          cell.style.borderRadius = CONFIG.radius + "px";

          var inner;
          if (conf.src) {
            inner = document.createElement("img");
            inner.className = "mk-pg-media";
            inner.src = conf.src;
          } else {
            inner = document.createElement("div");
            inner.className = "mk-pg-well";
            inner.style.background = WELL_FILLS[i % WELL_FILLS.length];
            var num = document.createElement("span");
            num.className = "mk-pg-well-num";
            num.textContent = String(i + 1);
            inner.appendChild(num);
          }
          inner.id = "mk-pg-inner-" + i;
          inner.setAttribute("data-layout-allow-overflow", ""); // ken-burns scales past the mask by design
          cell.appendChild(inner);
          grid.appendChild(cell);
          cells.push(cell);
          medias.push(inner);

          gsap.set(inner, { scale: conf.insideScale || 1 });
        });

        var tl = gsap.timeline({ paused: true });

        cells.forEach(function (cell, i) {
          var t0 = (CONFIG.animationIn ? 0.3 : 0) + i * CONFIG.stagger;

          if (CONFIG.animationIn) {
            gsap.set(cell, { opacity: 0, scale: 0.92, y: 28 });
            tl.to(cell, { opacity: 1, scale: 1, y: 0, duration: 0.65, ease: "power3.out" }, t0);
          }

          if (CONFIG.kenBurns) {
            var base = (CONFIG.cells[i] && CONFIG.cells[i].insideScale) || 1;
            tl.fromTo(
              medias[i],
              { scale: base * 1.06 },
              { scale: base, duration: DUR - t0 - 0.6, ease: "sine.out" },
              t0,
            );
          }
        });

        /* exit + hard kill */
        if (CONFIG.animationOut) {
          tl.to(grid, { opacity: 0, y: -20, duration: 0.4, ease: "power2.in" }, DUR - 0.5);
        }
        tl.set(root, { visibility: "hidden" }, DUR - 0.02);

        window.__timelines["mk-placeholder-grid"] = tl;
      })();
    </script>
  </body>
</html>
```

Copy npx hyperframes add mk-placeholder-grid to the clipboard

That writes one file: `compositions/mk-placeholder-grid.html`.

## Add it to your video

It runs for 8 seconds at 1920×1080. Paste this into your composition:

```html index.html
<div
  data-composition-id="mk-placeholder-grid"
  data-composition-src="compositions/mk-placeholder-grid.html"
  data-start="0"
  data-duration="8"
  data-track-index="1"
  data-width="1920"
  data-height="1080"
></div>
```

Move it in time with `data-start`. Put it on a different timeline row with
`data-track-index`. See [data attributes](/concepts/data-attributes.md) for the rest.

{/* hf:generated-footer */}

Tagged `placeholder` `media` `grid` `minimal`.

## Related topics

* [Browse the complete Catalog](/catalog.md)
* [Add assets and Catalog items in the browser editor](/studio/assets-and-blocks.md)
* [Put blocks together into one video](/concepts/compositions.md)
