Mirai's Miscellaneous Misadventures

M52 / 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 rch = [0x11, 0x44, 0x77, 0x99, 0xCC, 0xFF]
51let gch = [0x11, 0x33, 0x55, 0x77, 0x99, 0xBB, 0xDD, 0xFF]
52let bch = [0x22, 0x55, 0x88, 0xBB, 0xEE]
53
54let show = async (width, height, colors) =>
55{
56	let view = new DataView(memory.buffer)
57	
58	if (colors < 0) colors += 0x10000
59	
60	let image = new ImageData(width, height)
61	let {data} = image
62	
63	for (let x = 0 ; x < width ; x++)
64	for (let y = 0 ; y < height ; y++)
65	{
66		let o = x + y * width
67		let color = view.getUint8(colors + o)
68		
69		if (color === 0) continue
70		
71		if (color < 0x10)
72		{
73			let ch = color * 0x11
74			data[o * 4 + 0] = ch
75			data[o * 4 + 1] = ch
76			data[o * 4 + 2] = ch
77			data[o * 4 + 3] = 0xFF
78		}
79		else
80		{
81			color -= 0x10
82			let r = rch[Math.floor(color / 40) % 6]
83			let g = gch[Math.floor(color / 5) % 8]
84			let b = bch[Math.floor(color / 1) % 5]
85			
86			data[o * 4 + 0] = r
87			data[o * 4 + 1] = g
88			data[o * 4 + 2] = b
89			data[o * 4 + 3] = 0xFF
90		}
91	}
92	
93	canvas.width = width
94	canvas.height = height
95	context.putImageData(image, 0, 0)
96}
97
98let past = performance.now()
99
100let promise
101let resolve = () => { }
102let tick = () =>
103{
104	let now = performance.now()
105	resolve()
106	promise = new Promise(f => { setTimeout(tick, (100 / 3) + past - now) ; resolve = f })
107	past = now
108}
109
110let imports =
111{
112	env:
113	{
114		mimimi_wasm_sync: (width, height, colors) => promise.then(show(width, height, colors)),
115		mimimi_wasm_keys: () => left * 2 + right,
116		mimimi_wasm_width: () => innerWidth,
117		mimimi_wasm_height: () => innerHeight,
118		logx: console.log,
119	},
120	wasi_snapshot_preview1: {proc_exit: () => { throw new Error("exit called") }},
121}
122
123let response = await fetch("mimimi.wasm")
124let buffer = await response.arrayBuffer()
125let {instance} = await WebAssembly.instantiate(buffer, imports)
126let {memory, _start} = instance.exports
127
128let left = 0
129let right = 0
130
131addEventListener("keydown", ({code}) =>
132{
133	if (code === "ArrowLeft") left = 1
134	if (code === "ArrowRight") right = 1
135	if (code === "KeyA") left = 1
136	if (code === "KeyD") right = 1
137})
138
139addEventListener("keyup", ({code}) =>
140{
141	if (code === "ArrowLeft") left = 0
142	if (code === "ArrowRight") right = 0
143	if (code === "KeyA") left = 0
144	if (code === "KeyD") right = 0
145})
146
147addEventListener("contextmenu", event => event.preventDefault())
148
149addEventListener("pointerdown", event =>
150{
151	if (event.pointerType === "mouse") return
152	if (event.button !== 0) return
153	
154	if (event.offsetX < innerWidth / 2)
155		left = 1
156	else
157		right = 1
158})
159
160addEventListener("pointerup", event =>
161{
162	if (event.pointerType === "mouse") return
163	if (event.button !== 0) return
164	
165	left = 0
166	right = 0
167})
168
169addEventListener("mousedown", ({button}) =>
170{
171	if (button === 0) left = 1
172	if (button === 2) right = 1
173})
174
175addEventListener("mouseup", ({button}) =>
176{
177	if (button === 0) left = 0
178	if (button === 2) right = 0
179})
180
181tick()
182_start()
183
184</script>
185
186<canvas width="512" height="256"></canvas>