agentsclimarketplace

Remotion keyframes

Skill phamthanhnghia/remotion-agent-skills/skills/remotion-keyframes

Programmatic video creation agent skills suite for Remotion, modeled on HyperFrames architecture. Build explainers, product launches, motion graphics, captions, and data viz with AI.

Install
npx -y skills add phamthanhnghia/remotion-agent-skills --skill remotion-keyframes

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

3 things to look at

  • 15 days oldThe repository was created 15 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Keyframe animation engine for Remotion. Use for precise frame-level animation, interpolate curves, stagger patterns, entrance/exit choreography, and text reveal animations.

SKILL.md

7.0 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it

Remotion Keyframes

Keyframes are a pose contract: visible states, continuous subject identity, frame-deterministic, verified pixels.

Use remotion-animation for broad scene recipes. Use remotion-cli for full command docs.

Procedure

  1. Identify the animated subject, visible states, final state, and animation primitive (spring or interpolate).
  2. Choose the smallest mechanism that proves the prompt.
  3. Author frame-deterministic keyframes. All values derive from useCurrentFrame().
  4. Verify with npx remotion studio — scrub the full timeline, check first frame, all poses, and final frame.
  5. If proof fails, fix the source keyframes and re-verify before rendering.

Contract

  • Name the moving subject.
  • Name the poses needed to prove the intended motion, including the final state.
  • Keyframe visible channels, not hidden helper state.
  • Preserve object identity when continuity matters.
  • Hold readable or semantic states long enough to see (minimum 10 frames for text, 6 frames for icon).
  • Final frame is part of the animation, not cleanup.
  • Do not reset to rest unless requested.
  • Do not end on black unless requested.

Runtime Rules

interpolate() and spring():

  • all values computed synchronously from frame — no async inside interpolate/spring calls
  • extrapolateLeft: 'clamp' and extrapolateRight: 'clamp' to prevent value leaking outside intended range
  • spring({frame, fps, config}) — frame must be the Remotion useCurrentFrame() value, not a derived Date.now() derivative
  • For entrances, offset spring: spring({frame: frame - delay, fps, config}); use Math.max(0, frame - delay) to avoid negative frames driving spring

Never use for render-critical motion:

  • Date.now() or performance.now()
  • unseeded Math.random() (use Remotion's random(seed) instead)
  • CSS transitions or CSS animations (they don't seek)
  • requestAnimationFrame
  • setTimeout / setInterval in render path
  • useState / useEffect for visual-property values

Spring Config Reference

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

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

// Snappy entrance (default feel)
const scale = spring({frame, fps, config: {damping: 200}});

// Bouncy entrance
const bounce = spring({frame, fps, config: {damping: 8, stiffness: 300}});

// Very smooth, slow
const smooth = spring({frame, fps, config: {damping: 30, stiffness: 80, mass: 2}});

// Sharp exit (reverse spring — animate from 1 to 0)
const {durationInFrames} = useVideoConfig();
const exitFrame = durationInFrames - frame;
const exitScale = spring({frame: exitFrame, fps, config: {damping: 200}});
const scaleValue = 1 - (1 - exitScale) ; // goes from 1 down to 0

Interpolate Recipes

import {interpolate} from 'remotion';

// Fade in over 20 frames
const opacity = interpolate(frame, [0, 20], [0, 1], {extrapolateRight: 'clamp'});

// Slide in from left
const x = interpolate(frame, [0, 30], [-300, 0], {
  extrapolateLeft: 'clamp',
  extrapolateRight: 'clamp',
});

// Multi-stop color shift
const r = interpolate(frame, [0, 30, 60], [255, 100, 0], {extrapolateRight: 'clamp'});
const g = interpolate(frame, [0, 30, 60], [0, 150, 255], {extrapolateRight: 'clamp'});

// Scale pop
const scale = interpolate(frame, [0, 8, 12, 18], [0, 1.15, 0.95, 1], {
  extrapolateLeft: 'clamp',
  extrapolateRight: 'clamp',
});

Channels

Prefer compositor/visual channels: transform: translateX/Y/Z, transform: scale/rotate/skew, opacity, borderRadius, CSS vars, clipPath, SVG strokeDashoffset.

Avoid layout channels: top/left/right/bottom, width/height, margin/padding — they trigger reflow, are slow, and produce incorrect results when the renderer samples frames in parallel.

Stagger Pattern

const ITEM_COUNT = 5;
const STAGGER_FRAMES = 8; // delay between each item

const items = Array.from({length: ITEM_COUNT}, (_, i) => {
  const delayedFrame = Math.max(0, frame - i * STAGGER_FRAMES);
  const itemSpring = spring({frame: delayedFrame, fps, config: {damping: 200}});
  return {opacity: itemSpring, y: (1 - itemSpring) * 40};
});

Text Animation Pattern

const words = 'Hello Remotion World'.split(' ');

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

  return (
    <div style={{display: 'flex', gap: 12}}>
      {words.map((word, i) => {
        const delayedFrame = Math.max(0, frame - i * 6);
        const progress = spring({frame: delayedFrame, fps, config: {damping: 200}});
        return (
          <span
            key={i}
            style={{
              opacity: progress,
              transform: `translateY(${(1 - progress) * 20}px)`,
              display: 'inline-block',
            }}
          >
            {word}
          </span>
        );
      })}
    </div>
  );
};

SVG Stroke Draw

// SVG stroke-dasharray draw-on effect
const pathLength = 500; // measure with path.getTotalLength() in development
const drawProgress = interpolate(frame, [0, 60], [0, 1], {extrapolateRight: 'clamp'});

<path
  d="M 0 0 L 300 200"
  stroke="white"
  strokeWidth={4}
  fill="none"
  strokeDasharray={pathLength}
  strokeDashoffset={pathLength * (1 - drawProgress)}
/>

3D Depth (CSS Perspective)

// CSS perspective 3D scene
<div style={{perspective: 800, perspectiveOrigin: '50% 50%'}}>
  <div
    style={{
      transformStyle: 'preserve-3d',
      transform: `rotateY(${interpolate(frame, [0, 60], [45, 0], {extrapolateRight: 'clamp'})}deg)`,
    }}
  >
    {/* 3D content */}
  </div>
</div>

Mechanism Choice

NeedMechanism
Entrance with natural decelerationspring()
Timed value transitioninterpolate()
Multi-stop sequenceinterpolate() with multiple input/output stops
Many items with ordered entrancestagger: indexed frame - i * delay in spring()
Text reveal (word by word)stagger spring per word index
Stroke grows or tracesstrokeDashoffset via interpolate()
Shape reveal boundaryclipPath via interpolate()
3D depth sceneCSS perspective + rotateX/Y/Z via interpolate()

Error Handling

FailureFix
Values jump at certain framesCheck for negative frame passed to spring() — clamp with Math.max(0, frame - delay)
Animation doesn't seek correctlyConfirm no useState/CSS animation driving the value
Black frames at start or endCheck extrapolateLeft: 'clamp' on entrance, extrapolateRight: 'clamp' on exit
Text blinking / inconsistentEnsure random() seed is a stable string, not Math.random()
Spring overshoots off-screenIncrease damping (200 = no overshoot, 8 = lots of bounce)

Done

Verify in Studio: scrub first frame, all visible poses, final frame. Confirm subject-owned motion, no debug overlays, no flash on first frame.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.