Mirai's Miscellaneous Misadventures
M19 / index.html
<!-- copyright 2022 zamfofex -->
<!-- license: AGPLv3 or later -->
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Mirai’s Miscellaneous Misadventures</title>
<style>
html, body
{
width: 100%;
height: 100%;
display: flex;
}
body
{
margin: 0;
background: #000;
touch-action: manipulation;
}
canvas
{
width: 100%;
height: 100%;
image-rendering: crisp-edges;
image-rendering: pixelated;
object-fit: contain;
}
</style>
<script type="module">
let canvas = document.querySelector("canvas")
let context = canvas.getContext("2d")
let global = v =>
{
if (typeof v === "number") return v
return v.value
}
let main = async () =>
{
let stamp = (data, x, y, asset) =>
{
let image = toImage(asset)
if (!image) return
context.drawImage(image, x, y)
}
let imports = {env: {mimimi_wasm_javascript_stamp: stamp}}
let module
try { module = await WebAssembly.instantiateStreaming(fetch("mimimi.wasm"), imports) }
catch (e) { module = await WebAssembly.instantiate(await (await fetch("mimimi.wasm")).arrayBuffer(), imports) }
let {instance: {exports}} = module
let {memory, __indirect_function_table: table} = exports
let {mimimi_wasm_allocator} = exports
let {mimimi_wasm_allocate} = exports
let {mimimi_wasm_stamp} = exports
let {mimimi_test} = exports
let getView = () => new DataView(memory.buffer)
let allocator = getView().getUint32(global(mimimi_wasm_allocator), true)
let chapter = mimimi_test(allocator)
let behavior = getView().getUint32(chapter, true)
let engine = getView().getUint32(chapter + 4, true)
let keys = chapter + 8
let size = mimimi_wasm_allocate(8)
getView().setUint32(size + 0, canvas.width, true)
getView().setUint32(size + 4, canvas.height, true)
let f = table.grow(1)
table.set(f, mimimi_wasm_stamp)
getView().setUint32(engine + 4, f, true)
getView().setUint32(engine + 8, size, true)
let inputs = {ArrowLeft: 1, ArrowRight: 2}
let down = 0
addEventListener("keydown", ({code}) =>
{
let v = inputs[code]
if (v) down = down | v
})
addEventListener("keyup", ({code}) =>
{
let v = inputs[code]
if (v) down = down & ~v
down %= 0x100
})
let tap = 0
addEventListener("pointerdown", ({x, y, button}) =>
{
if (button !== 0) return
if (x < innerWidth / 2)
tap = tap | 1
else
tap = tap | 2
})
addEventListener("pointerup", () => tap = 0)
let cache = new Map()
let rch = [0x11, 0x44, 0x77, 0x99, 0xCC, 0xFF]
let gch = [0x11, 0x33, 0x55, 0x77, 0x99, 0xBB, 0xDD, 0xFF]
let bch = [0x22, 0x55, 0x88, 0xBB, 0xEE]
let toImage = asset =>
{
let view = getView()
let cached = cache.get(asset)
if (cached !== undefined) return cached
let width = view.getUint32(asset, true)
let height = view.getUint32(asset + 4, true)
let colors = view.getUint32(asset + 8, true)
if (width === 0 || height === 0)
{
cache.set(asset, null)
return null
}
let image = new ImageData(width, height)
let {data} = image
for (let x = 0 ; x < width ; x++)
for (let y = 0 ; y < height ; y++)
{
let o = x + y * width
let color = view.getUint8(colors + o)
if (color === 0) continue
if (color < 0x10)
{
let ch = color * 0x11
data[o * 4 + 0] = ch
data[o * 4 + 1] = ch
data[o * 4 + 2] = ch
data[o * 4 + 3] = 0xFF
}
else
{
color -= 0x10
let r = rch[Math.floor(color / 40) % 6]
let g = gch[Math.floor(color / 5) % 8]
let b = bch[Math.floor(color / 1) % 5]
data[o * 4 + 0] = r
data[o * 4 + 1] = g
data[o * 4 + 2] = b
data[o * 4 + 3] = 0xFF
}
}
let canvas = document.createElement("canvas")
let ctx = canvas.getContext("2d")
canvas.width = image.width
canvas.height = image.height
ctx.putImageData(image, 0, 0)
cache.set(asset, canvas)
return canvas
}
let past = performance.now()
let step = () =>
{
let view = getView()
view.setUint32(keys, down|tap, true)
table.get(view.getUint32(behavior, true))(view.getUint32(behavior + 8, true))
let now = performance.now()
setTimeout(step, (100/3) + past - now)
past = now
}
step()
}
main()
</script>
<canvas width="512" height="256"></canvas>