Skip to content

Commit a2d911f

Browse files
committed
ref(wasm): use brotli-11 + z85 wasm encoding
1 parent 4139212 commit a2d911f

1 file changed

Lines changed: 53 additions & 7 deletions

File tree

tasks/bundle-wasm.ts

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,59 @@
1-
import { encodeBase64 } from "@std/encoding/base64";
1+
import { brotliCompressSync, constants } from "node:zlib";
2+
3+
const Z85 =
4+
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#";
5+
6+
function encodeZ85(data: Uint8Array): string {
7+
let padLen = (4 - (data.length % 4)) % 4;
8+
let src = data;
9+
if (padLen > 0) {
10+
src = new Uint8Array(data.length + padLen);
11+
src.set(data);
12+
}
13+
let out: string[] = [];
14+
for (let i = 0; i < src.length; i += 4) {
15+
let v =
16+
src[i] * 16777216 +
17+
src[i + 1] * 65536 +
18+
src[i + 2] * 256 +
19+
src[i + 3];
20+
out.push(
21+
Z85[Math.floor(v / 52200625)],
22+
Z85[Math.floor(v / 614125) % 85],
23+
Z85[Math.floor(v / 7225) % 85],
24+
Z85[Math.floor(v / 85) % 85],
25+
Z85[v % 85],
26+
);
27+
}
28+
return out.join("");
29+
}
230

331
const wasm = await Deno.readFile("clayterm.wasm");
4-
const base64 = encodeBase64(wasm);
532

6-
const source = `const bin = atob("${base64}");
7-
const bytes = new Uint8Array(bin.length);
8-
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
9-
export const compiled = await WebAssembly.compile(bytes);
33+
const compressed = new Uint8Array(
34+
brotliCompressSync(wasm, {
35+
params: {
36+
[constants.BROTLI_PARAM_QUALITY]: 11,
37+
[constants.BROTLI_PARAM_SIZE_HINT]: wasm.length,
38+
[constants.BROTLI_PARAM_LGWIN]: 24,
39+
},
40+
}),
41+
);
42+
43+
const z85 = encodeZ85(compressed);
44+
45+
// Decoder uses division instead of >>> to avoid 32-bit truncation on values near 0xFFFFFFFF.
46+
const source = `import{brotliDecompressSync}from"node:zlib";
47+
const Z="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#";
48+
const T=new Uint8Array(128);for(let i=0;i<85;i++)T[Z.charCodeAt(i)]=i;
49+
function d(s:string,n:number){const b=new Uint8Array(n);let o=0;for(let i=0;i<s.length&&o<n;i+=5){const v=T[s.charCodeAt(i)]*52200625+T[s.charCodeAt(i+1)]*614125+T[s.charCodeAt(i+2)]*7225+T[s.charCodeAt(i+3)]*85+T[s.charCodeAt(i+4)];if(o<n)b[o++]=Math.floor(v/16777216);if(o<n)b[o++]=Math.floor(v/65536)%256;if(o<n)b[o++]=Math.floor(v/256)%256;if(o<n)b[o++]=v%256;}return b;}
50+
const compressed=d(${JSON.stringify(z85)},${compressed.byteLength});
51+
export const compiled=await WebAssembly.compile(new Uint8Array(brotliDecompressSync(compressed)));
1052
`;
1153

1254
await Deno.writeTextFile("wasm.ts", source);
13-
console.log(`wrote wasm.ts (${wasm.length} bytes encoded)`);
55+
console.log(
56+
`wrote wasm.ts (${wasm.length}${compressed.byteLength} bytes compressed, ${z85.length} bytes z85, ${
57+
Math.round(z85.length / wasm.length * 100)
58+
}%)`,
59+
);

0 commit comments

Comments
 (0)