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.
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.
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.
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)
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)
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)
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)
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()],
})
}