Smooth drag

The smooth() plugin replaces the core drag with a lerped position and inertia: the slider follows your pointer with a slight lag, keeps its momentum when you let go and settles on a slide. Horizontal trackpad scroll works too.

01

Drag me

02

Let it glide

03

Or scroll

04

Sideways

05

Loop forever

View code
<div id="demo-smooth-basic">
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#005345">
      <span>01</span>
      <h3>Drag me</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#0F766E">
      <span>02</span>
      <h3>Let it glide</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#115E59">
      <span>03</span>
      <h3>Or scroll</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#00221A">
      <span>04</span>
      <h3>Sideways</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#134E4A">
      <span>05</span>
      <h3>Loop forever</h3>
    </div>
  </div>
</div>
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
import { Slider } from '@andresclua/sliderkit'
import { arrows, smooth } from '@andresclua/sliderkit-plugins'

new Slider('#demo-smooth-basic', {
  items: 1,
  loop: true,
  touch: false,        // smooth() replaces the core drag
  mouseDrag: false,
  responsive: { 700: { items: 2 }, 1100: { items: 3 } },
  plugins: [smooth(), arrows()],
})

Smooth drag + skew (boilerplate)

Same slider, plus a velocity-driven skew on the cards. smooth() exposes velocity (slides per second, signed) so any effect can follow the movement. This is the home page slider without the WebGL canvas — a starting point for your own.

01

Drag me

02

Let it glide

03

Or scroll

04

Sideways

05

Loop forever

View code
<div id="demo-smooth-skew">
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#005345">
      <span>01</span>
      <h3>Drag me</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#0F766E">
      <span>02</span>
      <h3>Let it glide</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#115E59">
      <span>03</span>
      <h3>Or scroll</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#00221A">
      <span>04</span>
      <h3>Sideways</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#134E4A">
      <span>05</span>
      <h3>Loop forever</h3>
    </div>
  </div>
</div>
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
import { Slider } from '@andresclua/sliderkit'
import { arrows, smooth } from '@andresclua/sliderkit-plugins'

new Slider('#demo-smooth-skew', {
  items: 1,
  loop: true,
  touch: false,        // smooth() replaces the core drag
  mouseDrag: false,
  responsive: { 700: { items: 2 }, 1100: { items: 3 } },
  plugins: [
    smooth({
      skew: {
        target: '.smooth-card',   // element inside each slide that leans (default: the slide)
        perSecond: 2.5,           // degrees per slide/second of velocity
        max: 14,                  // max degrees either way
      },
    }),
    arrows(),
  ],
})

// Want a different effect? Keep the plugin and read sm.velocity (slides per second)
// every frame — see "Properties and methods" in the smooth plugin docs.
// Drawing on a canvas too? Use smooth({ raf: false }) and call sm.tick(now)
// at the start of your own requestAnimationFrame loop.

Your own effect with onUpdate

onUpdate runs every frame the slider moves, and once more when it stops, with the live state: velocity, position, progress and a position for every slide. Here the cards shrink while moving fast and the titles slide against the movement. Any effect you can think of fits in that callback.

01

Drag me

02

Let it glide

03

Or scroll

04

Sideways

05

Loop forever

View code
<div id="demo-smooth-update">
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#005345">
      <span>01</span>
      <h3>Drag me</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#0F766E">
      <span>02</span>
      <h3>Let it glide</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#115E59">
      <span>03</span>
      <h3>Or scroll</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#00221A">
      <span>04</span>
      <h3>Sideways</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#134E4A">
      <span>05</span>
      <h3>Loop forever</h3>
    </div>
  </div>
</div>
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
import { Slider } from '@andresclua/sliderkit'
import { arrows, smooth } from '@andresclua/sliderkit-plugins'

let cards = []      // one entry per slide element, loop clones included

const slider = new Slider('#demo-smooth-update', {
  items: 1,
  loop: true,
  touch: false,        // smooth() replaces the core drag
  mouseDrag: false,
  responsive: { 700: { items: 2 }, 1100: { items: 3 } },
  plugins: [
    smooth({
      // Called every frame the slider moves, and once more when it comes to rest.
      onUpdate(sm) {
        const middle = (slider.currentItems - 1) / 2                       // viewport centre, in slides
        const speed = Math.min(Math.abs(sm.velocity) * 0.02, 0.1)
        const lag = Math.max(-50, Math.min(50, sm.velocity * 6))           // px, follows the speed

        cards.forEach(({ card, title, index }) => {
          const near = Math.max(0, 1 - Math.abs(sm.positions[index] - middle) / 1.5)   // 1 at the centre, 0 at 1.5 slides away
          card.style.opacity = String(0.55 + 0.45 * near)                  // dims towards the edges
          card.style.transform = `scale(${1 - speed})`                     // shrinks while moving fast
          title.style.transform = `translateX(${lag}px)`                   // trails behind the movement
        })
      },
    }),
    arrows(),
  ],
})

// sm.positions has one value per REAL slide (0 = at the start of the viewport,
// 1 = one slide to the right...). Clones show the same slide, so they share its value.
// Build effects from continuous functions of these numbers: anything that steps
// (Math.round, %) makes the effect jump when the slider settles.
const clones = (slider.slides.length - slider.slideCount) / 2
cards = slider.slides.map((slide, i) => ({
  card: slide.querySelector('.smooth-card'),
  title: slide.querySelector('h3'),
  index: (((i - clones) % slider.slideCount) + slider.slideCount) % slider.slideCount,
}))

Preset: smooth

The default: a soft lag while dragging, a generous glide on release, and it always settles on a slide. (lerp 0.1 · inertia 350 · snap)

01

Drag me

02

Let it glide

03

Or scroll

04

Sideways

05

Loop forever

View code
<div id="demo-smooth-smooth">
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#005345">
      <span>01</span>
      <h3>Drag me</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#0F766E">
      <span>02</span>
      <h3>Let it glide</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#115E59">
      <span>03</span>
      <h3>Or scroll</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#00221A">
      <span>04</span>
      <h3>Sideways</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#134E4A">
      <span>05</span>
      <h3>Loop forever</h3>
    </div>
  </div>
</div>
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
import { Slider } from '@andresclua/sliderkit'
import { arrows, smooth } from '@andresclua/sliderkit-plugins'

// One slider per preset. Any option overrides the preset it starts from:
//   smooth({ preset: 'floaty', inertia: 1200, skew: true })
for (const preset of ['smooth', 'snappy', 'floaty', 'free']) {
  new Slider('#demo-smooth-' + preset, {
    items: 1,
    loop: true,
    touch: false,
    mouseDrag: false,
    responsive: { 700: { items: 2 }, 1100: { items: 3 } },
    plugins: [smooth({ preset }), arrows()],
  })
}

Preset: snappy

Quick and controlled: little lag, a short fling that never travels more than one slide. (lerp 0.22 · inertia 120 · snap · maxFling 1)

01

Drag me

02

Let it glide

03

Or scroll

04

Sideways

05

Loop forever

View code
<div id="demo-smooth-snappy">
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#005345">
      <span>01</span>
      <h3>Drag me</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#0F766E">
      <span>02</span>
      <h3>Let it glide</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#115E59">
      <span>03</span>
      <h3>Or scroll</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#00221A">
      <span>04</span>
      <h3>Sideways</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#134E4A">
      <span>05</span>
      <h3>Loop forever</h3>
    </div>
  </div>
</div>
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
import { Slider } from '@andresclua/sliderkit'
import { arrows, smooth } from '@andresclua/sliderkit-plugins'

// One slider per preset. Any option overrides the preset it starts from:
//   smooth({ preset: 'floaty', inertia: 1200, skew: true })
for (const preset of ['smooth', 'snappy', 'floaty', 'free']) {
  new Slider('#demo-smooth-' + preset, {
    items: 1,
    loop: true,
    touch: false,
    mouseDrag: false,
    responsive: { 700: { items: 2 }, 1100: { items: 3 } },
    plugins: [smooth({ preset }), arrows()],
  })
}

Preset: floaty

Heavy and dreamy: a lot of lag and a long glide before it settles. (lerp 0.05 · inertia 700 · snap)

01

Drag me

02

Let it glide

03

Or scroll

04

Sideways

05

Loop forever

View code
<div id="demo-smooth-floaty">
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#005345">
      <span>01</span>
      <h3>Drag me</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#0F766E">
      <span>02</span>
      <h3>Let it glide</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#115E59">
      <span>03</span>
      <h3>Or scroll</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#00221A">
      <span>04</span>
      <h3>Sideways</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#134E4A">
      <span>05</span>
      <h3>Loop forever</h3>
    </div>
  </div>
</div>
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
import { Slider } from '@andresclua/sliderkit'
import { arrows, smooth } from '@andresclua/sliderkit-plugins'

// One slider per preset. Any option overrides the preset it starts from:
//   smooth({ preset: 'floaty', inertia: 1200, skew: true })
for (const preset of ['smooth', 'snappy', 'floaty', 'free']) {
  new Slider('#demo-smooth-' + preset, {
    items: 1,
    loop: true,
    touch: false,
    mouseDrag: false,
    responsive: { 700: { items: 2 }, 1100: { items: 3 } },
    plugins: [smooth({ preset }), arrows()],
  })
}

Preset: free

No snapping: it glides and stops wherever the momentum runs out, like a free-scrolling strip. (lerp 0.08 · inertia 900 · no snap · maxFling 8)

01

Drag me

02

Let it glide

03

Or scroll

04

Sideways

05

Loop forever

View code
<div id="demo-smooth-free">
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#005345">
      <span>01</span>
      <h3>Drag me</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#0F766E">
      <span>02</span>
      <h3>Let it glide</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#115E59">
      <span>03</span>
      <h3>Or scroll</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#00221A">
      <span>04</span>
      <h3>Sideways</h3>
    </div>
  </div>
  <div class="smooth-slide">
    <div class="smooth-card" style="background:#134E4A">
      <span>05</span>
      <h3>Loop forever</h3>
    </div>
  </div>
</div>
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
.smooth-slide {
  padding: 0 10px;
}
.smooth-card {
  height: 300px;
  border-radius: 14px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
}
.smooth-card span {
  font: 500 0.75rem/1 ui-monospace, monospace;
  letter-spacing: 0.04em;
}
.smooth-card h3 {
  margin: 0;
  font-size: 1.6rem;
  letter-spacing: -0.02em;
}
import { Slider } from '@andresclua/sliderkit'
import { arrows, smooth } from '@andresclua/sliderkit-plugins'

// One slider per preset. Any option overrides the preset it starts from:
//   smooth({ preset: 'floaty', inertia: 1200, skew: true })
for (const preset of ['smooth', 'snappy', 'floaty', 'free']) {
  new Slider('#demo-smooth-' + preset, {
    items: 1,
    loop: true,
    touch: false,
    mouseDrag: false,
    responsive: { 700: { items: 2 }, 1100: { items: 3 } },
    plugins: [smooth({ preset }), arrows()],
  })
}