q5 2.0.15 → 2.1.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.
@@ -0,0 +1,200 @@
1
+ Q5.modules.canvas = ($, q) => {
2
+ $._OffscreenCanvas =
3
+ window.OffscreenCanvas ||
4
+ function () {
5
+ return document.createElement('canvas');
6
+ };
7
+
8
+ if (Q5._nodejs) {
9
+ if (Q5._createNodeJSCanvas) {
10
+ q.canvas = Q5._createNodeJSCanvas(100, 100);
11
+ }
12
+ } else if ($._scope == 'image' || $._scope == 'graphics') {
13
+ q.canvas = new $._OffscreenCanvas(100, 100);
14
+ }
15
+
16
+ if (!$.canvas) {
17
+ if (typeof document == 'object') {
18
+ q.canvas = document.createElement('canvas');
19
+ $.canvas.id = 'q5Canvas' + Q5._instanceCount;
20
+ $.canvas.classList.add('q5Canvas');
21
+ } else $.noCanvas();
22
+ }
23
+
24
+ let c = $.canvas;
25
+ c.width = $.width = 100;
26
+ c.height = $.height = 100;
27
+ if ($._scope != 'image') {
28
+ c.renderer = $._renderer;
29
+ c[$._renderer] = true;
30
+ }
31
+ $._pixelDensity = 1;
32
+
33
+ $._adjustDisplay = () => {
34
+ if (c.style) {
35
+ c.style.width = c.w + 'px';
36
+ c.style.height = c.h + 'px';
37
+ }
38
+ };
39
+
40
+ $.createCanvas = function (w, h, options) {
41
+ options ??= arguments[3];
42
+
43
+ let opt = Object.assign({}, Q5.canvasOptions);
44
+ if (typeof options == 'object') Object.assign(opt, options);
45
+
46
+ if ($._scope != 'image') {
47
+ let pd = $.displayDensity();
48
+ if ($._scope == 'graphics') pd = this._pixelDensity;
49
+ else if (window.IntersectionObserver) {
50
+ new IntersectionObserver((e) => {
51
+ c.visible = e[0].isIntersecting;
52
+ }).observe(c);
53
+ }
54
+ $._pixelDensity = Math.ceil(pd);
55
+ }
56
+
57
+ $._setCanvasSize(w, h);
58
+
59
+ Object.assign(c, opt);
60
+ let rend = $._createCanvas(c.w, c.h, opt);
61
+
62
+ if ($._hooks) {
63
+ for (let m of $._hooks.postCanvas) m();
64
+ }
65
+ return rend;
66
+ };
67
+
68
+ $._save = async (data, name, ext) => {
69
+ name = name || 'untitled';
70
+ ext = ext || 'png';
71
+ if (ext == 'jpg' || ext == 'png' || ext == 'webp') {
72
+ if (data instanceof OffscreenCanvas) {
73
+ const blob = await data.convertToBlob({ type: 'image/' + ext });
74
+ data = await new Promise((resolve) => {
75
+ const reader = new FileReader();
76
+ reader.onloadend = () => resolve(reader.result);
77
+ reader.readAsDataURL(blob);
78
+ });
79
+ } else {
80
+ data = data.toDataURL('image/' + ext);
81
+ }
82
+ } else {
83
+ let type = 'text/plain';
84
+ if (ext == 'json') {
85
+ if (typeof data != 'string') data = JSON.stringify(data);
86
+ type = 'text/json';
87
+ }
88
+ data = new Blob([data], { type });
89
+ data = URL.createObjectURL(data);
90
+ }
91
+ let a = document.createElement('a');
92
+ a.href = data;
93
+ a.download = name + '.' + ext;
94
+ a.click();
95
+ URL.revokeObjectURL(a.href);
96
+ };
97
+ $.save = (a, b, c) => {
98
+ if (!a || (typeof a == 'string' && (!b || (!c && b.length < 5)))) {
99
+ c = b;
100
+ b = a;
101
+ a = $.canvas;
102
+ }
103
+ if (c) return $._save(a, b, c);
104
+ if (b) {
105
+ b = b.split('.');
106
+ $._save(a, b[0], b.at(-1));
107
+ } else $._save(a);
108
+ };
109
+
110
+ $._setCanvasSize = (w, h) => {
111
+ w ??= window.innerWidth;
112
+ h ??= window.innerHeight;
113
+ c.w = w = Math.ceil(w);
114
+ c.h = h = Math.ceil(h);
115
+ c.hw = w / 2;
116
+ c.hh = h / 2;
117
+ c.width = Math.ceil(w * $._pixelDensity);
118
+ c.height = Math.ceil(h * $._pixelDensity);
119
+
120
+ if (!$._da) {
121
+ q.width = w;
122
+ q.height = h;
123
+ } else $.flexibleCanvas($._dau);
124
+
125
+ if ($.displayMode && !c.displayMode) $.displayMode();
126
+ else $._adjustDisplay();
127
+ };
128
+
129
+ if ($._scope == 'image') return;
130
+
131
+ if (c && $._scope != 'graphics') {
132
+ c.parent = (el) => {
133
+ if (c.parentElement) c.parentElement.removeChild(c);
134
+
135
+ if (typeof el == 'string') el = document.getElementById(el);
136
+ el.append(c);
137
+
138
+ function parentResized() {
139
+ if ($.frameCount > 1) {
140
+ $._shouldResize = true;
141
+ $._adjustDisplay();
142
+ }
143
+ }
144
+ if (typeof ResizeObserver == 'function') {
145
+ if ($._ro) $._ro.disconnect();
146
+ $._ro = new ResizeObserver(parentResized);
147
+ $._ro.observe(el);
148
+ } else if (!$.frameCount) {
149
+ window.addEventListener('resize', parentResized);
150
+ }
151
+ };
152
+
153
+ function addCanvas() {
154
+ let el = $._parent;
155
+ el ??= document.getElementsByTagName('main')[0];
156
+ if (!el) {
157
+ el = document.createElement('main');
158
+ document.body.append(el);
159
+ }
160
+ c.parent(el);
161
+ }
162
+ if (document.body) addCanvas();
163
+ else document.addEventListener('DOMContentLoaded', addCanvas);
164
+ }
165
+
166
+ $.resizeCanvas = (w, h) => {
167
+ if (!$.ctx) return $.createCanvas(w, h);
168
+ if (w == c.w && h == c.h) return;
169
+
170
+ $._resizeCanvas(w, h);
171
+ };
172
+
173
+ $.canvas.resize = $.resizeCanvas;
174
+ $.canvas.save = $.saveCanvas = $.save;
175
+
176
+ $.displayDensity = () => window.devicePixelRatio;
177
+ $.pixelDensity = (v) => {
178
+ if (!v || v == $._pixelDensity) return $._pixelDensity;
179
+ $._pixelDensity = v;
180
+ $._setCanvasSize(c.w, c.h);
181
+ return v;
182
+ };
183
+
184
+ $.flexibleCanvas = (unit = 400) => {
185
+ if (unit) {
186
+ $._da = c.width / (unit * $._pixelDensity);
187
+ q.width = $._dau = unit;
188
+ q.height = (c.h / c.w) * unit;
189
+ } else $._da = 0;
190
+ };
191
+ };
192
+
193
+ Q5.canvasOptions = {
194
+ alpha: false,
195
+ colorSpace: 'display-p3'
196
+ };
197
+
198
+ if (!window.matchMedia || !matchMedia('(dynamic-range: high) and (color-gamut: p3)').matches) {
199
+ Q5.canvasOptions.colorSpace = 'srgb';
200
+ } else Q5.supportsHDR = true;
package/src/q5-color.js CHANGED
@@ -1,19 +1,21 @@
1
- Q5.modules.color = ($, p) => {
1
+ Q5.modules.color = ($, q) => {
2
2
  $.RGB = $.RGBA = $._colorMode = 'rgb';
3
3
  $.OKLCH = 'oklch';
4
4
 
5
- if (Q5.supportsHDR) $.Color = Q5.ColorRGBA_P3;
6
- else $.Color = Q5.ColorRGBA;
7
-
8
- $.colorMode = (mode) => {
5
+ $.colorMode = (mode, format) => {
9
6
  $._colorMode = mode;
7
+ let srgb = $.canvas.colorSpace == 'srgb' || mode == 'srgb';
8
+ format ??= srgb ? 'integer' : 'float';
9
+ $._colorFormat = format;
10
10
  if (mode == 'oklch') {
11
- p.Color = Q5.ColorOKLCH;
12
- } else if (mode == 'rgb') {
13
- if ($.canvas.colorSpace == 'srgb') p.Color = Q5.ColorRGBA;
14
- else p.Color = Q5.ColorRGBA_P3;
15
- } else if (mode == 'srgb') {
16
- p.Color = Q5.ColorRGBA;
11
+ q.Color = Q5.ColorOKLCH;
12
+ } else {
13
+ let srgb = $.canvas.colorSpace == 'srgb';
14
+ if ($._colorFormat == 'integer') {
15
+ q.Color = srgb ? Q5.ColorRGBA_8 : Q5.ColorRGBA_P3_8;
16
+ } else {
17
+ q.Color = srgb ? Q5.ColorRGBA : Q5.ColorRGBA_P3;
18
+ }
17
19
  $._colorMode = 'rgb';
18
20
  }
19
21
  };
@@ -58,27 +60,33 @@ Q5.modules.color = ($, p) => {
58
60
  let args = arguments;
59
61
  if (args.length == 1) {
60
62
  if (typeof c0 == 'string') {
63
+ let r, g, b, a;
61
64
  if (c0[0] == '#') {
62
65
  if (c0.length <= 5) {
63
- return new C(
64
- parseInt(c0[1] + c0[1], 16),
65
- parseInt(c0[2] + c0[2], 16),
66
- parseInt(c0[3] + c0[3], 16),
67
- c0.length == 4 ? null : parseInt(c0[4] + c0[4], 16)
68
- );
66
+ r = parseInt(c0[1] + c0[1], 16);
67
+ g = parseInt(c0[2] + c0[2], 16);
68
+ b = parseInt(c0[3] + c0[3], 16);
69
+ a = c0.length == 4 ? null : parseInt(c0[4] + c0[4], 16);
70
+ } else {
71
+ r = parseInt(c0.slice(1, 3), 16);
72
+ g = parseInt(c0.slice(3, 5), 16);
73
+ b = parseInt(c0.slice(5, 7), 16);
74
+ a = c0.length == 7 ? null : parseInt(c0.slice(7, 9), 16);
69
75
  }
70
- return new C(
71
- parseInt(c0.slice(1, 3), 16),
72
- parseInt(c0.slice(3, 5), 16),
73
- parseInt(c0.slice(5, 7), 16),
74
- c0.length == 7 ? null : parseInt(c0.slice(7, 9), 16)
76
+ } else if ($._namedColors[c0]) [r, g, b] = $._namedColors[c0];
77
+ else {
78
+ console.error(
79
+ "q5 can't parse color: " + c0 + '\nOnly numeric input, hex, and common named colors are supported.'
75
80
  );
81
+ return new C(0, 0, 0);
76
82
  }
77
- if ($._namedColors[c0]) return new C(...$._namedColors[c0]);
78
- console.error(
79
- "q5 can't parse color: " + c0 + '\nOnly numeric input, hex, and common named colors are supported.'
80
- );
81
- return new C(0, 0, 0);
83
+ if ($._colorFormat != 'integer') {
84
+ r /= 255;
85
+ g /= 255;
86
+ b /= 255;
87
+ if (a != null) a /= 255;
88
+ }
89
+ return new C(r, g, b, a);
82
90
  }
83
91
  if (Array.isArray(c0)) return new C(...c0);
84
92
  }
@@ -148,7 +156,24 @@ Q5.ColorRGBA = class extends Q5.Color {
148
156
  this.r = r;
149
157
  this.g = g;
150
158
  this.b = b;
151
- this.a = a ?? 255;
159
+ this.a = a ?? 1;
160
+ }
161
+ get levels() {
162
+ return [this.r, this.g, this.b, this.a];
163
+ }
164
+ toString() {
165
+ return `color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`;
166
+ }
167
+ };
168
+ Q5.ColorRGBA_P3 = class extends Q5.ColorRGBA {
169
+ toString() {
170
+ return `color(display-p3 ${this.r} ${this.g} ${this.b} / ${this.a})`;
171
+ }
172
+ };
173
+ // legacy 8-bit (0-255) integer color format
174
+ Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
175
+ constructor(r, g, b, a) {
176
+ super(r, g, b, a ?? 255);
152
177
  }
153
178
  setRed(v) {
154
179
  this.r = v;
@@ -169,9 +194,10 @@ Q5.ColorRGBA = class extends Q5.Color {
169
194
  return `rgb(${this.r} ${this.g} ${this.b} / ${this.a / 255})`;
170
195
  }
171
196
  };
172
- Q5.ColorRGBA_P3 = class extends Q5.ColorRGBA {
197
+ // p3 10-bit color in integer color format, for backwards compatibility
198
+ Q5.ColorRGBA_P3_8 = class extends Q5.ColorRGBA {
173
199
  constructor(r, g, b, a) {
174
- super(r, g, b, a);
200
+ super(r, g, b, a ?? 255);
175
201
  this._edited = true;
176
202
  }
177
203
  get r() {
package/src/q5-core.js CHANGED
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * q5.js
3
- * @version 2.0
3
+ * @version 2.1
4
4
  * @author quinton-ashley, Tezumie, and LingDong-
5
5
  * @license LGPL-3.0
6
6
  * @class Q5
7
7
  */
8
- function Q5(scope, parent) {
8
+ function Q5(scope, parent, renderer) {
9
9
  let $ = this;
10
10
  $._q5 = true;
11
- $._scope = scope;
12
11
  $._parent = parent;
12
+ $._renderer = renderer || 'q2d';
13
13
  $._preloadCount = 0;
14
14
 
15
15
  scope ??= 'global';
@@ -17,13 +17,14 @@ function Q5(scope, parent) {
17
17
  if (!(window.setup || window.draw)) return;
18
18
  scope = 'global';
19
19
  }
20
+ $._scope = scope;
20
21
  let globalScope;
21
22
  if (scope == 'global') {
22
23
  Q5._hasGlobal = $._isGlobal = true;
23
24
  globalScope = !Q5._nodejs ? window : global;
24
25
  }
25
26
 
26
- let p = new Proxy($, {
27
+ let q = new Proxy($, {
27
28
  set: (t, p, v) => {
28
29
  $[p] = v;
29
30
  if ($._isGlobal) globalScope[p] = v;
@@ -41,6 +42,10 @@ function Q5(scope, parent) {
41
42
  $._targetFrameDuration = 16.666666666666668;
42
43
  $._frameRate = $._fps = 60;
43
44
  $._loop = true;
45
+ $._hooks = {
46
+ postCanvas: [],
47
+ preRender: []
48
+ };
44
49
 
45
50
  let millisStart = 0;
46
51
  $.millis = () => performance.now() - millisStart;
@@ -48,7 +53,7 @@ function Q5(scope, parent) {
48
53
  $.noCanvas = () => {
49
54
  if ($.canvas?.remove) $.canvas.remove();
50
55
  $.canvas = 0;
51
- p.ctx = p.drawingContext = 0;
56
+ q.ctx = q.drawingContext = 0;
52
57
  };
53
58
 
54
59
  if (window) {
@@ -57,10 +62,10 @@ function Q5(scope, parent) {
57
62
  $.deviceOrientation = window.screen?.orientation?.type;
58
63
  }
59
64
 
60
- $._incrementPreload = () => p._preloadCount++;
61
- $._decrementPreload = () => p._preloadCount--;
65
+ $._incrementPreload = () => q._preloadCount++;
66
+ $._decrementPreload = () => q._preloadCount--;
62
67
 
63
- function _draw(timestamp) {
68
+ $._draw = (timestamp) => {
64
69
  let ts = timestamp || performance.now();
65
70
  $._lastFrameTime ??= ts - $._targetFrameDuration;
66
71
 
@@ -69,43 +74,43 @@ function Q5(scope, parent) {
69
74
  $._shouldResize = false;
70
75
  }
71
76
 
72
- if ($._loop) looper = raf(_draw);
77
+ if ($._loop) looper = raf($._draw);
73
78
  else if ($.frameCount && !$._redraw) return;
74
79
 
75
80
  if (looper && $.frameCount) {
76
81
  let time_since_last = ts - $._lastFrameTime;
77
- if (time_since_last < $._targetFrameDuration - 1) return;
82
+ if (time_since_last < $._targetFrameDuration - 4) return;
78
83
  }
79
- p.deltaTime = ts - $._lastFrameTime;
84
+ q.deltaTime = ts - $._lastFrameTime;
80
85
  $._frameRate = 1000 / $.deltaTime;
81
- p.frameCount++;
86
+ q.frameCount++;
82
87
  let pre = performance.now();
83
- for (let m of Q5.prototype._methods.pre) m.call($);
84
- if ($.ctx) $.ctx.save();
88
+ if ($._beginRender) $._beginRender();
89
+ if ($.ctx) $.resetMatrix();
90
+ for (let m of Q5.methods.pre) m.call($);
85
91
  $.draw();
86
- for (let m of Q5.prototype._methods.post) m.call($);
87
- if ($.ctx) {
88
- $.ctx.restore();
89
- $.resetMatrix();
90
- }
91
- p.pmouseX = $.mouseX;
92
- p.pmouseY = $.mouseY;
92
+ if ($._render) $._render();
93
+ for (let m of Q5.methods.post) m.call($);
94
+ if ($._finishRender) $._finishRender();
95
+ q.pmouseX = $.mouseX;
96
+ q.pmouseY = $.mouseY;
93
97
  $._lastFrameTime = ts;
94
98
  let post = performance.now();
95
99
  $._fps = Math.round(1000 / (post - pre));
96
- }
100
+ };
97
101
  $.noLoop = () => {
98
102
  $._loop = false;
99
103
  looper = null;
100
104
  };
101
105
  $.loop = () => {
102
106
  $._loop = true;
103
- if (looper == null) _draw();
107
+ if (looper == null) $._draw();
104
108
  };
109
+ $.isLooping = () => $._loop;
105
110
  $.redraw = (n = 1) => {
106
111
  $._redraw = true;
107
112
  for (let i = 0; i < n; i++) {
108
- _draw();
113
+ $._draw();
109
114
  }
110
115
  $._redraw = false;
111
116
  };
@@ -135,7 +140,12 @@ function Q5(scope, parent) {
135
140
  $.describe = () => {};
136
141
 
137
142
  for (let m in Q5.modules) {
138
- Q5.modules[m]($, p);
143
+ Q5.modules[m]($, q);
144
+ }
145
+
146
+ let r = Q5.renderers[$._renderer];
147
+ for (let m in r) {
148
+ r[m]($, q);
139
149
  }
140
150
 
141
151
  // INIT
@@ -146,12 +156,14 @@ function Q5(scope, parent) {
146
156
  }
147
157
  }
148
158
 
159
+ if (scope == 'graphics') return;
160
+
149
161
  if (scope == 'global') {
150
162
  Object.assign(Q5, $);
151
163
  delete Q5.Q5;
152
164
  }
153
165
 
154
- for (let m of Q5.prototype._methods.init) {
166
+ for (let m of Q5.methods.init) {
155
167
  m.call($);
156
168
  }
157
169
 
@@ -168,8 +180,6 @@ function Q5(scope, parent) {
168
180
 
169
181
  if (typeof scope == 'function') scope($);
170
182
 
171
- if (scope == 'graphics') return;
172
-
173
183
  Q5._instanceCount++;
174
184
 
175
185
  let raf =
@@ -217,8 +227,6 @@ function Q5(scope, parent) {
217
227
 
218
228
  if (!($.setup || $.draw)) return;
219
229
 
220
- $._startDone = false;
221
-
222
230
  async function _start() {
223
231
  $._startDone = true;
224
232
  if ($._preloadCount > 0) return raf(_start);
@@ -228,7 +236,7 @@ function Q5(scope, parent) {
228
236
  if ($.ctx === null) $.createCanvas(100, 100);
229
237
  $._setupDone = true;
230
238
  if ($.ctx) $.resetMatrix();
231
- raf(_draw);
239
+ raf($._draw);
232
240
  }
233
241
 
234
242
  if ((arguments.length && scope != 'namespace') || preloadDefined) {
@@ -242,6 +250,7 @@ function Q5(scope, parent) {
242
250
  }
243
251
  }
244
252
 
253
+ Q5.renderers = {};
245
254
  Q5.modules = {};
246
255
 
247
256
  Q5._nodejs = typeof process == 'object';
@@ -252,13 +261,13 @@ Q5._friendlyError = (msg, func) => {
252
261
  };
253
262
  Q5._validateParameters = () => true;
254
263
 
255
- Q5.prototype._methods = {
264
+ Q5.methods = {
256
265
  init: [],
257
266
  pre: [],
258
267
  post: [],
259
268
  remove: []
260
269
  };
261
- Q5.prototype.registerMethod = (m, fn) => Q5.prototype._methods[m].push(fn);
270
+ Q5.prototype.registerMethod = (m, fn) => Q5.methods[m].push(fn);
262
271
  Q5.prototype.registerPreloadMethod = (n, fn) => (Q5.prototype[n] = fn[n]);
263
272
 
264
273
  if (Q5._nodejs) global.p5 ??= global.Q5 = Q5;
package/src/q5-display.js CHANGED
@@ -84,4 +84,10 @@ main {
84
84
  Object.assign(c, { displayMode, renderQuality, displayScale });
85
85
  $._adjustDisplay();
86
86
  };
87
+
88
+ $.fullscreen = (v) => {
89
+ if (v === undefined) return document.fullscreenElement;
90
+ if (v) document.body.requestFullscreen();
91
+ else document.body.exitFullscreen();
92
+ };
87
93
  };
package/src/q5-input.js CHANGED
@@ -1,4 +1,4 @@
1
- Q5.modules.input = ($, p) => {
1
+ Q5.modules.input = ($, q) => {
2
2
  if ($._scope == 'graphics') return;
3
3
 
4
4
  $.mouseX = 0;
@@ -42,17 +42,26 @@ Q5.modules.input = ($, p) => {
42
42
 
43
43
  $._updateMouse = (e) => {
44
44
  if (e.changedTouches) return;
45
- let rect = $.canvas.getBoundingClientRect();
46
- let sx = $.canvas.scrollWidth / $.width || 1;
47
- let sy = $.canvas.scrollHeight / $.height || 1;
48
- p.mouseX = (e.clientX - rect.left) / sx;
49
- p.mouseY = (e.clientY - rect.top) / sy;
45
+ if (c) {
46
+ let rect = c.getBoundingClientRect();
47
+ let sx = c.scrollWidth / $.width || 1;
48
+ let sy = c.scrollHeight / $.height || 1;
49
+ q.mouseX = (e.clientX - rect.left) / sx;
50
+ q.mouseY = (e.clientY - rect.top) / sy;
51
+ if (c.renderer == 'webgpu') {
52
+ q.mouseX -= c.hw;
53
+ q.mouseY -= c.hh;
54
+ }
55
+ } else {
56
+ q.mouseX = e.clientX;
57
+ q.mouseY = e.clientY;
58
+ }
50
59
  };
51
60
  $._onmousedown = (e) => {
52
61
  $._startAudio();
53
62
  $._updateMouse(e);
54
- p.mouseIsPressed = true;
55
- p.mouseButton = mouseBtns[e.button];
63
+ q.mouseIsPressed = true;
64
+ q.mouseButton = mouseBtns[e.button];
56
65
  $.mousePressed(e);
57
66
  };
58
67
  $._onmousemove = (e) => {
@@ -62,18 +71,15 @@ Q5.modules.input = ($, p) => {
62
71
  };
63
72
  $._onmouseup = (e) => {
64
73
  $._updateMouse(e);
65
- p.mouseIsPressed = false;
74
+ q.mouseIsPressed = false;
66
75
  $.mouseReleased(e);
67
76
  };
68
77
  $._onclick = (e) => {
69
78
  $._updateMouse(e);
70
- p.mouseIsPressed = true;
79
+ q.mouseIsPressed = true;
71
80
  $.mouseClicked(e);
72
- p.mouseIsPressed = false;
81
+ q.mouseIsPressed = false;
73
82
  };
74
- c.addEventListener('mousedown', (e) => $._onmousedown(e));
75
- c.addEventListener('mouseup', (e) => $._onmouseup(e));
76
- c.addEventListener('click', (e) => $._onclick(e));
77
83
 
78
84
  $.cursor = (name, x, y) => {
79
85
  let pfx = '';
@@ -95,17 +101,17 @@ Q5.modules.input = ($, p) => {
95
101
  $._onkeydown = (e) => {
96
102
  if (e.repeat) return;
97
103
  $._startAudio();
98
- p.keyIsPressed = true;
99
- p.key = e.key;
100
- p.keyCode = e.keyCode;
104
+ q.keyIsPressed = true;
105
+ q.key = e.key;
106
+ q.keyCode = e.keyCode;
101
107
  keysHeld[$.keyCode] = keysHeld[$.key.toLowerCase()] = true;
102
108
  $.keyPressed(e);
103
109
  if (e.key.length == 1) $.keyTyped(e);
104
110
  };
105
111
  $._onkeyup = (e) => {
106
- p.keyIsPressed = false;
107
- p.key = e.key;
108
- p.keyCode = e.keyCode;
112
+ q.keyIsPressed = false;
113
+ q.key = e.key;
114
+ q.keyCode = e.keyCode;
109
115
  keysHeld[$.keyCode] = keysHeld[$.key.toLowerCase()] = false;
110
116
  $.keyReleased(e);
111
117
  };
@@ -123,37 +129,43 @@ Q5.modules.input = ($, p) => {
123
129
  }
124
130
  $._ontouchstart = (e) => {
125
131
  $._startAudio();
126
- p.touches = [...e.touches].map(getTouchInfo);
132
+ q.touches = [...e.touches].map(getTouchInfo);
127
133
  if (!$._isTouchAware) {
128
- p.mouseX = $.touches[0].x;
129
- p.mouseY = $.touches[0].y;
130
- p.mouseIsPressed = true;
131
- p.mouseButton = $.LEFT;
134
+ q.mouseX = $.touches[0].x;
135
+ q.mouseY = $.touches[0].y;
136
+ q.mouseIsPressed = true;
137
+ q.mouseButton = $.LEFT;
132
138
  if (!$.mousePressed(e)) e.preventDefault();
133
139
  }
134
140
  if (!$.touchStarted(e)) e.preventDefault();
135
141
  };
136
142
  $._ontouchmove = (e) => {
137
- p.touches = [...e.touches].map(getTouchInfo);
143
+ q.touches = [...e.touches].map(getTouchInfo);
138
144
  if (!$._isTouchAware) {
139
- p.mouseX = $.touches[0].x;
140
- p.mouseY = $.touches[0].y;
145
+ q.mouseX = $.touches[0].x;
146
+ q.mouseY = $.touches[0].y;
141
147
  if (!$.mouseDragged(e)) e.preventDefault();
142
148
  }
143
149
  if (!$.touchMoved(e)) e.preventDefault();
144
150
  };
145
151
  $._ontouchend = (e) => {
146
- p.touches = [...e.touches].map(getTouchInfo);
152
+ q.touches = [...e.touches].map(getTouchInfo);
147
153
  if (!$._isTouchAware && !$.touches.length) {
148
- p.mouseIsPressed = false;
154
+ q.mouseIsPressed = false;
149
155
  if (!$.mouseReleased(e)) e.preventDefault();
150
156
  }
151
157
  if (!$.touchEnded(e)) e.preventDefault();
152
158
  };
153
- c.addEventListener('touchstart', (e) => $._ontouchstart(e));
154
- c.addEventListener('touchmove', (e) => $._ontouchmove(e));
155
- c.addEventListener('touchcancel', (e) => $._ontouchend(e));
156
- c.addEventListener('touchend', (e) => $._ontouchend(e));
159
+
160
+ if (c) {
161
+ c.addEventListener('mousedown', (e) => $._onmousedown(e));
162
+ c.addEventListener('mouseup', (e) => $._onmouseup(e));
163
+ c.addEventListener('click', (e) => $._onclick(e));
164
+ c.addEventListener('touchstart', (e) => $._ontouchstart(e));
165
+ c.addEventListener('touchmove', (e) => $._ontouchmove(e));
166
+ c.addEventListener('touchcancel', (e) => $._ontouchend(e));
167
+ c.addEventListener('touchend', (e) => $._ontouchend(e));
168
+ }
157
169
 
158
170
  if (window) {
159
171
  let l = window.addEventListener;