-
main.py
-
-
+
+
-
-
+
+
+
\ No newline at end of file
diff --git a/screen.js b/screen.js
new file mode 100644
index 0000000..81d8e1a
--- /dev/null
+++ b/screen.js
@@ -0,0 +1,226 @@
+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$;
+ });
+
+ function makeSafePyCallbackNoArgs(pyFunc) {
+ if (!pyFunc || pyFunc === Sk.builtin.none.none$) return null;
+ return function () {
+ 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 () { 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(typeof T !== 'undefined' ? T : 0); } });
+ Object.defineProperty(mod, 'W', { get: function () { return toPy(typeof W !== 'undefined' ? W : 0); } });
+ Object.defineProperty(mod, 'H', { get: function () { return toPy(typeof H !== 'undefined' ? H : 0); } });
+ Object.defineProperty(mod, 'MX', {
+ get: function () {
+ if (typeof MX === 'undefined') return toPy(-1);
+ const el = document.getElementById('canvas');
+ if (!el) return toPy(MX);
+ const r = el.getBoundingClientRect();
+ return toPy((MX - r.left) * (el.width / r.width));
+ }
+ });
+ Object.defineProperty(mod, 'MY', {
+ get: function () {
+ if (typeof MY === 'undefined') return toPy(-1);
+ const el = document.getElementById('canvas');
+ if (!el) return toPy(MY);
+ const r = el.getBoundingClientRect();
+ return toPy((MY - r.top) * (el.height / r.height));
+ }
+ });
+ Object.defineProperty(mod, 'CENTERX', { get: function () { return toPy(typeof CENTERX !== 'undefined' ? CENTERX : 0); } });
+ Object.defineProperty(mod, 'CENTERY', { get: function () { return toPy(typeof CENTERY !== 'undefined' ? CENTERY : 0); } });
+
+ 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.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.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.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;
+};
\ No newline at end of file