Motion · Data
Radial Grid Build & Colorize
An 8×7 card grid grows ring by ring from the center to fill up (mixed initials/icons/image placeholders), then ~15% of cards randomly turn red to flag anomalies, with a title legend anchored center.
Source: video-shotcraft (Vincent Wei) ↗ · Apache-2.0 · Remotion composition (React/TSX) — preview video, no in-browser player
When to use
Data narrative for "anomalies/highlights emerging from a crowd": user base health, monitoring dashboards, batch-status overviews.
Intention
A two-act structure: Act 1, "the group forms" — cards grow ring by ring from the center, like a colony growing under a microscope; Act 2, "anomalies surface" — once filled, individual cards turn red one after another, forcing the viewer's eye to scan the whole field for red dots. It turns the line "we watch over every item for you" into an experience.
Duration & energy
- Duration: About 5.6s (168f@30fps; fill 0.5–1.7s · coloring 1.7–3.4s, staggered).
- Energy: Medium (the build phase has rhythm; the coloring phase is a quiet "discovery" moment).
Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)
意图
两幕结构:第一幕"群体成形"——卡片从中心一环环长出,像镜头下的菌落生长;第二幕"异常浮现"——铺满后个别卡片陆续变红,观众的眼睛被迫扫描全场找红点。它把"我们帮你盯着所有项"这句话拍成了体验。
动效核心
- 分环 stagger:每格按
ring = round(hypot((c-3.5), (r-3)/0.85))算环号,延迟(ring*4 + rand*3)/TOTAL——同环内再加 3 帧随机抖动,生长波有机不机械 - 卡片入场只做 opacity(0.018 窗口)+ scale 0.8→1(0.03,outQuad),无位移——"长出来"而不是"飞进来"
- 卡片内容三种占位混合(
rand(i*9.1)决定):首字母对(logo 位)、几何图标符(◆▲●✦)、渐变色块(图片位)——实际使用换项目素材(头像/logo/缩略图均可) - 中央 3×6 区域
visibility:hidden占位不销毁——网格完整性保留,给标题和图例腾出舞台 - 染色幕:15% 的卡片(
rand<0.15)在 t=0.30–0.60 随机时刻各自 0.036 窗口染色——白底→浅红 #FDECEC、描边→#F6CFCF、状态点绿→红,三通道同拍 mix - 标题 0.02–0.10 先入(scale 0.98→1),图例(Active/Pending/Inactive 三色点)0.26 跟进
参数表
| 参数 | 典型值 | 调节手感 | |------|--------|----------| | 生长速度 | 每 4 帧一环 + 3 帧抖动,1.2s 铺满 | 快于 3 帧/环读作"闪现";抖动砍掉后波前整齐得像机器 | | 异常比例 | 15% | <8% 观众可能漏看;>25% "异常"变"普遍",叙事反转 | | 染色窗口 | 每张 0.036,散布在 0.30–0.60 | 全部同拍染色是警报不是浮现;散布区间越长"陆续发现"感越强 | | 状态色 | 绿 #37C46B → 红 #F0453A(点),底 #FDECEC | 功能色不随品牌换;底色染红别深过 #F8D8D8,卡片文字要仍可读 | | 网格规模 | 8×7 − 中央 18 格 = 38 张可见 | 更大网格需同步缩 gap 和字号;中央留空区随标题长度调 | | 内容混合比 | 首字母/图标/图片 各 1/3(rand 均分) | 全换成同类(如全头像)也成立;混合版本更像"多类型资产"场景 |
已知坑
- 中央留空用
visibility:hidden而不是不渲染——删格子会让分环计算的环心偏移,生长波变形 - 染色的三个通道(底/描边/点)必须同一条 cT 曲线驱动,分开会出现"点红了底还白"的中间态
- 图片占位是 CSS 渐变色块,换真实图片时保留
overflow:hidden和 border-radius 继承,注意深色图上状态点要加白描边 - 标题/图例 z-index 在卡片之上但无底板,若换更密的网格需给中央区加半透明底垫保证可读
参考实现
demos/data/avatar-grid-radial-build-colorize/ (AvatarGridRadialBuildColorize.tsx)
Reference implementation (Remotion)
- demos/data/avatar-grid-radial-build-colorize/AvatarGridRadialBuildColorize.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/data/avatar-grid-radial-build-colorize/AvatarGridRadialBuildColorize.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.
- Fetch the JSON — it holds the shot recipe (timing, easing, parameter table, pitfalls) and the full TSX source.
- Clone the video-shotcraft repo; the component imports shared fixtures from demos/_fixtures and helpers from assets/lib.
- 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/avatar-grid-radial-build-colorize.jsongit clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/data/avatar-grid-radial-build-colorize/AvatarGridRadialBuildColorize.tsx
npx remotion render <CompositionId> out.mp4claude mcp add --transport http gimgs https://gimgs.net/mcp
# then: search_motion_templates / get_motion_template("avatar-grid-radial-build-colorize")Prompt
Use the video-shotcraft shot recipe "Radial Grid Build & Colorize" (Remotion composition, Apache-2.0) published on gimgs.net. Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/avatar-grid-radial-build-colorize.json Raw TSX: https://gimgs.net/motion/avatar-grid-radial-build-colorize/template.html Repository: https://github.com/Vincentwei1021/video-shotcraft (component: demos/data/avatar-grid-radial-build-colorize/AvatarGridRadialBuildColorize.tsx; imports demos/_fixtures and assets/lib) Spec: 1920x1080, 30 fps, 6.1s 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).
// ===== demos/data/avatar-grid-radial-build-colorize/AvatarGridRadialBuildColorize.tsx =====
// avatar-grid-radial-build-colorize — Avatar Grid 分环生长随机染色(motion-lab 定稿转原生 Remotion)
// 8×7 小卡片网格由中心向四周分环生长(每 4 帧扩一环,1.2s 铺满),卡片内容混合三种占位:
// 首字母 / 图标符 / 色块缩略图,只做 opacity + scale 0.8→1 不位移;铺满后约 15% 的卡片
// 在 1s 内随机时刻把底色染成浅红、状态点转红,形成"异常项逐渐浮现"的呼吸感。
// 中央 3×6 区域 visibility:hidden 占位留给标题与图例,标题层始终 100% 不透明。
// 设计坐标 480×270(DesignStage 等比放大),参数表数值以此坐标系标定。
import React from 'react';
import { DesignStage, E, lerp, rand, seg, useT } from '../../_fixtures/Motion';
export const AVATAR_GRID_RADIAL_BUILD_COLORIZE_DURATION = 168; // 5600ms @30fps
const PAPER = '#F3F3F1';
const INK = '#111113';
const MID = '#8A8A8F';
const CARD_WHITE = '#ffffff';
const FLAG_BG = '#FDECEC';
// 颜色插值(effect.js 的 mix;hex2rgb 原来自 lab 页面全局,这里内联实现)
const hex2rgb = (hex: string): [number, number, number] => [
parseInt(hex.slice(1, 3), 16),
parseInt(hex.slice(3, 5), 16),
parseInt(hex.slice(5, 7), 16),
];
const mix = (a: string, b: string, t: number) => {
const A = hex2rgb(a);
const B = hex2rgb(b);
return `rgb(${Math.round(A[0] + (B[0] - A[0]) * t)},${Math.round(A[1] + (B[1] - A[1]) * t)},${Math.round(
A[2] + (B[2] - A[2]) * t,
)})`;
};
const COLS = 8;
const ROWS = 7;
const TOTAL = 5.6 * 30; // 总帧数(delay 换算用)
// 网格几何:等价 effect.js 的 inset:16px + gap:10px CSS grid,但改为绝对定位手排。
// CSS grid 在 480×270 设计坐标下会把轨道取整到整像素(放大 4 倍后节距 140/144 交替),
// 与原片的全分辨率均匀分布不符;小数设计坐标 + 绝对定位可保住亚像素节距。
const GAP = 10;
const CELL_W = (480 - 32 - (COLS - 1) * GAP) / COLS; // 47.25
const CELL_H = (270 - 32 - (ROWS - 1) * GAP) / ROWS; // ≈25.43
// 卡片内容三种占位:首字母(logo 位) / 图标符 / 色块缩略图(图片位),实际使用换项目素材
const INI = ['VS', 'KJ', 'EM', 'AL', 'TR', 'MN', 'BQ', 'DW', 'RC', 'SF', 'PL', 'GH'];
const ICONS = ['◆', '▲', '●', '■', '✦', '◐', '❖', '▣'];
// 每格的静态参数(种子与 effect.js 逐一对应,跨帧确定)
const CELLS = Array.from({ length: ROWS * COLS }, (_, i) => {
const r = Math.floor(i / COLS);
const c = i % COLS;
const hidden = r >= 2 && r <= 4 && c >= 1 && c <= 6; // 中央留空给标题 + 图例(占位不破坏网格)
const kind = Math.floor(rand(i * 9.1) * 3); // 0=首字母 1=图标 2=图片缩略
const ini = INI[Math.floor(rand(i * 3.7) * INI.length)];
const icon = ICONS[Math.floor(rand(i * 5.3) * ICONS.length)];
const h = Math.floor(rand(i * 7.7) * 360); // 缩略图渐变色相
const ring = Math.round(Math.hypot((c - 3.5) / 1.0, (r - 3) / 0.85)); // 到中心的"环号"
const delay = (ring * 4 + rand(i + 40) * 3) / TOTAL; // 每 4 帧扩一环 + 帧级抖动
const flagged = rand(i + 900) < 0.15; // ~15% 异常卡
const at = 0.3 + rand(i + 1600) * 0.3; // 染色随机时刻
return { hidden, kind, ini, icon, h, delay, flagged, at };
});
const LEGEND: Array<[string, string]> = [
['Active', '#37C46B'],
['Pending', '#F5A524'],
['Inactive', '#F0453A'],
];
export const AvatarGridRadialBuildColorize: React.FC = () => {
const t = useT();
// 标题淡入 + 轻微 scale;图例随后浮现
const tIn = seg(t, 0.02, 0.1, E.outQuad);
const legendIn = seg(t, 0.26, 0.36, E.outQuad);
return (
<DesignStage bg={PAPER} raster="zoom">
<div
style={{
position: 'absolute',
inset: 0,
overflow: 'hidden',
fontFamily: "-apple-system,'Helvetica Neue',Helvetica,Arial,sans-serif",
}}
>
<div style={{ position: 'absolute', inset: 16 }}>
{CELLS.map((cl, i) => {
const r = Math.floor(i / COLS);
const c = i % COLS;
const f = 0.09 + cl.delay;
const o = seg(t, f, f + 0.018, E.linear);
const sc = seg(t, f, f + 0.03, E.outQuad);
// 异常卡:底色染浅红、边框染粉、状态点转红
const cT = cl.flagged ? seg(t, cl.at, cl.at + 0.036, E.outQuad) : 0;
return (
<div
key={i}
style={{
position: 'absolute',
left: c * (CELL_W + GAP),
top: r * (CELL_H + GAP),
width: CELL_W,
height: CELL_H,
boxSizing: 'border-box', // 等价 grid stretch:边框计入轨道尺寸
borderRadius: 8,
background: cl.flagged ? mix(CARD_WHITE, FLAG_BG, cT) : CARD_WHITE,
border: `1px solid ${cl.flagged ? mix('#E7E7E4', '#F6CFCF', cT) : '#E7E7E4'}`,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden',
fontWeight: 700,
fontSize: cl.kind === 1 ? 13 : 11,
lineHeight: 1,
fontFamily: '-apple-system,Helvetica,sans-serif', // Remotion 无头浏览器缺 -apple-system,补 Helvetica 对齐原片 SF 字形
color: cl.kind === 1 ? '#6a6f7c' : '#3A3A3E',
opacity: o,
boxShadow: '0 1px 2px rgba(0,0,0,.04)',
visibility: cl.hidden ? 'hidden' : 'visible',
transform: `scale(${lerp(sc, 0.8, 1)})`,
}}
>
{cl.kind === 0 ? cl.ini : cl.kind === 1 ? cl.icon : null}
{cl.kind === 2 && (
<div
style={{
position: 'absolute',
inset: 0,
borderRadius: 7,
background: `linear-gradient(${45 + (cl.h % 90)}deg, hsl(${cl.h},18%,78%), hsl(${
(cl.h + 40) % 360
},22%,62%))`,
}}
/>
)}
<div
style={{
position: 'absolute',
right: 4,
top: 4,
width: 5,
height: 5,
borderRadius: '50%',
background: cl.flagged ? mix('#37C46B', '#F0453A', cT) : '#37C46B',
}}
/>
</div>
);
})}
</div>
<div
style={{
position: 'absolute',
left: '50%',
top: '45%',
transform: `translate(-50%,-50%) scale(${lerp(tIn, 0.98, 1)})`,
fontWeight: 800,
fontSize: 30,
lineHeight: 1.2,
fontFamily: "-apple-system,'Helvetica Neue',sans-serif",
letterSpacing: -1.2,
color: INK,
textAlign: 'center',
zIndex: 5,
whiteSpace: 'nowrap',
opacity: tIn,
}}
>
Let's bring them back in
</div>
<div
style={{
position: 'absolute',
left: '50%',
top: '56%',
transform: 'translateX(-50%)',
display: 'flex',
gap: 14,
alignItems: 'center',
zIndex: 5,
padding: '4px 10px',
opacity: legendIn,
whiteSpace: 'nowrap',
}}
>
{LEGEND.map(([txt, col]) => (
<div
key={txt}
style={{
display: 'flex',
alignItems: 'center',
gap: 5,
fontWeight: 600,
fontSize: 11,
lineHeight: 1,
fontFamily: '-apple-system,Helvetica,sans-serif', // Remotion 无头浏览器缺 -apple-system,补 Helvetica 对齐原片 SF 字形
color: MID,
}}
>
<span
style={{ width: 6, height: 6, borderRadius: '50%', background: col, display: 'inline-block' }}
/>
<span>{txt}</span>
</div>
))}
</div>
</div>
</DesignStage>
);
};
- Read the recipePrompt = when to use, intention, parameter table with typical values and how each one feels, known pitfalls. Treat values as calibrated starting points.
- Get the codetool: git
git clone https://github.com/Vincentwei1021/video-shotcraft && cd video-shotcraft && npm install - Register + rendertool: remotion
npx remotion render <CompositionId> out.mp4 # component: demos/data/avatar-grid-radial-build-colorize/AvatarGridRadialBuildColorize.tsx - Or re-implementPort the timing/easing from the recipe to HTML + WAAPI (gimgs motion contract) or any engine; keep the same segment windows and easing.
| param | type | default | description |
|---|---|---|---|
| — | |||
More in this category

Timeline travel pan
Timeline travel — the camera accelerates along a horizontal ruler axis past version tick marks, a card springs upright and pauses briefly at each tick, and an abrupt stop pushes in on the final tick.

Scroll brake moves
A long scroll decelerates to a precise stop on the latest item; a variant adds a reticle lock on the same frame.

Ring diagram annotation reveal
A full-screen subject is squeezed into a ring diagram by a circular window, then the group shrinks left to reveal annotations.

Particle celebration hits
Confetti cannons fire from both sides, or sparks fizz off the counter each time it ticks past a thousand.