q5 4.5.3 → 4.5.4

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/README.md CHANGED
@@ -47,7 +47,9 @@ p5.js is licensed under the LGPLv2, small sections of p5' code directly copied i
47
47
 
48
48
  q5 was inspired by the incredible work of [Ben Fry](https://benfry.com) and [Casey Reas](https://x.com/REAS) on Java [Processing](https://processingfoundation.org/) from 2001 to 2023, [Lauren McCarthy](http://lauren-mccarthy.com)'s work on [p5.js](https://p5js.org) from 2013 to 2019, and all contributors to these projects.
49
49
 
50
- ## Code Excerpt Sources
50
+ Huge thanks to all the [q5 contributors](https://github.com/q5js/q5.js/graphs/contributors)!
51
+
52
+ @evanalulu, @Tezumie, @keturn, @ormaq, @bertubi, @RedWilly, @Dukemz, @LingDong-
51
53
 
52
54
  WebGPU MSDF text rendering:
53
55
  https://webgpu.github.io/webgpu-samples/?sample=textRenderingMsdf
package/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@q5/q5",
3
- "version": "4.5.3",
3
+ "version": "4.5.4",
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.5.3",
3
+ "version": "4.5.4",
4
4
  "description": "Beginner friendly graphics powered by WebGPU, optimized for interactive art!",
5
5
  "author": "quinton-ashley",
6
6
  "contributors": [
package/q5.js CHANGED
@@ -393,6 +393,7 @@ Q5._esm = this === undefined;
393
393
 
394
394
  Q5._instanceCount = 0;
395
395
  Q5.instances = [];
396
+ Q5.errorTolerant = false;
396
397
  Q5._friendlyError = (msg, func) => {
397
398
  if (!Q5.disableFriendlyErrors) console.error(func + ': ' + msg);
398
399
  };
@@ -9591,35 +9592,42 @@ const runPython = async function () {
9591
9592
  }
9592
9593
 
9593
9594
  const useWebGPU = !code.slice(0, code.indexOf('\n')).includes('C2D'),
9594
- q5py = useWebGPU ? await Q5.WebGPU() : new Q5();
9595
+ q = useWebGPU ? await Q5.WebGPU() : new Q5();
9595
9596
 
9596
9597
  // `window.Canvas` returns a promise that resolves when Q5 is ready
9597
9598
  // but `q5py.Canvas` returns the renderer synchronously
9598
9599
  // so to make Brython happy with `await Canvas()` we need to make it async
9599
- const Canvas = q5py.Canvas;
9600
- q5py.Canvas = async (...a) => Canvas(...a);
9600
+ const Canvas = q.Canvas;
9601
+ q.Canvas = async (...a) => Canvas(...a);
9601
9602
 
9602
- code = code.replaceAll('\n', '\n\t');
9603
+ // add a tab before each line of code to nest it inside the __run function
9604
+ // but not within triple-quoted strings
9605
+ code = code
9606
+ .split(/(\"\"\"[\s\S]*?\"\"\"|\'\'\'[\s\S]*?\'\'\')/g)
9607
+ .map((part, i) => (i % 2 === 0 ? part.replaceAll('\n', '\n\t') : part))
9608
+ .join('');
9603
9609
 
9604
9610
  code = `
9605
- async def __run():
9611
+ async def __run(q):
9606
9612
  ${code}
9607
9613
 
9608
- _q5_state_vars = ["mouseX", "mouseY", "pmouseX", "pmouseY", "width", "height", "frameCount", "deltaTime", "mouseIsPressed", "mouseButton", "keyIsPressed", "key", "keyCode", "touches", "movedX", "movedY"]
9614
+ _state_vars = ["mouseX", "mouseY", "pmouseX", "pmouseY", "width", "height", "frameCount", "deltaTime", "mouseIsPressed", "mouseButton", "keyIsPressed", "key", "keyCode", "touches", "movedX", "movedY"]
9615
+
9616
+ _usr_fns = ["update", "draw", "postProcess", "mousePressed", "mouseReleased", "mouseMoved", "mouseDragged", "mouseClicked", "doubleClicked", "mouseWheel", "keyPressed", "keyReleased", "keyTyped", "touchStarted", "touchMoved", "touchEnded", "windowResized"]
9609
9617
 
9610
9618
  def _sync_and_call(fn):
9611
9619
  def _wrapper(*args):
9612
9620
  try:
9613
- for var in _q5_state_vars:
9614
- if hasattr(q5py, var):
9615
- ns[var] = getattr(q5py, var)
9621
+ for var in _state_vars:
9622
+ if hasattr(q, var):
9623
+ ns[var] = getattr(q, var)
9616
9624
  return fn(*args)
9617
9625
  except Exception as e:
9618
9626
  window._pyErr(_err())
9619
- raise e
9627
+ if not window.Q5.errorTolerant: noLoop()
9620
9628
  return _wrapper
9621
9629
 
9622
- for fn_name in ["update", "draw", "mousePressed", "mouseReleased", "mouseMoved", "mouseDragged", "mouseClicked", "doubleClicked", "mouseWheel", "keyPressed", "keyReleased", "keyTyped", "touchStarted", "touchMoved", "touchEnded", "windowResized"]:
9630
+ for fn_name in _usr_fns:
9623
9631
  if fn_name in locals():
9624
9632
  setattr(window, fn_name, _sync_and_call(locals()[fn_name]))
9625
9633
  `;
@@ -9627,7 +9635,7 @@ async def __run():
9627
9635
  window._pyErr = (err, lineNum) => {
9628
9636
  if (typeof err === 'string' && err.includes('Traceback')) {
9629
9637
  let lines = err.split('\n');
9630
- for (let i = 0; i < lines.length; i++) {
9638
+ for (let i = lines.length - 1; i > 0; i--) {
9631
9639
  const match = lines[i].match(/File "<string>", line (\d+)/);
9632
9640
  if (match) {
9633
9641
  lineNum = parseInt(match[1]);
@@ -9639,6 +9647,9 @@ async def __run():
9639
9647
  for (let j = 0; j < Math.min(2, lines.length); j++) {
9640
9648
  lines[j] = lines[j].slice(indent.length);
9641
9649
  }
9650
+ } else {
9651
+ let line = code.split('\n')[lineNum - 1].trim();
9652
+ lines.unshift(line, '');
9642
9653
  }
9643
9654
  err = lines.join('\n');
9644
9655
  break;
@@ -9646,7 +9657,9 @@ async def __run():
9646
9657
  }
9647
9658
  }
9648
9659
 
9649
- let file = scripts[0].src.split('/').at(-1);
9660
+ let file = scripts[0].src || scripts[0]['data-filename'] || 'sketch.py';
9661
+ file = file.split('/').at(-1);
9662
+
9650
9663
  lineNum -= 2; // adjust for the wrapper code lines
9651
9664
  if (Q5.friendlyError) Q5.friendlyError(file, lineNum, err);
9652
9665
  else console.error(`Error in ${file} on line ${lineNum}:\n\n${err}`);
@@ -9668,15 +9681,15 @@ def _err():
9668
9681
  traceback.print_exc(file=f)
9669
9682
  return f.getvalue()
9670
9683
 
9671
- async def _run_py(q5py, code):
9684
+ async def _run_py(q, code):
9672
9685
  ns = globals().copy()
9673
9686
  ns['ns'] = ns
9674
- ns['q5py'] = q5py
9687
+ ns['Q5'] = window.Q5
9675
9688
 
9676
- for attr in dir(q5py):
9689
+ for attr in dir(q):
9677
9690
  if not attr.startswith('_'):
9678
9691
  try:
9679
- ns[attr] = getattr(q5py, attr)
9692
+ ns[attr] = getattr(q, attr)
9680
9693
  except Exception:
9681
9694
  pass
9682
9695
 
@@ -9688,7 +9701,7 @@ async def _run_py(q5py, code):
9688
9701
  return window._pyErr(_err())
9689
9702
 
9690
9703
  try:
9691
- await ns["__run"]()
9704
+ await ns["__run"](q)
9692
9705
  except Exception as e:
9693
9706
  window._pyErr(_err())
9694
9707
 
@@ -9697,7 +9710,7 @@ window._runPy = _run_py
9697
9710
 
9698
9711
  console.log = log;
9699
9712
 
9700
- await window._runPy(q5py, code);
9713
+ await window._runPy(q, code);
9701
9714
  };
9702
9715
 
9703
9716
  if (typeof document == 'object') {