litecanvas 0.74.3 → 0.75.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.
package/dist/dist.dev.js CHANGED
@@ -1,27 +1,10 @@
1
1
  (() => {
2
2
  // src/zzfx.js
3
3
  var zzfxX = /* @__PURE__ */ new AudioContext();
4
- var zzfx = (p = 1, k = 0.05, b = 220, e = 0, r = 0, t = 0.1, q = 0, D = 1, u = 0, y = 0, v = 0, z = 0, l = 0, E = 0, A = 0, F = 0, c = 0, w = 1, m = 0, B = 0, N = 0) => {
5
- let M = Math, d = 2 * M.PI, R = 44100, G = u *= 500 * d / R / R, C = b *= (1 - k + 2 * k * M.random(k = [])) * d / R, g = 0, H = 0, a = 0, n = 1, I = 0, J = 0, f = 0, h = N < 0 ? -1 : 1, x = d * h * N * 2 / R, L = M.cos(x), Z = M.sin, K = Z(x) / 4, O = 1 + K, X = -2 * L / O, Y = (1 - K) / O, P = (1 + h * L) / 2 / O, Q = -(h + L) / O, S = P, T = 0, U = 0, V = 0, W = 0;
6
- e = R * e + 9;
7
- m *= R;
8
- r *= R;
9
- t *= R;
10
- c *= R;
11
- y *= 500 * d / R ** 3;
12
- A *= d / R;
13
- v *= d / R;
14
- z *= R;
15
- l = R * l | 0;
16
- p *= 0.3 * (globalThis.zzfxV || 1);
17
- for (h = e + m + r + t + c | 0; a < h; k[a++] = f * p)
18
- ++J % (100 * F | 0) || (f = q ? 1 < q ? 2 < q ? 3 < q ? Z(g * g) : M.max(M.min(M.tan(g), 1), -1) : 1 - (2 * g / d % 2 + 2) % 2 : 1 - 4 * M.abs(M.round(g / d) - g / d) : Z(g), f = (l ? 1 - B + B * Z(d * a / l) : 1) * (f < 0 ? -1 : 1) * M.abs(f) ** D * (a < e ? a / e : a < e + m ? 1 - (a - e) / m * (1 - w) : a < e + m + r ? w : a < h - c ? (h - a - c) / t * w : 0), f = c ? f / 2 + (c > a ? 0 : (a < h - c ? 1 : (h - a) / c) * k[a - c | 0] / 2 / p) : f, N ? f = W = S * T + Q * (T = U) + P * (U = f) - Y * V - X * (V = W) : 0), x = (b += u += y) * M.cos(A * H++), g += x + x * E * Z(a ** 5), n && ++n > z && (b += v, C += v, n = 0), !l || ++I % l || (b = C, u = G, n = n || 1);
19
- p = zzfxX.createBuffer(1, h, R);
20
- p.getChannelData(0).set(k);
21
- b = zzfxX.createBufferSource();
22
- b.buffer = p;
23
- b.connect(zzfxX.destination);
24
- b.start();
4
+ var zzfx = (i = 1, d = 0.05, z = 220, e = 0, P = 0, S = 0.1, I = 0, c = 1, T = 0, H = 0, V = 0, J = 0, h = 0, j = 0, K = 0, E = 0, r = 0, B = 1, X = 0, L = 0, D = 0) => {
5
+ let n = Math, t = 2 * n.PI, a = 44100, F = T *= 500 * t / a / a, O = z *= (1 - d + 2 * d * n.random(d = [])) * t / a, x = 0, _ = 0, f = 0, g = 1, $ = 0, l = 0, o = 0, s = D < 0 ? -1 : 1, u = t * s * D * 2 / a, G = n.cos(u), C = n.sin, Q = C(u) / 4, M = 1 + Q, m = -2 * G / M, y = (1 - Q) / M, R = (1 + s * G) / 2 / M, A = -(s + G) / M, v = R, U = 0, W = 0, Y = 0, Z = 0;
6
+ for (e = a * e + 9, X *= a, P *= a, S *= a, r *= a, H *= 500 * t / a ** 3, K *= t / a, V *= t / a, J *= a, h = a * h | 0, i *= 0.3 * (globalThis.zzfxV || 1), s = e + X + P + S + r | 0; f < s; d[f++] = o * i) ++l % (100 * E | 0) || (o = I ? 1 < I ? 2 < I ? 3 < I ? C(x * x) : n.max(n.min(n.tan(x), 1), -1) : 1 - (2 * x / t % 2 + 2) % 2 : 1 - 4 * n.abs(n.round(x / t) - x / t) : C(x), o = (h ? 1 - L + L * C(t * f / h) : 1) * (o < 0 ? -1 : 1) * n.abs(o) ** c * (f < e ? f / e : f < e + X ? 1 - (f - e) / X * (1 - B) : f < e + X + P ? B : f < s - r ? (s - f - r) / S * B : 0), o = r ? o / 2 + (r > f ? 0 : (f < s - r ? 1 : (s - f) / r) * d[f - r | 0] / 2 / i) : o, D && (o = Z = v * U + A * (U = W) + R * (W = o) - y * Y - m * (Y = Z))), u = (z += T += H) * n.cos(K * _++), x += u + u * j * C(f ** 5), g && ++g > J && (z += V, O += V, g = 0), !h || ++$ % h || (z = O, T = F, g = g || 1);
7
+ i = zzfxX.createBuffer(1, s, a), i.getChannelData(0).set(d), z = zzfxX.createBufferSource(), z.buffer = i, z.connect(zzfxX.destination), z.start();
25
8
  };
26
9
 
27
10
  // src/palette.js
@@ -101,13 +84,6 @@
101
84
  /** @type {number[]} */
102
85
  DEFAULT_SFX: [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
103
86
  /** MATH API */
104
- /**
105
- * The value of the mathematical constant PI (π).
106
- * Approximately 3.14159
107
- *
108
- * @type {number}
109
- */
110
- PI,
111
87
  /**
112
88
  * Twice the value of the mathematical constant PI (π).
113
89
  * Approximately 6.28318
@@ -124,7 +100,7 @@
124
100
  *
125
101
  * @type {number}
126
102
  */
127
- HALF_PI: PI * 0.5,
103
+ HALF_PI: PI / 2,
128
104
  /**
129
105
  * Calculates a linear (interpolation) value over t%.
130
106
  *
@@ -140,7 +116,7 @@
140
116
  assert(isFinite(end), "lerp: 2nd param must be a number");
141
117
  assert(isFinite(t), "lerp: 3rd param must be a number");
142
118
  }
143
- return start + t * (end - start);
119
+ return t * (end - start) + start;
144
120
  },
145
121
  /**
146
122
  * Convert degrees to radians
@@ -1096,24 +1072,7 @@
1096
1072
  }
1097
1073
  }
1098
1074
  };
1099
- for (const k of [
1100
- "sin",
1101
- "cos",
1102
- "atan2",
1103
- "hypot",
1104
- "tan",
1105
- "abs",
1106
- "ceil",
1107
- "round",
1108
- "floor",
1109
- "trunc",
1110
- "min",
1111
- "max",
1112
- "pow",
1113
- "sqrt",
1114
- "sign",
1115
- "exp"
1116
- ]) {
1075
+ for (const k of "PI,sin,cos,atan2,hypot,tan,abs,ceil,round,floor,trunc,min,max,pow,sqrt,sign,exp".split(",")) {
1117
1076
  instance[k] = Math[k];
1118
1077
  }
1119
1078
  function init() {
@@ -1148,17 +1107,32 @@
1148
1107
  const tap = _taps.get(id) || _registerTap(id);
1149
1108
  tap.x = x;
1150
1109
  tap.y = y;
1151
- }, _checkTapped = (tap) => tap && performance.now() - tap.ts <= 200;
1110
+ }, _checkTapped = (tap) => tap && performance.now() - tap.ts <= 200, preventDefault = (ev) => ev.preventDefault();
1152
1111
  let _pressingMouse = false;
1153
1112
  on(_canvas, "mousedown", (ev) => {
1154
- ev.preventDefault();
1155
- const [x, y] = _getXY(ev.pageX, ev.pageY);
1156
- instance.emit("tap", x, y, 0);
1157
- _registerTap(0, x, y);
1158
- _pressingMouse = true;
1113
+ if (ev.button === 0) {
1114
+ preventDefault(ev);
1115
+ const [x, y] = _getXY(ev.pageX, ev.pageY);
1116
+ instance.emit("tap", x, y, 0);
1117
+ _registerTap(0, x, y);
1118
+ _pressingMouse = true;
1119
+ }
1120
+ });
1121
+ on(_canvas, "mouseup", (ev) => {
1122
+ if (ev.button === 0) {
1123
+ preventDefault(ev);
1124
+ const tap = _taps.get(0);
1125
+ const [x, y] = _getXY(ev.pageX, ev.pageY);
1126
+ if (_checkTapped(tap)) {
1127
+ instance.emit("tapped", tap.startX, tap.startY, 0);
1128
+ }
1129
+ instance.emit("untap", x, y, 0);
1130
+ _taps.delete(0);
1131
+ _pressingMouse = false;
1132
+ }
1159
1133
  });
1160
1134
  on(_canvas, "mousemove", (ev) => {
1161
- ev.preventDefault();
1135
+ preventDefault(ev);
1162
1136
  const [x, y] = _getXY(ev.pageX, ev.pageY);
1163
1137
  instance.setvar("MOUSEX", x);
1164
1138
  instance.setvar("MOUSEY", y);
@@ -1166,19 +1140,8 @@
1166
1140
  instance.emit("tapping", x, y, 0);
1167
1141
  _updateTap(0, x, y);
1168
1142
  });
1169
- on(_canvas, "mouseup", (ev) => {
1170
- ev.preventDefault();
1171
- const tap = _taps.get(0);
1172
- const [x, y] = _getXY(ev.pageX, ev.pageY);
1173
- if (_checkTapped(tap)) {
1174
- instance.emit("tapped", tap.startX, tap.startY, 0);
1175
- }
1176
- instance.emit("untap", x, y, 0);
1177
- _taps.delete(0);
1178
- _pressingMouse = false;
1179
- });
1180
1143
  on(_canvas, "touchstart", (ev) => {
1181
- ev.preventDefault();
1144
+ preventDefault(ev);
1182
1145
  const touches = ev.changedTouches;
1183
1146
  for (const touch of touches) {
1184
1147
  const [x, y] = _getXY(touch.pageX, touch.pageY);
@@ -1187,7 +1150,7 @@
1187
1150
  }
1188
1151
  });
1189
1152
  on(_canvas, "touchmove", (ev) => {
1190
- ev.preventDefault();
1153
+ preventDefault(ev);
1191
1154
  const touches = ev.changedTouches;
1192
1155
  for (const touch of touches) {
1193
1156
  const [x, y] = _getXY(touch.pageX, touch.pageY);
@@ -1196,7 +1159,7 @@
1196
1159
  }
1197
1160
  });
1198
1161
  const _touchEndHandler = (ev) => {
1199
- ev.preventDefault();
1162
+ preventDefault(ev);
1200
1163
  const existing = [];
1201
1164
  if (ev.targetTouches.length > 0) {
1202
1165
  for (const touch of ev.targetTouches) {
@@ -1263,7 +1226,8 @@
1263
1226
  }
1264
1227
  let updated = 0, frameTime = (now - _lastFrameTime) / 1e3;
1265
1228
  _lastFrameTime = now;
1266
- if (frameTime > 1) return;
1229
+ if (frameTime > _deltaTime * 30)
1230
+ return void 0;
1267
1231
  _accumulated += frameTime;
1268
1232
  if (!_animated) {
1269
1233
  _accumulated = _deltaTime;
@@ -1283,6 +1247,20 @@
1283
1247
  }
1284
1248
  function setupCanvas() {
1285
1249
  _canvas = "string" === typeof _canvas ? document.querySelector(_canvas) : _canvas;
1250
+ if (true) {
1251
+ assert(
1252
+ _canvas && _canvas.tagName === "CANVAS",
1253
+ "Invalid canvas element"
1254
+ );
1255
+ assert(
1256
+ null === instance.WIDTH || instance.WIDTH > 0,
1257
+ `Litecanvas' "width" option should be null or a positive number`
1258
+ );
1259
+ assert(
1260
+ null === instance.HEIGHT || instance.HEIGHT > 0,
1261
+ `Litecanvas' "width" option should be null or a positive number`
1262
+ );
1263
+ }
1286
1264
  instance.setvar("CANVAS", _canvas);
1287
1265
  _ctx = _canvas.getContext("2d");
1288
1266
  on(_canvas, "click", () => root.focus());
@@ -1316,7 +1294,7 @@
1316
1294
  instance.setvar("CENTERY", instance.HEIGHT / 2);
1317
1295
  if (!settings.antialias || settings.pixelart) {
1318
1296
  _ctx.imageSmoothingEnabled = false;
1319
- _canvas.style.imageRendering = "pixelated";
1297
+ styles.imageRendering = "pixelated";
1320
1298
  }
1321
1299
  instance.emit("resized", _scale);
1322
1300
  if (!_animated) {
@@ -1331,10 +1309,14 @@
1331
1309
  }
1332
1310
  function loadPlugin(callback, config) {
1333
1311
  const pluginData = callback(instance, _helpers, config);
1334
- if ("object" === typeof pluginData) {
1335
- for (const key of Object.keys(pluginData)) {
1336
- instance.setvar(key, pluginData[key]);
1337
- }
1312
+ if (true) {
1313
+ assert(
1314
+ null == pluginData || "object" === typeof pluginData,
1315
+ "Litecanvas plugins should return an object or nothing"
1316
+ );
1317
+ }
1318
+ for (const key in pluginData) {
1319
+ instance.setvar(key, pluginData[key]);
1338
1320
  }
1339
1321
  }
1340
1322
  if (_global) {
package/dist/dist.js CHANGED
@@ -1,27 +1,10 @@
1
1
  (() => {
2
2
  // src/zzfx.js
3
3
  var zzfxX = /* @__PURE__ */ new AudioContext();
4
- var zzfx = (p = 1, k = 0.05, b = 220, e = 0, r = 0, t = 0.1, q = 0, D = 1, u = 0, y = 0, v = 0, z = 0, l = 0, E = 0, A = 0, F = 0, c = 0, w = 1, m = 0, B = 0, N = 0) => {
5
- let M = Math, d = 2 * M.PI, R = 44100, G = u *= 500 * d / R / R, C = b *= (1 - k + 2 * k * M.random(k = [])) * d / R, g = 0, H = 0, a = 0, n = 1, I = 0, J = 0, f = 0, h = N < 0 ? -1 : 1, x = d * h * N * 2 / R, L = M.cos(x), Z = M.sin, K = Z(x) / 4, O = 1 + K, X = -2 * L / O, Y = (1 - K) / O, P = (1 + h * L) / 2 / O, Q = -(h + L) / O, S = P, T = 0, U = 0, V = 0, W = 0;
6
- e = R * e + 9;
7
- m *= R;
8
- r *= R;
9
- t *= R;
10
- c *= R;
11
- y *= 500 * d / R ** 3;
12
- A *= d / R;
13
- v *= d / R;
14
- z *= R;
15
- l = R * l | 0;
16
- p *= 0.3 * (globalThis.zzfxV || 1);
17
- for (h = e + m + r + t + c | 0; a < h; k[a++] = f * p)
18
- ++J % (100 * F | 0) || (f = q ? 1 < q ? 2 < q ? 3 < q ? Z(g * g) : M.max(M.min(M.tan(g), 1), -1) : 1 - (2 * g / d % 2 + 2) % 2 : 1 - 4 * M.abs(M.round(g / d) - g / d) : Z(g), f = (l ? 1 - B + B * Z(d * a / l) : 1) * (f < 0 ? -1 : 1) * M.abs(f) ** D * (a < e ? a / e : a < e + m ? 1 - (a - e) / m * (1 - w) : a < e + m + r ? w : a < h - c ? (h - a - c) / t * w : 0), f = c ? f / 2 + (c > a ? 0 : (a < h - c ? 1 : (h - a) / c) * k[a - c | 0] / 2 / p) : f, N ? f = W = S * T + Q * (T = U) + P * (U = f) - Y * V - X * (V = W) : 0), x = (b += u += y) * M.cos(A * H++), g += x + x * E * Z(a ** 5), n && ++n > z && (b += v, C += v, n = 0), !l || ++I % l || (b = C, u = G, n = n || 1);
19
- p = zzfxX.createBuffer(1, h, R);
20
- p.getChannelData(0).set(k);
21
- b = zzfxX.createBufferSource();
22
- b.buffer = p;
23
- b.connect(zzfxX.destination);
24
- b.start();
4
+ var zzfx = (i = 1, d = 0.05, z = 220, e = 0, P = 0, S = 0.1, I = 0, c = 1, T = 0, H = 0, V = 0, J = 0, h = 0, j = 0, K = 0, E = 0, r = 0, B = 1, X = 0, L = 0, D = 0) => {
5
+ let n = Math, t = 2 * n.PI, a = 44100, F = T *= 500 * t / a / a, O = z *= (1 - d + 2 * d * n.random(d = [])) * t / a, x = 0, _ = 0, f = 0, g = 1, $ = 0, l = 0, o = 0, s = D < 0 ? -1 : 1, u = t * s * D * 2 / a, G = n.cos(u), C = n.sin, Q = C(u) / 4, M = 1 + Q, m = -2 * G / M, y = (1 - Q) / M, R = (1 + s * G) / 2 / M, A = -(s + G) / M, v = R, U = 0, W = 0, Y = 0, Z = 0;
6
+ for (e = a * e + 9, X *= a, P *= a, S *= a, r *= a, H *= 500 * t / a ** 3, K *= t / a, V *= t / a, J *= a, h = a * h | 0, i *= 0.3 * (globalThis.zzfxV || 1), s = e + X + P + S + r | 0; f < s; d[f++] = o * i) ++l % (100 * E | 0) || (o = I ? 1 < I ? 2 < I ? 3 < I ? C(x * x) : n.max(n.min(n.tan(x), 1), -1) : 1 - (2 * x / t % 2 + 2) % 2 : 1 - 4 * n.abs(n.round(x / t) - x / t) : C(x), o = (h ? 1 - L + L * C(t * f / h) : 1) * (o < 0 ? -1 : 1) * n.abs(o) ** c * (f < e ? f / e : f < e + X ? 1 - (f - e) / X * (1 - B) : f < e + X + P ? B : f < s - r ? (s - f - r) / S * B : 0), o = r ? o / 2 + (r > f ? 0 : (f < s - r ? 1 : (s - f) / r) * d[f - r | 0] / 2 / i) : o, D && (o = Z = v * U + A * (U = W) + R * (W = o) - y * Y - m * (Y = Z))), u = (z += T += H) * n.cos(K * _++), x += u + u * j * C(f ** 5), g && ++g > J && (z += V, O += V, g = 0), !h || ++$ % h || (z = O, T = F, g = g || 1);
7
+ i = zzfxX.createBuffer(1, s, a), i.getChannelData(0).set(d), z = zzfxX.createBufferSource(), z.buffer = i, z.connect(zzfxX.destination), z.start();
25
8
  };
26
9
 
27
10
  // src/palette.js
@@ -96,13 +79,6 @@
96
79
  /** @type {number[]} */
97
80
  DEFAULT_SFX: [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
98
81
  /** MATH API */
99
- /**
100
- * The value of the mathematical constant PI (π).
101
- * Approximately 3.14159
102
- *
103
- * @type {number}
104
- */
105
- PI,
106
82
  /**
107
83
  * Twice the value of the mathematical constant PI (π).
108
84
  * Approximately 6.28318
@@ -119,7 +95,7 @@
119
95
  *
120
96
  * @type {number}
121
97
  */
122
- HALF_PI: PI * 0.5,
98
+ HALF_PI: PI / 2,
123
99
  /**
124
100
  * Calculates a linear (interpolation) value over t%.
125
101
  *
@@ -135,7 +111,7 @@
135
111
  assert(isFinite(end), "lerp: 2nd param must be a number");
136
112
  assert(isFinite(t), "lerp: 3rd param must be a number");
137
113
  }
138
- return start + t * (end - start);
114
+ return t * (end - start) + start;
139
115
  },
140
116
  /**
141
117
  * Convert degrees to radians
@@ -1091,24 +1067,7 @@
1091
1067
  }
1092
1068
  }
1093
1069
  };
1094
- for (const k of [
1095
- "sin",
1096
- "cos",
1097
- "atan2",
1098
- "hypot",
1099
- "tan",
1100
- "abs",
1101
- "ceil",
1102
- "round",
1103
- "floor",
1104
- "trunc",
1105
- "min",
1106
- "max",
1107
- "pow",
1108
- "sqrt",
1109
- "sign",
1110
- "exp"
1111
- ]) {
1070
+ for (const k of "PI,sin,cos,atan2,hypot,tan,abs,ceil,round,floor,trunc,min,max,pow,sqrt,sign,exp".split(",")) {
1112
1071
  instance[k] = Math[k];
1113
1072
  }
1114
1073
  function init() {
@@ -1143,17 +1102,32 @@
1143
1102
  const tap = _taps.get(id) || _registerTap(id);
1144
1103
  tap.x = x;
1145
1104
  tap.y = y;
1146
- }, _checkTapped = (tap) => tap && performance.now() - tap.ts <= 200;
1105
+ }, _checkTapped = (tap) => tap && performance.now() - tap.ts <= 200, preventDefault = (ev) => ev.preventDefault();
1147
1106
  let _pressingMouse = false;
1148
1107
  on(_canvas, "mousedown", (ev) => {
1149
- ev.preventDefault();
1150
- const [x, y] = _getXY(ev.pageX, ev.pageY);
1151
- instance.emit("tap", x, y, 0);
1152
- _registerTap(0, x, y);
1153
- _pressingMouse = true;
1108
+ if (ev.button === 0) {
1109
+ preventDefault(ev);
1110
+ const [x, y] = _getXY(ev.pageX, ev.pageY);
1111
+ instance.emit("tap", x, y, 0);
1112
+ _registerTap(0, x, y);
1113
+ _pressingMouse = true;
1114
+ }
1115
+ });
1116
+ on(_canvas, "mouseup", (ev) => {
1117
+ if (ev.button === 0) {
1118
+ preventDefault(ev);
1119
+ const tap = _taps.get(0);
1120
+ const [x, y] = _getXY(ev.pageX, ev.pageY);
1121
+ if (_checkTapped(tap)) {
1122
+ instance.emit("tapped", tap.startX, tap.startY, 0);
1123
+ }
1124
+ instance.emit("untap", x, y, 0);
1125
+ _taps.delete(0);
1126
+ _pressingMouse = false;
1127
+ }
1154
1128
  });
1155
1129
  on(_canvas, "mousemove", (ev) => {
1156
- ev.preventDefault();
1130
+ preventDefault(ev);
1157
1131
  const [x, y] = _getXY(ev.pageX, ev.pageY);
1158
1132
  instance.setvar("MOUSEX", x);
1159
1133
  instance.setvar("MOUSEY", y);
@@ -1161,19 +1135,8 @@
1161
1135
  instance.emit("tapping", x, y, 0);
1162
1136
  _updateTap(0, x, y);
1163
1137
  });
1164
- on(_canvas, "mouseup", (ev) => {
1165
- ev.preventDefault();
1166
- const tap = _taps.get(0);
1167
- const [x, y] = _getXY(ev.pageX, ev.pageY);
1168
- if (_checkTapped(tap)) {
1169
- instance.emit("tapped", tap.startX, tap.startY, 0);
1170
- }
1171
- instance.emit("untap", x, y, 0);
1172
- _taps.delete(0);
1173
- _pressingMouse = false;
1174
- });
1175
1138
  on(_canvas, "touchstart", (ev) => {
1176
- ev.preventDefault();
1139
+ preventDefault(ev);
1177
1140
  const touches = ev.changedTouches;
1178
1141
  for (const touch of touches) {
1179
1142
  const [x, y] = _getXY(touch.pageX, touch.pageY);
@@ -1182,7 +1145,7 @@
1182
1145
  }
1183
1146
  });
1184
1147
  on(_canvas, "touchmove", (ev) => {
1185
- ev.preventDefault();
1148
+ preventDefault(ev);
1186
1149
  const touches = ev.changedTouches;
1187
1150
  for (const touch of touches) {
1188
1151
  const [x, y] = _getXY(touch.pageX, touch.pageY);
@@ -1191,7 +1154,7 @@
1191
1154
  }
1192
1155
  });
1193
1156
  const _touchEndHandler = (ev) => {
1194
- ev.preventDefault();
1157
+ preventDefault(ev);
1195
1158
  const existing = [];
1196
1159
  if (ev.targetTouches.length > 0) {
1197
1160
  for (const touch of ev.targetTouches) {
@@ -1258,7 +1221,8 @@
1258
1221
  }
1259
1222
  let updated = 0, frameTime = (now - _lastFrameTime) / 1e3;
1260
1223
  _lastFrameTime = now;
1261
- if (frameTime > 1) return;
1224
+ if (frameTime > _deltaTime * 30)
1225
+ return void 0;
1262
1226
  _accumulated += frameTime;
1263
1227
  if (!_animated) {
1264
1228
  _accumulated = _deltaTime;
@@ -1278,6 +1242,20 @@
1278
1242
  }
1279
1243
  function setupCanvas() {
1280
1244
  _canvas = "string" === typeof _canvas ? document.querySelector(_canvas) : _canvas;
1245
+ if (false) {
1246
+ assert(
1247
+ _canvas && _canvas.tagName === "CANVAS",
1248
+ "Invalid canvas element"
1249
+ );
1250
+ assert(
1251
+ null === instance.WIDTH || instance.WIDTH > 0,
1252
+ `Litecanvas' "width" option should be null or a positive number`
1253
+ );
1254
+ assert(
1255
+ null === instance.HEIGHT || instance.HEIGHT > 0,
1256
+ `Litecanvas' "width" option should be null or a positive number`
1257
+ );
1258
+ }
1281
1259
  instance.setvar("CANVAS", _canvas);
1282
1260
  _ctx = _canvas.getContext("2d");
1283
1261
  on(_canvas, "click", () => root.focus());
@@ -1311,7 +1289,7 @@
1311
1289
  instance.setvar("CENTERY", instance.HEIGHT / 2);
1312
1290
  if (!settings.antialias || settings.pixelart) {
1313
1291
  _ctx.imageSmoothingEnabled = false;
1314
- _canvas.style.imageRendering = "pixelated";
1292
+ styles.imageRendering = "pixelated";
1315
1293
  }
1316
1294
  instance.emit("resized", _scale);
1317
1295
  if (!_animated) {
@@ -1326,10 +1304,14 @@
1326
1304
  }
1327
1305
  function loadPlugin(callback, config) {
1328
1306
  const pluginData = callback(instance, _helpers, config);
1329
- if ("object" === typeof pluginData) {
1330
- for (const key of Object.keys(pluginData)) {
1331
- instance.setvar(key, pluginData[key]);
1332
- }
1307
+ if (false) {
1308
+ assert(
1309
+ null == pluginData || "object" === typeof pluginData,
1310
+ "Litecanvas plugins should return an object or nothing"
1311
+ );
1312
+ }
1313
+ for (const key in pluginData) {
1314
+ instance.setvar(key, pluginData[key]);
1333
1315
  }
1334
1316
  }
1335
1317
  if (_global) {
package/dist/dist.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e=new AudioContext,t=(t=1,a=.05,l=220,n=0,i=0,r=.1,o=0,s=1,c=0,f=0,u=0,p=0,d=0,h=0,g=0,m=0,v=0,E=1,b=0,w=0,T=0)=>{let x=Math,y=2*x.PI,D=c*=500*y/44100/44100,H=l*=(1-a+2*a*x.random(a=[]))*y/44100,I=0,S=0,A=0,k=1,C=0,L=0,X=0,O=T<0?-1:1,z=y*O*T*2/44100,M=x.cos(z),P=x.sin,Y=P(z)/4,F=1+Y,W=-2*M/F,_=(1-Y)/F,R=(1+O*M)/2/F,G=-(O+M)/F,N=0,B=0,U=0,j=0;for(n=44100*n+9,b*=44100,i*=44100,r*=44100,v*=44100,f*=500*y/85766121e6,g*=y/44100,u*=y/44100,p*=44100,d=44100*d|0,t*=.3*(globalThis.zzfxV||1),O=n+b+i+r+v|0;A<O;a[A++]=X*t)++L%(100*m|0)||(X=o?1<o?2<o?3<o?P(I*I):x.max(x.min(x.tan(I),1),-1):1-(2*I/y%2+2)%2:1-4*x.abs(x.round(I/y)-I/y):P(I),X=(d?1-w+w*P(y*A/d):1)*(X<0?-1:1)*x.abs(X)**s*(A<n?A/n:A<n+b?1-(A-n)/b*(1-E):A<n+b+i?E:A<O-v?(O-A-v)/r*E:0),X=v?X/2+(v>A?0:(A<O-v?1:(O-A)/v)*a[A-v|0]/2/t):X,T&&(X=j=R*N+G*(N=B)+R*(B=X)-_*U-W*(U=j))),I+=(z=(l+=c+=f)*x.cos(g*S++))+z*h*P(A**5),k&&++k>p&&(l+=u,H+=u,k=0),!d||++C%d||(l=H,c=D,k=k||1);(t=e.createBuffer(1,O,44100)).getChannelData(0).set(a),(l=e.createBufferSource()).buffer=t,l.connect(e.destination),l.start()},a=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(e={}){let l=globalThis,n=Math.PI,i=2*n,r=requestAnimationFrame,o=[],s=(e,t,a)=>{e.addEventListener(t,a,!1),o.push(()=>e.removeEventListener(t,a,!1))};e=Object.assign({fullscreen:!0,width:null,height:null,autoscale:!0,pixelart:!1,antialias:!1,canvas:null,global:!0,loop:null,pauseOnBlur:!0,tapEvents:!0,keyboardEvents:!0,animate:!0},e);let c=!1,f=[],u=e.canvas||document.createElement("canvas"),p=e.fullscreen,d=e.autoscale,h=e.animate,g=1,m,v=.5,E=1,b,w,T=0,x,y="sans-serif",D=32,H=Date.now(),I=e.global,S={init:null,update:null,draw:null,resized:null,tap:null,untap:null,tapping:null,tapped:null},A={settings:Object.assign({},e),colors:a},k={WIDTH:e.width,HEIGHT:e.height||e.width,CANVAS:null,ELAPSED:0,CENTERX:0,CENTERY:0,MOUSEX:-1,MOUSEY:-1,DEFAULT_SFX:[.5,,1675,,.06,.2,1,1.8,,,637,.06],PI:n,TWO_PI:i,HALF_PI:.5*n,lerp:(e,t,a)=>e+a*(t-e),deg2rad:e=>n/180*e,rad2deg:e=>180/n*e,clamp:(e,t,a)=>e<t?t:e>a?a:e,wrap:(e,t,a)=>e-(a-t)*Math.floor((e-t)/(a-t)),map(e,t,a,l,n,i){let r=(e-t)/(a-t)*(n-l)+l;return i?k.clamp(r,l,n):r},norm:(e,t,a)=>k.map(e,t,a,0,1),rand:(e=0,t=1)=>(H=(1664525*H+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>Math.floor(k.rand(e,t+1)),seed:e=>null==e?H:H=~~e,cls(e){null==e?m.clearRect(0,0,m.canvas.width,m.canvas.height):k.rectfill(0,0,m.canvas.width,m.canvas.height,e)},rect(e,t,a,l,n,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e-v,~~t-v,~~a+2*v,~~l+2*v,i),k.stroke(n)},rectfill(e,t,a,l,n,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),k.fill(n)},circ(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,~~a,0,i),k.stroke(l)},circfill(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,~~a,0,i),k.fill(l)},line(e,t,a,l,n){m.beginPath();let i=.5*(0!==v&&~~e==~~a),r=.5*(0!==v&&~~t==~~l);m.moveTo(~~e+i,~~t+r),m.lineTo(~~a+i,~~l+r),k.stroke(n)},linewidth(e){m.lineWidth=~~e,v=.5*(~~e%2!=0)},linedash(e,t=0){m.setLineDash(e),m.lineDashOffset=t},text(e,t,a,l=3,n="normal"){m.font=`${n} ${D}px ${y}`,m.fillStyle=k.getcolor(l),m.fillText(a,~~e,~~t)},textfont(e){y=e},textsize(e){D=e},textalign(e,t){e&&(m.textAlign=e),t&&(m.textBaseline=t)},image(e,t,a){m.drawImage(a,~~e,~~t)},paint(e,t,a,l={}){let n=l.canvas||new OffscreenCanvas(1,1),i=l.scale||1,r=m;if(n.width=e*i,n.height=t*i,(m=n.getContext("2d")).scale(i,i),a.push){let e=0,t=0;for(let l of(m.imageSmoothingEnabled=!1,a)){for(let a of l)" "!==a&&"."!==a&&k.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(m);return m=r,n},ctx:e=>(e&&(m=e),m),push:()=>m.save(),pop:()=>m.restore(),translate:(e,t)=>m.translate(~~e,~~t),scale:(e,t)=>m.scale(e,t||e),rotate:e=>m.rotate(e),alpha(e){m.globalAlpha=k.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){m.fillStyle=k.getcolor(e),t?m.fill(t):m.fill()},stroke(e,t){m.strokeStyle=k.getcolor(e),t?m.stroke(t):m.stroke()},clip(e){m.clip(e)},sfx:(e,a=0,n=1)=>!(l.zzfxV<=0)&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||k.DEFAULT_SFX,(0!==a||1!==n)&&((e=e.slice())[0]=n*(e[0]||1),e[10]=~~e[10]+a),t.apply(0,e),e),volume(e){l.zzfxV=e},colrect:(e,t,a,l,n,i,r,o)=>e<n+r&&e+a>n&&t<i+o&&t+l>i,colcirc:(e,t,a,l,n,i)=>(l-e)*(l-e)+(n-t)*(n-t)<=(a+i)*(a+i),use(e,t={}){c?z(e,t):f.push([e,t])},listen:(e,t)=>(S[e]=S[e]||new Set,S[e].add(t),()=>S[e].delete(t)),emit(e,t,a,l,n){O("before:"+e,t,a,l,n),O(e,t,a,l,n),O("after:"+e,t,a,l,n)},getcolor:e=>a[~~e%a.length],setvar(e,t){k[e]=t,I&&(l[e]=t)},resize(e,t){k.setvar("WIDTH",u.width=e),k.setvar("HEIGHT",u.height=t),X()},timescale(e){E=e},setfps(e){w=1/~~e},quit(){for(let e of(k.emit("quit"),o))e();if(cancelAnimationFrame(x),S=!1,I){for(let e in k)delete l[e];delete l.__litecanvas}}};for(let e of["sin","cos","atan2","hypot","tan","abs","ceil","round","floor","trunc","min","max","pow","sqrt","sign","exp"])k[e]=Math[e];function C(){c=!0;let t=e.loop?e.loop:l;for(let e in S)t[e]&&k.listen(e,t[e]);for(let[e,t]of f)z(e,t);if((p||d)&&s(l,"resize",X),X(),e.tapEvents){let e=(e,t)=>[(e-u.offsetLeft)/g,(t-u.offsetTop)/g],t=new Map,a=(e,a,l)=>{let n={x:a,y:l,startX:a,startY:l,ts:performance.now()};return t.set(e,n),n},n=(e,l,n)=>{let i=t.get(e)||a(e);i.x=l,i.y=n},i=e=>e&&performance.now()-e.ts<=200,r=!1;s(u,"mousedown",t=>{t.preventDefault();let[l,n]=e(t.pageX,t.pageY);k.emit("tap",l,n,0),a(0,l,n),r=!0}),s(u,"mousemove",t=>{t.preventDefault();let[a,l]=e(t.pageX,t.pageY);k.setvar("MOUSEX",a),k.setvar("MOUSEY",l),r&&(k.emit("tapping",a,l,0),n(0,a,l))}),s(u,"mouseup",a=>{a.preventDefault();let l=t.get(0),[n,o]=e(a.pageX,a.pageY);i(l)&&k.emit("tapped",l.startX,l.startY,0),k.emit("untap",n,o,0),t.delete(0),r=!1}),s(u,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l.pageX,l.pageY);k.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),s(u,"touchmove",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,l]=e(a.pageX,a.pageY);k.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let o=e=>{e.preventDefault();let a=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,l]of t)a.includes(e)||(i(l)&&k.emit("tapped",l.startX,l.startY,e),k.emit("untap",l.x,l.y,e),t.delete(e))};s(u,"touchend",o),s(u,"touchcancel",o),s(l,"blur",()=>{for(let[e,a]of(r=!1,t))k.emit("untap",a.x,a.y,e),t.delete(e)})}if(e.keyboardEvents){let e=new Set;k.setvar("iskeydown",t=>"any"===t?e.size>0:e.has(t.toLowerCase())),s(l,"keydown",t=>{e.add(t.key.toLowerCase())}),s(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),s(l,"blur",()=>e.clear())}e.pauseOnBlur&&(s(l,"blur",()=>{x=cancelAnimationFrame(x)}),s(l,"focus",()=>{x||(x=r(L))})),k.setfps(60),k.emit("init",k),b=performance.now(),x=r(L)}function L(e){h&&(x=r(L));let t=0,a=(e-b)/1e3;if(b=e,!(a>1)){for(T+=a,h||(T=w);T>=w;T-=w)k.emit("update",w*E),k.setvar("ELAPSED",k.ELAPSED+w*E),t++;t&&(k.textalign("start","top"),k.emit("draw"))}}function X(){let t=l.innerWidth,a=l.innerHeight,n=u.style;n.display="block",p?(n.position="absolute",n.inset=0,k.setvar("WIDTH",u.width=t),k.setvar("HEIGHT",u.height=a)):d&&(n.margin="auto",g=Math.min(t/k.WIDTH,a/k.HEIGHT),g=(e.pixelart?~~g:g)||1,n.width=k.WIDTH*g+"px",n.height=k.HEIGHT*g+"px"),k.setvar("CENTERX",k.WIDTH/2),k.setvar("CENTERY",k.HEIGHT/2),(!e.antialias||e.pixelart)&&(m.imageSmoothingEnabled=!1,u.style.imageRendering="pixelated"),k.emit("resized",g),h||r(L)}function O(e,t,a,l,n){if(S[e])for(let i of S[e])i(t,a,l,n)}function z(e,t){let a=e(k,A,t);if("object"==typeof a)for(let e of Object.keys(a))k.setvar(e,a[e])}if(I){if(l.__litecanvas)throw"global litecanvas already instantiated";Object.assign(l,k),l.__litecanvas=k}return u="string"==typeof u?document.querySelector(u):u,k.setvar("CANVAS",u),m=u.getContext("2d"),s(u,"click",()=>l.focus()),k.WIDTH>0&&(p=!1),u.style="",u.width=k.WIDTH,u.height=k.HEIGHT||k.WIDTH,u.parentNode||document.body.appendChild(u),"loading"===document.readyState?s(l,"DOMContentLoaded",()=>r(C)):r(C),k}})();
1
+ (()=>{var e=new AudioContext,t=(t=1,a=.05,l=220,n=0,i=0,o=.1,r=0,s=1,c=0,f=0,u=0,d=0,p=0,h=0,g=0,m=0,v=0,E=1,b=0,w=0,T=0)=>{let x=Math,H=2*x.PI,y=c*=500*H/44100/44100,I=l*=(1-a+2*a*x.random(a=[]))*H/44100,D=0,S=0,A=0,k=1,C=0,L=0,X=0,P=T<0?-1:1,z=H*P*T*2/44100,M=x.cos(z),O=x.sin,Y=O(z)/4,F=1+Y,W=-2*M/F,_=(1-Y)/F,R=(1+P*M)/2/F,G=-(P+M)/F,N=0,B=0,U=0,q=0;for(n=44100*n+9,b*=44100,i*=44100,o*=44100,v*=44100,f*=500*H/85766121e6,g*=H/44100,u*=H/44100,d*=44100,p=44100*p|0,t*=.3*(globalThis.zzfxV||1),P=n+b+i+o+v|0;A<P;a[A++]=X*t)++L%(100*m|0)||(X=r?1<r?2<r?3<r?O(D*D):x.max(x.min(x.tan(D),1),-1):1-(2*D/H%2+2)%2:1-4*x.abs(x.round(D/H)-D/H):O(D),X=(p?1-w+w*O(H*A/p):1)*(X<0?-1:1)*x.abs(X)**s*(A<n?A/n:A<n+b?1-(A-n)/b*(1-E):A<n+b+i?E:A<P-v?(P-A-v)/o*E:0),X=v?X/2+(v>A?0:(A<P-v?1:(P-A)/v)*a[A-v|0]/2/t):X,T&&(X=q=R*N+G*(N=B)+R*(B=X)-_*U-W*(U=q))),D+=(z=(l+=c+=f)*x.cos(g*S++))+z*h*O(A**5),k&&++k>d&&(l+=u,I+=u,k=0),!p||++C%p||(l=I,c=y,k=k||1);(t=e.createBuffer(1,P,44100)).getChannelData(0).set(a),(l=e.createBufferSource()).buffer=t,l.connect(e.destination),l.start()},a=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(e={}){let l=globalThis,n=Math.PI,i=2*n,o=requestAnimationFrame,r=[],s=(e,t,a)=>{e.addEventListener(t,a,!1),r.push(()=>e.removeEventListener(t,a,!1))};e=Object.assign({fullscreen:!0,width:null,height:null,autoscale:!0,pixelart:!1,antialias:!1,canvas:null,global:!0,loop:null,pauseOnBlur:!0,tapEvents:!0,keyboardEvents:!0,animate:!0},e);let c=!1,f=[],u=e.canvas||document.createElement("canvas"),d=e.fullscreen,p=e.autoscale,h=e.animate,g=1,m,v=.5,E=1,b,w,T=0,x,H="sans-serif",y=32,I=Date.now(),D=e.global,S={init:null,update:null,draw:null,resized:null,tap:null,untap:null,tapping:null,tapped:null},A={settings:Object.assign({},e),colors:a},k={WIDTH:e.width,HEIGHT:e.height||e.width,CANVAS:null,ELAPSED:0,CENTERX:0,CENTERY:0,MOUSEX:-1,MOUSEY:-1,DEFAULT_SFX:[.5,,1675,,.06,.2,1,1.8,,,637,.06],TWO_PI:i,HALF_PI:n/2,lerp:(e,t,a)=>a*(t-e)+e,deg2rad:e=>n/180*e,rad2deg:e=>180/n*e,clamp:(e,t,a)=>e<t?t:e>a?a:e,wrap:(e,t,a)=>e-(a-t)*Math.floor((e-t)/(a-t)),map(e,t,a,l,n,i){let o=(e-t)/(a-t)*(n-l)+l;return i?k.clamp(o,l,n):o},norm:(e,t,a)=>k.map(e,t,a,0,1),rand:(e=0,t=1)=>(I=(1664525*I+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>Math.floor(k.rand(e,t+1)),seed:e=>null==e?I:I=~~e,cls(e){null==e?m.clearRect(0,0,m.canvas.width,m.canvas.height):k.rectfill(0,0,m.canvas.width,m.canvas.height,e)},rect(e,t,a,l,n,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e-v,~~t-v,~~a+2*v,~~l+2*v,i),k.stroke(n)},rectfill(e,t,a,l,n,i=null){m.beginPath(),m[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),k.fill(n)},circ(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,~~a,0,i),k.stroke(l)},circfill(e,t,a,l){m.beginPath(),m.arc(~~e,~~t,~~a,0,i),k.fill(l)},line(e,t,a,l,n){m.beginPath();let i=.5*(0!==v&&~~e==~~a),o=.5*(0!==v&&~~t==~~l);m.moveTo(~~e+i,~~t+o),m.lineTo(~~a+i,~~l+o),k.stroke(n)},linewidth(e){m.lineWidth=~~e,v=.5*(~~e%2!=0)},linedash(e,t=0){m.setLineDash(e),m.lineDashOffset=t},text(e,t,a,l=3,n="normal"){m.font=`${n} ${y}px ${H}`,m.fillStyle=k.getcolor(l),m.fillText(a,~~e,~~t)},textfont(e){H=e},textsize(e){y=e},textalign(e,t){e&&(m.textAlign=e),t&&(m.textBaseline=t)},image(e,t,a){m.drawImage(a,~~e,~~t)},paint(e,t,a,l={}){let n=l.canvas||new OffscreenCanvas(1,1),i=l.scale||1,o=m;if(n.width=e*i,n.height=t*i,(m=n.getContext("2d")).scale(i,i),a.push){let e=0,t=0;for(let l of(m.imageSmoothingEnabled=!1,a)){for(let a of l)" "!==a&&"."!==a&&k.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(m);return m=o,n},ctx:e=>(e&&(m=e),m),push:()=>m.save(),pop:()=>m.restore(),translate:(e,t)=>m.translate(~~e,~~t),scale:(e,t)=>m.scale(e,t||e),rotate:e=>m.rotate(e),alpha(e){m.globalAlpha=k.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){m.fillStyle=k.getcolor(e),t?m.fill(t):m.fill()},stroke(e,t){m.strokeStyle=k.getcolor(e),t?m.stroke(t):m.stroke()},clip(e){m.clip(e)},sfx:(e,a=0,n=1)=>!(l.zzfxV<=0)&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||k.DEFAULT_SFX,(0!==a||1!==n)&&((e=e.slice())[0]=n*(e[0]||1),e[10]=~~e[10]+a),t.apply(0,e),e),volume(e){l.zzfxV=e},colrect:(e,t,a,l,n,i,o,r)=>e<n+o&&e+a>n&&t<i+r&&t+l>i,colcirc:(e,t,a,l,n,i)=>(l-e)*(l-e)+(n-t)*(n-t)<=(a+i)*(a+i),use(e,t={}){c?z(e,t):f.push([e,t])},listen:(e,t)=>(S[e]=S[e]||new Set,S[e].add(t),()=>S[e].delete(t)),emit(e,t,a,l,n){P("before:"+e,t,a,l,n),P(e,t,a,l,n),P("after:"+e,t,a,l,n)},getcolor:e=>a[~~e%a.length],setvar(e,t){k[e]=t,D&&(l[e]=t)},resize(e,t){k.setvar("WIDTH",u.width=e),k.setvar("HEIGHT",u.height=t),X()},timescale(e){E=e},setfps(e){w=1/~~e},quit(){for(let e of(k.emit("quit"),r))e();if(cancelAnimationFrame(x),S=!1,D){for(let e in k)delete l[e];delete l.__litecanvas}}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,round,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))k[e]=Math[e];function C(){c=!0;let t=e.loop?e.loop:l;for(let e in S)t[e]&&k.listen(e,t[e]);for(let[e,t]of f)z(e,t);if((d||p)&&s(l,"resize",X),X(),e.tapEvents){let e=(e,t)=>[(e-u.offsetLeft)/g,(t-u.offsetTop)/g],t=new Map,a=(e,a,l)=>{let n={x:a,y:l,startX:a,startY:l,ts:performance.now()};return t.set(e,n),n},n=(e,l,n)=>{let i=t.get(e)||a(e);i.x=l,i.y=n},i=e=>e&&performance.now()-e.ts<=200,o=e=>e.preventDefault(),r=!1;s(u,"mousedown",t=>{if(0===t.button){o(t);let[l,n]=e(t.pageX,t.pageY);k.emit("tap",l,n,0),a(0,l,n),r=!0}}),s(u,"mouseup",a=>{if(0===a.button){o(a);let l=t.get(0),[n,s]=e(a.pageX,a.pageY);i(l)&&k.emit("tapped",l.startX,l.startY,0),k.emit("untap",n,s,0),t.delete(0),r=!1}}),s(u,"mousemove",t=>{o(t);let[a,l]=e(t.pageX,t.pageY);k.setvar("MOUSEX",a),k.setvar("MOUSEY",l),r&&(k.emit("tapping",a,l,0),n(0,a,l))}),s(u,"touchstart",t=>{for(let l of(o(t),t.changedTouches)){let[t,n]=e(l.pageX,l.pageY);k.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),s(u,"touchmove",t=>{for(let a of(o(t),t.changedTouches)){let[t,l]=e(a.pageX,a.pageY);k.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let c=e=>{o(e);let a=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,l]of t)a.includes(e)||(i(l)&&k.emit("tapped",l.startX,l.startY,e),k.emit("untap",l.x,l.y,e),t.delete(e))};s(u,"touchend",c),s(u,"touchcancel",c),s(l,"blur",()=>{for(let[e,a]of(r=!1,t))k.emit("untap",a.x,a.y,e),t.delete(e)})}if(e.keyboardEvents){let e=new Set;k.setvar("iskeydown",t=>"any"===t?e.size>0:e.has(t.toLowerCase())),s(l,"keydown",t=>{e.add(t.key.toLowerCase())}),s(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),s(l,"blur",()=>e.clear())}e.pauseOnBlur&&(s(l,"blur",()=>{x=cancelAnimationFrame(x)}),s(l,"focus",()=>{x||(x=o(L))})),k.setfps(60),k.emit("init",k),b=performance.now(),x=o(L)}function L(e){h&&(x=o(L));let t=0,a=(e-b)/1e3;if(b=e,!(a>30*w)){for(T+=a,h||(T=w);T>=w;T-=w)k.emit("update",w*E),k.setvar("ELAPSED",k.ELAPSED+w*E),t++;t&&(k.textalign("start","top"),k.emit("draw"))}}function X(){let t=l.innerWidth,a=l.innerHeight,n=u.style;n.display="block",d?(n.position="absolute",n.inset=0,k.setvar("WIDTH",u.width=t),k.setvar("HEIGHT",u.height=a)):p&&(n.margin="auto",g=Math.min(t/k.WIDTH,a/k.HEIGHT),g=(e.pixelart?~~g:g)||1,n.width=k.WIDTH*g+"px",n.height=k.HEIGHT*g+"px"),k.setvar("CENTERX",k.WIDTH/2),k.setvar("CENTERY",k.HEIGHT/2),(!e.antialias||e.pixelart)&&(m.imageSmoothingEnabled=!1,n.imageRendering="pixelated"),k.emit("resized",g),h||o(L)}function P(e,t,a,l,n){if(S[e])for(let i of S[e])i(t,a,l,n)}function z(e,t){let a=e(k,A,t);for(let e in a)k.setvar(e,a[e])}if(D){if(l.__litecanvas)throw"global litecanvas already instantiated";Object.assign(l,k),l.__litecanvas=k}return u="string"==typeof u?document.querySelector(u):u,k.setvar("CANVAS",u),m=u.getContext("2d"),s(u,"click",()=>l.focus()),k.WIDTH>0&&(d=!1),u.style="",u.width=k.WIDTH,u.height=k.HEIGHT||k.WIDTH,u.parentNode||document.body.appendChild(u),"loading"===document.readyState?s(l,"DOMContentLoaded",()=>o(C)):o(C),k}})();
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.74.3",
4
- "description": "Lightweight HTML5 canvas engine suitable for small games and animations.",
3
+ "version": "0.75.0",
4
+ "description": "Lightweight HTML5 canvas game engine suitable for small projects and creative coding. Inspired by PICO-8 and P5/Processing.",
5
5
  "license": "MIT",
6
6
  "author": "Luiz Bills <luizbills@pm.me>",
7
7
  "contributors": [],
8
8
  "devDependencies": {
9
- "@swc/core": "^1.11.4",
9
+ "@swc/core": "^1.11.7",
10
10
  "ava": "^6.2.0",
11
11
  "esbuild": "^0.25.0",
12
12
  "gzip-size": "^7.0.0",
13
- "prettier": "^3.5.2"
13
+ "prettier": "^3.5.3"
14
14
  },
15
15
  "homepage": "https://litecanvas.github.io/about.html",
16
16
  "repository": {
@@ -41,8 +41,11 @@
41
41
  "gamedev",
42
42
  "game",
43
43
  "engine",
44
- "library",
45
- "framework"
44
+ "javascript",
45
+ "js13k",
46
+ "creative-coding",
47
+ "pico-8",
48
+ "p5"
46
49
  ],
47
50
  "files": [
48
51
  "dist",
package/src/dev.js CHANGED
@@ -1,5 +1,4 @@
1
1
  /**
2
- *
3
2
  * @param {any} condition
4
3
  * @param {string} message
5
4
  */
package/src/index.js CHANGED
@@ -134,14 +134,6 @@ export default function litecanvas(settings = {}) {
134
134
  DEFAULT_SFX: [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
135
135
 
136
136
  /** MATH API */
137
- /**
138
- * The value of the mathematical constant PI (π).
139
- * Approximately 3.14159
140
- *
141
- * @type {number}
142
- */
143
- PI,
144
-
145
137
  /**
146
138
  * Twice the value of the mathematical constant PI (π).
147
139
  * Approximately 6.28318
@@ -159,7 +151,7 @@ export default function litecanvas(settings = {}) {
159
151
  *
160
152
  * @type {number}
161
153
  */
162
- HALF_PI: PI * 0.5,
154
+ HALF_PI: PI / 2,
163
155
 
164
156
  /**
165
157
  * Calculates a linear (interpolation) value over t%.
@@ -176,7 +168,7 @@ export default function litecanvas(settings = {}) {
176
168
  assert(isFinite(end), 'lerp: 2nd param must be a number')
177
169
  assert(isFinite(t), 'lerp: 3rd param must be a number')
178
170
  }
179
- return start + t * (end - start)
171
+ return t * (end - start) + start
180
172
  },
181
173
 
182
174
  /**
@@ -1228,26 +1220,9 @@ export default function litecanvas(settings = {}) {
1228
1220
  },
1229
1221
  }
1230
1222
 
1231
- /** Copy some functions from native `Math` object */
1232
- for (const k of [
1233
- 'sin',
1234
- 'cos',
1235
- 'atan2',
1236
- 'hypot',
1237
- 'tan',
1238
- 'abs',
1239
- 'ceil',
1240
- 'round',
1241
- 'floor',
1242
- 'trunc',
1243
- 'min',
1244
- 'max',
1245
- 'pow',
1246
- 'sqrt',
1247
- 'sign',
1248
- 'exp',
1249
- ]) {
1250
- // import some native Math functions
1223
+ // prettier-ignore
1224
+ for (const k of 'PI,sin,cos,atan2,hypot,tan,abs,ceil,round,floor,trunc,min,max,pow,sqrt,sign,exp'.split(',')) {
1225
+ // import native Math functions
1251
1226
  instance[k] = Math[k]
1252
1227
  }
1253
1228
 
@@ -1296,20 +1271,38 @@ export default function litecanvas(settings = {}) {
1296
1271
  tap.x = x
1297
1272
  tap.y = y
1298
1273
  },
1299
- _checkTapped = (tap) => tap && performance.now() - tap.ts <= 200
1274
+ _checkTapped = (tap) =>
1275
+ tap && performance.now() - tap.ts <= 200,
1276
+ preventDefault = (ev) => ev.preventDefault()
1300
1277
 
1301
1278
  let _pressingMouse = false
1302
1279
 
1303
1280
  on(_canvas, 'mousedown', (ev) => {
1304
- ev.preventDefault()
1305
- const [x, y] = _getXY(ev.pageX, ev.pageY)
1306
- instance.emit('tap', x, y, 0)
1307
- _registerTap(0, x, y)
1308
- _pressingMouse = true
1281
+ if (ev.button === 0) {
1282
+ preventDefault(ev)
1283
+ const [x, y] = _getXY(ev.pageX, ev.pageY)
1284
+ instance.emit('tap', x, y, 0)
1285
+ _registerTap(0, x, y)
1286
+ _pressingMouse = true
1287
+ }
1288
+ })
1289
+
1290
+ on(_canvas, 'mouseup', (ev) => {
1291
+ if (ev.button === 0) {
1292
+ preventDefault(ev)
1293
+ const tap = _taps.get(0)
1294
+ const [x, y] = _getXY(ev.pageX, ev.pageY)
1295
+ if (_checkTapped(tap)) {
1296
+ instance.emit('tapped', tap.startX, tap.startY, 0)
1297
+ }
1298
+ instance.emit('untap', x, y, 0)
1299
+ _taps.delete(0)
1300
+ _pressingMouse = false
1301
+ }
1309
1302
  })
1310
1303
 
1311
1304
  on(_canvas, 'mousemove', (ev) => {
1312
- ev.preventDefault()
1305
+ preventDefault(ev)
1313
1306
 
1314
1307
  const [x, y] = _getXY(ev.pageX, ev.pageY)
1315
1308
  instance.setvar('MOUSEX', x)
@@ -1321,20 +1314,8 @@ export default function litecanvas(settings = {}) {
1321
1314
  _updateTap(0, x, y)
1322
1315
  })
1323
1316
 
1324
- on(_canvas, 'mouseup', (ev) => {
1325
- ev.preventDefault()
1326
- const tap = _taps.get(0)
1327
- const [x, y] = _getXY(ev.pageX, ev.pageY)
1328
- if (_checkTapped(tap)) {
1329
- instance.emit('tapped', tap.startX, tap.startY, 0)
1330
- }
1331
- instance.emit('untap', x, y, 0)
1332
- _taps.delete(0)
1333
- _pressingMouse = false
1334
- })
1335
-
1336
1317
  on(_canvas, 'touchstart', (ev) => {
1337
- ev.preventDefault()
1318
+ preventDefault(ev)
1338
1319
  /** @type {TouchList} touches */
1339
1320
  const touches = ev.changedTouches
1340
1321
  for (const touch of touches) {
@@ -1345,7 +1326,7 @@ export default function litecanvas(settings = {}) {
1345
1326
  })
1346
1327
 
1347
1328
  on(_canvas, 'touchmove', (ev) => {
1348
- ev.preventDefault()
1329
+ preventDefault(ev)
1349
1330
  /** @type {TouchList} touches */
1350
1331
  const touches = ev.changedTouches
1351
1332
  for (const touch of touches) {
@@ -1356,7 +1337,7 @@ export default function litecanvas(settings = {}) {
1356
1337
  })
1357
1338
 
1358
1339
  const _touchEndHandler = (ev) => {
1359
- ev.preventDefault()
1340
+ preventDefault(ev)
1360
1341
  const existing = []
1361
1342
 
1362
1343
  if (ev.targetTouches.length > 0) {
@@ -1460,7 +1441,8 @@ export default function litecanvas(settings = {}) {
1460
1441
 
1461
1442
  _lastFrameTime = now
1462
1443
 
1463
- if (frameTime > 1) return
1444
+ if (frameTime > _deltaTime * 30)
1445
+ return console.log('skipping too long frame')
1464
1446
 
1465
1447
  _accumulated += frameTime
1466
1448
 
@@ -1484,11 +1466,27 @@ export default function litecanvas(settings = {}) {
1484
1466
  }
1485
1467
 
1486
1468
  function setupCanvas() {
1469
+ /** @type {HTMLCanvasElement} */
1487
1470
  _canvas =
1488
1471
  'string' === typeof _canvas
1489
1472
  ? document.querySelector(_canvas)
1490
1473
  : _canvas
1491
1474
 
1475
+ if (DEV_BUILD) {
1476
+ assert(
1477
+ _canvas && _canvas.tagName === 'CANVAS',
1478
+ 'Invalid canvas element'
1479
+ )
1480
+ assert(
1481
+ null === instance.WIDTH || instance.WIDTH > 0,
1482
+ 'Litecanvas\' "width" option should be null or a positive number'
1483
+ )
1484
+ assert(
1485
+ null === instance.HEIGHT || instance.HEIGHT > 0,
1486
+ 'Litecanvas\' "width" option should be null or a positive number'
1487
+ )
1488
+ }
1489
+
1492
1490
  instance.setvar('CANVAS', _canvas)
1493
1491
  _ctx = _canvas.getContext('2d')
1494
1492
 
@@ -1535,7 +1533,7 @@ export default function litecanvas(settings = {}) {
1535
1533
  // restore canvas image rendering properties
1536
1534
  if (!settings.antialias || settings.pixelart) {
1537
1535
  _ctx.imageSmoothingEnabled = false
1538
- _canvas.style.imageRendering = 'pixelated'
1536
+ styles.imageRendering = 'pixelated'
1539
1537
  }
1540
1538
 
1541
1539
  instance.emit('resized', _scale)
@@ -1557,10 +1555,14 @@ export default function litecanvas(settings = {}) {
1557
1555
  */
1558
1556
  function loadPlugin(callback, config) {
1559
1557
  const pluginData = callback(instance, _helpers, config)
1560
- if ('object' === typeof pluginData) {
1561
- for (const key of Object.keys(pluginData)) {
1562
- instance.setvar(key, pluginData[key])
1563
- }
1558
+ if (DEV_BUILD) {
1559
+ assert(
1560
+ null == pluginData || 'object' === typeof pluginData,
1561
+ 'Litecanvas plugins should return an object or nothing'
1562
+ )
1563
+ }
1564
+ for (const key in pluginData) {
1565
+ instance.setvar(key, pluginData[key])
1564
1566
  }
1565
1567
  }
1566
1568
 
package/src/zzfx.js CHANGED
@@ -1,111 +1,5 @@
1
1
  // ZzFXMicro - Zuper Zmall Zound Zynth - v1.3.0 by Frank Force | https://github.com/KilledByAPixel/ZzFX
2
2
  const zzfxX = /** @__PURE__ */ new AudioContext()
3
3
 
4
- export const zzfx = (
5
- p = 1,
6
- k = 0.05,
7
- b = 220,
8
- e = 0,
9
- r = 0,
10
- t = 0.1,
11
- q = 0,
12
- D = 1,
13
- u = 0,
14
- y = 0,
15
- v = 0,
16
- z = 0,
17
- l = 0,
18
- E = 0,
19
- A = 0,
20
- F = 0,
21
- c = 0,
22
- w = 1,
23
- m = 0,
24
- B = 0,
25
- N = 0
26
- ) => {
27
- let M = Math,
28
- d = 2 * M.PI,
29
- R = 44100,
30
- G = (u *= (500 * d) / R / R),
31
- C = (b *= ((1 - k + 2 * k * M.random((k = []))) * d) / R),
32
- g = 0,
33
- H = 0,
34
- a = 0,
35
- n = 1,
36
- I = 0,
37
- J = 0,
38
- f = 0,
39
- h = N < 0 ? -1 : 1,
40
- x = (d * h * N * 2) / R,
41
- L = M.cos(x),
42
- Z = M.sin,
43
- K = Z(x) / 4,
44
- O = 1 + K,
45
- X = (-2 * L) / O,
46
- Y = (1 - K) / O,
47
- P = (1 + h * L) / 2 / O,
48
- Q = -(h + L) / O,
49
- S = P,
50
- T = 0,
51
- U = 0,
52
- V = 0,
53
- W = 0
54
- e = R * e + 9
55
- m *= R
56
- r *= R
57
- t *= R
58
- c *= R
59
- y *= (500 * d) / R ** 3
60
- A *= d / R
61
- v *= d / R
62
- z *= R
63
- l = (R * l) | 0
64
- p *= 0.3 * (globalThis.zzfxV || 1)
65
- for (h = (e + m + r + t + c) | 0; a < h; k[a++] = f * p)
66
- ++J % ((100 * F) | 0) ||
67
- ((f = q
68
- ? 1 < q
69
- ? 2 < q
70
- ? 3 < q
71
- ? Z(g * g)
72
- : M.max(M.min(M.tan(g), 1), -1)
73
- : 1 - (((((2 * g) / d) % 2) + 2) % 2)
74
- : 1 - 4 * M.abs(M.round(g / d) - g / d)
75
- : Z(g)),
76
- (f =
77
- (l ? 1 - B + B * Z((d * a) / l) : 1) *
78
- (f < 0 ? -1 : 1) *
79
- M.abs(f) ** D *
80
- (a < e
81
- ? a / e
82
- : a < e + m
83
- ? 1 - ((a - e) / m) * (1 - w)
84
- : a < e + m + r
85
- ? w
86
- : a < h - c
87
- ? ((h - a - c) / t) * w
88
- : 0)),
89
- (f = c
90
- ? f / 2 +
91
- (c > a
92
- ? 0
93
- : ((a < h - c ? 1 : (h - a) / c) * k[(a - c) | 0]) /
94
- 2 /
95
- p)
96
- : f),
97
- N
98
- ? (f = W =
99
- S * T + Q * (T = U) + P * (U = f) - Y * V - X * (V = W))
100
- : 0),
101
- (x = (b += u += y) * M.cos(A * H++)),
102
- (g += x + x * E * Z(a ** 5)),
103
- n && ++n > z && ((b += v), (C += v), (n = 0)),
104
- !l || ++I % l || ((b = C), (u = G), (n = n || 1))
105
- p = zzfxX.createBuffer(1, h, R)
106
- p.getChannelData(0).set(k)
107
- b = zzfxX.createBufferSource()
108
- b.buffer = p
109
- b.connect(zzfxX.destination)
110
- b.start()
111
- }
4
+ // prettier-ignore
5
+ export const zzfx=(i=1,d=.05,z=220,e=0,P=0,S=.1,I=0,c=1,T=0,H=0,V=0,J=0,h=0,j=0,K=0,E=0,r=0,B=1,X=0,L=0,D=0)=>{let n=Math,t=2*n.PI,a=44100,F=T*=500*t/a/a,O=z*=(1-d+2*d*n.random(d=[]))*t/a,x=0,_=0,f=0,g=1,$=0,l=0,o=0,s=D<0?-1:1,u=t*s*D*2/a,G=n.cos(u),C=n.sin,Q=C(u)/4,M=1+Q,m=-2*G/M,y=(1-Q)/M,R=(1+s*G)/2/M,A=-(s+G)/M,v=R,U=0,W=0,Y=0,Z=0;for(e=a*e+9,X*=a,P*=a,S*=a,r*=a,H*=500*t/a**3,K*=t/a,V*=t/a,J*=a,h=a*h|0,i*=.3*(globalThis.zzfxV||1),s=e+X+P+S+r|0;f<s;d[f++]=o*i)++l%(100*E|0)||(o=I?1<I?2<I?3<I?C(x*x):n.max(n.min(n.tan(x),1),-1):1-(2*x/t%2+2)%2:1-4*n.abs(n.round(x/t)-x/t):C(x),o=(h?1-L+L*C(t*f/h):1)*(o<0?-1:1)*n.abs(o)**c*(f<e?f/e:f<e+X?1-(f-e)/X*(1-B):f<e+X+P?B:f<s-r?(s-f-r)/S*B:0),o=r?o/2+(r>f?0:(f<s-r?1:(s-f)/r)*d[f-r|0]/2/i):o,D&&(o=Z=v*U+A*(U=W)+R*(W=o)-y*Y-m*(Y=Z))),u=(z+=T+=H)*n.cos(K*_++),x+=u+u*j*C(f**5),g&&++g>J&&(z+=V,O+=V,g=0),!h||++$%h||(z=O,T=F,g=g||1);i=zzfxX.createBuffer(1,s,a),i.getChannelData(0).set(d),z=zzfxX.createBufferSource(),z.buffer=i,z.connect(zzfxX.destination),z.start()};