mrly.js
2.9 kB · javascript · 96 lines
1import init, * as wasm from '../pkg/mrlydemo.js';2import wasmUrl from '../pkg/mrlydemo_bg.wasm';3import { palette } from '../kit/ui/palette.js';4import { dark, light } from '../kit/ui/theme.js';56export const mrly = wasm;7export { palette, dark, light };89// THEME1011const scheme = typeof matchMedia === 'function' ? matchMedia('(prefers-color-scheme: dark)') : null;1213export function isDark() {14 if (typeof document === 'undefined') return true;15 const set = document.documentElement.dataset.theme;16 return set ? set === 'dark' : Boolean(scheme?.matches);17}1819export function theme() {20 return isDark() ? dark : light;21}2223export const ink = new Proxy({}, { get: (_, key) => theme()[key] });2425export const role = () => [ink.dim, ink.yellow, ink.blue, ink.pink];2627export const plusminus = () => ({ plus: ink.orange, minus: ink.blue, empty: ink.deep });2829function tint() {30 if (typeof wasm.set_theme === 'function') wasm.set_theme(isDark());31}3233export async function ready() {34 const at = wasmUrl.startsWith('.') ? new URL(wasmUrl, import.meta.url) : wasmUrl;35 await init({ module_or_path: at });36 globalThis.mrly = wasm;37 tint();38 window.addEventListener('theme', tint);39 scheme?.addEventListener('change', tint);40 return wasm;41}4243export function rgb(hex) {44 const n = parseInt(hex.slice(1), 16);45 return [(n >> 16) & 255, (n >> 8) & 255, n & 255];46}4748// FLAT4950export function blit(canvas, pixels) {51 canvas.width = pixels.width;52 canvas.height = pixels.height;53 const image = new ImageData(new Uint8ClampedArray(pixels.rgba), pixels.width, pixels.height);54 canvas.getContext('2d').putImageData(image, 0, 0);55}5657export function paint(canvas, grid, on = ink.fg, off = ink.deep) {58 const [w, h] = [grid.width, grid.height];59 const a = rgb(on), b = rgb(off);60 const rgba = new Uint8ClampedArray(w * h * 4);61 for (let i = 0; i < w * h; i++) {62 const c = grid.types[i] ? a : b;63 rgba.set(c, i * 4);64 rgba[i * 4 + 3] = 255;65 }66 canvas.width = w;67 canvas.height = h;68 canvas.getContext('2d').putImageData(new ImageData(rgba, w, h), 0, 0);69}7071// SIGNED7273export function signs(canvas, grid, hues = {}) {74 const [w, h] = [grid.width, grid.height];75 const base = plusminus();76 const ramp = [rgb(hues.plus ?? base.plus), rgb(hues.minus ?? base.minus), rgb(hues.empty ?? base.empty)];77 const rgba = new Uint8ClampedArray(w * h * 4);78 for (let i = 0; i < w * h; i++) {79 rgba.set(ramp[grid.types[i]] ?? ramp[2], i * 4);80 rgba[i * 4 + 3] = 255;81 }82 canvas.width = w;83 canvas.height = h;84 canvas.getContext('2d').putImageData(new ImageData(rgba, w, h), 0, 0);85}8687export function fit(canvas, height) {88 const scale = Math.min(devicePixelRatio || 1, 2);89 const w = canvas.clientWidth;90 canvas.width = w * scale;91 canvas.height = height * scale;92 canvas.style.height = height + 'px';93 const ctx = canvas.getContext('2d');94 ctx.setTransform(scale, 0, 0, scale, 0, 0);95 return [ctx, w, height];96}