Anatomi QRIS
Penjelas interaktif yang membangun kode QR langkah demi langkah dan menyorot kotak di balik setiap isian QRIS

- tahap dalam satu slider yang bisa digeser
- 9
- permintaan jaringan selama dipakai
- 0
- versi QR dicocokkan dengan pustaka rujukan
- 1–15
- untuk membangun ulang kode terbesar per ketikan
- < 8 ms
Di halaman ini
Masalahnya
Kita memindai kode QR setiap hari, tapi hampir tidak pernah melihat bagaimana satu kode dibuat. Penjelasan yang beredar di internet berhenti di "ini bitstream, ini matriksnya". Koreksi galat dan masking tetap jadi kotak hitam, bahkan di tutorial untuk developer.
Di Indonesia ada celah kedua. QRIS, standar pembayaran QR nasional, tertempel di meja kasir hampir setiap warung. Isi di balik stiker itu adalah teks biasa yang bisa dibaca, berisi nama merchant, penyedia pembayaran, dan checksum. Parser QRIS yang ada menampilkan teks itu sebagai tabel, lalu selesai.
Saya ingin menyambungkan keduanya. Pilih "nama merchant" di data pembayaran, dan kotak hitam yang membawa huruf-huruf itu langsung menyala di kodenya. Aplikasi ini dibuat untuk dua pembaca sekaligus: orang awam yang penasaran, dan developer yang ingin memeriksa setiap angka dengan tangan.
Yang saya bangun
Encoder yang mengingat letak setiap bit
Saya menulis encoder QR sendiri supaya ia bisa mencatat setiap langkahnya. Untuk setiap kotak, encoder mencatat kenapa kotak itu gelap atau terang: byte dan bit mana yang dibawanya, atau pola tetap mana yang memilikinya, dan apakah mask membaliknya. Semua fitur membaca dari catatan yang sama. Sorotan isian, pelacakan kerusakan, urutan animasi, dan perbandingan mask berasal dari situ. Catatan ini saya bangun dan uji sebelum ada satu layar pun, jadi tidak ada tampilan yang menghitung tata letaknya sendiri lalu berbeda dari yang lain.
Layarnya menampilkan perhitungan yang sebenarnya
Saat menambahkan koreksi galat, encoder menyimpan setiap langkah pembagian panjangnya. Tampilan pembagian menggambar langkah-langkah itu, sehingga pembaca bisa memeriksa satu baris dengan pensil. Encoder juga menilai kedelapan pola mask, walaupun hanya satu yang menang. Galeri mask menampilkan kedelapannya beserta skor penaltinya, jadi selalu cocok dengan pemenangnya.
Setiap kode dicek oleh pustaka independen
Sebuah tes membandingkan hasil saya kotak demi kotak dengan pustaka QR independen. Cakupannya versi 1 sampai 15, keempat tingkat koreksi galat, ketiga mode teks, dan kedelapan mask. Kalau gagal, deploy diblokir. Keduanya berbeda di satu tempat. Untuk satu aturan penalti, pustaka itu membulatkan ke atas, sedangkan spesifikasi ISO membulatkan ke bawah, dan itu bisa mengubah mask pemenang. Saya mengikuti spesifikasi, dan ada tes yang mencatat perbedaan ini supaya tidak terlupakan.
Kode pembayaran yang ditempel tetap di perangkat
Orang menempelkan kode pembayaran asli ke aplikasi ini. Selama dipakai, aplikasi tidak mengirim permintaan jaringan apa pun: tanpa analitik, tanpa pelaporan error, dan font ikut dalam halaman. Pemeriksaan saat build akan gagal kalau ada bagian hasil build yang bisa memanggil jaringan. Teks yang diketik masuk ke URL supaya tautannya bisa dibagikan. Kode QRIS yang ditempel tidak pernah masuk ke URL, dan tombol salin tautan hilang selama kode itu dimuat.
Hasilnya
Anatomi QRIS sudah live dan terbuka untuk umum, dalam bahasa Indonesia dan Inggris. Aplikasi ini menelusuri sembilan tahap, dari teks yang diketik sampai kode yang rusak, lewat slider yang bisa digeser. Kodenya tidak pernah bergeser atau berubah ukuran, jadi di tengah dua tahap kita melihat keduanya setengah jadi. Di lab kerusakan, kita bisa menghapus kotak-kotak dan melihat koreksi galat memperbaikinya secara langsung. Kalau melewati batasnya, kodenya gagal di depan mata, lengkap dengan alasannya. Saya membangunnya dalam sekitar 28 jam selama dua hari pada September 2026.
Di balik layarDetail teknis untuk engineer
- Encoder mengembalikan peta provenans: untuk setiap modul, indeks codeword dan bit, atau pola fungsi, ditambah penanda apakah mask membaliknya. Ada juga peta kebalikannya (codeword ke koordinat modul, byte payload ke codeword). Satu tes men-decode hanya codeword yang disorot untuk membuktikan pemetaannya.
- Encoding Reed-Solomon menghasilkan
divisionTrace(suku utama, kelipatan generator, sisa sebelum dan sesudah), yang langsung digambar oleh tampilan Division. src/engine/murni: tanpa React, tanpa DOM, tanpa keacakan, tanpa jam. Kodenya jalan apa adanya dinode --test.encode()untuk simbol versi 15 selesai di bawah 8 ms, jadi setiap ketikan meng-encode ulang tanpa debounce dan tanpa worker. Caranya: tabel log/antilog GF(256) yang dihitung di awal,Uint8Arraydi jalur utama, dan array modul datar per baris.- Matriks terbesar berukuran 77×77, yaitu 5.929 modul SVG. Satu pointer listener di grup matriks melakukan hit-test dengan membagi koordinat dengan ukuran modul. React memasang rect sekali saja; sebuah painter mengubah warna isian dan menyimpan warna terakhir setiap modul.
- Tes oracle menuntut matriks yang identik per byte dengan
qrcodeuntuk versi 1–15, tingkat EC L/M/Q/H, mode numerik, alfanumerik, dan byte, kedua sisi setiap batas versi, dan kedelapan mask. Tes ini jalan di CI dan memblokir deploy. - Perbedaan di aturan 4:
qrcodememakaiceil(|pct − 50| / 5), sedangkan ISO/IEC 18004 Tabel 11 (dan ZXing) memakai floor. Pada 51,7% modul gelap, spesifikasi memberi penalti 0 danqrcodememberi 10. Oracle memaksa setiap mask dan menuntut kecocokan di kedelapannya, lalu mengecek aturan 1–3 dengan fungsi penalti milikqrcodesendiri. - Lensa QRIS aktif saat input terbaca sebagai payload EMVCo Merchant-Presented Mode yang valid: diawali
000201dan diakhiri CRC16 yang valid di tag 63. Parser TLV, CRC16, dan kamus tag ditulis sendiri, dengan tabel 85 kode kategori merchant. qrcodedanjsqrhanya jadi devDependencies, dan ada tes yang gagal kalau salah satunya di-import darisrc/. Dependensi runtime: React, React DOM, dan tiga paket@fontsource.scripts/check-bundle.mjsmemindai hasil build untuk API jaringan dan URL tak terduga. Favicon di-inline sebagai data URI setelah tes browser menemukan 404 di/favicon.ico.- Tujuh tampilan (Matrix, Bitstream, Division, Interleave, MaskGallery, PayloadTree, DamageLab), tujuh contoh bawaan, 86 token desain CSS, dan dua berkas teks datar untuk bahasa Indonesia dan Inggris. Bundle sekitar 83 KB gzip dari anggaran 250 KB.
- Tombol perbaikan di lab kerusakan menyimpan snapshot kerusakan saat ditekan dan mempertahankan yang tidak bisa diperbaiki decoder. Sebelumnya, kerusakan dari slider noise dihitung ulang setiap kali dibaca, sehingga tombol itu tampak tidak berfungsi di jalur utama.
- Yang sengaja tidak dibuat: mode Kanji, versi 16–40, pemindaian kamera, QR bergaya, dan konversi QRIS statis ke dinamis.
- 84 tes di 13 berkas, sekitar 8.600 baris kode sumber, 44 commit antara 2 dan 3 September 2026.
Tangkapan layar
Sedang merekrut, atau membangun hal serupa?
Saya terbuka untuk posisi full-time dan proyek freelance tertentu.