Motion · Light & emphasis
Riso print hits
Two Riso-print misregistration hits: a single split-and-snap impact, and a rhythmic version that compounds beat by beat.
Source: video-shotcraft (Vincent Wei) ↗ · Apache-2.0 · Remotion composition (React/TSX) — preview video, no in-browser player
Variants
The title slams in and freezes over 8f, splitting into two plates offset ~32px in opposite directions, decaying and oscillating for 44f before a hard cut snaps them into register with a scale pulse.
A stamp-of-impact used 1-2 times in the whole film; the landing instant for a title/large text
One beat every 24f: the whole frame snap-jumps to 1.08 scale with an exponential fall-back, plus the title's plate misregistration compounding beat by beat at 8/14/22/32px before snapping into register.
A music beat-hit section; a build-up of repeated hits that "gets harder every time"
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.
Everything on this page is also machine-readable. Point your agent at the JSON, or add the gimgs MCP server and ask it to search motion templates.
- Fetch the JSON — it holds the shot recipe (timing, easing, parameter table, pitfalls) and the full TSX source.
- Clone the video-shotcraft repo; the component imports shared fixtures from demos/_fixtures and helpers from assets/lib.
- Register the component as a <Composition> in a Remotion project and render with `npx remotion render`, or re-implement the recipe in your own engine.
curl -s https://gimgs.net/motion/riso-print-hits.jsongit 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.mp4claude 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).
// ===== 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>
);
};
- Read the recipePrompt = when to use, intention, parameter table with typical values and how each one feels, known pitfalls. Treat values as calibrated starting points.
- Get the codetool: git
git clone https://github.com/Vincentwei1021/video-shotcraft && cd video-shotcraft && npm install - Register + rendertool: remotion
npx remotion render <CompositionId> out.mp4 # component: demos/effects/riso-print-hits/RisoBeatPump.tsx, demos/effects/riso-print-hits/RisoMisregistrationHit.tsx - Or re-implementPort the timing/easing from the recipe to HTML + WAAPI (gimgs motion contract) or any engine; keep the same segment windows and easing.
| param | type | default | description |
|---|---|---|---|
| — | |||
More in this category

Dark-stage spotlight reveals
Three dark-stage spotlight reveals — A wake-sleep sweep (light in = bright, light out = dark), B edge-hugging glow pan (violet light seeps along UI edges + steady rightward sweep), C corner reveal (radial light expands steadily from a corner to light the whole screen); light itself narrates in the dark.

Slam entrance moves
Three high-energy slam entrances: a whip-in perspective stop, a heavy KPI drop, and a shockwave that hits neighboring cards.

Scanline assemble fly-in
A scan line sweeps down an empty grid, flying each region's component in from off-screen — finishing as the scan ends.

Scanline annotate focus
A bright scan line sweeps down the page, framing each element it passes and labeling it with monospace annotations.