Motion · Luz & ênfase

Riso print hits

Two Riso-print misregistration hits: a single split-and-snap impact, and a rhythmic version that compounds beat by beat.

1920×108016:930 fps4.05s · 122 quadrosremotionLicença: Apache-2.0#shotcraft#remotion#effects#typography#rhythm

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

Variantes

misregistration-hitmisregistration-hit 单发
标题 8f 撞入撞停,裂两版反向错 ~32px,44f 衰减震荡后硬切套准 + scale 脉冲
全片 1-2 次的命中盖章;标题/大字的到位一瞬
beat-pumpbeat-pump 节拍泵
每 24f 一拍:整画面瞬跳 1.08 指数回落 + 标题错版逐拍 8/14/22/32px 加码套准
音乐卡点段;"越打越狠"的蓄力连打

When to use

Hit emphasis for titles/cards, a paper-and-ink take on the "glitch flash"; A for a single climax hit, B for repeated hits in a rhythm section

Intention

RGB chromatic-aberration glitch (part of impact-feedback style C) is a screen-native language that clashes with a paper-and-ink tonality. These two styles are the print-based equivalent: the element splits into light-gray and dark-ink single-color print plates (a multiply ink feel rather than a screen glow feel), like a risograph print that's out of register, shaking a few times before snapping "clack" into register — the same impact, but with the medium fully swapped to ink on paper. A is a single hit: the impact freezes and splits the plates, the shake decays, then a hard cut snaps them into register, stamping one hit; B is its rhythmic form: every beat the whole frame jumps 8% and the title splits its plates, the misregistration compounding with each beat — getting harder every time, a visual bass drum for a beat-driven section. Same technical root (decaying-oscillation two-plate misregistration), choose single-hit or repeated-hit.

Duration & energy

  • Duration: A 4s (single hit); B 4.7s (four beats)
  • Energy: High

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

意图

RGB 色散故障闪(impact-feedback C 式的一部分)是荧光屏语言,与纸墨 调性相克。这两式给出印刷版平替:元素裂成浅灰/深墨两份单色印版 (multiply 油墨感而非 screen 荧光感),像 risograph 没对准版,抖几下 "啪"地套准——同样的冲击力,介质想象完全换成纸上油墨。A 是单发: 撞停瞬间裂版、震荡衰减、硬切套准,给一次命中盖章;B 是它的节奏化: 每个鼓点整画面跳大 8% + 标题裂版,错位逐拍加码,越打越狠—— 卡点段的视觉低音鼓。同技术根(衰减震荡的双版错位),单发/连打二选一。

两式选型

| 式 | 做法 | 适用 | |----|------|------| | A misregistration-hit 单发 | 标题 8f 撞入撞停,裂两版反向错 ~32px,44f 衰减震荡后硬切套准 + scale 脉冲 | 全片 1–2 次的命中盖章;标题/大字的到位一瞬 | | B beat-pump 节拍泵 | 每 24f 一拍:整画面瞬跳 1.08 指数回落 + 标题错版逐拍 8/14/22/32px 加码套准 | 音乐卡点段;"越打越狠"的蓄力连打 |

参数表

| 参数 | 典型值 | 调节手感 | |------|--------|----------| | 双版 | 浅灰版(G.mid)+ 深墨版(G.ink),mix-blend-mode: multiply,位移反向 | multiply 叠出的重影灰阶就是"油墨没对准";screen 叠加立刻变荧光故障 | | A 错位包络 | offset = A·cos(2πt/18)·exp(-t/60),A=(16,7)px 两版反向;帧 72 硬切归零 | 命门:套准是硬切跳变不是渐收——衰减到 ~14px 残余时啪地归零才有"啪";纯渐收读不出套准一拍 | | A 撞入 | 8f Easing.in(cubic) 从画外撞停,命中帧即裂版 | 裂版必须与撞停同帧——晚 2f 就读作两件事 | | A 套准脉冲 | 归零帧 4f scale 1.03→1 | 盖章的一拍;省略则套准无重量 | | B 泵 | scale = 1 + 0.08·exp(-t/3)(t=0 即满值、一帧到位无渐入),14f 窗口外精确归 1 | 瞬跳是"顿推"本体——加渐入就成了普通 zoom 呼吸 | | B 错版加码 | AMP 逐拍 4/7/11/16px(单版,双版反向即总分离 8/14/22/32px),AMP·cos(2πt/6)·exp(-t/3) 12f 窗口 | 逐次加码是命门(同 hit-counter 判例):四拍一样大读不出"越打越狠" | | B 作用域 | scale 作用整画面容器,错版只作用标题 | 整画面全裂读作故障而非印刷 | | B 节拍参照物 | 底部节拍刻度点,命中闪深常驻 | 静音预览环境的节拍可读性 | | 收尾 | A 套准后 ≥40f / B 末拍归零后 ≥20f 真静止 | R1 |

已知坑

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

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

  • 错位幅度可感性判例(本批实渲):词汇表原案 ±5px 在 1920 宽画面

正常速度下肉眼几乎不可见——单版 16px/总分离 32px 起步才可感; 幅度存疑时做极端版给用户看(可感性优先)

  • 两式与 impact-feedback C(负片冲击帧)语义重叠——纸墨调性片子用本卡、

游戏/动漫调性用 C 式,同片不并用(P4)

  • B 式是声音强依赖:命中帧必须钉鼓点(sound-design §4.5);无音轨

段落读作画面抽搐

  • A 式错位方向一横一纵混合(x 为主 y 少量)更像没对准版;纯横向读作

左右晃动

  • B 式四拍后必须接足量 hold(≥24f)——连打完不还呼吸,观众的耳朵还

在等第五拍

参考实现

demos/effects/riso-print-hits/ (RisoBeatPump.tsx / RisoMisregistrationHit.tsx)

Reference implementation (Remotion)

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

Prompt

Use the video-shotcraft shot recipe "Riso print hits" (Remotion composition, Apache-2.0) published on gimgs.net.
Recipe JSON (prompt = timing/easing/parameter table/pitfalls, files = TSX source): https://gimgs.net/motion/riso-print-hits.json
Raw TSX: https://gimgs.net/motion/riso-print-hits/template.html
Repository: https://github.com/Vincentwei1021/video-shotcraft  (component: demos/effects/riso-print-hits/RisoBeatPump.tsx, demos/effects/riso-print-hits/RisoMisregistrationHit.tsx; imports demos/_fixtures and assets/lib)
Spec: 1920x1080, 30 fps, 4.05s

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

7,773 chars · Apache-2.0Abrir template bruto ↗
// ===== demos/effects/riso-print-hits/RisoBeatPump.tsx =====
// 套印节拍泵(riso-beat-pump)——beat-punch-in(卡点顿推)× riso-misregistration-hit
// (套印错位)的组合节奏。节拍帧 [30,54,78,102](每 24f 一拍),每命中帧:
// ① 整画面 scale 一帧瞬跳 1.08(无渐入),14f 内按 exp(-t/3) 指数衰减回 1;
// ② 标题裂成 G.mid/G.ink 双色印版 multiply 错位,初始错位逐拍加码 4/7/11/16px
//    (每版反向 → 总分离 8/14/22/32px),12f 衰减余弦震荡收敛套准;
// ③ 底部对应节拍刻度点闪深并常驻。结构:0–29f hold;30–115f 四拍;116–139f 真静止。
import React from 'react';
import { useCurrentFrame } from 'remotion';
import { G, Card, TitleBlock } from '../../_fixtures/Fixtures';

const HITS = [30, 54, 78, 102]; // 节拍命中帧
const AMP = [4, 7, 11, 16]; // 每拍单版初始错位(px),逐拍加码
const PUMP_WIN = 14; // scale 泵窗口:14f 后精确归 1(保证结尾真静止)
const SPLIT_WIN = 12; // 错位窗口:12f 后精确归 0(余量 <0.4px,硬切套准)

// 与 TitleBlock 同字形的单色印版(错位需要可调色副本)
const Plate: React.FC<{ color: string; dx: number; dy: number }> = ({ color, dx, dy }) => (
  <div
    style={{
      position: 'absolute',
      inset: 0,
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      transform: `translate(${dx}px, ${dy}px)`,
      mixBlendMode: 'multiply',
    }}
  >
    <div
      style={{
        fontFamily: 'Helvetica, Arial, sans-serif',
        fontWeight: 800,
        fontSize: 160,
        color,
        letterSpacing: -1,
        whiteSpace: 'nowrap',
      }}
    >
      ON THE BEAT
    </div>
  </div>
);

export const RisoBeatPump: React.FC = () => {
  const frame = useCurrentFrame();

  // 找最近一次已命中的节拍(24f 间隔 > 14f 窗口,永远只有一拍在作用)
  let beatIdx = -1;
  for (let i = 0; i < HITS.length; i++) {
    if (frame >= HITS[i]) beatIdx = i;
  }
  const t = beatIdx >= 0 ? frame - HITS[beatIdx] : Infinity;

  // ① 整画面泵:命中帧一帧到位 1.08(t=0 即满值,无渐入),指数衰减回 1
  const pump = t < PUMP_WIN ? 1 + 0.08 * Math.exp(-t / 3) : 1;

  // ② 标题错位:衰减余弦震荡(周期 6f 抖两下),窗口外精确 0 = 套准
  const split = t < SPLIT_WIN;
  const m = split ? Math.cos((2 * Math.PI * t) / 6) * Math.exp(-t / 3) : 0;
  const dx = beatIdx >= 0 ? AMP[beatIdx] * m : 0;
  const dy = dx * 0.45; // y 少量,更像没对准版

  return (
    <div
      style={{
        width: 1920,
        height: 1080,
        background: G.bg,
        position: 'relative',
        overflow: 'hidden',
      }}
    >
      {/* 整画面容器:scale 泵作用在全部内容上 */}
      <div
        style={{
          position: 'absolute',
          inset: 0,
          transform: `scale(${pump})`,
          transformOrigin: 'center center',
        }}
      >
        {/* 标题区:正体 / 双版错位互斥切换 */}
        <div style={{ position: 'absolute', left: 0, right: 0, top: 0, height: 660 }}>
          {!split && (
            <div
              style={{
                position: 'absolute',
                inset: 0,
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
              }}
            >
              <TitleBlock text="ON THE BEAT" size={160} />
            </div>
          )}
          {split && (
            <>
              <Plate color={G.mid} dx={-dx} dy={dy} />
              <Plate color={G.ink} dx={dx} dy={-dy} />
            </>
          )}
        </div>

        {/* 底下一排 3 张小卡 */}
        <div
          style={{
            position: 'absolute',
            left: 0,
            right: 0,
            top: 660,
            display: 'flex',
            justifyContent: 'center',
            gap: 44,
          }}
        >
          <Card w={330} h={200} seed={2} />
          <Card w={330} h={200} seed={5} />
          <Card w={330} h={200} seed={8} />
        </div>

        {/* 节拍刻度:命中即闪深(8f 缩放脉冲 1.8→1)并常驻深色 */}
        <div
          style={{
            position: 'absolute',
            left: 0,
            right: 0,
            top: 950,
            display: 'flex',
            justifyContent: 'center',
            gap: 60,
          }}
        >
          {HITS.map((hit, i) => {
            const dt = frame - hit;
            const on = dt >= 0;
            const s = on && dt < 8 ? 1 + 0.8 * (1 - dt / 8) : 1;
            return (
              <div
                key={i}
                style={{
                  width: 22,
                  height: 22,
                  borderRadius: 11,
                  background: on ? G.ink : G.bar,
                  transform: `scale(${s})`,
                }}
              />
            );
          })}
        </div>
      </div>
    </div>
  );
};


// ===== demos/effects/riso-print-hits/RisoMisregistrationHit.tsx =====
// 套印错位冲击帧(riso-misregistration-hit)——标题撞停瞬间裂成两份单色"印版"
// (浅灰琥珀版 G.mid + 深墨版 G.ink,mix-blend-mode: multiply 叠加),像 riso 印刷
// 没对准版;两版反向错位(x 为主 y 少量)做衰减震荡 offset = A*cos(ωt)*exp(-t/τ)
// 抖两下,帧 72 啪地硬切回单一正体(套准合一),带 4f scale 1.03→1 脉冲收束。
// 结构:0–19f 空场 hold(只有底部装饰线);20–28f 标题从右画外 Easing.in(cubic)
// 撞入屏心(帧 28 命中);28–71f 双版错位震荡;72–75f 套准脉冲;76–119f 真静止 44f。
import React from 'react';
import { useCurrentFrame, interpolate, Easing } from 'remotion';
import { G, TitleBlock } from '../../_fixtures/Fixtures';

const HIT = 28; // 撞停命中帧
const SNAP = 72; // 套准合一帧
const AX = 16; // 单版 x 错位振幅(两版反向 → 总分离 ~32px,肉眼明显)
const AY = 7; // 单版 y 错位振幅(少量,更像没对准版)
const OMEGA = (2 * Math.PI) / 18; // 震荡周期 18f,44f 内抖两下半
const TAU = 60; // 缓衰减:帧 72 前仍余 ~14px 总分离,被"啪地"硬切归零

// 与 TitleBlock 同字形的可调色标题(错位印版需要单色副本)
const Plate: React.FC<{ color: string; dx: number; dy: number }> = ({ color, dx, dy }) => (
  <div
    style={{
      position: 'absolute',
      inset: 0,
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      transform: `translate(${dx}px, ${dy}px)`,
      mixBlendMode: 'multiply',
    }}
  >
    <div
      style={{
        fontFamily: 'Helvetica, Arial, sans-serif',
        fontWeight: 800,
        fontSize: 200,
        color,
        letterSpacing: -1,
        whiteSpace: 'nowrap',
      }}
    >
      IMPACT
    </div>
  </div>
);

export const RisoMisregistrationHit: React.FC = () => {
  const frame = useCurrentFrame();

  // 阶段判定
  const entering = frame >= 20 && frame < HIT; // 撞入
  const split = frame >= HIT && frame < SNAP; // 双版错位震荡
  const showSingle = frame < HIT || frame >= SNAP; // 正体(画外/撞入/套准后)

  // 撞入位移:右画外 1400px → 0,8f Easing.in(cubic)(加速撞停)
  const slideX = interpolate(frame, [20, HIT], [1400, 0], {
    easing: Easing.in(Easing.cubic),
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
  });

  // 错位震荡包络:t 自命中起,衰减余弦(帧 72 前仍有可见残余,硬切归零成"啪")
  const t = frame - HIT;
  const m = split ? Math.cos(OMEGA * t) * Math.exp(-t / TAU) : 0;
  const dx = AX * m;
  const dy = AY * m;

  // 套准合一脉冲:帧 72 起 4f scale 1.03 → 1,之后精确 1(保证结尾真静止)
  const pulse =
    frame >= SNAP && frame < SNAP + 4 ? 1 + 0.03 * (1 - (frame - SNAP) / 4) : 1;

  return (
    <div
      style={{
        width: 1920,
        height: 1080,
        background: G.bg,
        position: 'relative',
        overflow: 'hidden',
      }}
    >
      {/* 底部装饰线:全程静止的布景锚点 */}
      <div
        style={{
          position: 'absolute',
          left: 510,
          top: 740,
          width: 900,
          height: 6,
          borderRadius: 3,
          background: G.bar,
        }}
      />

      {/* 正体:画外等待 / 撞入 / 套准后(撞入前 frame<20 时在画外,视觉等同空场) */}
      {showSingle && (
        <div
          style={{
            position: 'absolute',
            inset: 0,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            transform: `translateX(${entering || frame < 20 ? slideX : 0}px) scale(${pulse})`,
            transformOrigin: 'center center',
          }}
        >
          <TitleBlock text="IMPACT" size={200} />
        </div>
      )}

      {/* 双版错位:浅灰版与深墨版反向偏移,multiply 叠加出"重影套印" */}
      {split && (
        <>
          <Plate color={G.mid} dx={-dx} dy={dy} />
          <Plate color={G.ink} dx={dx} dy={-dy} />
        </>
      )}
    </div>
  );
};


  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/effects/riso-print-hits/RisoBeatPump.tsx, demos/effects/riso-print-hits/RisoMisregistrationHit.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