╭ changed ───────────╮ │src/assets/script.js│ ╰────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │ 4 let wasmInstance; │ │ 5 const decoder = new TextDecoder(); │ │ 6 let currentHtml = ""; │ │ 7 + │ │ 8 +const MIN_COLS = 30; │ │ 9 │ │10 +// measured once after the font is loaded. recomputed lazily if it ever │ │11 +// reads back as zero (e.g. measured before the font was actually ready). │ │12 +let cellWidth = null; │ │13 + │ │14 +function measureCellWidth() { │ │15 + const probe = document.createElement("span"); │ │16 + probe.style.position = "absolute"; │ │17 + probe.style.visibility = "hidden"; │ │18 + probe.style.whiteSpace = "pre"; │ │19 + probe.textContent = "X".repeat(100); │ │20 + grid.appendChild(probe); │ │21 + const w = probe.getBoundingClientRect().width / 100; │ │22 + probe.remove(); │ │23 + return w; │ │24 +} │ │25 + │ │26 +function maxCols() { │ │27 + if (!cellWidth) cellWidth = measureCellWidth(); │ │28 + return Math.max(MIN_COLS, Math.floor(document.body.clientWidth / cellWidth));│ │29 +} │ │30 + │ │31 function readWasmString(ptr, len) { │ │32 const memory = wasmInstance.exports.memory; │ │33 return decoder.decode(new Uint8Array(memory.buffer, ptr, len)); │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────╮ │34 } │ │35 │ │13 -var importObject = { │ │36 +const importObject = { │ │37 env: { │ │15 - _consoleLog: function(ptr, len) { │ │38 + _consoleLog: function (ptr, len) { │ │39 console.log(readWasmString(ptr, len));│ │40 }, │ │18 - _setHtml: function(ptr, len) { │ │41 + _setHtml: function (ptr, len) { │ │42 const html = readWasmString(ptr, len);│ │43 if (html !== currentHtml) { │ │44 currentHtml = html; │ ╰──────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────╮ │48 }, │ │49 }; │ │50 │ │28 -WebAssembly.instantiateStreaming(fetch("haxy.wasm"), importObject).then((result) => { │ │51 +WebAssembly.instantiateStreaming(fetch("haxy.wasm"), importObject).then(async (result) => {│ │52 wasmInstance = result.instance; │ │53 + │ │54 + // wait for the @font-face to load before measuring cell width, otherwise │ │55 + // we get the fallback font's metrics. │ │56 + if (document.fonts && document.fonts.ready) { │ │57 + await document.fonts.ready; │ │58 + } │ │59 │ │60 // the page is embedded as base64 so it can sit inside the host html │ │61 // without worrying about characters that would terminate the script tag. │ ╰───────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │63 const jsonBytes = Uint8Array.from(atob(pageJsonBase64), (c) => c.charCodeAt(0)); │ │64 const ptr = wasmInstance.exports._alloc(jsonBytes.length); │ │65 new Uint8Array(wasmInstance.exports.memory.buffer, ptr, jsonBytes.length).set(jsonBytes); │ │37 - wasmInstance.exports._start(ptr, jsonBytes.length); │ │66 + wasmInstance.exports._start(ptr, jsonBytes.length, maxCols()); │ │67 │ │68 document.addEventListener("keydown", (event) => { │ │69 if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "PageUp", "PageDown", "Home", "End"].includes(event.key)) {│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────╮ │70 event.preventDefault(); │ │71 } │ │72 wasmInstance.exports._onKeyDown(event.keyCode);│ │44 - wasmInstance.exports._tick(); │ │73 + wasmInstance.exports._tick(maxCols()); │ │74 + }); │ │75 + │ │76 + let resizeTimer = null; │ │77 + window.addEventListener("resize", () => { │ │78 + clearTimeout(resizeTimer); │ │79 + resizeTimer = setTimeout(() => { │ │80 + wasmInstance.exports._tick(maxCols()); │ │81 + }, 100); │ │82 }); │ │83 }); │ │84 │ ╰───────────────────────────────────────────────────────────╯