littlejsengine 1.24.2 → 1.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/EDITOR.md +2 -2
  3. package/FAQ.md +6 -0
  4. package/REFERENCE.md +86 -41
  5. package/dist/littlejs.d.ts +600 -323
  6. package/dist/littlejs.esm.js +2412 -1797
  7. package/dist/littlejs.esm.min.js +38 -24
  8. package/dist/littlejs.js +2410 -1797
  9. package/dist/littlejs.min.js +37 -23
  10. package/dist/littlejs.release.js +2393 -1826
  11. package/package.json +1 -1
  12. package/plugins/box2d.js +41 -28
  13. package/plugins/drawUtilities.js +374 -380
  14. package/plugins/gltf.js +331 -55
  15. package/plugins/lightSystem.js +2 -2
  16. package/plugins/math3d.js +1013 -1014
  17. package/plugins/newgrounds.js +1 -4
  18. package/plugins/particleEffects.js +3 -4
  19. package/plugins/pathFinder.js +52 -28
  20. package/plugins/pluginExport.js +2 -0
  21. package/plugins/postProcess.js +196 -65
  22. package/plugins/render3d.js +8 -6
  23. package/plugins/render3dEditor.js +3 -3
  24. package/plugins/render3dExtras.js +31 -10
  25. package/plugins/render3dLevel.js +15 -4
  26. package/plugins/textureSheet.js +15 -7
  27. package/plugins/tweenSystem.js +43 -38
  28. package/plugins/uiSystem.js +25 -20
  29. package/src/engine.js +39 -21
  30. package/src/engineAudio.js +13 -9
  31. package/src/engineBuild.mjs +49 -2
  32. package/src/engineDebug.js +3 -2
  33. package/src/engineDraw.js +20 -18
  34. package/src/engineEditor.js +75 -23
  35. package/src/engineInput.js +10 -10
  36. package/src/engineMath.js +3 -6
  37. package/src/engineObject.js +8 -9
  38. package/src/engineParticles.js +8 -7
  39. package/src/engineRelease.js +17 -10
  40. package/src/engineTileLayer.js +33 -14
  41. package/src/engineUtilities.js +15 -2
  42. package/src/engineWebGL.js +34 -12
package/CHANGELOG.md CHANGED
@@ -7,6 +7,61 @@ What changed in each release, newest first. Releases before 1.20.0 are on the
7
7
 
8
8
  Nothing yet.
9
9
 
10
+ ## 1.25.0 - 2026-10-04
11
+
12
+ ### New Changes
13
+
14
+ - glTF skinned animation: a rigged character plays its animations, its mesh bent by its joints each frame, the four strongest of up to eight a vertex, on the CPU, so shadows, picking and custom shaders work with it; `object.play(name, loop, speed, blend)` cross-fades from the pose it is in over `blend` seconds, and `object.getJointMatrix(name)` gives a joint's place to hang a sword on a hand
15
+ - Tilt shift and depth of field post effects: `postProcessTiltShift(focus, size, blur)` keeps a band across the screen sharp, in 2D or 3D, and `postProcessDepthOfField(focus, range, blur)` keeps what is at a distance sharp, reading the 3D depth, with the edges of what is in focus kept crisp; the new 3D Focus Blur example focuses either with the mouse
16
+ - `postProcess.values`: a game's own values for the post process shader, set every frame, and any effect setting may name one in place of a number, to change it live without making the shader again, all but glow's size; the shader is made at the first render, so values set right after the plugin is made are in it
17
+ - The 3D Mesh example steps through a dropped model's animations with two buttons or the arrow keys, each cross-faded from the one before
18
+
19
+ ### Breaking Changes
20
+
21
+ - The names deprecated in 1.20 are gone: `collideTiles` is `collideLevel`, the weld joint's `setSpringDampingRatio` and `getSpringDampingRatio` are `setDampingRatio` and `getDampingRatio` (the wheel joint keeps its own), and `NewgroundsPlugin.logView()`, which did nothing, is removed
22
+ - `drawNineSliceScreen` and `drawThreeSliceScreen` take only the order since 1.20, a color after the tile and then the border size; a number in the color's place asserts in a debug build
23
+
24
+ ### Fixes
25
+
26
+ - REFERENCE says where the draw functions' parameter orders differ, and has a section on what functions give back: what each raycast returns, overlaps and collide helpers, not found, how a failed load is reported and how each kind of thing is ended; the FAQ lists the global names a game's own top level declarations clash with in a script build
27
+ - REFERENCE has a section on units and directions (angles in radians, clockwise in 2D, what is per frame and what is in seconds), says which vector and color methods give a copy, and names parameters as the code does; the Box2D shape methods, the vector helpers and a few others say what they return
28
+ - In a browser with no audio, a zzfx sound and the page hiding do nothing, where they threw
29
+ - A resume of the audio the browser refuses is caught, where it showed as an uncaught error in the console
30
+ - `debug`, `debugOverlay` and `debugWatermark` are `false` in a release build, as their types say, where they were 0
31
+ - `Box2dPinJoint`'s docs say its point defaults to objectA's position, which the d.ts showed as objectB's
32
+ - TypeScript: `tileLayersLoad` and `objectLayersLoad` take a `TiledMap`, `level3DLoad` a `Level3D`, the types' defaults and properties are records, a tool's `pos` and `ray` and `onPlayFrom`'s position are typed, `levelEditor.open` and `close` return nothing, `Sound` takes a zzfx array as numbers, and `fetchJSON` gives `any`, as JSON is, so its result goes straight into any of them
33
+ - A JSON, glTF or particle effect file that fails to read names the file, and says when it is a web page, as a dev server sends for a mistyped path, where it gave only "Unexpected token '<'"; an OBJ file with no faces warns, naming the file
34
+ - In a release build `levelEditor.edit2D` is there and changes nothing, where it was undefined and a call on it threw, so a game needs no guard around it
35
+ - A shader that fails to build on a device says why in the console in a release build too, where the screen stayed blank with no message: when the engine's own fails, the game draws with Canvas2D, a game's `Shader` that fails draws as if it had none, and a post process that fails leaves the frame as it is
36
+ - The post process depth is read at full precision, where phones with Mali and Adreno GPUs read it at 11 bits and the outline drew false lines on flat ground; the outline draws nothing with no depth texture, and nothing wrong at the sky of a camera with no far plane, where both gave NaN pixels; a value or a setting may not be named as a GLSL word or a name the shader uses, which was a compile error or a value silently hidden; a setting below .01 keeps its digits
37
+ - The 3D shader gives a mesh flattened to nothing on an axis no normal, where it was NaN, keeps the reflection's Fresnel term from NaN specks where a surface is seen head on, and treats fog that starts where it ends, and a shininess of 0, as defined
38
+ - `lineTest`, and the tile raycasts on it, from a whole x or y heading down the grid start in the cell they head into, where they tested the cell behind first and could hit at the start
39
+ - A particle whose `gravityScale` makes it rise lands on a ceiling, where its ground was the way the world's gravity points
40
+ - `readSaveData` takes only an object from storage, where a stored string was spread into its letters
41
+ - Faster where a game grows: path smoothing on a winding path checks lines from each corner, not each cell, a tween stopped among many no longer searches the list, a CSG cut leaves what is far from it alone, so a mesh cut many times does not grow slower to cut, and a paint stroke in the level editor draws the cells it changed, the whole layer only for a game's `onTile` or its own `onRedraw`
42
+ - Examples: the breakout tutorial runs at every step, the platformer's debug explosion is on B, not the dodge key, the Box2D example's smoke rises and its explosion falls off, the raycaster has no fisheye, the 3D Mesh viewer's normals leave a rigged model alone, positions are copied where they were shared, and a list of smaller fixes across the shorts
43
+ - An object whose child's update throws leaves the engine's list of children being updated as it was, where each throw kept them on it for good
44
+ - Level editor: a turned or mirrored stamp turns or mirrors its objects too, each object's rotation with it, a box placed from the corner that becomes its own, a polygon's points and a tile object's image mirrored
45
+
46
+ ## 1.24.3 - 2026-10-03
47
+
48
+ ### Fixes
49
+
50
+ - TypeScript: the d.ts keeps `undefined` where a value may be missing, so a game in strict mode can write `render3D.shader = undefined` and is told `light.flare`, `levelEditor.edit3D` or `uiSystem.keyInputObject` may be undefined; a game not in strict mode reads the same types as before
51
+ - `box2d.boxCast` and `boxCastAll` say that they test each shape's bounding box, which can find an object near the corner of a turned box or a circle that the box does not touch
52
+ - An image that failed to load gives tiles of no size, which draw nothing, where `tile()` gave NaN places in release builds and stopped debug builds at an assert; a texture slot never given an image still asserts in debug
53
+ - A release build says when a sound, a `loadSprite` or a `loadAtlas` fails to load, as it did for textures and tile sets
54
+ - A `Box2dObject` keeps one `pos` for life, moved in place each step as an EngineObject's is, so a camera holding it follows the body
55
+ - `drawRectGradient` takes no size, as its docs say
56
+ - A release build going on past an error logs each new error, not only the first, and an error every tick no longer runs the game at the screen's refresh rate
57
+ - Under pointer lock a click is a press wherever the locked mouse was left, a letterbox bar too
58
+ - A gamepad with no sticks keeps the one its d-pad stands in for, where its stick count flickered
59
+ - A zzfx `Sound` made in a browser with no audio counts as loaded and plays nothing, where it threw
60
+ - `glCompileShader`, `glCreateProgram` and `glCreateTexture` are typed as giving undefined with no WebGL
61
+ - A release build going on past an error clears that frame's input, where a key press whose action threw was pressed again every frame
62
+ - `loadSprite`, `loadTiles` and `loadAtlas` forget a load whose file failed, so loading it again tries again, where a failure once was kept for the session
63
+ - glTF: a file the model names in subfolders is found when what is in its folder was dropped, not the folder, and a file found by its name alone may have capitals in it, where both said the file was not among those given; the 3D Mesh short keeps a dropped folder's name when other files come with it
64
+
10
65
  ## 1.24.2 - 2026-10-03
11
66
 
12
67
  ### New Changes
package/EDITOR.md CHANGED
@@ -22,8 +22,8 @@ is run by `test/editorCustom.test.mjs` straight from this file, so it works as w
22
22
  and release are ended for you.
23
23
  5. **A type is named by a string**, never by its class, because minified builds rename classes.
24
24
  6. **Use `levelEditor.edit3D` and `levelEditor.edit2D` only inside what the editor calls**: a key's action, a
25
- button's click, a tool's callbacks, `onUpdate`, `onDraw`. In a release build they are undefined, and none of
26
- those are ever called.
25
+ button's click, a tool's callbacks, `onUpdate`, `onDraw`. In a release build none of those are ever called;
26
+ `edit2D` is there and changes nothing, and `edit3D` is undefined, as it is in a game without the 3D plugins.
27
27
  7. **`levelEditor.is3D`** says which editor is in use, for a game that has both kinds of level.
28
28
 
29
29
  ## The hooks
package/FAQ.md CHANGED
@@ -196,6 +196,12 @@ This will show you any errors that occur and allows stepping through code to hel
196
196
  A common issue is the image data failing to load with a message like "The image element contains cross-origin data, and may not be loaded."
197
197
  This is probably because the game was loaded directly without using a web server!
198
198
 
199
+ ### Why does my game say a name "has already been declared"?
200
+
201
+ In a script tag build the engine's names are globals, so a top-level `let`, `const` or `class` in your game with the same name is an error, as is any declaration of a name the engine declares with `let` or `const`, like `time`. A `function` or `var` named like an engine function replaces it instead, which breaks the engine wherever it calls that function. The names most likely to clash are the short ones: `time`, `frame`, `paused`, `debug`, `gravity`, `tile`, `rand`, `percent`, `lerp`, `clamp`, `mod`, `sign`, `min`, `max`, `abs`, `floor`, `round`, `ceil`, `sin`, `cos`, `tan`, `PI`, the colors (`RED`, `GREEN`, `BLUE`, `GRAY`, `WHITE`, `BLACK` and the rest), `mousePos`, `cameraPos`, `medals`, `speak`, `vibrate`, `tweak`, the classes `Timer`, `Sound`, `Color`, `Light`, `Mesh`, `Particle` and `Shader`, and the plugin objects `box2d`, `render3D`, `uiSystem`, `postProcess` and `levelEditor`. [REFERENCE.md](REFERENCE.md) lists every name.
202
+
203
+ Rename yours, keep your game's state inside an object or class, or use the ES module build, where nothing is global and you import only the names you use (`import * as LJS from 'littlejsengine'` keeps them all under `LJS`).
204
+
199
205
  ### Do I need a local server to run LittleJS games, and how do I set one up?
200
206
 
201
207
  Yes, this is a necessary step because web browsers just have protection from loading local files which includes images.
package/REFERENCE.md CHANGED
@@ -82,6 +82,36 @@ let remaining = 36000;
82
82
  })();
83
83
  ```
84
84
 
85
+ ## Units and directions
86
+ - **Space:** world units, y up. Draws and objects take full sizes (a circle's diameter); only the math helpers and
87
+ lights take a radius, and their parameter says so
88
+ - **2D angles:** radians, clockwise: `EngineObject.angle`, `cameraAngle`, the `angle` of every draw and of a
89
+ `ParticleEmitter`; `Vector2.angle()` is 0 up
90
+ - **3D angles:** radians, `rotation3D` is pitch, yaw and roll, turning as three.js does, counter clockwise seen
91
+ down an axis; `Camera3D.fov` is radians; a 3D level file and the 3D editor's `setTransform` take degrees, as
92
+ does `ThreeJSPlugin.cameraFOV`
93
+ - **Per frame:** speeds and spins, `velocity`, `angleVelocity`, a particle's `speed` and `angleSpeed`, damping and
94
+ gravity, at the fixed 60 updates a second
95
+ - **Seconds:** `Timer`, `Tween`, `time`, a particle emitter's `emitTime` and `particleTime` and its `emitRate` (per
96
+ second) and `lifeTime`; a particle's `fadeRate` is a part of its life, not seconds
97
+ - **Milliseconds:** `gamepadVibrate`'s duration, `vibrate` patterns and `saveDataURL`'s `revokeTime`
98
+
99
+ ## What functions give back
100
+ - **Raycasts:** where the ray hits, a Vector2: `tileCollisionRaycast`, `lineTest`; how far along the ray, a number:
101
+ `raycastBox`, `raycastSphere`, `raycastPlane`, `HeightMap.raycast`; a record of the hit: `VoxelMap.raycast` (a
102
+ `VoxelHit`), `render3D.pick` (`{object, distance}`), `box2d.raycast` (a `Box2dRaycastResult`); every object
103
+ hit, a list: `engineObjectsRaycast`; nothing hit is `undefined`, or an empty list
104
+ - **Overlaps:** `isOverlapping` and `isIntersecting` say whether, a boolean, as does a layer's `collisionTest`;
105
+ `tileCollisionTest` gives the layer hit; the collide helpers (`collideCircleBox`, `collideSphereBox` and the rest)
106
+ give the push that moves the first shape out, each `undefined` for none
107
+ - **Not found:** `undefined`, but `PathFinder.getNode` and `getNearestClearNode`, which give `null`
108
+ - **Loading:** an image that fails, from `engineInit` or `loadTexture`, and a `Sound` made from a file that fails,
109
+ warn in the console and the game goes on without them; `fetchJSON`, `loadGLTF`, `loadOBJ` and `Sound.loadSound`
110
+ reject with an error naming the file, for the game to catch
111
+ - **Ending things:** objects, particles, UI, Box2D objects and joints are ended with `destroy`; a `Mesh` or a
112
+ `GLTFModel` frees its GPU buffers with `dispose`, a `TextureInfo` its texture with `destroyWebGLTexture`; a
113
+ playing sound, a `Tween` and an animation `stop`
114
+
85
115
  ## LittleJS Utilities Classes and Functions
86
116
  - General purpose math library
87
117
  - Vector2 - Fast, simple, easy 2D vector class
@@ -116,7 +146,7 @@ lerpAngle(angleA, angleB, percent) // Linearly interpolates with wrap
116
146
  smoothStep(percent) // Applies smoothstep function, percent clamped to 0-1
117
147
  isPowerOfTwo(value) // Checks if the value is a power of two
118
148
  nearestPowerOfTwo(value) // Smallest power of two not less than the value
119
- isOverlapping(pointA, sizeA, pointB, sizeB) // Checks if bounding boxes overlap
149
+ isOverlapping(posA, sizeA, posB, sizeB) // Checks if bounding boxes overlap
120
150
  isIntersecting(start, end, pos, size) // Checks if ray intersects box
121
151
  // the collide helpers answer how far out, where isOverlapping answers whether; boxes are axis aligned and centered
122
152
  // with a full size, and each returns undefined when the shapes are not touching
@@ -169,13 +199,13 @@ Vector2.length() // Get length
169
199
  Vector2.lengthSquared() // Get length squared
170
200
  Vector2.distance(v) // Get distance to vector
171
201
  Vector2.distanceSquared(v) // Get distance to vector squared
172
- Vector2.normalize(length=1) // Normalize this vector to length
173
- Vector2.clampLength(length=1) // Clamp this vector to length
202
+ Vector2.normalize(length=1) // Copy of this vector at a length, its direction kept
203
+ Vector2.clampLength(length=1) // Copy of this vector no longer than a length
174
204
  Vector2.dot(v) // Dot product with vector
175
205
  Vector2.cross(v) // Cross product with vector
176
206
  Vector2.reflect(normal, restitution=1) // Reflect off a surface normal
177
- Vector2.floor() // Floor this vector
178
- Vector2.round() // Round this vector
207
+ Vector2.floor() // Copy with each component floored
208
+ Vector2.round() // Copy with each component rounded
179
209
  Vector2.abs() // Get copy with absolute value components
180
210
  Vector2.snap(grid) // Snap down to the grid, grid is steps per unit
181
211
  Vector2.mod(divisor=1) // Get modulo of each component
@@ -188,6 +218,8 @@ Vector2.rotate(angle) // Rotate by angle
188
218
  Vector2.setDirection(direction, length=1) // Set integer direction (0-3) and length
189
219
  Vector2.direction() // Get integer direction (0-3)
190
220
  Vector2.toString(digits=3) // Get string representation
221
+ // every Vector2 and Color method gives a new one and leaves it as it is, but set, setFrom, setAngle and
222
+ // setDirection, and Color's set, setFrom, setAlpha, setHSLA and setHex, which change it in place
191
223
 
192
224
  // RGBA color object
193
225
  Color(r=1, g=1, b=1, a=1) // Create an RGBA color
@@ -199,11 +231,11 @@ Color.subtract(c) // Subtract a color
199
231
  Color.multiply(c) // Multiply by a color
200
232
  Color.divide(c) // Divide by a color
201
233
  Color.scale(scale, alphaScale=scale) // Scale by a float
202
- Color.clamp() // Clamp this color
234
+ Color.clamp() // Copy with each component clamped to 0 to 1
203
235
  Color.lerp(c, percent) // Interpolate between colors
204
236
  Color.setHSLA(h=0, s=0, l=1, a=1) // Set the color from HSLA values
205
237
  Color.HSLA() // Get the color in HSLA format
206
- Color.mutate(amount=.05, alphaAmount=0) // Randomly diverge from this color
238
+ Color.mutate(amount=.05, alphaAmount=0) // Copy randomly diverged from this color
207
239
  Color.setHex(hex) // Set this color from a hex code
208
240
  Color.setAlpha(a=1) // Set the alpha of this color
209
241
  Color.withAlpha(a=1) // Get a copy of this color with the alpha set
@@ -267,6 +299,14 @@ drawEllipseGradient(pos, size=(1,1), colorInner=WHITE, colorOuter=CLEAR_WHITE, a
267
299
  drawCircleGradient(pos, size=1, colorInner=WHITE, colorOuter=CLEAR_WHITE)
268
300
  drawCanvas2D(pos, size, angle=0, mirror=false, drawFunction, screenSpace=drawScreenSpace, context)
269
301
 
302
+ // Where the orders differ, worth a look when changing one draw for another:
303
+ // - angle is after the colors in drawTile, drawRect, drawEllipse and the gradients, after size in drawCanvas2D,
304
+ // after lineColor in drawRegularPoly and after pos in drawLine, drawLineList and drawPoly; drawCircle has none
305
+ // - a line's width is before its color in drawLine and drawLineList, the outline's after the fill color, with
306
+ // lineColor, in drawPoly, drawRegularPoly, drawEllipse, drawCircle and the text
307
+ // - pos comes first in most draws, but is an offset near the end in drawLine, drawLineList and drawPoly
308
+ // - drawText and drawTextScreen draw with Canvas2D and take no useWebGL or screenSpace
309
+
270
310
  // Text functions
271
311
  drawText(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font, fontStyle, maxWidth, angle=0)
272
312
  drawTextScreen(text, pos, size, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font, fontStyle, maxWidth, angle=0)
@@ -487,12 +527,12 @@ AudioFilter.node, AudioReverb.node, ... // Each effect's wrapped Web A
487
527
 
488
528
  ```javascript
489
529
  // Keyboard, keys are KeyboardEvent.code names like 'KeyW', 'Space' or 'ArrowUp', not characters
490
- keyIsDown(key) // Is key down?
491
- keyWasPressed(key) // Was key pressed this frame?
492
- keyWasReleased(key) // Was key released this frame?
530
+ keyIsDown(key, device=0) // Is key down? device 0 is the keyboard and mouse, 1 on the gamepads
531
+ keyWasPressed(key, device=0) // Was key pressed this frame?
532
+ keyWasReleased(key, device=0) // Was key released this frame?
493
533
  keyDirection(up, down, left, right) // Get input vector from arrow keys or wasd
494
534
  inputClear() // Clear all input state
495
- inputClearKey(key) // Clear input state for a specific key
535
+ inputClearKey(key, device=0, clearDown=true, clearPressed=true, clearReleased=true) // Clear input state for a key
496
536
 
497
537
  // Mouse / Touch
498
538
  mousePos // World space mouse position
@@ -713,9 +753,9 @@ TileCollisionLayer.collisionTest(pos, size=(0,0), object) // Like tileCollisionT
713
753
  TileCollisionLayer.collisionRaycast(posStart, posEnd, object, normal) // Like tileCollisionRaycast for this layer only
714
754
  TileCollisionLayer.isSolid = true // Solid layers block objects and particles, the solidOnly tests
715
755
  // skip the others
716
- tileCollisionGetData(pos) // Get tile collision data at pos
756
+ tileCollisionGetData(pos, solidOnly=true) // Get tile collision data at pos
717
757
  tileCollisionTest(pos, size=(0,0), object) // Check if collision should occur
718
- tileCollisionRaycast(posStart, posEnd, object, normal, solidOnly=true) // Where the ray meets the first tile hit,
758
+ tileCollisionRaycast(posStart, posEnd, callbackObject, normal, solidOnly=true) // Where the ray meets the first tile hit,
719
759
  // or undefined; a normal vec2 passed in is set to the surface's
720
760
  tileCollisionLayers // List of all tile collision layers
721
761
  tileLayersLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisionLayer, draw=true) // collisionLayer is the index
@@ -783,7 +823,7 @@ particleEffectsBuiltIn // the built-in names: fire, torch, smok
783
823
  // itself, a continuous one goes until destroyed
784
824
  'fire' // hue .08, continuous
785
825
  'torch' // hue .09, continuous
786
- 'smoke' // no hue, grey, continuous
826
+ 'smoke' // no hue, gray, continuous
787
827
  'steam' // no hue, white, continuous
788
828
  'explosion' // hue .12, one-shot
789
829
  'sparks' // hue .17, continuous
@@ -806,9 +846,10 @@ particleEffectsBuiltIn // the built-in names: fire, torch, smok
806
846
  'confetti' // hue 0 and .6, mixed, one-shot
807
847
  'splash' // hue .58, one-shot
808
848
  particleEffectApply(emitter, effect) // set a live 2D emitter to an effect
809
- particleEffectApply3D(emitter3D, effect) // the same for a ParticleEmitter3D, its particles, place and scale kept
810
- particleEffectFromEmitter(emitter) // a 2D emitter's settings as an effect, to save or build in 3D
811
- particleEffectsAddBehavior(name, update, update3D) // add a behavior effects can name, with 2D and 3D pushes
849
+ particleEffectApply3D(emitter, effect) // the same for a ParticleEmitter3D, its particles, place and scale kept
850
+ particleEffectFromEmitter(emitter, name='Effect') // a 2D emitter's settings as an effect, to save or build in 3D
851
+ particleEffectsAddBehavior(name, update, update3D, min=-2, max=2, value=1, description='') // add a behavior effects
852
+ // can name, with 2D and 3D pushes; min, max and value for the designer
812
853
  particleEffectsAdd(effects) // add effects to play by name, one of the same name replaces it
813
854
  particleEffectsGet(name) // an effect's data, any case, to change or build by hand
814
855
  await particleEffectsLoad(url) // load the file the particle designer's Save Library wrote, and add its effects
@@ -973,7 +1014,7 @@ uiSystem.drawSlice(slice, pos, size, color=WHITE) // Draw a TileSlice to the UI
973
1014
  uiSystem.nativeHeight // If set, UI coords are normalized to this height
974
1015
  uiSystem.destroyObjects() // Remove all UI elements
975
1016
  uiSystem.isMouseOverUI() // True if the mouse is over a visible hoverable UI object, or a confirm dialog is open
976
- uiSetDebug(enable) // Toggle uiDebug rendering of widget bounds
1017
+ uiSetDebug(debugMode) // Toggle uiDebug rendering of widget bounds
977
1018
 
978
1019
  // Confirm dialog
979
1020
  uiSystem.showConfirmDialog(text='Are you sure?', yes, no, size, exitKey='Escape') // the exit key or gamepad B answers no, the title and buttons scale with size
@@ -1129,6 +1170,16 @@ postProcessChromatic(strength=.005) // red and blue split apart toward
1129
1170
  postProcessGlow(threshold=.6, strength=1, size=6) // the bloom as a piece
1130
1171
  postProcessOutline(color=BLACK, thickness=1, threshold=.02) // lines where the 3D depth jumps, needs
1131
1172
  // render3D.depthTexture
1173
+ postProcessTiltShift(focus=.5, size=.25, blur=8) // a sharp band across the screen at focus, 0 bottom to 1 top,
1174
+ // size its height, blurred above and below, 2D or 3D
1175
+ postProcessDepthOfField(focus=10, range=4, blur=8) // sharp at focus world units from the camera, range deep,
1176
+ // blurred nearer and farther; needs render3D.depthTexture
1177
+ postProcess.values = {focus: .5} // the game's own values for the shader, a uniform each, set every
1178
+ // frame; any effect setting but glow's size, which sets its sample
1179
+ // count, may be such a name, to change it live; set them after the
1180
+ // plugin is made, as the shader is made at the first render;
1181
+ // not named _x, iX, gl_x, c, uv or p, which the shader uses:
1182
+ new PostProcessPlugin(postProcessEffects(postProcessTiltShift('focus'))); postProcess.values.focus = .6; // live
1132
1183
  ```
1133
1184
 
1134
1185
  ## LittleJS 3D Math
@@ -1164,7 +1215,7 @@ m.invert() m.transpose() // in place, return self
1164
1215
  m.copy() m.transformPoint(v) m.transformDirection(v) m.getTranslation() // or v.transform(m), v.transformDirection(m)
1165
1216
  m.getScale() m.getRotation() // the scale and the vec3(pitch, yaw, roll) back out of a transform, a mirror is a negative x
1166
1217
  m.determinant() // of the rotation and scale part: negative when it mirrors, 0 when it flattens
1167
- buildMatrix(pos, rotation, scale, out) // translate * rotate * scale, any arg optional; out is written into
1218
+ buildMatrix(pos, rotation, scale, matrix) // translate * rotate * scale, any arg optional; matrix is written into
1168
1219
  // instead of a new matrix, for a loop that builds many each frame
1169
1220
 
1170
1221
  // Collision - boxes are centered with full size, upright unless given a rotation, an Euler vec3 like rotation3D;
@@ -1687,8 +1738,9 @@ await loadOBJ(url, smooth) // fetch then parse, in an async gameInit; chain .cen
1687
1738
  // units
1688
1739
 
1689
1740
  // glTF models - the glTF plugin, .gltf with its files beside it or .glb in one file; meshes with their node placement,
1690
- // vertex colors, material colors and base color textures, and node animations; no skins or morph targets, and no
1691
- // Draco or meshopt compressed geometry, which throws saying so
1741
+ // vertex colors, material colors and base color textures, node animations and skinned characters, four joints a
1742
+ // vertex, bent on the CPU each frame; no morph targets, and no Draco or meshopt compressed geometry, which throws
1743
+ // saying so
1692
1744
  const model = await loadGLTF(url) // a GLTFModel, in an async gameInit; or await parseGLTF(data, baseUrl, files) on
1693
1745
  // bytes or JSON you already have; files, a Map of the .bin and image files a
1694
1746
  // .gltf names by their paths, like the files of a drop, in place of fetching,
@@ -1709,15 +1761,20 @@ model.createObject(pos3D) // a GLTFObject, an EngineObject3D with a c
1709
1761
  // emissive 1 for an unlit one; move and turn the root and the parts follow
1710
1762
  model.animations // one GLTFAnimation each: name, duration in seconds, and the channels that
1711
1763
  // move, turn and scale nodes; model.getAnimation(nameOrNumber) finds one
1712
- object.play(animation=0, loop=true, speed=1) // play one on a GLTFObject by name or number, its parts move with it;
1713
- // speed below 0 plays it backward, and one that does not loop holds its end
1764
+ object.play(animation=0, loop=true, speed=1, blend=0) // play one on a GLTFObject by name or number, its parts move
1765
+ // and a skinned mesh bends with it; speed below 0 plays it backward, one that
1766
+ // does not loop holds its end, and blend is seconds to cross-fade from the pose
1767
+ // it is in, the animation it leaves going on through the fade
1768
+ object.getJointMatrix(name) // a node's world Matrix4 as posed now, by its name in the file, to hang a sword
1769
+ // on a hand; undefined for a name the model does not have
1714
1770
  object.stop() // hold the pose where it is; object.setAnimationTime(t) poses it at a time
1715
1771
  object.animation .animationTime .animationSpeed .animationLoop .animationPlaying
1716
1772
  model.getPose(animation, time) // one Matrix4 per part, how far it moved from its resting place
1717
1773
  model.dispose() // free the part meshes, the combined mesh and the textures of a model that
1718
1774
  // is done with; destroy the objects createObject made first
1719
1775
  // colors come in converted from glTF's linear values, a NEAREST sampler makes a part pixelated, sparse accessors
1720
- // are read, and object.parts is what an animation poses
1776
+ // are read, and object.parts is what an animation poses; a skinned part's object bends a mesh of its own, so
1777
+ // characters of one model hold their own poses, and part.skin is what bends it
1721
1778
  model.center().fit(size) // move the model's bounds onto the origin and scale its largest extent to
1722
1779
  // size, every part together, like Mesh.center and fit; getBounds and
1723
1780
  // transform(matrix) as well
@@ -1840,8 +1897,8 @@ new THREE.Raycaster() // render3D.screenToRay, pick and engi
1840
1897
  OBJLoader // loadOBJ(url) or parseOBJ(text)
1841
1898
  GLTFLoader // loadGLTF(url): model.createObject(pos) is the scene as objects, model.mesh
1842
1899
  // is everything as one Mesh
1843
- mixer.clipAction(clip).play() // object.play(name) on the object createObject made, node animation only,
1844
- // no skinned characters
1900
+ mixer.clipAction(clip).play() // object.play(name) on the object createObject made, skinned characters
1901
+ crossFadeTo(next, seconds) // object.play(next, true, 1, seconds); bone.getWorldPosition: getJointMatrix
1845
1902
  EffectComposer and UnrealBloomPass // postProcessBloom()
1846
1903
  renderer.render(scene, camera) // nothing to do, the engine draws every frame and handles resizing
1847
1904
  position.setUsage(THREE.DynamicDrawUsage) // mesh.dynamicDraw = true once, then mesh.dirty = true when the points
@@ -2048,7 +2105,8 @@ box2d.raycast(start, end, includeSensors=false) // Returns the closest Box2dR
2048
2105
  // are passed through unless includeSensors
2049
2106
  box2d.raycastAll(start, end, includeSensors=false) // Every Box2dRaycastResult along the ray, nearest first
2050
2107
  box2d.boxCast(pos, size, includeSensors=false) / boxCastAll(pos, size, includeSensors=false) // An object, or all
2051
- // of them, whose shapes overlap the box; sensors are passed through unless included
2108
+ // of them, whose shapes' bounding boxes overlap the box, so near the corner of a turned
2109
+ // box or a circle it can find one the box misses; sensors are passed through unless included
2052
2110
  box2d.circleCast(pos, diameter, includeSensors=false) / circleCastAll(pos, diameter, includeSensors=false) // The
2053
2111
  // nearest object, or all of them, whose position is in the circle, wherever its shapes
2054
2112
  // are; objects of only sensors are passed over unless included
@@ -2300,7 +2358,7 @@ debugPoint(pos, color, time, angle) // Draw debug point
2300
2358
  debugLine(posA, posB, color, width=.1, time) // Draw debug line
2301
2359
  debugPoly(pos, points, color=WHITE, time=0, angle=0, fill) // Draw debug polygon
2302
2360
  debugText(text, pos, size=1, color=WHITE, time=0, angle=0) // Draw debug text
2303
- debugOverlap(pA, sA, pB, sB, color) // Draw a debug overlap between two boxes
2361
+ debugOverlap(posA, sizeA, posB, sizeB, color) // Draw a debug overlap between two boxes
2304
2362
  // each debug draw also takes screenSpace as its last parameter, defaulting to drawScreenSpace; debugText takes a
2305
2363
  // font before it
2306
2364
  debugClear() // Clear all debug primitives
@@ -2326,19 +2384,6 @@ debugTweakables = false // Is the tweakables panel shown? setDebugTweakables(sho
2326
2384
  debugWatermark // Should watermark with FPS appear in debug mode?
2327
2385
  ```
2328
2386
 
2329
- ## Deprecated
2330
-
2331
- Old names and argument orders that still work, marked `@deprecated` in the types; use the new ones, the old are
2332
- kept until 1.25 at least.
2333
-
2334
- ```javascript
2335
- obj.collideTiles // since 1.20, use obj.collideLevel, the same flag
2336
- weldJoint.setSpringDampingRatio(ratio) // since 1.20, use setDampingRatio, and getDampingRatio for the getter
2337
- newgrounds.logView() // since 1.20, does nothing, the view is logged when the plugin starts
2338
- drawNineSliceScreen(pos, size, startTile, borderSize, extraSpace, angle) // since 1.20, the order is now
2339
- drawThreeSliceScreen(pos, size, startTile, borderSize, extraSpace, angle) // (pos, size, startTile, color, ...)
2340
- ```
2341
-
2342
2387
  [LittleJS Engine](https://github.com/KilledByAPixel/LittleJS) Copyright 2021 Frank Force
2343
2388
 
2344
2389
  ![LittleJS Logo](examples/favicon.png)