Dos cosas siempre llenan el alma de nuevas y cada vez m谩s fuertes sorpresas y reverencias, cuanto m谩s a menudo y m谩s pensamos en ellas: este es el cielo estrellado sobre m铆 y la ley moral en m铆. Immanuel Kant
JS1k es una competencia anual donde necesitas acomodar una demo, un juego o cualquier cosa, en 1024 caracteres en JavaScript. Este a帽o, mi demo ocup贸 el cuarto lugar (hasta el tercero no hab铆a suficientes dos puntos). Puede ver la demostraci贸n en el sitio web JS1k . Quien no abre o no trabaja, deber铆a verse as铆:
El c贸digo fuente completo y minimizado se encuentra en github . Y debajo del corte hay un an谩lisis de c贸mo JavaScript se est谩 minimizando para tales concursos.
Descargo de responsabilidad
La belleza principal de la demo es un sombreador de fragmentos de Pablo Roman Andrioli. Pablo es un artista que trabaja con fractales, y en el foro de foros fractales da algunos detalles de los c谩lculos. Mi tarea consist铆a en empaquetar un sombreador y un c贸digo WebGL de 1024 bytes.
Inicializaci贸n de WebGL
El contenedor JS1k al comienzo de la demostraci贸n proporciona un contexto WebGL en la variable global g . A pesar de esto, trabajar con WebGL es muy detallado. Por ejemplo, para agregar un sombreador de v茅rtices a un programa, se necesitan 159 caracteres:
Para resolver este problema, todas las soluciones JS1k de los 煤ltimos a帽os utilizan un truco con sin贸nimos de funciones:
for(i in g){ g[i[0] + i[6]] = g[i]; }
El bucle agrega un sin贸nimo para cada funci贸n (y para cualquier miembro) del contexto WebGL, que consta de la primera y las 7 letras. Por ejemplo, el programa P reagram se convierte en cP , s hader S ource - sS , etc. Adem谩s, enmarcando todo el c贸digo with(g)
construcci贸n with(g)
(que no se puede usar en estos proyectos), obtenemos:
with(g){ p=cP(); sS(s=cS(35633),'attribute vec2 p;void main(){gl_Position=vec4(p,1,1);}'); ce(s); aS(p,s); }
Minificaci贸n de sombreadores
El sombreador original tiene 1100 caracteres. Las abreviaturas principales: eliminar variables innecesarias y combinar fragmentos similares. Despu茅s de todo, pas茅 el c贸digo a trav茅s del minificador en l铆nea . Como resultado, quedaba un poco m谩s de 500 bytes del sombreador.
JSCrush
JSCrush es el est谩ndar de facto para comprimir c贸digo en tales competiciones. La utilidad convierte el c贸digo en aproximadamente la siguiente secuencia:
_ = '(i 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(_)
El principio de JSCrush se puede ver visualmente en la herramienta para la conversi贸n inversa de c贸digo . O leer en detalle en el art铆culo . En general, esto est谩 codificando con un diccionario:
- Encontramos un personaje que no se usa en el c贸digo
- Encontramos fragmentos repetidos en el c贸digo que reemplazamos con el car谩cter del primer p谩rrafo
- Reemplace la cadena con un caracter
- Repita 1-3 hasta que el resultado sea m谩s peque帽o que el c贸digo fuente.
Optimizaci贸n
Despu茅s de todas las operaciones, todav铆a me quedaban unos 30 caracteres, que podr铆an usarse para optimizar el rendimiento. Al cargar la demostraci贸n, puede especificar el tama帽o del lienzo: pantalla completa o tama帽o fijo. El lanzamiento en pantalla completa es hermoso, pero el sombreador de fragmentos se llama para cada p铆xel y funciona lentamente. La soluci贸n fue pedirle al lienzo JS1k un tama帽o fijo (eleg铆 640x640), y luego aumentarlo a pantalla completa en el c贸digo:
a.style='width:100%;height:100vh;float:left';
Luego, la imagen ocupa toda la pantalla, pero el sombreador se ejecuta solo para cada p铆xel del tama帽o del lienzo original.