window.onerror = function (message, source, lineno, colno, error) { if (window.outf) window.outf(`[JS Error] ${message} at ${source}:${lineno}:${colno}\n`); return false; }; var $builtinmodule = function (name) { var mod = {}; var lc_instance = null; var python_callbacks = {}; function toJS(obj) { if (obj === undefined || obj === null) return obj; if (obj instanceof Sk.builtin.int_ || obj instanceof Sk.builtin.float_) { return Sk.ffi.remapToJs(obj); } if (obj instanceof Sk.builtin.str) return obj.v; if (obj instanceof Sk.builtin.bool) return obj.v; if (obj instanceof Sk.builtin.list || obj instanceof Sk.builtin.tuple || obj instanceof Sk.builtin.dict) { return Sk.ffi.remapToJs(obj); } return obj; } function toPy(obj) { if (obj === undefined || obj === null) return Sk.builtin.none.none$; if (typeof obj === 'number') { return (obj % 1 === 0) ? new Sk.builtin.int_(obj) : new Sk.builtin.float_(obj); } if (typeof obj === 'string') return new Sk.builtin.str(obj); if (typeof obj === 'boolean') return obj ? Sk.builtin.bool.true$ : Sk.builtin.bool.false$; if (Array.isArray(obj)) return new Sk.builtin.list(obj.map(toPy)); return obj; } function makePyCallback(pyFunc) { if (!pyFunc || pyFunc === Sk.builtin.none.none$) return null; return function (...args) { var pyArgs = args.map(toPy); return Sk.misceval.callsimArray(pyFunc, pyArgs); }; } function getDictItem(skDict, keyStr) { if (!skDict || !(skDict instanceof Sk.builtin.dict)) return null; const key = new Sk.builtin.str(keyStr); return skDict.mp$lookup(key); } mod.start = new Sk.builtin.func(function (settings) { let jsSettings = {}; var loopInit = null; var loopUpdate = null; var loopDraw = null; var loopResized = null; var loopTap = null; var loopUntap = null; var loopTapping = null; var loopTapped = null; if (settings && settings !== Sk.builtin.none.none$) { jsSettings = toJS(settings); if (settings instanceof Sk.builtin.dict) { var loopDict = getDictItem(settings, 'loop'); if (loopDict && loopDict instanceof Sk.builtin.dict) { loopInit = getDictItem(loopDict, 'init'); loopUpdate = getDictItem(loopDict, 'update'); loopDraw = getDictItem(loopDict, 'draw'); loopResized = getDictItem(loopDict, 'resized'); loopTap = getDictItem(loopDict, 'tap'); loopUntap = getDictItem(loopDict, 'untap'); loopTapping = getDictItem(loopDict, 'tapping'); loopTapped = getDictItem(loopDict, 'tapped'); } } } if (!jsSettings.canvas) jsSettings.canvas = '#canvas'; const canvasEl = document.querySelector(jsSettings.canvas); if (canvasEl) { const rect = canvasEl.getBoundingClientRect(); canvasEl.width = rect.width || canvasEl.clientWidth; canvasEl.height = rect.height || canvasEl.clientHeight; jsSettings.width = Math.floor(canvasEl.clientWidth); jsSettings.height = Math.floor(canvasEl.clientHeight); jsSettings.canvas = canvasEl; jsSettings.fullscreen = false; jsSettings.autoscale = false; } if (jsSettings.autoscale === undefined) jsSettings.autoscale = false; var jsLoop = jsSettings.loop || {}; python_callbacks = { init: loopInit || jsLoop.init, update: loopUpdate || jsLoop.update, draw: loopDraw || jsLoop.draw, resized: loopResized || jsLoop.resized, tap: loopTap || jsLoop.tap, untap: loopUntap || jsLoop.untap, tapping: loopTapping || jsLoop.tapping, tapped: loopTapped || jsLoop.tapped }; jsSettings.loop = { init: python_callbacks.init ? makePyCallbackNoArgs(python_callbacks.init) : null, update: python_callbacks.update ? makePyCallbackNoArgs(python_callbacks.update) : null, draw: python_callbacks.draw ? makeSafePyCallbackNoArgs(python_callbacks.draw) : null, resized: python_callbacks.resized ? makePyCallback(python_callbacks.resized) : null, tap: python_callbacks.tap ? makePyCallbackTapArgs(python_callbacks.tap) : null, untap: python_callbacks.untap ? makePyCallbackTapArgs(python_callbacks.untap) : null, tapping: python_callbacks.tapping ? makePyCallbackTapArgs(python_callbacks.tapping) : null, tapped: python_callbacks.tapped ? makePyCallbackTapArgs(python_callbacks.tapped) : null }; if (typeof litecanvas === 'undefined') { throw new Sk.builtin.ImportError("litecanvas library not found."); } try { lc_instance = litecanvas(jsSettings); window.__lc_instance = lc_instance; } catch (e) { if (window.outf) window.outf(`[litecanvas] Error: ${e}\n`); throw e; } return Sk.builtin.none.none$; }); var current_dt = 0; function makeSafePyCallbackNoArgs(pyFunc) { if (!pyFunc || pyFunc === Sk.builtin.none.none$) return null; return function (dt) { if (typeof dt === 'number') current_dt = dt; try { return Sk.misceval.callsimArray(pyFunc, []); } catch (e) { if (window.outf) window.outf(`[Error] ${e}\n`); if (lc_instance) lc_instance.pause(); throw e; } }; } function makePyCallbackNoArgs(pyFunc) { if (!pyFunc || pyFunc === Sk.builtin.none.none$) return null; return function (dt) { if (typeof dt === 'number') current_dt = dt; return Sk.misceval.callsimArray(pyFunc, []); }; } function makePyCallbackTapArgs(pyFunc) { if (!pyFunc || pyFunc === Sk.builtin.none.none$) return null; return function (x, y, id) { const el = document.getElementById('canvas'); let lx = x; let ly = y; if (el) { const rect = el.getBoundingClientRect(); // Map from window coordinates to canvas local coordinates lx = (x - rect.left) * (el.width / rect.width); ly = (y - rect.top) * (el.height / rect.height); } var pyArgs = [lx, ly, id].map(toPy); return Sk.misceval.callsimArray(pyFunc, pyArgs); }; } Object.defineProperty(mod, 'T', { get: function () { return toPy(lc_instance ? lc_instance.T : (window.T || 0)); } }); Object.defineProperty(mod, 'W', { get: function () { return toPy(lc_instance ? lc_instance.W : (window.W || 0)); } }); Object.defineProperty(mod, 'H', { get: function () { return toPy(lc_instance ? lc_instance.H : (window.H || 0)); } }); Object.defineProperty(mod, 'DT', { get: function () { if (lc_instance && lc_instance.dt !== undefined) return toPy(lc_instance.dt); return toPy(current_dt); } }); Object.defineProperty(mod, 'MX', { get: function () { let mx = lc_instance ? lc_instance.MX : (window.MX || -1); const el = document.getElementById('canvas'); if (!el || mx === -1) return toPy(mx); const r = el.getBoundingClientRect(); return toPy((mx - r.left) * (el.width / r.width)); } }); Object.defineProperty(mod, 'MY', { get: function () { let my = lc_instance ? lc_instance.MY : (window.MY || -1); const el = document.getElementById('canvas'); if (!el || my === -1) return toPy(my); const r = el.getBoundingClientRect(); return toPy((my - r.top) * (el.height / r.height)); } }); Object.defineProperty(mod, 'CENTERX', { get: function () { if (lc_instance && lc_instance.CENTERX !== undefined) return toPy(lc_instance.CENTERX); if (window.CENTERX !== undefined) return toPy(window.CENTERX); let w = lc_instance ? lc_instance.W : (window.W || 0); return toPy(w / 2); } }); Object.defineProperty(mod, 'CENTERY', { get: function () { if (lc_instance && lc_instance.CENTERY !== undefined) return toPy(lc_instance.CENTERY); if (window.CENTERY !== undefined) return toPy(window.CENTERY); let h = lc_instance ? lc_instance.H : (window.H || 0); return toPy(h / 2); } }); mod.PI = toPy(Math.PI); mod.TWO_PI = toPy(Math.PI * 2); mod.HALF_PI = toPy(Math.PI / 2); mod.cls = new Sk.builtin.func((c) => { cls(c !== undefined ? toJS(c) : undefined); return Sk.builtin.none.none$; }); mod.rectfill = new Sk.builtin.func((x, y, w, h, c) => { rectfill(toJS(x), toJS(y), toJS(w), toJS(h), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); mod.rect = new Sk.builtin.func((x, y, w, h, c) => { rect(toJS(x), toJS(y), toJS(w), toJS(h), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); mod.circfill = new Sk.builtin.func((x, y, r, c) => { circfill(toJS(x), toJS(y), toJS(r), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); mod.circ = new Sk.builtin.func((x, y, r, c) => { circ(toJS(x), toJS(y), toJS(r), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); mod.text = new Sk.builtin.func((x, y, t, c, s) => { text(toJS(x), toJS(y), toJS(t), c !== undefined ? toJS(c) : 3, s !== undefined ? toJS(s) : 'normal'); return Sk.builtin.none.none$; }); mod.textsize = new Sk.builtin.func((s) => { textsize(toJS(s)); return Sk.builtin.none.none$; }); mod.textalign = new Sk.builtin.func((h, v) => { textalign(toJS(h), v !== undefined ? toJS(v) : undefined); return Sk.builtin.none.none$; }); mod.ovalfill = new Sk.builtin.func((x, y, rx, ry, c) => { ovalfill(toJS(x), toJS(y), toJS(rx), toJS(ry), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); mod.oval = new Sk.builtin.func((x, y, rx, ry, c) => { oval(toJS(x), toJS(y), toJS(rx), toJS(ry), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); mod.line = new Sk.builtin.func((x1, y1, x2, y2, c) => { line(toJS(x1), toJS(y1), toJS(x2), toJS(y2), c !== undefined ? toJS(c) : 0); return Sk.builtin.none.none$; }); mod.linewidth = new Sk.builtin.func((v) => { linewidth(toJS(v)); return Sk.builtin.none.none$; }); mod.push = new Sk.builtin.func(() => { push(); return Sk.builtin.none.none$; }); mod.pop = new Sk.builtin.func(() => { pop(); return Sk.builtin.none.none$; }); mod.translate = new Sk.builtin.func((x, y) => { translate(toJS(x), toJS(y)); return Sk.builtin.none.none$; }); mod.scale = new Sk.builtin.func((x, y) => { window.scale(toJS(x), y !== undefined ? toJS(y) : undefined); return Sk.builtin.none.none$; }); mod.rotate = new Sk.builtin.func((r) => { rotate(toJS(r)); return Sk.builtin.none.none$; }); mod.alpha = new Sk.builtin.func((v) => { alpha(toJS(v)); return Sk.builtin.none.none$; }); mod.fill = new Sk.builtin.func((c) => { fill(toJS(c)); return Sk.builtin.none.none$; }); mod.stroke = new Sk.builtin.func((c) => { window.stroke(toJS(c)); return Sk.builtin.none.none$; }); mod.sfx = new Sk.builtin.func((p, ps, vf) => { var r = sfx(toJS(p), ps ? toJS(ps) : 0, vf ? toJS(vf) : 1); return r ? toPy(r) : Sk.builtin.bool.false$; }); mod.volume = new Sk.builtin.func((v) => { volume(toJS(v)); return Sk.builtin.none.none$; }); mod.iskeydown = new Sk.builtin.func((k) => toPy(iskeydown(k ? toJS(k) : undefined))); mod.iskeypressed = new Sk.builtin.func((k) => toPy(iskeypressed(k ? toJS(k) : undefined))); mod.rand = new Sk.builtin.func((mn, mx) => toPy(rand(mn ? toJS(mn) : 0, mx ? toJS(mx) : 1))); mod.randi = new Sk.builtin.func((mn, mx) => toPy(randi(mn ? toJS(mn) : 0, mx ? toJS(mx) : 1))); mod.rseed = new Sk.builtin.func((s) => { seed(toJS(s)); return Sk.builtin.none.none$; }); mod.sin = new Sk.builtin.func((a) => toPy(Math.sin(toJS(a)))); mod.cos = new Sk.builtin.func((a) => toPy(Math.cos(toJS(a)))); mod.abs = new Sk.builtin.func((n) => toPy(Math.abs(toJS(n)))); mod.sqrt = new Sk.builtin.func((n) => toPy(Math.sqrt(toJS(n)))); mod.pause = new Sk.builtin.func(() => { pause(); return Sk.builtin.none.none$; }); mod.resume = new Sk.builtin.func(() => { resume(); return Sk.builtin.none.none$; }); return mod; };