Lab · Tool

Tug

An interaction workbench for the gap between a Figma file and the code: bring your own button or card, compose how it should behave under the pointer, tune it by feel, and leave with something exact.

Tug's workspace: a row of cards across the top of a light stage, one card large in the center, and the stack, feel, and export code in a panel on the right Click here to open the tool full screen
Tug's workspace: a row of cards across the top of a light stage, one card large in the center, and the stack, feel, and export code in a panel on the right

Tug is a desktop tool. Open this page on a larger screen to use it here.

The workbench wants the whole window. Open it full screen, sweep across the recipe row, then click one and pull the sliders.

Open full screen
Role
Design and engineering
Build
One file, no dependencies
Runs
In your browser, nothing uploaded

What it's for

A designer decides how a button should feel, and then has no way to hand that over. Figma prototypes stop short of the pointer, and the code on the other side starts from a sentence. Four things go wrong in that gap.

  • Figma can't follow the pointer. Prototypes have hover and springs, but nothing that tracks the cursor, so magnetic, tilt, and spotlight effects can't be shown at all.
  • Springs don't travel. Figma's spring values never reach the code, and a developer's easing never comes back to the design.
  • The handoff is a sentence. "Make it feel a little bouncy" turns into a guess, then a round of feedback, then another guess.
  • Galleries show their button. Effect libraries demo on a sample component, so you can't judge the feel on the thing you actually designed.

Tug sits in the gap. You bring the real component, build up how it should behave, feel it, and hand over the code and the spec together.

How to use it

  1. Bring your component

    Start with a real-looking button, product card, article card, or pricing card, or bring yours: paste HTML and CSS, paste the CSS that Figma's Dev Mode copies, or drop an image of the frame.

  2. Sweep the row

    Every recipe runs on your component across the top of the stage. Move across them and feel each one before you commit.

  3. Compose the stack

    Click a recipe, then add or remove layers: lift, magnetic, spotlight, tilt, press-sink. Each layer has its own amounts and a reduced-motion policy.

  4. Tune the spring

    Start from Gentle, Quick, Bouncy, or Slow, the same names Figma uses. Flip on Advanced for stiffness, damping, mass, and the response curve. Replay plays the whole motion without the pointer; Throw flicks a magnetic element and lets it settle.

  5. Check it honestly

    Toggle the dark stage, touch, reduced motion, and keyboard focus to see exactly what each kind of visitor gets.

  6. Hand it off

    Copy the CSS and JS, the reduced-motion variant, or a spec sentence and table for a ticket or a Dev Mode note. The share link carries the whole recipe.

What it can do

Your component, not ours
Every recipe runs on what you pasted, inside a sandbox that strips scripts and outside requests.
Layers that compose
Transforms stack in a fixed order, so lift, magnetic, tilt, and press never fight over the same channel.
Figma's spring dialect
Stiffness, damping, and mass, with the same preset names, so values move between the file and the tool without translation.
Code that matches the stage
The runtime on the stage is the same function the JS export ships. A lift-only recipe exports as pure CSS with the spring sampled into a linear() easing.
Reduced motion by policy
Each layer is kept as a short cross-fade or dropped, and the export writes the media query for you.
Cheap to run
Only transform and opacity animate. Shadows and spotlights live on pseudo-elements that fade, so nothing repaints per frame.

How it works

  1. recipe stage code spec link

    One recipe drives everything

    A recipe is a small JSON object: a spring and a list of layers. The stage plays it, the exporters compile it, the spec reads it aloud, and the share link encodes it. There is no second model to keep in sync.

  2. Bouncy: 31% overshoot, settles in about 633ms. Gentle in gray.

    Each channel is a spring

    Every moving value, from the lift to each tilt axis, is its own damped spring stepped at 120 updates a second. Stiffness, damping, and mass are the physical constants, the same three Figma exposes, so the feel is a number you can pass along. Shown: Bouncy overshoots by 31% and settles in about 633ms; Gentle, in gray, never crosses the target.

  3. panel stage yours

    The stage runs the export

    Your pasted component renders in a sandboxed frame with no access to the page. Inside it, the function animating the specimen is the same function the JS tab hands you, so what you feel on the stage is what a developer gets.

  4. Quick, 24 samples: transition 283ms linear(0, 0.043 4%, ...)

    CSS when CSS is enough

    A recipe with no pointer-driven layers needs no script. The tool samples the spring's step response into a CSS linear() easing and exports hover, focus, active, and reduced-motion rules on the element itself. Shown: Quick, sampled 24 times into a 283ms transition.

Tug with Advanced on: the product card on the stage, the layer stack with reduced-motion and spring options, the spring sliders and response curve, and the spec table export
Advanced mode: every layer opened up, the spring curve, and the spec table a developer pastes into a ticket.

Need a tool like this for your team?

Email me