Koreografi Scroll & Fisika Pegas
Teknik mengikat properti visual elemen langsung ke progres gulir halaman yang dihaluskan dengan simulasi pegas.
Membaca sekitar 2 menit
Teknik mengikat properti visual elemen langsung ke progres gulir halaman yang dihaluskan dengan simulasi pegas.
Menggabungkan useScroll, useTransform, dan useSpring dari Framer Motion di setiap seksi untuk mengubah skala foto, sudut lengkung (border-radius), dan garis pembatas secara proporsional terhadap gerakan jari pengguna.
Tanpa redaman pegas (useSpring) dan petunjuk akselerasi GPU, animasi yang terikat langsung ke scroll akan terasa kaku dan patah-patah di layar ponsel.
Masalahnya dulu
Sekadar memunculkan teks dengan efek fade-in saat digulir sudah terlalu biasa untuk undangan pernikahan. Saya ingin elemen-elemen visual seperti foto pasangan, lengkungan sudut bingkai, hingga garis-garis dekoratif bereaksi secara proporsional terhadap seberapa jauh jari pengguna menggulir layar—baik saat digulir ke bawah maupun saat ditarik kembali ke atas.
Merangkai useScroll, useTransform, dan useSpring
Setiap seksi di HomePage.tsx memiliki ref tersendiri yang dipantau oleh hook useScroll dengan pengaturan offset spesifik (misalnya ["start end", "center center"]). Nilai scrollYProgress (0 sampai 1) kemudian dipetakan oleh useTransform menjadi nilai skala (scale), posisi horizontal (x), radius sudut (borderRadius), atau panjang garis (scaleY/scaleX). Agar pergerakannya tidak kaku mengikuti detak pixel scroll yang kasar, nilai transformasi tersebut dibungkus lagi dengan useSpring.
Scroll menentukan tujuan posisi elemen, tetapi fisika pegaslah yang membuat pergerakannya terasa bernyawa.
Implementasi di ngodingan ini
Pada Section3 dan Section6 di src/pages/HomePage.tsx, foto menyusut atau membesar secara halus sementara garis vertikal dan horizontal tumbuh berurutan sesuai rentang scroll:
const { scrollYProgress } = useScroll({
target: sectionRef,
offset: ["start start", "end start"],
});
const imgScale = useSpring(useTransform(scrollYProgress, [0, 1], [1, 0.78]), {
stiffness: 100,
damping: 30,
});
const imgBR = useTransform(scrollYProgress, [0, 0.5], [0, 16]);
// Pada Section 6: garis vertikal & horizontal tumbuh bertahap dari satu sumber scroll
const line2Progress = useTransform(scrollYProgress2, [0.4, 0.85], [0, 1]);
const horizProgress = useTransform(scrollYProgress2, [0.6, 0.95], [0, 1]);Jebakan dan detail yang harus dijaga
- Mengubah skala gambar besar sambil mengubah border-radius saat scroll sering memicu flickering di Safari/Chrome mobile. Solusinya adalah menyematkan translateZ: 0, backfaceVisibility: "hidden", dan willChange: "transform" pada motion.div pembungkus gambar.
- Untuk menggambar garis yang tumbuh dari atas ke bawah atau dari kanan ke kiri, gunakan transformasi scaleY atau scaleX dengan titik tumpu originY: 0 atau originX: 1, bukan menganimasikan height atau width yang memaksa browser menghitung ulang layout (reflow) setiap frame.
- Pemilihan angka stiffness (80–100) dan damping (20–30) pada useSpring harus seimbang: terlalu kecil membuat gambar membal berlebihan, terlalu besar menghilangkan efek halusnya.