litecanvas 0.98.4 → 0.100.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/README.md +54 -41
- package/dist/dist.dev.js +52 -29
- package/dist/dist.js +46 -28
- package/dist/dist.min.js +1 -1
- package/package.json +13 -9
- package/src/index.js +69 -38
- package/src/version.js +1 -1
- package/types/global.d.ts +19 -9
- package/types/types.d.ts +19 -9
package/README.md
CHANGED
|
@@ -30,22 +30,24 @@ Litecanvas is a lightweight HTML5 canvas 2D engine suitable for small web games,
|
|
|
30
30
|
|
|
31
31
|
## Getting Started
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
You can get started using our [online playground](https://litecanvas.github.io) without installing nothing.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
If you want to test locally, just use one of the installation options.
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
### HTML/CDN
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
npm i litecanvas
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Or just create a HTML file and add a `<script>` tag with our CDN link:
|
|
39
|
+
Create a HTML file and add a `<script>` tag with our CDN link:
|
|
44
40
|
|
|
45
41
|
```html
|
|
46
42
|
<script src="https://unpkg.com/litecanvas"></script>
|
|
47
43
|
```
|
|
48
44
|
|
|
45
|
+
### Template
|
|
46
|
+
|
|
47
|
+
For those who are familiar with Node/NPM, we have a [basic template](https://github.com/litecanvas/template).
|
|
48
|
+
|
|
49
|
+
## API
|
|
50
|
+
|
|
49
51
|
### Basic game structure
|
|
50
52
|
|
|
51
53
|
```js
|
|
@@ -104,7 +106,7 @@ Each time a Litecanvas' function ask for a color, you should use an of theses co
|
|
|
104
106
|
|
|
105
107
|
```js
|
|
106
108
|
// example: draw a white rectangle
|
|
107
|
-
color = 3
|
|
109
|
+
let color = 3
|
|
108
110
|
rectfill(0, 0, 32, 32, color)
|
|
109
111
|
```
|
|
110
112
|
|
|
@@ -117,11 +119,13 @@ function draw() {
|
|
|
117
119
|
// clear and fill the game screen with color #0 (black)
|
|
118
120
|
cls(0)
|
|
119
121
|
|
|
120
|
-
// print a red
|
|
121
|
-
text(0, 0, 'Hello', 4)
|
|
122
|
+
// print a red text at x=0, y=0
|
|
123
|
+
text(0, 0, 'Hello!!!', 4)
|
|
122
124
|
}
|
|
123
125
|
```
|
|
124
126
|
|
|
127
|
+
[Live Demo](https://litecanvas.js.org?c=eJwtTDEOwjAQ2%2FMKVwxNpErNwNqdbxzXK404EpQGWoT4O6HC8mBbtjUUYYpPWqwzZnpELiFFjJlW6%2FA2qOh7sAplUBwxBVWUWXChm2DhLBKxhjKDk6aMg4c9K%2FHV7VvWxfr6%2FP%2B55xALCFlGFNmqLNgG3%2BE1%2BL3zC231le1JVFPTNG2HozOfL6wIMU0%3D)
|
|
128
|
+
|
|
125
129
|
### Drawing shapes
|
|
126
130
|
|
|
127
131
|
You can use the following functions to draw shapes:
|
|
@@ -139,18 +143,20 @@ litecanvas()
|
|
|
139
143
|
function draw() {
|
|
140
144
|
cls(0)
|
|
141
145
|
|
|
142
|
-
// draw a color filled rectangle at x=
|
|
146
|
+
// draw a color filled rectangle at x=10 and y=20
|
|
143
147
|
// with width=32 and height=32
|
|
144
148
|
// and color=3 (white)
|
|
145
|
-
rectfill(
|
|
149
|
+
rectfill(10, 20, 32, 32, 3)
|
|
146
150
|
|
|
147
|
-
// draw a circle outline at x=64 and y=
|
|
148
|
-
// with radius=
|
|
151
|
+
// draw a circle outline at x=64 and y=96
|
|
152
|
+
// with radius=50
|
|
149
153
|
// and color=5 (yellow)
|
|
150
|
-
circ(64,
|
|
154
|
+
circ(64, 96, 50, 5)
|
|
151
155
|
}
|
|
152
156
|
```
|
|
153
157
|
|
|
158
|
+
[Live Demo](https://litecanvas.js.org?c=eJxljk0KwyAQhfc5xSwNBGJ%2BFLrwMKImCoOCMU1D6d2rabIoGZhBfeN7H7pklPRPuZC6qqbVq%2BSCBx3lRmp4V5BL4UJoVsu5bQ8NJKiAIcLkEI2GaFSSfkYDMsFLdBSk17CLnl6%2FNpdsHjpZMfSHao2bbcq3a6U8Hq5iALLZTFYfUjEvOaSjDfS5h%2F7sO5SLKkOENaHzJwwfT5gH%2F4OJUrt1EYze8xmQ3SCG7QdQXAkfG3jwBlgGYHX1%2BQLFaFeI)
|
|
159
|
+
|
|
154
160
|
### Drawing sprites
|
|
155
161
|
|
|
156
162
|
```js
|
|
@@ -162,7 +168,7 @@ litecanvas({
|
|
|
162
168
|
// each visible char is a pixel
|
|
163
169
|
// numbers are colors
|
|
164
170
|
// dots are transparent pixels
|
|
165
|
-
|
|
171
|
+
let smile8x8 = `
|
|
166
172
|
.555555.
|
|
167
173
|
55555555
|
|
168
174
|
55055055
|
|
@@ -176,26 +182,26 @@ function draw() {
|
|
|
176
182
|
cls(0)
|
|
177
183
|
|
|
178
184
|
spr(
|
|
179
|
-
0, 0,
|
|
180
|
-
8, 8,
|
|
181
|
-
|
|
185
|
+
0, 0, // position X Y
|
|
186
|
+
8, 8, // the sprite Width and Height
|
|
187
|
+
smile8x8 // the sprite Pixels
|
|
182
188
|
)
|
|
183
189
|
}
|
|
184
190
|
```
|
|
185
191
|
|
|
192
|
+
[Live Demo](https://litecanvas.js.org?c=eJxtUMtqwzAQvOsr5mhDSNxCIBR67x%2B0vUWR1UigSEa7zoOQf%2B9KdkwPHfawuzOzSBM8W6PjWVNzV8DF9%2Bze8PK6U49Wqc0GtzRCBDDZaragIYuDRMgOxNnHIxWZ1cbh7MkfgoVxOsMTNAZ%2FtaHwcTwdbJZVFjqFlKurTzytOOtIg3SRJw%2BpYBl08nLuHXt5GrDeVqzrsJ0xD12t%2F4a%2Fsq603SITzMzz9F6pnzEa9imiz%2FrStLhXgQnUdJJI6SWDpjYF3aqU%2FGVI5KvvC98Lu1uVEnbKDZ8lX%2BjY48P6o%2BNFOP1UhOzsM4Gyb9XjF0Vyb7o%3D)
|
|
193
|
+
|
|
186
194
|
### Creating and drawing images
|
|
187
195
|
|
|
188
196
|
```js
|
|
189
197
|
litecanvas()
|
|
190
198
|
|
|
191
|
-
// lets create
|
|
192
|
-
|
|
193
|
-
48, 32, // image width and height
|
|
199
|
+
// lets create flag of Japan
|
|
200
|
+
let japanFlag = paint(
|
|
201
|
+
48, 32, // the image width and height
|
|
194
202
|
function () {
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
rectfill(0, 0, 48, 32, 3)
|
|
198
|
-
circfill(24, 16, 8, 4)
|
|
203
|
+
cls(3) // white background
|
|
204
|
+
circfill(24, 16, 8, 4) // red circle
|
|
199
205
|
}, {
|
|
200
206
|
// you can scale your image
|
|
201
207
|
// by default, scale=1
|
|
@@ -205,25 +211,32 @@ const japan = paint(
|
|
|
205
211
|
|
|
206
212
|
function draw() {
|
|
207
213
|
cls(0)
|
|
208
|
-
|
|
209
|
-
|
|
214
|
+
|
|
215
|
+
// draw the japanFlag image
|
|
216
|
+
image(
|
|
217
|
+
W/2 - japanFlag.width/2, // game screen center X
|
|
218
|
+
H/2 - japanFlag.height/2, // game screen center Y
|
|
219
|
+
japanFlag // the image
|
|
220
|
+
)
|
|
210
221
|
}
|
|
211
222
|
```
|
|
212
223
|
|
|
213
|
-
|
|
224
|
+
[Live Demo](https://litecanvas.js.org?c=eJxtUctOwzAQvPsr5phIgdA0QgipV4T4AeC4dTaJi%2BtUjkNUof47toOcqmJPXs%2FMPma1cizJfNOY5UKUJTS7EdIyOUarqcPQ4o1OZIRHcAivl%2FC9w4mUcZmAj%2FqpwLYq4PWuZ6gjdYxZNa4HmQY9q653kdlORjo1GGQ5fuJPCKnHbJsH%2Bdz7gbAn%2BdXZYTLNSlFWtkrrrKoLbB4L%2BJZ1lFhuIqo5ki%2FFVWEPn4cJfkOMkjSHzC7zXXP2ZzTc0qRdsfB2mwTH%2FBn1Ulx4l9IOjaU57RF2ePDoX8mARTNWy9a28ZWlFu9lhbuVeB%2BdK72foVBHR%2FZDWGYDycaxxUdSvt4oF6fL5RT%2FKD%2BTch3rNq6PGOm5uPwCs6aXUg%3D%3D)
|
|
214
225
|
|
|
215
|
-
|
|
226
|
+
> Note: It's very useful when you need to draw something the same way every time. This way, you create an image of that drawing, working as a kind of cache.
|
|
227
|
+
|
|
228
|
+
You can also draw PNG/JPG image files, but you'll need to load them first:
|
|
216
229
|
|
|
217
230
|
```js
|
|
218
231
|
litecanvas()
|
|
219
232
|
|
|
220
|
-
let
|
|
233
|
+
let myImage
|
|
221
234
|
|
|
222
235
|
function init() {
|
|
223
236
|
// load a image from its URL
|
|
224
|
-
|
|
237
|
+
let img = new Image()
|
|
225
238
|
img.onload = () => {
|
|
226
|
-
|
|
239
|
+
myImage = img
|
|
227
240
|
}
|
|
228
241
|
img.src = 'https://litecanvas.js.org/icons/icon-128.png'
|
|
229
242
|
}
|
|
@@ -231,17 +244,19 @@ function init() {
|
|
|
231
244
|
function draw() {
|
|
232
245
|
cls(0)
|
|
233
246
|
|
|
234
|
-
if (!
|
|
247
|
+
if (!myImage) {
|
|
235
248
|
// if not loaded, show this message
|
|
236
249
|
text(10, 10, 'Loading image...')
|
|
237
250
|
} else {
|
|
238
251
|
// when loaded, draw the image file
|
|
239
|
-
image(0, 0,
|
|
252
|
+
image(0, 0, myImage)
|
|
240
253
|
}
|
|
241
254
|
}
|
|
242
255
|
```
|
|
243
256
|
|
|
244
|
-
|
|
257
|
+
[Live Demo](https://litecanvas.js.org?c=eJxVkMFOwzAMhu95CnNqKo1044SQyh1pJyQeIGrTNih1ptpQEOq742RtGVGSg%2F37s38Hz66x%2BGlJl0oFxzB%2Bv4y2d0p1H9iwjwgePesSfhTIqSoI0bZgwScZdFMcwTPB2%2Bs5CxLDjz3UgG6GzBJ0ykjURMzVNQiwfl6Z6axtJSOyHF32IpoaiRcD84WeqirsM5t3MnHqK99EpPzfnx4ezQX7Qi03DtrJzruDJpA%2BitlM70Dfra3Lm2nEpaQwcjbr2gPQEGfgwROMjigtaNOy%2B2J9Oh4gveIseo%2F9dTvGmOLqfQEXyP3vMA8Od34aUfhuW6sPfx1ySAtd7jbsuqLlFwWNf7A%3D)
|
|
258
|
+
|
|
259
|
+
If you need to load multiple assets (images, fonts, music, etc.), I recommend you the [Asset Loader Plugin](https://github.com/litecanvas/plugin-asset-loader).
|
|
245
260
|
|
|
246
261
|
### Keyboard
|
|
247
262
|
|
|
@@ -258,9 +273,7 @@ function update() {
|
|
|
258
273
|
}
|
|
259
274
|
|
|
260
275
|
// Returns the last key pressed in your keyboard.
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
console.log(key)
|
|
276
|
+
let key = lastkey()
|
|
264
277
|
}
|
|
265
278
|
```
|
|
266
279
|
|
|
@@ -324,7 +337,7 @@ You can find a complete list of everything litecanvas has to offer on our [cheat
|
|
|
324
337
|
|
|
325
338
|
Try some demos in the playground:
|
|
326
339
|
|
|
327
|
-
- [Bouncing Ball](https://litecanvas.js.org?c=
|
|
340
|
+
- [Bouncing Ball](https://litecanvas.js.org?c=eJxtksFygyAQhu8%2BxR7VmGjSdqZNag89%2BQaeGcAMM1QdRBsm8d27Co3Y9MAM7M%2F%2B%2By2L5BraphNaNDXkMHAa7rMswRUlAeBZNlRoM%2B3PigxuqwgTfYf3n1%2BDQArNKakH0oVREFR9TWczUQsdRnD1XDDhejmW8SExxyI9jKfF1UrZJGB49Hz6lhHNQ6at1y%2Fs7gKb%2FO6MpxiY9nWz0o3VPRhr4Mov%2BV6GJy%2FpaQqfDbJxaKoKODvzDqOignAh27j3%2BYASbjcPeeuEd8hsNyucOIft%2FvRPNNu9vcxhr%2FkcqCRfrVc1cWNJoHR1Ikwa%2F9JhX3DnKx4wzIzxWHGaUOF8Z1t%2FRkyRbzdrKrswi6YuqFC0ElL6iItd4mCfovW4px%2BIrRjrprjuVY1fAyNY8gdFptV%2F)
|
|
328
341
|
- [Scroller](https://litecanvas.js.org?c=eJxVUM1SgzAQvvMU68FpAhFDLVpH%2BxbOcOj0ECGUzATSIYsyOn13NwXRHpJNvv1%2BkrUGdam6D%2BUZj6J66Eo0rgPTGQTG4TsCaLX36qhhB6tC29K1GtCBXYQ3KyKN1C6onpSl034jcvEonsRWPItMiiw7ROd%2F9sOpUqiBVThFePMV%2FIv7OSu1ujtiQ52G4FxeAu528CAlxFDhHNiqkY0C1pJfuVe9%2Bvx9fGk9ozZA7XpgViMYEsoXKq9wnUZYkkwqgMBEYr4lTKZZbPiC0kLdh%2FRZ7Yd3jz0zArI%2FVumsCySax762zvUM4%2FyWbnMYP1yoqEcMn2dh4wvExsTEAYpluhXQJGuZeNORx4bHjZjfIKaUIDvTAH4AEIGEgw%3D%3D)
|
|
329
342
|
- [3D projection](https://litecanvas.js.org?c=eJyNVcuS2jAQvPsrJofUykE8wykJySlVyRckuy4fZGwWgZEpWQSWFP%2BeGUlgizVLqgyyprul1mgkl9IUc6H%2BiJrFUbTYqbmRlQKppGEx%2FI0AanksYAa%2F4Cv8gG%2F4G8IUPmEfW4S3uloVTjSDBAMAyZjDCJ%2BUuy6%2Bj8MuRWw3pREqqUzdqPs0I4d2k3IYDiE5cHjhcEwdr4vWRjqA%2Fj2kRQgHuwm8jvc7gbTJVZHTYikg1HNJyR1Fp1byd9tcmILlxm2AI%2FWQNRiNIwwsKg2sLAxIkn7G5otP4qAs1LNZYqjXc2KAeaVqgzhl2LImG2G0PLDBYOBUiUxjS6UxdWWEc4i0za5kNoC2fjNrJOY0luPf5D5euJ5yh%2F%2FUzb%2FkCx02oqbiAvopyGGuxd4X8Lys2SimxG139ZIRt5Sq2MvcLNmEukYLVZeUc6rqCbdFbpGuVE%2Bv06vQDZMcmIQejGN4D1PeeI9DGlIQZS1u7EK3BBxkB%2BFkD84WV9Ne9VkkOGTc14QzSitmfrtFmozoOTMoMA4C2TUjuzA%2BhjP6PaEJfbZtuYl5VVLBCdT4omwwXe0tdg1kXpR1iDIvys4AInIBzE30bjZzjBjMElvA7YXvWleaPfzEy62UObiqL%2BoHWwpuVF3U56PYtdPWabDbKHC1mLhL6KJaOdUKVXYZ%2BNqo3Mmqdxt71F3kolw75Zrmc8p1WwlW16NUyjRZp%2FAB87NOk1XqCSffOmsYx%2FFQEp2xEy1XF2anFXGC3WvOtha5xEPg5vXsm7f5vKovAns1qla3TQyRUDby12KXn8e3%2FFwNE85y45tz7TE084aTp%2F93cisP95Pw6qPYdhLc2f4LGJpJDngukxf6O6Yk%2FgdWEko3)
|
|
330
343
|
- [Rendering Benchmark](https://litecanvas.js.org?c=eJylVVtP2zAUfs%2BvsLpJSSCkSS9QurYTQkx7AAkB0x6qariJ21q4See40Az633dsp8G9UNDmB1Kf853j71yJ0iQTKEoTwVOWoS6K02g%2BJYnwI06wIBeMyJtjx%2FTRdq0V0KdJQvj3u6tLMLm3OqDtWQhOJwN9Mu6dTdN5ItqdanHXSowmnIy6la9YqbthEFR68KdTxW8gmhLR3IcAc%2Bnk4W1ETSFqexANhWjsQbQUorUHER5rIsd7MHVNpV5w6VRV3mT2UCZyRrqVWZpRQdOkjThhWNBHUil8RTh5xBmicbcSVXqdqr6vnNxbZeGGaZz7eDYjSeys6uVaG3r1nB%2BlLOVQQftTGIb2TsgQRw9jDuzj8xI8Go1sy2JEoDlnIEnIE%2Fpxc%2BmwNMKSvOspypmABgL1s7rJE6mmQIdg5mcE82hyjTmeZv6YQIvpJNkuenlBUFWvNHuisZi0QVZrvAonhI4n4KzRKpBLoEQF0Xlx9KOFpWLiq4vGroy1Qt%2B0Rpu3IcrItpaQNw3JZpyqYGaYwjgoaFjz1r79kpvtw2nAkV%2Fb25BjvEMeBFIeBFvymvRT25CfwKnDacJZkx8fn9TDsN4cDj8mf8OPfPcUzua7kudpq3W6zdP3pXxXvNKPIR%2Foz2tTZBFmpI3qqypCzkfzJJKNhGhCheMW4G%2FXt7%2BuLu4ubvyYZjOGc0fwOQF42Wx%2BRv%2FIIpk102XXoGoVQcMJGjGC1H6DN3TV1RqcFbqs6OkzzuER7Uy1rmuAYyqHoR966CgcKPkIxsORU0FBEXyBTwcZxiA4PHTXpkH6WQCYY5hVFx2YjYqOjJg2bPJtG93D%2B4z68cJDcT6QrEuVPMoTxFGX3iCsvhRQJ%2FBQ6A68f4EOyl9lSvtUPvyMgEMONBQVKLYuuVFBswblb8vIO6PJg%2Fl%2F6vec8PyWMBKJlDv3%2FfWN%2B%2FnZqMCyMrjXJaQjqBQ4Mssh78XSG8Ha%2FKkTCvtumLLYLpgujeaMOX4qmxNa65zBSkNiQoolokmzzAnc7fbDCZ3u67%2BNbPxHg3Ezk1AGq9Rzf4GOoJP8eGHI8kKWvwJluiS4gwLT%2F8oHkNmQxQt00IXBKMVLRFhGCkf5bkf5Lkf5pqNtVofm8PfMGdpN9t0h%2B1gMO5%2FVY7g7tvcH9QMxT%2FGYyKg96dRb23Ru2aN%2FASaYns8%3D)
|
package/dist/dist.dev.js
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
// src/version.js
|
|
35
|
-
var version = "0.
|
|
35
|
+
var version = "0.100.0";
|
|
36
36
|
|
|
37
37
|
// src/index.js
|
|
38
38
|
function litecanvas(settings = {}) {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
keyboardEvents: true
|
|
51
51
|
};
|
|
52
52
|
settings = Object.assign(defaults, settings);
|
|
53
|
-
let _initialized = false, _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _rngSeed = Date.now(), _colorPalette = defaultPalette, _colorPaletteState = [], _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1], _coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized", _mathFunctions = "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp", _eventListeners = {};
|
|
53
|
+
let _initialized = false, _paused = true, _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _fontLineHeight = 1.2, _rngSeed = Date.now(), _colorPalette = defaultPalette, _colorPaletteState = [], _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1], _coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized", _mathFunctions = "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp", _eventListeners = {};
|
|
54
54
|
const instance = {
|
|
55
55
|
/** @type {number} */
|
|
56
56
|
W: 0,
|
|
@@ -545,7 +545,7 @@
|
|
|
545
545
|
},
|
|
546
546
|
/** TEXT RENDERING API */
|
|
547
547
|
/**
|
|
548
|
-
* Draw text
|
|
548
|
+
* Draw text. You can use `\n` to break lines.
|
|
549
549
|
*
|
|
550
550
|
* @param {number} x
|
|
551
551
|
* @param {number} y
|
|
@@ -566,7 +566,20 @@
|
|
|
566
566
|
);
|
|
567
567
|
_ctx.font = `${fontStyle} ${_fontSize}px ${_fontFamily}`;
|
|
568
568
|
_ctx.fillStyle = getColor(color);
|
|
569
|
-
|
|
569
|
+
const messages = ("" + message).split("\n");
|
|
570
|
+
for (let i = 0; i < messages.length; i++) {
|
|
571
|
+
_ctx.fillText(messages[i], ~~x, ~~y + _fontSize * _fontLineHeight * i);
|
|
572
|
+
}
|
|
573
|
+
},
|
|
574
|
+
/**
|
|
575
|
+
* Sets the height ratio of the text lines based on current text size.
|
|
576
|
+
*
|
|
577
|
+
* Default = `1.2`
|
|
578
|
+
*
|
|
579
|
+
* @param value
|
|
580
|
+
*/
|
|
581
|
+
textgap(value) {
|
|
582
|
+
_fontLineHeight = value;
|
|
570
583
|
},
|
|
571
584
|
/**
|
|
572
585
|
* Set the font family
|
|
@@ -995,7 +1008,7 @@
|
|
|
995
1008
|
_fpsInterval = 1e3 / ~~value;
|
|
996
1009
|
},
|
|
997
1010
|
/**
|
|
998
|
-
* Returns information about
|
|
1011
|
+
* Returns information about the engine instance.
|
|
999
1012
|
*
|
|
1000
1013
|
* @param {number|string} index
|
|
1001
1014
|
* @returns {any}
|
|
@@ -1028,43 +1041,34 @@
|
|
|
1028
1041
|
_rngSeed,
|
|
1029
1042
|
// 10
|
|
1030
1043
|
_fontSize,
|
|
1031
|
-
//
|
|
1032
|
-
_fontFamily
|
|
1044
|
+
// 11
|
|
1045
|
+
_fontFamily,
|
|
1046
|
+
// 12
|
|
1047
|
+
_colorPaletteState,
|
|
1048
|
+
// 13
|
|
1049
|
+
_fontLineHeight
|
|
1033
1050
|
];
|
|
1034
1051
|
const data = { index, value: internals[index] };
|
|
1035
1052
|
instance.emit("stat", data);
|
|
1036
1053
|
return data.value;
|
|
1037
1054
|
},
|
|
1038
|
-
/**
|
|
1039
|
-
* Stops the litecanvas instance and remove all event listeners.
|
|
1040
|
-
*/
|
|
1041
|
-
quit() {
|
|
1042
|
-
instance.pause();
|
|
1043
|
-
instance.emit("quit");
|
|
1044
|
-
_eventListeners = {};
|
|
1045
|
-
for (const removeListener of _browserEventListeners) {
|
|
1046
|
-
removeListener();
|
|
1047
|
-
}
|
|
1048
|
-
if (settings.global) {
|
|
1049
|
-
for (const key in instance) {
|
|
1050
|
-
delete root[key];
|
|
1051
|
-
}
|
|
1052
|
-
delete root.ENGINE;
|
|
1053
|
-
}
|
|
1054
|
-
_initialized = false;
|
|
1055
|
-
},
|
|
1056
1055
|
/**
|
|
1057
1056
|
* Pauses the engine loop (update & draw).
|
|
1058
1057
|
*/
|
|
1059
1058
|
pause() {
|
|
1059
|
+
_paused = true;
|
|
1060
1060
|
cancelAnimationFrame(_rafid);
|
|
1061
|
-
_rafid = 0;
|
|
1062
1061
|
},
|
|
1063
1062
|
/**
|
|
1064
1063
|
* Resumes (if paused) the engine loop.
|
|
1065
1064
|
*/
|
|
1066
1065
|
resume() {
|
|
1067
|
-
|
|
1066
|
+
DEV: assert(
|
|
1067
|
+
_initialized,
|
|
1068
|
+
'[litecanvas] resume() cannot be called before the "init" event and neither after the quit() function'
|
|
1069
|
+
);
|
|
1070
|
+
if (_initialized && _paused) {
|
|
1071
|
+
_paused = false;
|
|
1068
1072
|
_accumulated = _fpsInterval;
|
|
1069
1073
|
_lastFrameTime = Date.now();
|
|
1070
1074
|
_rafid = raf(drawFrame);
|
|
@@ -1076,7 +1080,26 @@
|
|
|
1076
1080
|
* @returns {boolean}
|
|
1077
1081
|
*/
|
|
1078
1082
|
paused() {
|
|
1079
|
-
return
|
|
1083
|
+
return _paused;
|
|
1084
|
+
},
|
|
1085
|
+
/**
|
|
1086
|
+
* Shutdown the litecanvas instance and remove all event listeners.
|
|
1087
|
+
*/
|
|
1088
|
+
quit() {
|
|
1089
|
+
instance.emit("quit");
|
|
1090
|
+
instance.pause();
|
|
1091
|
+
_initialized = false;
|
|
1092
|
+
_eventListeners = {};
|
|
1093
|
+
for (const removeListener of _browserEventListeners) {
|
|
1094
|
+
removeListener();
|
|
1095
|
+
}
|
|
1096
|
+
if (settings.global) {
|
|
1097
|
+
for (const key in instance) {
|
|
1098
|
+
delete root[key];
|
|
1099
|
+
}
|
|
1100
|
+
delete root.ENGINE;
|
|
1101
|
+
}
|
|
1102
|
+
DEV: console.warn("[litecanvas] quit() terminated a Litecanvas instance.");
|
|
1080
1103
|
}
|
|
1081
1104
|
};
|
|
1082
1105
|
for (const k of _mathFunctions.split(",")) {
|
|
@@ -1428,7 +1451,7 @@
|
|
|
1428
1451
|
if ("loading" === document.readyState) {
|
|
1429
1452
|
on(root, "DOMContentLoaded", () => raf(init));
|
|
1430
1453
|
} else {
|
|
1431
|
-
raf(init);
|
|
1454
|
+
_rafid = raf(init);
|
|
1432
1455
|
}
|
|
1433
1456
|
return instance;
|
|
1434
1457
|
}
|
package/dist/dist.js
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
keyboardEvents: true
|
|
43
43
|
};
|
|
44
44
|
settings = Object.assign(defaults, settings);
|
|
45
|
-
let _initialized = false, _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _rngSeed = Date.now(), _colorPalette = defaultPalette, _colorPaletteState = [], _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1], _coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized", _mathFunctions = "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp", _eventListeners = {};
|
|
45
|
+
let _initialized = false, _paused = true, _canvas, _scale = 1, _ctx, _outline_fix = 0.5, _timeScale = 1, _lastFrameTime, _fpsInterval = 1e3 / 60, _accumulated, _rafid, _fontFamily = "sans-serif", _fontSize = 20, _fontLineHeight = 1.2, _rngSeed = Date.now(), _colorPalette = defaultPalette, _colorPaletteState = [], _defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1], _coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized", _mathFunctions = "PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp", _eventListeners = {};
|
|
46
46
|
const instance = {
|
|
47
47
|
/** @type {number} */
|
|
48
48
|
W: 0,
|
|
@@ -363,7 +363,7 @@
|
|
|
363
363
|
},
|
|
364
364
|
/** TEXT RENDERING API */
|
|
365
365
|
/**
|
|
366
|
-
* Draw text
|
|
366
|
+
* Draw text. You can use `\n` to break lines.
|
|
367
367
|
*
|
|
368
368
|
* @param {number} x
|
|
369
369
|
* @param {number} y
|
|
@@ -374,7 +374,20 @@
|
|
|
374
374
|
text(x, y, message, color = 3, fontStyle = "normal") {
|
|
375
375
|
_ctx.font = `${fontStyle} ${_fontSize}px ${_fontFamily}`;
|
|
376
376
|
_ctx.fillStyle = getColor(color);
|
|
377
|
-
|
|
377
|
+
const messages = ("" + message).split("\n");
|
|
378
|
+
for (let i = 0; i < messages.length; i++) {
|
|
379
|
+
_ctx.fillText(messages[i], ~~x, ~~y + _fontSize * _fontLineHeight * i);
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
/**
|
|
383
|
+
* Sets the height ratio of the text lines based on current text size.
|
|
384
|
+
*
|
|
385
|
+
* Default = `1.2`
|
|
386
|
+
*
|
|
387
|
+
* @param value
|
|
388
|
+
*/
|
|
389
|
+
textgap(value) {
|
|
390
|
+
_fontLineHeight = value;
|
|
378
391
|
},
|
|
379
392
|
/**
|
|
380
393
|
* Set the font family
|
|
@@ -687,7 +700,7 @@
|
|
|
687
700
|
_fpsInterval = 1e3 / ~~value;
|
|
688
701
|
},
|
|
689
702
|
/**
|
|
690
|
-
* Returns information about
|
|
703
|
+
* Returns information about the engine instance.
|
|
691
704
|
*
|
|
692
705
|
* @param {number|string} index
|
|
693
706
|
* @returns {any}
|
|
@@ -716,43 +729,30 @@
|
|
|
716
729
|
_rngSeed,
|
|
717
730
|
// 10
|
|
718
731
|
_fontSize,
|
|
719
|
-
//
|
|
720
|
-
_fontFamily
|
|
732
|
+
// 11
|
|
733
|
+
_fontFamily,
|
|
734
|
+
// 12
|
|
735
|
+
_colorPaletteState,
|
|
736
|
+
// 13
|
|
737
|
+
_fontLineHeight
|
|
721
738
|
];
|
|
722
739
|
const data = { index, value: internals[index] };
|
|
723
740
|
instance.emit("stat", data);
|
|
724
741
|
return data.value;
|
|
725
742
|
},
|
|
726
|
-
/**
|
|
727
|
-
* Stops the litecanvas instance and remove all event listeners.
|
|
728
|
-
*/
|
|
729
|
-
quit() {
|
|
730
|
-
instance.pause();
|
|
731
|
-
instance.emit("quit");
|
|
732
|
-
_eventListeners = {};
|
|
733
|
-
for (const removeListener of _browserEventListeners) {
|
|
734
|
-
removeListener();
|
|
735
|
-
}
|
|
736
|
-
if (settings.global) {
|
|
737
|
-
for (const key in instance) {
|
|
738
|
-
delete root[key];
|
|
739
|
-
}
|
|
740
|
-
delete root.ENGINE;
|
|
741
|
-
}
|
|
742
|
-
_initialized = false;
|
|
743
|
-
},
|
|
744
743
|
/**
|
|
745
744
|
* Pauses the engine loop (update & draw).
|
|
746
745
|
*/
|
|
747
746
|
pause() {
|
|
747
|
+
_paused = true;
|
|
748
748
|
cancelAnimationFrame(_rafid);
|
|
749
|
-
_rafid = 0;
|
|
750
749
|
},
|
|
751
750
|
/**
|
|
752
751
|
* Resumes (if paused) the engine loop.
|
|
753
752
|
*/
|
|
754
753
|
resume() {
|
|
755
|
-
if (_initialized &&
|
|
754
|
+
if (_initialized && _paused) {
|
|
755
|
+
_paused = false;
|
|
756
756
|
_accumulated = _fpsInterval;
|
|
757
757
|
_lastFrameTime = Date.now();
|
|
758
758
|
_rafid = raf(drawFrame);
|
|
@@ -764,7 +764,25 @@
|
|
|
764
764
|
* @returns {boolean}
|
|
765
765
|
*/
|
|
766
766
|
paused() {
|
|
767
|
-
return
|
|
767
|
+
return _paused;
|
|
768
|
+
},
|
|
769
|
+
/**
|
|
770
|
+
* Shutdown the litecanvas instance and remove all event listeners.
|
|
771
|
+
*/
|
|
772
|
+
quit() {
|
|
773
|
+
instance.emit("quit");
|
|
774
|
+
instance.pause();
|
|
775
|
+
_initialized = false;
|
|
776
|
+
_eventListeners = {};
|
|
777
|
+
for (const removeListener of _browserEventListeners) {
|
|
778
|
+
removeListener();
|
|
779
|
+
}
|
|
780
|
+
if (settings.global) {
|
|
781
|
+
for (const key in instance) {
|
|
782
|
+
delete root[key];
|
|
783
|
+
}
|
|
784
|
+
delete root.ENGINE;
|
|
785
|
+
}
|
|
768
786
|
}
|
|
769
787
|
};
|
|
770
788
|
for (const k of _mathFunctions.split(",")) {
|
|
@@ -1076,7 +1094,7 @@
|
|
|
1076
1094
|
if ("loading" === document.readyState) {
|
|
1077
1095
|
on(root, "DOMContentLoaded", () => raf(init));
|
|
1078
1096
|
} else {
|
|
1079
|
-
raf(init);
|
|
1097
|
+
_rafid = raf(init);
|
|
1080
1098
|
}
|
|
1081
1099
|
return instance;
|
|
1082
1100
|
}
|
package/dist/dist.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{var e=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(t={}){let a=window,
|
|
1
|
+
(()=>{var e=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(t={}){let a,l=window,n=Math,i=2*n.PI,o=requestAnimationFrame,r=[],s=(e,t,a)=>{e.addEventListener(t,a,!1),r.push(()=>e.removeEventListener(t,a,!1))},f=(a=new AudioContext,l.zzfxV=1,(e=1,t=.05,n=220,i=0,o=0,r=.1,s=0,f=1,c=0,d=0,u=0,p=0,h=0,g=0,m=0,v=0,w=0,x=1,b=0,y=0,k=0)=>{let E=Math,z=2*E.PI,D=c*=500*z/44100/44100,P=n*=(1-t+2*t*E.random(t=[]))*z/44100,T=0,C=0,I=0,L=1,S=0,A=0,M=0,N=k<0?-1:1,F=z*N*k*2/44100,q=E.cos(F),B=E.sin,H=B(F)/4,O=1+H,V=-2*q/O,W=(1-H)/O,R=(1+N*q)/2/O,G=-(N+q)/O,X=0,Y=0,$=0,j=0;for(i=44100*i+9,b*=44100,o*=44100,r*=44100,w*=44100,d*=500*z/85766121e6,m*=z/44100,u*=z/44100,p*=44100,h=44100*h|0,e*=.3*l.zzfxV,N=i+b+o+r+w|0;I<N;t[I++]=M*e)++A%(100*v|0)||(M=s?1<s?2<s?3<s?B(T*T):E.max(E.min(E.tan(T),1),-1):1-(2*T/z%2+2)%2:1-4*E.abs(E.round(T/z)-T/z):B(T),M=(h?1-y+y*B(z*I/h):1)*(M<0?-1:1)*E.abs(M)**f*(I<i?I/i:I<i+b?1-(I-i)/b*(1-x):I<i+b+o?x:I<N-w?(N-I-w)/r*x:0),M=w?M/2+(w>I?0:(I<N-w?1:(N-I)/w)*t[I-w|0]/2/e):M,k&&(M=j=R*X+G*(X=Y)+R*(Y=M)-W*$-V*($=j))),T+=(F=(n+=c+=d)*E.cos(m*C++))+F*g*B(I**5),L&&++L>p&&(n+=u,P+=u,L=0),!h||++S%h||(n=P,c=D,L=L||1);(e=a.createBuffer(1,N,44100)).getChannelData(0).set(t),(n=a.createBufferSource()).buffer=e,n.connect(a.destination),n.start()});t=Object.assign({width:null,height:null,autoscale:!0,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0},t);let c=!1,d=!0,u,p=1,h,g=.5,m=1,v,w=1e3/60,x,b,y="sans-serif",k=20,E=1.2,z=Date.now(),D=e,P=[],T=[.5,0,1750,,,.3,1,,,,600,.1],C={},I={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:i,HALF_PI:i/4,lerp:(e,t,a)=>a*(t-e)+e,deg2rad:e=>n.PI/180*e,rad2deg:e=>180/n.PI*e,round:(e,t=0)=>{if(!t)return n.round(e);let a=10**t;return n.round(e*a)/a},clamp:(e,t,a)=>e<t?t:e>a?a:e,wrap:(e,t,a)=>e-(a-t)*n.floor((e-t)/(a-t)),map(e,t,a,l,n,i){let o=(e-t)/(a-t)*(n-l)+l;return i?I.clamp(o,l,n):o},norm:(e,t,a)=>I.map(e,t,a,0,1),wave:(e,t,a,l=Math.sin)=>e+(l(a)+1)/2*(t-e),rand:(e=0,t=1)=>(z=(1664525*z+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>n.floor(I.rand(e,t+1)),rseed(e){z=~~e},cls(e){null==e?h.clearRect(0,0,h.canvas.width,h.canvas.height):I.rectfill(0,0,h.canvas.width,h.canvas.height,e)},rect(e,t,a,l,n,i){h.beginPath(),h[i?"roundRect":"rect"](~~e-g,~~t-g,~~a+2*g,~~l+2*g,i),I.stroke(n)},rectfill(e,t,a,l,n,i){h.beginPath(),h[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),I.fill(n)},circ(e,t,a,l){h.beginPath(),h.arc(~~e,~~t,~~a,0,i),I.stroke(l)},circfill(e,t,a,l){h.beginPath(),h.arc(~~e,~~t,~~a,0,i),I.fill(l)},oval(e,t,a,l,n){h.beginPath(),h.ellipse(~~e,~~t,~~a,~~l,0,0,i),I.stroke(n)},ovalfill(e,t,a,l,n){h.beginPath(),h.ellipse(~~e,~~t,~~a,~~l,0,0,i),I.fill(n)},line(e,t,a,l,n){h.beginPath();let i=.5*(0!==g&&~~e==~~a),o=.5*(0!==g&&~~t==~~l);h.moveTo(~~e+i,~~t+o),h.lineTo(~~a+i,~~l+o),I.stroke(n)},linewidth(e){h.lineWidth=~~e,g=.5*(0!=~~e%2)},linedash(e,t=0){h.setLineDash(e),h.lineDashOffset=t},text(e,t,a,l=3,n="normal"){h.font=`${n} ${k}px ${y}`,h.fillStyle=N(l);let i=(""+a).split("\n");for(let a=0;a<i.length;a++)h.fillText(i[a],~~e,~~t+k*E*a)},textgap(e){E=e},textfont(e){y=e},textsize(e){k=e},textalign(e,t){e&&(h.textAlign=e),t&&(h.textBaseline=t)},image(e,t,a){h.drawImage(a,~~e,~~t)},spr(e,t,a,l,n){let i=n.replace(/\s/g,"");for(let n=0;n<a;n++)for(let o=0;o<l;o++){let l=i[a*o+n]||".";"."!==l&&I.rectfill(e+n,t+o,1,1,parseInt(l,36)||0)}},paint(e,t,a,l={}){let n=l.canvas||new OffscreenCanvas(1,1),i=l.scale||1,o=h;return n.width=e*i,n.height=t*i,(h=n.getContext("2d")).scale(i,i),a(h),h=o,n.transferToImageBitmap()},ctx:e=>(e&&(h=e),h),push(){h.save()},pop(){h.restore()},translate(e,t){h.translate(~~e,~~t)},scale(e,t){h.scale(e,t||e)},rotate(e){h.rotate(e)},alpha(e){h.globalAlpha=I.clamp(e,0,1)},fill(e){h.fillStyle=N(e),h.fill()},stroke(e){h.strokeStyle=N(e),h.stroke()},clip(e){h.beginPath(),e(h),h.clip()},sfx:(e,t=0,a=1)=>!!l.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||T,(0!==t||1!==a)&&((e=e.slice())[0]=a*(e[0]||1),e[10]=~~e[10]+t),f.apply(0,e),e),volume(e){l.zzfxV=e},canvas:()=>u,use(e,t={}){var a=e,l=t;let n=a(I,l);for(let e in n)I.def(e,n[e])},listen:(e,t)=>(C[e=e.toLowerCase()]=C[e]||new Set,C[e].add(t),()=>C&&C[e].delete(t)),emit(e,t,a,l,n){c&&(M("before:"+(e=e.toLowerCase()),t,a,l,n),M(e,t,a,l,n),M("after:"+e,t,a,l,n))},pal(t=e){D=t,P=[]},palc(e,t){null==e?P=[]:P[e]=t},def(e,a){I[e]=a,t.global&&(l[e]=a)},timescale(e){m=e},framerate(e){w=1e3/~~e},stat(e){let a={index:e,value:[t,c,w/1e3,p,C,D,T,m,l.zzfxV,z,k,y,P,E][e]};return I.emit("stat",a),a.value},pause(){d=!0,cancelAnimationFrame(b)},resume(){c&&d&&(d=!1,x=w,v=Date.now(),b=o(S))},paused:()=>d,quit(){for(let e of(I.emit("quit"),I.pause(),c=!1,C={},r))e();if(t.global){for(let e in I)delete l[e];delete l.ENGINE}}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))I[e]=n[e];function L(){let e=t.loop?t.loop:l;for(let t of"init,update,draw,tap,untap,tapping,tapped,resized".split(","))e[t]&&I.listen(t,e[t]);if(t.autoscale&&s(l,"resize",A),t.tapEvents){let e=e=>[(e.pageX-u.offsetLeft)/p,(e.pageY-u.offsetTop)/p],t=new Map,a=(e,a,l)=>{let n={x:a,y:l,xi:a,yi:l,t:Date.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&&Date.now()-e.t<=300,o=!1;s(u,"mousedown",t=>{if(0===t.button){t.preventDefault();let[l,n]=e(t);I.emit("tap",l,n,0),a(0,l,n),o=!0}}),s(u,"mouseup",a=>{if(0===a.button){a.preventDefault();let l=t.get(0),[n,r]=e(a);i(l)&&I.emit("tapped",l.xi,l.yi,0),I.emit("untap",n,r,0),t.delete(0),o=!1}}),s(l,"mousemove",t=>{t.preventDefault();let[a,l]=e(t);I.def("MX",a),I.def("MY",l),o&&(I.emit("tapping",a,l,0),n(0,a,l))}),s(u,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l);I.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);I.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let r=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)&&I.emit("tapped",l.xi,l.yi,e),I.emit("untap",l.x,l.y,e),t.delete(e))};s(u,"touchend",r),s(u,"touchcancel",r),s(l,"blur",()=>{for(let[e,a]of(o=!1,t))I.emit("untap",a.x,a.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,a=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0,n="";s(l,"keydown",a=>{let l=a.key.toLowerCase();e.has(l)||(e.add(l),t.add(l),n=" "===l?"space":l)}),s(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),s(l,"blur",()=>e.clear()),I.listen("after:update",()=>t.clear()),I.def("iskeydown",t=>a(e,t)),I.def("iskeypressed",e=>a(t,e)),I.def("lastkey",()=>n)}c=!0,I.emit("init",I),I.resume()}function S(){b=o(S);let e=Date.now(),t=0,a=e-v;for(v=e,x+=a<100?a:w;x>=w;){t++,x-=w;let e=w/1e3*m;I.emit("update",e,t),I.def("T",I.T+e)}t&&(I.emit("draw",h),t>1&&(x=0))}function A(){let e=t.width>0?t.width:innerWidth,a=t.width>0?t.height||t.width:innerHeight;if(I.def("W",e),I.def("H",a),u.width=e,u.height=a,t.autoscale){let l=+t.autoscale;u.style.display||(u.style.display="block",u.style.margin="auto"),p=n.min(innerWidth/e,innerHeight/a),p=l>1&&p>l?l:p,u.style.width=e*p+"px",u.style.height=a*p+"px"}h.imageSmoothingEnabled=!1,I.textalign("start","top"),I.emit("resized",p)}function M(e,t,a,l,n){if(C[e])for(let i of C[e])i(t,a,l,n)}function N(e){return D[~~(P[e]??e)%D.length]}if(t.global){if(l.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(l,I),l.ENGINE=I}return h=(u=(u="string"==typeof t.canvas?document.querySelector(t.canvas):t.canvas)||document.createElement("canvas")).getContext("2d"),s(u,"click",()=>focus()),A(),u.parentNode||document.body.appendChild(u),u.style.imageRendering="pixelated",u.oncontextmenu=()=>!1,"loading"===document.readyState?s(l,"DOMContentLoaded",()=>o(L)):b=o(L),I}})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "litecanvas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.100.0",
|
|
4
4
|
"description": "Lightweight HTML5 canvas 2D game engine suitable for small projects and creative coding. Inspired by PICO-8 and p5.js/Processing.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Luiz Bills <luizbills@pm.me>",
|
|
@@ -31,15 +31,13 @@
|
|
|
31
31
|
"creative coding"
|
|
32
32
|
],
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@
|
|
34
|
+
"@happy-dom/global-registrator": "^18.0.1",
|
|
35
35
|
"@size-limit/preset-small-lib": "^11.2.0",
|
|
36
|
-
"@swc/core": "^1.13.
|
|
37
|
-
"@types/jsdom": "^21.1.7",
|
|
36
|
+
"@swc/core": "^1.13.19",
|
|
38
37
|
"ava": "^6.4.1",
|
|
39
|
-
"esbuild": "^0.25.
|
|
38
|
+
"esbuild": "^0.25.10",
|
|
40
39
|
"genversion": "^3.2.0",
|
|
41
40
|
"gzip-size": "^7.0.0",
|
|
42
|
-
"jsdom": "^26.1.0",
|
|
43
41
|
"prettier": "^3.6.2",
|
|
44
42
|
"sinon": "^21.0.0",
|
|
45
43
|
"size-limit": "^11.2.0",
|
|
@@ -51,7 +49,7 @@
|
|
|
51
49
|
"scripts": {
|
|
52
50
|
"prepare": "npm run build",
|
|
53
51
|
"prepublishOnly": "npm test",
|
|
54
|
-
"test": "ava --
|
|
52
|
+
"test": "ava --tap | tap-min",
|
|
55
53
|
"test:watch": "ava --watch",
|
|
56
54
|
"dev": "esbuild src/web.js --bundle --watch --outfile=samples/dist.js --servedir=samples",
|
|
57
55
|
"build": "npm run genversion && node script/build.js && size-limit",
|
|
@@ -66,8 +64,14 @@
|
|
|
66
64
|
],
|
|
67
65
|
"ava": {
|
|
68
66
|
"files": [
|
|
69
|
-
"tests/**/*.js"
|
|
70
|
-
|
|
67
|
+
"tests/**/*.js",
|
|
68
|
+
"!tests/_preload/**/*.js"
|
|
69
|
+
],
|
|
70
|
+
"require": [
|
|
71
|
+
"./tests/_preload/happy-dom.js"
|
|
72
|
+
],
|
|
73
|
+
"failFast": true,
|
|
74
|
+
"timeout": "10s"
|
|
71
75
|
},
|
|
72
76
|
"size-limit": [
|
|
73
77
|
{
|
package/src/index.js
CHANGED
|
@@ -48,6 +48,8 @@ export default function litecanvas(settings = {}) {
|
|
|
48
48
|
|
|
49
49
|
let /** @type {boolean} */
|
|
50
50
|
_initialized = false,
|
|
51
|
+
/** @type {boolean} */
|
|
52
|
+
_paused = true,
|
|
51
53
|
/** @type {HTMLCanvasElement} _canvas */
|
|
52
54
|
_canvas,
|
|
53
55
|
/** @type {number} */
|
|
@@ -71,6 +73,8 @@ export default function litecanvas(settings = {}) {
|
|
|
71
73
|
/** @type {number} */
|
|
72
74
|
_fontSize = 20,
|
|
73
75
|
/** @type {number} */
|
|
76
|
+
_fontLineHeight = 1.2,
|
|
77
|
+
/** @type {number} */
|
|
74
78
|
_rngSeed = Date.now(),
|
|
75
79
|
/** @type {string[]} */
|
|
76
80
|
_colorPalette = defaultPalette,
|
|
@@ -637,7 +641,7 @@ export default function litecanvas(settings = {}) {
|
|
|
637
641
|
|
|
638
642
|
/** TEXT RENDERING API */
|
|
639
643
|
/**
|
|
640
|
-
* Draw text
|
|
644
|
+
* Draw text. You can use `\n` to break lines.
|
|
641
645
|
*
|
|
642
646
|
* @param {number} x
|
|
643
647
|
* @param {number} y
|
|
@@ -659,7 +663,22 @@ export default function litecanvas(settings = {}) {
|
|
|
659
663
|
|
|
660
664
|
_ctx.font = `${fontStyle} ${_fontSize}px ${_fontFamily}`
|
|
661
665
|
_ctx.fillStyle = getColor(color)
|
|
662
|
-
|
|
666
|
+
|
|
667
|
+
const messages = ('' + message).split('\n')
|
|
668
|
+
for (let i = 0; i < messages.length; i++) {
|
|
669
|
+
_ctx.fillText(messages[i], ~~x, ~~y + _fontSize * _fontLineHeight * i)
|
|
670
|
+
}
|
|
671
|
+
},
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Sets the height ratio of the text lines based on current text size.
|
|
675
|
+
*
|
|
676
|
+
* Default = `1.2`
|
|
677
|
+
*
|
|
678
|
+
* @param value
|
|
679
|
+
*/
|
|
680
|
+
textgap(value) {
|
|
681
|
+
_fontLineHeight = value
|
|
663
682
|
},
|
|
664
683
|
|
|
665
684
|
/**
|
|
@@ -1056,6 +1075,7 @@ export default function litecanvas(settings = {}) {
|
|
|
1056
1075
|
'string' === typeof eventName,
|
|
1057
1076
|
'[litecanvas] emit() 1st param must be a string'
|
|
1058
1077
|
)
|
|
1078
|
+
|
|
1059
1079
|
if (_initialized) {
|
|
1060
1080
|
eventName = lowerCase(eventName)
|
|
1061
1081
|
|
|
@@ -1156,7 +1176,7 @@ export default function litecanvas(settings = {}) {
|
|
|
1156
1176
|
},
|
|
1157
1177
|
|
|
1158
1178
|
/**
|
|
1159
|
-
* Returns information about
|
|
1179
|
+
* Returns information about the engine instance.
|
|
1160
1180
|
*
|
|
1161
1181
|
* @param {number|string} index
|
|
1162
1182
|
* @returns {any}
|
|
@@ -1190,8 +1210,12 @@ export default function litecanvas(settings = {}) {
|
|
|
1190
1210
|
_rngSeed,
|
|
1191
1211
|
// 10
|
|
1192
1212
|
_fontSize,
|
|
1193
|
-
//
|
|
1213
|
+
// 11
|
|
1194
1214
|
_fontFamily,
|
|
1215
|
+
// 12
|
|
1216
|
+
_colorPaletteState,
|
|
1217
|
+
// 13
|
|
1218
|
+
_fontLineHeight,
|
|
1195
1219
|
]
|
|
1196
1220
|
|
|
1197
1221
|
const data = { index, value: internals[index] }
|
|
@@ -1202,49 +1226,24 @@ export default function litecanvas(settings = {}) {
|
|
|
1202
1226
|
return data.value
|
|
1203
1227
|
},
|
|
1204
1228
|
|
|
1205
|
-
/**
|
|
1206
|
-
* Stops the litecanvas instance and remove all event listeners.
|
|
1207
|
-
*/
|
|
1208
|
-
quit() {
|
|
1209
|
-
// stop the game loop (update & draw)
|
|
1210
|
-
instance.pause()
|
|
1211
|
-
|
|
1212
|
-
// emit "quit" event to manual clean ups
|
|
1213
|
-
instance.emit('quit')
|
|
1214
|
-
|
|
1215
|
-
// clear all engine event listeners
|
|
1216
|
-
_eventListeners = {}
|
|
1217
|
-
|
|
1218
|
-
// clear all browser event listeners
|
|
1219
|
-
for (const removeListener of _browserEventListeners) {
|
|
1220
|
-
removeListener()
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
// maybe clear global context
|
|
1224
|
-
if (settings.global) {
|
|
1225
|
-
for (const key in instance) {
|
|
1226
|
-
delete root[key]
|
|
1227
|
-
}
|
|
1228
|
-
delete root.ENGINE
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
// unset that flag
|
|
1232
|
-
_initialized = false
|
|
1233
|
-
},
|
|
1234
|
-
|
|
1235
1229
|
/**
|
|
1236
1230
|
* Pauses the engine loop (update & draw).
|
|
1237
1231
|
*/
|
|
1238
1232
|
pause() {
|
|
1233
|
+
_paused = true
|
|
1239
1234
|
cancelAnimationFrame(_rafid)
|
|
1240
|
-
_rafid = 0
|
|
1241
1235
|
},
|
|
1242
1236
|
|
|
1243
1237
|
/**
|
|
1244
1238
|
* Resumes (if paused) the engine loop.
|
|
1245
1239
|
*/
|
|
1246
1240
|
resume() {
|
|
1247
|
-
|
|
1241
|
+
DEV: assert(
|
|
1242
|
+
_initialized,
|
|
1243
|
+
'[litecanvas] resume() cannot be called before the "init" event and neither after the quit() function'
|
|
1244
|
+
)
|
|
1245
|
+
if (_initialized && _paused) {
|
|
1246
|
+
_paused = false
|
|
1248
1247
|
_accumulated = _fpsInterval
|
|
1249
1248
|
_lastFrameTime = Date.now()
|
|
1250
1249
|
_rafid = raf(drawFrame)
|
|
@@ -1257,7 +1256,39 @@ export default function litecanvas(settings = {}) {
|
|
|
1257
1256
|
* @returns {boolean}
|
|
1258
1257
|
*/
|
|
1259
1258
|
paused() {
|
|
1260
|
-
return
|
|
1259
|
+
return _paused
|
|
1260
|
+
},
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* Shutdown the litecanvas instance and remove all event listeners.
|
|
1264
|
+
*/
|
|
1265
|
+
quit() {
|
|
1266
|
+
// emit "quit" event to manual clean ups
|
|
1267
|
+
instance.emit('quit')
|
|
1268
|
+
|
|
1269
|
+
// stop the game loop (update & draw)
|
|
1270
|
+
instance.pause()
|
|
1271
|
+
|
|
1272
|
+
// deinitialize the engine
|
|
1273
|
+
_initialized = false
|
|
1274
|
+
|
|
1275
|
+
// clear all engine event listeners
|
|
1276
|
+
_eventListeners = {}
|
|
1277
|
+
|
|
1278
|
+
// clear all browser event listeners
|
|
1279
|
+
for (const removeListener of _browserEventListeners) {
|
|
1280
|
+
removeListener()
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
// maybe clear global context
|
|
1284
|
+
if (settings.global) {
|
|
1285
|
+
for (const key in instance) {
|
|
1286
|
+
delete root[key]
|
|
1287
|
+
}
|
|
1288
|
+
delete root.ENGINE
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
DEV: console.warn('[litecanvas] quit() terminated a Litecanvas instance.')
|
|
1261
1292
|
},
|
|
1262
1293
|
}
|
|
1263
1294
|
|
|
@@ -1713,7 +1744,7 @@ export default function litecanvas(settings = {}) {
|
|
|
1713
1744
|
if ('loading' === document.readyState) {
|
|
1714
1745
|
on(root, 'DOMContentLoaded', () => raf(init))
|
|
1715
1746
|
} else {
|
|
1716
|
-
raf(init)
|
|
1747
|
+
_rafid = raf(init)
|
|
1717
1748
|
}
|
|
1718
1749
|
|
|
1719
1750
|
return instance
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '0.
|
|
2
|
+
export const version = '0.100.0'
|
package/types/global.d.ts
CHANGED
|
@@ -325,7 +325,7 @@ declare global {
|
|
|
325
325
|
|
|
326
326
|
/** TEXT RENDERING API */
|
|
327
327
|
/**
|
|
328
|
-
* Draw text
|
|
328
|
+
* Draw text. You can use `\n` to break lines.
|
|
329
329
|
*
|
|
330
330
|
* @param x
|
|
331
331
|
* @param y
|
|
@@ -355,6 +355,14 @@ declare global {
|
|
|
355
355
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
|
|
356
356
|
*/
|
|
357
357
|
function textalign(align: CanvasTextAlign, baseline: CanvasTextBaseline): void
|
|
358
|
+
/**
|
|
359
|
+
* Sets the height ratio of the text lines based on current text size.
|
|
360
|
+
*
|
|
361
|
+
* Default = `1.2`
|
|
362
|
+
*
|
|
363
|
+
* @param value
|
|
364
|
+
*/
|
|
365
|
+
function textgap(value: number): void
|
|
358
366
|
|
|
359
367
|
/** BASIC GRAPHICS API */
|
|
360
368
|
/**
|
|
@@ -583,9 +591,9 @@ declare global {
|
|
|
583
591
|
*/
|
|
584
592
|
function framerate(fps: number): void
|
|
585
593
|
/**
|
|
586
|
-
* Returns information about
|
|
594
|
+
* Returns information about the engine instance.
|
|
587
595
|
*
|
|
588
|
-
* - n = 0: the settings passed to
|
|
596
|
+
* - n = 0: the settings passed to this instance
|
|
589
597
|
* - n = 1: returns true if the "init" event has already been emitted
|
|
590
598
|
* - n = 2: the current delta time (dt)
|
|
591
599
|
* - n = 3: the current canvas element scale (not the context 2D scale)
|
|
@@ -597,15 +605,13 @@ declare global {
|
|
|
597
605
|
* - n = 9: the current RNG state
|
|
598
606
|
* - n = 10: the current font size
|
|
599
607
|
* - n = 11: the current font family
|
|
608
|
+
* - n = 12: the current state of the color palette
|
|
609
|
+
* - n = 13: the current font gap
|
|
600
610
|
* - n = *any other value*: probably returns undefined
|
|
601
611
|
*
|
|
602
|
-
* @param
|
|
612
|
+
* @param index
|
|
603
613
|
*/
|
|
604
|
-
function stat(
|
|
605
|
-
/**
|
|
606
|
-
* Shutdown the litecanvas instance and remove all event listeners.
|
|
607
|
-
*/
|
|
608
|
-
function quit(): void
|
|
614
|
+
function stat(index: number | string): any
|
|
609
615
|
/**
|
|
610
616
|
* Pauses the engine loop (update & draw).
|
|
611
617
|
*/
|
|
@@ -618,4 +624,8 @@ declare global {
|
|
|
618
624
|
* Returns `true` if the engine loop is paused.
|
|
619
625
|
*/
|
|
620
626
|
function paused(): boolean
|
|
627
|
+
/**
|
|
628
|
+
* Shutdown the litecanvas instance and remove all event listeners.
|
|
629
|
+
*/
|
|
630
|
+
function quit(): void
|
|
621
631
|
}
|
package/types/types.d.ts
CHANGED
|
@@ -319,7 +319,7 @@ type LitecanvasInstance = {
|
|
|
319
319
|
|
|
320
320
|
/** TEXT RENDERING API */
|
|
321
321
|
/**
|
|
322
|
-
* Draw text
|
|
322
|
+
* Draw text. You can use `\n` to break lines.
|
|
323
323
|
*
|
|
324
324
|
* @param x
|
|
325
325
|
* @param y
|
|
@@ -349,6 +349,14 @@ type LitecanvasInstance = {
|
|
|
349
349
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
|
|
350
350
|
*/
|
|
351
351
|
textalign(align: CanvasTextAlign, baseline: CanvasTextBaseline): void
|
|
352
|
+
/**
|
|
353
|
+
* Sets the height ratio of the text lines based on current text size.
|
|
354
|
+
*
|
|
355
|
+
* Default = `1.2`
|
|
356
|
+
*
|
|
357
|
+
* @param value
|
|
358
|
+
*/
|
|
359
|
+
textgap(value: number): void
|
|
352
360
|
|
|
353
361
|
/** BASIC GRAPHICS API */
|
|
354
362
|
/**
|
|
@@ -573,9 +581,9 @@ type LitecanvasInstance = {
|
|
|
573
581
|
*/
|
|
574
582
|
framerate(fps: number): void
|
|
575
583
|
/**
|
|
576
|
-
* Returns information about
|
|
584
|
+
* Returns information about the engine instance.
|
|
577
585
|
*
|
|
578
|
-
* - n = 0: the settings passed to
|
|
586
|
+
* - n = 0: the settings passed to this instance
|
|
579
587
|
* - n = 1: returns true if the "init" event has already been emitted
|
|
580
588
|
* - n = 2: the current delta time (dt)
|
|
581
589
|
* - n = 3: the current canvas element scale (not the context 2D scale)
|
|
@@ -587,15 +595,13 @@ type LitecanvasInstance = {
|
|
|
587
595
|
* - n = 9: the current RNG state
|
|
588
596
|
* - n = 10: the current font size
|
|
589
597
|
* - n = 11: the current font family
|
|
598
|
+
* - n = 12: the current state of the color palette
|
|
599
|
+
* - n = 13: the current font gap
|
|
590
600
|
* - n = *any other value*: probably returns undefined
|
|
591
601
|
*
|
|
592
|
-
* @param
|
|
602
|
+
* @param index
|
|
593
603
|
*/
|
|
594
|
-
stat(
|
|
595
|
-
/**
|
|
596
|
-
* Stops the litecanvas instance and remove all event listeners.
|
|
597
|
-
*/
|
|
598
|
-
quit(): void
|
|
604
|
+
stat(index: number | string): any
|
|
599
605
|
/**
|
|
600
606
|
* Pauses the engine loop (update & draw).
|
|
601
607
|
*/
|
|
@@ -608,6 +614,10 @@ type LitecanvasInstance = {
|
|
|
608
614
|
* Returns `true` if the engine loop is paused.
|
|
609
615
|
*/
|
|
610
616
|
paused(): boolean
|
|
617
|
+
/**
|
|
618
|
+
* Shutdown the litecanvas instance and remove all event listeners.
|
|
619
|
+
*/
|
|
620
|
+
quit(): void
|
|
611
621
|
}
|
|
612
622
|
|
|
613
623
|
type LitecanvasOptions = {
|