- canvas-confetti adalah library klien untuk menjalankan animasi confetti berbasis canvas di halaman web, mendukung instalasi NPM maupun penyertaan langsung lewat CDN
- API dasar
confetti() mengatur jumlah partikel, sudut, sebaran, kecepatan, gravitasi, warna, bentuk, posisi, z-index, dan lainnya hanya dengan satu objek opsi; di lingkungan yang mendukung Promise, waktu selesai animasi juga bisa diterima
- Untuk pengguna Reduced Motion, tersedia opsi
disableForReducedMotion; nilainya secara default false, tetapi ada kemungkinan berubah pada rilis mayor mendatang
- Dapat membuat bentuk kustom berbasis SVG Path dan teks, serta mengimplementasikan efek seperti emoji confetti selain bentuk bawaan
square, circle, dan star
confetti.create() membuat instance pada canvas tertentu dan mendukung opsi global seperti resize dan useWorker, tetapi pada useWorker: true, kendali canvas dipindahkan ke web worker sehingga manipulasi dari main thread akan menyebabkan error
Cara instalasi dan eksekusi
- Anda dapat melihat cara kerja library di halaman demo
- Dapat diinstal sebagai paket NPM
npm install --save canvas-confetti
- Dalam build proyek, dapat digunakan dengan
require('canvas-confetti')
- Library ini adalah komponen klien dan tidak berjalan di Node
- README menjelaskan bahwa proyek harus dibuild dengan alat seperti webpack
- Di halaman HTML, dapat disertakan langsung sebagai skrip CDN
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.4/…;
- Saat menggunakan CDN, disarankan memakai versi terbaru pada saat disertakan ke proyek; daftar versi lengkap dapat dilihat di releases page
Dukungan Reduced Motion
- Sebagian pengguna mungkin tidak menginginkan atau lebih memilih mengurangi gerakan di situs web, dan browser dapat menyampaikan preferensi ini melalui
prefers-reduced-motion
- Dengan opsi
disableForReducedMotion, confetti dapat tidak ditampilkan bagi pengguna yang kesulitan dengan animasi yang mengganggu
- Nilai default opsi ini saat ini adalah
false
- Perubahan nilai default sedang dipertimbangkan untuk rilis mayor mendatang, dan jika memiliki pendapat kuat, dapat disampaikan melalui issue
- Jika confetti dinonaktifkan karena
disableForReducedMotion diterapkan, Promise confetti() akan langsung resolve
API dasar dan perilaku Promise
- Saat diinstal lewat NPM, library dapat di-require sebagai komponen klien dalam build proyek; pada versi CDN, library diekspos sebagai fungsi
confetti di window
confetti([options]) menerima satu objek opsi opsional
- Jika
window.Promise tersedia, fungsi ini mengembalikan Promise yang memberi tahu saat animasi selesai
- Di lingkungan seperti IE yang tidak memiliki Promise, fungsi ini mengembalikan
null
- Promise polyfill dapat digunakan
- Implementasi Promise juga dapat diberikan langsung dalam bentuk
confetti.Promise = MyPromise
- Jika
confetti dipanggil beberapa kali sebelum selesai, Promise yang sama akan dikembalikan setiap kali
- Secara internal, elemen canvas yang sama digunakan kembali, dan confetti baru ditambahkan sambil melanjutkan animasi yang sudah ada
- Promise yang dikembalikan oleh setiap pemanggilan akan resolve setelah semua animasi selesai
Opsi utama
particleCount: jumlah confetti yang ditembakkan, default 50
angle: sudut tembakan, default 90, dengan 90 berarti ke arah atas
spread: rentang sebaran dari pusat, default 45
startVelocity: kecepatan awal, default 45
decay: tingkat berkurangnya kecepatan, default 0.9
- Harus dijaga di antara 0 dan 1; jika keluar dari rentang ini, kecepatan dapat meningkat
gravity: seberapa kuat partikel tertarik ke bawah, default 1
0.5 berarti setengah gravitasi, dan karena tidak ada batasan, juga bisa dibuat bergerak ke atas
drift: tingkat pergeseran ke kiri atau kanan, default 0
- Nilai negatif berarti ke kiri, nilai positif berarti ke kanan
flat: dapat mematikan efek miring dan bergoyang seperti confetti 3D di dunia nyata, default false
ticks: jumlah langkah pergerakan confetti, default 200
origin: posisi awal tembakan
origin.x: posisi x pada halaman, 0 berarti kiri, 1 berarti kanan, default 0.5
origin.y: posisi y pada halaman, 0 berarti atas, 1 berarti bawah, default 0.5
colors: array string warna dalam format HEX
shapes: array bentuk confetti
- Nilai bawaan adalah
square, circle, star
- Secara default, square dan circle dicampur merata
- Rasio campuran dapat diatur melalui proporsi array, misalnya
['circle', 'circle', 'square']
scalar: skala setiap partikel, default 1
zIndex: lapisan tampilan confetti, default 100
disableForReducedMotion: menonaktifkan confetti untuk pengguna yang memilih Reduced Motion
Membuat bentuk kustom
confetti.shapeFromPath({ path, matrix? }) membuat bentuk confetti kustom dari SVG Path string
- Bentuk berbasis Path memiliki beberapa batasan
- Semua path diperlakukan sebagai bentuk terisi, dan stroke path tidak diimplementasikan
- Path dibatasi pada satu warna
- Semua path memerlukan transform matrix yang valid
- Perhitungan matrix memiliki biaya, jadi sebaiknya dihitung sekali per path selama pengembangan lalu di-cache
- Matrix selalu sama untuk nilai path yang sama
- Saat memperbarui library, sebaiknya matrix dibuat ulang dan di-cache kembali demi forward compatibility
- Confetti berbasis path terbatas pada browser yang mendukung
Path2D
- Nilai kembaliannya adalah objek
Shape, dan dapat langsung dimasukkan ke array shapes
var triangle = confetti.shapeFromPath({ path: 'M0 10 L5 0 L10 10z' });
confetti({
shapes: [triangle]
});
confetti.shapeFromText({ text, scalar?, color?, fontFamily? }) membuat bentuk confetti berbasis teks dan dapat menggunakan emoji Unicode standar
- Bentuk berbasis teks cocok untuk emoji confetti
- Untuk confetti yang bergoyang, umumnya satu karakter yang mendekati persegi, terutama emoji, bekerja dengan baik
- Karena teks dirasterisasi alih-alih digambar ulang setiap kali, perubahan skala besar setelah pembuatan dapat membuatnya tampak buram
- Jika berencana menggunakan
scalar pada opsi confetti, sebaiknya gunakan nilai scalar yang sama saat membuat shape
- Opsi teks menerima
text, scalar, color, dan fontFamily
- Default
fontFamily mengikuti praktik rendering emoji native OS dan fallback ke sans-serif
- Saat menggunakan web font, font harus sudah dimuat sebelum rendering confetti
var scalar = 2;
var pineapple = confetti.shapeFromText({ text: '🍍', scalar });
confetti({
shapes: [pineapple],
scalar
});
Canvas kustom dan rendering worker
confetti.create(canvas, [globalOptions]) membuat instance fungsi confetti yang menggunakan canvas tertentu
- Berguna saat ingin membatasi confetti hanya pada area tertentu di halaman
- Secara default, metode ini tidak mengubah canvas selain menggambar di atasnya
- Jika ukuran tampilan canvas diubah lewat CSS, ukuran gambar canvas sebenarnya tidak ikut berubah sehingga dapat meregang dan terlihat buram
- Jika opsi
resize diaktifkan, library akan menyesuaikan ukuran gambar canvas dan merespons perubahan ukuran jendela atau rotasi perangkat mobile
- Jangan menginisialisasi instance confetti berkali-kali dengan elemen canvas yang sama; simpan instance kustom yang sudah dibuat
-
Opsi global
resize: menentukan apakah ukuran gambar canvas diatur dan dipertahankan sesuai perubahan jendela, default false
useWorker: jika memungkinkan, merender animasi confetti secara asinkron di web worker, default false
- Pada default, animasi selalu berjalan di main thread
- Jika didukung browser, animasi berjalan di luar main thread agar tidak memblokir main thread
- Pada browser yang tidak mendukung, nilai ini diabaikan
disableForReducedMotion: membuat instance confetti tersebut selalu menghormati permintaan Reduced Motion pengguna
-
Catatan untuk useWorker: true
- Jika memakai
useWorker: true, kendali canvas dipindahkan ke web worker
- Dalam kondisi ini, selain menghapus canvas dari DOM, manipulasi dari main thread akan menyebabkan error
- Jika perlu memanipulasi canvas secara langsung, jangan gunakan opsi
useWorker
var myCanvas = document.createElement('canvas');
document.body.appendChild(myCanvas);
var myConfetti = confetti.create(myCanvas, {
resize: true,
useWorker: true
});
myConfetti({
particleCount: 100,
spread: 160
});
Menghentikan animasi dan pola contoh
confetti.reset() menghentikan animasi, menghapus semua confetti, dan langsung me-resolve Promise yang sedang menunggu
- Instance terpisah yang dibuat dengan
confetti.create() memiliki metode reset sendiri
confetti();
setTimeout(() => {
confetti.reset();
}, 100);
- Eksekusi dasar dilakukan dengan memanggil
confetti() tanpa argumen
- Banyak confetti dapat ditembakkan dengan
particleCount: 150
- Confetti yang menyebar luas dapat dibuat dengan
spread: 180
- Menggunakan
Math.random() pada origin dapat membuat efek ledakan kecil dari posisi acak di halaman
- Contoh README menunjukkan pola yang menggunakan
requestAnimationFrame untuk terus menembakkan confetti dari tepi kiri dan kanan selama 30 detik
1 komentar
Komentar Hacker News
Trik membuat animasi yang berperforma baik di sini adalah menggambarnya di canvas, lalu menaruh canvas itu di depan semua elemen lain, tetapi mematikan pointer events agar pengguna tetap bisa berinteraksi dengan halaman
Mengingatkan pada masa-masa indah ketika saya membuat web di SMA pada 2015. Saya membuat situs web kecil dengan confetti untuk mengajak seorang cewek pergi ke homecoming bersama, dan kalau dipikir lagi itu sangat nerd
Saat itu, membuat situs web untuk seorang anak terasa seperti kekuatan super. Dari waktunya, sepertinya bukan paket ini, tetapi animasinya cukup bagus
Saya suka proyek-proyek kecil yang murni menyenangkan seperti ini. Itu juga alasan saya mulai memprogram, dan sampai sekarang masih menjadi pendorong besar
Saya suka bagian ini di halaman demo:
Obsesi terhadap detail seperti ini jarang, dan setiap kali menemukannya—entah di visualisasi statistik, properti film, atau confetti situs web—rasanya berharga
Sebagai solusinya, saya mungkin akan mencoba mengubah distribusi acaknya sendiri. Perlu dicek langsung, tetapi dugaan saya distribusi di dunia nyata lebih mendekati distribusi Gaussian
Kami menambahkan confetti di dashboard admin yang muncul saat staf sales berhasil menutup penjualan, dan ternyata cukup menyenangkan serta memotivasi
Seandainya fungsi reset dinamai confetti.resetti()
"confetti.resetti = confetti.reset"Pendekatan ini mungkin punya sedikit biaya rekayasa perangkat lunak, tetapi seperti yang jelas bagi pengamat yang cermat, manfaatnya jauh lebih besar, jadi menurut saya lakukan saja
Terlepas dari ini pustaka yang keren dan berguna, ini juga contoh bagus dari modul dalam yang dibicarakan John Ousterhout dalam Philosophy of Software Design
Versi paling dasar, yaitu memunculkan confetti, sangat mudah digunakan, tetapi kalau melihat opsinya, ada cukup banyak hal yang bisa didapat: salju, warna tertentu, berbagai efek confetti, dan lain-lain
Keren dan impresif
Pada saat yang sama, saya tidak ingin melihatnya berjalan di situs web apa pun yang saya gunakan. Terutama popup newsletter atau confetti yang muncul saat memasukkan barang ke keranjang belanja
Anehnya, efek ini bisa digunakan dengan cukup efektif. Entah untuk pendekatan layar penuh seperti ini, tetapi di software manajemen proyek yang dipakai klien yang baru-baru ini saya kunjungi, ketika sebuah item ditutup, tombolnya berubah hijau dan efek seperti ini muncul
Efeknya halus tetapi cukup terlihat, dan setelah rapat saya dan developer lain sama-sama berkata, “efeknya lumayan bagus ya.” Rasanya menyampaikan, “Oke, ada kemajuan!”
Namun cukup buat bisa dipilih saja
Penggunaan yang sah mungkin seperti tombol suka di YouTube. Ada animasi yang bagus, dan di aplikasi mobile perangkatnya juga bergetar. Itu pengalaman pengguna yang sangat menyenangkan
Di browser, pengguna bisa mengatur preferensi mengurangi gerakan. Operator situs dan maintainer pustaka harus menghormati ini saat mengimplementasikan hal seperti confetti. Pustaka ini secara khusus punya opsi
disableForReducedMotionAda tempat yang cocok untuk efek seperti ini. Misalnya saat menyelesaikan game
Kami memakai pustaka ini saat seseorang memenuhi kualifikasi tertentu. Efeknya cukup bagus untuk alur onboarding
Ada juga pustaka Party.js: https://party.js.org/
Kalau begitu, mana yang lebih kecil?
10,4 kB minified, 4,2 kB minified + Gzip
https://bundlephobia.com/package/canvas-confetti@1.9.2
28,3 kB minified, 7,4 kB minified + Gzip
https://bundlephobia.com/package/party-js@2.2.0
Namun, saya tidak terlalu tahu bagaimana bundlephobia bekerja. Bisa jadi itu tidak menunjukkan ukuran akhir paket dengan paling baik. Mungkin tidak mencerminkan code splitting atau hanya mengimpor bagian yang diperlukan. Saya hanya melihatnya sebagai gambaran cepat dan kasar
Berdasarkan Gzip, confetti tampaknya unggul beberapa KB, jadi kecuali benar-benar perlu memeras beberapa KB itu, keduanya bisa dipilih tergantung fitur yang dibutuhkan
Skrip di artikel asli tampak jauh lebih berperforma baik di mobile
Pustaka di artikel asli tampak jauh lebih berperforma. Di komputer kerja lama saya, Party.js mulai terasa sedikit lag hanya setelah 3 klik
canvas-confetti baru mulai lag setelah saya mengklik terus tanpa henti selama beberapa detik, mungkin ketika sudah membuat lebih dari 30 instance confetti dan banyak partikel
Saya bermain teka-teki silang di downforacross.com, dan saat puzzle selesai, confetti muncul
Mungkin bisa memakai sebagian kode yang lebih berperforma di sini agar terasa lebih ringan
Namun, kecuali untuk situs “fun” atau penggunaan yang jarang, saya tidak ingin melihat animasi seperti ini muncul di mana-mana
Menurut saya tidak perlu memasukkan kata useful di judul