Mirai's Miscellaneous Misadventures

M49 / index.html

<!-- license: AGPLv3 or later -->
<!-- copyright 2024 zamfofex -->

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">

<title> Mirai's Miscellaneous Misadventures </title>

<style>

*, ::before, ::after
{
	touch-action: none;
}

html, body
{
	width: 100%;
	height: 100%;
	display: flex;
}

body
{
	margin: 0;
	background: #000;
}

canvas
{
	width: 100%;
	height: 100%;
	image-rendering: crisp-edges;
	image-rendering: pixelated;
	object-fit: contain;
	outline: none;
}

</style>

<script type="module">

import * as WebAssembly from "https://esm.sh/asyncify-wasm@1.2.1"

let canvas = document.querySelector("canvas")
let context = canvas.getContext("2d")

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 createTexture = async (data0, asset) =>
{
	let view = new DataView(memory.buffer)
	
	if (asset < 0) asset = 0x10000 + asset
	
	let width = view.getUint32(asset, true)
	let height = view.getUint32(asset + 4, true)
	let colors = view.getUint32(asset + 8, true)
	
	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
		}
	}
	
	cache.set(asset, await createImageBitmap(image))
	return asset
}

let stamp = (data, x, y, asset) => context.drawImage(cache.get(asset), x, y)

let invalidate = (data, asset) => cache.delete(asset)

let past = performance.now()

let promise
let resolve = () => { }
let tick = () =>
{
	let now = performance.now()
	resolve(left * 2 + right)
	promise = new Promise(f => { setTimeout(tick, (100 / 3) + past - now) ; resolve = f })
	past = now
}

let imports =
{
	env:
	{
		mimimi_wasm_texture: createTexture,
		mimimi_wasm_invalidate: invalidate,
		mimimi_wasm_stamp: stamp,
		mimimi_wasm_sync: () => promise,
	},
	wasi_snapshot_preview1: {proc_exit: () => { throw new Error("exit called") }},
}

let response = await fetch("mimimi-loader.wasm")
let buffer = await response.arrayBuffer()
let {instance} = await WebAssembly.instantiate(buffer, imports)
let {memory, _start} = instance.exports

let left = 0
let right = 0

addEventListener("keydown", ({code}) =>
{
	if (code === "ArrowLeft") left = 1
	if (code === "ArrowRight") right = 1
	if (code === "KeyA") left = 1
	if (code === "KeyD") right = 1
})

addEventListener("keyup", ({code}) =>
{
	if (code === "ArrowLeft") left = 0
	if (code === "ArrowRight") right = 0
	if (code === "KeyA") left = 0
	if (code === "KeyD") right = 0
})

addEventListener("contextmenu", event => event.preventDefault())

addEventListener("pointerdown", event =>
{
	if (event.pointerType === "mouse") return
	if (event.button !== 0) return
	
	if (event.offsetX < innerWidth / 2)
		left = 1
	else
		right = 1
})

addEventListener("pointerup", event =>
{
	if (event.pointerType === "mouse") return
	if (event.button !== 0) return
	
	left = 0
	right = 0
})

addEventListener("mousedown", ({button}) =>
{
	if (button === 0) left = 1
	if (button === 2) right = 1
})

addEventListener("mouseup", ({button}) =>
{
	if (button === 0) left = 0
	if (button === 2) right = 0
})

tick()
_start()

</script>

<canvas width="512" height="256"></canvas>