← Easeout Lab
Free component

Ease-out vs linear

Same distance, same time. Ease-out starts fast and settles, so it feels responsive instead of robotic.

Linear
Ease-out

Needspnpm add motion

components/ease-vs-linear.tsx
"use client"

import { useState } from "react"
import { motion, useReducedMotion } from "motion/react"

// Two dots cross the same track in the same time. Linear starts and stops abruptly;
// ease-out starts fast and settles, which reads as more natural.
const EASE_OUT = [0.16, 1, 0.3, 1] as const

const rows = [
  { label: "Linear", ease: "linear" as const, dot: "bg-current" },
  { label: "Ease-out", ease: EASE_OUT, dot: "bg-[#FF5A1F]" },
]

export function EaseVsLinear() {
  const [end, setEnd] = useState(false)
  const reduce = useReducedMotion()

  return (
    <div className="flex w-full max-w-xs flex-col gap-4 text-left">
      {rows.map((r) => (
        <div key={r.label} className="flex flex-col gap-1.5">
          <span className="font-mono text-[11px] tracking-[0.06em] uppercase opacity-70">{r.label}</span>
          <div className="relative h-4 rounded-full bg-current/10">
            {/* the wrapper is the track minus one dot wide, so x: 100% lands the dot at the right edge */}
            <motion.div
              className="absolute inset-y-0 left-0 w-[calc(100%-1rem)]"
              initial={false}
              animate={{ x: end ? "100%" : "0%" }}
              transition={reduce ? { duration: 0 } : { duration: 0.8, ease: r.ease }}
            >
              <span className={`block size-4 rounded-full ${r.dot}`} />
            </motion.div>
          </div>
        </div>
      ))}
      <button
        type="button"
        onClick={() => setEnd((v) => !v)}
        className="mt-1 h-11 cursor-pointer self-center rounded-full border border-current/20 bg-transparent px-5 text-[14px] font-medium text-current focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current"
      >
        {end ? "Slide back" : "Slide"}
      </button>
    </div>
  )
}

Want a whole page built like this?