RemotionUI

IK Rig

A lit, shadowed two-bone IK arm that reaches for any target or plots SVG strokes with a pen, laying ink exactly where the solved hand is. Install with npx remotion-ui@latest add ik-rig.

PrimitiveMotion graphicsAdvanced

ik-rig30fps · 960×540
Install
$ npx remotion-ui@latest add ik-rig

A two-bone inverse-kinematics arm built like a SCARA plotter. Move the hand and the elbow solves itself. The solve is closed-form law of cosines on every frame, so it has no drift or jitter and gives the same result in any render order.

  • Reach. Pass a target and the hand follows it. The target can be a fixed point, an ae-motion keyframe track, or an expression (another rig's hand, a cursor, a product shot's hotspot).
  • Plot. Pass plot={{ d }} and the arm draws the SVG strokes with a pen, laying ink exactly under the solved hand. The pen moves the way a plotter's motion controller drives it. It cruises with ramped acceleration and brakes to a stop in every cusp. Between strokes it lifts, travels with a little anticipation and overshoot, settles, and drops with a small rebound.
  • Mechanics. bend fixes the side the elbow folds to, so it can never flip mid-shot. softness is soft IK: the arm eases into full extension instead of popping straight when a target runs away from it. base is animatable, so the arm can ride a rail, a vehicle or a character.

The built-in arm is lit from lightAngle. Each link's bevel and specular edge are re-shaded from its heading every frame, and every part casts a blurred shadow whose offset grows with its height. The pen's own shadow separates from the nib as it lifts. Pass renderArm to draw your own arm from the solved pose.

The preview is the whole API at work. A rail-mounted plotter signs "motion" in one continuous cursive stroke, flicks into an underline, crosses the t and dots the i. The base rides the rail on an expression that trails the pen, and the camera frames a blend of the word and the rig's centroid, read from solveIkPose.

Usage

import { IkRig } from "@/remotion/primitives/ik-rig";

// Draw a logo stroke, then park.
<IkRig
  base={[640, 480]}
  lengths={[220, 200]}
  plot={{
    d: "M300 260 C380 160 520 360 600 240 M320 320 L580 320",
    speed: 600,          // px/s with the pen down
    startFrame: -30,     // open mid-drawing on frame 0
    park: [700, 300],
  }}
/>

// Reach for a moving target.
<IkRig base={[480, 470]} target={({ time }) => [480 + Math.sin(time * 2) * 180, 220]} />

Every subpath (every M) in plot.d is one pen-down stroke, drawn in document order. Keep the strokes inside the arm's reach, which is between |a − b| and a + b from the base. Out of reach, the hand stops short, the ink no longer meets the nib, and pose.reached is false.

To drive other things off the rig, call solveIkPose() for the pose, or planPlot / penAt / inkAt from lib/pen-plot for the pen, at any frame. The preview's camera and rail do exactly this.

Closed-form law-of-cosines solve every frame: no drift, no jitter, same result in any render order. Plots must stay inside the arm's reach (|a − b| to a + b from the base); out of reach, the hand stops short and pose.reached is false. solveIkPose() and lib/pen-plot's planPlot/penAt/inkAt are exported for cameras or props driven off the rig.

Agent notes

Install first, then import the copied source component locally. AI guide →

Import
@/remotion/primitives/ik-rig
  • Use when: After Effects-style motion graphics built from composable, keyframeable operators.
  • Customize: base, lengths, target, plot, plus copied source for timing, layout, colors, and typography.
  • Rule: do not import this component from the remotion-ui npm package; it is copied into your project.

Usage

Example
import { IkRig } from "@/remotion/primitives/ik-rig"; // A plotter: the arm draws the strokes, ink lands exactly under the solved hand. <IkRig base={[640, 480]} lengths={[220, 200]} plot={{ d: "M300 260 C380 160 520 360 600 240", speed: 600, park: [700, 300] }} /> // A reach: point the hand at anything — a keyframed track, an expression, another rig's hand. <IkRig base={[480, 470]} target={({ time }) => [480 + Math.sin(time * 2) * 180, 220]} />

API Reference

PropTypeDescription
base*Animatable<[number, number]>Shoulder position. Animate it to mount the arm on a rail, a vehicle or a body.
lengthsreadonly [number, number]Upper arm and forearm length, px.
targetAnimatable<[number, number]>What the hand reaches for: static, keyframed or an expression. Ignored when plot is set.
plotIkPlot{ d, speed?, travelSpeed?, ramp?, cornerAngle?, liftFrames?, minTravelFrames?, overshoot?, startFrame?, home?, park? } — strokes the hand draws with a pen. Each subpath is one pen-down stroke.
bend1 | -1Side the elbow folds to. Fixed for the shot, so the elbow never flips.
softnessnumberSoft IK: share of the reach over which the arm eases into full extension instead of popping straight.
thicknessnumberUpper-arm width, px; the rest of the arm is proportioned from it.
armColorstringAnodised body colour; lit and shaded per frame from lightAngle.
accentColorstringStatus light on the pen head; bright while the pen is down.
inkColorstringInk and the hot glow at the nib.
inkWidthnumberInk stroke width, px.
glownumberBloom on the ink, 0–1. 0 draws flat ink.
lightAnglenumberDirection the key light comes from, degrees in screen space (-90 = from above).
shadownumberCast-shadow opacity. Shadow offset grows with each part's height and with pen lift.
cablebooleanSlack service cable from base to elbow (a constant-length rubber hose).
renderArm(pose: IkPose) => ReactNodeReplaces the built-in arm with your own SVG, drawn from the solved pose.
renderUnder(pose: IkPose) => ReactNodeSVG under the ink — paper, beds, rails.
renderOver(pose: IkPose) => ReactNodeSVG over everything.
widthnumberSVG width in px.
heightnumberSVG height in px.
framenumberRender this frame instead of the current one.

On this page