///|
extern "js" fn dom_create_canvas() -> JsValue =
  #| () => {
  #|   const canvas = document.createElement("canvas");
  #|   canvas.style.width = "100%";
  #|   canvas.style.height = "100%";
  #|   canvas.style.display = "block";
  #|   canvas.style.cursor = "crosshair";
  #|   document.body.style.margin = "0";
  #|   document.body.style.overflow = "hidden";
  #|   document.body.appendChild(canvas);
  #|   return canvas;
  #| }

///|
extern "js" fn dom_resize_canvas(canvas : JsValue) -> Array[Int] =
  #| (canvas) => {
  #|   const dpr = window.devicePixelRatio || 1;
  #|   const w = window.innerWidth || 800;
  #|   const h = window.innerHeight || 600;
  #|   const width = Math.floor(w * dpr);
  #|   const height = Math.floor(h * dpr);
  #|   if (canvas.width !== width || canvas.height !== height) {
  #|     canvas.width = width;
  #|     canvas.height = height;
  #|     canvas.style.width = w + "px";
  #|     canvas.style.height = h + "px";
  #|   }
  #|   return [canvas.width, canvas.height];
  #| }

///|
extern "js" fn dom_request_animation_frame(cb : (Double) -> Unit) -> Int =
  #| (cb) => window.requestAnimationFrame(cb)

///|
extern "js" fn dom_now_ms() -> Double =
  #| () => (performance && performance.now) ? performance.now() : Date.now()

///|
extern "js" fn input_init(canvas : JsValue) -> Unit =
  #| (canvas) => {
  #|   const prev = window.__moonbit_input;
  #|   const state = {
  #|     keys: Object.create(null),
  #|     buttons: Object.create(null),
  #|     clicks: Object.create(null),
  #|     dx: 0,
  #|     dy: 0,
  #|     fly: prev && typeof prev.fly === "boolean" ? prev.fly : false,
  #|     teleport: false,
  #|     cmds: prev && Array.isArray(prev.cmds) ? prev.cmds : [],
  #|   };
  #|   window.__moonbit_input = state;
  #|   window.addEventListener("keydown", (e) => { state.keys[e.code] = true; });
  #|   window.addEventListener("keyup", (e) => { state.keys[e.code] = false; });
  #|   window.addEventListener("blur", () => {
  #|     state.keys = Object.create(null);
  #|     state.buttons = Object.create(null);
  #|     state.clicks = Object.create(null);
  #|   });
  #|   canvas.addEventListener("mousedown", (e) => {
  #|     if (document.pointerLockElement !== canvas) {
  #|       canvas.requestPointerLock();
  #|     }
  #|     state.buttons[e.button] = true;
  #|     state.clicks[e.button] = true;
  #|   });
  #|   window.addEventListener("mouseup", (e) => { state.buttons[e.button] = false; });
  #|   window.addEventListener("mousemove", (e) => {
  #|     if (document.pointerLockElement === canvas) {
  #|       state.dx += e.movementX || 0;
  #|       state.dy += e.movementY || 0;
  #|     }
  #|   });
  #|   window.addEventListener("contextmenu", (e) => e.preventDefault());
  #|   const btn = document.getElementById("fly-toggle");
  #|   if (btn) {
  #|     btn.textContent = state.fly ? "Fly: On" : "Fly: Off";
  #|     btn.classList.toggle("active", !!state.fly);
  #|   }
  #| }

///|
extern "js" fn input_key(code : String) -> Bool =
  #| (code) => {
  #|   const s = window.__moonbit_input;
  #|   return !!(s && s.keys && s.keys[code]);
  #| }

///|
extern "js" fn input_consume_click(button : Int) -> Bool =
  #| (button) => {
  #|   const s = window.__moonbit_input;
  #|   if (!s || !s.clicks) return false;
  #|   const v = !!s.clicks[button];
  #|   s.clicks[button] = false;
  #|   return v;
  #| }

///|
extern "js" fn input_mouse_dx() -> Double =
  #| () => {
  #|   const s = window.__moonbit_input;
  #|   if (!s) return 0;
  #|   const v = s.dx || 0;
  #|   s.dx = 0;
  #|   return v;
  #| }

///|
extern "js" fn input_mouse_dy() -> Double =
  #| () => {
  #|   const s = window.__moonbit_input;
  #|   if (!s) return 0;
  #|   const v = s.dy || 0;
  #|   s.dy = 0;
  #|   return v;
  #| }

///|
extern "js" fn input_fly_enabled() -> Bool =
  #| () => {
  #|   const s = window.__moonbit_input;
  #|   return !!(s && s.fly);
  #| }

///|
extern "js" fn input_consume_teleport() -> Bool =
  #| () => {
  #|   const s = window.__moonbit_input;
  #|   if (!s) return false;
  #|   const v = !!s.teleport;
  #|   s.teleport = false;
  #|   return v;
  #| }

///|
extern "js" fn input_consume_command() -> Array[Int] =
  #| () => {
  #|   const s = window.__moonbit_input;
  #|   if (!s || !Array.isArray(s.cmds) || s.cmds.length === 0) return [];
  #|   return s.cmds.shift();
  #| }

///|
extern "js" fn dom_init_fly_toggle() -> Unit =
  #| () => {
  #|   const btn = document.getElementById("fly-toggle");
  #|   if (!btn) return;
  #|   const getState = () => {
  #|     let s = window.__moonbit_input;
  #|     if (!s) {
  #|       s = {
  #|         keys: Object.create(null),
  #|         buttons: Object.create(null),
  #|         clicks: Object.create(null),
  #|         dx: 0,
  #|         dy: 0,
  #|         fly: false,
  #|         teleport: false,
  #|         cmds: [],
  #|       };
  #|       window.__moonbit_input = s;
  #|     }
  #|     if (typeof s.fly !== "boolean") s.fly = false;
  #|     return s;
  #|   };
  #|   const update = (s) => {
  #|     const on = !!s.fly;
  #|     btn.textContent = on ? "Fly: On" : "Fly: Off";
  #|     btn.classList.toggle("active", on);
  #|   };
  #|   update(getState());
  #|   btn.addEventListener("click", (e) => {
  #|     e.preventDefault();
  #|     const s = getState();
  #|     s.fly = !s.fly;
  #|     update(s);
  #|   });
  #| }

///|
extern "js" fn dom_init_random_teleport() -> Unit =
  #| () => {
  #|   const btn = document.getElementById("teleport-random");
  #|   if (!btn) return;
  #|   const getState = () => {
  #|     let s = window.__moonbit_input;
  #|     if (!s) {
  #|       s = {
  #|         keys: Object.create(null),
  #|         buttons: Object.create(null),
  #|         clicks: Object.create(null),
  #|         dx: 0,
  #|         dy: 0,
  #|         fly: false,
  #|         teleport: false,
  #|         cmds: [],
  #|       };
  #|       window.__moonbit_input = s;
  #|     }
  #|     if (typeof s.teleport !== "boolean") s.teleport = false;
  #|     return s;
  #|   };
  #|   btn.addEventListener("click", (e) => {
  #|     e.preventDefault();
  #|     const s = getState();
  #|     s.teleport = true;
  #|     btn.classList.add("active");
  #|     setTimeout(() => btn.classList.remove("active"), 120);
  #|   });
  #| }

///|
extern "js" fn dom_init_command_input() -> Unit =
  #| () => {
  #|   const input = document.getElementById("cmd-input");
  #|   const btn = document.getElementById("cmd-run");
  #|   if (!input || !btn) return;
  #|   const getState = () => {
  #|     let s = window.__moonbit_input;
  #|     if (!s) {
  #|       s = {
  #|         keys: Object.create(null),
  #|         buttons: Object.create(null),
  #|         clicks: Object.create(null),
  #|         dx: 0,
  #|         dy: 0,
  #|         fly: false,
  #|         teleport: false,
  #|         cmds: [],
  #|       };
  #|       window.__moonbit_input = s;
  #|     }
  #|     if (!Array.isArray(s.cmds)) s.cmds = [];
  #|     return s;
  #|   };
  #|   const parseInts = (parts) => {
  #|     const out = [];
  #|     for (let i = 0; i < parts.length; i++) {
  #|       const v = parseInt(parts[i], 10);
  #|       if (Number.isFinite(v)) out.push(v);
  #|     }
  #|     return out;
  #|   };
  #|   const submit = () => {
  #|     const text = input.value.trim();
  #|     if (!text) return;
  #|     const parts = text.split(/\s+/);
  #|     const cmd = parts[0].toLowerCase();
  #|     const nums = parseInts(parts.slice(1));
  #|     let payload = null;
  #|     if (cmd === "tp") {
  #|       if (nums.length >= 3) {
  #|         payload = [1, nums[0], nums[1], nums[2]];
  #|       } else if (nums.length >= 2) {
  #|         payload = [2, nums[0], nums[1]];
  #|       }
  #|     } else if (cmd === "look") {
  #|       if (nums.length >= 2) {
  #|         payload = [3, nums[0], nums[1]];
  #|       }
  #|     }
  #|     if (payload) {
  #|       const s = getState();
  #|       s.cmds.push(payload);
  #|       input.value = "";
  #|     }
  #|   };
  #|   btn.addEventListener("click", (e) => {
  #|     e.preventDefault();
  #|     submit();
  #|   });
  #|   input.addEventListener("keydown", (e) => {
  #|     if (e.key === "Enter") {
  #|       e.preventDefault();
  #|       submit();
  #|     }
  #|   });
  #| }

///|
extern "js" fn dom_set_hotbar(selected : Int) -> Unit =
  #| (selected) => {
  #|   const bar = document.getElementById("hotbar");
  #|   if (!bar) return;
  #|   const slots = bar.querySelectorAll(".slot");
  #|   for (let i = 0; i < slots.length; i++) {
  #|     if (i === selected) {
  #|       slots[i].classList.add("active");
  #|     } else {
  #|       slots[i].classList.remove("active");
  #|     }
  #|   }
  #| }

///|
extern "js" fn dom_set_loading(progress : Double) -> Unit =
  #| (progress) => {
  #|   const el = document.getElementById("loading");
  #|   if (!el) return;
  #|   const text = el.querySelector(".loading-text");
  #|   const fill = el.querySelector(".bar-fill");
  #|   const p = Math.max(0, Math.min(1, progress || 0));
  #|   if (p >= 1) {
  #|     el.style.display = "none";
  #|     return;
  #|   }
  #|   el.style.display = "flex";
  #|   const pct = Math.round(p * 100);
  #|   if (text) text.textContent = `Loading ${pct}%`;
  #|   if (fill) fill.style.width = `${pct}%`;
  #| }

///|
extern "js" fn dom_create_atlas() -> JsValue =
  #| () => {
  #|   const tile = 16;
  #|   const cols = 4;
  #|   const rows = 4;
  #|   const canvas = document.createElement("canvas");
  #|   canvas.width = tile * cols;
  #|   canvas.height = tile * rows;
  #|   const ctx = canvas.getContext("2d");
  #|   ctx.imageSmoothingEnabled = false;
  #|   function rowsFrom(str) {
  #|     return str.trim().split("\n").map((line) => line.trim());
  #|   }
  #|   function drawTile(tx, ty, palette, rows) {
  #|     const x0 = tx * tile;
  #|     const y0 = ty * tile;
  #|     for (let y = 0; y < tile; y++) {
  #|       const row = rows[y];
  #|       for (let x = 0; x < tile; x++) {
  #|         const ch = row[x];
  #|         if (ch === ".") continue;
  #|         const color = palette[ch];
  #|         if (!color) continue;
  #|         ctx.fillStyle = color;
  #|         ctx.fillRect(x0 + x, y0 + y, 1, 1);
  #|       }
  #|     }
  #|   }
  #|   const grassPalette = {
  #|     a: "#5fb84a",
  #|     b: "#56aa42",
  #|     c: "#4a9637",
  #|     d: "#6ed05a",
  #|   };
  #|   const dirtPalette = {
  #|     "1": "#8a5a2b",
  #|     "2": "#7a4d24",
  #|     "3": "#9a6431",
  #|     "4": "#6d4420",
  #|   };
  #|   const stonePalette = {
  #|     a: "#8b8d90",
  #|     b: "#7c7e82",
  #|     c: "#9a9da1",
  #|     d: "#6f7175",
  #|   };
  #|   const sandPalette = {
  #|     a: "#d9c48a",
  #|     b: "#cfb87c",
  #|     c: "#e2cf95",
  #|     d: "#c4ad6f",
  #|   };
  #|   const waterPalette = {
  #|     a: "rgba(70,125,210,0.6)",
  #|     b: "rgba(58,110,195,0.6)",
  #|     c: "rgba(80,140,220,0.6)",
  #|     d: "rgba(95,155,235,0.45)",
  #|   };
  #|   const woodTopPalette = {
  #|     a: "#d0a36a",
  #|     b: "#c08a52",
  #|     c: "#a97443",
  #|     d: "#8c5e32",
  #|   };
  #|   const woodSidePalette = {
  #|     a: "#c79253",
  #|     b: "#b17b45",
  #|     c: "#9e6a39",
  #|     d: "#7f532c",
  #|   };
  #|   const leavesPalette = {
  #|     a: "#4aa34a",
  #|     b: "#3f8f3f",
  #|     c: "#5cb85c",
  #|     d: "#357a35",
  #|   };
  #|   const bedrockPalette = {
  #|     a: "#3b3b3b",
  #|     b: "#2f2f2f",
  #|     c: "#4a4a4a",
  #|     d: "#1f1f1f",
  #|   };
  #|   const planksPalette = {
  #|     a: "#cfa26a",
  #|     b: "#b9874f",
  #|     c: "#a07040",
  #|     d: "#8d5c33",
  #|   };
  #|   const brickPalette = {
  #|     a: "#b65a4a",
  #|     b: "#9e483b",
  #|     c: "#c76b58",
  #|     m: "#8a7b6f",
  #|   };
  #|   const cobblePalette = {
  #|     a: "#8d8d8d",
  #|     b: "#7a7a7a",
  #|     c: "#9c9c9c",
  #|     d: "#6a6a6a",
  #|   };
  #|   const gravelPalette = {
  #|     a: "#8a887f",
  #|     b: "#7a786f",
  #|     c: "#94928a",
  #|     d: "#6b6861",
  #|   };
  #|   const clayPalette = {
  #|     a: "#8a94a6",
  #|     b: "#7c8697",
  #|     c: "#9aa4b6",
  #|   };
  #|   const snowPalette = {
  #|     a: "#f7fbff",
  #|     b: "#e5edf6",
  #|     c: "#d7e0ea",
  #|   };
  #|   const grassTopRows = rowsFrom(`
  #|     abacbabcabacbabc
  #|     bacabdbcbacabdbc
  #|     acbbacabacbbacab
  #|     baccdbabbaccdbab
  #|     cbacbaccabacbacc
  #|     abacbabcabacbabc
  #|     bacabbacbacabbac
  #|     acbbacdaacbbacda
  #|     abacbabcabacbabc
  #|     bacabdbcbacabdbc
  #|     acbbacabacbbacab
  #|     baccdbabbaccdbab
  #|     cbacbaccabacbacc
  #|     abacbabcabacbabc
  #|     bacabbacbacabbac
  #|     acbbacdaacbbacda
  #|   `);
  #|   const dirtRows = rowsFrom(`
  #|     1213212312132123
  #|     2312213223122132
  #|     1322131213221312
  #|     2133122121331221
  #|     3213213332132133
  #|     1213212312132123
  #|     2131221321312213
  #|     1322132113221321
  #|     2213431222134312
  #|     3122132231221322
  #|     1213212312132123
  #|     2312213223122132
  #|     1322131213221312
  #|     2133122121331221
  #|     3213213332132133
  #|     1213212312132123
  #|   `);
  #|   const grassSideRows = grassTopRows.slice(0, 4).concat(dirtRows.slice(4));
  #|   const stoneRows = rowsFrom(`
  #|     abbcacbbabbcacbb
  #|     bbacabbcbbacabbc
  #|     cabbabdccabbabdc
  #|     abbdbcababbdbcab
  #|     bcabbabcbcabbabc
  #|     cabbcabbcabbcabb
  #|     abbcacbbabbcacbb
  #|     bbacabbcbbacabbc
  #|     cabbabdccabbabdc
  #|     abbdbcababbdbcab
  #|     bcabbabcbcabbabc
  #|     cabbcabbcabbcabb
  #|     abbcacbbabbcacbb
  #|     bbacabbcbbacabbc
  #|     cabbabdccabbabdc
  #|     abbdbcababbdbcab
  #|   `);
  #|   const sandRows = rowsFrom(`
  #|     aacbbacaaacbbaca
  #|     bcaaabcabcaaabca
  #|     caaabccacaaabcca
  #|     acbbacaaacbbacaa
  #|     bcaabcaabcaabcaa
  #|     aacbbacaaacbbaca
  #|     bcaaabcabcaaabca
  #|     caaabccacaaabcca
  #|     acbbacaaacbbacaa
  #|     bcaabcaabcaabcaa
  #|     aacbbacaaacbbaca
  #|     bcaaabcabcaaabca
  #|     caaabccacaaabcca
  #|     acbbacaaacbbacaa
  #|     bcaabcaabcaabcaa
  #|     aacbbacaaacbbaca
  #|   `);
  #|   const waterRows = rowsFrom(`
  #|     aabccbaaaabccbaa
  #|     abbccbcaabbccbca
  #|     bccabccbbccabccb
  #|     ccbaabccccbaabcc
  #|     abccbaababccbaab
  #|     bbccaabbbbccaabb
  #|     ccbbaaccccbbaacc
  #|     baccbbacbaccbbac
  #|     aabccbaaaabccbaa
  #|     abbccbcaabbccbca
  #|     bccabccbbccabccb
  #|     ccbaabccccbaabcc
  #|     abccbaababccbaab
  #|     bbccaabbbbccaabb
  #|     ccbbaaccccbbaacc
  #|     baccbbacbaccbbac
  #|   `);
  #|   const woodTopRows = rowsFrom(`
  #|     cccccccccccccccc
  #|     cbbbbbbbbbbbbbbc
  #|     cbaaaaaaaaaaaabc
  #|     cbabaaaaaaaababc
  #|     cbababaaaabababc
  #|     cbababddddbababc
  #|     cbababddddbababc
  #|     cbababddcdbababc
  #|     cbababdcdcbababc
  #|     cbababddcdbababc
  #|     cbababddddbababc
  #|     cbababaaaabababc
  #|     cbabaaaaaaaababc
  #|     cbaaaaaaaaaaaabc
  #|     cbbbbbbbbbbbbbbc
  #|     cccccccccccccccc
  #|   `);
  #|   const woodSideRows = rowsFrom(`
  #|     aabbbbaaaabbbbaa
  #|     aabbbbaaaabbbbaa
  #|     aabbbbaaaabbbbaa
  #|     aabbbbaaaabbbbaa
  #|     aabbbbaaaabbbbaa
  #|     aabbbbaadabbbbaa
  #|     aabbbbaaaabbbbaa
  #|     aabbbbadaabbbbaa
  #|     aabbbbaaaabbbbaa
  #|     aabbbbaaaabbbbaa
  #|     aabbbbaaaabbbbaa
  #|     aabbbbaadabbbbaa
  #|     aabbbbaaaabbbbaa
  #|     aabbbbaaaabbbbaa
  #|     aabbbbaaaabbbbaa
  #|     aabbbbaaaabbbbaa
  #|   `);
  #|   const leavesRows = rowsFrom(`
  #|     aabac..bacabacaa
  #|     abbacabb..bacaba
  #|     bacab..abacabbac
  #|     acabbac..abacaba
  #|     baca..abbacabbac
  #|     abacabbac..abbac
  #|     bacabbac..abacaa
  #|     acaba..bacabbaca
  #|     aabac..bacabacaa
  #|     abbacabb..bacaba
  #|     bacab..abacabbac
  #|     acabbac..abacaba
  #|     baca..abbacabbac
  #|     abacabbac..abbac
  #|     bacabbac..abacaa
  #|     acaba..bacabbaca
  #|   `);
  #|   const bedrockRows = rowsFrom(`
  #|     abcbadbbabcbadbb
  #|     bbacbbdabbacbbda
  #|     cbabdbaccbabdbac
  #|     bacbabadbacbabad
  #|     abcbadbbabcbadbb
  #|     bbacbbdabbacbbda
  #|     cbabdbaccbabdbac
  #|     bacbabadbacbabad
  #|     abcbadbbabcbadbb
  #|     bbacbbdabbacbbda
  #|     cbabdbaccbabdbac
  #|     bacbabadbacbabad
  #|     abcbadbbabcbadbb
  #|     bbacbbdabbacbbda
  #|     cbabdbaccbabdbac
  #|     bacbabadbacbabad
  #|   `);
  #|   const planksRows = rowsFrom(`
  #|     cccccccccccccccc
  #|     aaabbaaabaaabbaa
  #|     aabbaaabbaaabbaa
  #|     aaabbaaabaaabbaa
  #|     cccccccccccccccc
  #|     aabbaaabbaaabbaa
  #|     aaabbaaadaaabbaa
  #|     aabbaaabbaaabbaa
  #|     cccccccccccccccc
  #|     aaabbaaabaaabbaa
  #|     aabbaaabbaaabbaa
  #|     aaabbaaabaaabbaa
  #|     cccccccccccccccc
  #|     aabbaaabbaaabbaa
  #|     aaabbaaabaaabbaa
  #|     aabbaaabbaaabbaa
  #|   `);
  #|   const brickRows = rowsFrom(`
  #|     mmmmmmmmmmmmmmmm
  #|     mcaamabamaacmbaa
  #|     mbacmcaamabamaac
  #|     mcaamabamaacmbaa
  #|     mmmmmmmmmmmmmmmm
  #|     camaabmcaamabama
  #|     bamcacmaabmcaamb
  #|     camaabmcaamabama
  #|     mmmmmmmmmmmmmmmm
  #|     mcaamabamaacmbaa
  #|     mbacmcaamabamaac
  #|     mcaamabamaacmbaa
  #|     mmmmmmmmmmmmmmmm
  #|     camaabmcaamabama
  #|     bamcacmaabmcaamb
  #|     camaabmcaamabama
  #|   `);
  #|   const cobbleRows = rowsFrom(`
  #|     abccabbbabccabbb
  #|     bccabbccbccabbcc
  #|     cabbccaacabbccaa
  #|     abbccabbabbccabb
  #|     bccabbbdbccabbbd
  #|     cabbccabcabbccab
  #|     abccabbbabccabbb
  #|     bccabbccbccabbcc
  #|     cabbccaacabbccaa
  #|     abbccabbabbccabb
  #|     bccabbbdbccabbbd
  #|     cabbccabcabbccab
  #|     abccabbbabccabbb
  #|     bccabbccbccabbcc
  #|     cabbccaacabbccaa
  #|     abbccabbabbccabb
  #|   `);
  #|   const gravelRows = rowsFrom(`
  #|     aabbccabaabbccab
  #|     bbacccbabbacccba
  #|     acbbacdcacbbacdc
  #|     bccababcbccababc
  #|     abbccabaabbccaba
  #|     ccbabccaccbabcca
  #|     bacbacbbbacbacbb
  #|     cabbacbccabbacbc
  #|     aabbccabaabbccab
  #|     bbacccbabbacccba
  #|     acbbacdcacbbacdc
  #|     bccababcbccababc
  #|     abbccabaabbccaba
  #|     ccbabccaccbabcca
  #|     bacbacbbbacbacbb
  #|     cabbacbccabbacbc
  #|   `);
  #|   const clayRows = rowsFrom(`
  #|     aabaccaaaabaccaa
  #|     baccaabbbaccaabb
  #|     accaaabbaccaaabb
  #|     caaabbaccaaabbac
  #|     aabaccaaaabaccaa
  #|     baccaabbbaccaabb
  #|     accaaabbaccaaabb
  #|     caaabbaccaaabbac
  #|     aabaccaaaabaccaa
  #|     baccaabbbaccaabb
  #|     accaaabbaccaaabb
  #|     caaabbaccaaabbac
  #|     aabaccaaaabaccaa
  #|     baccaabbbaccaabb
  #|     accaaabbaccaaabb
  #|     caaabbaccaaabbac
  #|   `);
  #|   const snowRows = rowsFrom(`
  #|     aaaaaaaaaaaaaaaa
  #|     aaabaaaaaaabaaaa
  #|     aabaaabaaabaaaba
  #|     aaaaacaaaaacaaaa
  #|     aaabaaaaaaabaaaa
  #|     aabaaabaaabaaaba
  #|     aaaaacaaaaacaaaa
  #|     aaabaaaaaaabaaaa
  #|     aabaaabaaabaaaba
  #|     aaaaacaaaaacaaaa
  #|     aaabaaaaaaabaaaa
  #|     aabaaabaaabaaaba
  #|     aaaaacaaaaacaaaa
  #|     aaabaaaaaaabaaaa
  #|     aabaaabaaabaaaba
  #|     aaaaaaaaaaaaaaaa
  #|   `);
  #|   const grassSidePalette = Object.assign({}, grassPalette, dirtPalette);
  #|   drawTile(0, 0, grassPalette, grassTopRows);
  #|   drawTile(1, 0, grassSidePalette, grassSideRows);
  #|   drawTile(2, 0, dirtPalette, dirtRows);
  #|   drawTile(3, 0, stonePalette, stoneRows);
  #|   drawTile(0, 1, sandPalette, sandRows);
  #|   drawTile(1, 1, waterPalette, waterRows);
  #|   drawTile(2, 1, woodTopPalette, woodTopRows);
  #|   drawTile(3, 1, woodSidePalette, woodSideRows);
  #|   drawTile(0, 2, leavesPalette, leavesRows);
  #|   drawTile(1, 2, bedrockPalette, bedrockRows);
  #|   drawTile(2, 2, planksPalette, planksRows);
  #|   drawTile(3, 2, brickPalette, brickRows);
  #|   drawTile(0, 3, cobblePalette, cobbleRows);
  #|   drawTile(1, 3, gravelPalette, gravelRows);
  #|   drawTile(2, 3, clayPalette, clayRows);
  #|   drawTile(3, 3, snowPalette, snowRows);
  #|   window.__atlas = canvas;
  #|   return canvas;
  #| }