kinda/web/sim.js

108 lines
2.6 KiB
JavaScript

const EVENT_UP = 0;
const EVENT_DOWN = 1;
const EVENT_SELECT = 2;
const EVENT_BACK = 3;
const canvas = document.getElementById('display');
const context = canvas.getContext('2d');
const status = document.getElementById('status');
const buttons = Array.from(document.querySelectorAll('[data-event]'));
let wasm;
async function loadWasm() {
const imports = {};
const response = fetch('./pkg/kinda.wasm');
if ('instantiateStreaming' in WebAssembly) {
try {
return await WebAssembly.instantiateStreaming(response, imports);
} catch (error) {
console.warn('Falling back to ArrayBuffer WebAssembly load', error);
}
}
const bytes = await (await fetch('./pkg/kinda.wasm')).arrayBuffer();
return WebAssembly.instantiate(bytes, imports);
}
function render() {
const width = wasm.kinda_sim_width();
const height = wasm.kinda_sim_height();
const pixelPointer = wasm.kinda_sim_pixels();
const pixelLength = wasm.kinda_sim_pixel_len();
const pixels = new Uint8Array(wasm.memory.buffer, pixelPointer, pixelLength);
canvas.width = width;
canvas.height = height;
const image = context.createImageData(width, height);
for (let source = 0, target = 0; source < pixels.length; source += 1, target += 4) {
const value = Math.round(18 + (pixels[source] * 230) / 255);
image.data[target] = value;
image.data[target + 1] = value;
image.data[target + 2] = value;
image.data[target + 3] = 255;
}
context.putImageData(image, 0, 0);
}
function sendInput(eventCode) {
if (!wasm) {
return;
}
wasm.kinda_sim_input(eventCode);
render();
}
function keyboardEventCode(event) {
if (event.key === 'ArrowUp') {
return EVENT_UP;
}
if (event.key === 'ArrowDown') {
return EVENT_DOWN;
}
if (event.key === 'Enter') {
return EVENT_SELECT;
}
if (event.key === 'Escape' || event.key === 'Backspace') {
return EVENT_BACK;
}
return null;
}
buttons.forEach((button) => {
button.disabled = true;
button.addEventListener('click', () => sendInput(Number(button.dataset.event)));
});
window.addEventListener('keydown', (event) => {
const eventCode = keyboardEventCode(event);
if (eventCode === null) {
return;
}
event.preventDefault();
sendInput(eventCode);
});
try {
const instance = await loadWasm();
wasm = instance.instance.exports;
wasm.kinda_sim_init();
render();
buttons.forEach((button) => {
button.disabled = false;
});
status.textContent = 'Ready. Select scans with mock WiFi results.';
} catch (error) {
console.error(error);
status.textContent = error instanceof Error ? error.message : 'Could not load simulator.';
}