q5play 4.2.2 → 4.3.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.
Files changed (4) hide show
  1. package/package.json +1 -1
  2. package/q5play.d.ts +12 -0
  3. package/q5play.js +162 -197
  4. package/q5play.pyi +12 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q5play",
3
- "version": "4.2.2",
3
+ "version": "4.3.0",
4
4
  "author": "quinton-ashley",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "description": "A beginner friendly, web-based game engine that uses q5.js WebGPU for graphics and Box2D v3 WASM for physics.",
package/q5play.d.ts CHANGED
@@ -60,6 +60,18 @@ declare global {
60
60
  hasMouse: boolean;
61
61
  standardizeKeyboard: boolean;
62
62
 
63
+ /**
64
+ * Set to true to disable q5play's console logs, warnings, and error messages.
65
+ * Severe errors will still be thrown.
66
+ */
67
+ silent: boolean;
68
+
69
+ /**
70
+ * Set to true to disable q5play's console logs.
71
+ * Warnings and errors will still be shown, and severe errors will still be thrown.
72
+ */
73
+ quiet: boolean;
74
+
63
75
  /**
64
76
  * Displays the version of q5play being used,
65
77
  * the number of sprites being drawn
package/q5play.js CHANGED
@@ -12,15 +12,15 @@
12
12
  * |__/ |__/ \______/
13
13
  *
14
14
  * @package q5play
15
- * @version 4.2
15
+ * @version 4.3
16
16
  * @author quinton-ashley
17
17
  * @website https://q5play.org
18
18
  */
19
19
 
20
- let q5play_version = '4.2';
20
+ let q5play_version = '4.3';
21
21
 
22
22
  if (typeof globalThis.Q5 == 'undefined' && typeof globalThis.p5 == 'undefined') {
23
- console.error('q5play requires q5.js to be loaded first. Visit https://q5js.org to learn more.');
23
+ throw new Error('q5play requires q5.js to be loaded first. Visit https://q5js.org to learn more.');
24
24
  }
25
25
 
26
26
  let box2dPromise,
@@ -28,8 +28,9 @@ let box2dPromise,
28
28
 
29
29
  // called when a new instance of Q5 is created
30
30
  async function q5playPreSetup(q) {
31
- const $ = this,
32
- log = console.log;
31
+ const $ = this;
32
+
33
+ using_p5 = !$._q5;
33
34
 
34
35
  if (!box2dPromise) {
35
36
  box2dPromise = (async () => {
@@ -246,6 +247,8 @@ async function q5playPreSetup(q) {
246
247
  this.emojiScale = 1;
247
248
  this.os = {};
248
249
  this.context = 'web';
250
+ this.silent = false;
251
+ this.quiet = false;
249
252
 
250
253
  this.update = () => q5playUpdate.call($, q);
251
254
  this.draw = () => q5playPostDraw.call($, q);
@@ -365,23 +368,27 @@ async function q5playPreSetup(q) {
365
368
  $.q5play = new $.Q5Play();
366
369
  delete $.Q5Play;
367
370
 
368
- using_p5 = !$._q5;
369
- if (using_p5 && p5.VERSION[0] != 2) {
370
- throw new Error(`q5play requires q5.js or p5.js v2. Detected version: ${p5.VERSION}. Please upgrade.`);
371
- }
371
+ const log = (...args) => {
372
+ if (!$.q5play.quiet && !$.q5play.silent) console.log(...args);
373
+ };
374
+ const warn = (...args) => {
375
+ if (!$.q5play.silent) console.warn(...args);
376
+ };
377
+ const error = (...args) => {
378
+ if (!$.q5play.silent) console.error(...args);
379
+ };
372
380
 
373
381
  const DEGREES = $.DEGREES,
374
382
  DEGTORAD = Math.PI / 180,
375
383
  RADTODEG = 180 / Math.PI;
376
384
 
377
- // in q5play the default angle mode is degrees
385
+ // in q5play defaults
378
386
  $.angleMode(DEGREES);
379
-
380
- // in q5play the default color mode is float RGB
381
- if (!using_p5) $.colorMode($.RGB, 1);
382
-
383
- // in q5play the default image mode is center
384
- if (!using_p5) $.imageMode($.CENTER);
387
+ if (!using_p5) {
388
+ // set later in p5 compatibility mode
389
+ $.colorMode($.RGB, 1);
390
+ $.imageMode($.CENTER);
391
+ }
385
392
 
386
393
  const ZERO_VEC = new b2Vec2(0, 0),
387
394
  ZERO_ROT = b2MakeRot(0),
@@ -702,6 +709,8 @@ async function q5playPreSetup(q) {
702
709
  if (typeof val == 'string') {
703
710
  if (!val.includes('.')) {
704
711
  val = new $.EmojiImage(val, this.w);
712
+ } else if (using_p5) {
713
+ return this._setP5Img(val);
705
714
  } else val = $.loadImage(val);
706
715
  }
707
716
  this._img = this._extendImage(val);
@@ -730,6 +739,13 @@ async function q5playPreSetup(q) {
730
739
  return img;
731
740
  }
732
741
 
742
+ async _setP5Img(val) {
743
+ // for p5 v2 compatibility
744
+ let img = await $.loadImage(val);
745
+ this._img = this._extendImage(img);
746
+ this._hasImagery = true;
747
+ }
748
+
733
749
  addAni() {
734
750
  let args = [...arguments];
735
751
  let ani, name;
@@ -776,7 +792,7 @@ async function q5playPreSetup(q) {
776
792
  }
777
793
  if (args.length >= 2) {
778
794
  if (typeof spriteSheet == 'string') {
779
- spriteSheet = $.load(spriteSheet);
795
+ spriteSheet = $.loadImage(spriteSheet);
780
796
  }
781
797
  this.anis.spriteSheet = spriteSheet;
782
798
  }
@@ -804,7 +820,7 @@ async function q5playPreSetup(q) {
804
820
  ani = v._anis?.[name];
805
821
  }
806
822
  if (ani) ani = ani.clone();
807
- else return console.error('Ani not found: ' + name);
823
+ else return error('Ani not found: ' + name);
808
824
  }
809
825
  // reset to frame 0 of that animation
810
826
  if (this.resetAniOnChange) ani._frame = 0;
@@ -1337,7 +1353,7 @@ async function q5playPreSetup(q) {
1337
1353
 
1338
1354
  addCollider(offsetX, offsetY, w, h) {
1339
1355
  if (this._deleted) {
1340
- console.error("Can't add colliders to a sprite that was deleted.");
1356
+ error("Can't add colliders to a sprite that was deleted.");
1341
1357
  return;
1342
1358
  }
1343
1359
 
@@ -1353,7 +1369,7 @@ async function q5playPreSetup(q) {
1353
1369
 
1354
1370
  addSensor(offsetX, offsetY, w, h) {
1355
1371
  if (this._deleted) {
1356
- console.error("Can't add sensors to a sprite that was deleted.");
1372
+ error("Can't add sensors to a sprite that was deleted.");
1357
1373
  return;
1358
1374
  }
1359
1375
 
@@ -1376,7 +1392,7 @@ async function q5playPreSetup(q) {
1376
1392
  _add(isSensor, a0, a1, a2, a3, a4) {
1377
1393
  if (this._shapes.length >= $.Sprite.maxColliders) {
1378
1394
  if (!this._warnedMaxColliders) {
1379
- console.warn(
1395
+ warn(
1380
1396
  `Sprite has ${this._shapes.length} colliders and sensors, which is greater than Sprite.maxColliders. Increasing the limit may cause performance issues.`
1381
1397
  );
1382
1398
  this._warnedMaxColliders = true;
@@ -2291,7 +2307,7 @@ async function q5playPreSetup(q) {
2291
2307
  set surfaceSpeed(val) {
2292
2308
  if (this.watch) this.mod[21] = true;
2293
2309
  if (this._hasCapsuleChain) {
2294
- return console.error('Can not set surfaceSpeed of a capsule chain.');
2310
+ return error('Can not set surfaceSpeed of a capsule chain.');
2295
2311
  }
2296
2312
  if (this._hasChain) this._chain.surfaceSpeed = val;
2297
2313
  for (let collider of this.colliders) {
@@ -2918,7 +2934,7 @@ async function q5playPreSetup(q) {
2918
2934
 
2919
2935
  attractTo(x, y, force) {
2920
2936
  if (this._phys != 0) {
2921
- console.error('attractTo can only be used on sprites with dynamic physics bodies');
2937
+ error('attractTo can only be used on sprites with dynamic physics bodies');
2922
2938
  return;
2923
2939
  }
2924
2940
  if (typeof x != 'number') {
@@ -2942,7 +2958,7 @@ async function q5playPreSetup(q) {
2942
2958
 
2943
2959
  repelFrom(x, y, force) {
2944
2960
  if (this._phys != 0) {
2945
- console.error('repelFrom can only be used on sprites with dynamic colliders');
2961
+ error('repelFrom can only be used on sprites with dynamic colliders');
2946
2962
  return;
2947
2963
  }
2948
2964
  if (typeof x != 'number') {
@@ -3611,6 +3627,12 @@ async function q5playPreSetup(q) {
3611
3627
 
3612
3628
  // image sequence format
3613
3629
  if (args.length == 2 && typeof args[0] == 'string' && typeof args[1] == 'string' && !args[1].includes('.')) {
3630
+ if (using_p5) {
3631
+ throw new Error(
3632
+ 'p5.js v2 does not support preloading or lazy loading images. Convert the image sequence to a sprite sheet.'
3633
+ );
3634
+ }
3635
+
3614
3636
  let file = args[0],
3615
3637
  extIndex = file.lastIndexOf('.'),
3616
3638
  digits = 0;
@@ -3765,7 +3787,9 @@ async function q5playPreSetup(q) {
3765
3787
  if (typeof sheet == 'string') {
3766
3788
  sheet = $.loadImage(sheet);
3767
3789
  }
3768
- sheet.promise.then(() => {
3790
+ let promise = !using_p5 ? sheet.promise : sheet;
3791
+ promise.then((img) => {
3792
+ if (using_p5) this.spriteSheet = sheet = img;
3769
3793
  if (!this.length) findFrames();
3770
3794
 
3771
3795
  if (this._clones) {
@@ -3787,7 +3811,11 @@ async function q5playPreSetup(q) {
3787
3811
  else {
3788
3812
  for (let i = 0; i < args.length; i++) {
3789
3813
  if (args[i] instanceof Q5.Image) this.push(args[i]);
3790
- else this.push($.loadImage(args[i]));
3814
+ else if (using_p5) {
3815
+ throw new Error(
3816
+ 'p5.js v2 does not support preloading or lazy loading images. You need to use `await loadImage(url)`.'
3817
+ );
3818
+ } else this.push($.loadImage(args[i]));
3791
3819
  }
3792
3820
  }
3793
3821
 
@@ -4156,6 +4184,8 @@ async function q5playPreSetup(q) {
4156
4184
  if (typeof val == 'string') {
4157
4185
  if (!val.includes('.')) {
4158
4186
  val = new $.EmojiImage(val, this.w || this.width || this.d || this.diameter);
4187
+ } else if (using_p5) {
4188
+ return $.Visual.prototype._setP5Img(val);
4159
4189
  } else val = $.loadImage(val);
4160
4190
  }
4161
4191
  this._img = $.Visual.prototype._extendImage(val);
@@ -4325,7 +4355,7 @@ async function q5playPreSetup(q) {
4325
4355
  }
4326
4356
  }
4327
4357
  if (!this.idNum) {
4328
- console.warn('ERROR: Surpassed the limit of 999 groups in memory. Delete groups to recycle group ids.');
4358
+ warn('ERROR: Surpassed the limit of 999 groups in memory. Delete groups to recycle group ids.');
4329
4359
  // if there are no empty slots, try to prevent a crash by
4330
4360
  // finding the first slot that has a group with no sprites in it
4331
4361
  for (let i = 1; i < $.q5play.groups.length; i++) {
@@ -5111,7 +5141,7 @@ async function q5playPreSetup(q) {
5111
5141
 
5112
5142
  splice(start, removalCount, ...sprites) {
5113
5143
  if (this.deleted) {
5114
- console.warn(
5144
+ warn(
5115
5145
  'Edited group' +
5116
5146
  this._uid +
5117
5147
  " that was deleted. Use `group.deleteAll()` to remove all of a group's sprites without deleting the group itself. Restoring the group to q5play's memory."
@@ -5123,11 +5153,11 @@ async function q5playPreSetup(q) {
5123
5153
  // filter out non-sprites and log a warning
5124
5154
  sprites = sprites.filter((s) => {
5125
5155
  if (!(s instanceof $.Sprite)) {
5126
- console.warn('Only sprites can be added to a group, skipping:', s);
5156
+ warn('Only sprites can be added to a group, skipping:', s);
5127
5157
  return false;
5128
5158
  }
5129
5159
  if (s.deleted) {
5130
- console.warn("Can't add a deleted sprite to a group, skipping:", s);
5160
+ warn("Can't add a deleted sprite to a group, skipping:", s);
5131
5161
  return false;
5132
5162
  }
5133
5163
  return true;
@@ -5582,7 +5612,7 @@ async function q5playPreSetup(q) {
5582
5612
  }
5583
5613
  set timeScale(val) {
5584
5614
  if (val < 0 || val > 2) {
5585
- return console.error('world.timeScale must be between 0 and 2');
5615
+ return error('world.timeScale must be between 0 and 2');
5586
5616
  }
5587
5617
  if (this._timeScale == val) return;
5588
5618
  this._timeScale = val;
@@ -5982,7 +6012,7 @@ async function q5playPreSetup(q) {
5982
6012
  }
5983
6013
  speed ??= 1;
5984
6014
  if (speed <= 0) {
5985
- console.warn('camera.moveTo: speed should be a positive number');
6015
+ warn('camera.moveTo: speed should be a positive number');
5986
6016
  return Promise.resolve(false);
5987
6017
  }
5988
6018
  let a = y - this.y;
@@ -6985,7 +7015,7 @@ async function q5playPreSetup(q) {
6985
7015
 
6986
7016
  // same code as img.trim() in q5.js
6987
7017
  let ctx = g.drawingContext;
6988
- let pd = g._pixelDensity || 1;
7018
+ let pd = g._pixelDensity || g._renderer?._pixelDensity || 1;
6989
7019
  let w = g.canvas.width;
6990
7020
  let h = g.canvas.height;
6991
7021
  let data = ctx.getImageData(0, 0, w, h).data;
@@ -7094,7 +7124,7 @@ async function q5playPreSetup(q) {
7094
7124
  }
7095
7125
  } else $.image(img, dx, dy, dw, dh);
7096
7126
  } else {
7097
- console.warn(
7127
+ warn(
7098
7128
  'q5play: "' +
7099
7129
  ani.name +
7100
7130
  '"' +
@@ -7197,53 +7227,19 @@ async function q5playPreSetup(q) {
7197
7227
  }
7198
7228
  }
7199
7229
 
7200
- // let userDisabledP5Errors = p5.disableFriendlyErrors;
7201
- // p5.disableFriendlyErrors = true;
7202
-
7203
7230
  let didCreateCanvas = false;
7204
7231
 
7205
- const _createCanvas = $.createCanvas;
7206
-
7207
- $.Canvas = $.createCanvas = function (w, h) {
7208
- let args = [...arguments];
7209
-
7210
- if (using_p5 && !didCreateCanvas && w == 100 && h == 100) return _createCanvas.call($, ...args);
7211
-
7212
- // prevent p5 v1 overriding the user's canvas with a new default canvas
7213
- if (didCreateCanvas && w == 100 && h == 100) return;
7214
-
7215
- if (typeof args[0] == 'string') {
7216
- if (args[0].includes(':')) {
7217
- let ratio = args[0].split(':'),
7218
- rW = Number(ratio[0]),
7219
- rH = Number(ratio[1]),
7220
- w = window.innerWidth,
7221
- h = window.innerWidth * (rH / rW);
7222
- if (h > window.innerHeight) {
7223
- w = window.innerHeight * (rW / rH);
7224
- h = window.innerHeight;
7225
- }
7226
- args[0] = Math.round(w);
7227
- args.splice(1, 0, Math.round(h));
7228
- } else {
7229
- args = [0, 0, ...args];
7230
- }
7231
- }
7232
- if (!args[0]) {
7233
- args[0] = window.innerWidth;
7234
- args[1] = window.innerHeight;
7235
- }
7236
- args[1] ??= args[0];
7237
- args[0] = Math.floor(args[0] / 2) * 2;
7238
- args[1] = Math.floor(args[1] / 2) * 2;
7239
- let rend = _createCanvas.call($, ...args);
7232
+ const q5playCanvas = (rend, args) => {
7240
7233
  $.ctx = $.drawingContext;
7241
7234
  let c = rend.canvas || rend;
7242
- if (using_p5) window.canvas = c;
7243
- if (rend.GL) {
7244
- c.renderer = 'webgl';
7245
- $._webgl = true;
7246
- } else if (!$._webgpu) $._c2d = true;
7235
+
7236
+ if (using_p5) {
7237
+ if (rend.device) $._webgpu = true;
7238
+ else if (rend.GL) $._webgl = true;
7239
+ else if ($._specifiedRenderer) $._c2d = true;
7240
+ else $._webgpu = $._webgpuFallback = true;
7241
+ }
7242
+
7247
7243
  c.tabIndex = 0;
7248
7244
  c.w = args[0];
7249
7245
  c.h = args[1];
@@ -7293,7 +7289,6 @@ async function q5playPreSetup(q) {
7293
7289
  rs.y = -c.hh + 20;
7294
7290
  }
7295
7291
  }
7296
- // p5.disableFriendlyErrors = userDisabledP5Errors;
7297
7292
 
7298
7293
  let pointer = window.PointerEvent ? 'pointer' : 'mouse';
7299
7294
  c.addEventListener(pointer + 'down', onpointerdown);
@@ -7303,9 +7298,57 @@ async function q5playPreSetup(q) {
7303
7298
  }
7304
7299
 
7305
7300
  didCreateCanvas = true;
7301
+
7302
+ if (using_p5) p5._q5playCompat($);
7303
+
7306
7304
  return rend;
7307
7305
  };
7308
7306
 
7307
+ const _createCanvas = $.createCanvas;
7308
+
7309
+ $.Canvas = $.createCanvas = function (w, h) {
7310
+ let args = [...arguments];
7311
+
7312
+ if (using_p5 && !didCreateCanvas && w == 100 && h == 100) return _createCanvas.call($, ...args);
7313
+
7314
+ // prevent p5 v1 overriding the user's canvas with a new default canvas
7315
+ if (didCreateCanvas && w == 100 && h == 100) return;
7316
+
7317
+ if (typeof args[0] == 'string') {
7318
+ if (args[0].includes(':')) {
7319
+ let ratio = args[0].split(':'),
7320
+ rW = Number(ratio[0]),
7321
+ rH = Number(ratio[1]),
7322
+ w = window.innerWidth,
7323
+ h = window.innerWidth * (rH / rW);
7324
+ if (h > window.innerHeight) {
7325
+ w = window.innerHeight * (rW / rH);
7326
+ h = window.innerHeight;
7327
+ }
7328
+ args[0] = Math.round(w);
7329
+ args.splice(1, 0, Math.round(h));
7330
+ } else {
7331
+ args = [0, 0, ...args];
7332
+ }
7333
+ }
7334
+ if (!args[0]) {
7335
+ args[0] = window.innerWidth;
7336
+ args[1] = window.innerHeight;
7337
+ }
7338
+ args[1] ??= args[0];
7339
+ args[0] = Math.floor(args[0] / 2) * 2;
7340
+ args[1] = Math.floor(args[1] / 2) * 2;
7341
+
7342
+ let rend = _createCanvas.call($, ...args);
7343
+
7344
+ if (rend instanceof Promise) {
7345
+ return rend.then((r) => {
7346
+ return q5playCanvas(r, args);
7347
+ });
7348
+ }
7349
+ return q5playCanvas(rend, args);
7350
+ };
7351
+
7309
7352
  $.canvas = $.canvas; // for brython
7310
7353
 
7311
7354
  const _resizeCanvas = $.resizeCanvas;
@@ -7392,6 +7435,8 @@ async function q5playPreSetup(q) {
7392
7435
  constructor(func, errorNum, e) {
7393
7436
  super();
7394
7437
 
7438
+ if ($.q5play.silent) return;
7439
+
7395
7440
  if (typeof func != 'string') {
7396
7441
  e = errorNum;
7397
7442
  errorNum = func;
@@ -7566,15 +7611,14 @@ async function q5playPreSetup(q) {
7566
7611
  mx = $.mouseX,
7567
7612
  my = $.mouseY;
7568
7613
 
7569
- if (using_p5) {
7570
- if ($._webgpuFallback) {
7571
- mx -= $.halfWidth;
7572
- my -= $.halfHeight;
7573
- }
7614
+ if (using_p5 && ($._webgpuFallback || $._webgl)) {
7615
+ mx -= $.halfWidth;
7616
+ my -= $.halfHeight;
7574
7617
  }
7575
7618
 
7576
- m.x = mx / cam.zoom + cam.x;
7577
- m.y = my / cam.zoom + cam.y;
7619
+ // divide by camera zoom and add camera translation
7620
+ m.x = mx / cam.zoom + cam.__pos.x;
7621
+ m.y = my / cam.zoom + cam.__pos.y;
7578
7622
 
7579
7623
  if (m.scroll < 0) m.scroll = 0;
7580
7624
  if (m.scrollDelta.x == 0 && m.scrollDelta.y == 0) {
@@ -8379,7 +8423,7 @@ async function q5playPreSetup(q) {
8379
8423
  */
8380
8424
  _update() {
8381
8425
  for (let c of this) {
8382
- if (c.connected) c._update();
8426
+ if (c?.connected) c._update();
8383
8427
  }
8384
8428
  }
8385
8429
  };
@@ -8497,29 +8541,19 @@ async function q5playPreSetup(q) {
8497
8541
  shapeStack = [];
8498
8542
 
8499
8543
  const colorMax = $._colorFormat,
8500
- debugGreen = $._q5 ? $.color(0, colorMax, 0, colorMax * 0.9) : 'lime',
8501
- debugGreenFill = $._q5 ? $.color(0, colorMax, 0, colorMax * 0.1) : 'lime',
8502
- debugYellow = $._q5 ? $.color(colorMax, colorMax, 0, colorMax * 0.9) : 'yellow',
8503
- debugYellowFill = $._q5 ? $.color(colorMax, colorMax, 0, colorMax * 0.1) : 'yellow';
8504
-
8505
- if (using_p5) {
8506
- $._getFillIdx = () => $._renderer.states.fillColor;
8507
- $._setFillIdx = (v) => $.fill(v);
8508
- $._getStrokeIdx = () => $._renderer.states.strokeColor;
8509
- $._setStrokeIdx = (v) => {
8510
- if ($._renderer.states.strokeSet) $.stroke(v);
8511
- };
8512
- $._getStrokeWeight = () => [$._renderer.states.strokeWeight];
8513
- $._setStrokeWeight = (v) => $.strokeWeight(...v);
8514
- $._getImageMode = () => $._renderer.states.imageMode;
8515
- } else if ($.canvas.c2d) {
8516
- // polyfill for q5 WebGPU high efficiency functions
8544
+ debugGreen = $._q5 ? $.color(0, colorMax, 0, colorMax * 0.9) : '#0f0e',
8545
+ debugGreenFill = $._q5 ? $.color(0, colorMax, 0, colorMax * 0.1) : '#0f02',
8546
+ debugYellow = $._q5 ? $.color(colorMax, colorMax, 0, colorMax * 0.9) : '#ff0e',
8547
+ debugYellowFill = $._q5 ? $.color(colorMax, colorMax, 0, colorMax * 0.1) : '#ff02';
8548
+
8549
+ // polyfills for q5 WebGPU high efficiency style changing functions
8550
+ if ($._c2d || $._webgpuFallback) {
8517
8551
  $._getFillIdx = () => $._fill;
8518
8552
  $._setFillIdx = (v) => ($._fill = v);
8519
8553
  $._getStrokeIdx = () => $._stroke;
8520
8554
  $._setStrokeIdx = (v) => ($._stroke = v);
8521
8555
  $._getStrokeWeight = () => [$._strokeWeight];
8522
- $._setStrokeWeight = (v) => $.strokeWeight(...v);
8556
+ $._setStrokeWeight = (v) => ($.ctx.lineWidth = $._strokeWeight = v[0]);
8523
8557
  }
8524
8558
 
8525
8559
  $._q5playDraw = () => {
@@ -8535,8 +8569,12 @@ async function q5playPreSetup(q) {
8535
8569
 
8536
8570
  let swData = $._getStrokeWeight();
8537
8571
  let ogSW = [...swData];
8538
- for (let i = 0; i < swData.length; i++) {
8539
- swData[i] /= meterSize;
8572
+ // if using q5 or p5's P2D mode
8573
+ // (in p5's WebGL and WebGPU modes, stroke weight doesn't scale)
8574
+ if ($._q5 || $._c2d || $._webgpuFallback) {
8575
+ for (let i = 0; i < swData.length; i++) {
8576
+ swData[i] /= meterSize;
8577
+ }
8540
8578
  }
8541
8579
  $._setStrokeWeight(swData);
8542
8580
 
@@ -8613,7 +8651,7 @@ async function q5playPreSetup(q) {
8613
8651
  transformPoint(xf, v);
8614
8652
  $.vertex(v.x, v.y);
8615
8653
  }
8616
- $.endShape(true);
8654
+ $.endShape($.CLOSE);
8617
8655
  if (rr > 0) {
8618
8656
  $._setStrokeWeight(swData);
8619
8657
  $._setStrokeIdx(ogStroke);
@@ -8659,7 +8697,7 @@ async function q5playPreSetup(q) {
8659
8697
  transformPoint(xf, v);
8660
8698
  $.vertex(v.x, v.y);
8661
8699
  }
8662
- $.endShape(true);
8700
+ $.endShape($.CLOSE);
8663
8701
  } else {
8664
8702
  let x = (cmd.data[0] + cmd.data[2]) / 2,
8665
8703
  y = (cmd.data[1] + cmd.data[3]) / 2;
@@ -8697,8 +8735,11 @@ async function q5playPreSetup(q) {
8697
8735
  if (ta) $.textAlign(ta.horizontal, ta.vertical);
8698
8736
  };
8699
8737
 
8738
+ // p5 won't run the draw loop unless a draw function is defined
8739
+ if (using_p5) window.draw ??= () => {};
8740
+
8700
8741
  // prettier-ignore
8701
- let q5playGlobals = ['q5play','Box2D','DYN','DYNAMIC','STA','STATIC','KIN','KINEMATIC','Sprite','Group','allSprites','Ani','Anis','Visual','Visuals','Joint','GlueJoint','DistanceJoint','WheelJoint','HingeJoint','SliderJoint','GrabberJoint','world','kb','keyboard','mouse','contro','contros','controllers','pointer','pointers','spriteArt','EmojiImage','getFPS','animation','parseTextureAtlas','delay'];
8742
+ let q5playGlobals = ['q5play','Box2D','Canvas','createCanvas','DYN','DYNAMIC','STA','STATIC','KIN','KINEMATIC','Sprite','Group','allSprites','Ani','Anis','Visual','Visuals','Joint','GlueJoint','DistanceJoint','WheelJoint','HingeJoint','SliderJoint','GrabberJoint','world','camera','kb','keyboard','mouse','contro','contros','controllers','pointer','pointers','spriteArt','EmojiImage','getFPS','animation','parseTextureAtlas','delay'];
8702
8743
 
8703
8744
  // manually propagate q5play stuff to the global window object
8704
8745
  if ($._isGlobal) {
@@ -8721,31 +8762,6 @@ function q5playPostSetup() {
8721
8762
 
8722
8763
  if ($._isGlobal && window.update) $.update = window.update;
8723
8764
 
8724
- if (using_p5) {
8725
- // p5 won't run the draw loop without a draw function defined
8726
- window.draw = () => {};
8727
-
8728
- $.loge = $.log;
8729
- $.log = console.log;
8730
- $.camera = $._camera;
8731
-
8732
- if ($._isGlobal) {
8733
- Object.defineProperty(window, 'log', {
8734
- value: console.log
8735
- });
8736
- Object.defineProperty(window, 'loge', {
8737
- value: $.loge
8738
- });
8739
- $.camera3D = window.camera;
8740
- Object.defineProperty(window, 'camera3D', {
8741
- value: $.camera3D
8742
- });
8743
- Object.defineProperty(window, 'camera', {
8744
- value: $.camera
8745
- });
8746
- }
8747
- }
8748
-
8749
8765
  $.update ??= $.clear;
8750
8766
 
8751
8767
  $._setupDone = true;
@@ -8755,11 +8771,6 @@ function q5playPostSetup() {
8755
8771
  function q5playUpdate() {
8756
8772
  const $ = this;
8757
8773
 
8758
- if (using_p5) {
8759
- $.q5play._preDrawFrameTime = performance.now();
8760
- $.resetMatrix();
8761
- }
8762
-
8763
8774
  $.q5play.spritesDrawn = 0;
8764
8775
 
8765
8776
  $.contros._update();
@@ -8902,10 +8913,6 @@ function q5playPostDraw() {
8902
8913
  else if ($.kb[k] > 0) $.kb[k]++;
8903
8914
  }
8904
8915
 
8905
- if (using_p5) {
8906
- $.q5play._postDrawFrameTime = performance.now();
8907
- $.q5play._fps = Math.round(1000 / ($.q5play._postDrawFrameTime - $.q5play._preDrawFrameTime)) || 1;
8908
- }
8909
8916
  $.q5play._inPostDraw = false;
8910
8917
  }
8911
8918
 
@@ -9111,58 +9118,16 @@ pressure -> es:presión
9111
9118
  };
9112
9119
  q5playClassLangs.Group += q5playClassLangs.Sprite;
9113
9120
 
9114
- if (typeof globalThis.Q5 == 'undefined') {
9115
- console.warn('p5.js v2 is not fully compatible with q5play. Consider using q5 instead: https://q5js.org');
9116
-
9117
- p5.addHook = (hook, fn) => {
9118
- p5.registerAddon((p5, proto, lifecycles) => {
9119
- lifecycles[hook] = fn;
9120
- });
9121
- };
9122
-
9123
- // p5.js v2 compatibility layer
9124
- globalThis.Canvas = (...args) => {
9125
- return new Promise((resolve) => {
9126
- window.setup = async function () {
9127
- const $ = p5.instance;
9128
- $._webgpu = $._webgpuFallback = true;
9129
-
9130
- $.Canvas(...args);
9131
-
9132
- // q5play defaults
9133
- colorMode(RGB, 1);
9134
- imageMode(CENTER);
9135
-
9136
- $.halfWidth = width / 2;
9137
- $.halfHeight = height / 2;
9138
-
9139
- let _resetMatrix = $.resetMatrix;
9140
-
9141
- $.resetMatrix = () => {
9142
- _resetMatrix.call($);
9143
- $.translate($.halfWidth, $.halfHeight);
9144
- };
9145
-
9146
- Object.defineProperty(p5, 'update', {
9147
- set(fn) {
9148
- $.update = fn;
9149
- },
9150
- get() {
9151
- return $.update;
9152
- },
9153
- configurable: true
9154
- });
9155
-
9156
- resolve();
9157
- };
9158
- });
9159
- };
9160
-
9161
- globalThis.Q5 = globalThis.q5 = p5;
9162
- }
9121
+ globalThis.Canvas ??= () => {
9122
+ p5._friendlyError(`Visit https://github.com/q5play/p5-compat to learn how to use q5play with p5.js`);
9123
+ throw new Error();
9124
+ };
9163
9125
 
9164
- Q5.addHook('presetup', q5playPreSetup);
9165
- Q5.addHook('postsetup', q5playPostSetup);
9166
- Q5.addHook('predraw', q5playUpdate);
9167
- Q5.addHook('postdraw', q5playPostDraw);
9168
- Q5.addHook('remove', q5playRemove);
9126
+ (p5 || Q5).registerAddon((_, __, l) => {
9127
+ // add lifecycle hooks for q5play
9128
+ l.presetup = q5playPreSetup;
9129
+ l.postsetup = q5playPostSetup;
9130
+ l.predraw = q5playUpdate;
9131
+ l.postdraw = q5playPostDraw;
9132
+ l.remove = q5playRemove;
9133
+ });
package/q5play.pyi CHANGED
@@ -60,6 +60,18 @@ class Q5Play:
60
60
 
61
61
  standardizeKeyboard: bool
62
62
 
63
+ silent: bool
64
+ """
65
+ Set to true to disable q5play's console logs, warnings, and error messages.
66
+ Severe errors will still be thrown.
67
+ """
68
+
69
+ quiet: bool
70
+ """
71
+ Set to true to disable q5play's console logs.
72
+ Warnings and errors will still be shown, and severe errors will still be thrown.
73
+ """
74
+
63
75
  renderStats: bool
64
76
  """
65
77
  Displays the version of q5play being used,