Motion · Light & emphasis

Line boil

Line boil — during a hold, text/outline contours wriggle slightly every 3 frames like a hand-redrawn frame, keeping a still image "alive" and breathing.

1920×108016:930 fps4.72s · 142 framesremotionLicense: Apache-2.0#shotcraft#remotion#effects#typography

Source: video-shotcraft (Vincent Wei) ↗ · Apache-2.0 · Remotion composition (React/TSX) — preview video, no in-browser player

When to use

For long holds on title cards/outlined elements (the go-to upgrade for a black-scene title card); a textural technique that piggybacks on another shot.

Intention

The library's precedent demands "real stillness" once things settle, but a long title card freezing completely reads as "the film froze". This card offers a third state: living stillness — the outline gets "redrawn" every 3 frames, position and content completely unchanged, only the line edges breathing very slightly, a century-old convention of hand-drawn animation hold frames. The difference from a rejected drift technique: perceptibility — drift is an overall shift imperceptible to the eye, boiling is contour deformation with stepped jumps that are visible. In a paper-and-ink aesthetic, this is the direct source of "handmade feel".

Duration & energy

  • Duration: Parasitic — the boil segment lasts as long as its host's hold; it has no duration of its own
  • Energy: Low (ambient-noise level)

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

意图

库内 R 系判例要求落定后"真静止",但长字卡(3s+ 的黑场字卡、片尾) 完全冻结会读作"片子卡了"。本卡给第三种状态:活着的静止——轮廓 每 3 帧被"重描"一次,位置内容全然不动,只有线条边缘在极轻微地呼吸, 手绘动画 hold 帧的百年惯例。与 noise-drift(被否决)的区别正是可感性: 漂移是整体 1–3px 位移(肉眼读不出),沸腾是轮廓形变+阶梯跳变(每次 换 seed 都是一次可见的"重描")。纸墨审美里这是"手工感"的直接来源。

动效核心

  • SVG filter:feTurbulence(fractalNoise, baseFrequency 0.015,

numOctaves 2) + feDisplacementMap scale=8(原案 3–6 不可感, 已加码)作用于文字/描边层

  • seed = Math.floor(f/3) 阶梯换——每 3 帧跳一次新形变,

10fps 的手翻书质感;逐帧换 seed 读作电噪不是手绘

  • 摘罩命门(feTurbulence 判例):沸腾段之外 filter 与 SVG defs

根本不渲染(条件挂载),不是 opacity 到 0——否则永不真静止

  • 结构靠对比:demo 用 静止 35f → 沸腾 70f → 摘罩静止 35f 三段

自证可感;实战沸腾段直接铺满宿主 hold

参数表

| 参数 | 典型值 | 调节手感 | |------|--------|----------| | displacement scale | 8(大字标题);小字/细线 5–6 | >12 读作故障扭曲;<4 不可感 | | seed 节拍 | floor(f/3),即每 3 帧重描 | /2 太贼、/4 以上读作卡顿跳帧 | | baseFrequency | 0.015(形变尺度约字高级) | 0.05+ 变成毛边噪点,不是"重描" | | 适用对象 | 大标题、描边框、手绘圈注 | 实心小元素(图标/头像)沸腾读作模糊 | | 与 R 系关系 | 沸腾段视作合法 hold;宿主镜头收尾若需绝对静止则提前 ≥15f 摘罩 | 摘罩瞬间轮廓归位本身就是一次收束 |

已知坑

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

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

  • 全片同时沸腾的元素 ≤1 组——标题在沸腾、卡片框也在沸腾,观众

找不到该看哪(P4)

  • 与 speed-lines/集中线的"沸腾"(impact-feedback C 式每 2 帧换形态)

同族不同职:那是冲击帧的高能沸腾,这是 hold 帧的底噪沸腾,能量 档位差两级,别互换参数

  • SVG filter 对大面积层有渲染开销;1920 全幅文字层可接受,整页

截图套 boil 渲染时间翻倍且语义不对(页面不是手绘物)

  • paper-title-card/黑场字卡(shot-transitions D 式)是本卡首选宿主,

组合时字卡的打字机/压印入场完成后再起沸腾

参考实现

demos/effects/line-boil/ (LineBoil.tsx)

Reference implementation (Remotion)

  • demos/effects/line-boil/LineBoil.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/effects/line-boil/LineBoil.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.

  1. Fetch the JSON — it holds the shot recipe (timing, easing, parameter table, pitfalls) and the full TSX source.
  2. Clone the video-shotcraft repo; the component imports shared fixtures from demos/_fixtures and helpers from assets/lib.
  3. 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/line-boil.json
git clone https://github.com/Vincentwei1021/video-shotcraft
# component: demos/effects/line-boil/LineBoil.tsx
npx remotion render <CompositionId> out.mp4
claude mcp add --transport http gimgs https://gimgs.net/mcp
# then: search_motion_templates / get_motion_template("line-boil")

Prompt

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

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,709 chars · Apache-2.0Open raw template ↗
// ===== demos/effects/line-boil/LineBoil.tsx =====
// 线条沸腾(line-boil)——手绘动画 line boil 质感:静止线稿在"沸腾段"
// 边缘逐帧微颤,像手绘逐帧描线的抖动。SVG filter feTurbulence(baseFrequency
// 0.015, numOctaves 2, seed = Math.floor(f/3) 每 3 帧阶梯换) + feDisplacementMap
// scale=8(原案 3–6 已按可感性加码)作用于大标题 "ALIVE" 与描边卡整层。
// 结构靠"对比"可感:先静止(干净版)→ 沸腾 → 摘罩回静止;判例:feTurbulence
// 收尾必须整个 filter 移除(沸腾段外根本不渲染 filter 与 SVG def),
// 105f 起逐帧完全相同,真静止 ≥35f。
// 关键帧:0–35 完全静止(boil off) → 35–105 沸腾(boil on, seed 每 3 帧一换)
// → 105 摘罩 → 105–140 真静止(boil off)。
import React, { useId } from 'react';
import { useCurrentFrame, interpolate } from 'remotion';
import { G, TitleBlock } from '../../_fixtures/Fixtures';

const BOIL_START = 35;
const BOIL_END = 105;
const BOIL_SCALE = 8; // 原案 3–6 已按可感性加码;QA 看不出再加到 12

const CornerTag: React.FC<{ text: string; opacity: number }> = ({ text, opacity }) => (
  <div
    style={{
      position: 'absolute',
      right: 72,
      bottom: 56,
      padding: '10px 22px',
      border: `3px solid ${G.ink}`,
      borderRadius: 999,
      color: G.ink,
      background: G.bg,
      fontFamily: 'Helvetica, Arial, sans-serif',
      fontWeight: 700,
      fontSize: 30,
      letterSpacing: 2,
      opacity,
    }}
  >
    {text}
  </div>
);

export const LineBoil: React.FC = () => {
  const f = useCurrentFrame();
  // 滤镜 ID 按实例生成,多实例同场不串引(useId 的 «:» 在 url() 里非法,需清洗)
  const boilId = `boil-${useId().replace(/[^a-zA-Z0-9]/g, '')}`;
  const boiling = f >= BOIL_START && f < BOIL_END;
  // seed 每 3 帧阶梯换 → 8~10Hz 的手绘颤动感;帧确定,无随机源
  const seed = Math.floor(f / 3);

  // 角标:boil on 只在沸腾段淡入淡出;boil off 与之互补。
  // 全部过渡在 105f 前完成 → 105–140 逐帧完全相同
  const onOp = interpolate(f, [35, 40, 100, 105], [0, 1, 1, 0], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
  });
  const offOp = 1 - onOp;

  return (
    <div style={{ width: 1920, height: 1080, background: G.bg, position: 'relative', overflow: 'hidden' }}>
      {/* 沸腾段才渲染 filter 定义——摘罩即整个 SVG def 消失,收尾天然真静止 */}
      {boiling && (
        <svg width={0} height={0} style={{ position: 'absolute' }}>
          <defs>
            <filter id={boilId} x="-15%" y="-15%" width="130%" height="130%">
              <feTurbulence
                type="fractalNoise"
                baseFrequency={0.015}
                numOctaves={2}
                seed={seed}
                result="noise"
              />
              <feDisplacementMap
                in="SourceGraphic"
                in2="noise"
                scale={BOIL_SCALE}
                xChannelSelector="R"
                yChannelSelector="G"
              />
            </filter>
          </defs>
        </svg>
      )}

      {/* 手法名标签:不入滤镜层,作为静止参照物 */}
      <div style={{ position: 'absolute', left: 120, top: 96 }}>
        <TitleBlock text="LINE BOIL" size={54} />
      </div>

      {/* 被沸腾的整层:大标题 + 描边卡 */}
      <div
        style={{
          position: 'absolute',
          inset: 0,
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'center',
          justifyContent: 'center',
          gap: 56,
          filter: boiling ? `url(#${boilId})` : undefined,
        }}
      >
        <div
          style={{
            fontFamily: 'Helvetica, Arial, sans-serif',
            fontWeight: 800,
            fontSize: 170,
            color: G.ink,
            letterSpacing: 4,
            lineHeight: 1,
          }}
        >
          ALIVE
        </div>
        {/* 描边卡:透明底 3px ink 描边 520×300 圆角框 + 几条灰线 */}
        <div
          style={{
            width: 520,
            height: 300,
            border: `3px solid ${G.ink}`,
            borderRadius: 20,
            boxSizing: 'border-box',
            padding: '36px 40px',
            display: 'flex',
            flexDirection: 'column',
            gap: 26,
          }}
        >
          <div style={{ height: 16, width: '62%', background: G.mid, borderRadius: 8 }} />
          <div style={{ height: 12, width: '88%', background: G.bar, borderRadius: 6 }} />
          <div style={{ height: 12, width: '74%', background: G.bar, borderRadius: 6 }} />
          <div style={{ height: 12, width: '81%', background: G.bar, borderRadius: 6 }} />
          <div style={{ marginTop: 'auto', display: 'flex', gap: 12, alignItems: 'center' }}>
            <div style={{ width: 30, height: 30, borderRadius: 15, border: `3px solid ${G.ink}`, boxSizing: 'border-box' }} />
            <div style={{ height: 12, width: 120, background: G.mid, borderRadius: 6 }} />
          </div>
        </div>
      </div>

      {/* 状态角标:沸腾段 boil on,静止段 boil off */}
      <CornerTag text="boil on" opacity={onOp} />
      <CornerTag text="boil off" opacity={offOp} />
    </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/line-boil/LineBoil.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
—

More in this category