q5 2.9.21 → 2.9.22

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/src/q5-2d-text.js CHANGED
@@ -36,6 +36,7 @@ Q5.renderers.q2d.text = ($, q) => {
36
36
  fontMod = true;
37
37
  styleHash = -1;
38
38
  };
39
+
39
40
  $.textSize = (x) => {
40
41
  if (x == undefined || x == $._textSize) return $._textSize;
41
42
  if ($._da) x *= $._da;
@@ -47,12 +48,14 @@ Q5.renderers.q2d.text = ($, q) => {
47
48
  leadDiff = leading - x;
48
49
  }
49
50
  };
51
+
50
52
  $.textStyle = (x) => {
51
53
  if (!x || x == emphasis) return emphasis;
52
54
  emphasis = x;
53
55
  fontMod = true;
54
56
  styleHash = -1;
55
57
  };
58
+
56
59
  $.textLeading = (x) => {
57
60
  leadingSet = true;
58
61
  if (x == undefined || x == leading) return leading;
@@ -61,6 +64,7 @@ Q5.renderers.q2d.text = ($, q) => {
61
64
  leadDiff = x - $._textSize;
62
65
  styleHash = -1;
63
66
  };
67
+
64
68
  $.textAlign = (horiz, vert) => {
65
69
  $.ctx.textAlign = $._textAlign = horiz;
66
70
  if (vert) {
@@ -90,6 +94,7 @@ Q5.renderers.q2d.text = ($, q) => {
90
94
  if (enable !== undefined) useCache = enable;
91
95
  return useCache;
92
96
  };
97
+
93
98
  $.createTextImage = (str, w, h) => {
94
99
  genTextImage = true;
95
100
  img = $.text(str, 0, 0, w, h);
@@ -98,6 +103,7 @@ Q5.renderers.q2d.text = ($, q) => {
98
103
  };
99
104
 
100
105
  let lines = [];
106
+
101
107
  $.text = (str, x, y, w, h) => {
102
108
  if (str === undefined || (!$._doFill && !$._doStroke)) return;
103
109
  str = str.toString();
@@ -223,6 +229,7 @@ Q5.renderers.q2d.text = ($, q) => {
223
229
  $.textImage(img, x, y);
224
230
  }
225
231
  };
232
+
226
233
  $.textImage = (img, x, y) => {
227
234
  if (typeof img == 'string') img = $.createTextImage(img);
228
235
 
package/src/q5-canvas.js CHANGED
@@ -146,7 +146,7 @@ Q5.modules.canvas = ($, q) => {
146
146
  return g;
147
147
  };
148
148
 
149
- $._save = async (data, name, ext) => {
149
+ async function saveFile(data, name, ext) {
150
150
  name = name || 'untitled';
151
151
  ext = ext || 'png';
152
152
  if (ext == 'jpg' || ext == 'png' || ext == 'webp') {
@@ -174,18 +174,19 @@ Q5.modules.canvas = ($, q) => {
174
174
  a.download = name + '.' + ext;
175
175
  a.click();
176
176
  URL.revokeObjectURL(a.href);
177
- };
177
+ }
178
+
178
179
  $.save = (a, b, c) => {
179
180
  if (!a || (typeof a == 'string' && (!b || (!c && b.length < 5)))) {
180
181
  c = b;
181
182
  b = a;
182
183
  a = $.canvas;
183
184
  }
184
- if (c) return $._save(a, b, c);
185
+ if (c) return saveFile(a, b, c);
185
186
  if (b) {
186
187
  b = b.split('.');
187
- $._save(a, b[0], b.at(-1));
188
- } else $._save(a);
188
+ saveFile(a, b[0], b.at(-1));
189
+ } else saveFile(a);
189
190
  };
190
191
 
191
192
  $._setCanvasSize = (w, h) => {
package/src/q5-color.js CHANGED
@@ -146,6 +146,7 @@ Q5.Color = class {
146
146
  this._q5Color = true;
147
147
  }
148
148
  };
149
+
149
150
  Q5.ColorOKLCH = class extends Q5.Color {
150
151
  constructor(l, c, h, a) {
151
152
  super();
@@ -158,6 +159,7 @@ Q5.ColorOKLCH = class extends Q5.Color {
158
159
  return `oklch(${this.l} ${this.c} ${this.h} / ${this.a})`;
159
160
  }
160
161
  };
162
+
161
163
  Q5.ColorRGBA = class extends Q5.Color {
162
164
  constructor(r, g, b, a) {
163
165
  super();
@@ -173,11 +175,13 @@ Q5.ColorRGBA = class extends Q5.Color {
173
175
  return `color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`;
174
176
  }
175
177
  };
178
+
176
179
  Q5.ColorRGBA_P3 = class extends Q5.ColorRGBA {
177
180
  toString() {
178
181
  return `color(display-p3 ${this.r} ${this.g} ${this.b} / ${this.a})`;
179
182
  }
180
183
  };
184
+
181
185
  // legacy 8-bit (0-255) integer color format
182
186
  Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
183
187
  constructor(r, g, b, a) {
@@ -202,6 +206,7 @@ Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
202
206
  return `rgb(${this.r} ${this.g} ${this.b} / ${this.a / 255})`;
203
207
  }
204
208
  };
209
+
205
210
  // p3 10-bit color in integer color format, for backwards compatibility
206
211
  Q5.ColorRGBA_P3_8 = class extends Q5.ColorRGBA {
207
212
  constructor(r, g, b, a) {
package/src/q5-input.js CHANGED
@@ -59,6 +59,7 @@ Q5.modules.input = ($, q) => {
59
59
  q.moveX = e.movementX;
60
60
  q.moveY = e.movementY;
61
61
  };
62
+
62
63
  $._onmousedown = (e) => {
63
64
  $._startAudio();
64
65
  $._updateMouse(e);
@@ -66,22 +67,26 @@ Q5.modules.input = ($, q) => {
66
67
  q.mouseButton = mouseBtns[e.button];
67
68
  $.mousePressed(e);
68
69
  };
70
+
69
71
  $._onmousemove = (e) => {
70
72
  $._updateMouse(e);
71
73
  if ($.mouseIsPressed) $.mouseDragged(e);
72
74
  else $.mouseMoved(e);
73
75
  };
76
+
74
77
  $._onmouseup = (e) => {
75
78
  $._updateMouse(e);
76
79
  q.mouseIsPressed = false;
77
80
  $.mouseReleased(e);
78
81
  };
82
+
79
83
  $._onclick = (e) => {
80
84
  $._updateMouse(e);
81
85
  q.mouseIsPressed = true;
82
86
  $.mouseClicked(e);
83
87
  q.mouseIsPressed = false;
84
88
  };
89
+
85
90
  $._onwheel = (e) => {
86
91
  $._updateMouse(e);
87
92
  e.delta = e.deltaY;
@@ -99,9 +104,11 @@ Q5.modules.input = ($, q) => {
99
104
  }
100
105
  $.canvas.style.cursor = name + pfx;
101
106
  };
107
+
102
108
  $.noCursor = () => {
103
109
  $.canvas.style.cursor = 'none';
104
110
  };
111
+
105
112
  if (window) {
106
113
  $.requestPointerLock = document.body?.requestPointerLock;
107
114
  $.exitPointerLock = document.exitPointerLock;
@@ -117,6 +124,7 @@ Q5.modules.input = ($, q) => {
117
124
  $.keyPressed(e);
118
125
  if (e.key.length == 1) $.keyTyped(e);
119
126
  };
127
+
120
128
  $._onkeyup = (e) => {
121
129
  q.keyIsPressed = false;
122
130
  q.key = e.key;
@@ -124,6 +132,7 @@ Q5.modules.input = ($, q) => {
124
132
  keysHeld[$.keyCode] = keysHeld[$.key.toLowerCase()] = false;
125
133
  $.keyReleased(e);
126
134
  };
135
+
127
136
  $.keyIsDown = (v) => !!keysHeld[typeof v == 'string' ? v.toLowerCase() : v];
128
137
 
129
138
  function getTouchInfo(touch) {
@@ -136,6 +145,7 @@ Q5.modules.input = ($, q) => {
136
145
  id: touch.identifier
137
146
  };
138
147
  }
148
+
139
149
  $._ontouchstart = (e) => {
140
150
  $._startAudio();
141
151
  q.touches = [...e.touches].map(getTouchInfo);
@@ -148,6 +158,7 @@ Q5.modules.input = ($, q) => {
148
158
  }
149
159
  if (!$.touchStarted(e)) e.preventDefault();
150
160
  };
161
+
151
162
  $._ontouchmove = (e) => {
152
163
  q.touches = [...e.touches].map(getTouchInfo);
153
164
  if (!$._isTouchAware) {
@@ -157,6 +168,7 @@ Q5.modules.input = ($, q) => {
157
168
  }
158
169
  if (!$.touchMoved(e)) e.preventDefault();
159
170
  };
171
+
160
172
  $._ontouchend = (e) => {
161
173
  q.touches = [...e.touches].map(getTouchInfo);
162
174
  if (!$._isTouchAware && !$.touches.length) {
package/src/q5-math.js CHANGED
@@ -42,13 +42,15 @@ Q5.modules.math = ($, q) => {
42
42
  return Math.min(Math.max(val, ostop), ostart);
43
43
  }
44
44
  };
45
- $.lerp = (a, b, t) => a * (1 - t) + b * t;
46
- $.constrain = (x, lo, hi) => Math.min(Math.max(x, lo), hi);
45
+
47
46
  $.dist = function () {
48
47
  let a = arguments;
49
48
  if (a.length == 4) return Math.hypot(a[0] - a[2], a[1] - a[3]);
50
49
  else return Math.hypot(a[0] - a[3], a[1] - a[4], a[2] - a[5]);
51
50
  };
51
+
52
+ $.lerp = (a, b, t) => a * (1 - t) + b * t;
53
+ $.constrain = (x, lo, hi) => Math.min(Math.max(x, lo), hi);
52
54
  $.norm = (value, start, stop) => $.map(value, start, stop, 0, 1);
53
55
  $.sq = (x) => x * x;
54
56
  $.fract = (x) => x - Math.floor(x);
@@ -69,7 +71,6 @@ Q5.modules.math = ($, q) => {
69
71
  let a = Math.atan(x);
70
72
  return !angleMode ? a : a * RADTODEG;
71
73
  };
72
-
73
74
  $.atan2 = (y, x) => {
74
75
  let a = Math.atan2(y, x);
75
76
  return !angleMode ? a : a * RADTODEG;
@@ -93,6 +94,7 @@ Q5.modules.math = ($, q) => {
93
94
  }
94
95
  };
95
96
  }
97
+
96
98
  function shr3() {
97
99
  let jsr, seed;
98
100
  let m = 4294967295;
@@ -111,6 +113,7 @@ Q5.modules.math = ($, q) => {
111
113
  }
112
114
  };
113
115
  }
116
+
114
117
  let rng1 = shr3();
115
118
  rng1.setSeed();
116
119
 
@@ -127,6 +130,7 @@ Q5.modules.math = ($, q) => {
127
130
  return a[Math.trunc(a.length * rng1.rand())];
128
131
  }
129
132
  };
133
+
130
134
  $.randomGenerator = (method) => {
131
135
  if (method == $.LCG) rng1 = lcg();
132
136
  else if (method == $.SHR3) rng1 = shr3();
@@ -282,13 +286,16 @@ Q5.modules.math = ($, q) => {
282
286
  q.Noise = Q5[mode[0].toUpperCase() + mode.slice(1) + 'Noise'];
283
287
  _noise = null;
284
288
  };
289
+
285
290
  $.noiseSeed = (seed) => {
286
291
  _noise = new $.Noise(seed);
287
292
  };
293
+
288
294
  $.noise = (x = 0, y = 0, z = 0) => {
289
295
  _noise ??= new $.Noise();
290
296
  return _noise.noise(x, y, z);
291
297
  };
298
+
292
299
  $.noiseDetail = (lod, falloff) => {
293
300
  _noise ??= new $.Noise();
294
301
  if (lod > 0) _noise.octaves = lod;
@@ -0,0 +1,2 @@
1
+ /* help wanted! */
2
+ Q5.modules.record = ($) => {};
package/src/q5-vector.js CHANGED
@@ -11,15 +11,18 @@ Q5.Vector = class {
11
11
  this._cn = null;
12
12
  this._cnsq = null;
13
13
  }
14
+
14
15
  set(x, y, z) {
15
16
  this.x = x?.x || x || 0;
16
17
  this.y = x?.y || y || 0;
17
18
  this.z = x?.z || z || 0;
18
19
  return this;
19
20
  }
21
+
20
22
  copy() {
21
23
  return new Q5.Vector(this.x, this.y, this.z);
22
24
  }
25
+
23
26
  _arg2v(x, y, z) {
24
27
  if (x?.x !== undefined) return x;
25
28
  if (y !== undefined) {
@@ -27,10 +30,12 @@ Q5.Vector = class {
27
30
  }
28
31
  return { x: x, y: x, z: x };
29
32
  }
33
+
30
34
  _calcNorm() {
31
35
  this._cnsq = this.x * this.x + this.y * this.y + this.z * this.z;
32
36
  this._cn = Math.sqrt(this._cnsq);
33
37
  }
38
+
34
39
  add() {
35
40
  let u = this._arg2v(...arguments);
36
41
  this.x += u.x;
@@ -38,6 +43,7 @@ Q5.Vector = class {
38
43
  this.z += u.z;
39
44
  return this;
40
45
  }
46
+
41
47
  rem() {
42
48
  let u = this._arg2v(...arguments);
43
49
  this.x %= u.x;
@@ -45,6 +51,7 @@ Q5.Vector = class {
45
51
  this.z %= u.z;
46
52
  return this;
47
53
  }
54
+
48
55
  sub() {
49
56
  let u = this._arg2v(...arguments);
50
57
  this.x -= u.x;
@@ -52,6 +59,7 @@ Q5.Vector = class {
52
59
  this.z -= u.z;
53
60
  return this;
54
61
  }
62
+
55
63
  mult() {
56
64
  let u = this._arg2v(...arguments);
57
65
  this.x *= u.x;
@@ -59,6 +67,7 @@ Q5.Vector = class {
59
67
  this.z *= u.z;
60
68
  return this;
61
69
  }
70
+
62
71
  div() {
63
72
  let u = this._arg2v(...arguments);
64
73
  if (u.x) this.x /= u.x;
@@ -69,18 +78,22 @@ Q5.Vector = class {
69
78
  else this.z = 0;
70
79
  return this;
71
80
  }
81
+
72
82
  mag() {
73
83
  this._calcNorm();
74
84
  return this._cn;
75
85
  }
86
+
76
87
  magSq() {
77
88
  this._calcNorm();
78
89
  return this._cnsq;
79
90
  }
91
+
80
92
  dot() {
81
93
  let u = this._arg2v(...arguments);
82
94
  return this.x * u.x + this.y * u.y + this.z * u.z;
83
95
  }
96
+
84
97
  dist() {
85
98
  let u = this._arg2v(...arguments);
86
99
  let x = this.x - u.x;
@@ -88,6 +101,7 @@ Q5.Vector = class {
88
101
  let z = this.z - u.z;
89
102
  return Math.sqrt(x * x + y * y + z * z);
90
103
  }
104
+
91
105
  cross() {
92
106
  let u = this._arg2v(...arguments);
93
107
  let x = this.y * u.z - this.z * u.y;
@@ -98,6 +112,7 @@ Q5.Vector = class {
98
112
  this.z = z;
99
113
  return this;
100
114
  }
115
+
101
116
  normalize() {
102
117
  this._calcNorm();
103
118
  let n = this._cn;
@@ -110,6 +125,7 @@ Q5.Vector = class {
110
125
  this._cnsq = 1;
111
126
  return this;
112
127
  }
128
+
113
129
  limit(m) {
114
130
  this._calcNorm();
115
131
  let n = this._cn;
@@ -123,6 +139,7 @@ Q5.Vector = class {
123
139
  }
124
140
  return this;
125
141
  }
142
+
126
143
  setMag(m) {
127
144
  this._calcNorm();
128
145
  let n = this._cn;
@@ -134,15 +151,18 @@ Q5.Vector = class {
134
151
  this._cnsq = m * m;
135
152
  return this;
136
153
  }
154
+
137
155
  heading() {
138
156
  return this._$.atan2(this.y, this.x);
139
157
  }
158
+
140
159
  setHeading(ang) {
141
160
  let mag = this.mag();
142
161
  this.x = mag * this._$.cos(ang);
143
162
  this.y = mag * this._$.sin(ang);
144
163
  return this;
145
164
  }
165
+
146
166
  rotate(ang) {
147
167
  let costh = this._$.cos(ang);
148
168
  let sinth = this._$.sin(ang);
@@ -152,12 +172,14 @@ Q5.Vector = class {
152
172
  this.y = vy;
153
173
  return this;
154
174
  }
175
+
155
176
  angleBetween() {
156
177
  let u = this._arg2v(...arguments);
157
178
  let o = Q5.Vector.cross(this, u);
158
179
  let ang = this._$.atan2(o.mag(), this.dot(u));
159
180
  return ang * Math.sign(o.z || 1);
160
181
  }
182
+
161
183
  lerp() {
162
184
  let args = [...arguments];
163
185
  let amt = args.at(-1);
@@ -168,6 +190,7 @@ Q5.Vector = class {
168
190
  this.z += (u.z - this.z) * amt;
169
191
  return this;
170
192
  }
193
+
171
194
  slerp() {
172
195
  let args = [...arguments];
173
196
  let amt = args.at(-1);
@@ -206,17 +229,21 @@ Q5.Vector = class {
206
229
  this.z = this.z * cosMultiplier + ey.z * sinMultiplier;
207
230
  return this;
208
231
  }
232
+
209
233
  reflect(n) {
210
234
  n.normalize();
211
235
  return this.sub(n.mult(2 * this.dot(n)));
212
236
  }
237
+
213
238
  array() {
214
239
  return [this.x, this.y, this.z];
215
240
  }
241
+
216
242
  equals(u, epsilon) {
217
243
  epsilon ??= Number.EPSILON || 0;
218
244
  return Math.abs(u.x - this.x) < epsilon && Math.abs(u.y - this.y) < epsilon && Math.abs(u.z - this.z) < epsilon;
219
245
  }
246
+
220
247
  fromAngle(th, l) {
221
248
  if (l === undefined) l = 1;
222
249
  this._cn = l;
@@ -226,6 +253,7 @@ Q5.Vector = class {
226
253
  this.z = 0;
227
254
  return this;
228
255
  }
256
+
229
257
  fromAngles(th, ph, l) {
230
258
  if (l === undefined) l = 1;
231
259
  this._cn = l;
@@ -239,18 +267,22 @@ Q5.Vector = class {
239
267
  this.z = l * sinth * cosph;
240
268
  return this;
241
269
  }
270
+
242
271
  random2D() {
243
272
  this._cn = this._cnsq = 1;
244
273
  return this.fromAngle(Math.random() * Math.PI * 2);
245
274
  }
275
+
246
276
  random3D() {
247
277
  this._cn = this._cnsq = 1;
248
278
  return this.fromAngles(Math.random() * Math.PI * 2, Math.random() * Math.PI * 2);
249
279
  }
280
+
250
281
  toString() {
251
282
  return `[${this.x}, ${this.y}, ${this.z}]`;
252
283
  }
253
284
  };
285
+
254
286
  Q5.Vector.add = (v, u) => v.copy().add(u);
255
287
  Q5.Vector.cross = (v, u) => v.copy().cross(u);
256
288
  Q5.Vector.dist = (v, u) => Math.hypot(v.x - u.x, v.y - u.y, v.z - u.z);
@@ -267,6 +299,7 @@ Q5.Vector.mult = (v, u) => v.copy().mult(u);
267
299
  Q5.Vector.normalize = (v) => v.copy().normalize();
268
300
  Q5.Vector.rem = (v, u) => v.copy().rem(u);
269
301
  Q5.Vector.sub = (v, u) => v.copy().sub(u);
302
+
270
303
  for (let k of ['fromAngle', 'fromAngles', 'random2D', 'random3D']) {
271
304
  Q5.Vector[k] = (u, v, t) => new Q5.Vector()[k](u, v, t);
272
305
  }
@@ -314,6 +314,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
314
314
  if ($._matrixDirty) $._saveMatrix();
315
315
  $._transformIndexStack.push($._transformIndex);
316
316
  };
317
+
317
318
  $.popMatrix = () => {
318
319
  if (!$._transformIndexStack.length) {
319
320
  return console.warn('Matrix index stack is empty!');
@@ -329,6 +330,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
329
330
  $.pushMatrix();
330
331
  $.pushStyles();
331
332
  };
333
+
332
334
  $.pop = () => {
333
335
  $.popMatrix();
334
336
  $.popStyles();
@@ -410,6 +412,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
410
412
  }
411
413
 
412
414
  $._blendMode = 'normal';
415
+
413
416
  $.blendMode = (mode) => {
414
417
  if (mode == $._blendMode) return;
415
418
  if (mode == 'source-over') mode = 'normal';
@@ -114,6 +114,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
114
114
  mipmapFilter: 'linear',
115
115
  maxAnisotropy: 16
116
116
  });
117
+
117
118
  let fontBindGroupLayout = Q5.device.createBindGroupLayout({
118
119
  label: 'MSDF font group layout',
119
120
  entries: [
@@ -151,6 +152,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
151
152
  primitive: { topology: 'triangle-strip', stripIndexFormat: 'uint32' },
152
153
  multisample: { count: 4 }
153
154
  };
155
+
154
156
  $._pipelines[2] = Q5.device.createRenderPipeline($._pipelineConfigs[2]);
155
157
 
156
158
  class MsdfFont {
@@ -299,6 +301,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
299
301
  $.textFont = (fontName) => {
300
302
  $._font = fonts[fontName];
301
303
  };
304
+
302
305
  $.textSize = (size) => {
303
306
  $._textSize = size;
304
307
  if (!leadingSet) {
@@ -306,12 +309,14 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
306
309
  leadDiff = leading - size;
307
310
  }
308
311
  };
312
+
309
313
  $.textLeading = (lineHeight) => {
310
314
  $._font.lineHeight = leading = lineHeight;
311
315
  leadDiff = leading - $._textSize;
312
316
  leadPercent = leading / $._textSize;
313
317
  leadingSet = true;
314
318
  };
319
+
315
320
  $.textAlign = (horiz, vert) => {
316
321
  $._textAlign = horiz;
317
322
  if (vert) $._textBaseline = vert;