Skip to content

No.79 · Buttons· New

Yarn Wrap

Point at the button and a ball of yarn rolls round it from where you came in, unwinding as it goes and leaving the thread wrapped round the pill in loose laps that cross each other; the ball shrinks as it pays out. Leave and it winds itself back up. Press to make the ball hop.

The prompt

Copy this text

Automatic copying is unavailable. Copy the selected text using your device’s copy command.

Written for the variant you picked above: Wool

Build a pill button that a ball of yarn wraps itself round. Props: children, yarn (one of three yarns), onClick, type and motion. Geometry (pure functions): the pill outline walked by distance with its tangent and outward normal, the distance nearest a point, and a coil — 2.3 laps round the outline from the entry point in the direction the pointer was moving, sampled every 3px, each sample pushed out from the edge by 7 + 4·sin(2π·3.3t/L) + 2·sin(2π·7.1t/L + 1) px so the laps drift in and out and cross each other. Plus running lengths along a polyline and the point (with direction) at any distance along it. An SVG overlay 34px round the button, pointer-events none, draws the coil twice through a mask: a 2.6px round-capped stroke in the yarn colour with a faint shadow, and a lighter 1.1px dashed strand (1.6 2.4) on top for the twist of the plies. The mask is the same path as an 8px white stroke whose dash offset reveals it. A ball rides the head of the revealed thread: a circle with five curved strand lines, rolling — rotated by distance travelled over its radius — and shrinking from 11px to 6px as it pays out. Progress runs on requestAnimationFrame: towards 1 on hover at about 0.6/s, slowing as it fills, and back to 0 at 1.5/s on leave, so the yarn winds itself up quicker than it came out; the ball fades when it's home. Pressing makes the ball hop 10px on a sine. Keyboard focus wraps from the top centre; touch wraps on press for 2.4s. Reduced motion jumps straight to wrapped or unwrapped. The button: a 54px pill in a deep colour with a light label and a 1px lift on hover. Selected variant — Wool (wool): Tomato-red wool #c8432f with a peach twist #f19a7f round a dark brown #2c2420 button, on oatmeal #f2e8dc. This selection takes precedence over references to other themes or options in the general brief. Implement this selected appearance; do not add a variant picker or alternative appearances unless requested. Implementation requirements: Use React and TypeScript. Keep the component self-contained, with uniquely scoped CSS and no animation libraries. Include required imports, styles and font setup in the result. Interaction: Point at the button to wrap it in yarn; leave to wind it back; press to make the ball hop. Keyboard focus wraps it too. Motion: The thread pays out over about two seconds and winds back in under one; the ball rolls and shrinks with it. Reduced motion skips the movement. Accessibility: A real button with its text label; the yarn is decorative SVG, hidden and pointer-transparent. Responsive behavior: Leave about 34px of room round the button. Touch: A press wraps the button for a couple of seconds. Preserve keyboard access, visible focus and reduced-motion behavior. Keep fictional demo data and simulated service calls in a separate usage example; expose callbacks for real actions and recover from rejected requests. Keep usage-example links inside the demo: use local buttons or prevent navigation. Demonstration links must not navigate to Vitrine routes or open other pages; preserve real URL support in the reusable component itself. Verify the result at narrow and wide viewport sizes, with keyboard input and reduced motion enabled.

Notes

Interaction
Point at the button to wrap it in yarn; leave to wind it back; press to make the ball hop. Keyboard focus wraps it too.
Motion
The thread pays out over about two seconds and winds back in under one; the ball rolls and shrinks with it. Reduced motion skips the movement.
Accessibility
A real button with its text label; the yarn is decorative SVG, hidden and pointer-transparent.
Responsive
Leave about 34px of room round the button.
On touch
A press wraps the button for a couple of seconds.

Loading components…