Motion · UI xuất hiện

Sóng lan tỏa lưới chấm

Lưới 17×9 chấm tròn sáng lên theo sóng dựa trên khoảng cách tới nguồn, mỗi chấm vọt quá 1.5 lần rồi ổn định.

1920×108016:930 fps4.3s · 129 frameremotionGiấy phép: Apache-2.0#shotcraft#remotion#ui-entrance

Nguồn: video-shotcraft (Vincent Wei) ↗ · Apache-2.0 · Composition Remotion (React/TSX) — có video preview, không có player trong trình duyệt

Khi nào dùng

Nhịp "hệ thống lên điện" cho mở đầu sản phẩm/thương hiệu; cũng dùng làm cảnh thiết lập cho lưới dữ liệu, bản đồ nút, hay câu chuyện vùng phủ sóng

Ý đồ

Viết lại sự kiện tĩnh "rất nhiều chấm cùng tồn tại" thành sự kiện động "năng lượng lan tỏa từ một nguồn ra toàn bộ". Điều người xem thấy không phải một lưới chấm, mà là một lần lên điện: tâm sáng trước, độ sáng đẩy ra như sóng nước, đi hết một lượt thì cả lưới giữ ở trạng thái sáng ổn định — dọn nền cho nội dung nhịp tiếp theo. Sóng ngược thứ hai là một lời hồi đáp, cho người xem biết hệ thống này sẽ phản hồi.

Thời lượng & năng lượng

  • Thời lượng: Khoảng 3.8s (114f@30fps)
  • Năng lượng: Trung bình cao (bùng nổ một lần lúc mở đầu, sau khi sóng đi qua chuyển thành nền sáng ổn định năng lượng thấp)

Công thức cảnh quay (bản gốc tiếng Trung — timing, easing, bảng tham số, lỗi hay gặp)

意图

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

动效核心

  • 阵列 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)

Mã nguồn tham chiếu (Remotion)

  • demos/ui-entrance/radial-wave/RadialWave.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/ui-entrance/radial-wave/RadialWave.tsx

Component import fixture chung từ demos/_fixtures và helper từ assets/lib của repo; xem SKILL.md trong repo để biết quy trình render.

Mọi thứ trên trang này đều có bản máy đọc. Đưa agent link JSON, hoặc thêm MCP server gimgs rồi bảo nó tìm motion template.

  1. Tải JSON — trong đó có công thức cảnh quay (timing, easing, bảng tham số, lỗi hay gặp) và toàn bộ source TSX.
  2. Clone repo video-shotcraft; component import fixture chung từ demos/_fixtures và helper từ assets/lib.
  3. Đăng ký component thành <Composition> trong project Remotion rồi render bằng `npx remotion render`, hoặc dựng lại công thức bằng engine của bạn.
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 "Sóng lan tỏa lưới chấm" (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.0Mở template gốc ↗
// ===== 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
—

Cùng danh mục