Motion · Dữ liệu

Vạch chéo hóa thành dữ liệu thật

Các cột vạch chéo giữ chỗ lần lượt kéo dài, rồi vạch chéo mờ đi khi lớp màu nhấn đặc mờ hiện vào kèm giá trị bật ra, biểu đồ giữ chỗ biến thành biểu đồ cột dữ liệu thật.

1920×108016:930 fps4.9s · 147 frameremotionGiấy phép: Apache-2.0#shotcraft#remotion#data

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 kể chuyện "từ bản nháp thành dữ liệu thật"; giới thiệu tính năng dashboard/báo cáo, hoặc đoạn nhấn mạnh tính thời gian thực của dữ liệu.

Ý đồ

Quay khoảnh khắc sản phẩm "chỗ giữ chỗ biến thành dữ liệu thật" như một sự chuyển đổi chất liệu nhìn thấy được: trước tiên dùng các cột vạch chéo 45° vẽ cảm giác nháp "ở đây sẽ có dữ liệu", rồi để lớp màu đặc thay thế đúng tại chỗ — hình học hoàn toàn không đổi, chỉ đổi lớp da — điều khán giả đọc được là "cùng một thứ vừa sống dậy".

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

  • Thời lượng: Khoảng 4.4s (132f@30fps; lớn dần 0–1.7s · biến đổi 2.2–3.4s · rung nhẹ khi ổn định)
  • Năng lượng: Trung bình (thông tin tiến dần, không có đỉnh bùng nổ; chính sự chuyển đổi chất liệu tạo ra khoảnh khắc "đã lên sóng")

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)

意图

把"占位符变成真数据"这个产品瞬间拍成看得见的材质转换:先用 45° 斜纹条画出"这里将有数据"的草稿感,再让实心色层原位替换——几何完全不动、只换皮肤,观众读到的是"同一样东西活了"。

动效核心

  • 5 条横柱按 0.06 + i*0.05 错峰生长,各 0.22 时长 outCubic wipe 伸长到目标宽度(0.4–0.95 归一化)
  • 生长阶段斜纹层(repeating-linear-gradient 45° + 同色描边)与实心层同宽同步长,但实心层 opacity=0——蜕变只是交叉淡化,宽度曲线共用,保证几何零跳变
  • t=0.5 起按 0.5 + i*0.03 逐条蜕变(0.14 时长):斜纹 1-morph 淡出、实心 morph 淡入,标签同拍从灰变暗灰(视觉重心让给数据)
  • 数值文字 w*420 K 挂在柱端 left: calc(w% + 8px),随蜕变淡入
  • t=0.7–0.85 全体柱宽乘 1 + sin(t*30 + i*2.1)*0.02 微颤——"活数据在呼吸"的暗示
  • 表头 METRICS ● LIVE 行 t=0.62–0.78 从上方 30px 滑入,宣告蜕变完成

参数表

| 参数 | 典型值 | 调节手感 | |------|--------|----------| | 错峰间隔 | 生长 0.05/条、蜕变 0.03/条 | 生长间隔可到 0.08 增强"逐条点亮";蜕变间隔别超 0.05,拖长会读作故障闪烁 | | 生长时长 | 0.22(outCubic) | 缩到 0.15 更利落;配合错峰保证末条 ≤0.5 长完,给蜕变留窗口 | | 蜕变窗口 | 0.5 起、每条 0.14 交叉淡化 | 这是卡点位——BGM 重音应压在首条蜕变(t=0.5)上 | | 柱宽数据 | [0.85, 0.55, 0.95, 0.4, 0.7] | 换成真实数据比例即可;最长条 ≥0.9 保证画面有满幅锚点 | | 微颤幅度 | ±2%,t=0.7–0.85 | >4% 读作抖动 bug;不想要"呼吸感"可归零,但收尾会偏死板 | | 强调色 | ACCENT='#5B8DEF' / ACCENT_HI='#8FB2F7' | 双常量整体换肤;HI 用于数值文字,保持同族但更亮 |

已知坑

  • 斜纹层和实心层宽度必须共用同一条 grow 曲线——分开算会在蜕变瞬间产生 1–2px 宽度跳变,"原位换皮"的错觉立刻穿帮
  • 标签(SERIES_A 等)是占位词,换项目真实指标名时注意 70px 定宽标签列,超长会被裁
  • 数值 w*420 是演示映射,接真数据时换成实际数值格式化函数,但保持"随 grow 滚动"(终值 ×grow)的读数感
  • 微颤用全局 t 驱动(sin(t*30)),改动画总时长 dur 会改变颤动频率,需重新目检

参考实现

demos/data/hatch-depth/ (HatchDepth.tsx)

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

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

Prompt

Use the video-shotcraft shot recipe "Vạch chéo hóa thành dữ liệu thật" (Remotion composition, Apache-2.0) published on gimgs.net.
Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/hatch-depth.json
Raw TSX: https://gimgs.net/motion/hatch-depth/template.html
Repository: https://github.com/Vincentwei1021/video-shotcraft  (component: demos/data/hatch-depth/HatchDepth.tsx; imports demos/_fixtures and assets/lib)
Spec: 1920x1080, 30 fps, 4.9s

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

4,650 chars · Apache-2.0Mở template gốc ↗
// ===== demos/data/hatch-depth/HatchDepth.tsx =====
// hatch-depth — Hatch → Depth Chart 斜纹柱实体化(motion-lab 定稿转原生 Remotion)
// 标签下的斜纹条逐条 wipe 伸长(保持 45° 斜纹占位质感),随后斜纹层淡出、强调色
// 实心层淡入,蜕变为数据横柱条形图——几何无跳变、只换纹理与颜色,讲"占位变真数据"的隐喻。
// 设计坐标 480×270(DesignStage 等比放大),参数表数值以此坐标系标定。
import React from 'react';
import { DesignStage, E, seg, useT } from '../../_fixtures/Motion';

export const HATCH_DEPTH_DURATION = 132; // 4400ms @30fps

const ACCENT = '#5B8DEF'; // 模板强调色,可按项目替换
const ACCENT_HI = '#8FB2F7'; // 同族高亮(数值文字)

const ROWS = [
  { label: 'SERIES_A', w: 0.85 },
  { label: 'SERIES_B', w: 0.55 },
  { label: 'GROUP_C', w: 0.95 },
  { label: 'GROUP_D', w: 0.4 },
  { label: 'OTHER_E', w: 0.7 },
];

// 头部信息条里的 &nbsp;&nbsp;(连续普通空格在 JSX 会被折叠,须用不换行空格)
const NBSP2 = '  ';

export const HatchDepth: React.FC = () => {
  const t = useT();
  // 头部信息条:下滑入场
  const headIn = seg(t, 0.62, 0.78, E.outCubic);
  return (
    <DesignStage bg="#0a0a0c">
      <div
        style={{
          position: 'absolute',
          inset: 0,
          background: '#0a0a0c',
          padding: '36px 60px',
          display: 'flex',
          flexDirection: 'column',
          justifyContent: 'center',
          gap: 13,
          // 原栈 SF Mono 对无头 Chrome 不可见,真实 Chrome 落到 macOS 默认
          // 等宽字体 Courier(衬线打字机形);显式补 Courier 兜底对齐原片
          fontFamily: '"SF Mono",Courier,monospace',
        }}
      >
        {ROWS.map(({ label, w }, i) => {
          // 逐条 wipe 伸长 → 斜纹淡出/实心淡入 → 末段轻微 wiggle
          const grow = seg(t, 0.06 + i * 0.05, 0.06 + i * 0.05 + 0.22, E.outCubic);
          const morph = seg(t, 0.5 + i * 0.03, 0.5 + i * 0.03 + 0.14);
          const wiggle = 1 + Math.sin(t * 30 + i * 2.1) * 0.02 * seg(t, 0.7, 0.85);
          const wPct = grow * w * 100 * wiggle;
          return (
            <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 14, height: 26 }}>
              <span
                style={{
                  color: morph > 0.5 ? '#5c626f' : '#8b91a3',
                  fontSize: 11,
                  width: 70,
                  flex: 'none',
                  textAlign: 'right',
                }}
              >
                {label}
              </span>
              <div style={{ position: 'relative', height: '100%', flex: 1 }}>
                {/* 斜纹占位层 */}
                <div
                  style={{
                    position: 'absolute',
                    left: 0,
                    top: 0,
                    height: '100%',
                    width: `${wPct}%`,
                    borderRadius: 3,
                    background: 'repeating-linear-gradient(45deg,#565860 0 4px,transparent 4px 9px)',
                    border: '1px solid #565860',
                    // 原渲染无全局 border-box:宽高为内容尺寸,1px 边框外扩
                    // (斜纹相位随元素尺寸变化,box-sizing 不还原相位就对不上)
                    boxSizing: 'content-box',
                    opacity: 1 - morph,
                  }}
                />
                {/* 强调色实心层 */}
                <div
                  style={{
                    position: 'absolute',
                    left: 0,
                    top: 0,
                    height: '100%',
                    width: `${wPct}%`,
                    borderRadius: 3,
                    background: `linear-gradient(90deg,${ACCENT},${ACCENT_HI})`,
                    opacity: morph,
                  }}
                />
                {/* 柱端数值 */}
                <span
                  style={{
                    position: 'absolute',
                    top: '50%',
                    transform: 'translateY(-50%)',
                    color: ACCENT_HI,
                    fontSize: 10,
                    left: `calc(${wPct}% + 8px)`,
                    opacity: morph,
                  }}
                >
                  {Math.round(w * 420 * grow)}K
                </span>
              </div>
            </div>
          );
        })}
        {/* 头部信息条 */}
        <div
          style={{
            position: 'absolute',
            top: 20,
            left: 60,
            fontWeight: 600,
            fontSize: 12,
            fontFamily: '"SF Mono",Courier,monospace', // 同上:Courier 兜底
            letterSpacing: 1,
            transform: `translateY(${-30 + headIn * 30}px)`,
            opacity: headIn,
          }}
        >
          <span style={{ color: '#e8eaf0', fontWeight: 700 }}>METRICS</span>
          {NBSP2}
          <span style={{ color: '#67d17c' }}>● LIVE</span>
          {NBSP2}
          <span style={{ color: '#8b91a3' }}>TOTAL 875K{NBSP2}AVG 1.02M</span>
        </div>
      </div>
    </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/data/hatch-depth/HatchDepth.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