@litecanvas/utils 0.24.2 → 0.25.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/all.js CHANGED
@@ -54,6 +54,8 @@
54
54
  mod: () => mod_default,
55
55
  range: () => range_default,
56
56
  resolve: () => resolve_default,
57
+ scaleImage: () => scale_image_default,
58
+ tint: () => tint_default,
57
59
  tween: () => tween,
58
60
  vec: () => vec,
59
61
  vecAbs: () => vecAbs,
@@ -729,972 +731,6 @@
729
731
  var DOWN = /* @__PURE__ */ vec(0, 1);
730
732
  var LEFT = /* @__PURE__ */ vec(-1, 0);
731
733
 
732
- // node_modules/litecanvas/src/zzfx.js
733
- var zzfxX = /* @__PURE__ */ new AudioContext();
734
- 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) => {
735
- 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;
736
- e = R * e + 9;
737
- m *= R;
738
- r *= R;
739
- t *= R;
740
- c *= R;
741
- y *= 500 * d / R ** 3;
742
- A *= d / R;
743
- v *= d / R;
744
- z *= R;
745
- l = R * l | 0;
746
- p *= 0.3 * (globalThis.zzfxV || 1);
747
- for (h = e + m + r + t + c | 0; a < h; k[a++] = f * p)
748
- ++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);
749
- p = zzfxX.createBuffer(1, h, R);
750
- p.getChannelData(0).set(k);
751
- b = zzfxX.createBufferSource();
752
- b.buffer = p;
753
- b.connect(zzfxX.destination);
754
- b.start();
755
- };
756
-
757
- // node_modules/litecanvas/src/palette.js
758
- var colors = [
759
- "#111",
760
- "#6a7799",
761
- "#aec2c2",
762
- "#FFF1E8",
763
- "#e83b3b",
764
- "#fabc20",
765
- "#155fd9",
766
- "#3cbcfc",
767
- "#327345",
768
- "#63c64d",
769
- "#6c2c1f",
770
- "#ac7c00"
771
- ];
772
-
773
- // node_modules/litecanvas/src/index.js
774
- globalThis.litecanvas = litecanvas;
775
- function litecanvas(settings = {}) {
776
- const root = globalThis, PI = Math.PI, TWO_PI = PI * 2, raf = requestAnimationFrame, _browserEventListeners = [], on = (elem, evt, callback) => {
777
- elem.addEventListener(evt, callback, false);
778
- _browserEventListeners.push(
779
- () => elem.removeEventListener(evt, callback, false)
780
- );
781
- }, defaults = {
782
- fps: 60,
783
- fullscreen: true,
784
- width: null,
785
- height: null,
786
- autoscale: true,
787
- pixelart: false,
788
- antialias: false,
789
- canvas: null,
790
- global: true,
791
- loop: null,
792
- pauseOnBlur: true,
793
- tapEvents: true,
794
- keyboardEvents: true,
795
- animate: true
796
- };
797
- settings = Object.assign(defaults, settings);
798
- let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _fullscreen = settings.fullscreen, _autoscale = settings.autoscale, _animated = settings.animate, _scale = 1, _ctx, _timeScale = 1, _lastFrame, _step, _stepMs, _accumulated = 0, _focused = true, _fontFamily = "sans-serif", _fontStyle = "", _fontSize = 32, _rng_seed = Date.now(), _global = settings.global, _events = {
799
- init: null,
800
- update: null,
801
- draw: null,
802
- resized: null,
803
- tap: null,
804
- untap: null,
805
- tapping: null,
806
- tapped: null
807
- }, _helpers = {
808
- settings: Object.assign({}, settings),
809
- colors
810
- };
811
- const instance = {
812
- /** @type {number} */
813
- WIDTH: settings.width,
814
- /** @type {number} */
815
- HEIGHT: settings.height || settings.width,
816
- /** @type {HTMLCanvasElement} */
817
- CANVAS: null,
818
- /** @type {number} */
819
- ELAPSED: 0,
820
- /** @type {number} */
821
- CENTERX: 0,
822
- /** @type {number} */
823
- CENTERY: 0,
824
- /** @type {number} */
825
- MOUSEX: -1,
826
- /** @type {number} */
827
- MOUSEY: -1,
828
- /** @type {number[]} */
829
- DEFAULT_SFX: [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
830
- /** MATH API */
831
- /**
832
- * The value of the mathematical constant PI (π).
833
- * Approximately 3.14159
834
- *
835
- * @type {number}
836
- */
837
- PI,
838
- /**
839
- * Twice the value of the mathematical constant PI (π).
840
- * Approximately 6.28318
841
- *
842
- * Note: TWO_PI radians equals 360°, PI radians equals 180°,
843
- * HALF_PI radians equals 90°, and HALF_PI/2 radians equals 45°.
844
- *
845
- * @type {number}
846
- */
847
- TWO_PI,
848
- /**
849
- * Half the value of the mathematical constant PI (π).
850
- * Approximately 1.57079
851
- *
852
- * @type {number}
853
- */
854
- HALF_PI: PI * 0.5,
855
- /**
856
- * Calculates a linear (interpolation) value over t%.
857
- *
858
- * @param {number} start
859
- * @param {number} end
860
- * @param {number} t The progress in percentage, where 0 = 0% and 1 = 100%.
861
- * @returns {number} The unterpolated value
862
- * @tutorial https://gamedev.net/tutorials/programming/general-and-gameplay-programming/a-brief-introduction-to-lerp-r4954/
863
- */
864
- lerp: (start, end, t) => start + t * (end - start),
865
- /**
866
- * Convert degrees to radians
867
- *
868
- * @param {number} degs
869
- * @returns {number} the value in radians
870
- */
871
- deg2rad: (degs) => PI / 180 * degs,
872
- /**
873
- * Convert radians to degrees
874
- *
875
- * @param {number} rads
876
- * @returns {number} the value in degrees
877
- */
878
- rad2deg: (rads) => 180 / PI * rads,
879
- /**
880
- * Constrains a number between `min` and `max`.
881
- *
882
- * @param {number} value
883
- * @param {number} min
884
- * @param {number} max
885
- * @returns {number}
886
- */
887
- clamp: (value, min, max) => {
888
- if (value < min) return min;
889
- if (value > max) return max;
890
- return value;
891
- },
892
- /**
893
- * Wraps a number between `min` (inclusive) and `max` (exclusive).
894
- *
895
- * @param {number} value
896
- * @param {number} min
897
- * @param {number} max
898
- * @returns {number}
899
- */
900
- wrap: (value, min, max) => value - (max - min) * Math.floor((value - min) / (max - min)),
901
- /**
902
- * Re-maps a number from one range to another.
903
- *
904
- * @param {number} value the value to be remapped.
905
- * @param {number} min1 lower bound of the value's current range.
906
- * @param {number} max1 upper bound of the value's current range.
907
- * @param {number} min2 lower bound of the value's target range.
908
- * @param {number} max2 upper bound of the value's target range.
909
- * @param {boolean} [withinBounds=false] constrain the value to the newly mapped range
910
- * @returns {number} the remapped number
911
- */
912
- map(value, min1, max1, min2, max2, withinBounds) {
913
- const result = (value - min1) / (max1 - min1) * (max2 - min2) + min2;
914
- return withinBounds ? instance.clamp(result, min2, max2) : result;
915
- },
916
- /**
917
- * Maps a number from one range to a value between 0 and 1.
918
- * Identical to `map(value, min, max, 0, 1)`.
919
- * Note: Numbers outside the range are not clamped to 0 and 1.
920
- *
921
- * @param {number} value
922
- * @param {number} min
923
- * @param {number} min
924
- * @returns {number} the normalized number.
925
- */
926
- norm: (value, min, max) => instance.map(value, min, max, 0, 1),
927
- /** RNG API */
928
- /**
929
- * Generates a pseudorandom float between min (inclusive) and max (exclusive)
930
- * using the Linear Congruential Generator (LCG) algorithm.
931
- *
932
- * @param {number} [min=0.0]
933
- * @param {number} [max=1.0]
934
- * @returns {number} the random number
935
- */
936
- rand: (min = 0, max = 1) => {
937
- const a = 1664525;
938
- const c = 1013904223;
939
- const m = 4294967296;
940
- _rng_seed = (a * _rng_seed + c) % m;
941
- return _rng_seed / m * (max - min) + min;
942
- },
943
- /**
944
- * Generates a pseudorandom integer between min (inclusive) and max (inclusive)
945
- *
946
- * @param {number} [min=0]
947
- * @param {number} [max=1]
948
- * @returns {number} the random number
949
- */
950
- randi: (min = 0, max = 1) => Math.floor(instance.rand(min, max + 1)),
951
- /**
952
- * If a value is passed, initializes the random number generator with an explicit seed value.
953
- * Otherwise, returns the current seed state.
954
- *
955
- * @param {number} value
956
- * @returns {number} the seed state
957
- */
958
- seed: (value) => {
959
- return null == value ? _rng_seed : _rng_seed = ~~value;
960
- },
961
- /** BASIC GRAPHICS API */
962
- /**
963
- * Clear the game screen
964
- *
965
- * @param {number|null} color The background color (from 0 to 7) or null (for transparent)
966
- */
967
- cls(color) {
968
- if (null == color) {
969
- _ctx.clearRect(0, 0, instance.WIDTH, instance.HEIGHT);
970
- } else {
971
- instance.rectfill(0, 0, instance.WIDTH, instance.HEIGHT, color);
972
- }
973
- },
974
- /**
975
- * Draw a rectangle outline
976
- *
977
- * @param {number} x
978
- * @param {number} y
979
- * @param {number} width
980
- * @param {number} height
981
- * @param {number} [color=0] the color index (generally from 0 to 7)
982
- * @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
983
- */
984
- rect(x, y, width, height, color = 0, radii = null) {
985
- _ctx.beginPath();
986
- _ctx[radii ? "roundRect" : "rect"](~~x, ~~y, width, height, radii);
987
- instance.stroke(color);
988
- },
989
- /**
990
- * Draw a color-filled rectangle
991
- *
992
- * @param {number} x
993
- * @param {number} y
994
- * @param {number} width
995
- * @param {number} height
996
- * @param {number} [color=0] the color index (generally from 0 to 7)
997
- * @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
998
- */
999
- rectfill(x, y, width, height, color = 0, radii = null) {
1000
- _ctx.beginPath();
1001
- _ctx[radii ? "roundRect" : "rect"](~~x, ~~y, width, height, radii);
1002
- instance.fill(color);
1003
- },
1004
- /**
1005
- * Draw a circle outline
1006
- *
1007
- * @param {number} x
1008
- * @param {number} y
1009
- * @param {number} radius
1010
- * @param {number} [color=0] the color index (generally from 0 to 7)
1011
- */
1012
- circ(x, y, radius, color) {
1013
- _ctx.beginPath();
1014
- _ctx.arc(~~x, ~~y, radius, 0, TWO_PI);
1015
- instance.stroke(color);
1016
- },
1017
- /**
1018
- * Draw a color-filled circle
1019
- *
1020
- * @param {number} x
1021
- * @param {number} y
1022
- * @param {number} radius
1023
- * @param {number} [color=0] the color index (generally from 0 to 7)
1024
- */
1025
- circfill(x, y, radius, color) {
1026
- _ctx.beginPath();
1027
- _ctx.arc(~~x, ~~y, radius, 0, TWO_PI);
1028
- instance.fill(color);
1029
- },
1030
- /**
1031
- * Draw a line
1032
- *
1033
- * @param {number} x1
1034
- * @param {number} y1
1035
- * @param {number} x2
1036
- * @param {number} y2
1037
- * @param {number} [color=0] the color index (generally from 0 to 7)
1038
- */
1039
- line(x1, y1, x2, y2, color) {
1040
- _ctx.beginPath();
1041
- _ctx.moveTo(~~x1, ~~y1);
1042
- _ctx.lineTo(~~x2, ~~y2);
1043
- instance.stroke(color);
1044
- },
1045
- /**
1046
- * Sets the thickness of lines
1047
- *
1048
- * @param {number} value
1049
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineWidth
1050
- */
1051
- linewidth(value) {
1052
- _ctx.lineWidth = value;
1053
- },
1054
- /**
1055
- * Sets the line dash pattern used when drawing lines
1056
- *
1057
- * @param {number[]} segments the line dash pattern
1058
- * @param {number} [offset=0] the line dash offset, or "phase".
1059
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
1060
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
1061
- */
1062
- linedash(segments, offset = 0) {
1063
- _ctx.setLineDash(segments);
1064
- _ctx.lineDashOffset = offset;
1065
- },
1066
- /** TEXT RENDERING API */
1067
- /**
1068
- * Draw text
1069
- *
1070
- * @param {number} x
1071
- * @param {number} y
1072
- * @param {string} text the text message
1073
- * @param {number} [color=3] the color index (generally from 0 to 7)
1074
- */
1075
- text(x, y, text, color = 3) {
1076
- _ctx.font = `${_fontStyle} ${_fontSize}px ${_fontFamily}`;
1077
- _ctx.fillStyle = instance.getcolor(color);
1078
- _ctx.fillText(text, ~~x, ~~y);
1079
- },
1080
- /**
1081
- * Set the font family
1082
- *
1083
- * @param {string} fontFamily
1084
- */
1085
- textfont(fontFamily) {
1086
- _fontFamily = fontFamily;
1087
- },
1088
- /**
1089
- * Set the font size
1090
- *
1091
- * @param {string} size
1092
- */
1093
- textsize(size) {
1094
- _fontSize = size;
1095
- },
1096
- /**
1097
- * Sets whether a font should be styled with a "normal", "italic", or "bold".
1098
- *
1099
- * @param {string} style
1100
- */
1101
- textstyle(style) {
1102
- _fontStyle = style || "";
1103
- },
1104
- /**
1105
- * Sets the alignment used when drawing texts
1106
- *
1107
- * @param {string} align the horizontal alignment. Possible values: "left", "right", "center", "start" or "end"
1108
- * @param {string} baseline the vertical alignment. Possible values: "top", "bottom", "middle", "hanging" or "ideographic"
1109
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textBaseline
1110
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
1111
- */
1112
- textalign(align, baseline) {
1113
- if (align) _ctx.textAlign = align;
1114
- if (baseline) _ctx.textBaseline = baseline;
1115
- },
1116
- /**
1117
- * Returns a TextMetrics object that contains information about the measured text (such as its width, for example)
1118
- *
1119
- * @param {string} text
1120
- * @param {number} [size]
1121
- * @returns {TextMetrics}
1122
- * @see https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics
1123
- */
1124
- textmetrics(text, size = _fontSize) {
1125
- _ctx.font = `${_fontStyle} ${size}px ${_fontFamily}`;
1126
- const metrics = _ctx.measureText(text);
1127
- metrics.height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
1128
- return metrics;
1129
- },
1130
- /** IMAGE GRAPHICS API */
1131
- /**
1132
- * Draw an image
1133
- *
1134
- * @param {number} x
1135
- * @param {number} y
1136
- * @param {OffscreenCanvas|HTMLImageElement|HTMLCanvasElement} image
1137
- */
1138
- image(x, y, image) {
1139
- _ctx.drawImage(image, ~~x, ~~y);
1140
- },
1141
- /**
1142
- * Creates a offscreen canvas to draw on it
1143
- *
1144
- * @param {number} width
1145
- * @param {number} height
1146
- * @param {string[]|drawCallback} draw
1147
- * @param {object} [options]
1148
- * @param {number} [options.scale=1]
1149
- * @param {OffscreenCanvas | HTMLCanvasElement} [options.canvas]
1150
- * @returns {OffscreenCanvas}
1151
- * @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
1152
- */
1153
- paint(width, height, draw, options = {}) {
1154
- const canvas = options.canvas || new OffscreenCanvas(1, 1), scale = options.scale || 1, contextOriginal = _ctx;
1155
- canvas.width = width * scale;
1156
- canvas.height = height * scale;
1157
- _ctx = canvas.getContext("2d");
1158
- _ctx.scale(scale, scale);
1159
- if (draw.push) {
1160
- let x = 0, y = 0;
1161
- _ctx.imageSmoothingEnabled = false;
1162
- for (const str of draw) {
1163
- for (const color of str) {
1164
- if (" " !== color && "." !== color) {
1165
- instance.rectfill(x, y, 1, 1, parseInt(color, 16));
1166
- }
1167
- x++;
1168
- }
1169
- y++;
1170
- x = 0;
1171
- }
1172
- } else {
1173
- draw(_ctx);
1174
- }
1175
- _ctx = contextOriginal;
1176
- return canvas;
1177
- },
1178
- /** ADVANCED GRAPHICS API */
1179
- /**
1180
- * Get or set the canvas context 2D
1181
- *
1182
- * @param {CanvasRenderingContext2D} [context]
1183
- * @returns {CanvasRenderingContext2D}
1184
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
1185
- */
1186
- ctx(context) {
1187
- if (context) {
1188
- _ctx = context;
1189
- }
1190
- return _ctx;
1191
- },
1192
- /**
1193
- * saves the current drawing style settings and transformations
1194
- *
1195
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
1196
- */
1197
- push: () => _ctx.save(),
1198
- /**
1199
- * restores the drawing style settings and transformations
1200
- *
1201
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore
1202
- */
1203
- pop: () => _ctx.restore(),
1204
- /**
1205
- * Adds a translation to the transformation matrix.
1206
- *
1207
- * @param {number} x
1208
- * @param {number} y
1209
- */
1210
- translate: (x, y) => _ctx.translate(~~x, ~~y),
1211
- /**
1212
- * Adds a scaling transformation to the canvas units horizontally and/or vertically.
1213
- *
1214
- * @param {number} x
1215
- * @param {number} [y]
1216
- */
1217
- scale: (x, y) => _ctx.scale(x, y || x),
1218
- /**
1219
- * Adds a rotation to the transformation matrix.
1220
- *
1221
- * @param {number} radians
1222
- */
1223
- rotate: (radians) => _ctx.rotate(radians),
1224
- /**
1225
- * @param {number} a
1226
- * @param {number} b
1227
- * @param {number} c
1228
- * @param {number} d
1229
- * @param {number} e
1230
- * @param {number} f
1231
- * @param {boolean} [resetFirst=true] `false` to use _ctx.transform(); by default use _ctx.setTransform()
1232
- *
1233
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setTransform
1234
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/transform
1235
- */
1236
- transform: (a, b, c, d, e, f, resetFirst = true) => _ctx[resetFirst ? "setTransform" : "transform"](a, b, c, d, e, f),
1237
- /**
1238
- * Sets the alpha (opacity) value to apply when drawing new shapes and images
1239
- *
1240
- * @param {number} alpha float from 0 to 1 (e.g: 0.5 = 50% transparent)
1241
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalAlpha
1242
- */
1243
- alpha(value) {
1244
- _ctx.globalAlpha = instance.clamp(value, 0, 1);
1245
- },
1246
- /**
1247
- * Returns a newly instantiated Path2D object, optionally with another
1248
- * path as an argument (creates a copy), or optionally with a string
1249
- * consisting of SVG path data.
1250
- *
1251
- * @param {Path2D|string} [arg]
1252
- * @returns Path2D
1253
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D
1254
- */
1255
- path: (arg) => new Path2D(arg),
1256
- /**
1257
- * Fills the current or given path with a given color.
1258
- *
1259
- * @param {number} [color=0]
1260
- * @param {Path2D} [path]
1261
- */
1262
- fill(color, path2) {
1263
- _ctx.fillStyle = instance.getcolor(color);
1264
- if (path2) {
1265
- _ctx.fill(path2);
1266
- } else {
1267
- _ctx.fill();
1268
- }
1269
- },
1270
- /**
1271
- * Outlines the current or given path with a given color.
1272
- *
1273
- * @param {number} [color=0]
1274
- * @param {Path2D} [path]
1275
- */
1276
- stroke(color, path2) {
1277
- _ctx.strokeStyle = instance.getcolor(color);
1278
- if (path2) {
1279
- _ctx.stroke(path2);
1280
- } else {
1281
- _ctx.stroke();
1282
- }
1283
- },
1284
- /**
1285
- * Turn given path into a clipping region.
1286
- *
1287
- * @param {Path2D} path
1288
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip
1289
- */
1290
- clip(path2) {
1291
- _ctx.clip(path2);
1292
- },
1293
- /** SOUND API */
1294
- /**
1295
- * Play a sound effects using ZzFX library.
1296
- * If the first argument is omitted, plays an default sound.
1297
- *
1298
- * @param {number[]} [zzfxParams] a ZzFX array of params
1299
- * @param {number} [pitchSlide] a value to increment/decrement the pitch
1300
- * @param {number} [volumeFactor] the volume factor
1301
- * @returns {number[] | boolean} The sound that was played or `false`
1302
- *
1303
- * @see https://github.com/KilledByAPixel/ZzFX
1304
- */
1305
- sfx(zzfxParams, pitchSlide = 0, volumeFactor = 1) {
1306
- if (root.zzfxV <= 0 || navigator.userActivation && !navigator.userActivation.hasBeenActive) {
1307
- return false;
1308
- }
1309
- zzfxParams = zzfxParams || instance.DEFAULT_SFX;
1310
- if (pitchSlide > 0 || volumeFactor !== 1) {
1311
- zzfxParams = zzfxParams.slice();
1312
- zzfxParams[0] = volumeFactor * (zzfxParams[0] || 1);
1313
- zzfxParams[10] = ~~zzfxParams[10] + pitchSlide;
1314
- }
1315
- zzfx.apply(0, zzfxParams);
1316
- return zzfxParams;
1317
- },
1318
- /**
1319
- * Set the ZzFX's global volume factor.
1320
- * Note: use 0 to mute all sound effects.
1321
- *
1322
- * @param {number} value
1323
- */
1324
- volume(value) {
1325
- root.zzfxV = +value;
1326
- },
1327
- /** UTILS API */
1328
- /**
1329
- * Check a collision between two rectangles
1330
- *
1331
- * @param {number} x1 first rectangle position X
1332
- * @param {number} y1 first rectangle position Y
1333
- * @param {number} w1 first rectangle width
1334
- * @param {number} h1 first rectangle height
1335
- * @param {number} x2 second rectangle position X
1336
- * @param {number} y2 second rectangle position Y
1337
- * @param {number} w2 second rectangle width
1338
- * @param {number} h2 second rectangle height
1339
- * @returns {boolean}
1340
- */
1341
- colrect: (x1, y1, w1, h1, x2, y2, w2, h2) => x1 < x2 + w2 && x1 + w1 > x2 && y1 < y2 + h2 && y1 + h1 > y2,
1342
- /**
1343
- * Check a collision between two circles
1344
- *
1345
- * @param {number} x1 first circle position X
1346
- * @param {number} y1 first circle position Y
1347
- * @param {number} r1 first circle position radius
1348
- * @param {number} x2 second circle position X
1349
- * @param {number} y2 second circle position Y
1350
- * @param {number} r2 second circle position radius
1351
- * @returns {boolean}
1352
- */
1353
- colcirc: (x1, y1, r1, x2, y2, r2) => (x2 - x1) ** 2 + (y2 - y1) ** 2 <= (r1 + r2) ** 2,
1354
- /** PLUGINS API */
1355
- /**
1356
- * Prepares a plugin to be loaded
1357
- *
1358
- * @param {pluginCallback} callback
1359
- */
1360
- use(callback, config = {}) {
1361
- _initialized ? loadPlugin(callback, config) : _plugins.push([callback, config]);
1362
- },
1363
- /**
1364
- * Add a game event listener
1365
- *
1366
- * @param {string} eventName the event type name
1367
- * @param {Function} callback the function that is called when the event occurs
1368
- * @returns {Function} a function to remove the listener
1369
- */
1370
- listen(eventName, callback) {
1371
- _events[eventName] = _events[eventName] || /* @__PURE__ */ new Set();
1372
- _events[eventName].add(callback);
1373
- return () => _events[eventName].delete(callback);
1374
- },
1375
- /**
1376
- * Call all listeners attached to a game event
1377
- *
1378
- * @param {string} eventName The event type name
1379
- * @param {*} [arg1] any data to be passed over the listeners
1380
- * @param {*} [arg2] any data to be passed over the listeners
1381
- * @param {*} [arg3] any data to be passed over the listeners
1382
- * @param {*} [arg4] any data to be passed over the listeners
1383
- */
1384
- emit(eventName, arg1, arg2, arg3, arg4) {
1385
- triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
1386
- triggerEvent(eventName, arg1, arg2, arg3, arg4);
1387
- triggerEvent("after:" + eventName, arg1, arg2, arg3, arg4);
1388
- },
1389
- /**
1390
- * Get a color by index
1391
- *
1392
- * @param {number} [index=0] The color number
1393
- * @returns {string} the color code
1394
- */
1395
- getcolor: (index) => colors[~~index % colors.length],
1396
- /**
1397
- * Create or update a instance variable
1398
- *
1399
- * @param {string} key
1400
- * @param {*} value
1401
- */
1402
- setvar(key, value) {
1403
- instance[key] = value;
1404
- if (_global) {
1405
- root[key] = value;
1406
- }
1407
- },
1408
- /**
1409
- * Resizes the game canvas and emit the "resized" event
1410
- *
1411
- * @param {number} width
1412
- * @param {number} height
1413
- */
1414
- resize(width, height) {
1415
- instance.setvar("WIDTH", _canvas.width = width);
1416
- instance.setvar("HEIGHT", _canvas.height = height || width);
1417
- pageResized();
1418
- },
1419
- /**
1420
- * The scale of the game's delta time (dt).
1421
- * Values higher than 1 increase the speed of time, while values smaller than 1 decrease it.
1422
- * A value of 0 freezes time and is effectively equivalent to pausing.
1423
- *
1424
- * @param {number} value
1425
- */
1426
- timescale(value) {
1427
- _timeScale = value;
1428
- },
1429
- /**
1430
- * Set the target FPS at runtime.
1431
- *
1432
- * @param {number} fps
1433
- */
1434
- setfps(fps) {
1435
- _step = 1 / fps;
1436
- _stepMs = _step * 1e3;
1437
- _accumulated = 0;
1438
- },
1439
- /**
1440
- * Stops the litecanvas instance and remove all event listeners.
1441
- */
1442
- quit() {
1443
- instance.emit("quit");
1444
- for (const removeListener of _browserEventListeners) {
1445
- removeListener();
1446
- }
1447
- _focused = _events = false;
1448
- if (_global) {
1449
- for (const key in instance) {
1450
- delete root[key];
1451
- }
1452
- delete root.__litecanvas;
1453
- }
1454
- }
1455
- };
1456
- for (const k of [
1457
- "sin",
1458
- "cos",
1459
- "atan2",
1460
- "hypot",
1461
- "tan",
1462
- "abs",
1463
- "ceil",
1464
- "round",
1465
- "floor",
1466
- "trunc",
1467
- "min",
1468
- "max",
1469
- "pow",
1470
- "sqrt",
1471
- "sign",
1472
- "exp"
1473
- ]) {
1474
- instance[k] = Math[k];
1475
- }
1476
- function init() {
1477
- _initialized = true;
1478
- const source = settings.loop ? settings.loop : root;
1479
- for (const event in _events) {
1480
- if (source[event]) instance.listen(event, source[event]);
1481
- }
1482
- for (const [callback, config] of _plugins) {
1483
- loadPlugin(callback, config);
1484
- }
1485
- if (_fullscreen || _autoscale) {
1486
- on(root, "resize", pageResized);
1487
- }
1488
- pageResized();
1489
- if (settings.tapEvents) {
1490
- const _getXY = (pageX, pageY) => [
1491
- (pageX - _canvas.offsetLeft) / _scale,
1492
- (pageY - _canvas.offsetTop) / _scale
1493
- ], _taps = /* @__PURE__ */ new Map(), _registerTap = (id, x, y) => {
1494
- const tap = {
1495
- x,
1496
- y,
1497
- startX: x,
1498
- startY: y,
1499
- // timestamp
1500
- ts: performance.now()
1501
- };
1502
- _taps.set(id, tap);
1503
- return tap;
1504
- }, _updateTap = (id, x, y) => {
1505
- const tap = _taps.get(id) || _registerTap(id);
1506
- tap.x = x;
1507
- tap.y = y;
1508
- }, _checkTapped = (tap) => tap && performance.now() - tap.ts <= 200;
1509
- let _pressingMouse = false;
1510
- on(_canvas, "mousedown", (ev) => {
1511
- ev.preventDefault();
1512
- const [x, y] = _getXY(ev.pageX, ev.pageY);
1513
- instance.emit("tap", x, y, 0);
1514
- _registerTap(0, x, y);
1515
- _pressingMouse = true;
1516
- });
1517
- on(_canvas, "mousemove", (ev) => {
1518
- ev.preventDefault();
1519
- const [x, y] = _getXY(ev.pageX, ev.pageY);
1520
- instance.setvar("MOUSEX", x);
1521
- instance.setvar("MOUSEY", y);
1522
- if (!_pressingMouse) return;
1523
- instance.emit("tapping", x, y, 0);
1524
- _updateTap(0, x, y);
1525
- });
1526
- on(_canvas, "mouseup", (ev) => {
1527
- ev.preventDefault();
1528
- const tap = _taps.get(0);
1529
- const [x, y] = _getXY(ev.pageX, ev.pageY);
1530
- if (_checkTapped(tap)) {
1531
- instance.emit("tapped", tap.startX, tap.startY, 0);
1532
- }
1533
- instance.emit("untap", x, y, 0);
1534
- _taps.delete(0);
1535
- _pressingMouse = false;
1536
- });
1537
- on(_canvas, "touchstart", (ev) => {
1538
- ev.preventDefault();
1539
- const touches = ev.changedTouches;
1540
- for (const touch of touches) {
1541
- const [x, y] = _getXY(touch.pageX, touch.pageY);
1542
- instance.emit("tap", x, y, touch.identifier + 1);
1543
- _registerTap(touch.identifier + 1, x, y);
1544
- }
1545
- });
1546
- on(_canvas, "touchmove", (ev) => {
1547
- ev.preventDefault();
1548
- const touches = ev.changedTouches;
1549
- for (const touch of touches) {
1550
- const [x, y] = _getXY(touch.pageX, touch.pageY);
1551
- instance.emit("tapping", x, y, touch.identifier + 1);
1552
- _updateTap(touch.identifier + 1, x, y);
1553
- }
1554
- });
1555
- const _touchEndHandler = (ev) => {
1556
- ev.preventDefault();
1557
- const existing = [];
1558
- if (ev.targetTouches.length > 0) {
1559
- for (const touch of ev.targetTouches) {
1560
- existing.push(touch.identifier + 1);
1561
- }
1562
- }
1563
- for (const [id, tap] of _taps) {
1564
- if (existing.includes(id)) continue;
1565
- if (_checkTapped(tap)) {
1566
- instance.emit("tapped", tap.startX, tap.startY, id);
1567
- }
1568
- instance.emit("untap", tap.x, tap.y, id);
1569
- _taps.delete(id);
1570
- }
1571
- };
1572
- on(_canvas, "touchend", _touchEndHandler);
1573
- on(_canvas, "touchcancel", _touchEndHandler);
1574
- on(root, "blur", () => {
1575
- _pressingMouse = false;
1576
- for (const [id, tap] of _taps) {
1577
- instance.emit("untap", tap.x, tap.y, id);
1578
- _taps.delete(id);
1579
- }
1580
- });
1581
- }
1582
- if (settings.keyboardEvents) {
1583
- const _keys = /* @__PURE__ */ new Set();
1584
- const iskeydown = (key) => "any" === key ? _keys.size > 0 : _keys.has(key.toLowerCase());
1585
- instance.setvar("iskeydown", iskeydown);
1586
- on(root, "keydown", (event) => {
1587
- _keys.add(event.key.toLowerCase());
1588
- });
1589
- on(root, "keyup", (event) => {
1590
- _keys.delete(event.key.toLowerCase());
1591
- });
1592
- on(root, "blur", () => _keys.clear());
1593
- }
1594
- if (settings.pauseOnBlur) {
1595
- on(root, "blur", () => {
1596
- _focused = false;
1597
- });
1598
- on(root, "focus", () => {
1599
- _focused = true;
1600
- raf(drawFrame);
1601
- });
1602
- }
1603
- instance.setfps(settings.fps);
1604
- instance.emit("init", instance);
1605
- _lastFrame = performance.now();
1606
- raf(drawFrame);
1607
- }
1608
- function drawFrame(now) {
1609
- let shouldRender = !_animated, delta = now - _lastFrame;
1610
- _accumulated += delta > 100 ? _stepMs : delta;
1611
- _lastFrame = now;
1612
- while (_accumulated >= _stepMs) {
1613
- instance.emit("update", _step * _timeScale);
1614
- instance.setvar("ELAPSED", instance.ELAPSED + _step * _timeScale);
1615
- _accumulated -= _stepMs;
1616
- shouldRender = true;
1617
- }
1618
- if (shouldRender) {
1619
- instance.textalign("start", "top");
1620
- instance.emit("draw");
1621
- }
1622
- if (_focused && _animated) {
1623
- raf(drawFrame);
1624
- }
1625
- }
1626
- function setupCanvas() {
1627
- _canvas = "string" === typeof _canvas ? document.querySelector(_canvas) : _canvas;
1628
- instance.setvar("CANVAS", _canvas);
1629
- _ctx = _canvas.getContext("2d");
1630
- on(_canvas, "click", () => root.focus());
1631
- if (instance.WIDTH > 0) {
1632
- _fullscreen = false;
1633
- }
1634
- _canvas.style = "";
1635
- _canvas.width = instance.WIDTH;
1636
- _canvas.height = instance.HEIGHT || instance.WIDTH;
1637
- if (!_canvas.parentNode) document.body.appendChild(_canvas);
1638
- }
1639
- function pageResized() {
1640
- const pageWidth = root.innerWidth, pageHeight = root.innerHeight, styles = _canvas.style;
1641
- styles.display = "block";
1642
- if (_fullscreen) {
1643
- styles.position = "absolute";
1644
- styles.inset = 0;
1645
- instance.setvar("WIDTH", _canvas.width = pageWidth);
1646
- instance.setvar("HEIGHT", _canvas.height = pageHeight);
1647
- } else if (_autoscale) {
1648
- styles.margin = "auto";
1649
- _scale = Math.min(
1650
- pageWidth / instance.WIDTH,
1651
- pageHeight / instance.HEIGHT
1652
- );
1653
- _scale = (settings.pixelart ? ~~_scale : _scale) || 1;
1654
- styles.width = instance.WIDTH * _scale + "px";
1655
- styles.height = instance.HEIGHT * _scale + "px";
1656
- }
1657
- instance.setvar("CENTERX", instance.WIDTH / 2);
1658
- instance.setvar("CENTERY", instance.HEIGHT / 2);
1659
- if (!settings.antialias || settings.pixelart) {
1660
- _ctx.imageSmoothingEnabled = false;
1661
- _canvas.style.imageRendering = "pixelated";
1662
- }
1663
- instance.emit("resized", _scale);
1664
- if (!_animated) {
1665
- raf(drawFrame);
1666
- }
1667
- }
1668
- function triggerEvent(eventName, arg1, arg2, arg3, arg4) {
1669
- if (!_events[eventName]) return;
1670
- for (const callback of _events[eventName]) {
1671
- callback(arg1, arg2, arg3, arg4);
1672
- }
1673
- }
1674
- function loadPlugin(callback, config) {
1675
- const pluginData = callback(instance, _helpers, config);
1676
- if ("object" === typeof pluginData) {
1677
- for (const key of Object.keys(pluginData)) {
1678
- instance.setvar(key, pluginData[key]);
1679
- }
1680
- }
1681
- }
1682
- if (_global) {
1683
- if (root.__litecanvas) {
1684
- throw "global litecanvas already instantiated";
1685
- }
1686
- Object.assign(root, instance);
1687
- root.__litecanvas = instance;
1688
- }
1689
- setupCanvas();
1690
- if ("loading" === document.readyState) {
1691
- on(root, "DOMContentLoaded", () => raf(init));
1692
- } else {
1693
- raf(init);
1694
- }
1695
- return instance;
1696
- }
1697
-
1698
734
  // src/actor/index.js
1699
735
  var ANCHOR_CENTER = /* @__PURE__ */ vec(0.5, 0.5);
1700
736
  var ANCHOR_TOP_LEFT = /* @__PURE__ */ vec(0, 0);
@@ -1821,20 +857,20 @@
1821
857
  *
1822
858
  * @param {LitecanvasInstance} [litecanvas]
1823
859
  */
1824
- draw(litecanvas2 = globalThis, saveContext = true) {
860
+ draw(litecanvas = globalThis, saveContext = true) {
1825
861
  if (this.hidden || this.opacity <= 0) return;
1826
- if (saveContext) litecanvas2.push();
1827
- this.transform(litecanvas2);
1828
- this.drawImage(litecanvas2);
1829
- if (saveContext) litecanvas2.pop();
862
+ if (saveContext) litecanvas.push();
863
+ this.transform(litecanvas);
864
+ this.drawImage(litecanvas);
865
+ if (saveContext) litecanvas.pop();
1830
866
  }
1831
867
  /**
1832
868
  * @param {LitecanvasInstance} litecanvas
1833
869
  */
1834
- transform(litecanvas2) {
1835
- litecanvas2.translate(this.pos.x, this.pos.y);
1836
- litecanvas2.rotate(litecanvas2.deg2rad(this.angle));
1837
- litecanvas2.scale(
870
+ transform(litecanvas) {
871
+ litecanvas.translate(this.pos.x, this.pos.y);
872
+ litecanvas.rotate(litecanvas.deg2rad(this.angle));
873
+ litecanvas.scale(
1838
874
  (this.flipX ? -1 : 1) * this._s.x,
1839
875
  (this.flipY ? -1 : 1) * this._s.y
1840
876
  );
@@ -1842,12 +878,12 @@
1842
878
  /**
1843
879
  * @param {LitecanvasInstance} litecanvas
1844
880
  */
1845
- drawImage(litecanvas2, alpha = true) {
881
+ drawImage(litecanvas, alpha = true) {
1846
882
  const anchor = this.anchor;
1847
883
  const x = -this.sprite.width * (this.flipX ? 1 - anchor.x : anchor.x);
1848
884
  const y = -this.sprite.height * (this.flipY ? 1 - anchor.y : anchor.y);
1849
- if (alpha) litecanvas2.alpha(this.opacity);
1850
- litecanvas2.image(x, y, this.sprite);
885
+ if (alpha) litecanvas.alpha(this.opacity);
886
+ litecanvas.image(x, y, this.sprite);
1851
887
  }
1852
888
  };
1853
889
 
@@ -2224,6 +1260,30 @@
2224
1260
  }
2225
1261
  };
2226
1262
 
1263
+ // src/image/tint.js
1264
+ var tint_default = (img, color, opacity = 1, engine = globalThis) => {
1265
+ return engine.paint(img.width, img.height, (ctx) => {
1266
+ engine.push();
1267
+ engine.alpha(opacity);
1268
+ engine.rectfill(0, 0, img.width, img.height, color);
1269
+ ctx.globalCompositeOperation = "destination-atop";
1270
+ engine.alpha(1);
1271
+ engine.image(0, 0, img);
1272
+ engine.pop();
1273
+ });
1274
+ };
1275
+
1276
+ // src/image/scale-image.js
1277
+ var scale_image_default = (img, factor, pixelart = true, engine = globalThis) => {
1278
+ return engine.paint(img.width * factor, img.height * factor, (ctx) => {
1279
+ engine.push();
1280
+ ctx.imageSmoothingEnabled = !pixelart;
1281
+ engine.scale(factor);
1282
+ engine.image(0, 0, img);
1283
+ engine.pop();
1284
+ });
1285
+ };
1286
+
2227
1287
  // src/_web.js
2228
1288
  globalThis.utils = Object.assign(globalThis.utils || {}, src_exports);
2229
1289
  })();