Skip to content

Getting started

damped is a family of three packages that share one spring. This page gets you from an empty project to an element that you can interrupt mid-flight.

You build with Install What you get
The DOM, with or without a framework @damped/core animate, layout, morph, enter and exit, createSpringValue and the spring itself.
React 19 @damped/react and @damped/core useSpring, useSpringValue, useLayout, useMorph and <Presence>. Values reach the DOM without re-rendering on every frame.
React Native with Reanimated 4 (Expo SDK 57) @damped/native withDamped and toReanimated, which keep velocity on reversal. See React Native.

@damped/react builds on @damped/core, so the two are installed together.

bun add @damped/core

For React, install the React package next to the core:

bun add @damped/react @damped/core

The packages are ES modules with no runtime dependencies. They are tested in Chromium; @damped/react needs React 19.

animate(element, values, options) moves an element to the values you give it. x and y are pixels, scale is a ratio, opacity runs from 0 to 1.

import { animate } from "@damped/core";
const card = document.querySelector<HTMLElement>("#card");
if (card) {
let open = false;
card.addEventListener("click", () => {
open = !open;
animate(
card,
{ x: open ? 240 : 0, opacity: open ? 0.6 : 1 },
{ duration: 0.5, bounce: 0.2 },
);
});
}

Click the card twice quickly. The second call does not wait for the first one and does not restart from rest: it starts from the position and the velocity the card has at that moment, so the card turns around smoothly. That is the property the whole library is built around, and the interruption guide explains it.

useSpring returns a ref. Attach it to an element and give the hook the styles the element should spring to.

import { useState } from "react";
import { useSpring } from "@damped/react";
export function Card() {
const [open, setOpen] = useState(false);
const ref = useSpring<HTMLButtonElement>(
{ x: open ? 240 : 0, opacity: open ? 0.6 : 1 },
{ duration: 0.5, bounce: 0.2 },
);
return (
<button ref={ref} type="button" onClick={() => setOpen((value) => !value)}>
Corner Grocery
</button>
);
}

The component renders when open changes and not once per animation frame: every frame is written to the DOM through the ref. Changing open again mid-flight retargets the running spring and keeps its velocity.

A spring is a pure function of time, so you can sample it without animating anything. This is handy for understanding what your duration and bounce do.

import { createSpring } from "@damped/core";
// Move from 0 to 100, starting at rest.
const spring = createSpring(0, 100, 0, { duration: 0.5, bounce: 0.15 });
const { position, velocity } = spring.at(0.25);
console.log(position.toFixed(1), velocity.toFixed(1), spring.settleTime().toFixed(2));
// 89.5 164.6 1.16

After a quarter of a second the value is at 89.5 and still moving at 164.6 units per second. It comes to rest after 1.16 s. Note that duration is not the time to rest; Springs explained covers what it is.