littlejsengine 1.19.3 → 1.20.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/FAQ.md +841 -820
- package/README.md +29 -25
- package/dist/littlejs.d.ts +2455 -935
- package/dist/littlejs.esm.js +30344 -21110
- package/dist/littlejs.esm.min.js +4 -3
- package/dist/littlejs.js +30259 -21052
- package/dist/littlejs.min.js +2 -2
- package/dist/littlejs.release.js +26567 -20455
- package/package.json +10 -5
- package/plugins/audioEffects.js +28 -24
- package/plugins/box2d.js +2516 -2073
- package/plugins/drawUtilities.js +206 -31
- package/plugins/gltf.js +740 -0
- package/plugins/jsconfig.json +19 -0
- package/plugins/lightSystem.js +719 -332
- package/plugins/math3d.js +58 -17
- package/plugins/medalSystem.js +326 -280
- package/plugins/newgrounds.js +400 -199
- package/plugins/pathFinder.js +208 -175
- package/plugins/pluginExport.js +15 -0
- package/plugins/postProcess.js +56 -13
- package/plugins/render3d.js +1643 -1577
- package/plugins/render3dDebug.js +109 -0
- package/plugins/render3dExtras.js +1754 -0
- package/plugins/render3dVoxels.js +502 -0
- package/plugins/textureSheet.js +496 -458
- package/plugins/threejs.js +183 -163
- package/plugins/tweakables.js +411 -0
- package/plugins/tweenSystem.js +263 -145
- package/plugins/uiSystem.js +2024 -1687
- package/plugins/zzfxm.js +159 -159
- package/src/engine.js +191 -75
- package/src/engineAudio.js +229 -125
- package/src/engineBuild.mjs +289 -256
- package/src/engineDebug.js +912 -742
- package/src/engineDraw.js +295 -193
- package/src/engineEditor.js +2431 -0
- package/src/engineExport.js +12 -0
- package/src/engineInput.js +1462 -1293
- package/src/engineMath.js +1274 -1252
- package/src/engineObject.js +194 -80
- package/src/engineParticles.js +583 -532
- package/src/engineRelease.js +67 -45
- package/src/engineSettings.js +77 -29
- package/src/engineTileLayer.js +995 -741
- package/src/engineUtilities.js +19 -13
- package/src/engineWebGL.js +239 -82
- package/src/jsconfig.json +17 -13
- package/plugins/box2d.wasm.js +0 -630
- package/plugins/box2d.wasm.wasm +0 -0
package/package.json
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "littlejsengine",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"description": "LittleJS - Tiny and Fast HTML5 Game Engine",
|
|
5
5
|
"main": "dist/littlejs.esm.js",
|
|
6
6
|
"types": "dist/littlejs.d.ts",
|
|
7
7
|
"exports": {
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/littlejs.d.ts",
|
|
10
|
+
"production": "./dist/littlejs.esm.min.js",
|
|
11
|
+
"default": "./dist/littlejs.esm.js"
|
|
12
|
+
},
|
|
13
|
+
"./dist/*": "./dist/*",
|
|
14
|
+
"./package.json": "./package.json"
|
|
11
15
|
},
|
|
12
16
|
"repository": {
|
|
13
17
|
"type": "git",
|
|
@@ -33,6 +37,7 @@
|
|
|
33
37
|
"dist/",
|
|
34
38
|
"src/",
|
|
35
39
|
"plugins/",
|
|
40
|
+
"!plugins/box2d.wasm.*",
|
|
36
41
|
"COPYRIGHT.txt",
|
|
37
42
|
"FAQ.md"
|
|
38
43
|
],
|
|
@@ -43,7 +48,7 @@
|
|
|
43
48
|
"test": "node --test --import ./test/setup.mjs \"test/**/*.test.mjs\""
|
|
44
49
|
},
|
|
45
50
|
"engines": {
|
|
46
|
-
"node": ">=
|
|
51
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
47
52
|
},
|
|
48
53
|
"devDependencies": {
|
|
49
54
|
"bestzip": "^2.2.1",
|
package/plugins/audioEffects.js
CHANGED
|
@@ -10,23 +10,7 @@
|
|
|
10
10
|
'use strict';
|
|
11
11
|
|
|
12
12
|
///////////////////////////////////////////////////////////////////////////////
|
|
13
|
-
|
|
14
|
-
// ramp an audio param to a value, cancelling anything already scheduled so stacked calls don't fight
|
|
15
|
-
function audioParamRamp(param, value, fadeTime=0)
|
|
16
|
-
{
|
|
17
|
-
ASSERT(fadeTime >= 0, 'fadeTime must be positive or zero');
|
|
18
|
-
const startTime = audioContext.currentTime;
|
|
19
|
-
param.cancelScheduledValues(startTime);
|
|
20
|
-
if (fadeTime)
|
|
21
|
-
{
|
|
22
|
-
param.setValueAtTime(param.value, startTime);
|
|
23
|
-
param.linearRampToValueAtTime(value, startTime + fadeTime);
|
|
24
|
-
}
|
|
25
|
-
else
|
|
26
|
-
param.value = value;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
13
|
+
// audioParamRamp lives in engineAudio.js, core loads before plugins in the bundle
|
|
30
14
|
/**
|
|
31
15
|
* Base class for audio effects, an input and output with a wet/dry mix between them
|
|
32
16
|
* - Sounds connect to input, output goes to the master gain until connect() moves it
|
|
@@ -44,6 +28,10 @@ class AudioEffect
|
|
|
44
28
|
{
|
|
45
29
|
ASSERT(isNumber(mix), 'mix must be a number');
|
|
46
30
|
|
|
31
|
+
/** @property {number} - Wet/dry balance, 0 is fully dry and 1 is fully wet */
|
|
32
|
+
this.mix = clamp(mix);
|
|
33
|
+
if (!audioContext) return; // no audio outside a browser, where the engine runs headless
|
|
34
|
+
|
|
47
35
|
/** @property {GainNode} - Connect sounds to this node */
|
|
48
36
|
this.input = audioContext.createGain();
|
|
49
37
|
/** @property {GainNode} - This node carries the mixed result, send it somewhere with connect(), never by assigning here
|
|
@@ -53,8 +41,6 @@ class AudioEffect
|
|
|
53
41
|
this.dryGain = audioContext.createGain();
|
|
54
42
|
/** @property {GainNode} - Level of the processed signal */
|
|
55
43
|
this.wetGain = audioContext.createGain();
|
|
56
|
-
/** @property {number} - Wet/dry balance, 0 is fully dry and 1 is fully wet */
|
|
57
|
-
this.mix = mix;
|
|
58
44
|
|
|
59
45
|
this.input.connect(this.dryGain).connect(this.output);
|
|
60
46
|
this.wetGain.connect(this.output);
|
|
@@ -71,6 +57,7 @@ class AudioEffect
|
|
|
71
57
|
{
|
|
72
58
|
ASSERT(isNumber(mix), 'mix must be a number');
|
|
73
59
|
this.mix = mix = clamp(mix);
|
|
60
|
+
if (!audioContext) return;
|
|
74
61
|
this.rampParam(this.dryGain.gain, 1-mix, fadeTime);
|
|
75
62
|
this.rampParam(this.wetGain.gain, mix, fadeTime);
|
|
76
63
|
}
|
|
@@ -94,10 +81,13 @@ class AudioEffect
|
|
|
94
81
|
}
|
|
95
82
|
|
|
96
83
|
/** Send this effect's output into another effect or audio node instead of the speakers
|
|
97
|
-
* @
|
|
98
|
-
* @
|
|
84
|
+
* @template {AudioEffect|AudioNode} T
|
|
85
|
+
* @param {T} target - The next effect in the chain, or any audio node
|
|
86
|
+
* @return {T} - The target, so chains read left to right */
|
|
99
87
|
connect(target)
|
|
100
88
|
{
|
|
89
|
+
if (!audioContext) return target; // no audio outside a browser, where the engine runs headless
|
|
90
|
+
|
|
101
91
|
// an effect stands in for its input node, the same rule as sound.output
|
|
102
92
|
const node = /** @type {AudioNode} */ (target && 'input' in target ? target.input : target);
|
|
103
93
|
ASSERT(node && typeof node.connect === 'function', 'target must be an AudioEffect or AudioNode');
|
|
@@ -107,7 +97,7 @@ class AudioEffect
|
|
|
107
97
|
}
|
|
108
98
|
|
|
109
99
|
/** Stop sending this effect's output anywhere */
|
|
110
|
-
disconnect() { this.output
|
|
100
|
+
disconnect() { this.output?.disconnect(); }
|
|
111
101
|
|
|
112
102
|
/** Wire nodes between the input and the wet gain, for subclasses
|
|
113
103
|
* @param {AudioNode} first - Node the input connects to
|
|
@@ -142,6 +132,7 @@ class AudioFilter extends AudioEffect
|
|
|
142
132
|
super(mix);
|
|
143
133
|
ASSERT(isNumber(frequency) && frequency >= 0, 'frequency must be positive or zero');
|
|
144
134
|
ASSERT(isNumber(q), 'q must be a number');
|
|
135
|
+
if (!audioContext) return; // no audio outside a browser, where the engine runs headless
|
|
145
136
|
|
|
146
137
|
/** @property {BiquadFilterNode} - The filter node */
|
|
147
138
|
this.node = audioContext.createBiquadFilter();
|
|
@@ -157,6 +148,7 @@ class AudioFilter extends AudioEffect
|
|
|
157
148
|
setFrequency(frequency, fadeTime=0)
|
|
158
149
|
{
|
|
159
150
|
ASSERT(isNumber(frequency) && frequency >= 0, 'frequency must be positive or zero');
|
|
151
|
+
if (!audioContext) return;
|
|
160
152
|
this.rampParam(this.node.frequency, frequency, fadeTime);
|
|
161
153
|
}
|
|
162
154
|
|
|
@@ -166,6 +158,7 @@ class AudioFilter extends AudioEffect
|
|
|
166
158
|
setQ(q, fadeTime=0)
|
|
167
159
|
{
|
|
168
160
|
ASSERT(isNumber(q), 'q must be a number');
|
|
161
|
+
if (!audioContext) return;
|
|
169
162
|
this.rampParam(this.node.Q, q, fadeTime);
|
|
170
163
|
}
|
|
171
164
|
}
|
|
@@ -189,6 +182,7 @@ class AudioReverb extends AudioEffect
|
|
|
189
182
|
constructor(duration=2, decay=2, mix=.5)
|
|
190
183
|
{
|
|
191
184
|
super(mix);
|
|
185
|
+
if (!audioContext) return; // no audio outside a browser, where the engine runs headless
|
|
192
186
|
|
|
193
187
|
/** @property {ConvolverNode} - The convolver node */
|
|
194
188
|
this.node = audioContext.createConvolver();
|
|
@@ -203,6 +197,7 @@ class AudioReverb extends AudioEffect
|
|
|
203
197
|
{
|
|
204
198
|
ASSERT(isNumber(duration) && duration > 0, 'duration must be positive');
|
|
205
199
|
ASSERT(isNumber(decay) && decay > 0, 'decay must be positive');
|
|
200
|
+
if (!audioContext) return;
|
|
206
201
|
this.node.buffer = this.createImpulse(duration, decay);
|
|
207
202
|
}
|
|
208
203
|
|
|
@@ -243,6 +238,7 @@ class AudioDelay extends AudioEffect
|
|
|
243
238
|
constructor(time=.3, feedback=.4, mix=.5)
|
|
244
239
|
{
|
|
245
240
|
super(mix);
|
|
241
|
+
if (!audioContext) return; // no audio outside a browser, where the engine runs headless
|
|
246
242
|
|
|
247
243
|
/** @property {DelayNode} - The delay node */
|
|
248
244
|
this.node = audioContext.createDelay(5);
|
|
@@ -261,6 +257,7 @@ class AudioDelay extends AudioEffect
|
|
|
261
257
|
setTime(time, fadeTime=0)
|
|
262
258
|
{
|
|
263
259
|
ASSERT(isNumber(time) && time >= 0 && time <= 5, 'time must be between 0 and 5');
|
|
260
|
+
if (!audioContext) return;
|
|
264
261
|
this.rampParam(this.node.delayTime, time, fadeTime);
|
|
265
262
|
}
|
|
266
263
|
|
|
@@ -270,6 +267,7 @@ class AudioDelay extends AudioEffect
|
|
|
270
267
|
setFeedback(feedback, fadeTime=0)
|
|
271
268
|
{
|
|
272
269
|
ASSERT(isNumber(feedback), 'feedback must be a number');
|
|
270
|
+
if (!audioContext) return;
|
|
273
271
|
this.rampParam(this.feedbackGain.gain, clamp(feedback, 0, .95), fadeTime);
|
|
274
272
|
}
|
|
275
273
|
}
|
|
@@ -292,11 +290,13 @@ class AudioDistortion extends AudioEffect
|
|
|
292
290
|
{
|
|
293
291
|
super(mix);
|
|
294
292
|
|
|
293
|
+
/** @property {number} - How hard the signal is driven, 0 is clean and 1 is crushed */
|
|
294
|
+
this.amount = clamp(amount);
|
|
295
|
+
if (!audioContext) return; // no audio outside a browser, where the engine runs headless
|
|
296
|
+
|
|
295
297
|
/** @property {WaveShaperNode} - The wave shaper node */
|
|
296
298
|
this.node = audioContext.createWaveShaper();
|
|
297
299
|
this.node.oversample = '2x';
|
|
298
|
-
/** @property {number} - How hard the signal is driven, 0 is clean and 1 is crushed */
|
|
299
|
-
this.amount = amount;
|
|
300
300
|
this.setAmount(amount);
|
|
301
301
|
this.connectEffect(this.node);
|
|
302
302
|
}
|
|
@@ -307,6 +307,7 @@ class AudioDistortion extends AudioEffect
|
|
|
307
307
|
{
|
|
308
308
|
ASSERT(isNumber(amount), 'amount must be a number');
|
|
309
309
|
this.amount = amount = clamp(amount);
|
|
310
|
+
if (!audioContext) return;
|
|
310
311
|
|
|
311
312
|
// soft clip curve, drive grows with the square of amount so low values stay subtle
|
|
312
313
|
// enough points that quiet signals are still shaped at high drive, where the curve is steep near 0
|
|
@@ -343,6 +344,7 @@ class AudioCompressor extends AudioEffect
|
|
|
343
344
|
super(mix);
|
|
344
345
|
ASSERT(isNumber(threshold), 'threshold must be a number');
|
|
345
346
|
ASSERT(isNumber(ratio) && ratio >= 1, 'ratio must be 1 or more');
|
|
347
|
+
if (!audioContext) return; // no audio outside a browser, where the engine runs headless
|
|
346
348
|
|
|
347
349
|
/** @property {DynamicsCompressorNode} - The compressor node */
|
|
348
350
|
this.node = audioContext.createDynamicsCompressor();
|
|
@@ -357,6 +359,7 @@ class AudioCompressor extends AudioEffect
|
|
|
357
359
|
setThreshold(threshold, fadeTime=0)
|
|
358
360
|
{
|
|
359
361
|
ASSERT(isNumber(threshold), 'threshold must be a number');
|
|
362
|
+
if (!audioContext) return;
|
|
360
363
|
this.rampParam(this.node.threshold, threshold, fadeTime);
|
|
361
364
|
}
|
|
362
365
|
|
|
@@ -366,6 +369,7 @@ class AudioCompressor extends AudioEffect
|
|
|
366
369
|
setRatio(ratio, fadeTime=0)
|
|
367
370
|
{
|
|
368
371
|
ASSERT(isNumber(ratio) && ratio >= 1, 'ratio must be 1 or more');
|
|
372
|
+
if (!audioContext) return;
|
|
369
373
|
this.rampParam(this.node.ratio, ratio, fadeTime);
|
|
370
374
|
}
|
|
371
375
|
}
|