q5 4.6.6 → 4.7.1

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",
@@ -32,7 +32,9 @@
32
32
  "CODE_OF_CONDUCT.md",
33
33
  "deno.lock",
34
34
  "Icon?",
35
- "package.json"
35
+ "package.json",
36
+ "q5.min.js",
37
+ "q5.min.js.map"
36
38
  ]
37
39
  }
38
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q5",
3
- "version": "4.6.6",
3
+ "version": "4.7.1",
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 =
@@ -6660,7 +6659,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6660
6659
  if (shapeVertCount === 0) throw new Error('Shape needs a vertex()');
6661
6660
 
6662
6661
  // Get the last vertex as the starting point (P₀)
6663
- let prevIndex = (shapeVertCount - 1) * 4;
6662
+ let prevIndex = (shapeVertCount - 1) * 3;
6664
6663
  let startX = sv[prevIndex];
6665
6664
  let startY = sv[prevIndex + 1];
6666
6665
 
@@ -6673,7 +6672,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6673
6672
  y = cy2;
6674
6673
  }
6675
6674
 
6676
- let end = 1 + step;
6675
+ let end = 1 + step * 0.5;
6677
6676
  for (let t = step; t <= end; t += step) {
6678
6677
  // Start from 0.1 to avoid duplicating the start point
6679
6678
  let t2 = t * t;
@@ -6802,15 +6801,6 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6802
6801
  }
6803
6802
  }
6804
6803
  } else {
6805
- let cx = 0,
6806
- cy = 0;
6807
- for (let i = 0; i < shapeVertCount - 1; i++) {
6808
- cx += sv[i * 3];
6809
- cy += sv[i * 3 + 1];
6810
- }
6811
- cx /= Math.max(1, shapeVertCount - 1);
6812
- cy /= Math.max(1, shapeVertCount - 1);
6813
-
6814
6804
  let signedArea = 0,
6815
6805
  sign = 1;
6816
6806
  for (let i = 0; i < shapeVertCount - 1; i++) {
@@ -9621,42 +9611,60 @@ Q5.addHook('predraw', (q) => {
9621
9611
  }
9622
9612
  });
9623
9613
  const runPython = async function () {
9624
- let scripts = [...document.getElementsByTagName('script')];
9625
- scripts = scripts.filter((s) => s.type == 'q5-python' || s.type == 'text/q5-python');
9614
+ let scripts = [...document.getElementsByTagName('script')].filter(
9615
+ (s) => s.type == 'q5-python' || s.type == 'text/q5-python'
9616
+ );
9626
9617
  if (!scripts.length) return;
9627
9618
 
9628
9619
  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);
9620
+ const load = (src) =>
9621
+ new Promise((res, rej) => {
9622
+ const s = document.createElement('script');
9623
+ s.src = src;
9624
+ s.onload = res;
9625
+ s.onerror = rej;
9626
+ document.head.appendChild(s);
9636
9627
  });
9637
9628
 
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');
9629
+ await load('https://cdn.jsdelivr.net/npm/brython@3.14.0/brython.min.js');
9630
+ await load('https://cdn.jsdelivr.net/npm/brython@3.14.0/brython_stdlib.min.js');
9640
9631
  }
9641
9632
 
9642
9633
  let code = '';
9643
9634
  for (const script of scripts) {
9644
- code += script.src ? await (await fetch(script.src)).text() : script.innerText;
9635
+ if (script.src?.endsWith?.('.ipynb')) {
9636
+ const nb = await (await fetch(script.src)).json();
9637
+ for (const cell of nb.cells) {
9638
+ if (cell.cell_type !== 'code') continue;
9639
+ const m = cell.metadata,
9640
+ cellLang = m?.language_info?.name ?? m?.kernelspec?.language ?? m?.kernelspec?.name ?? m?.language;
9641
+ if (cellLang && !String(cellLang).toLowerCase().includes('python')) continue;
9642
+ const src = Array.isArray(cell.source)
9643
+ ? cell.source.join('')
9644
+ : typeof cell.source === 'string'
9645
+ ? cell.source
9646
+ : '';
9647
+ code += src + '\n';
9648
+ }
9649
+ } else {
9650
+ code += script.src ? await (await fetch(script.src)).text() : script.innerText;
9651
+ }
9645
9652
  }
9646
9653
 
9654
+ // strip `from q5 import *` — it's only used for type hints (q5.pyi)
9655
+ code = code.startsWith('from q5') ? code.slice(code.indexOf('\n') + 1) : code;
9656
+
9647
9657
  const useWebGPU = !code.slice(0, code.indexOf('\n')).includes('C2D'),
9648
9658
  q = useWebGPU ? await Q5.WebGPU() : new Q5();
9659
+ await q.ready;
9649
9660
 
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);
9661
+ let pyReady;
9662
+ q._loaders.push(new Promise((res) => (pyReady = res)));
9655
9663
 
9656
9664
  // add a tab before each line of code to nest it inside the __run function
9657
9665
  // but not within triple-quoted strings
9658
9666
  code = code
9659
- .split(/(\"\"\"[\s\S]*?\"\"\"|\'\'\'[\s\S]*?\'\'\')/g)
9667
+ .split(/("""[\s\S]*?"""|\'\'\'[\s\S]*?\'\'\')/g)
9660
9668
  .map((part, i) => (i % 2 === 0 ? part.replaceAll('\n', '\n\t') : part))
9661
9669
  .join('');
9662
9670
 
@@ -9753,8 +9761,8 @@ async def _run_py(q, code):
9753
9761
  pass
9754
9762
 
9755
9763
  _orig_Canvas = ns['Canvas']
9756
- async def _canvas_wrapper(*args):
9757
- result = await _orig_Canvas(*args)
9764
+ def _canvas_wrapper(*args):
9765
+ result = _orig_Canvas(*args)
9758
9766
  _sync_state(q, ns)
9759
9767
  return result
9760
9768
  ns['Canvas'] = ns['createCanvas'] = _canvas_wrapper
@@ -9776,6 +9784,8 @@ window._runPy = _run_py
9776
9784
 
9777
9785
  console.log = log;
9778
9786
 
9787
+ pyReady();
9788
+
9779
9789
  await window._runPy(q, code);
9780
9790
  };
9781
9791