Token导航 LogoToken导航TokenDH.com
开发需要联网github未标认证来源可访问许可证需确认审计通过

spring-animation春天动画

Agent Skill

用于辅助 Java 项目开发、面向对象设计、Spring 生态、Maven 或 Gradle 依赖和后端工程实践。它适合让 Agent 分析类结构、设计接口、整理服务分层、生成测试或检查常见代码坏味道。使用时需要结合项目已有架构、包结构和依赖版本,不应只按通用教程改代码;涉及数据库、事务、并发或框架配置时,应先确认运行环境和回归测试范围。

总安装

1,335

周安装

54

GitHub Stars

334

下载量

419
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:spring-animation(春天动画)
来源仓库:https://github.com/notedit/happy-skills
仓库路径:skills/spring-animation
安装命令:
npx skills add https://github.com/notedit/happy-skills --skill spring-animation
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/notedit/happy-skills --skill spring-animation

简介

用于为 Spring Web 应用添加前端动画交互效果支持。

  • 适用于提升用户界面动态体验的 Web 模块开发场景。
  • 提供基于 Thymeleaf 或 RESTful API 的动画集成方案参考。
  • 需配合前端框架如 Vue 或 React 使用时注意资源加载顺序。
  • 不建议在低性能设备或弱网环境下启用复杂动画逻辑。spring-animation 属于开发类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

When to use

Use this skill when creating Remotion video compositions that need spring physics -- natural, organic motion with bounce, overshoot, and elastic settling.

Use spring when you need:

  • Bouncy/elastic entrances (overshoot + settle)
  • Organic deceleration (not linear, not eased -- physically modeled)
  • Staggered trails with spring physics per element
  • Number counters that overshoot then settle
  • Scale/rotate with natural weight and inertia
  • Enter + exit animations with spring math (in - out)
  • Multi-property orchestration with different spring configs per property

Use Remotion native interpolate() when:

  • Linear or eased motion with no bounce (fade, slide, wipe)
  • Exact timing control (must end at precisely frame N)
  • Clip-path animations
  • Progress bars / deterministic counters

Use GSAP (gsap-animation skill) when:

  • Text splitting (SplitText: chars/words/lines with mask)
  • SVG stroke drawing (DrawSVG)
  • SVG morphing (MorphSVG)
  • Complex timeline orchestration with labels and position parameters
  • ScrambleText decode effects
  • Registered reusable effects

Note: @react-spring/web is NOT compatible with Remotion (it uses requestAnimationFrame internally). This skill uses Remotion's native spring() function which provides the same physics model in a frame-deterministic way.


Core API

spring()

Returns a value from 0 to 1 (can overshoot past 1 with low damping) based on spring physics simulation.

import { spring, useCurrentFrame, useVideoConfig } from 'remotion';

const frame = useCurrentFrame();
const { fps } = useVideoConfig();

const value = spring({
  frame,
  fps,
  config: {
    damping: 10,     // 1-200: higher = less bounce
    stiffness: 100,  // 1-200: higher = faster snap
    mass: 1,         // 0.1-5: higher = more inertia
  },
});

Config Parameters

ParameterRangeDefaultEffect
damping1-20010Resistance. Low = bouncy, high = smooth
stiffness1-200100Snap speed. High = fast, low = slow
mass0.1-51Weight/inertia. High = sluggish, low = light
overshootClampingboolfalseClamp at target (no overshoot)

Additional Options

OptionTypeEffect
delaynumberDelay start by N frames (returns 0 until delay elapses)
durationInFramesnumberForce spring to settle within N frames
reverseboolAnimate from 1 to 0
fromnumberStarting value (default 0)
tonumberEnding value (default 1)

measureSpring()

Calculate how many frames a spring config takes to settle. Essential for <Sequence> and composition duration.

import { measureSpring } from 'remotion';

const frames = measureSpring({
  fps: 30,
  config: { damping: 10, stiffness: 100 },
}); // => number of frames until settled

Physics Presets

// src/spring-presets.ts
import { SpringConfig } from 'remotion';

export const SPRING = {
  // Smooth, no bounce -- subtle reveals, background motion
  smooth: { damping: 200 } as Partial<SpringConfig>,

  // Snappy, minimal bounce -- UI elements, clean entrances
  snappy: { damping: 20, stiffness: 200 } as Partial<SpringConfig>,

  // Bouncy -- playful entrances, attention-grabbing
  bouncy: { damping: 8 } as Partial<SpringConfig>,

  // Heavy, slow -- dramatic reveals, weighty objects
  heavy: { damping: 15, stiffness: 80, mass: 2 } as Partial<SpringConfig>,

  // Wobbly -- elastic, cartoon-like overshoot
  wobbly: { damping: 4, stiffness: 80 } as Partial<SpringConfig>,

  // Stiff -- fast snap with tiny bounce
  stiff: { damping: 15, stiffness: 300 } as Partial<SpringConfig>,

  // Gentle -- slow, dreamy, organic
  gentle: { damping: 20, stiffness: 40, mass: 1.5 } as Partial<SpringConfig>,

  // Molasses -- very slow, heavy, barely bounces
  molasses: { damping: 25, stiffness: 30, mass: 3 } as Partial<SpringConfig>,

  // Pop -- strong overshoot for scale-in effects
  pop: { damping: 6, stiffness: 150 } as Partial<SpringConfig>,

  // Rubber -- exaggerated elastic bounce
  rubber: { damping: 3, stiffness: 100, mass: 0.5 } as Partial<SpringConfig>,
} as const;

Preset Visual Reference

PresetBounceSpeedFeelBest For
smoothNoneMediumButterBackground, subtle reveals
snappyMinimalFastCrispUI elements, buttons
bouncyStrongMediumPlayfulTitles, icons, attention
heavySmallSlowWeightyDramatic reveals, large objects
wobblyExtremeMediumCartoonPlayful, humorous
stiffTinyVery fastMechanicalData viz, precise motion
gentleMinimalSlowDreamyLuxury, calm, organic
molassesAlmost noneVery slowHeavyCinematic, suspense
popStrongFastPunchyScale-in, badge, icon pop
rubberExtremeFastElasticExaggerated, cartoon, fun

1. Spring Entrance Patterns

Basic Spring Entrance

import { spring, interpolate, useCurrentFrame, useVideoConfig, AbsoluteFill } from 'remotion';
import { SPRING } from './spring-presets';

const SpringEntrance: React.FC<{
  children: React.ReactNode;
  preset?: keyof typeof SPRING;
  delay?: number;
}> = ({ children, preset = 'bouncy', delay = 0 }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  const progress = spring({ frame, fps, delay, config: SPRING[preset] });
  const translateY = interpolate(progress, [0, 1], [60, 0]);

  return (
    <AbsoluteFill style={{
      opacity: progress,
      transform: `translateY(${translateY}px)`,
    }}>
      {children}
    </AbsoluteFill>
  );
};

Scale Pop

const ScalePop: React.FC<{
  children: React.ReactNode;
  delay?: number;
}> = ({ children, delay = 0 }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  // pop preset overshoots past 1, creating natural scale bounce
  const scale = spring({ frame, fps, delay, config: SPRING.pop });
  const opacity = spring({ frame, fps, delay, config: SPRING.smooth });

  return (
    <div style={{
      transform: `scale(${scale})`,
      opacity,
    }}>
      {children}
    </div>
  );
};

Enter + Exit (Spring Math)

const EnterExit: React.FC<{
  children: React.ReactNode;
  enterDelay?: number;
  exitBeforeEnd?: number; // frames before composition end to start exit
}> = ({ children, enterDelay = 0, exitBeforeEnd = 30 }) => {
  const frame = useCurrentFrame();
  const { fps, durationInFrames } = useVideoConfig();

  const enter = spring({ frame, fps, delay: enterDelay, config: SPRING.bouncy });
  const exit = spring({
    frame, fps,
    delay: durationInFrames - exitBeforeEnd,
    config: SPRING.snappy,
  });

  const scale = enter - exit; // 0 -> 1 -> 0
  const opacity = enter - exit;

  return (
    <div style={{ transform: `scale(${scale})`, opacity }}>
      {children}
    </div>
  );
};

2. Trail / Stagger Patterns

Spring Trail (staggered entrance)

Mimics React Spring's useTrail -- each element enters with a frame delay.

const SpringTrail: React.FC<{
  items: React.ReactNode[];
  staggerFrames?: number;
  preset?: keyof typeof SPRING;
  direction?: 'up' | 'down' | 'left' | 'right';
}> = ({ items, staggerFrames = 4, preset = 'bouncy', direction = 'up' }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  const getOffset = (progress: number) => {
    const distance = 50;
    const remaining = interpolate(progress, [0, 1], [distance, 0]);
    switch (direction) {
      case 'up': return { transform: `translateY(${remaining}px)` };
      case 'down': return { transform: `translateY(${-remaining}px)` };
      case 'left': return { transform: `translateX(${remaining}px)` };
      case 'right': return { transform: `translateX(${-remaining}px)` };
    }
  };

  return (
    <>
      {items.map((item, i) => {
        const delay = i * staggerFrames;
        const progress = spring({ frame, fps, delay, config: SPRING[preset] });
        return (
          <div key={i} style={{ opacity: progress, ...getOffset(progress) }}>
            {item}
          </div>
        );
      })}
    </>
  );
};

Character Trail (text animation)

Manual character splitting with spring stagger. For advanced text splitting (mask reveals, line wrapping), use gsap-animation skill instead.

const CharacterTrail: React.FC<{
  text: string;
  staggerFrames?: number;
  preset?: keyof typeof SPRING;
  fontSize?: number;
}> = ({ text, staggerFrames = 2, preset = 'pop', fontSize = 80 }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  return (
    <div style={{ display: 'flex', justifyContent: 'center', overflow: 'hidden' }}>
      {text.split('').map((char, i) => {
        const delay = i * staggerFrames;
        const progress = spring({ frame, fps, delay, config: SPRING[preset] });
        const translateY = interpolate(progress, [0, 1], [fontSize, 0]);

        return (
          <span key={i} style={{
            display: 'inline-block',
            fontSize,
            fontWeight: 'bold',
            color: '#fff',
            opacity: progress,
            transform: `translateY(${translateY}px)`,
            whiteSpace: 'pre',
          }}>
            {char === ' ' ? '\u00A0' : char}
          </span>
        );
      })}
    </div>
  );
};

Word Trail

const WordTrail: React.FC<{
  text: string;
  staggerFrames?: number;
  preset?: keyof typeof SPRING;
  fontSize?: number;
}> = ({ text, staggerFrames = 5, preset = 'bouncy', fontSize = 64 }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const words = text.split(' ');

  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.3em', justifyContent: 'center' }}>
      {words.map((word, i) => {
        const delay = i * staggerFrames;
        const progress = spring({ frame, fps, delay, config: SPRING[preset] });
        const scale = spring({ frame, fps, delay, config: SPRING.pop });

        return (
          <span key={i} style={{
            display: 'inline-block',
            fontSize,
            fontWeight: 'bold',
            color: '#fff',
            opacity: progress,
            transform: `scale(${scale})`,
          }}>
            {word}
          </span>
        );
      })}
    </div>
  );
};

Grid Stagger (center-out)

const GridStagger: React.FC<{
  items: React.ReactNode[];
  columns: number;
  cellSize?: number;
  gap?: number;
}> = ({ items, columns, cellSize = 120, gap = 16 }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const rows = Math.ceil(items.length / columns);
  const centerCol = (columns - 1) / 2;
  const centerRow = (rows - 1) / 2;

  return (
    <div style={{
      display: 'grid',
      gridTemplateColumns: `repeat(${columns}, ${cellSize}px)`,
      gap,
    }}>
      {items.map((item, i) => {
        const col = i % columns;
        const row = Math.floor(i / columns);
        // Distance from center determines delay
        const dist = Math.sqrt((col - centerCol) ** 2 + (row - centerRow) ** 2);
        const delay = Math.round(dist * 4);
        const progress = spring({ frame, fps, delay, config: SPRING.pop });

        return (
          <div key={i} style={{
            width: cellSize, height: cellSize,
            opacity: progress,
            transform: `scale(${progress})`,
          }}>
            {item}
          </div>
        );
      })}
    </div>
  );
};

3. Chain / Sequence Patterns

Spring Chain (sequential animations)

Mimics React Spring's useChain -- animations trigger in sequence using measureSpring for timing.

import { spring, measureSpring, interpolate, useCurrentFrame, useVideoConfig } from 'remotion';

const SpringChain: React.FC = () => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  // Step 1: Container scales in
  const step1Config = SPRING.bouncy;
  const step1 = spring({ frame, fps, config: step1Config });
  const step1Duration = measureSpring({ fps, config: step1Config });

  // Step 2: Title fades up (starts when step1 is 80% done)
  const step2Delay = Math.round(step1Duration * 0.8);
  const step2Config = SPRING.snappy;
  const step2 = spring({ frame, fps, delay: step2Delay, config: step2Config });
  const step2Duration = measureSpring({ fps, config: step2Config });

  // Step 3: Subtitle appears (starts when step2 finishes)
  const step3Delay = step2Delay + step2Duration;
  const step3 = spring({ frame, fps, delay: step3Delay, config: SPRING.gentle });

  return (
    <AbsoluteFill style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      {/* Container */}
      <div style={{
        transform: `scale(${step1})`,
        opacity: step1,
        background: '#1e293b',
        padding: 60,
        borderRadius: 24,
        textAlign: 'center',
      }}>
        {/* Title */}
        <h1 style={{
          fontSize: 72, fontWeight: 'bold', color: '#fff',
          opacity: step2,
          transform: `translateY(${interpolate(step2, [0, 1], [30, 0])}px)`,
        }}>Spring Chain</h1>
        {/* Subtitle */}
        <p style={{
          fontSize: 28, color: 'rgba(255,255,255,0.7)', marginTop: 16,
          opacity: step3,
          transform: `translateY(${interpolate(step3, [0, 1], [20, 0])}px)`,
        }}>Sequential spring orchestration</p>
      </div>
    </AbsoluteFill>
  );
};

useSpringChain Hook

Reusable hook for chaining multiple springs with overlap control.

import { spring, measureSpring, SpringConfig, useCurrentFrame, useVideoConfig } from 'remotion';

type ChainStep = {
  config: Partial<SpringConfig>;
  overlap?: number; // 0-1, how much to overlap with previous step (default 0)
};

function useSpringChain(steps: ChainStep[]) {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  let currentDelay = 0;
  return steps.map((step, i) => {
    if (i > 0) {
      const prevDuration = measureSpring({ fps, config: steps[i - 1].config });
      const overlap = step.overlap ?? 0;
      currentDelay += Math.round(prevDuration * (1 - overlap));
    }
    return spring({ frame, fps, delay: currentDelay, config: step.config });
  });
}

// Usage:
const [container, title, subtitle, cta] = useSpringChain([
  { config: SPRING.bouncy },
  { config: SPRING.snappy, overlap: 0.2 },
  { config: SPRING.gentle, overlap: 0.3 },
  { config: SPRING.pop, overlap: 0.1 },
]);

4. Multi-Property Springs

Different physics per property

const MultiPropertySpring: React.FC<{ delay?: number }> = ({ delay = 0 }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  // Position: snappy (arrives fast)
  const position = spring({ frame, fps, delay, config: SPRING.snappy });
  // Scale: bouncy (overshoots then settles)
  const scale = spring({ frame, fps, delay, config: SPRING.bouncy });
  // Rotation: wobbly (elastic wobble)
  const rotation = spring({ frame, fps, delay, config: SPRING.wobbly });
  // Opacity: smooth (no bounce)
  const opacity = spring({ frame, fps, delay, config: SPRING.smooth });

  const translateX = interpolate(position, [0, 1], [-300, 0]);
  const rotate = interpolate(rotation, [0, 1], [-15, 0]);

  return (
    <div style={{
      transform: `translateX(${translateX}px) scale(${scale}) rotate(${rotate}deg)`,
      opacity,
    }}>
      Multi-Property
    </div>
  );
};

5. Spring Counter

Number counter with spring physics -- overshoots the target then settles.

const SpringCounter: React.FC<{
  endValue: number;
  prefix?: string;
  suffix?: string;
  preset?: keyof typeof SPRING;
  delay?: number;
}> = ({ endValue, prefix = '', suffix = '', preset = 'bouncy', delay = 0 }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  const progress = spring({ frame, fps, delay, config: SPRING[preset] });
  // With bouncy config, progress overshoots past 1.0 before settling
  // This means the counter briefly shows a number > endValue, then settles
  const value = Math.round(progress * endValue);

  return (
    <div style={{
      fontSize: 96, fontWeight: 'bold', color: '#fff',
      fontVariantNumeric: 'tabular-nums',
    }}>
      {prefix}{value.toLocaleString()}{suffix}
    </div>
  );
};

Comparison with linear counter:

  • interpolate() counter: smoothly reaches exact target, no overshoot
  • Spring counter: overshoots then settles -- feels more energetic and alive

6. 3D Transform Patterns

Spring Card Flip

const SpringCardFlip: React.FC<{
  frontContent: React.ReactNode;
  backContent: React.ReactNode;
  flipDelay?: number;
}> = ({ frontContent, backContent, flipDelay = 15 }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  const flipProgress = spring({
    frame, fps, delay: flipDelay,
    config: { damping: 15, stiffness: 80 }, // slow, weighty flip
  });
  const rotateY = interpolate(flipProgress, [0, 1], [0, 180]);

  return (
    <AbsoluteFill style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <div style={{ perspective: 800 }}>
        <div style={{
          width: 500, height: 320, position: 'relative',
          transformStyle: 'preserve-3d',
          transform: `rotateY(${rotateY}deg)`,
        }}>
          <div style={{
            position: 'absolute', inset: 0, backfaceVisibility: 'hidden',
            background: '#1e293b', borderRadius: 16,
            display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 32,
          }}>{frontContent}</div>
          <div style={{
            position: 'absolute', inset: 0, backfaceVisibility: 'hidden',
            background: '#3b82f6', borderRadius: 16, transform: 'rotateY(180deg)',
            display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 32,
          }}>{backContent}</div>
        </div>
      </div>
    </AbsoluteFill>
  );
};

Perspective Tilt

const PerspectiveTilt: React.FC<{
  children: React.ReactNode;
  rotateX?: number;
  rotateY?: number;
  delay?: number;
}> = ({ children, rotateX = -20, rotateY = 15, delay = 0 }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  const progress = spring({ frame, fps, delay, config: SPRING.heavy });
  const rx = interpolate(progress, [0, 1], [rotateX, 0]);
  const ry = interpolate(progress, [0, 1], [rotateY, 0]);
  const translateZ = interpolate(progress, [0, 1], [-200, 0]);

  return (
    <div style={{
      perspective: 1000,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      <div style={{
        transform: `perspective(1000px) rotateX(${rx}deg) rotateY(${ry}deg) translateZ(${translateZ}px)`,
        opacity: progress,
      }}>
        {children}
      </div>
    </div>
  );
};

7. Spring Transitions

Crossfade with Spring

const SpringCrossfade: React.FC<{
  outgoing: React.ReactNode;
  incoming: React.ReactNode;
  switchFrame: number;
}> = ({ outgoing, incoming, switchFrame }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  const outOpacity = frame < switchFrame ? 1 : 1 - spring({
    frame: frame - switchFrame, fps, config: SPRING.smooth,
  });
  const inOpacity = frame < switchFrame ? 0 : spring({
    frame: frame - switchFrame, fps, config: SPRING.smooth,
  });
  const inScale = frame < switchFrame ? 0.95 : interpolate(
    spring({ frame: frame - switchFrame, fps, config: SPRING.bouncy }),
    [0, 1], [0.95, 1]
  );

  return (
    <AbsoluteFill>
      <AbsoluteFill style={{ opacity: outOpacity }}>{outgoing}</AbsoluteFill>
      <AbsoluteFill style={{ opacity: inOpacity, transform: `scale(${inScale})` }}>
        {incoming}
      </AbsoluteFill>
    </AbsoluteFill>
  );
};

Slide Transition with Spring

const SpringSlide: React.FC<{
  outgoing: React.ReactNode;
  incoming: React.ReactNode;
  switchFrame: number;
  direction?: 'left' | 'right' | 'up' | 'down';
}> = ({ outgoing, incoming, switchFrame, direction = 'left' }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  const progress = frame < switchFrame ? 0 : spring({
    frame: frame - switchFrame, fps, config: SPRING.snappy,
  });

  const getTransform = (isOutgoing: boolean) => {
    const offset = isOutgoing ? interpolate(progress, [0, 1], [0, -100]) : interpolate(progress, [0, 1], [100, 0]);
    switch (direction) {
      case 'left': return `translateX(${offset}%)`;
      case 'right': return `translateX(${-offset}%)`;
      case 'up': return `translateY(${offset}%)`;
      case 'down': return `translateY(${-offset}%)`;
    }
  };

  return (
    <AbsoluteFill style={{ overflow: 'hidden' }}>
      <AbsoluteFill style={{ transform: getTransform(true) }}>{outgoing}</AbsoluteFill>
      <AbsoluteFill style={{ transform: getTransform(false) }}>{incoming}</AbsoluteFill>
    </AbsoluteFill>
  );
};

8. Templates

Spring Title Card

const SpringTitleCard: React.FC<{
  title: string;
  subtitle?: string;
  accent?: string;
}> = ({ title, subtitle, accent = '#3b82f6' }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  // Background shape
  const bgScale = spring({ frame, fps, config: SPRING.heavy });
  // Title words stagger
  const words = title.split(' ');
  // Divider
  const dividerWidth = spring({ frame, fps, delay: 8, config: SPRING.snappy });
  // Subtitle
  const subtitleProgress = spring({ frame, fps, delay: 15, config: SPRING.gentle });

  return (
    <AbsoluteFill style={{
      background: '#0f172a',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      {/* Accent circle */}
      <div style={{
        position: 'absolute', width: 300, height: 300, borderRadius: '50%',
        background: `${accent}20`, transform: `scale(${bgScale})`,
      }} />

      <div style={{ textAlign: 'center', position: 'relative', zIndex: 1 }}>
        {/* Title with word stagger */}
        <div style={{ display: 'flex', gap: '0.3em', justifyContent: 'center', flexWrap: 'wrap' }}>
          {words.map((word, i) => {
            const delay = i * 4;
            const progress = spring({ frame, fps, delay, config: SPRING.pop });
            const y = interpolate(progress, [0, 1], [40, 0]);
            return (
              <span key={i} style={{
                fontSize: 80, fontWeight: 'bold', color: '#fff',
                display: 'inline-block',
                opacity: progress,
                transform: `translateY(${y}px) scale(${progress})`,
              }}>{word}</span>
            );
          })}
        </div>

        {/* Divider */}
        <div style={{
          width: 80, height: 3, background: accent, margin: '20px auto',
          transform: `scaleX(${dividerWidth})`, transformOrigin: 'center',
        }} />

        {/* Subtitle */}
        {subtitle && (
          <p style={{
            fontSize: 28, color: 'rgba(255,255,255,0.7)',
            opacity: subtitleProgress,
            transform: `translateY(${interpolate(subtitleProgress, [0, 1], [15, 0])}px)`,
          }}>{subtitle}</p>
        )}
      </div>
    </AbsoluteFill>
  );
};

Spring Lower Third

const SpringLowerThird: React.FC<{
  name: string;
  title: string;
  accent?: string;
  hold?: number;
}> = ({ name, title, accent = '#3b82f6', hold = 90 }) => {
  const frame = useCurrentFrame();
  const { fps, durationInFrames } = useVideoConfig();

  // Enter
  const barIn = spring({ frame, fps, config: SPRING.snappy });
  const nameIn = spring({ frame, fps, delay: 6, config: SPRING.bouncy });
  const titleIn = spring({ frame, fps, delay: 10, config: SPRING.gentle });

  // Exit (spring math subtraction)
  const exitDelay = durationInFrames - 20;
  const barOut = spring({ frame, fps, delay: exitDelay, config: SPRING.stiff });
  const nameOut = spring({ frame, fps, delay: exitDelay - 4, config: SPRING.stiff });
  const titleOut = spring({ frame, fps, delay: exitDelay - 8, config: SPRING.stiff });

  return (
    <AbsoluteFill>
      <div style={{ position: 'absolute', bottom: 80, left: 60 }}>
        {/* Bar */}
        <div style={{
          background: accent, padding: '12px 24px', borderRadius: 4,
          transform: `scaleX(${barIn - barOut})`,
          transformOrigin: 'left',
          opacity: barIn - barOut,
        }}>
          <div style={{
            fontSize: 28, fontWeight: 'bold', color: '#fff',
            opacity: nameIn - nameOut,
            transform: `translateX(${interpolate(nameIn - nameOut, [0, 1], [-20, 0])}px)`,
          }}>{name}</div>
          <div style={{
            fontSize: 18, color: 'rgba(255,255,255,0.8)',
            opacity: titleIn - titleOut,
            transform: `translateX(${interpolate(titleIn - titleOut, [0, 1], [-15, 0])}px)`,
          }}>{title}</div>
        </div>
      </div>
    </AbsoluteFill>
  );
};

Spring Feature Grid

const SpringFeatureGrid: React.FC<{
  features: Array<{ icon: string; label: string }>;
  columns?: number;
}> = ({ features, columns = 3 }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  return (
    <AbsoluteFill style={{
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      background: '#0f172a',
    }}>
      <div style={{
        display: 'grid',
        gridTemplateColumns: `repeat(${columns}, 200px)`,
        gap: 32,
      }}>
        {features.map(({ icon, label }, i) => {
          const delay = i * 5;
          const scale = spring({ frame, fps, delay, config: SPRING.pop });
          const opacity = spring({ frame, fps, delay, config: SPRING.smooth });

          return (
            <div key={i} style={{
              textAlign: 'center', padding: 24,
              background: 'rgba(255,255,255,0.05)', borderRadius: 16,
              transform: `scale(${scale})`, opacity,
            }}>
              <div style={{ fontSize: 48 }}>{icon}</div>
              <div style={{ fontSize: 18, color: '#fff', marginTop: 12 }}>{label}</div>
            </div>
          );
        })}
      </div>
    </AbsoluteFill>
  );
};

Spring Outro

const SpringOutro: React.FC<{
  headline: string;
  tagline?: string;
  ctaText?: string;
  accent?: string;
}> = ({ headline, tagline, ctaText, accent = '#3b82f6' }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  const headlineProgress = spring({ frame, fps, config: SPRING.heavy });
  const taglineProgress = spring({ frame, fps, delay: 12, config: SPRING.gentle });
  const ctaProgress = spring({ frame, fps, delay: 20, config: SPRING.pop });

  return (
    <AbsoluteFill style={{
      background: '#0f172a',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      <div style={{ textAlign: 'center' }}>
        <h1 style={{
          fontSize: 72, fontWeight: 'bold', color: '#fff',
          opacity: headlineProgress,
          transform: `scale(${headlineProgress})`,
        }}>{headline}</h1>

        {tagline && (
          <p style={{
            fontSize: 28, color: 'rgba(255,255,255,0.6)', marginTop: 16,
            opacity: taglineProgress,
            transform: `translateY(${interpolate(taglineProgress, [0, 1], [15, 0])}px)`,
          }}>{tagline}</p>
        )}

        {ctaText && (
          <div style={{
            display: 'inline-block', marginTop: 32,
            background: accent, padding: '16px 40px', borderRadius: 8,
            fontSize: 24, fontWeight: 'bold', color: '#fff',
            transform: `scale(${ctaProgress})`, opacity: ctaProgress,
          }}>{ctaText}</div>
        )}
      </div>
    </AbsoluteFill>
  );
};

9. Utility: useSpringTrail

Reusable hook for trail animations.

import { spring, SpringConfig, useCurrentFrame, useVideoConfig } from 'remotion';

function useSpringTrail(
  count: number,
  config: Partial<SpringConfig>,
  staggerFrames = 4,
  baseDelay = 0,
) {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  return Array.from({ length: count }, (_, i) => {
    const delay = baseDelay + i * staggerFrames;
    return spring({ frame, fps, delay, config });
  });
}

// Usage:
const trail = useSpringTrail(5, SPRING.pop, 4);
// trail = [0.98, 0.85, 0.5, 0.1, 0] -- each item at different progress

10. Utility: useSpringEnterExit

Reusable hook for enter + exit pattern.

function useSpringEnterExit(
  enterConfig: Partial<SpringConfig>,
  exitConfig: Partial<SpringConfig>,
  enterDelay = 0,
  exitBeforeEnd = 30,
) {
  const frame = useCurrentFrame();
  const { fps, durationInFrames } = useVideoConfig();

  const enter = spring({ frame, fps, delay: enterDelay, config: enterConfig });
  const exit = spring({
    frame, fps,
    delay: durationInFrames - exitBeforeEnd,
    config: exitConfig,
  });

  return enter - exit;
}

// Usage:
const progress = useSpringEnterExit(SPRING.bouncy, SPRING.stiff, 0, 25);

11. Combining with Other Skills

const CombinedScene: React.FC = () => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  const bgOpacity = spring({ frame, fps, config: SPRING.smooth });

  return (
    <AbsoluteFill>
      {/* react-animation: visual atmosphere */}
      <div style={{ opacity: bgOpacity }}>
        <Aurora colorStops={['#3A29FF', '#FF94B4']} />
      </div>

      {/* spring-animation: bouncy title entrance */}
      <SpringTitleCard title="Natural Motion" subtitle="Physics-driven beauty" />

      {/* gsap-animation: text splitting that spring can't do */}
      <GSAPTextReveal text="Advanced Typography" />
    </AbsoluteFill>
  );
};
SkillBest For
spring-animationBouncy entrances, elastic trails, organic physics, overshoot effects, spring counters
gsap-animationText splitting (SplitText), SVG drawing (DrawSVG), SVG morphing, complex timeline labels
react-animationVisual backgrounds (Aurora, Silk, Particles), shader effects

12. Composition Registration

export const RemotionRoot: React.FC = () => (
  <>
    <Composition id="SpringTitleCard" component={SpringTitleCard}
      durationInFrames={90} fps={30} width={1920} height={1080}
      defaultProps={{ title: 'SPRING PHYSICS', subtitle: 'Natural motion for video' }} />
    <Composition id="SpringLowerThird" component={SpringLowerThird}
      durationInFrames={180} fps={30} width={1920} height={1080}
      defaultProps={{ name: 'Jane Smith', title: 'Creative Director' }} />
    <Composition id="SpringFeatureGrid" component={SpringFeatureGrid}
      durationInFrames={90} fps={30} width={1920} height={1080}
      defaultProps={{ features: [
        { icon: '🚀', label: 'Fast' },
        { icon: '🎯', label: 'Precise' },
        { icon: '✨', label: 'Beautiful' },
      ]}} />
    <Composition id="SpringOutro" component={SpringOutro}
      durationInFrames={120} fps={30} width={1920} height={1080}
      defaultProps={{ headline: 'GET STARTED', tagline: 'Try it free today', ctaText: 'Sign Up →' }} />
  </>
);

13. Rendering

# Default MP4
npx remotion render src/index.ts SpringTitleCard --output out/title.mp4

# High quality
npx remotion render src/index.ts SpringTitleCard --codec h264 --crf 15

# GIF
npx remotion render src/index.ts SpringTitleCard --codec gif --every-nth-frame 2

# ProRes for editing
npx remotion render src/index.ts SpringTitleCard --codec prores --prores-profile 4444

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

37.83%
按下载量换算159

Claude

29.12%
按下载量换算122

Cursor

19.61%
按下载量换算82

Gemini CLI

8.6%
按下载量换算36

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills