Motion · Chữ & title card

Vòng lặp trạng thái nhiễu glitch

Cùng một khe chữ lần lượt phát 4 cụm trạng thái, mỗi cụm nhiễu loạn ở đầu-đuôi, giữa đoạn thỉnh thoảng rung một chữ, lúc chuyển chồng tách kênh RGB và dịch cả dòng; cụm cuối kết thúc sạch.

1920×108016:930 fps6.1s · 183 frameremotionGiấy phép: Apache-2.0#shotcraft#remotion#typography

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

Phát trạng thái cho quá trình tải/build/triển khai; "tự thuật của hệ thống" trong đoạn mở đầu chất công nghệ; nền để dòng thời gian trôi bằng giọng máy.

Ý đồ

Cách phát trạng thái vụng về nhất là bốn dòng chữ mờ hiện lần lượt. Vòng lặp nén chúng vào một khe duy nhất: đầu-đuôi mỗi cụm "cháy" thành nhiễu loạn rồi "đông cứng" lại, giữa đoạn gần như sạch chỉ thỉnh thoảng giật một cái — điều khán giả đọc được là "hệ thống đang tiến từng bước", không phải bốn dòng chú thích rời rạc. Mật độ nhiễu chính là ngữ pháp của thẻ này: đậm = đang chuyển, nhạt = đang ở trạng thái này. Thanh tiến trình bên dưới xâu bốn nhịp thành một đường thời gian, cụm cuối xác suất về 0 nên ổn định là kết thúc.

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

  • Thời lượng: Khoảng 5.6s (168f@30fps, 4 cụm mỗi cụm 42f)
  • Năng lượng: Trung bình cao (xung nhiễu tần số cao liên tục, điểm chuyển là đỉnh)

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)

意图

状态播报最笨的做法是四行字逐条淡入。轮播把它们压进一个槽位: 短语头尾用乱码"熔断"再"凝固",中段几乎干净只偶尔抽一下——观众读到的 是"系统在一步步推进",而不是四条独立文案。乱码浓度是这卡的语法: 浓 = 正在切换,淡 = 正在这一状态里。底部进度条把四拍串成一条时间线, 最后一条把概率收到 0,落定即结束。

动效核心

  • 槽位按最长短语预建 MAXCH 个 span(min-width:0.66em 固定槽宽),

短短语右侧填空格——字符不增删,只换内容,整行永不重排

  • 时段等分:slot = floor(t·4),短语内进度 p = t·4 - slot(每条 42f)
  • glitch 概率关键帧 KF=[1,0,0,0.1,0,0,1] 按 p 线性插值:**开头 1.0 全乱、

中段 0、约 p=0.5 处回弹到 0.1(偶发抽字)、结尾又回 1.0 熔进下一条**

  • 末条专用 KF_LAST=[1,0,0,0.1,0,0,0],结尾概率归零 → t=1 画面干净
  • 逐字符判定:rand(i·31 + bucket·17 + slot·97) < g 才替换成字池字符,

命中字随机上 #6c8cff 蓝或 #4a5270 暗灰;bucket = floor(frame/2), 即每 2 帧重掷一次

  • 整行抖动与 RGB 分离强度全部乘 g:jx = ±g·10px、jy = ±g·4px,

text-shadow 左红右青各偏 g·3px(g>0.04 才开)——噪声浓度一个变量 同时驱动换字、位移、色散,所以三者永不打架;底部 120×2px 进度条 width = t·100% 线性走满,与四拍无关地铺底

参数表

| 参数 | 典型值 | 调节手感 | |------|--------|----------| | 短语表 | 4 条,最长 17 字符(COMPILING SHADERS) | 每条 42f 是"读得完一个状态"的下限;5 条以上单条不足 34f 观众只看到闪 | | 概率关键帧 | [1,0,0,0.1,0,0,1](6 段) | 中间那个 0.1 是"活着"的证据,删了短语中段死板;把 0 段调到 0.3+ 全片糊成故障 | | 重掷频率 | 每 2 帧(floor(frame/2)) | 1 帧一换糊成灰带;4 帧以上乱码看得清是"另一个词",不像噪声 | | 抖动幅度 | x ±g·10 / y ±g·4px | x 大于 y 是横向撕裂的关键(等比抖动读作地震);>20px 整行跳出槽位 | | RGB 分离 | 左红右青各 g·3px,阈值 g>0.04 | 这是"电子故障"的身份证;无阈值时中段那 0.1 的概率会让字常年带毛边 | | 槽宽字体 | SF Mono 26px、letter-spacing:3px、槽 0.66em | 等宽 + 固定槽宽是刚需;字距 3px 让乱码之间有呼吸,挤在一起读作乱码块 | | 进度条 | 120×2px,#6c8cff 填充,线性 | 唯一的线性元素,给四拍噪声一个稳定参照;删了轮播读不出"在推进" |

已知坑

  • demo 在灰阶/占位素材上调校通过——参数是调校起点非实战定稿,

首次实战须以真实素材回验

  • 换项目文案时四条短语字符数要接近(demo 12–17 字符):槽位数按最长

短语一次建好,短短语靠右填空格——如果一条只有 4 字符、另一条 30 字符, 短的那条在 30 格里孤零零居左,行宽全程被最长条撑着,节奏读作漂移

  • 概率关键帧是 6 段等分映射到短语内进度:短语条数变了单条时长跟着变,

但关键帧形状不变——所以条数越多,"全乱码"那两段的绝对时长越短, 切换感越弱,超过 5 条就该把首尾的 1.0 段拉宽

  • 末条必须用 KF_LAST(结尾收 0):用普通 KF 会让 t=1 停在满乱码上,

接下一镜时读作没渲染完

  • 深底专用:#0a0b10 底 + 冷蓝噪声是整套配色的地基,浅底上 RGB 分离

几乎不可见;声音也强依赖——四个切换点天然是四个节奏点,实战必须配 电子故障/开关音; 配法纪律见 sound-design.md(同类元素同音,连发交替双样本防机枪感)

  • 与 scramble 分工:那卡是一次性解密(乱→定,不再乱),本卡是

循环播报(乱→定→乱→定);同片只留一个,两个并置读作同一手法用了两遍

参考实现

demos/typography/glitch-cycle/ (GlitchCycle.tsx)

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

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

Prompt

Use the video-shotcraft shot recipe "Vòng lặp trạng thái nhiễu glitch" (Remotion composition, Apache-2.0) published on gimgs.net.
Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/glitch-cycle.json
Raw TSX: https://gimgs.net/motion/glitch-cycle/template.html
Repository: https://github.com/Vincentwei1021/video-shotcraft  (component: demos/typography/glitch-cycle/GlitchCycle.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).

JSON · Markdown · llms.txt

3,564 chars · Apache-2.0Mở template gốc ↗
// ===== demos/typography/glitch-cycle/GlitchCycle.tsx =====
// glitch-cycle — Glitch Cycle 乱码轮播(motion-lab 定稿转原生 Remotion)
// 同一位置循环轮播状态短语,每条短语头尾乱码、中段偶发轻微抖动
// (glitch 概率关键帧 [1,0,0,0.1,0,0,1],最后一条结尾收为 0 保证 t=1 画面干净),
// 切换瞬间伴随 RGB 分离与位移抖动;底部细进度条随 t 匀速填满。
// 设计坐标 480×270(DesignStage 等比放大),参数表数值以此坐标系标定。
import React from 'react';
import { DesignStage, lerp, rand, useT } from '../../_fixtures/Motion';

export const GLITCH_CYCLE_DURATION = 168; // 5600ms @30fps

const PHRASES = ['INITIALIZING', 'LOADING ASSETS', 'COMPILING SHADERS', 'READY TO SHIP'];
const POOL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#$%&<>/\\';
// glitch 概率关键帧 [1,0,0,0.1,0,0,1](最后一条结尾收为 0,保证 t=1 画面干净)
const KF = [1, 0, 0, 0.1, 0, 0, 1];
const KF_LAST = [1, 0, 0, 0.1, 0, 0, 0];
const MAXCH = Math.max(...PHRASES.map((p) => p.length));

// 关键帧折线采样:p∈[0,1] 映射到 kf 段内线性插值
const glitchAt = (kf: number[], p: number) => {
  const segs = kf.length - 1;
  const x = Math.min(segs - 1e-6, Math.max(0, p * segs));
  const i = Math.floor(x);
  return lerp(x - i, kf[i], kf[i + 1]);
};

export const GlitchCycle: React.FC = () => {
  const t = useT();
  const N = PHRASES.length;
  const slot = Math.min(N - 1, Math.floor(t * N));
  const p = t * N - slot; // 短语内进度 0..1
  const text = PHRASES[slot];
  const g = glitchAt(slot === N - 1 ? KF_LAST : KF, p);
  const frame = Math.floor(t * 168);
  const bucket = Math.floor(frame / 2); // 乱码跳字节流:每 2 帧换一批随机字符
  // 整行抖动 + RGB 分离,强度跟随 glitch 概率
  const jx = (rand(bucket * 5 + slot) - 0.5) * g * 10;
  const jy = (rand(bucket * 9 + slot + 40) - 0.5) * g * 4;
  return (
    <DesignStage bg="#0a0b10">
      <div
        style={{
          position: 'absolute',
          inset: 0,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          background: '#0a0b10',
        }}
      >
        <div
          style={{
            display: 'flex',
            fontFamily: '"SF Mono",Menlo,monospace',
            fontSize: 26,
            letterSpacing: 3,
            color: '#dfe6f5',
            transform: `translate(${jx}px,${jy}px)`,
            textShadow:
              g > 0.04
                ? `${g * 3}px 0 rgba(255,60,90,${g * 0.8}), ${-g * 3}px 0 rgba(60,220,255,${g * 0.8})`
                : 'none',
          }}
        >
          {Array.from({ length: MAXCH }, (_, i) => {
            const ch = i < text.length ? text[i] : ' ';
            let content = ch;
            let color: string | undefined;
            if (ch !== ' ') {
              // 逐字符按种子掷 glitch:命中显示乱码 + 变色,未命中显示真字符
              const hit = rand(i * 31 + bucket * 17 + slot * 97) < g;
              if (hit) {
                content = POOL[Math.floor(rand(i * 131 + bucket * 7 + slot * 13) * POOL.length)];
                color = rand(i + bucket) > 0.5 ? '#6c8cff' : '#4a5270';
              } else {
                color = '#dfe6f5';
              }
            }
            return (
              <span key={i} style={{ minWidth: '0.66em', textAlign: 'center', color }}>
                {content}
              </span>
            );
          })}
        </div>
      </div>
      {/* 底部细进度条:随 t 匀速填满 */}
      <div
        style={{
          position: 'absolute',
          left: '50%',
          top: '63%',
          width: 120,
          height: 2,
          marginLeft: -60,
          background: '#232840',
          borderRadius: 1,
          overflow: 'hidden',
        }}
      >
        <div style={{ height: '100%', width: `${t * 100}%`, background: '#6c8cff' }} />
      </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/typography/glitch-cycle/GlitchCycle.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