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
$ npx remotion-ui@latest add ik-rigA 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
targetand the hand follows it. The target can be a fixed point, anae-motionkeyframe 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.
bendfixes the side the elbow folds to, so it can never flip mid-shot.softnessis soft IK: the arm eases into full extension instead of popping straight when a target runs away from it.baseis 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 →
@/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-uinpm package; it is copied into your project.
Usage
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
| Prop | Type | Default | Description |
|---|---|---|---|
| base* | Animatable<[number, number]> | - | Shoulder position. Animate it to mount the arm on a rail, a vehicle or a body. |
| lengths | readonly [number, number] | [220, 200] | Upper arm and forearm length, px. |
| target | Animatable<[number, number]> | - | What the hand reaches for: static, keyframed or an expression. Ignored when plot is set. |
| plot | IkPlot | - | { 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. |
| bend | 1 | -1 | 1 | Side the elbow folds to. Fixed for the shot, so the elbow never flips. |
| softness | number | 0.08 | Soft IK: share of the reach over which the arm eases into full extension instead of popping straight. |
| thickness | number | 34 | Upper-arm width, px; the rest of the arm is proportioned from it. |
| armColor | string | "#80848f" | Anodised body colour; lit and shaded per frame from lightAngle. |
| accentColor | string | "#2dd4bf" | Status light on the pen head; bright while the pen is down. |
| inkColor | string | "#e8b86d" | Ink and the hot glow at the nib. |
| inkWidth | number | 4 | Ink stroke width, px. |
| glow | number | 0.6 | Bloom on the ink, 0–1. 0 draws flat ink. |
| lightAngle | number | -125 | Direction the key light comes from, degrees in screen space (-90 = from above). |
| shadow | number | 0.55 | Cast-shadow opacity. Shadow offset grows with each part's height and with pen lift. |
| cable | boolean | true | Slack service cable from base to elbow (a constant-length rubber hose). |
| renderArm | (pose: IkPose) => ReactNode | - | Replaces the built-in arm with your own SVG, drawn from the solved pose. |
| renderUnder | (pose: IkPose) => ReactNode | - | SVG under the ink — paper, beds, rails. |
| renderOver | (pose: IkPose) => ReactNode | - | SVG over everything. |
| width | number | 960 | SVG width in px. |
| height | number | 540 | SVG height in px. |
| frame | number | - | Render this frame instead of the current one. |
Related
Slit Scan
Slit-scan time displacement: each strip of any child — rows, columns, rings or a gradient map — shows that child at a different moment, deterministically. Install with npx remotion-ui@latest add slit-scan.
Track Matte
After Effects track mattes: reveal any child through any other with alpha, inverted alpha, luma or inverted luma. Install with npx remotion-ui@latest add track-matte.