Difference between revisions of "JavaScript"
(Created page with "The Javascript sizecoding community has been quite active for years now. === Setting up === * Tools: [http://www.iteral.com/jscrush/ JSCrush online] [https://github.com/gre/...") |
|||
(34 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
The Javascript sizecoding community has been quite active for years now. | The Javascript sizecoding community has been quite active for years now. | ||
− | + | == Setting up == | |
+ | ==== Tools ==== | ||
* Tools: [http://www.iteral.com/jscrush/ JSCrush online] [https://github.com/gre/jscrush JSCrush cli-tool] [https://siorki.github.io/regPack.html Reg Pack] | * Tools: [http://www.iteral.com/jscrush/ JSCrush online] [https://github.com/gre/jscrush JSCrush cli-tool] [https://siorki.github.io/regPack.html Reg Pack] | ||
* Execution environment(s): Browser, [https://www.dwitter.net Dwitter] | * Execution environment(s): Browser, [https://www.dwitter.net Dwitter] | ||
− | + | == Video display == | |
− | + | There are basically a ways to go about getting some graphics on screen: Minimal 2D Canvas, WebGL and WebAssembly. | |
− | === | + | === Minimal 2D Canvas === |
+ | Here a a couple of minimal HTML 2D Canvas setups for animation: | ||
− | + | <syntaxhighlight lang="html"> | |
+ | <canvas id=c style=width:99%><svg onload=setInterval('',t=9)> | ||
+ | <canvas id=c style=width:99% onclick=setInterval('',t=9)> | ||
+ | <canvas id=c><svg onload=setInterval('',t=9)> | ||
+ | <canvas id=c onclick=setInterval('',t=9)> | ||
+ | <svg onload=setInterval('',t=9)> | ||
+ | </syntaxhighlight> | ||
+ | And here are a few for static content: | ||
+ | <syntaxhighlight lang="html"> | ||
+ | <canvas id=c><svg onload=''> | ||
+ | <svg onload=''> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==== A minimal 2D Canvas Example ==== | ||
+ | Here would be an example of a simple 128 byte setup of a scrolling XOR-pattern using grayscale. | ||
+ | <syntaxhighlight lang="html"> | ||
+ | <canvas id=c onclick=setInterval('for(c.width=w=320,++t,o=w*w;o--;c.getContext`2d`.fillRect(X=o%w,Y=o/w,1-(X+t^Y)/99,1));',t=9)> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | And here is one for static text content in 64 bytes. | ||
+ | <syntaxhighlight lang="html"> | ||
+ | <svg onload=for(i=8160;i--;)write(i%128?i/128&i?'_':'#':'\n')> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === WebGL === | ||
+ | To be added. | ||
+ | |||
+ | === Dwitter template === | ||
+ | For anyone familiar with Dwitter, here is a 189 byte dwitter template that will allow you to directly convert a dweet to a working standalone javascript/html | ||
+ | |||
+ | <syntaxhighlight lang="html"> | ||
+ | <body onload='t=0;x=c.getContext'2d';with(Math)S=sin,C=cos,T=tan;R=(r,g,b,a=1)=>'rgba(${[r|0,g|0,b|0,a]})';setInterval("{/* code */};t+=.016",16)'><canvas id=c width=1920 height=1080 style=width:99%> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === WebAssembly === | ||
+ | It is also possible to bootstrap a base64 binary of WebAssembly directly into HTML. | ||
+ | There is a toolchain called wasmer ( https://github.com/Kaproncai/wasmer ) that helps you do this. Now you can write WASM code that writes pixeldata to memory and bootstrap | ||
+ | that to HTML. | ||
+ | |||
+ | == Sound == | ||
+ | Here are a few methods to get sound for your tiny intro. Note that all of these methods will need a user-click | ||
+ | to active the browser and start the intro. | ||
+ | |||
+ | === Audio Buffer Source === | ||
+ | <syntaxhighlight lang="javascript"> | ||
+ | // Audio element + Wave PCM | ||
+ | h=d='data:audio/wav;base64,'+'UklGRiQAAABXQVZFZm10...'; | ||
+ | for(t=0;t++<8e5;) d+=String.fromCharCode(/*ByteBeat*/); | ||
+ | Z=new Audio(h+btoa(d));z.play(); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Audio Buffer Source === | ||
+ | <syntaxhighlight lang="javascript"> | ||
+ | // Audio element + buffer | ||
+ | A=new AudioContext;B=A.createBuffer(1, 8e5, freq);d=B.getChannelData(0); | ||
+ | for(t=0;t<8e5;t++) d[t]= /* FloatBeat */; | ||
+ | S=A.createBufferSource();S.buffer=B; | ||
+ | S.connect(A.destination);S.start(); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Other Methods === | ||
+ | Audio worklets, Nodes, WebGL, Speechsynth | ||
+ | |||
+ | === More information === | ||
* [https://marcgg.com/blog/2016/11/01/javascript-audio/ Generate Sounds Programmatically With Javascript] | * [https://marcgg.com/blog/2016/11/01/javascript-audio/ Generate Sounds Programmatically With Javascript] | ||
− | + | == Compression == | |
+ | When it comes to compressing your code, there are several options you can consider: | ||
+ | |||
+ | ==== RegPack / jscrush ==== | ||
+ | The default packesr that helps to rename and shuffle variables and code contructs to pack Javascript code. No additional bootstrapping overhead needed. | ||
+ | |||
+ | JSCrush works by: | ||
+ | * Finding the first unused ASCII character to act as the join | ||
+ | * Finding the substring of the program text that gives the best space savings if its repetitions are all replaced by the ASCII character from 1. | ||
+ | * Splitting the source on 2 and joining the pieces using 1, tacking on 2 to the end. This string replaces the original source. | ||
+ | * Repeating 1, 2 and 3 until no more savings are possible or we’re all out of ASCII. | ||
+ | * Wrapping the compressed source into a string, then using the list of join ASCII characters to unroll the string. | ||
+ | * Unrolling is performed by splitting on every ASCII character used in 3, extracting the original repeated substring 2 from the split and joining the parts. | ||
+ | |||
+ | The online tool https://xem.github.io/terser-online/ is a great example of a code-minifier that supports both | ||
+ | regpack and deflate-compressed outputs. | ||
+ | |||
+ | ==== Using DecompressionStream ==== | ||
+ | On modern browsers its possible to use HTML self decompression based on the DecompressionStream API | ||
+ | * [https://subzey.github.io/fetchcrunch/ FetchCrunch packer] | ||
+ | * [https://gist.github.com/0b5vr/09ee96ca2efbe5bf9d64dad7220e923b compeko JavaScript into a self-extracting html+deflate packer] | ||
+ | |||
+ | ==== Bootstrapping PNG ==== | ||
+ | It is possible to bootstrap ZLIB compressed code by encoding your code inside a (usually single line) PNG file and bootstrap that from HTML. | ||
+ | For example the pnginator tool helps you create such a PNG file. Overhead size for bootstrapping the PNG is about 160 bytes so it is mostly | ||
+ | viable for 1K and bigger sized intros. | ||
+ | |||
+ | ==== Bootstrapping WEBP ==== | ||
+ | The same technique is also possible for WEBP files, which use a LZ type of compression which tends to work a little less efficient. on compressing code. | ||
+ | |||
+ | ==== Bootstrapping Brotli ==== | ||
+ | It is also possible to bootstap Brotli compressed code to a WOFF2 font as described here: | ||
+ | * https://gist.github.com/lifthrasiir/1c7f9c5a421ad39c1af19a9c4f060743 | ||
+ | |||
+ | Which can then be bootsrapped using the tool above and accessed from HTML with the following (256 character) code: | ||
+ | <syntaxhighlight lang="html"> | ||
+ | <body[ARBITRARY_BYTES_HERE] onload="new FontFace('x','url(#').load(C=$.getContext`2d`).then(A=>{document.fonts.add(A);C.font='1pc x';K=String.fromCharCode;for(A=I='';I<[NUM_GLYPHS];A+=K(W>>8,W&255))W=C.measureText(K(2e4+I++)).width;eval(A)})"><canvas id=$> | ||
+ | </syntaxhighlight> | ||
− | === | + | Or alternatively, if you are lucky maybe some parties will accept brotli code directly when you provide your own server: |
− | + | <syntaxhighlight lang="html"> | |
+ | require("http").createServer((req, res) => { | ||
+ | const path = (req.url || "/").slice(1); | ||
+ | if (path === "") { | ||
+ | const buffer = require("fs").readFileSync("intro.htm.br"); | ||
+ | res.setHeader("Content-Type", "text/html"); | ||
+ | res.setHeader("Content-Encoding", "br"); | ||
+ | res.setHeader("Content-Length", buffer.byteLength); | ||
+ | res.write(buffer); | ||
+ | } | ||
+ | res.end(); | ||
+ | }).listen(1337); | ||
+ | console.log(` | ||
+ | Open http://localhost:1337 to watch intro. | ||
+ | This mini http server is only here to pass the Content-Encoding we are missing on file:// compared to the normal environment of a web page | ||
+ | `); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Additional Resources == | ||
− | + | ==== Seminars ==== | |
+ | * [https://www.youtube.com/watch?v=waFzG0IVXCw Javascript and demoscene sizecoding, by p01] | ||
+ | * [https://www.youtube.com/watch?v=HV7Dmo277Rs JavaScript Haikus: My adventures in Tiny Coding by Frank Force] | ||
+ | * [https://www.youtube.com/watch?v=CagnRwPkw_M JavaScript Haikus:My adventures in Tiny Coding (Texas Edition) by Frank Force] | ||
− | * [https://frankforce.com/ | + | ==== Tutorials / Postmortems ==== |
+ | * [https://www.p01.org/ Various writeups by Mathieu 'p01' Henri] | ||
+ | * [https://frankforce.com/ Various writeups by Frank Force aka KilledByAPixel] | ||
* [https://nikhilism.com/post/2012/demystifying-jscrush/ Demystifying JSCrush] | * [https://nikhilism.com/post/2012/demystifying-jscrush/ Demystifying JSCrush] | ||
− | + | ==== Tools ==== | |
+ | * [https://siorki.github.io/regPack.html regPack] | ||
+ | * [http://www.iteral.com/jscrush jscrush] | ||
+ | * [https://xem.github.io/terser-online/ terser minifier] | ||
+ | * [https://subzey.github.io/fetchcrunch/ FetchCrunch packer] | ||
+ | * [https://gist.github.com/0b5vr/09ee96ca2efbe5bf9d64dad7220e923b compeko JavaScript into a self-extracting html+deflate packer] | ||
+ | * [https://gist.github.com/gasman/2560551 pnginator PNG bootstrapper] | ||
+ | * [https://gist.github.com/lifthrasiir/1c7f9c5a421ad39c1af19a9c4f060743 Brotli WOFF2 font bootstrap] | ||
+ | * [https://github.com/Kaproncai/wasmer Wasmer: WASM to HTML bootstrapper] | ||
+ | |||
+ | ==== Browser Intros ==== | ||
+ | * [https://demozoo.org/productions/?platform=12&production_type=21 1024 byte intros] | ||
+ | * [https://demozoo.org/productions/?platform=12&production_type=20 512 byte intros] | ||
+ | * [https://demozoo.org/productions/?platform=12&production_type=19 256 byte intros] | ||
+ | * [https://demozoo.org/productions/?platform=12&production_type=18 128 byte intros] | ||
+ | * [https://demozoo.org/productions/?platform=12&production_type=16 64 byte intros] | ||
+ | |||
+ | ==== Other Links ==== | ||
+ | * [https://js1k.com JS1k] |
Latest revision as of 01:16, 11 November 2024
The Javascript sizecoding community has been quite active for years now.
Setting up
Tools
- Tools: JSCrush online JSCrush cli-tool Reg Pack
- Execution environment(s): Browser, Dwitter
Video display
There are basically a ways to go about getting some graphics on screen: Minimal 2D Canvas, WebGL and WebAssembly.
Minimal 2D Canvas
Here a a couple of minimal HTML 2D Canvas setups for animation:
<canvas id=c style=width:99%><svg onload=setInterval('',t=9)>
<canvas id=c style=width:99% onclick=setInterval('',t=9)>
<canvas id=c><svg onload=setInterval('',t=9)>
<canvas id=c onclick=setInterval('',t=9)>
<svg onload=setInterval('',t=9)>
And here are a few for static content:
<canvas id=c><svg onload=''>
<svg onload=''>
A minimal 2D Canvas Example
Here would be an example of a simple 128 byte setup of a scrolling XOR-pattern using grayscale.
<canvas id=c onclick=setInterval('for(c.width=w=320,++t,o=w*w;o--;c.getContext`2d`.fillRect(X=o%w,Y=o/w,1-(X+t^Y)/99,1));',t=9)>
And here is one for static text content in 64 bytes.
<svg onload=for(i=8160;i--;)write(i%128?i/128&i?'_':'#':'\n')>
WebGL
To be added.
Dwitter template
For anyone familiar with Dwitter, here is a 189 byte dwitter template that will allow you to directly convert a dweet to a working standalone javascript/html
<body onload='t=0;x=c.getContext'2d';with(Math)S=sin,C=cos,T=tan;R=(r,g,b,a=1)=>'rgba(${[r|0,g|0,b|0,a]})';setInterval("{/* code */};t+=.016",16)'><canvas id=c width=1920 height=1080 style=width:99%>
WebAssembly
It is also possible to bootstrap a base64 binary of WebAssembly directly into HTML. There is a toolchain called wasmer ( https://github.com/Kaproncai/wasmer ) that helps you do this. Now you can write WASM code that writes pixeldata to memory and bootstrap that to HTML.
Sound
Here are a few methods to get sound for your tiny intro. Note that all of these methods will need a user-click to active the browser and start the intro.
Audio Buffer Source
// Audio element + Wave PCM
h=d='data:audio/wav;base64,'+'UklGRiQAAABXQVZFZm10...';
for(t=0;t++<8e5;) d+=String.fromCharCode(/*ByteBeat*/);
Z=new Audio(h+btoa(d));z.play();
Audio Buffer Source
// Audio element + buffer
A=new AudioContext;B=A.createBuffer(1, 8e5, freq);d=B.getChannelData(0);
for(t=0;t<8e5;t++) d[t]= /* FloatBeat */;
S=A.createBufferSource();S.buffer=B;
S.connect(A.destination);S.start();
Other Methods
Audio worklets, Nodes, WebGL, Speechsynth
More information
Compression
When it comes to compressing your code, there are several options you can consider:
RegPack / jscrush
The default packesr that helps to rename and shuffle variables and code contructs to pack Javascript code. No additional bootstrapping overhead needed.
JSCrush works by:
- Finding the first unused ASCII character to act as the join
- Finding the substring of the program text that gives the best space savings if its repetitions are all replaced by the ASCII character from 1.
- Splitting the source on 2 and joining the pieces using 1, tacking on 2 to the end. This string replaces the original source.
- Repeating 1, 2 and 3 until no more savings are possible or we’re all out of ASCII.
- Wrapping the compressed source into a string, then using the list of join ASCII characters to unroll the string.
- Unrolling is performed by splitting on every ASCII character used in 3, extracting the original repeated substring 2 from the split and joining the parts.
The online tool https://xem.github.io/terser-online/ is a great example of a code-minifier that supports both regpack and deflate-compressed outputs.
Using DecompressionStream
On modern browsers its possible to use HTML self decompression based on the DecompressionStream API
Bootstrapping PNG
It is possible to bootstrap ZLIB compressed code by encoding your code inside a (usually single line) PNG file and bootstrap that from HTML. For example the pnginator tool helps you create such a PNG file. Overhead size for bootstrapping the PNG is about 160 bytes so it is mostly viable for 1K and bigger sized intros.
Bootstrapping WEBP
The same technique is also possible for WEBP files, which use a LZ type of compression which tends to work a little less efficient. on compressing code.
Bootstrapping Brotli
It is also possible to bootstap Brotli compressed code to a WOFF2 font as described here:
Which can then be bootsrapped using the tool above and accessed from HTML with the following (256 character) code:
<body[ARBITRARY_BYTES_HERE] onload="new FontFace('x','url(#').load(C=$.getContext`2d`).then(A=>{document.fonts.add(A);C.font='1pc x';K=String.fromCharCode;for(A=I='';I<[NUM_GLYPHS];A+=K(W>>8,W&255))W=C.measureText(K(2e4+I++)).width;eval(A)})"><canvas id=$>
Or alternatively, if you are lucky maybe some parties will accept brotli code directly when you provide your own server:
require("http").createServer((req, res) => {
const path = (req.url || "/").slice(1);
if (path === "") {
const buffer = require("fs").readFileSync("intro.htm.br");
res.setHeader("Content-Type", "text/html");
res.setHeader("Content-Encoding", "br");
res.setHeader("Content-Length", buffer.byteLength);
res.write(buffer);
}
res.end();
}).listen(1337);
console.log(`
Open http://localhost:1337 to watch intro.
This mini http server is only here to pass the Content-Encoding we are missing on file:// compared to the normal environment of a web page
`);
Additional Resources
Seminars
- Javascript and demoscene sizecoding, by p01
- JavaScript Haikus: My adventures in Tiny Coding by Frank Force
- JavaScript Haikus:My adventures in Tiny Coding (Texas Edition) by Frank Force
Tutorials / Postmortems
- Various writeups by Mathieu 'p01' Henri
- Various writeups by Frank Force aka KilledByAPixel
- Demystifying JSCrush
Tools
- regPack
- jscrush
- terser minifier
- FetchCrunch packer
- compeko JavaScript into a self-extracting html+deflate packer
- pnginator PNG bootstrapper
- Brotli WOFF2 font bootstrap
- Wasmer: WASM to HTML bootstrapper