littlejsengine 1.23.1 → 1.24.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,261 @@
1
+ # LittleJS Changelog
2
+
3
+ What changed in each release, newest first. Releases before 1.20.0 are on the
4
+ [GitHub releases page](https://github.com/KilledByAPixel/LittleJS/releases).
5
+
6
+ ## Unreleased
7
+
8
+ Nothing yet.
9
+
10
+ ## 1.24.1 - 2026-10-02
11
+
12
+ ### New Changes
13
+
14
+ - A VoxelMap block type can be `doubleSided`, its faces shown from inside the block too, so the surface of water shows from under it
15
+ - 3D Voxels: the player goes under water and walks on the bottom, in place of floating at the surface
16
+ - `tileLayersLoad`'s `collisionLayer` may be a layer's name
17
+ - `light.addFlare` takes the flare's color too
18
+ - 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
20
+
21
+ ### Fixes
22
+
23
+ - Box2D: `addRegularPoly` with a side count that is not a whole number no longer hangs, as the engine's own polygons do not since 1.23.1
24
+ - The level editor's tile palette no longer asserts on a Tiled tileset with a margin or a spacing
25
+ - LDtk: a see-through tile keeps its opacity, in a layer of its own; a layer whose tileset is another size is left out with a warning, in place of being read as stacks; a missing level says so in release builds too
26
+ - A Tiled tileset's margin and spacing count from where the game's sheet starts, so a sheet inside an atlas keeps its place
27
+ - 2D level editor: applying an autosave of another size leaves an object layer it does not know about as the file has it, and an autosave whose tiles do not fit its size no longer resizes the map
28
+ - A light's lens flare is hidden by a room or a level mesh around it, seen from outside: only a lamp, a mesh around the light no wider than half its radius, is passed by
29
+ - Example browser: Enter on a focused example selects it, a heading named in a write-up is no longer a link that does nothing, blocked or broken saved preferences no longer stop the page, and the handle drags with the main button only
30
+ - 3D level editor: a broken autosave no longer blocks every edit until Drop, and one older than the last edits, which storage had no room for, says so as the 2D editor does
31
+
32
+ ## 1.24.0 - 2026-10-02
33
+
34
+ ### New Demos
35
+
36
+ - [3D Lens Flare](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Lens%20Flare) - Now with hexagons, and flares on lamps as well as the sun
37
+ - [Text](https://killedbyapixel.github.io/LittleJS/examples/?example=Text) - What drawText can do: sizes, outlines, alignment, fonts, rows and text placed in pixels
38
+ - [Physics](https://killedbyapixel.github.io/LittleJS/examples/?example=Physics) - The engine's own objects falling, bouncing, sliding and floating, and a sensor
39
+ - [Random](https://killedbyapixel.github.io/LittleJS/examples/?example=Random) - Random numbers, and a seeded generator that gives the same result every time
40
+
41
+ ### New Changes
42
+
43
+ - Every short example has a write-up in the example browser: what it shows, how its code works, things to try in the editor and where to look next, with links to the docs and to other examples
44
+ - Lens flares on lights: `light.addFlare()` gives a `Light3D` a lens flare of its own and returns it, `light.flare` is the flare, and it goes with the light; a `DirectionalLight3D` can have one too, far away like the sun's
45
+ - Lens flares in the 3D level editor: a level's Light has a `lensFlare` property, and the Scene box has a Lens flare checkbox for the sun's, saved in the level's scene block
46
+ - Lens flares have three more shapes, `hex`, `streak` and `star`; `flare.shapes` says what the ghosts are picked from, `glowSize` and `ghostSize` scale its parts, and an element may be a tile of the game's own (`tileInfo`), turned (`angle`) and wider than tall
47
+ - 3D picking is triangle accurate: `render3D.pick`, `engineObjectsRaycast3D` and clicks in the 3D level editor hit a mesh on its triangles, not the box around it
48
+ - LDtk levels load: `tileLayersFromLDtk(ldtk, level)` makes a level of an LDtk project a Tiled map for `tileLayersLoad` and `objectLayersLoad`, with its tile, auto and IntGrid layers, tiles stacked in a cell and see-through tiles, its entities as objects and their fields as properties
49
+ - A Tiled tileset with a margin or a spacing, a sheet with gaps between its tiles, is read where its tiles are
50
+ - The 3D Example has lens flares, on the sun and on each orb
51
+ - CHANGELOG.md lists what changed in each release, and the site's root goes to the example browser
52
+
53
+ ### Breaking Changes
54
+
55
+ - ZzFXM, the tracker music plugin, is removed: it was made for the js13k size limit. A game with a song in that format includes ZzFXM itself and hands its samples to a `Sound`
56
+ - 3D picking hits only the faces that are drawn: a mesh seen from inside is no longer hit unless it is `doubleSided`
57
+ - `LensFlare3D`: `getSunScreenPos` is now `getScreenPos` and `isSunHidden` is now `isHidden`, since a flare may be a light's; `visible` is 0 while the sun is off the screen; a flare pointed at a light is destroyed with it
58
+ - The repository's `dist/` is now the last release, not the latest source: it is committed only for a release, and the site is built from the source
59
+
60
+ ### Fixes
61
+
62
+ - A lens flare that is off the screen, or of a light that is off, no longer looks for what hides it every frame
63
+ - 3D level editor: an edit of a level's scene, or its undo, no longer takes away a sun lens flare that an earlier level's scene gave the game
64
+ - Shorts: the lander lands upright after a full turn, the maze reaches its top row and works at even sizes, a pocketed cue ball comes back, the 3D Voxels player floats in water, and more that writing them up turned up
65
+
66
+ ## 1.23.1 - 2026-10-02
67
+
68
+ ### New Changes
69
+
70
+ - 3D sprites are batched: an object with a tile and no mesh, or a `drawBillboard`, that is not transparent is drawn as one instanced batch with the other sprites of its sheet, its clear pixels cut out, so many sprites cost little; transparent and additive sprites still draw sorted, one by one
71
+ - A level's block map works in a game with no images: it shows plain colored blocks, where it used to fail
72
+ - glTF: emission stronger than 1 from Blender is read (`KHR_materials_emissive_strength`), a texture is smooth or pixelated as its sampler says whatever the game's tiles are, and a model with basis textures says they are not read
73
+ - The 2D level editor keeps the last 100 undo steps, as the 3D one does
74
+ - The npm package and the release zip include REFERENCE.md and EDITOR.md
75
+ - EDITOR.md says how to keep a level as a script for a game opened from disk, and what changing the editors' own tools takes
76
+ - The deprecated names from 1.20 are kept until 1.25 at least
77
+
78
+ ### Fixes
79
+
80
+ - A UI button pressed and released inside one frame was clicked twice
81
+ - `drawRegularPoly`, and circles with `setGLCircleSides`, hung on a side count that was not a whole number
82
+ - 2D level editor: a click on an object no longer rewrites its position with rounding noise and adds an undo step; applying saved edits to a file that gained an object layer leaves that layer alone; a level whose url has a `%20` in it matches its file again
83
+ - 3D level editor: saves of a prefab are written in the order they were asked for when `onSave` is async, a prefab edit that was undone no longer comes back after a reload, and objects a game's tool adds without ids get ids
84
+ - An attached prefab inside another prefab is placed where it belongs, and its collision box follows parts that are turned
85
+ - `levelEditor.onSave` may be an async function in TypeScript too
86
+ - A `Sound` made while sound is off counts as loaded, so a loading screen that waits for sounds finishes
87
+ - A tween callback that throws no longer leaves the tween system allocating on every update
88
+ - The build and the docs build leave `dist/` and `docs/` untouched when a step fails
89
+ - A `Timer` set to a time below zero reads as done
90
+ - `UIVideo` lets go of its video when it is destroyed
91
+ - A texture atlas tag with no frames no longer drops the groups after it
92
+ - `setAdditiveBlendMode` works in headless mode
93
+ - The release build's `levelEditor` has `keys`, `buttons` and `tools`, as the debug one does
94
+
95
+ ## 1.23.0 - 2026-10-01
96
+
97
+ ### New Demos
98
+
99
+ - [3D Prefab Maker](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Prefab%20Maker) - Build a prefab in the level editor and save it for a game to place
100
+ - [3D Level Editor](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Level%20Editor) - Now makes prefabs, flattens and paints terrain, and fills boxes of blocks
101
+ - [Parallax](https://killedbyapixel.github.io/LittleJS/examples/?example=Parallax) - Rebuilt on the new parallax plugin, with ranges of mountains that repeat as the camera goes by
102
+
103
+ ### New Changes
104
+
105
+ - 3D prefabs: a prefab is a small level placed many times. `level3DAddPrefab('House', data)` makes it a type, a level places it like a Box, and `level3DSpawn` places one from code; each part is a solid object of its own, or with `attached` the parts move with the instance as one body, for a vehicle or a creature
106
+ - The 3D level editor is the prefab editor too: Ctrl+G makes the selection a prefab, Enter opens one to edit it alone and every instance follows, Ctrl+Shift+G unpacks one, and the panel exports a prefab to a file and loads one from a file; prefabs can hold prefabs, and are saved in the level
107
+ - Make the level editors your own: `levelEditor.addKey`, `addButton` and `addTool` add a key, a panel button and a mouse tool of your game's own, `onOpen`, `onUpdate`, `onDraw`, `onPanel` and `onSave` are called by the editors, and `levelEditor.edit2D` and `edit3D` are the edit functions, each change an undo step. The same calls work in the 2D and the 3D editor
108
+ - Or extend it: `class MyEditor extends LevelEditor` with the hooks as methods, then `setLevelEditor(new MyEditor)`. Release builds take all of it and call none of it, so a game needs no guards
109
+ - New guide, [EDITOR.md](https://github.com/KilledByAPixel/LittleJS/blob/main/EDITOR.md): how to turn the built-in editors into an editor for your own game, written for people and AI assistants, with every example tested
110
+ - Added the Parallax plugin: a `ParallaxLayer` follows the camera by a part of its movement and repeats across the view, so a level of any width has a background; it draws mountains by default, or anything you draw into it
111
+ - Touch has a mouse wheel: a pinch of two fingers turns `mouseWheel`, so what zooms with the wheel zooms with a pinch, and `touchPinch` reads it by itself
112
+ - 3D level editor: the Terrain tool has a flatten brush and a paint brush that colors the ground, the Blocks tool fills a box with a drag and resizes its map, and the Move handles can follow an object's own axes (L)
113
+ - A `LensFlare3D` can be a light's flare: set `flare.light` and it sits at the lamp, in its color, hidden by what is in front of it
114
+ - The example browser has Prev and Next buttons, to go through the examples on a phone
115
+ - `Sound.range` can be set after a sound is made, and 3D sounds use it
116
+ - Size: the full build is about 122 KB gzipped, up from 119 KB; a bundler like Vite leaves out the plugins you don't use
117
+ - Fixes: a `SpriteAnimator` clip that ends and switches clips reads the new clip, glass and water blocks no longer hide the sun's lens flare, 3D particles appear at once like 2D ones, a spotlight that casts shadows lights no wider than its shadow map, the 3D editor's Scene box no longer undoes a field edited just before, and the example browser always shows the example picked last; the test suite grew from 1724 to 1848 tests
118
+
119
+ ### Upgrade Notes
120
+
121
+ - With two fingers down the touch screen pinches: the second finger lets go of the button the first one pressed. A game that uses two fingers its own way calls `setTouchPinchWheel(false)` to get the old behavior back
122
+ - A `ParticleEmitter3D` makes its first particle at once, where it used to wait one emit interval
123
+ - A spotlight set as `render3D.shadowLight` has its cone capped at 1.35 radians, what its shadow map covers
124
+ - `levelEditor.onRestart`, `onPlayFrom` and `onTile` are set the same way as before, but they are now empty methods when a game has not set them, so `if (levelEditor.onRestart)` is always true; nothing in a game needs to read them
125
+ - The Parallax short moved to the plugins section, and the platformer example uses the plugin for its mountains
126
+ - These names changed in 1.20 and the old ones still work for now: `collideTiles` is now `collideLevel`, and `Box2dWeldJoint.setSpringDampingRatio` is now `setDampingRatio`
127
+
128
+ ## 1.22.0 - 2026-10-01
129
+
130
+ ### New Demos
131
+
132
+ - [Particle Effects](https://killedbyapixel.github.io/LittleJS/examples/?example=Particle%20Effects) - Every built-in particle effect, one line each
133
+ - [Particle Options](https://killedbyapixel.github.io/LittleJS/examples/?example=Particle%20Options) - One effect, and what each option does to it
134
+ - [3D Lens Flare](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Lens%20Flare) - The sun flares across the screen and hides behind pillars
135
+ - [3D First Person](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20First%20Person) - Now with a night, and a flashlight that casts the shadows
136
+ - [3D Level Editor](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Level%20Editor) - Now paints blocks, sculpts terrain and sets the sky, sun and fog
137
+ - [Tween Advanced](https://killedbyapixel.github.io/LittleJS/examples/?example=Tween%20Advanced) - Every tween feature in labeled rows
138
+ - [Particle Designer](https://killedbyapixel.github.io/LittleJS/examples/particles/) - Rebuilt on the effects library, with a 3D preview
139
+
140
+ ### New Changes
141
+
142
+ - Added the Particle Effects plugin: `particleEffect('fire', pos)` plays one of 24 built-in effects in one line, and `particleEffect3D` plays the same effect in 3D; the options scale it, turn its hue, change its saturation, swap in your own tile, or replace any setting, like `{emitTime: .5}` for a burst
143
+ - The built-in effects are fire, torch, smoke, steam, explosion, sparks, hit, dust, debris, sparkle, magic, heal, poison, portal, rain, snow, leaves, bubbles, fireflies, trail, muzzle, blood, confetti and splash, each sized to fit a one unit object and drawn with shapes the plugin makes itself, so they need no image
144
+ - The Particle Designer is rebuilt on the plugin: the built-in effects are its presets, Save Library writes the file `particleEffectsLoad` reads so a game plays your effects by name, and it previews an effect in 2D or 3D with the same options a game passes
145
+ - `ParticleEmitter` has `scale`, which grows a whole effect, and `gravity`, its own fall; `ParticleEmitter3D` has `gravityScale` and `emitFlat`, which makes its spawn area a disc or a flat sheet
146
+ - 3D level editor: the Blocks tool (B) paints a level's block map, the Terrain tool (T) sculpts its terrain with a brush, and the Scene box sets its sky, sun, fog and shadows; all three are saved in the level's JSON, undo and autosave with the rest, and `level3DLoad` makes them with no game code
147
+ - Spotlights: a `Light3D` with a `coneAngle` shines along its own forward, with `coneSoftness` for where the fade starts, and `render3D.shadowLight` makes one spotlight cast the shadows in place of the sun, for a flashlight in the dark
148
+ - Added `LensFlare3D`, the sun's lens flare: a glow at the sun and a row of discs and rings across the screen, with its size, count, brightness and colors to set, fading out when something hides the sun
149
+ - 2D lights glow like the 3D ones: `light.glow` and `glowFalloff` on a `Light` of the light system
150
+ - Built-in post processing effects: `postProcessEffects` joins scanlines, noise, vignette, curve, chromatic, glow and a 3D outline into one shader, with your own GLSL as a piece too
151
+ - A texture can be smooth or pixelated on its own: `TextureInfo` takes `pixelated`, and `setPixelated` changes it
152
+ - Textures the engine sizes itself, like the shadow maps, fall back to the largest size a device supports; `glClampTextureSize` does the same for your own
153
+ - Faster: particles draw about 30% faster, `InstancedMesh3D` moves many instances with `setTransforms` and uploads less, the 3D draw state is checked with one number per draw, and ZzFX 1.4.0 generates sounds faster
154
+ - `render3D.playSound` hears a sound with no range of its own out to `render3D.soundDefaultRange`, 100 units
155
+ - Added a browser smoke suite, `npm run test:browser`: real WebGL in headless Chrome checks 2D draws, shaders, the 3D pass, spotlights, the lens flare, a lost and restored context, and that every short runs
156
+ - Size: the full build is about 119 KB gzipped, up from 108 KB; a bundler like Vite leaves out the plugins you don't use
157
+ - Fixes: post process feedback keeps the previous frame again, `loadGLTF` follows redirects and takes blob and data urls, overlapping Saves in the level editors write in order, and a scene `leave` that throws no longer blocks later switches; the test suite grew from 1562 to 1724 tests
158
+
159
+ ### Upgrade Notes
160
+
161
+ - A sound with no range of its own is now heard to 100 units when played with `render3D.playSound`, where it was 40; pass a range to `new Sound`, or set `render3D.soundDefaultRange`, to change it. 2D sounds are unchanged
162
+ - `particleEffect3D` and the particle designer's files use the plugin's effect format; an effect saved by the older designer still loads and keeps its tile
163
+ - The light system writes the sizes it could make back to `shadowMapSize`, `shadowTextureSize` and `textureSize` when a device can not make the size asked for
164
+ - The engine's own soft textures, the light glow and the particle shapes, are smooth even when `tilesPixelated` is on
165
+ - The Tween System and Stress Test full examples are gone, the Tween Advanced short covers tweens
166
+ - These names changed in 1.20 and the old ones still work for now: `collideTiles` is now `collideLevel`, and `Box2dWeldJoint.setSpringDampingRatio` is now `setDampingRatio`
167
+
168
+ ## 1.21.0 - 2026-09-29
169
+
170
+ ### New Demos
171
+
172
+ - [3D Level Editor](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Level%20Editor) - Place boxes, lights and coins, then walk around
173
+ - [3D Materials](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Materials) - Bricks from a normal map made in code, a polished ball reflecting the sky, and glowing windows
174
+ - [3D Ambient Occlusion](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Ambient%20Occlusion) - Creases and corners darkened from the new depth texture, side by side with plain
175
+ - [3D Water](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Water) - Rain on a pool, its waves a cellular automaton, reflecting the sky
176
+ - [Scenes](https://killedbyapixel.github.io/LittleJS/examples/?example=Scenes) - A title, a game with a pause overlay and game over, switched with `setScene`
177
+ - [Animation](https://killedbyapixel.github.io/LittleJS/examples/?example=Animation) - Sprite animation, with clips switched by name
178
+ - [3D Lights](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Lights) - The lamps now glow
179
+
180
+ ### New Changes
181
+
182
+ - Added the 3D Level Editor, in debug builds only: press 0 on the debug overlay in a game that loaded a 3D level to pause it and place, move, rotate and scale its objects with handles, grid and ground snapping, undo, autosave, Save back to the level's JSON file and Reset to file
183
+ - 3D levels: `level3DAddType`, `level3DAddMesh` and `level3DLoad` make a level's objects from plain JSON, with Box, Sphere, Cylinder and Light built in
184
+ - Added a free camera, in debug builds only: press C on the debug overlay to fly around the running game while it reads no keyboard or mouse (`inputCapture`)
185
+ - 3D materials: `normalMap` and `normalScale` bend the surface with no tangents needed, `normalMapFromHeight` makes a normal map in code, `shininess` sets the highlight's size, `reflectivity` reflects the sky with a Fresnel edge, and `emissiveMap` with `emissiveMapColor` makes parts of a surface glow; glTF models bring their normal and emissive textures
186
+ - Turned boxes collide as turned: a box with a `rotation3D` collides as the box you see, so ramps, tilted platforms and turned walls just work, and the 3D box helpers take an optional rotation
187
+ - Standing in 3D: resting on another object sets `groundObject`, and `groundAngle` (45 degrees by default) is the steepest slope an object stands on without sliding
188
+ - The 2D physics settings work in 3D: `damping`, `angleDamping`, `friction` on the ground (a moving platform carries what rides it) and `clampSpeed`
189
+ - Added `render3D.depthTexture`: the post process shader gets the 3D depth as `iChannel2` and reads it with `sceneDepth(uv)`, for ambient occlusion, fog and outlines
190
+ - `Light3D` has a soft hazy `glow`, with `glowFalloff` for how fast it fades
191
+ - 3D particles have the 2D emitter's callbacks, `particleCreateCallback`, `particleUpdateCallback`, `particleCollideCallback` and `particleDestroyCallback`, and `collideLevel` to bounce off height maps and voxel maps
192
+ - Added a loading screen: after the splash, startup waits for the images, `gameInit` and everything loaded while it runs, and shows a loading bar if that takes more than half a second; `setLoadingScreen` draws your own, and `engineAddLoad` adds anything else you load
193
+ - Added the Scene plugin: `setScene` and `getScene` switch between scenes with enter, leave, update and render hooks, clearing all but persistent objects
194
+ - Added `setEngineVariableStep`: one update per display frame with `timeDelta` the frame's time, and frame times are smoothed to whole display frames in both modes
195
+ - `SpriteAnimation.play(onEnd)` calls back when a play ends, and `SpriteAnimator` switches a character's clips by name
196
+ - A mesh with `dynamicDraw` uploads faster, and `levelEditor.paletteTiles` picks the tiles the 2D level editor's palette shows
197
+ - Size: the full build is about 107 KB gzipped, up from 100 KB; a bundler like Vite leaves out the plugins you don't use
198
+ - Fixes: three external review passes and their fixes, and the test suite grew from 1313 to 1562 tests
199
+
200
+ ### Upgrade Notes
201
+
202
+ - `clampSpeed` now only holds an object to `objectMaxSpeed` (1 unit a frame per axis) while it collides, with solids, or with tiles or the level while it has a mass, in 2D and 3D; something that does not collide, like a bullet you move yourself, now moves at its full speed instead of being slowed
203
+ - In 3D, colliding objects are now held to `objectMaxSpeed`; set `clampSpeed = false` on fast colliding things, as in 2D
204
+ - In 3D, an object standing on something now slows by `friction`, 0.8 by default; set `friction = 1` for none
205
+ - In 3D, `damping` now slows objects with no mass too, and `angleDamping` slows `angleVelocity3D`; both are 1 by default, so nothing changes unless you set them
206
+ - A turned 3D solid now collides as turned, so a spinning solid sweeps what it touches; sprites still collide upright
207
+ - `engineObjectsCollect3D` finds a turned object by its turned box
208
+ - The game loop now starts once `gameInit` and everything loaded while it ran are done, sounds from files included; call `setLoadingScreen()` to turn the loading screen off
209
+ - These names changed in 1.20 and the old ones still work until 1.22: `collideTiles` is now `collideLevel`, and `Box2dWeldJoint.setSpringDampingRatio` is now `setDampingRatio`
210
+
211
+ ## 1.20.0 - 2026-09-28
212
+
213
+ ### New Demos
214
+
215
+ - [3D Voxels](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Voxels) - Walk, jump, dig and build in a little Minecraft style world
216
+ - [3D Mesh Operations](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Mesh%20Operations) - Bevels, CSG cuts, mirror and spin
217
+ - [3D Sync 2D](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Sync%202D) - A 2D platformer with 2D physics and tile collision, drawn in 3D
218
+ - [3D Mesh](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Mesh) - Load an OBJ or glTF model, or drop one in
219
+ - [Level Editor](https://killedbyapixel.github.io/LittleJS/examples/?example=Level%20Editor) - Paint a level and place objects, then play it
220
+ - [Platformer](https://killedbyapixel.github.io/LittleJS/examples/platformer/) - Press Esc then 0 to open the level editor on a real game
221
+ - [Light Shadows](https://killedbyapixel.github.io/LittleJS/examples/?example=Light%20Shadows) - Lights blocked by walls and tinted by glass
222
+ - [Particle Designer](https://killedbyapixel.github.io/LittleJS/examples/particles/) - Reworked, with an effect library, presets and code export
223
+ - [Tweakables](https://killedbyapixel.github.io/LittleJS/examples/?example=Tweakables) - Change values live from a debug panel
224
+ - [UI Tile Slice](https://killedbyapixel.github.io/LittleJS/examples/?example=UI%20Tile%20Slice) - UI styled with nine-slice and tile art
225
+
226
+ ### New Changes
227
+
228
+ - Added the Level Editor, in debug builds only: press 0 on the debug overlay to pause the game and paint its Tiled tile layers, with stamps, fill, selections, undo and redo, then Escape to play and edit again
229
+ - The level editor places objects too: `objectLayersAddType` names your object classes, `objectLayersLoad` makes them from a Tiled object layer, and their properties are edited in the panel
230
+ - It saves straight back to the level's Tiled JSON file where the browser allows it (Chrome and Edge), autosaves every change, and has `levelEditor` hooks for restart, play from the mouse, resizing and your own tile rules
231
+ - Added the Tweakables plugin: `tweak()` puts any value on a debug panel (press 9) with sliders, checkboxes, colors and buttons
232
+ - Added `VoxelMap`, a grid of blocks drawn in chunks with hidden faces left out, per face tiles, see-through and blending blocks, corner shading, collision and a grid raycast for digging and building
233
+ - Level collision in 3D: objects with `collideLevel` land on and are stopped by height maps and voxel maps, `groundObject` says what they stand on, and `FirstPersonCamera3D` can jump (`jumpSpeed`) and set its `eyeHeight`
234
+ - `HeightMap` is now an object that draws itself, with world space lookups wherever it is placed
235
+ - Mesh operations: bevels and chamfers on the box, cylinder and cone builders, `mirror` and `spin`, and CSG `union`, `subtract` and `intersect`
236
+ - Added the glTF plugin: `loadGLTF` and `parseGLTF` load .gltf and .glb models with textures, node animations, WebP images and glass
237
+ - `InstancedMesh3D` keeps a set of instances on the GPU and draws them as one call, meshes upload as indexed triangle lists, and particles and objects allocate nothing per frame
238
+ - 3D lighting: the sky lights the scene from above and below, and `Light3D` point lights make specular highlights
239
+ - `sync2D` 3D objects start at their 3D position, so a 2D game with 3D looks just works
240
+ - Light System: lights are blocked by shadow casters, colored glass tints what passes through, and `emissive` objects glow in the dark
241
+ - Added `drawScreenSpace`, a setting that makes the draw functions default to screen space, for HUDs or a 3D game's 2D overlay
242
+ - `TileSlice` draws a tile as a nine-slice, three-slice or plain box, and the UI system can style its widgets with tile art
243
+ - Tiled maps keep their flipped and turned tiles, and the debug overlay's new Debug Tiles view (key 8) shows each tile layer's bounds and collision
244
+ - The particle designer was rebuilt with an effect library, presets, grouped settings and code export, and `particleUpdateCallback` runs for each particle
245
+ - The Newgrounds plugin was rewritten: medals unlock on the server, leaderboards work for guests too, and it uses the browser's WebCrypto with no dependencies
246
+ - The example tile sheets now have a 1 pixel border around each tile, with `setTileDefaultPadding(1)`, and the starter builds its level from a string you can edit
247
+ - Release builds no longer evaluate assert arguments, and `RandomGenerator` gives unrelated values for nearby seeds
248
+ - Size: the core engine is about 36 KB gzipped and every build includes the plugins; a bundler like Vite leaves out the ones you don't use, so a small 2D game is about 26 KB and a lit 3D scene about 47 KB
249
+ - Fixes: fifteen review passes fixed hundreds of bugs across the engine and plugins, the engine and plugins type check clean, and the test suite grew from 570 to 1313 tests
250
+
251
+ ### Upgrade Notes
252
+
253
+ - These names changed in 1.20 and the old ones still work until 1.22:
254
+ - `collideTiles` is now `collideLevel`
255
+ - `Box2dWeldJoint.setSpringDampingRatio` and `getSpringDampingRatio` are now `setDampingRatio` and `getDampingRatio`
256
+ - `NewgroundsPlugin.logView()` does nothing, since the view is logged on start
257
+ - `drawNineSliceScreen` and `drawThreeSliceScreen` take a color after the start tile, before the border size; a number there still reads the old order
258
+ - `setCollision()` now turns on level collision for 3D objects
259
+ - A `HeightMap` draws itself, so remove any separate object you made to draw its mesh, and `terrain.size` is now `terrain.mapSize`
260
+ - A flat `buildGrid` is flat shaded unless you pass `smooth`
261
+ - The example tile sheets changed layout; if you copied `tiles.png` from an example, use it with `setTileDefaultPadding(1)`
package/COPYRIGHT.txt CHANGED
@@ -36,30 +36,3 @@ appreciated but is not required.
36
36
  2. Altered source versions must be plainly marked as such, and must not be
37
37
  misrepresented as being the original software.
38
38
  3. This notice may not be removed or altered from any source distribution.
39
-
40
- -------------------------------------------------------------------------------
41
-
42
- ZzFXM License
43
-
44
- The ZzFXM plugin (plugins/zzfxm.js) is a port of ZzFXM, the Zuper Zmall Zound Zynth music player.
45
- https://github.com/keithclark/ZzFXM
46
-
47
- Copyright (c) 2020 Keith Clark, Frank Force
48
-
49
- Permission is hereby granted, free of charge, to any person obtaining a copy
50
- of this software and associated documentation files (the "Software"), to deal
51
- in the Software without restriction, including without limitation the rights
52
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
53
- copies of the Software, and to permit persons to whom the Software is
54
- furnished to do so, subject to the following conditions:
55
-
56
- The above copyright notice and this permission notice shall be included in all
57
- copies or substantial portions of the Software.
58
-
59
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
60
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
61
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
62
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
63
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
64
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
65
- SOFTWARE.
package/FAQ.md CHANGED
@@ -261,7 +261,6 @@ Plugins are self-contained features that live alongside the engine but aren't pa
261
261
  | `tweakables.js` | A debug panel to change values live while the game runs, press 9 with the debug overlay open |
262
262
  | `medalSystem.js` | Achievement / medal tracking with popup notifications |
263
263
  | `newgrounds.js` | Newgrounds.io integration (medals held on the server, scoreboards) |
264
- | `zzfxm.js` | Procedural chiptune music via the `ZzFXMusic` class |
265
264
  | `audioEffects.js` | Web Audio effects like filter, reverb, delay, distortion and compressor, for a group of sounds or everything |
266
265
  | `drawUtilities.js` | Higher-level drawing helpers like nine-slice and three-slice |
267
266
 
@@ -365,7 +364,7 @@ LittleJS has a dedicated [js13k branch](https://github.com/KilledByAPixel/Little
365
364
 
366
365
  - **Use Canvas2D instead of WebGL**: call `setGLEnable(false)` before `engineInit`. Stripping the WebGL renderer saves a significant chunk of bytes, and for most pixel-art and low-sprite-count games the visual difference is imperceptible. A nice side effect: once the jam is over, you can flip WebGL back on with a single setting change for a big performance boost when publishing the game elsewhere.
367
366
  - **Drop unused plugins**: every plugin is self-contained, so only include what you actually use. Skip `uiSystem.js`, `box2d.js`, `pathFinder.js`, etc. unless you need them.
368
- - **Lean on built-ins to avoid asset files**: `Sound` with ZzFX parameters generates sound effects from a tiny array, `ZzFXMusic` makes procedural chiptunes, and built-in shape drawing avoids shipping image assets.
367
+ - **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.
369
368
  - **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.
370
369
 
371
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.
@@ -538,19 +537,15 @@ sound_click.play(pos, volume, pitch); // play a sound
538
537
 
539
538
  ### How do I play music?
540
539
 
541
- For procedural chiptune music, use the `ZzFXMusic` class from the [ZzFXM plugin](plugins/zzfxm.js). It extends `Sound` and accepts a ZzFXM-format song array — the music is generated on the fly so it adds essentially no bytes to your build. For longer scored music, load an mp3 or ogg file with the regular `Sound` class and play it with `playMusic`, which loops by default.
540
+ Load an mp3 or ogg file with the regular `Sound` class and play it with `playMusic`, which loops by default.
542
541
 
543
542
  ```javascript
544
- // procedural ZzFXM music (tiny, generated at runtime)
545
- const song = new ZzFXMusic(zzfxmSongData);
546
- const songInstance = song.playMusic();
547
-
548
- // or load an mp3/ogg and loop it
543
+ // load an mp3/ogg and loop it
549
544
  const track = new Sound('music.mp3');
550
545
  const trackInstance = track.playMusic(1, true); // volume, loop
551
546
  ```
552
547
 
553
- Both pause automatically when the tab loses focus (audio context suspends) and resume when it comes back. `playMusic` returns a `SoundInstance`; keep it and call `songInstance.stop()` to halt playback.
548
+ Music pauses automatically when the tab loses focus (audio context suspends) and resumes when it comes back. `playMusic` returns a `SoundInstance`; keep it and call `trackInstance.stop()` to halt playback.
554
549
 
555
550
  ### Why doesn't my audio play until the user clicks something?
556
551
 
package/README.md CHANGED
@@ -25,7 +25,7 @@ The code is very clean and well documented with many examples to get you started
25
25
 
26
26
  <div align='center' markdown='1'>
27
27
 
28
- ## [Demos](https://killedbyapixel.github.io/LittleJS/examples) | [Arcade](https://killedbyapixel.github.io/LittleJSArcade) | [Docs](https://killedbyapixel.github.io/LittleJS/docs) | [FAQ](https://github.com/KilledByAPixel/LittleJS/blob/main/FAQ.md) | [Trailer](https://youtu.be/chuBzGjv7Ms) | [Discord](https://discord.gg/zb7hcGkyZe) | [AI](https://github.com/KilledByAPixel/LittleJS-AI)
28
+ ## [Demos](https://killedbyapixel.github.io/LittleJS/examples) | [Arcade](https://killedbyapixel.github.io/LittleJSArcade) | [Docs](https://killedbyapixel.github.io/LittleJS/docs) | [Reference](https://github.com/KilledByAPixel/LittleJS/blob/main/REFERENCE.md) | [FAQ](https://github.com/KilledByAPixel/LittleJS/blob/main/FAQ.md) | [Trailer](https://youtu.be/chuBzGjv7Ms) | [Discord](https://discord.gg/zb7hcGkyZe) | [AI](https://github.com/KilledByAPixel/LittleJS-AI)
29
29
 
30
30
  </div>
31
31
 
@@ -105,7 +105,7 @@ The code is very clean and well documented with many examples to get you started
105
105
 
106
106
  ## How To Use LittleJS
107
107
 
108
- To get started download the latest LittleJS package from GitHub or install via npm:
108
+ To get started download the latest release from GitHub, the engine's builds and source as npm has them (the examples are in the repository), or install via npm:
109
109
 
110
110
  ```
111
111
  npm install littlejsengine
@@ -140,9 +140,10 @@ engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost);
140
140
  - [Making Awesome Games With LittleJS](https://youtu.be/_dXKU0WgAj8) - A short talk about LittleJS with some tips on how to use it
141
141
  - [Tutorial: Breakout](https://github.com/KilledByAPixel/LittleJS/tree/main/examples/breakoutTutorial) - Learn how to make a simple game from scratch
142
142
  - [Tutorial: Make a ski game](https://eoinmcgrath.com/little-ski/tutorial.html) - A tutorial by eoinmcg that shows how to make a pixel art style game
143
- - [LittleJS Quick Reference Sheet](https://github.com/KilledByAPixel/LittleJS/blob/main/REFERENCE.md) - A reference sheet to help you get started
143
+ - [LittleJS Quick Reference Sheet](https://github.com/KilledByAPixel/LittleJS/blob/main/REFERENCE.md) - The whole API in one file, made to be read by people and by AI coding tools
144
144
  - [Making Your Own Level Editor](https://github.com/KilledByAPixel/LittleJS/blob/main/EDITOR.md) - How to turn the built in 2D and 3D level editors into an editor for your own game
145
145
  - [LittleJS FAQ](https://github.com/KilledByAPixel/LittleJS/blob/main/FAQ.md) - Answers to common questions about LittleJS
146
+ - [Changelog](https://github.com/KilledByAPixel/LittleJS/blob/main/CHANGELOG.md) - What changed in each release
146
147
  - [JS13k Branch](https://github.com/KilledByAPixel/LittleJS/tree/js13k) - A special branch for size coding events that builds to a 7KB zip
147
148
 
148
149
  ## Examples
package/REFERENCE.md CHANGED
@@ -403,7 +403,6 @@ glDraw(x, y, sizeX, sizeY, angle=0, uv0X, uv0Y, uv1X, uv1Y, rgba=-1, rgbaAdditiv
403
403
  - Ability to play mp3, ogg, and wave files
404
404
  - Route sounds or everything through effects with the audio effects plugin
405
405
  - [ZzFX Sound Effect Generator](https://killedbyapixel.github.io/ZzFX)
406
- - [ZzFXM Music System](https://keithclark.github.io/ZzFXM)
407
406
 
408
407
  ```javascript
409
408
  // Sound Object
@@ -435,10 +434,6 @@ SoundInstance.getDuration() // Length of the sound, the same at any rate;
435
434
  SoundInstance.getSource() // Get AudioBufferSourceNode
436
435
  SoundInstance.onendedCallback // Called when it plays to its end, not on stop or pause; set it any time
437
436
 
438
- // ZzFXM - Tiny music playing system
439
- ZzFXMusic(zzfxMusic) // Create a zzfx music object
440
- ZzFXMusic.playMusic(volume=1, loop=true, paused=false) // Play the music, it is a Sound so play and playLoop work too
441
-
442
437
  // Audio functions
443
438
  speak(text, volume=1, rate=1, pitch=1, language='') // Speak text line
444
439
  speakStop() // Stop all queued speech
@@ -722,10 +717,20 @@ tileCollisionRaycast(posStart, posEnd, object, normal, solidOnly=true) // Where
722
717
  // or undefined; a normal vec2 passed in is set to the surface's
723
718
  tileCollisionLayers // List of all tile collision layers
724
719
  tileLayersLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisionLayer, draw=true) // collisionLayer is the index
725
- // of the layer that gets collision, no tile when no image is loaded
720
+ // or the name of the layer that gets collision, no tile when no
721
+ // image is loaded
726
722
  // Load tile layers from exported data, Tiled flips and turns included;
727
723
  // groups are flattened and layer indices count that flat list,
728
- // hidden layers load with collision but are not drawn
724
+ // hidden layers load with collision but are not drawn; a
725
+ // tileset in the map with a margin or spacing is read where
726
+ // its tiles are
727
+ tileLayersFromLDtk(ldtk, level=0) // A Tiled map of an LDtk level, by index or identifier, to give
728
+ // tileLayersLoad and objectLayersLoad: its layers bottom first, an
729
+ // IntGrid layer a hidden layer of its values under its name, for
730
+ // collisionLayer, its rule tiles over it as name tiles, tiles
731
+ // stacked in a cell in layers above, named (2), (3), and a
732
+ // see-through tile in a layer of its opacity; its entities
733
+ // objects with their fields as properties
729
734
  objectLayersAddType(name, make, defaults={}, tileInfo) // Name a type of object in a Tiled map: a class made
730
735
  // with new make(pos), or an arrow function called make(pos),
731
736
  // defaults set on what it made; tileInfo is an editor icon
@@ -1263,8 +1268,9 @@ render3D.screenToRay(screenPos, canvasSize) // Ray3D under a screen point, alwa
1263
1268
  // date for it, so worldToScreen keeps agreeing with them
1264
1269
  render3D.screenToGround(screenPos, groundHeight=0, canvasSize) // where that ray meets a flat ground plane, or
1265
1270
  // undefined; terrain has HeightMap.raycast
1266
- render3D.pick(screenPos or ray, objects) // {object, distance} of the nearest object hit, the box of its mesh
1267
- // or a sprite's size3D; a screen position goes through screenToRay
1271
+ render3D.pick(screenPos or ray, objects) // {object, distance} of the nearest object hit, on its mesh's
1272
+ // triangles, the faces that show, both sides when doubleSided,
1273
+ // or a sprite's quad; a screen position goes through screenToRay
1268
1274
  render3D.soundDefaultRange = 100 // how far a sound with no range of its own is heard in 3D, the 2D
1269
1275
  // soundDefaultRange is 40; a Sound made with a range keeps it
1270
1276
  render3D.playSound(sound, pos3D, volume, pitch, randomnessScale, loop, paused) // like sound.play(pos): quieter with
@@ -1744,14 +1750,22 @@ new LensFlare3D(size=1, count=7, intensity=1, saturation=1, color) // the sun's
1744
1750
  // screen; it fades as the sun leaves the screen or goes behind something
1745
1751
  flare.flareSize = 1.5 // scales every part; count is how many ghosts, intensity how bright, saturation
1746
1752
  // how colorful, 0 all its own color; seed picks another arrangement
1747
- flare.elements = [{at: .5, size: .1, color: hsl(.6,1,.6,.3), shape: 'disc'}] // or parts of your own: at 0 the sun,
1748
- // 1 the middle, 2 as far past it; size a part of the screen's height; shape
1749
- // glow, disc or ring
1753
+ flare.shapes = ['hex', 'streak'] // what the ghosts are picked from: glow, disc, ring, hex, streak or star; glowSize
1754
+ // scales the glow at the sun, 0 for none, and ghostSize the ghosts
1755
+ flare.elements = [{at: .5, size: .1, color: hsl(.6,1,.6,.3), shape: 'disc'}] // or parts of your own, each a
1756
+ // LensFlareElement: at 0 the sun, 1 the middle, 2 as far past it; size a part of
1757
+ // the screen's height, or a vec2 for a wide one; shape one of the six, or
1758
+ // tileInfo for a tile of your own; angle turns it
1750
1759
  flare.visible // how much of the sun shows, 0 to 1, eased over fadeTime, to read; what is not
1751
1760
  // see through hides it, flare.occlusion = false turns that off
1752
- flare.light = lamp // the flare of a Light3D in place of the sun's: at the light, in its color,
1753
- // smaller from farther than its radius, hidden by what is in front of it; a
1754
- // spotlight's shows from inside its beam only
1761
+ light.addFlare(size, count, intensity, saturation, color) // gives a Light3D a flare of its own and returns it: at the
1762
+ // light, in its color, smaller from farther than its radius, hidden by what is
1763
+ // in front of it, a spotlight's only from inside its beam
1764
+ light.flare // the light's LensFlare3D, its child, or undefined; set one of your own, and
1765
+ // destroy it to take it away; it goes with the light; a level's Light has a
1766
+ // lensFlare property
1767
+ flare.light = lamp // the same by hand, a flare made on its own and pointed at a light; it goes when
1768
+ // the light does; a DirectionalLight3D's flare is far away, where it shines from
1755
1769
  // Trails - a ribbon through where the object has been, parent it to something that moves
1756
1770
  new Trail3D(pos3D, lifeTime, width, tileInfo, color, colorEnd, additive) // thins and fades from head to tail over
1757
1771
  // lifeTime seconds; Infinity keeps every
@@ -1856,7 +1870,8 @@ level3DVoxelSetup(tileInfo, (map)=> {}) // The sheet a level's block m
1856
1870
  "sunDirection": [0.5, 1, 0.3], "sunColor": "#ffffff",
1857
1871
  "fog": [25, 70], "fogColor": "#d6ecff", // start and end, an end of 0 for none; the horizon color
1858
1872
  // when the level has a sky and no fogColor
1859
- "shadows": true},
1873
+ "shadows": true,
1874
+ "lensFlare": true}, // the sun's lens flare, a LensFlare3D made for it
1860
1875
  "objects": []}
1861
1876
 
1862
1877
  // A level can hold a map of blocks, made a VoxelMap when it loads: its corner, its size in cells, and its blocks
@@ -1893,14 +1908,15 @@ prefab.originOffset // from the prefab's origin to
1893
1908
  // Built-in types and their properties
1894
1909
  Box, Sphere, Cylinder // color, tile (-1 for none), solid (true); 1 unit across, the scale is the size
1895
1910
  Light // color, radius (5), intensity (1); cone (0), degrees from its forward to the edge of
1896
- // its beam, makes it a spotlight aimed by its rotation, softness (.2), shadows (false)
1911
+ // its beam, makes it a spotlight aimed by its rotation, softness (.2), shadows (false);
1912
+ // lensFlare (false) gives it a lens flare
1897
1913
  ```
1898
1914
 
1899
1915
  ### 3D level editor
1900
1916
  Debug builds only. `0` on the debug overlay opens it for a level loaded with `level3DLoad`, the game pauses under it.
1901
1917
  To make it your own game's editor, with your own types, keys and panel buttons, see [EDITOR.md](EDITOR.md).
1902
1918
  The panel's Scene box edits the level's scene block: "Level sets the scene" starts one from what is on screen, and
1903
- off leaves the sky, sun, fog and shadows to the game.
1919
+ off leaves the sky, sun, fog, shadows and lens flare to the game.
1904
1920
 
1905
1921
  ```javascript
1906
1922
  // Tools, the keys Unity, Unreal and Godot use