q5 4.6.6 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@q5/q5",
3
- "version": "4.6.6",
3
+ "version": "4.7.0",
4
4
  "license": "LGPL-3.0-only",
5
5
  "description": "Beginner friendly graphics powered by WebGPU, optimized for interactive art!",
6
6
  "author": "quinton-ashley",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q5",
3
- "version": "4.6.6",
3
+ "version": "4.7.0",
4
4
  "description": "Beginner friendly graphics powered by WebGPU, optimized for interactive art!",
5
5
  "author": "quinton-ashley",
6
6
  "license": "LGPL-3.0-only",
@@ -18,7 +18,6 @@
18
18
  "node": "./q5-server.js",
19
19
  "default": "./q5.js"
20
20
  },
21
- "./q5.min.js": "./q5.min.js",
22
21
  "./q5.js": "./q5.js",
23
22
  "./q5-server.js": {
24
23
  "browser": null,
@@ -43,7 +42,7 @@
43
42
  "scripts": {
44
43
  "bundle": "cat src/q5-core.js src/q5-canvas.js src/q5-c2d-canvas.js src/q5-c2d-shapes.js src/q5-c2d-image.js src/q5-c2d-soft-filters.js src/q5-c2d-text.js src/q5-color.js src/q5-display.js src/q5-dom.js src/q5-fes.js src/q5-input.js src/q5-math.js src/q5-record.js src/q5-sound.js src/q5-util.js src/q5-vector.js src/q5-webgpu.js src/q5-lang.js src/q5-python.js > q5.js",
45
44
  "min": "terser q5.js --compress ecma=2026 --mangle --output q5.min.js --source-map url=q5.min.js.map",
46
- "dist": "bun bundle && bun min",
45
+ "dist": "bun bundle",
47
46
  "tests": "jest test",
48
47
  "bld": "node lang/build.js",
49
48
  "types": "node lang/types.js",
package/py.typed ADDED
File without changes
package/q5.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * q5.js
3
- * @version 4.6
3
+ * @version 4.7
4
4
  * @author quinton-ashley
5
5
  * @contributors evanalulu, Tezumie, keturn, ormaq, bertubi, RedWilly, Dukemz, LingDong-
6
6
  * @license LGPL-3.0
@@ -226,8 +226,6 @@ function Q5(scope, parent, renderer) {
226
226
  r[m]($, q);
227
227
  }
228
228
 
229
- // INIT
230
-
231
229
  for (let k in Q5) {
232
230
  if (k[1] != '_' && k[1] == k[1].toUpperCase()) {
233
231
  $[k] = Q5[k];
@@ -496,18 +494,19 @@ if (typeof window == 'object') {
496
494
  window.addEventListener('pagehide', cleanup);
497
495
  } else global.window = 0;
498
496
 
499
- Q5.version = Q5.VERSION = '4.6';
497
+ Q5.version = Q5.VERSION = '4.7';
500
498
 
501
499
  if (typeof document == 'object') {
502
- document.addEventListener('DOMContentLoaded', () => {
503
- if (!Q5._hasGlobal) {
504
- if (Q5.update || Q5.draw) {
505
- Q5.WebGPU();
506
- } else {
507
- new Q5('auto');
508
- }
500
+ function init() {
501
+ if (Q5._hasGlobal) return;
502
+ if (Q5.update || Q5.draw) {
503
+ Q5.WebGPU();
504
+ } else {
505
+ new Q5('auto');
509
506
  }
510
- });
507
+ }
508
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
509
+ else setTimeout(init, 0); // defer until the rest of q5.js is run
511
510
  }
512
511
  Q5.modules.canvas = ($, q) => {
513
512
  $._Canvas =
@@ -9621,42 +9620,60 @@ Q5.addHook('predraw', (q) => {
9621
9620
  }
9622
9621
  });
9623
9622
  const runPython = async function () {
9624
- let scripts = [...document.getElementsByTagName('script')];
9625
- scripts = scripts.filter((s) => s.type == 'q5-python' || s.type == 'text/q5-python');
9623
+ let scripts = [...document.getElementsByTagName('script')].filter(
9624
+ (s) => s.type == 'q5-python' || s.type == 'text/q5-python'
9625
+ );
9626
9626
  if (!scripts.length) return;
9627
9627
 
9628
9628
  if (!window.brython) {
9629
- const loadScript = (src) =>
9630
- new Promise((resolve, reject) => {
9631
- const script = document.createElement('script');
9632
- script.src = src;
9633
- script.onload = resolve;
9634
- script.onerror = reject;
9635
- document.head.appendChild(script);
9629
+ const load = (src) =>
9630
+ new Promise((res, rej) => {
9631
+ const s = document.createElement('script');
9632
+ s.src = src;
9633
+ s.onload = res;
9634
+ s.onerror = rej;
9635
+ document.head.appendChild(s);
9636
9636
  });
9637
9637
 
9638
- await loadScript('https://cdn.jsdelivr.net/npm/brython@3.14.0/brython.min.js');
9639
- await loadScript('https://cdn.jsdelivr.net/npm/brython@3.14.0/brython_stdlib.min.js');
9638
+ await load('https://cdn.jsdelivr.net/npm/brython@3.14.0/brython.min.js');
9639
+ await load('https://cdn.jsdelivr.net/npm/brython@3.14.0/brython_stdlib.min.js');
9640
9640
  }
9641
9641
 
9642
9642
  let code = '';
9643
9643
  for (const script of scripts) {
9644
- code += script.src ? await (await fetch(script.src)).text() : script.innerText;
9644
+ if (script.src?.endsWith?.('.ipynb')) {
9645
+ const nb = await (await fetch(script.src)).json();
9646
+ for (const cell of nb.cells) {
9647
+ if (cell.cell_type !== 'code') continue;
9648
+ const m = cell.metadata,
9649
+ cellLang = m?.language_info?.name ?? m?.kernelspec?.language ?? m?.kernelspec?.name ?? m?.language;
9650
+ if (cellLang && !String(cellLang).toLowerCase().includes('python')) continue;
9651
+ const src = Array.isArray(cell.source)
9652
+ ? cell.source.join('')
9653
+ : typeof cell.source === 'string'
9654
+ ? cell.source
9655
+ : '';
9656
+ code += src + '\n';
9657
+ }
9658
+ } else {
9659
+ code += script.src ? await (await fetch(script.src)).text() : script.innerText;
9660
+ }
9645
9661
  }
9646
9662
 
9663
+ // strip `from q5 import *` — it's only used for type hints (q5.pyi)
9664
+ code = code.startsWith('from q5') ? code.slice(code.indexOf('\n') + 1) : code;
9665
+
9647
9666
  const useWebGPU = !code.slice(0, code.indexOf('\n')).includes('C2D'),
9648
9667
  q = useWebGPU ? await Q5.WebGPU() : new Q5();
9668
+ await q.ready;
9649
9669
 
9650
- // `window.Canvas` returns a promise that resolves when Q5 is ready
9651
- // but `q5py.Canvas` returns the renderer synchronously
9652
- // so to make Brython happy with `await Canvas()` we need to make it async
9653
- const Canvas = q.Canvas;
9654
- q.Canvas = async (...a) => Canvas(...a);
9670
+ let pyReady;
9671
+ q._loaders.push(new Promise((res) => (pyReady = res)));
9655
9672
 
9656
9673
  // add a tab before each line of code to nest it inside the __run function
9657
9674
  // but not within triple-quoted strings
9658
9675
  code = code
9659
- .split(/(\"\"\"[\s\S]*?\"\"\"|\'\'\'[\s\S]*?\'\'\')/g)
9676
+ .split(/("""[\s\S]*?"""|\'\'\'[\s\S]*?\'\'\')/g)
9660
9677
  .map((part, i) => (i % 2 === 0 ? part.replaceAll('\n', '\n\t') : part))
9661
9678
  .join('');
9662
9679
 
@@ -9753,8 +9770,8 @@ async def _run_py(q, code):
9753
9770
  pass
9754
9771
 
9755
9772
  _orig_Canvas = ns['Canvas']
9756
- async def _canvas_wrapper(*args):
9757
- result = await _orig_Canvas(*args)
9773
+ def _canvas_wrapper(*args):
9774
+ result = _orig_Canvas(*args)
9758
9775
  _sync_state(q, ns)
9759
9776
  return result
9760
9777
  ns['Canvas'] = ns['createCanvas'] = _canvas_wrapper
@@ -9776,6 +9793,8 @@ window._runPy = _run_py
9776
9793
 
9777
9794
  console.log = log;
9778
9795
 
9796
+ pyReady();
9797
+
9779
9798
  await window._runPy(q, code);
9780
9799
  };
9781
9800