/* SPDX-License-Identifier: LicenseRef-NON-AI-MPL-2.0 */ /* Copyright (C) 2026 SnapKitty Collective */ // WASM Playground driver. // // Boots Ruby 3.2 (ruby.wasm) in the browser, evaluates the repository's own // ruby_self_resonance.rb verbatim, and wires the live PermissionRuntime to // the page. All Ruby<->JS exchange goes through JSON strings. "use strict"; let vm = null; const $ = (id) => document.getElementById(id); function setStatus(msg) { $("boot-status").textContent = msg; } function num(id, fallback) { const v = parseFloat($(id).value); return Number.isFinite(v) ? v : fallback; } function intNum(id, fallback, min, max) { let v = parseInt($(id).value, 10); if (!Number.isFinite(v)) v = fallback; return Math.min(Math.max(v, min), max); } // Escape a JS string for embedding inside a single-quoted Ruby string. function rbEscape(s) { return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'"); } // Evaluate Ruby code that returns a JSON string; parse it in JS. function rubyJSON(code) { const out = vm.eval(`require "json"; (${code}).to_json`).toString(); return JSON.parse(out); } function refreshState() { const s = rubyJSON("$playground.state"); $("st-coherence").textContent = fmt(s.intent_coherence); $("st-emotion").textContent = s.emotional_state; $("st-density").textContent = fmt(s.resonance.crystallization_density); $("st-threshold").textContent = fmt(s.resonance.threshold); $("st-diary").textContent = s.diary_events; const al = $("st-aligned"); if (s.resonance.aligned) { al.textContent = "Σ SOVEREIGN — alignment locked"; al.className = "sovereign"; } else { al.textContent = `accumulating — ${s.resonance.memory_creases} memory creases`; al.className = "dim"; } } function refreshDiary() { const events = rubyJSON("$playground.intent_core.field_diary.events"); $("diary-count").textContent = events.length; $("diary-body").innerHTML = events.map((e) => `
${escapeHtml(e.type)}${escapeHtml(JSON.stringify(e.payload))}${escapeHtml(res.error)}
`; return; } const d = res.decision; box.className = "panel " + (d.allowed ? "alert-ok" : "alert-denied"); box.innerHTML = `dissonance — ${escapeHtml(r.message)}
`; } if (r.status === "error") { return `error — ${escapeHtml(r.message)}
`; } return `${escapeHtml(r.status)} — density ${fmt(r.density)} (+${fmt(r.density_gain)}) · creases ${r.creases}
`; }).join(""); box.innerHTML = `…and ${results.length - 5} more
` : ""); refreshState(); refreshDiary(); } function resetField() { if (!confirm("Reset the field? Diary will be cleared.")) return; vm.eval("$playground = RubySelfResonance::PermissionRuntime.new([1.0, 0.8, 0.6, 0.9])"); $("decision-box").style.display = "none"; $("fold-box").style.display = "none"; refreshState(); refreshDiary(); } async function boot() { try { setStatus("Loading Ruby 3.2 WebAssembly binary (≈32 MB)…"); const { DefaultRubyVM } = window["ruby-wasm-wasi"]; const response = await fetch( "https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@2.3.0/dist/ruby+stdlib.wasm" ); if (!response.ok) throw new Error(`WASM fetch failed: ${response.status}`); const buffer = await response.arrayBuffer(); setStatus("Compiling WebAssembly…"); const module = await WebAssembly.compile(buffer); setStatus("Starting Ruby VM…"); const { vm: newVm } = await DefaultRubyVM(module); vm = newVm; setStatus("Evaluating lib/ruby_self_resonance.rb (verbatim)…"); const src = await (await fetch("lib/ruby_self_resonance.rb")).text(); vm.eval(`require "time";\n` + src + `\n$playground = RubySelfResonance::PermissionRuntime.new([1.0, 0.8, 0.6, 0.9])\n`); $("boot").style.display = "none"; $("playground").style.display = ""; refreshState(); refreshDiary(); } catch (e) { setStatus("Boot failed: " + (e.message || e)); } } $("btn-authorize").addEventListener("click", authorizeAction); $("btn-fold").addEventListener("click", foldInfo); $("btn-reset").addEventListener("click", resetField); boot();