Dua hal selalu mengisi jiwa dengan kejutan dan penghormatan yang baru dan semakin kuat, semakin sering dan semakin lama kita memikirkannya - ini adalah langit berbintang di atasku dan hukum moral dalam diriku. Immanuel Kant
JS1k adalah kompetisi tahunan di mana Anda perlu mengakomodasi demo, game, atau apa pun, dalam 1024 karakter dalam JavaScript. Tahun ini, demo saya mengambil tempat keempat (sampai ketiga tidak ada cukup dua poin). Anda dapat menonton demo di situs web JS1k . Siapa yang tidak membuka atau tidak bekerja, akan terlihat seperti ini:
Kode sumber yang diperkecil dan lengkap ada di github . Dan di bawah potongan adalah analisis tentang bagaimana JavaScript sekarang sedang diperkecil untuk kontes seperti itu.
Penafian
Keindahan utama dari demo adalah fragmen shader oleh Pablo Roman Andrioli. Pablo adalah seorang seniman yang bekerja dengan fraktal, dan di forum fractalforums ia memberikan beberapa detail perhitungan. Tugas saya adalah mengemas kode shader dan WebGL 1024 byte.
Inisialisasi WebGL
Pembungkus JS1k pada awal demo menyediakan konteks WebGL dalam variabel global g . Meskipun demikian, bekerja dengan WebGL sangat bertele-tele. Misalnya, untuk menambahkan vertex shader ke program, diperlukan 159 karakter:
Untuk mengatasi masalah ini, semua solusi JS1k dalam beberapa tahun terakhir menggunakan trik dengan sinonim fungsi:
for(i in g){ g[i[0] + i[6]] = g[i]; }
Loop menambahkan sinonim untuk setiap fungsi (dan untuk setiap anggota) dari konteks WebGL, yang terdiri dari huruf pertama dan 7. Sebagai contoh, c reate P rogram menjadi cP , s hader S ource - sS , dll. Selain itu, membingkai semua kode with(g)
konstruksi ( with(g)
(yang tidak dapat digunakan dalam proyek-proyek ini), kita mendapatkan:
with(g){ p=cP(); sS(s=cS(35633),'attribute vec2 p;void main(){gl_Position=vec4(p,1,1);}'); ce(s); aS(p,s); }
Minifikasi shader
Shader asli membutuhkan 1100 karakter. Singkatan utama: menghapus variabel yang tidak perlu, dan menggabungkan fragmen serupa. Bagaimanapun, saya melewati kode melalui minifier online . Akibatnya, sedikit lebih dari 500 byte tetap dari shader.
JSCrush
JSCrush adalah standar de facto untuk mengompresi kode dalam kompetisi semacam itu. Utilitas mengubah kode menjadi sekitar urutan berikut:
_ = '(saya a.style = ... _='(i a.style="widMj%;hEjvh;:left",g)g[i[0]+i[6]]=g[i];wiMO.u=g.G1f,x=y=k=g)p=cP(35633"tribute 2 p gl_Posit=4?FN"precis mediump ;G Zt,a,x,y Uf`ord.rg/64!-.f.=a;Zc=+xz,v=+yz;m2 m$cc-cc)s$vv-vv)fJf#Ur`Q,,r+`t*2.,t,-2.rJr#Zg=.1,b=Q;Ui`!Kl=Rl<2Rl++){Uo=r+f*;oQ)-mod(o,2.))Ze,n=e=!;Kd=Rd<2Rd++)oo)/dot(o,o)-3,n+o)-ee=oif(l>6)Q-max(!,.3-i+=b+g,g,g)*n*5*b;.73;g+=.1;}i=mix(i)i,.85lor=4(i*.01.lo?ug?bfO=34962,cB()eV(0vA(2,5120bDO,Tw Int8Array([|,|]35044o=,(Lt@-oa@TrHE/TrWidMx@xy@ydr(6,3requestAnimFrame(L)})(down=upk^=1},movek&&(xX,yY)};),3=funct(e){uOf?,"flo}@ce(saS?,slengM(onmouse ;void ma(){Tw De/1e5);incos(for=abs(gl_FragCo,1g*(sS(s=cS(n*n*.001at.5vecionb*=s(=e.page0,!0.#.r=s;$=m2(?(p@"EeightGunimJ.rm;K(t MthO(gQ1.R0;TneU Z `=j:100z/50!|-3';for(Y in $='|zj`ZUTRQOMKJGE@?$#! ')with(_.split($[Y]))_=join(pop());eval(_)
Prinsip JSCrush dapat dilihat secara visual di alat untuk konversi kode terbalik . Atau baca secara detail di artikel . Secara umum, ini disandikan dengan kamus:
- Kami menemukan karakter yang tidak digunakan dalam kode
- Kami menemukan fragmen berulang dalam kode yang kami ganti dengan karakter dari paragraf pertama
- Ganti string dengan karakter
- Ulangi 1-3 hingga hasilnya lebih kecil dari kode sumber.
Optimasi
Setelah semua operasi, saya masih memiliki sekitar 30 karakter yang tersisa, yang dapat digunakan untuk mengoptimalkan kinerja. Saat memuat demo, Anda dapat menentukan ukuran kanvas: layar penuh atau ukuran tetap. Meluncurkan dalam layar penuh itu indah, tetapi shader fragmen dipanggil untuk setiap piksel dan bekerja lambat. Solusinya adalah meminta kanvas JS1k untuk ukuran tetap (saya memilih 640x640), dan kemudian menambahkannya ke layar penuh dalam kode:
a.style='width:100%;height:100vh;float:left';
Kemudian gambar menempati seluruh layar, tetapi shader dijalankan hanya untuk setiap piksel dari ukuran kanvas asli.