Motion · UI entrance

Radial wave dot grid

A 17×9 grid of dots lights up in a wave based on distance from a source point, each dot overshooting to 1.5x scale then settling.

1920×108016:930 fps4.3s · 129 framesremotionLicense: Apache-2.0#shotcraft#remotion#ui-entrance

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

When to use

A "system power-on" beat for a product/brand opening; also used as an establishing shot for data grids, node maps, or coverage-area narratives

Intention

Rewrites the static fact of "many dots existing at once" into the dynamic fact of "energy spreading from one source to everyone." What the viewer sees isn't a dot grid, it's a power-on moment: the center lights first, brightness pushes outward like a wave, and once it's done the whole grid holds steady, laying the groundwork for whatever content comes next. The second, reverse wave is an acknowledgment — telling the viewer this system responds.

Duration & energy

  • Duration: About 3.8s (114f@30fps)
  • Energy: Medium-high (one burst at the start, settling into a low-energy steady-lit base after the wavefront passes)

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

意图

把"很多点同时存在"这件静态事实,改写成"能量从一个源头扩散到全体"的动态事实。观众 看到的不是一张点阵图,而是一次通电:中心先亮,亮度像水波推过去,走完之后整张阵列 留在常亮态——为下一拍要放的内容铺好底。第二道反向波是回执,告诉观众这个系统会回应。

动效核心

  • 阵列 17×9 共 153 点,dot 用百分比定位(left:(c+0.5)/COLS),因此改变行列数不需要

重算坐标;每点预存归一化距离 dist = hypot(c-cx, r-cy) / maxD(maxD = hypot(8,4))

  • 第一道波:seg(t, dist*0.35, dist*0.35+0.18, E.outCubic)——起点由距离线性推迟(最外

圈延后 0.35),单点自己的行程恒定 0.18;波前是"起点错峰"而不是变速

  • 每点的 scale 不是简单 0→1,而是 w1*(1+0.5*sin(w1*π)):中途鼓到约 1.5 再收回 1,

正弦包络让过冲发生在行程正中而非落位时

  • 第二道波:seg(t, 0.62+(1-dist)*0.25, +0.15) 把偏移量反号(外圈先动),取

sin(w2*π) 做纯脉冲,叠加 0.8 的 scale 增量与 0.25 的透明度增量,走完不留状态

  • 脉冲峰值处(pulse2 > 0.3)硬切成 #b9f2ff 并挂 0 0 12px #7fd8ff 光晕——只有第二

道波带发光,第一道波全程是 #6c8cff 常色,两道波在视觉上不会混成一件事

参数表

| 参数 | 典型值 | 调节手感 | |------|--------|----------| | 阵列规模 | COLS=17 / ROWS=9(153 点) | 点数决定波前的"分辨率";<8 列时距离分档太粗,波读作三四圈同心环在跳 | | 波速系数 | dist*0.35 | 这个 0.35 就是波速倒数:调大波走得慢、拖尾长;>0.5 时最外圈要等到全片过半才亮 | | 单点行程 | 0.18(≈21f) | 决定波前的厚度;<0.1 波前锐利像扫描线,>0.3 全场几乎同时亮,扩散感消失 | | 过冲幅度 | 1+0.5*sin(w1*π) → 峰值 1.5 | 系数 0.5 是"弹一下"的量;去掉正弦项就是平淡的 0→1 淡入,>0.8 点会互相咬边 | | 第二道波 | 起点 0.62+(1-dist)*0.25,窗 0.15,幅度 0.8 | 0.62 是两波之间的呼吸;提前到 0.5 以下会和第一道波尾巴叠在一起读作一团乱闪 | | 常亮底 | opacity = 0.25 + w1*0.5 + pulse2*0.25 | 0.25 是未点亮点的存在感;调到 0 则波前之外一片黑,阵列的"规模"交代不出来 | | 高亮阈值 | pulse2 > 0.3 切色 + 光晕 | 阈值越低发光段越长;这是硬切不是渐变,阈值贴近 0 时会看到明显的开关跳变 |

已知坑

  • 波源写死在几何中心(cx=(COLS-1)/2, cy=(ROWS-1)/2)。要改成从角落或某个"节点"起波,

必须同时改 cx/cy 与 maxD,否则归一化距离 >1,最外圈的起点会被推到 t=1 之外永不点亮

  • 末帧不完全静止:中心点(dist=0)的第二道波窗是 0.87→1.02,t=1 时才走到 87%,

pulse2≈0.41 仍在高亮。要做循环或干净收尾,得把第二道波起点压到 0.85 以内

  • dot 的 width:10px 与 margin:-5px 是绑定的一对(靠负 margin 居中),改点径必须同步改

margin,否则整阵列会朝右下偏半个点径

  • 颜色只有两档(常色 #6c8cff / 峰值 #b9f2ff),换品牌色要改这两处加光晕色共三处;

背景 #0a0b10 是发光的前提,白底上这套亮度脉冲基本看不见

参考实现

demos/ui-entrance/radial-wave/ (RadialWave.tsx)

Reference implementation (Remotion)

  • demos/ui-entrance/radial-wave/RadialWave.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/ui-entrance/radial-wave/RadialWave.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/radial-wave.json
git clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/ui-entrance/radial-wave/RadialWave.tsx
npx remotion render <CompositionId> out.mp4
claude mcp add --transport http gimgs https://gimgs.net/mcp
# then: search_motion_templates / get_motion_template("radial-wave")

Prompt

Use the video-shotcraft shot recipe "Radial wave dot grid" (Remotion composition, Apache-2.0) published on gimgs.net.
Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/radial-wave.json
Raw TSX: https://gimgs.net/motion/radial-wave/template.html
Repository: https://github.com/Vincentwei1021/video-shotcraft  (component: demos/ui-entrance/radial-wave/RadialWave.tsx; imports demos/_fixtures and assets/lib)
Spec: 1920x1080, 30 fps, 4.3s

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

1,861 chars · Apache-2.0Open raw template ↗
// ===== demos/ui-entrance/radial-wave/RadialWave.tsx =====
// radial-wave — Grid Radial Wave 点阵涟漪(motion-lab 定稿转原生 Remotion)
// 17×9 圆点阵列,波从中心向外按欧氏距离 stagger 扩散:每点 scale 0→1.5→1 +
// 亮度脉冲,波前过后留下常亮点阵;第二道波反向收拢。offset = k·dist(cell, origin)。
// 设计坐标 480×270(DesignStage 等比放大),参数表数值以此坐标系标定。
import React from 'react';
import { DesignStage, E, seg, useT } from '../../_fixtures/Motion';

export const RADIAL_WAVE_DURATION = 114; // 3800ms @30fps

const COLS = 17;
const ROWS = 9;
const CX = (COLS - 1) / 2;
const CY = (ROWS - 1) / 2;
const MAX_D = Math.hypot(CX, CY);

const DOTS = Array.from({ length: ROWS * COLS }, (_, i) => {
  const r = Math.floor(i / COLS);
  const c = i % COLS;
  return {
    left: `${((c + 0.5) / COLS) * 100}%`,
    top: `${((r + 0.5) / ROWS) * 100}%`,
    dist: Math.hypot(c - CX, r - CY) / MAX_D,
  };
});

export const RadialWave: React.FC = () => {
  const t = useT();
  return (
    <DesignStage bg="#0a0b10">
      {DOTS.map(({ left, top, dist }, i) => {
        // 第一道波:扩散点亮;第二道波:反向脉冲
        const w1 = seg(t, dist * 0.35, dist * 0.35 + 0.18, E.outCubic);
        const w2 = seg(t, 0.62 + (1 - dist) * 0.25, 0.62 + (1 - dist) * 0.25 + 0.15);
        const pulse2 = Math.sin(w2 * Math.PI);
        const s = w1 * (1 + 0.5 * Math.sin(w1 * Math.PI)) + pulse2 * 0.8;
        return (
          <div
            key={i}
            style={{
              position: 'absolute',
              width: 10,
              height: 10,
              borderRadius: '50%',
              left,
              top,
              margin: -5,
              background: pulse2 > 0.3 ? '#b9f2ff' : '#6c8cff',
              transform: `scale(${s})`,
              opacity: 0.25 + w1 * 0.5 + pulse2 * 0.25,
              boxShadow: pulse2 > 0.3 ? '0 0 12px #7fd8ff' : 'none',
            }}
          />
        );
      })}
    </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/ui-entrance/radial-wave/RadialWave.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