Mirai's Miscellaneous Misadventures

M51 / index.html

1<!-- license: AGPLv3 or later -->
2<!-- copyright 2024 zamfofex -->
3
4<!doctype html>
5<html lang="en">
6<meta charset="utf-8">
7<meta name="viewport" content="width=device-width">
8
9<title> Mirai's Miscellaneous Misadventures </title>
10
11<style>
12
13*, ::before, ::after
14{
15	touch-action: none;
16}
17
18html, body
19{
20	width: 100%;
21	height: 100%;
22	display: flex;
23}
24
25body
26{
27	margin: 0;
28	background: #000;
29}
30
31canvas
32{
33	width: 100%;
34	height: 100%;
35	image-rendering: crisp-edges;
36	image-rendering: pixelated;
37	object-fit: contain;
38	outline: none;
39}
40
41</style>
42
43<script type="module">
44
45import * as WebAssembly from "https://esm.sh/asyncify-wasm@1.2.1"
46
47let canvas = document.querySelector("canvas")
48let context = canvas.getContext("2d")
49
50let cache = new Map()
51
52let rch = [0x11, 0x44, 0x77, 0x99, 0xCC, 0xFF]
53let gch = [0x11, 0x33, 0x55, 0x77, 0x99, 0xBB, 0xDD, 0xFF]
54let bch = [0x22, 0x55, 0x88, 0xBB, 0xEE]
55
56let createTexture = async (data0, asset) =>
57{
58	let view = new DataView(memory.buffer)
59	
60	if (asset < 0) asset = 0x10000 + asset
61	
62	let width = view.getUint32(asset, true)
63	let height = view.getUint32(asset + 4, true)
64	let colors = view.getUint32(asset + 8, true)
65	
66	let image = new ImageData(width, height)
67	let {data} = image
68	
69	for (let x = 0 ; x < width ; x++)
70	for (let y = 0 ; y < height ; y++)
71	{
72		let o = x + y * width
73		let color = view.getUint8(colors + o)
74		
75		if (color === 0) continue
76		
77		if (color < 0x10)
78		{
79			let ch = color * 0x11
80			data[o * 4 + 0] = ch
81			data[o * 4 + 1] = ch
82			data[o * 4 + 2] = ch
83			data[o * 4 + 3] = 0xFF
84		}
85		else
86		{
87			color -= 0x10
88			let r = rch[Math.floor(color / 40) % 6]
89			let g = gch[Math.floor(color / 5) % 8]
90			let b = bch[Math.floor(color / 1) % 5]
91			
92			data[o * 4 + 0] = r
93			data[o * 4 + 1] = g
94			data[o * 4 + 2] = b
95			data[o * 4 + 3] = 0xFF
96		}
97	}
98	
99	cache.set(asset, await createImageBitmap(image))
100	return asset
101}
102
103let stamp = (x, y, asset, width, height) =>
104{
105	if (width !== canvas.width || height !== canvas.height)
106		Object.assign(canvas, {width, height})
107	
108	context.drawImage(cache.get(asset), x, y)
109}
110
111let invalidate = (data, asset) => cache.delete(asset)
112
113let past = performance.now()
114
115let promise
116let resolve = () => { }
117let tick = () =>
118{
119	let now = performance.now()
120	resolve()
121	promise = new Promise(f => { setTimeout(tick, (100 / 3) + past - now) ; resolve = f })
122	past = now
123}
124
125let imports =
126{
127	env:
128	{
129		mimimi_wasm_texture: createTexture,
130		mimimi_wasm_invalidate: invalidate,
131		mimimi_wasm_stamp: stamp,
132		mimimi_wasm_sync: (width, height) => promise.then(() => Object.assign(canvas, {width, height})),
133		mimimi_wasm_keys: () => left * 2 + right,
134		mimimi_wasm_width: () => innerWidth,
135		mimimi_wasm_height: () => innerHeight,
136	},
137	wasi_snapshot_preview1: {proc_exit: () => { throw new Error("exit called") }},
138}
139
140let response = await fetch("mimimi.wasm")
141let buffer = await response.arrayBuffer()
142let {instance} = await WebAssembly.instantiate(buffer, imports)
143let {memory, _start} = instance.exports
144
145let left = 0
146let right = 0
147
148addEventListener("keydown", ({code}) =>
149{
150	if (code === "ArrowLeft") left = 1
151	if (code === "ArrowRight") right = 1
152	if (code === "KeyA") left = 1
153	if (code === "KeyD") right = 1
154})
155
156addEventListener("keyup", ({code}) =>
157{
158	if (code === "ArrowLeft") left = 0
159	if (code === "ArrowRight") right = 0
160	if (code === "KeyA") left = 0
161	if (code === "KeyD") right = 0
162})
163
164addEventListener("contextmenu", event => event.preventDefault())
165
166addEventListener("pointerdown", event =>
167{
168	if (event.pointerType === "mouse") return
169	if (event.button !== 0) return
170	
171	if (event.offsetX < innerWidth / 2)
172		left = 1
173	else
174		right = 1
175})
176
177addEventListener("pointerup", event =>
178{
179	if (event.pointerType === "mouse") return
180	if (event.button !== 0) return
181	
182	left = 0
183	right = 0
184})
185
186addEventListener("mousedown", ({button}) =>
187{
188	if (button === 0) left = 1
189	if (button === 2) right = 1
190})
191
192addEventListener("mouseup", ({button}) =>
193{
194	if (button === 0) left = 0
195	if (button === 2) right = 0
196})
197
198tick()
199_start()
200
201</script>
202
203<canvas width="512" height="256"></canvas>