Motion · Tipografia

Glitch status cycle

The same slot cycles through 4 status phrases, each scrambling fully at the head and tail with occasional mid-phrase jitter, RGB split and a full-line shift at each switch; the last phrase resolves clean.

1920×108016:930 fps6.1s · 183 quadrosremotionLicença: Apache-2.0#shotcraft#remotion#typography

Fonte: video-shotcraft (Vincent Wei) ↗ · Apache-2.0 · Composição Remotion (React/TSX) — vídeo de prévia, sem player no navegador

When to use

Status broadcasting for loading/build/deploy processes; the "system self-narration" of a tech-flavored opener; a backdrop for advancing time with a machine voice.

Intention

The clumsiest way to broadcast status is four lines fading in one after another. Cycling compresses them into one slot: each phrase "burns out" into scramble at head and tail then "solidifies", staying almost clean mid-phrase with only occasional twitches — what the audience reads is "the system is progressing step by step", not four independent captions. Scramble density is this card's grammar: dense = switching, clean = currently in this state. A progress bar at the bottom strings the four beats into one timeline, and the last phrase's probability resolves to 0 so it ends the moment it settles.

Duration & energy

  • Duration: About 5.6s (168f@30fps, 4 phrases at 42f each)
  • Energy: Medium-high (a sustained high-frequency noise pulse, with switch points as peaks)

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

意图

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

Reference implementation (Remotion)

  • demos/typography/glitch-cycle/GlitchCycle.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/typography/glitch-cycle/GlitchCycle.tsx

The component imports shared fixtures from demos/_fixtures and helpers from assets/lib in the repo; SKILL.md there documents the render workflow.

Tudo nesta página também é legível por máquina. Aponte seu agente para o JSON ou adicione o servidor MCP do gimgs e peça para buscar templates de motion.

  1. Baixe o JSON — contém a receita do plano (timing, easing, tabela de parâmetros, armadilhas) e o código TSX completo.
  2. Clone o repositório video-shotcraft; o componente importa fixtures de demos/_fixtures e helpers de assets/lib.
  3. Registre o componente como <Composition> em um projeto Remotion e renderize com `npx remotion render`, ou reimplemente a receita no seu próprio engine.
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 "Glitch status cycle" (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.0Abrir template bruto ↗
// ===== 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
—

Mais nesta categoria