The design tool for how your interface behaves

www.choreomotion.app · 2026-08-03 · by Long Nguyen ·generic
Choreograph hover, press, focus and drag states on a canvas that is a real browser. Design the interaction by doing it, then hand off a live link or the production code. Free, no account needed.

The design tool for how your interface behaves

The design tool for how your interface behaves

Choreograph hover, press, focus and drag states on a canvas that is a real browser. You design the interaction by doing it.

Open ChoreoRead the docsFree · no account · files stay in your browser

The handoff problem

Designers describe motion in Loom recordings. Engineers reinterpret it by eye. What ships is an approximation of an approximation.

Motion tools think in linear timelines and export artefacts that don’t map to component states or respond to real events. Prototypes show intent and ship nothing.

Code gets it exactly right, and asks designers to think in keyframe syntax to get there. So the interaction is rebuilt by hand after handoff, lossily, every time.

Figma is the source of truth for structure. Choreo is the source of truth for behaviour, so the interaction you hand over is the one that ships.

Scrubbing is the whole idea

Try the real thing

Drag a playhead and the component responds in the same frame. No render step, no preview mode. Scroll this section and you are the playhead.

You design the interaction by doing it

Open Choreo

Nothing to declare up front. Choreo's canvas is a real browser, so the thing you drag is the thing your users will touch.

Bank App cardSaved

Compositor onlyLive Preview

BaseClicked410ms

View cards details \*\*7520

JANNET SMITH 2400 3256 2323 7619

EXP DATE 05/35

CVC 123

BANK

Lock your card

What is a virtual card

Your virtual card will have a different number than your physical card. This helps keep your information secure.

Direct deposit

Institution number 832

Transit/branch number 0055

Account number \\\\\\\\

Direct deposit details Void cheque

hover it · click to change state · flip the switch

HoverPressFocusIn-ViewToggleDragLoad

CardTRIGGERScale XScale YMove YOpacity

0ms100ms200ms300ms410ms

This is a real Choreo file, not a picture of one

The Bank App card template, dropped straight into this page. Hover it, click it to flip between its Base and Clicked states, flip the switch. There is no player in between that can drift from what the browser does.

See the canvas docs

New animationesc

Trigger

HoverPressFocusIn-ViewToggleDragLoad

Source element

Pricing cardbutton

Start recording

01

#### Arm a trigger

Pick one of seven triggers and the element that fires it. That is the whole setup.

Recording Hover · Pricing cardStop

Y −8px

0ms140ms400ms

02

#### Then just design

Drag it, restyle it, resize it. Every edit lands as a keyframe at the playhead.

Export

  • Vanilla CSSstyles.css
  • Web Animationsanimation.js
  • ReactCard.tsx
  • Motion Specspec.md
  • Zero dependencies

    03

    #### Copy the output

    The code panel has been compiling the whole time. Take any of the four targets.

    You already know how to animate. You just don't know the syntax.

    There is no Animate tab and no property palette. Arm a trigger, make the change you want, and Choreo writes down what you did.

    Read the authoring guide

    HoverPressFocusIn-ViewToggleDragLoad

    CardLift on hover60fps

    #### Hover

    Enter and exit are edited apart, so a card can rise fast and settle slow instead of playing one curve backwards.

    Recorded

  • Move Y0 → −8px240ms
  • Shadowsoft → deep240ms

Every trigger is authored the same way. Arm it, make the change you want, and Choreo writes down what you did.

Seven triggers, each owning its own timeline

A linear timeline is the wrong shape for interface motion. The unit of choreography here is a trigger state, and enter and exit are edited apart, so a card can rise fast and settle slow.

Browse the trigger docs

Vanilla CSSBehaviourWeb AnimationsReactMotion Spec

styles.css

Copy

.choreo-bank-app-card {  position: relative;  width: 411px;  height: 530px;  background-image: linear-gradient(0deg, #f7f5f5 0%, #efefef 100%);  box-sizing: border-box;  border: 1px solid #ffffff;  overflow: hidden;  border-radius: 31px;}.choreo-bank-app-card__frame-1686561429 {  position: absolute;  left: 23px;  top: 27px;  width: fit-content;  height: fit-content;  box-sizing: border-box;  display: flex;  gap: 10px;  align-items: center;  transform: translateX(0px) translateY(0px);  opacity: 1;  pointer-events: none;}.choreo-bank-app-card__visa-inc-logo-2005-2014-1 {  width: 30px;  height: 11px;}.choreo-bank-app-card__visa-inc-logo-2005-2014-1 svg {  display: block;  width: 100%;  height: 100%;  overflow: visible;}.choreo-bank-app-card__view-cards-details {  width: 125px;  height: 17px;  color: #171717;  font-size: 14px;  font-weight: 500;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__7520 {  width: fit-content;  height: fit-content;  color: #969696;  font-size: 14px;  font-weight: 600;  font-family: 'Inter', sans-serif;  white-space: nowrap;  overflow-wrap: break-word;}.choreo-bank-app-card__card {  appearance: none;  border: none;  margin: 0;  padding: 0;  font: inherit;  text-align: inherit;  background: none;  color: inherit;  position: absolute;  left: 22px;  top: 20px;  width: 367px;  height: 210px;  box-sizing: border-box;  display: flex;  flex-direction: column;  gap: 72px;  padding: 32px 0px;  justify-content: center;  background-image: radial-gradient(circle, #1b1c23 0%, #32343d 100%);  box-shadow: 0px 11px 34px 0px rgba(0, 0, 0, 0.45);  overflow: hidden;  transform: rotateY(180deg);  border-radius: 12px;  opacity: 0;  cursor: pointer;}.choreo-bank-app-card__frame-1686561438 {  position: relative;  align-self: stretch;  height: 63px;  box-sizing: border-box;  display: flex;  flex-direction: column;  gap: 10px;  justify-content: flex-end;}.choreo-bank-app-card__frame-1686561432 {  position: relative;  align-self: stretch;  height: 38px;  box-sizing: border-box;  display: flex;  flex-direction: column;  gap: 10px;  justify-content: center;  background-color: #0000004a;}.choreo-bank-app-card__frame-1686561436 {  position: relative;  align-self: stretch;  height: fit-content;  box-sizing: border-box;  display: flex;  gap: 27px;  padding: 0px 20px;  justify-content: space-between;  opacity: 0.5;}.choreo-bank-app-card__frame-1686561433 {  position: relative;  width: 152px;  height: fit-content;  box-sizing: border-box;  display: flex;  flex-direction: column;  gap: 10px;}.choreo-bank-app-card__jannet-smith {  width: 152px;  height: 12px;  color: #969696;  font-size: 10px;  font-weight: 600;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__2400-3256-2323-7619 {  width: 152px;  height: 17px;  color: #969696;  font-size: 14px;  font-weight: 600;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__frame-1686561437 {  position: relative;  width: fit-content;  height: fit-content;  box-sizing: border-box;  display: flex;  gap: 27px;  align-items: center;}.choreo-bank-app-card__frame-1686561434 {  position: relative;  width: 67px;  height: fit-content;  box-sizing: border-box;  display: flex;  flex-direction: column;  gap: 11px;}.choreo-bank-app-card__exp-date {  width: 67px;  height: 17px;  color: #969696;  font-size: 14px;  font-weight: 600;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__05-35 {  width: 67px;  height: 17px;  color: #969696;  font-size: 14px;  font-weight: 600;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__frame-1686561435 {  position: relative;  width: 31px;  height: fit-content;  box-sizing: border-box;  display: flex;  flex-direction: column;  gap: 11px;}.choreo-bank-app-card__cvc {  width: 31px;  height: 17px;  color: #969696;  font-size: 14px;  font-weight: 600;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__123 {  width: 31px;  height: 17px;  color: #969696;  font-size: 14px;  font-weight: 600;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__card-2 {  appearance: none;  border: none;  margin: 0;  padding: 0;  font: inherit;  text-align: inherit;  background: none;  color: inherit;  position: absolute;  left: 90px;  top: 80px;  width: 227px;  height: fit-content;  box-sizing: border-box;  display: flex;  flex-direction: column;  gap: 28px;  padding: 12px 16px;  justify-content: flex-end;  align-items: flex-end;  background-image: radial-gradient(circle, #1b1c23 0%, #32343d 100%);  box-shadow: 0px 11px 34px 0px rgba(0, 0, 0, 0.45);  overflow: hidden;  border-radius: 12px;  transform: translateX(0px) translateY(0px) scaleX(1) scaleY(1);  cursor: pointer;}.choreo-bank-app-card__frame-1686561427 {  position: relative;  align-self: stretch;  height: fit-content;  box-sizing: border-box;  display: flex;  gap: 137px;  justify-content: space-between;  align-items: center;}.choreo-bank-app-card__bank {  width: 41px;  height: 17px;  color: #ffffff;  font-size: 14px;  font-weight: 800;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__mynaui-contactless {  width: 18px;  height: 18px;}.choreo-bank-app-card__mynaui-contactless svg {  display: block;  width: 100%;  height: 100%;  overflow: visible;}.choreo-bank-app-card__frame-1686561432-2 {  position: relative;  align-self: stretch;  height: fit-content;  box-sizing: border-box;  display: flex;  flex-direction: column;  gap: 10px;}.choreo-bank-app-card__uit-sim-card {  width: 27px;  height: 21px;}.choreo-bank-app-card__uit-sim-card svg {  display: block;  width: 100%;  height: 100%;  overflow: visible;}.choreo-bank-app-card__g4158 {  width: 30px;  height: 11px;}.choreo-bank-app-card__g4158 svg {  display: block;  width: 100%;  height: 100%;  overflow: visible;}.choreo-bank-app-card__frame-1686561430 {  position: absolute;  left: 20px;  top: 218px;  width: 367px;  height: fit-content;  box-sizing: border-box;  display: flex;  flex-direction: column;  gap: 14px;  justify-content: center;  align-items: center;}.choreo-bank-app-card__card-details {  position: relative;  width: 367px;  height: fit-content;  box-sizing: border-box;  display: flex;  flex-direction: column;  gap: 5px;  align-items: center;}.choreo-bank-app-card__frame-1686561427-2 {  position: relative;  align-self: stretch;  height: 108px;  background-color: #ffffff;  overflow: hidden;  border-radius: 20px;  opacity: 0;  display: none;}.choreo-bank-app-card__frame-1686561422 {  position: absolute;  left: 22px;  top: 18px;  width: 323px;  height: fit-content;  box-sizing: border-box;  display: flex;  gap: 159px;  justify-content: space-between;  align-items: flex-end;}.choreo-bank-app-card__lock-your-card {  margin: 0;  width: 114px;  height: 19px;  color: #979797;  font-size: 16px;  font-weight: 500;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__switch {  appearance: none;  border: none;  margin: 0;  padding: 0;  font: inherit;  text-align: inherit;  background: none;  color: inherit;  position: relative;  width: 51px;  height: 24px;  box-sizing: border-box;  display: flex;  gap: 10px;  padding: 0px 2px;  justify-content: flex-end;  align-items: center;  border-radius: 30px;  transform: translateX(0px) translateY(0px);  background-color: #1cc24b;  cursor: pointer;}.choreo-bank-app-card__rectangle-9 {  position: relative;  width: 27px;  height: 20px;  background-color: #ffffff;  transform-origin: 51% 50%;  border-radius: 30px;  transform: translateX(0px) translateY(0px);}.choreo-bank-app-card__frame-1686561423 {  position: absolute;  left: 22px;  top: 71px;  width: 326px;  height: 20px;  box-sizing: border-box;  display: flex;  gap: 115px;  justify-content: space-between;  align-items: center;}.choreo-bank-app-card__what-is-a-virtual-card {  width: 162px;  height: 19px;  color: #979797;  font-size: 16px;  font-weight: 500;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__wordpress-external {  position: relative;  width: 20px;  height: 20px;  overflow: hidden;}.choreo-bank-app-card__wordpress-external-2 {  position: absolute;  left: 0px;  top: 0px;  width: 18px;  height: 18px;}.choreo-bank-app-card__wordpress-external-2 svg {  display: block;  width: 100%;  height: 100%;  overflow: visible;}.choreo-bank-app-card__line-19 {  position: absolute;  left: 23px;  top: 53px;  width: 322px;  height: 1px;  fill: none;  stroke: #efefef;  stroke-width: 1px;}.choreo-bank-app-card__line-19 svg {  display: block;  width: 100%;  height: 100%;  overflow: visible;}.choreo-bank-app-card__line-19 svg, .choreo-bank-app-card__line-19 svg  {  stroke: inherit !important;  fill: inherit !important;  stroke-width: inherit !important;}.choreo-bank-app-card__your-virtual-card-will-have-a-different-number-than-your-physical-card-this-helps-keep-your-information-secure {  width: 341px;  height: 30px;  display: none;  color: #b4b4b4;  font-size: 12px;  font-weight: 500;  font-family: 'Inter', sans-serif;  text-align: center;  overflow-wrap: break-word;}.choreo-bank-app-card__group {  position: relative;  align-self: stretch;  height: 278px;  box-sizing: border-box;  display: flex;  flex-direction: column;  gap: 14px;}.choreo-bank-app-card__direct-deposit {  width: 367px;  height: fit-content;  color: #b0afaf;  font-size: 13px;  font-weight: 500;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__frame-1686561421 {  position: relative;  align-self: stretch;  height: 163px;  background-color: #ffffff;  overflow: hidden;  border-radius: 20px;}.choreo-bank-app-card__frame-1686561422-2 {  position: absolute;  left: 22px;  top: 18px;  width: 323px;  height: fit-content;  box-sizing: border-box;  display: flex;  gap: 159px;  justify-content: space-between;  align-items: flex-end;}.choreo-bank-app-card__institution-number {  width: 140px;  height: 19px;  color: #b5b5b5;  font-size: 16px;  font-weight: 500;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__832 {  width: 21px;  height: 16px;  color: #000000;  font-size: 12px;  font-weight: 500;  font-family: 'Reddit Mono', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__frame-1686561423-2 {  position: absolute;  left: 22px;  top: 71px;  width: 323px;  height: fit-content;  box-sizing: border-box;  display: flex;  gap: 115px;  justify-content: space-between;  align-items: flex-end;}.choreo-bank-app-card__transit-branch-number {  width: 176px;  height: 19px;  color: #b5b5b5;  font-size: 16px;  font-weight: 500;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__0055 {  width: 27px;  height: 16px;  color: #000000;  font-size: 12px;  font-weight: 500;  font-family: 'Reddit Mono', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__frame-1686561424 {  position: absolute;  left: 22px;  top: 126px;  width: 323px;  height: fit-content;  box-sizing: border-box;  display: flex;  gap: 133px;  justify-content: space-between;  align-items: flex-end;}.choreo-bank-app-card__account-number {  width: 127px;  height: 19px;  color: #b5b5b5;  font-size: 16px;  font-weight: 500;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__node {  width: fit-content;  height: fit-content;  color: #000000;  font-size: 14px;  font-weight: 500;  font-family: 'Reddit Mono', sans-serif;  white-space: nowrap;  overflow-wrap: break-word;}.choreo-bank-app-card__line-19-2 {  position: absolute;  left: 23px;  top: 53px;  width: 322px;  height: 1px;  fill: none;  stroke: #efefef;  stroke-width: 1px;}.choreo-bank-app-card__line-19-2 svg {  display: block;  width: 100%;  height: 100%;  overflow: visible;}.choreo-bank-app-card__line-19-2 svg, .choreo-bank-app-card__line-19-2 svg  {  stroke: inherit !important;  fill: inherit !important;  stroke-width: inherit !important;}.choreo-bank-app-card__line-20 {  position: absolute;  left: 23px;  top: 105px;  width: 322px;  height: 1px;  fill: none;  stroke: #efefef;  stroke-width: 1px;}.choreo-bank-app-card__line-20 svg {  display: block;  width: 100%;  height: 100%;  overflow: visible;}.choreo-bank-app-card__line-20 svg, .choreo-bank-app-card__line-20 svg * {  stroke: inherit !important;  fill: inherit !important;  stroke-width: inherit !important;}.choreo-bank-app-card__frame-1686561428 {  position: relative;  align-self: stretch;  height: 51px;  box-sizing: border-box;  display: flex;  gap: 10px;  padding: 0px 24px;  justify-content: space-between;  align-items: center;  background-color: #ffffff;  overflow: hidden;  border-radius: 20px;}.choreo-bank-app-card__direct-deposit-details {  width: 163px;  height: 19px;  color: #b5b5b5;  font-size: 16px;  font-weight: 500;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card__void-cheque {  width: 72px;  height: 15px;  color: #b4b4b4;  font-size: 12px;  font-weight: 500;  font-family: 'Inter', sans-serif;  overflow-wrap: break-word;}.choreo-bank-app-card.is-bank-app-card__card-2-hover .choreo-bank-app-card__frame-1686561429 {  transform: translateX(0px) translateY(16px);  opacity: 0;}.choreo-bank-app-card.is-bank-app-card__card-2-hover .choreo-bank-app-card__card-2 {  transform: translateX(0px) translateY(-28px) scaleX(1.55) scaleY(1.55);}.choreo-bank-app-card__switch.is-bank-app-card__switch-toggle {  transform: translateX(0px) translateY(0px);  background-color: #d8d8d8;}.choreo-bank-app-card__switch.is-bank-app-card__switch-toggle .choreo-bank-app-card__rectangle-9 {  transform: translateX(-19px) translateY(0px);}.choreo-bank-app-card[data-state="clicked"] .choreo-bank-app-card__card {  transform: translateX(-9px) translateY(-9px) rotateY(0deg);  border-radius: 23px;  display: flex;  height: 221px;  opacity: 1;  width: 386px;}.choreo-bank-app-card[data-state="clicked"] .choreo-bank-app-card__card-2 {  transform: translateX(2px) translateY(-23px) rotateY(-180deg) scaleX(1.7) scaleY(1.7);  opacity: 0;}.choreo-bank-app-card[data-state="clicked"] .choreo-bank-app-card__frame-1686561430 {  transform: translateY(132px);}.choreo-bank-app-card[data-state="clicked"] .choreo-bank-app-card__frame-1686561427-2 {  transform: translateX(0px) translateY(0px);  display: block;  height: 106px;  opacity: 1;  width: 370px;}.choreo-bank-app-card[data-state="clicked"] .choreo-bank-app-card__switch {  transform: translateX(0px) translateY(0px);}.choreo-bank-app-card[data-state="clicked"] .choreo-bank-app-card__your-virtual-card-will-have-a-different-number-than-your-physical-card-this-helps-keep-your-information-secure {  display: block;}.choreo-bank-app-card[data-state="clicked"] .choreo-bank-app-card__group {  opacity: 0;}.choreo-bank-app-card[data-state="clicked"] .choreo-bank-app-card__direct-deposit {  transform: translateX(0px) translateY(0px);  opacity: 0.94;}@media (prefers-reduced-motion: no-preference) {  .choreo-bank-app-card__frame-1686561429 {    transition: transform 350ms cubic-bezier(0.25, 1, 0.5, 1), opacity 350ms cubic-bezier(0.25, 1, 0.5, 1);  }  .choreo-bank-app-card__card-2 {    transition: transform 410ms cubic-bezier(0.34, 1.56, 0.64, 1), opacity 500ms cubic-bezier(0.33, 1, 0.68, 1);  }  .choreo-bank-app-card__switch {    transition: transform 300ms cubic-bezier(0, 0, 0.58, 1), background-color 300ms cubic-bezier(0, 0, 0.58, 1);  }  .choreo-bank-app-card__rectangle-9 {    transition: transform 300ms cubic-bezier(0, 0, 0.58, 1);  }  .choreo-bank-app-card__card {    transition: transform 500ms cubic-bezier(0.33, 1, 0.68, 1), border-radius 500ms cubic-bezier(0.33, 1, 0.68, 1), height 500ms cubic-bezier(0.33, 1, 0.68, 1), opacity 500ms cubic-bezier(0.33, 1, 0.68, 1), width 500ms cubic-bezier(0.33, 1, 0.68, 1);  }  .choreo-bank-app-card__frame-1686561430 {    transition: transform 500ms cubic-bezier(0.33, 1, 0.68, 1);  }  .choreo-bank-app-card__frame-1686561427-2 {    transition: transform 500ms cubic-bezier(0.33, 1, 0.68, 1), height 500ms cubic-bezier(0.33, 1, 0.68, 1), opacity 500ms cubic-bezier(0.33, 1, 0.68, 1), width 500ms cubic-bezier(0.33, 1, 0.68, 1);  }  .choreo-bank-app-card__group {    transition: opacity 500ms cubic-bezier(0.33, 1, 0.68, 1);  }  .choreo-bank-app-card__direct-deposit {    transition: transform 500ms cubic-bezier(0.33, 1, 0.68, 1), opacity 500ms cubic-bezier(0.33, 1, 0.68, 1);  }  .choreo-bank-app-card__frame-1686561429 {    will-change: opacity, transform;  }  .choreo-bank-app-card__card {    will-change: opacity, transform;  }  .choreo-bank-app-card__card-2 {    will-change: opacity, transform;  }  .choreo-bank-app-card__frame-1686561430 {    will-change: transform;  }  .choreo-bank-app-card__frame-1686561427-2 {    will-change: opacity, transform;  }  .choreo-bank-app-card__switch {    will-change: transform;  }  .choreo-bank-app-card__rectangle-9 {    will-change: transform;  }  .choreo-bank-app-card__group {    will-change: opacity;  }  .choreo-bank-app-card__direct-deposit {    will-change: opacity, transform;  }}

#### You never wrote it

No syntax, no coefficients, no class names to invent. All of it came from the layers you dragged.

#### Nothing to install

No Choreo runtime and no required library. Paste it into the project and it runs.

#### Reduced motion, handled

Every export honours a reduced-motion preference. You did not have to remember.

#### Or skip it entirely

Send a live link instead, and let the engineer lift these same files from the panel.

Then, at the very end, there's code

You never touched it while designing. These are the actual files Choreo emitted for the card you just used: 56 layers, three triggers and a state machine, in one pass.

See the export options

Not just a timeline. A real editor.

Browse the docs

Choreo opens your Figma frames but does not depend on them. Structure, style, states and motion are all editable in-tool.

Import report28 layersAuto layout → FlexboxexactIcons → inline SVGexactGradient text → solid colorapproximatedFigma import that tells you the truthThe bundled plugin walks a selected frame in, with layout, vectors and sizing intact. Anything that could not translate exactly is listed in the Import Report and linked to the layer, so an imperfect import is a task instead of a silent lie. Re-import later and your choreography survives.BaseOnLoading+SwitchclickOnBaseNamed component statesBase plus named states, Figma-variant style. Wire a click, double-click or hover to a state, then read the whole machine as a graph.cubic-bezier( 0.16, 1, 0.3, 1)Emphasized decelerateCurves the browser can drawA bezier editor with presets and springs that document their own fidelity. It cannot express a curve your export would have to fake.transform, opacitycompositorwidthlayoutNamed as you keyframe it, not in an audit later.Green until it isn'tA signal beside the timeline: green while the motion stays cheap, amber the moment it gets expensive, with the property named.?share=pricing-cardCopyLive, not a videoInspect modeShare the interaction itselfPublish a link where stakeholders hover, click and scroll the real component. Engineers take the export from the same page, no account needed.

Local-firstDocuments autosave to your browser and save out as portable files. Cloud sync is an optional layer you can switch on later.Motion pathsMove a layer along a curve with editable tangents, not just from one point to another in a straight line.Vector motionIcons animate as real vectors: stroke draw-on, path morphing, gradient fills, with engine differences stated where they exist.Presets and templatesCard float, jelly press, focus ring, toast slide-in. Drop one on and it stays fully editable, never a black box.

Why not just use Figma or Lottielab?

Try it yourself

Because the three tools are different shapes. Figma owns structure, Lottielab owns illustrative motion, and neither is built to make a hover state behave in a browser.

| How Choreo compares with Figma Motion and Lottielab| | Choreo | Figma Motion | Lottielab | | ---------------------------------------------------- | ------------------------------------------------ | ------------------------------------ | ----------------------------------- | | Built for | Interface micro-interactions | Prototypes and design specs | Vector and illustrative animation | | The canvas is | Real DOM, styled with real CSS | The Figma design canvas | A vector animation canvas | | Time is organised by | One timeline per trigger state | Transitions between frames | A single linear timeline | | Real UI states | Seven triggers, enter and exit edited separately | Prototype interactions on frames | Whatever the Lottie player exposes | | What reaches production | CSS, Web Animations, React, or a written spec | An engineer rebuilds it by hand | A Lottie JSON file | | Runtime needed to play it | None | None; it stays a prototype | The Lottie player | | Handoff is | A live link stakeholders can interact with | A prototype link plus a written spec | A file plus the player that runs it |

Choreo is not trying to replace either one. It is for the layer in between, where a component has to respond to a real pointer. This comparison reflects how each tool positions itself today; all three keep moving.

Five commitments the tool holds

Read the docs

Each one is a constraint Choreo works within, and together they are the reason you can trust what comes out the other side.

1. 01

Predictable, never guessed

Nothing is generated for you. Every result comes from choreography you performed, so the same file always behaves the same way. 2. 02

The canvas is the browser

Your component is live in the page, so nothing sits between the canvas and what your users see. What you scrub is what ships. 3. 03

States, not seconds

The web is event-driven, so the unit of choreography is a trigger state, not a position on a linear timeline. 4. 04

Honest about limits

When an import cannot be translated faithfully, or something cannot animate smoothly, the tool tells you and points at the layer. 5. 05

Deletable

What you hand off needs no Choreo runtime and no account. Drop the tool tomorrow and nothing it produced breaks.

Your next interaction starts here

Open a file, arm a hover, and drag something. Nothing to install, and nothing leaves your browser.

Open ChoreoStart from a template

Free to use · no account · files stay local

www.choreomotion.app · 1 videos · 14 links

Comments (0)

No comments yet