littlejsengine 1.24.1 → 1.24.2

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 +59 -1
  2. package/EDITOR.md +2 -0
  3. package/FAQ.md +13 -2
  4. package/README.md +1 -1
  5. package/REFERENCE.md +20 -6
  6. package/dist/littlejs.d.ts +77 -13
  7. package/dist/littlejs.esm.js +2395 -1939
  8. package/dist/littlejs.esm.min.js +3 -3
  9. package/dist/littlejs.js +2392 -1939
  10. package/dist/littlejs.min.js +2 -2
  11. package/dist/littlejs.release.js +2356 -1952
  12. package/package.json +1 -1
  13. package/plugins/gltf.js +62 -9
  14. package/plugins/lightSystem.js +1 -1
  15. package/plugins/math3d.js +1014 -1013
  16. package/plugins/medalSystem.js +7 -11
  17. package/plugins/particleEffects.js +2 -2
  18. package/plugins/pathFinder.js +2 -2
  19. package/plugins/pluginExport.js +1 -0
  20. package/plugins/render3d.js +131 -55
  21. package/plugins/render3dEditor.js +24 -10
  22. package/plugins/render3dExtras.js +29 -17
  23. package/plugins/render3dLevel.js +21 -12
  24. package/plugins/render3dVoxels.js +2 -2
  25. package/plugins/textureSheet.js +97 -3
  26. package/plugins/tweakables.js +1 -1
  27. package/plugins/tweenSystem.js +2 -2
  28. package/plugins/uiSystem.js +6 -2
  29. package/src/engine.js +34 -11
  30. package/src/engineAudio.js +13 -3
  31. package/src/engineDebug.js +4 -1
  32. package/src/engineDraw.js +29 -16
  33. package/src/engineEditor.js +82 -50
  34. package/src/engineExport.js +2 -0
  35. package/src/engineInput.js +17 -3
  36. package/src/engineMath.js +6 -2
  37. package/src/engineObject.js +675 -675
  38. package/src/engineParticles.js +1 -1
  39. package/src/engineSettings.js +16 -0
  40. package/src/engineTileLayer.js +85 -22
  41. package/src/engineUtilities.js +20 -8
  42. package/src/engineWebGL.js +12 -8
package/CHANGELOG.md CHANGED
@@ -7,6 +7,60 @@ 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.24.2 - 2026-10-03
11
+
12
+ ### New Changes
13
+
14
+ - Tile sets from separate images: `loadTiles(['grass.png', 'brick.png', 'props.png'], 16)` packs tile images, or several tile sheets, into the texture sheets as one tile set, numbered in the order given, for `tileLayersLoad`, tile layers and the level editor's palette; an image that is not whole tiles gives the whole tiles in it, and a map's tileset margin or spacing does not replace the set
15
+ - Spotlight gels: `light.gel` is a picture the shadow casting spotlight shines through, cast along its beam in its colors, like a slide or stained glass; with none a scene draws exactly as before. The 3D First Person flashlight has one on G
16
+ - Less garbage each frame: objects are sorted only when one is out of render order and the destroyed taken out only when there are some, an object with mass that collides with nothing copies no position, and outlines and regular polygons are made into kept vectors, about 98 fewer for each outlined circle; a 3D pick makes no vectors for an object it misses
17
+ - `Mesh.computeNormals(true)` is 5 to 7 times faster, the same normals to the last bit: a 960 point flag in 0.24 ms where it took 1.8, so a mesh can be bent every frame
18
+ - `loadSprite`, `loadTiles` and `loadAtlas` give back what the first load did when the same image is loaded again with the same settings, packed once
19
+ - A release build goes on past an error in a frame, logging the first, where one error froze the game for good; a debug build stops and shows it as before
20
+
21
+ ### Fixes
22
+
23
+ - A Tiled property named as a method of the object it is for, like `update`, is left out, where it replaced the method; a debug build says so
24
+ - `noise2D` stays noise however far out y is, where past about 24 million every row was one value; it gives the same values as before everywhere else
25
+ - Medals: the save keeps the unlock of a medal the game has not made this time, and a medal made after `medalsInit` reads its unlock, so a medal made late or behind a flag is never lost; `medalsReset` locks those too
26
+ - Older browsers: the engine starts with no `OffscreenCanvas` (Safari before 16.4), drawing into a canvas element in its place, and so do the textures it makes itself (normal maps from heights, particle shapes, light glows, lens flares, glTF's white texture), and uses neither `Array.prototype.at` nor `Object.hasOwn` (Safari before 15.4); the example browser's markdown has no lookbehind, which Safari before 16.4 could not read
27
+ - On an iPhone the silent switch mutes the game, as it does a ringtone, and the player's music plays on beside it; `setSoundIgnoreSilentSwitch(true)` has the game play through the switch as media does (Safari 16.4 and up)
28
+ - Level editor: the brush, its ghost and the palette read a tile past the end of a sheet as nothing, as the layer draws it, where a collision value picked up with the right button asserted every frame; the palette of a tile set filled in after it was first shown shows its tiles
29
+ - A light's flare looks past four lamps around it to what is behind them, where the fourth counted as hidden
30
+ - A click or tap in the bars around a letterboxed canvas presses nothing, where it pressed whatever was at the canvas edge
31
+ - `showConfirmDialog` while one is open gives the one open, where a second broke UI navigation in release builds
32
+ - The level editor's cut, copy and stamps keep an object's name, size, turn and visibility, where a paste made a bare point; objects moved with a selection or stamped land on their place to the digit, not a hair off
33
+ - The 3D editor's terrain paint rounds no heights, and a sculpt stroke rounds only those it changed
34
+ - A `UISlider` let go in the frame it moves takes that last place
35
+ - A gamepad of fewer buttons put in the slot of another holds none of the other's buttons; a gamepad axis that reads NaN is centered, where it failed an assert in debug builds
36
+ - `UITextInput` takes a keydown with no key, as autofill sends, where it threw
37
+ - `parseOBJ` reads a comment after a face, carriage return line ends and a line carried on with a backslash, and a release build leaves out a face of a vertex the file does not have
38
+ - `tileLayersFromLDtk` keeps a tile layer with no tiles as an empty layer, so a level of one loads and the editor can paint it
39
+ - Level editor: a property set in the box keeps its place and a `file` or `object` property its type; a save leaves out the object layer made for a first object that was undone; a new object layer's id is past every layer's
40
+ - 3D editor: taking a prefab out of the level takes its instances out of the game; a level's parts are saved in one order, so a level reloaded from its autosave saves the same
41
+ - `writeSaveData` asserts its data is an object, which `readSaveData` reads back, and returns whether it was written, false when storage is full or unavailable
42
+ - `parseAtlas` warns of two sprites with one name; `nearestPowerOfTwo` is never less than its value and is 1 for a value of 1 or less; a particle effect's name cut to 60 characters ends with no space
43
+ - A tile layer's raycast toward a point far beyond the layer walks only across the layer, where a ray to a far constant took seconds
44
+ - `debugShowErrors` shows a message as text, so a file name with markup in it can not add elements to the page
45
+ - Canvas2D tints clamp the color to 0 to 1, as WebGL does
46
+ - glTF: the keys of the files given may start with ./ or / or use backslashes, a uri above them is refused, and an accessor that reaches past its buffer is refused before its floats are made
47
+ - A level whose prefab holds itself, several times over, loads at once with that prefab left out where it holds itself, in place of making thousands of objects
48
+ - Small malformed files no longer make a loader run on: an Aseprite tag past its frames keeps to them, a glTF node reached twice and an accessor of millions with no buffer are refused, an LDtk level of millions of cells is refused and a tile or entity with no place is passed by
49
+ - LDtk: an IntGrid layer whose rule tiles are on another tileset keeps its values for collision, its tiles left out with a warning
50
+ - A collision layer named that no layer has says so in release builds too
51
+ - A light's lens flare: its lamp is a mesh around the light that the ray meets near the light and that is thin, so a globe or a lamp post is its own fixture, while a room or a level mesh hides the light, even one close behind its wall
52
+ - VoxelMap: the inside of a doubleSided face is split along the same diagonal as its outside, so it shows no seam
53
+ - glTF: `parseGLTF(data, baseUrl, files)` finds the `.bin` and image files a `.gltf` names among files given, like a drop's, from the model's own folder, or by the file name alone when only one file has it; a file it can not find is named in the error, and an image that can not be read in a warning; the 3D Mesh example takes a `.gltf` dropped with its files or in its folder, and frees the model it replaces
54
+ - Example browser: after the arrow keys move through the list, Enter keeps the example they went to, and Escape in the search clears it without also closing the list
55
+ - 3D levels: a color that is not a string, and a number that is NaN or Infinity (1e999 in JSON), are read as the default, in place of an assert or a NaN
56
+ - `tileLayersLoad` says so when a map is not a whole number of cells across and down, has no layers, or a layer's tiles do not fill it, in release builds too, in place of running on; every layer is checked before any is made. A game that relied on a release build loading such a map anyway now gets the error
57
+ - A tile past the end of a sheet read by its columns draws nothing, as an LDtk IntGrid layer's values past the art did in the level editor, which asserted
58
+ - A tween that loops or ping pongs with a duration of 0 or less, possible in release builds, ends its loops
59
+
60
+ ### New Demos
61
+
62
+ - [Custom Editor](https://killedbyapixel.github.io/LittleJS/examples/?example=Custom%20Editor) - A level editor made for one game: a class of its own with a tool that lays out rooms by a drag, a button, a key and an overlay
63
+
10
64
  ## 1.24.1 - 2026-10-02
11
65
 
12
66
  ### New Changes
@@ -16,7 +70,11 @@ Nothing yet.
16
70
  - `tileLayersLoad`'s `collisionLayer` may be a layer's name
17
71
  - `light.addFlare` takes the flare's color too
18
72
  - LDtk: an IntGrid layer is always a hidden layer of its values under its own name, its rule tiles in layers over it named with tiles, so `tileLayersLoad(map, tileInfo, 0, 'Collisions')` is solid where the values say, whatever the tiles stack or fade; a project of several worlds loads; a project with no tileset entry keeps its tiles
19
- - The example browser has a new look, in the dark colors of the docs site: a slim top bar in place of the title, the demo at 16:9, and the example list as rows under their headings. A handle between the code and its write-up drags to give one the other's space, by touch and the arrow keys too, and is remembered; a double click puts the quarter back. On a phone the example's name, between Prev and Next, opens a full screen picker with the search. The Screenshot button is gone
73
+ - The example browser has a new look, in the dark colors of the docs site: a slim top bar in place of the title, the demo at 16:9, and the example list as rows under their headings. A handle between the code and its write-up drags to give one the other's space, by touch and the arrow keys too, and is remembered; a double click puts the quarter back. On a phone the example's name, between Prev and Next, opens a full screen picker with the search. The Screenshot button is gone. A button in the top bar switches between dark and light, the choice shared with the docs site
74
+
75
+ ### Breaking Changes
76
+
77
+ - LDtk: an IntGrid layer with tiles is now a hidden layer of its values under its own name, its tiles in layers named with tiles over it, so the layer indices and names of such a level move; name the collision layer, `tileLayersLoad(map, tileInfo, 0, 'Collisions')`, in place of an index
20
78
 
21
79
  ### Fixes
22
80
 
package/EDITOR.md CHANGED
@@ -341,6 +341,8 @@ after a reload.
341
341
 
342
342
  ## Where the working examples are
343
343
 
344
+ - `examples/shorts/customEditor.js`: a 2D editor class of a game's own, with a tool that lays out rooms by a
345
+ drag, a button, a key and an overlay drawn in `onDraw`.
344
346
  - `examples/shorts/render3dLevelEditor.js`: a 3D level with its own Coin and PlayerStart types and both hooks.
345
347
  - `examples/shorts/render3dPrefab.js`: the 3D editor used as a prefab maker.
346
348
  - `examples/shorts/levelEditor.js` and `examples/platformer/`: the 2D editor with a game's own types, palette
package/FAQ.md CHANGED
@@ -206,6 +206,10 @@ If you are using [Visual Studio Code](https://code.visualstudio.com/) there is a
206
206
 
207
207
  Another option is to setup a simple local web server like [http-server](https://www.npmjs.com/package/http-server) via npm.
208
208
 
209
+ ### Which browsers does LittleJS run in?
210
+
211
+ Current Chrome, Edge, Firefox and Safari, on desktop and on phones. The oldest it aims to support is Safari 15 (iOS 15) and the other browsers from 2021 on. Where WebGL2 is missing, 2D games fall back to Canvas2D rendering on their own; the 3D plugin needs WebGL2.
212
+
209
213
  ### How does the camera and world coordinate systems work?
210
214
 
211
215
  LittleJS drawing functions are all handled in world coordinates by default.
@@ -263,6 +267,13 @@ Plugins are self-contained features that live alongside the engine but aren't pa
263
267
  | `newgrounds.js` | Newgrounds.io integration (medals held on the server, scoreboards) |
264
268
  | `audioEffects.js` | Web Audio effects like filter, reverb, delay, distortion and compressor, for a group of sounds or everything |
265
269
  | `drawUtilities.js` | Higher-level drawing helpers like nine-slice and three-slice |
270
+ | `render3dVoxels.js` | `VoxelMap`, a 3D grid of blocks that draws itself and that objects collide with |
271
+ | `render3dLevel.js` | 3D levels as JSON: object types, prefabs, a scene block, block maps and terrain, loaded with `level3DLoad` |
272
+ | `render3dDebug.js` | 3D debug draws (`debugBox3D`, `debugSphere3D`, `debugLine3D`), in debug builds only |
273
+ | `render3dEditor.js` | The free camera and the 3D level editor, in debug builds only |
274
+ | `sceneSystem.js` | Scenes as plain objects, switched with `setScene` |
275
+ | `parallax.js` | `ParallaxLayer`, a background that follows the camera at its own depth and repeats |
276
+ | `particleEffects.js` | A library of ready made particle effects, and their designer's file format |
266
277
 
267
278
  This self-contained design means the community can also ship plugins independently of the main repo — you can write your own plugin as just a JavaScript file that uses the engine's public API.
268
279
 
@@ -367,7 +378,7 @@ LittleJS has a dedicated [js13k branch](https://github.com/KilledByAPixel/Little
367
378
  - **Lean on built-ins to avoid asset files**: `Sound` with ZzFX parameters generates sound effects from a tiny array, and built-in shape drawing avoids shipping image assets.
368
379
  - **Use a packer**: the js13k branch is set up to compress the final bundle with Roadroller or a similar packer. Check the branch's build script for the current toolchain.
369
380
 
370
- For normal production (non-13KB) builds, the engine ships `dist/littlejs.release.js` (asserts stripped) and `dist/littlejs.min.js` (minified) — both well under 100KB.
381
+ For normal production (non-13KB) builds, the engine ships `dist/littlejs.release.js` (asserts stripped, about 1.5 MB with every plugin and its comments) and `dist/littlejs.min.js` (minified, about 420 KB, about 125 KB gzipped). A bundler like Vite leaves out the plugins a game does not use, which makes a small game far smaller.
371
382
 
372
383
  ---
373
384
 
@@ -387,7 +398,7 @@ LittleJS works best when your tile sheet is broken up into grids of tiles becaus
387
398
  drawTile(vec2(21,5), vec2(4.5), tile(3,128));
388
399
  ```
389
400
 
390
- Once loaded, the underlying images are available via `textureInfos[0].image`, `textureInfos[1].image`, etc. This is useful for tasks like reading pixel data to generate a level — see [examples/module/game.js](examples/module/game.js) for an example that reads tile data directly from an image.
401
+ Once loaded, the underlying images are available via `textureInfos[0].image`, `textureInfos[1].image`, etc. This is useful for tasks like reading pixel data to generate a level — the [Level Editor short](https://killedbyapixel.github.io/LittleJS/examples/?example=Level%20Editor) loads a level from data instead, and [examples/module/game.js](examples/module/game.js) builds one from a string.
391
402
 
392
403
  ### What is the tile function and how do tile indexes work?
393
404
 
package/README.md CHANGED
@@ -172,7 +172,7 @@ LittleJS comes with several demos both for learning and using as starter project
172
172
  | [littlejs.esm.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.esm.js) | Debug | ESM | Debug mode with asserts |
173
173
  | [littlejs.esm.min.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.esm.min.js) | Release | ESM | Optimized for release and minified |
174
174
 
175
- Every build includes the plugins. littlejs.min.js is about 100 KB gzipped: the core engine is about 36 KB of that and the 3D plugins about 40 KB. A bundler like Vite leaves out the plugins a game does not use, so a small 2D game comes to about 26 KB gzipped, and a lit 3D scene to about 47 KB.
175
+ Every build includes the plugins. littlejs.min.js is about 125 KB gzipped, and the 3D plugins are a large part of that. A bundler like Vite leaves out the plugins a game does not use, so a small 2D game comes to about 26 KB gzipped, and a lit 3D scene to about 47 KB.
176
176
 
177
177
  ## Games Made With LittleJS
178
178
 
package/REFERENCE.md CHANGED
@@ -144,7 +144,7 @@ fetchJSON(url) // Fetch and parse a JSON file (async)
144
144
  shareURL(title, url, callback) // Share a URL via the navigator share API
145
145
  readSaveData(saveName, defaultSaveData) // Read game save data from localStorage, default must be an object
146
146
  // the result has the default's type in TypeScript
147
- writeSaveData(saveName, saveData) // Write game save data to localStorage; give medalsInit a different name
147
+ writeSaveData(saveName, saveData) // Write a save data object to localStorage, false if it could not; give medalsInit a different name
148
148
 
149
149
  // Random functions
150
150
  rand(valueA=1, valueB=0) // Random float between values
@@ -441,6 +441,8 @@ getNoteFrequency(semitoneOffset, rootFrequency=220) // Get frequency for musica
441
441
 
442
442
  // Audio settings
443
443
  soundEnable = true // Should sound be enabled?
444
+ soundIgnoreSilentSwitch = false // play with an iPhone's silent switch on, as media, pausing the player's music;
445
+ // off, the switch mutes the game; setSoundIgnoreSilentSwitch(true)
444
446
  soundVolume = .3 // Volume scale to apply to all sound
445
447
  soundDefaultRange = 40 // Default range where sound no longer plays
446
448
  soundDefaultTaper = .7 // Default range percent to taper off sound (0-1)
@@ -1301,6 +1303,9 @@ light.coneAngle = .5 // a spotlight: the angle in radians from its
1301
1303
  // cone, 0 by default for a light that shines every way; it shines along its
1302
1304
  // own forward, so rotation3D or what it is attached to aims it
1303
1305
  light.coneSoftness = .2 // how much of the cone is its fading edge: 0 a hard edge, 1 fading from the middle
1306
+ light.gel = textureInfo // or a TileInfo's whole texture: a picture the light shines through, cast along its cone in its colors, upright
1307
+ // as the light looks out, like a slide or stained glass; only the spotlight that
1308
+ // casts the shadows has one, render3D.shadows on and it as render3D.shadowLight
1304
1309
  light.glow = 1 // a soft hazy glow over the light this big, like a lamp at night; 0 by default,
1305
1310
  // added onto what is behind it, hidden by what is in front
1306
1311
  light.glowFalloff = 1 // how fast the glow fades from its middle, .5 a wide haze, 2 a tight bright core
@@ -1667,8 +1672,9 @@ const map = new VoxelMap(pos3D=vec3(), mapSize=vec3(16), tileInfo=tile()) // a g
1667
1672
  // that objects with collideLevel collide with; pos3D is its corner and a cell is 1 unit, it stays upright
1668
1673
  map.setVoxel(cell, type) / map.getVoxel(cell) // type 1-255 shows that tile on every face, 0 is empty, a cell outside
1669
1674
  // the map is ignored and reads 0
1670
- map.setBlockType(type, faces, {seeThrough, transparent}) // faces: a tile, six (+x, -x, +y, -y, +z, -z), or
1671
- // {top, side, bottom}; seeThrough for holes like leaves, transparent to blend like water, drawn after the rest
1675
+ map.setBlockType(type, faces, {seeThrough, transparent, doubleSided}) // faces: a tile, six (+x, -x, +y, -y, +z,
1676
+ // -z), or {top, side, bottom}; seeThrough for holes like leaves, transparent to blend like water, drawn after
1677
+ // the rest; doubleSided for faces seen from inside too, so the surface of water shows from under it
1672
1678
  map.raycast(ray, maxDistance, test) // {distance, cell, normal, type} of the first block a ray hits, or
1673
1679
  // undefined; test(type, cell) says which blocks count
1674
1680
  map.data / map.rebuild() // the Uint8Array of types, x + mapSize.x*(y + mapSize.y*z); rebuild
@@ -1683,8 +1689,10 @@ await loadOBJ(url, smooth) // fetch then parse, in an async gameInit; chain .cen
1683
1689
  // glTF models - the glTF plugin, .gltf with its files beside it or .glb in one file; meshes with their node placement,
1684
1690
  // vertex colors, material colors and base color textures, and node animations; no skins or morph targets, and no
1685
1691
  // Draco or meshopt compressed geometry, which throws saying so
1686
- const model = await loadGLTF(url) // a GLTFModel, in an async gameInit; or await parseGLTF(data, baseUrl) on bytes or
1687
- // JSON you already have
1692
+ const model = await loadGLTF(url) // a GLTFModel, in an async gameInit; or await parseGLTF(data, baseUrl, files) on
1693
+ // bytes or JSON you already have; files, a Map of the .bin and image files a
1694
+ // .gltf names by their paths, like the files of a drop, in place of fetching,
1695
+ // baseUrl then the .gltf's folder among them
1688
1696
  model.parts // one GLTFPart per primitive of every node: name, mesh in model space, color,
1689
1697
  // textureInfo when the material has one and WebGL is on, transparent for a
1690
1698
  // blending material or glass (KHR_materials_transmission), which comes in
@@ -2172,6 +2180,11 @@ getCrescentPoints(pos, size=1, percent=0, angle=0, invert=false, sides=glCircleS
2172
2180
  - See `examples/shorts/textureSheet.js`
2173
2181
 
2174
2182
  ```javascript
2183
+ loadTiles(sources, tileSize, padding=1) // Pack tile images, or several tile sheets, into one tile set: each image cut
2184
+ // into tiles, numbered from 0 in the order given; give the TileInfo it
2185
+ // returns to tileLayersLoad or a TileLayer, and await spritesReady first
2186
+ tileInfo.tiles // a tile set's tiles, each where it was packed: a tile layer draws tile n
2187
+ // from tiles[n], and the level editor's palette offers each
2175
2188
  loadSprite(src, frameSize, padding=1, sourcePadding=0) // Load an image and pack it, returns a TileInfo
2176
2189
  loadAtlas(imageSrc, jsonSrc, padding=1) // Load a TexturePacker or Aseprite atlas, returns name->TileInfo object
2177
2190
  parseAtlas(data) // Parse atlas json into named frame groups, used by loadAtlas
@@ -2288,7 +2301,8 @@ debugLine(posA, posB, color, width=.1, time) // Draw debug line
2288
2301
  debugPoly(pos, points, color=WHITE, time=0, angle=0, fill) // Draw debug polygon
2289
2302
  debugText(text, pos, size=1, color=WHITE, time=0, angle=0) // Draw debug text
2290
2303
  debugOverlap(pA, sA, pB, sB, color) // Draw a debug overlap between two boxes
2291
- // each debug draw also takes screenSpace after the params above, defaulting to drawScreenSpace
2304
+ // each debug draw also takes screenSpace as its last parameter, defaulting to drawScreenSpace; debugText takes a
2305
+ // font before it
2292
2306
  debugClear() // Clear all debug primitives
2293
2307
  debugScreenshot() // Save a screenshot at the end of this frame
2294
2308
  debugShowErrors() // Show full page error message when an error occurs
@@ -1345,6 +1345,12 @@ declare module "littlejsengine" {
1345
1345
  * @default
1346
1346
  * @memberof Settings */
1347
1347
  export let soundEnable: boolean;
1348
+ /** Play sound with an iPhone's silent switch on, as media does; off by default, so the switch mutes the game as it
1349
+ * does a ringtone, and the player's own music keeps playing beside it; Safari 16.4 and up, elsewhere it does nothing
1350
+ * @type {boolean}
1351
+ * @default
1352
+ * @memberof Settings */
1353
+ export let soundIgnoreSilentSwitch: boolean;
1348
1354
  /** Volume scale to apply to all sound, music and speech
1349
1355
  * Use setSoundVolume to also update the audio master gain immediately
1350
1356
  * @type {number}
@@ -1614,6 +1620,10 @@ declare module "littlejsengine" {
1614
1620
  * @param {boolean} enable
1615
1621
  * @memberof Settings */
1616
1622
  export function setSoundEnable(enable: boolean): void;
1623
+ /** Set if sound plays with an iPhone's silent switch on, as media does, which also pauses the player's own music
1624
+ * @param {boolean} ignore
1625
+ * @memberof Settings */
1626
+ export function setSoundIgnoreSilentSwitch(ignore: boolean): void;
1617
1627
  /** Set volume scale to apply to all sound, music and speech
1618
1628
  * @param {number} volume
1619
1629
  * @memberof Settings */
@@ -1806,7 +1816,7 @@ declare module "littlejsengine" {
1806
1816
  * @return {number}
1807
1817
  * @memberof Math */
1808
1818
  export function smoothStep(percent: number): number;
1809
- /** Returns the nearest power of two not less than the value
1819
+ /** Returns the nearest whole power of two not less than the value, 1 for a value of 1 or less
1810
1820
  * @param {number} value
1811
1821
  * @return {number}
1812
1822
  * @memberof Math */
@@ -1899,6 +1909,7 @@ declare module "littlejsengine" {
1899
1909
  export function saveText(text: string, filename?: string, type?: string): void;
1900
1910
  /** Create an offscreen canvas to draw into, and return its 2D context
1901
1911
  * - The canvas is context.canvas, which is what TextureInfo and the like take
1912
+ * - A browser with no OffscreenCanvas, Safari before 16.4, gets a canvas element that is not on the page
1902
1913
  * @param {number} width - In pixels
1903
1914
  * @param {number} [height] - In pixels, defaults to the width for a square
1904
1915
  * @param {boolean} [willReadFrequently] - Keep it in software, faster when getImageData is called on it often
@@ -1933,11 +1944,12 @@ declare module "littlejsengine" {
1933
1944
  export function readSaveData<T extends {
1934
1945
  [x: string]: any;
1935
1946
  } = any>(saveName: string, defaultSaveData?: T): T;
1936
- /** Write save data to local storage
1947
+ /** Write save data to local storage, an object as readSaveData gives it back
1937
1948
  * @param {string} saveName - unique name for the game/save
1938
1949
  * @param {object} saveData - object containing data to be saved
1950
+ * @return {boolean} - Whether it was written, false when storage is unavailable or full
1939
1951
  * @memberof Utilities */
1940
- export function writeSaveData(saveName: string, saveData: object): void;
1952
+ export function writeSaveData(saveName: string, saveData: object): boolean;
1941
1953
  /** 1D value noise — returns a smooth value in [0, 1] for any real x.
1942
1954
  * Integer inputs land on deterministic lattice values; non-integer inputs
1943
1955
  * are interpolated with smoothStep for C1 continuity.
@@ -2535,6 +2547,10 @@ declare module "littlejsengine" {
2535
2547
  padding: number;
2536
2548
  /** @property {TextureInfo} - The texture info for this tile */
2537
2549
  textureInfo: TextureInfo;
2550
+ /** @property {Array<TileInfo>|undefined} - A tile set's tiles, each wherever it was packed, as loadTiles makes
2551
+ * them: a tile layer given this tile info draws its tile n from tiles[n] and not from a grid on one sheet
2552
+ * @type {Array<TileInfo>|undefined} */
2553
+ tiles: Array<TileInfo> | undefined;
2538
2554
  /** @property {number} - Shrinks tile by this many pixels to prevent neighbors bleeding */
2539
2555
  bleed: number;
2540
2556
  /** @property {number} - How many frames per row for frame(), 0 to keep frames on a single row */
@@ -3660,13 +3676,13 @@ declare module "littlejsengine" {
3660
3676
  * @memberof Audio
3661
3677
  * @example
3662
3678
  * // load an audio asset file
3663
- * const sound_example = new Sound('sound.mp3');
3679
+ * const music = new Sound('sound.mp3');
3664
3680
  *
3665
3681
  * // create a zzfx sound
3666
- * const sound_example = new Sound([.5,.5]);
3682
+ * const blip = new Sound([.5,.5]);
3667
3683
  *
3668
3684
  * // play a sound
3669
- * sound_example.play();
3685
+ * blip.play();
3670
3686
  */
3671
3687
  export class Sound {
3672
3688
  /** Create a sound object and cache the audio for later use
@@ -4284,7 +4300,8 @@ declare module "littlejsengine" {
4284
4300
  * @param {number} [renderOrder] - Render order of the top layer
4285
4301
  * @param {number|string} [collisionLayer] - Layer to use for collision if any, by its index or its name
4286
4302
  * @param {boolean} [draw] - Should the layer be drawn automatically
4287
- * @return {Array<TileCollisionLayer>}
4303
+ * @return {Array<TileCollisionLayer>} - It throws for a map that is not whole cells, or a layer whose tiles do not
4304
+ * fill it, before it makes any layer
4288
4305
  * @memberof TileLayers */
4289
4306
  export function tileLayersLoad(tileMapData: any, tileInfo?: TileInfo, renderOrder?: number, collisionLayer?: number | string, draw?: boolean): Array<TileCollisionLayer>;
4290
4307
  /**
@@ -4605,7 +4622,7 @@ declare module "littlejsengine" {
4605
4622
  * rgb(1,1,1,0), rgb(0,0,0,0), // colorEndA, colorEndB
4606
4623
  * 1, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
4607
4624
  * .99, 1, 1, PI, .05, // damping, angleDamping, gravityScale, particleCone, fadeRate
4608
- * .5, 1 // randomness, collide
4625
+ * .5, true // randomness, collide
4609
4626
  * );
4610
4627
  */
4611
4628
  export class ParticleEmitter extends EngineObject {
@@ -7681,8 +7698,8 @@ declare module "littlejsengine" {
7681
7698
  * const path = pf.findPath(player.pos, mousePos);
7682
7699
  *
7683
7700
  * // Bare grid with custom walkability:
7684
- * const pf = new PathFinder(vec2(50, 50));
7685
- * pf.isWalkable = (x, y) => myGrid[y*50 + x] === 0;
7701
+ * const gridFinder = new PathFinder(vec2(50, 50));
7702
+ * gridFinder.isWalkable = (x, y) => myGrid[y*50 + x] === 0;
7686
7703
  */
7687
7704
  export class PathFinder {
7688
7705
  /** @param {TileCollisionLayer|Vector2} source - Either a TileCollisionLayer
@@ -8503,6 +8520,7 @@ declare module "littlejsengine" {
8503
8520
  viewProjection: Matrix4;
8504
8521
  /** @property {Matrix4} - This frame's light view projection for the shadow map */
8505
8522
  shadowMatrix: Matrix4;
8523
+ gelAxes: number[];
8506
8524
  /** @property {Vector3} - Camera right axis this frame */
8507
8525
  cameraRight: Vector3;
8508
8526
  /** @property {Vector3} - Camera up axis this frame */
@@ -9885,6 +9903,13 @@ declare module "littlejsengine" {
9885
9903
  /** @property {number} - How fast the glow fades from its middle: 1 by default, .5 a wide haze, 2 a tight
9886
9904
  * bright core */
9887
9905
  glowFalloff: number;
9906
+ /** @property {TextureInfo|TileInfo|undefined} - A gel: a picture the light shines through, like a stained glass
9907
+ * window or the leaves of a tree, cast along its cone in its colors, upright as the light looks out, the whole
9908
+ * texture of a TileInfo; only the spotlight that casts the shadows has one, with render3D.shadows on and it
9909
+ * as render3D.shadowLight, and only on what takes its shadows: an object with receiveShadow off is lit
9910
+ * without the gel; its alpha is not read, see through panes are dark
9911
+ * @type {TextureInfo|TileInfo|undefined} */
9912
+ gel: TextureInfo | TileInfo | undefined;
9888
9913
  /** @type {LensFlare3D|undefined} */
9889
9914
  flareObject: LensFlare3D | undefined;
9890
9915
  /** Give the light a lens flare, made with the arguments of LensFlare3D, in place of the one it had
@@ -10219,7 +10244,8 @@ declare module "littlejsengine" {
10219
10244
  * with the sun's own color; shapes says what its ghosts are, glowSize and ghostSize how big its parts are; or
10220
10245
  * give it elements of your own, which may be tiles of the game's
10221
10246
  * - visible is how much of the sun shows, 0 to 1, eased over fadeTime, there for a game to read; it is 0 while the
10222
- * sun is too far off the screen for the flare to show, a third of the screen past its edge, where nothing is tested
10247
+ * sun is too far off the screen for the flare to show, about a seventh of the screen past its edge, where nothing
10248
+ * is tested
10223
10249
  * - What hides the sun is found with a ray from the camera, against the level and every object that is not see
10224
10250
  * through, each on the triangles of its mesh, see render3D.pick; turn it off with occlusion
10225
10251
  * - It needs WebGL, and it draws nothing in the shadow of renderAfter2D
@@ -10262,7 +10288,7 @@ declare module "littlejsengine" {
10262
10288
  elements: Array<LensFlareElement> | undefined;
10263
10289
  /** @property {Light3D|undefined} - A light the flare is of in place of the sun, a lamp or a spotlight: the
10264
10290
  * flare is at the light and in its color, smaller from farther than the light reaches, hidden by what is
10265
- * in front of the light but its lamp, a mesh around it no wider than half its radius, and a spotlight's
10291
+ * in front of the light but its lamp, a mesh around it whose surface is near it, and a spotlight's
10266
10292
  * shows from inside its beam only; a DirectionalLight3D's is far
10267
10293
  * away where it shines from, like the sun's; the flare is destroyed when its light is; light.addFlare
10268
10294
  * sets this
@@ -10566,11 +10592,24 @@ declare module "littlejsengine" {
10566
10592
  duration: number;
10567
10593
  }
10568
10594
  /** Parse a model from GLB bytes or glTF JSON, fetching the buffers and images it refers to
10595
+ * - A .gltf names its .bin and image files, which are fetched from baseUrl, or found among files: what a game
10596
+ * has in hand, like the files dropped on the page, by their paths in the drop; with files, baseUrl is the
10597
+ * .gltf's own folder among them ('' or 'models/house/'), its names are read from there, and a name found nowhere
10598
+ * there is taken by its file name alone only when one file of the drop has it; only an http, https or blob uri
10599
+ * is fetched then
10600
+ * - A file the model needs that is not found is named in the error, and an image that can not be read is named in
10601
+ * a warning and left out
10569
10602
  * @param {ArrayBuffer|Object|string} data - GLB bytes, or the glTF JSON as bytes, text or an object
10570
10603
  * @param {string} [baseUrl] - Where the .bin and image files are, with its trailing slash; loadGLTF passes the file's folder
10604
+ * @param {Map<string, Blob>} [files] - The files it refers to, by their paths, in place of fetching them
10571
10605
  * @return {Promise<GLTFModel>}
10606
+ * @example
10607
+ * // the files of a drop, a .gltf with its .bin and textures, by their names
10608
+ * const files = new Map([...dataTransfer.files].map((file)=> [file.name, file]));
10609
+ * const gltf = [...files.values()].find((file)=> file.name.endsWith('.gltf'));
10610
+ * const model = await parseGLTF(await gltf.text(), '', files);
10572
10611
  * @memberof GLTF */
10573
- export function parseGLTF(data: ArrayBuffer | any | string, baseUrl?: string): Promise<GLTFModel>;
10612
+ export function parseGLTF(data: ArrayBuffer | any | string, baseUrl?: string, files?: Map<string, Blob>): Promise<GLTFModel>;
10574
10613
  /** Load a glTF or GLB model, the .bin and images of a .gltf from beside it
10575
10614
  * - A texture only OPAQUE materials use loads with its alpha set to 1, so the 3D pass cuts no holes in it
10576
10615
  * @param {string} url
@@ -10831,6 +10870,7 @@ declare module "littlejsengine" {
10831
10870
  * - Animation frames keep layout and wrap across rows as needed
10832
10871
  * - WebGL textures upload once per batch of loads
10833
10872
  * - loadAtlas imports pre-packed atlases (TexturePacker and Aseprite json)
10873
+ * - loadTiles packs separate tile images, or several tile sheets, into one tile set for tile layers and maps
10834
10874
  * @namespace TextureSheets
10835
10875
  */
10836
10876
  /** Width and height in pixels of texture sheets created by loadSprite
@@ -10901,6 +10941,7 @@ declare module "littlejsengine" {
10901
10941
  * - Pass frameSize for animations, then step through them with TileInfo.frame
10902
10942
  * - Grid images keep their layout and frames wrap down to the next row
10903
10943
  * - Pass sourcePadding if the source image has padding baked in around frames
10944
+ * - The same image loaded again with the same settings gives back what the first load did, packed once
10904
10945
  * @param {string} src - Image source path
10905
10946
  * @param {Vector2|number} [frameSize] - Size of each animation frame in pixels, or the whole image less its
10906
10947
  * source padding if not passed
@@ -10912,6 +10953,28 @@ declare module "littlejsengine" {
10912
10953
  * const runTile = loadSprite('run.png', vec2(16)); // a 16x16 frame animation
10913
10954
  * @memberof TextureSheets */
10914
10955
  export function loadSprite(src: string, frameSize?: Vector2 | number, padding?: number, sourcePadding?: number | Vector2): TileInfo;
10956
+ /** Load tile images and pack them into texture sheets as one tile set, for tile layers and maps
10957
+ * - Each image is cut into tiles of tileSize, left to right then down, so an image of one tile is one tile and a
10958
+ * sheet is all of its tiles; the tiles are numbered from 0 in the order the images are given
10959
+ * - Returns a tile set at once, a TileInfo whose tiles fill in as the images load; wait for them with spritesReady
10960
+ * - Give it to tileLayersLoad, a TileLayer or a TileCollisionLayer as its tile info: tile n draws tiles[n],
10961
+ * wherever it was packed, and the level editor's palette offers each of them; frame and index do not read the
10962
+ * list, use set.tiles[n] for one tile; make the layers after spritesReady, a layer made before draws nothing
10963
+ * - An image that is not a whole number of tiles gives the whole tiles in it; a sheet with gaps between its tiles
10964
+ * is not read, cut it into its tiles first
10965
+ * - An image that fails to load, or that no sheet can hold, adds no tiles and says so in the console, so the tiles
10966
+ * of the images after it move up
10967
+ * - The same images loaded again with the same settings give back what the first load did, packed once
10968
+ * @param {Array<string>} sources - Image source paths
10969
+ * @param {Vector2|number} [tileSize] - Size of a tile in pixels
10970
+ * @param {number} [padding] - How many pixels padding around each tile on the sheet
10971
+ * @return {TileInfo}
10972
+ * @example
10973
+ * const tiles = loadTiles(['grass.png', 'dirt.png', 'water.png', 'props.png'], 16);
10974
+ * await spritesReady();
10975
+ * tileLayersLoad(map, tiles); // tile 0 is grass, 1 dirt, 2 water, then the tiles of props.png
10976
+ * @memberof TextureSheets */
10977
+ export function loadTiles(sources: Array<string>, tileSize?: Vector2 | number, padding?: number): TileInfo;
10915
10978
  /** Load a pre-packed texture atlas and repack it onto texture sheets
10916
10979
  * - Supports TexturePacker json (hash and array) and Aseprite json
10917
10980
  * - Returns an empty object which is filled with TileInfos when loaded
@@ -10919,6 +10982,7 @@ declare module "littlejsengine" {
10919
10982
  * - Aseprite frame tags become animations, so do names like run_0, run_1
10920
10983
  * - Trimmed frames are restored to their full source size when packed
10921
10984
  * - Rotated frames are rotated back upright when packed
10985
+ * - The same atlas loaded again by its paths, with the same padding, gives back what the first load did, packed once
10922
10986
  * @param {string} imageSrc - Atlas image path
10923
10987
  * @param {string|Object} jsonSrc - Atlas json path, or already parsed json data
10924
10988
  * @param {number} [padding] - How many pixels padding around each frame