## KilledByAPixel/LittleJS — v1.24.0…v1.24.2

_40 commits._

### Features
- **1.24.1: the fixes of the 2026-10-02 reviews, LDtk collision by an IntGrid layer's name, doubleSided voxel blocks and water to swim under, and the example browser's new look; dist built for it** (7eb6e3c)
- **Changelog: 1.24.0 was published from af607777, so the example browser's new look and the palette and LDtk opacity fixes after it are in Unreleased, with the voxel water change** (66d5dde)
- **1.24.0, review 2026-10-02 pass 3 update: the level editor's palette of a sheet with a spacing stops at its last row instead of asserting past it; a see-through LDtk tile keeps its opacity, in a layer of its own; the example browser's new look in the notes; dist, docs and zip built again** (c82f972)
- **Example browser: no white flash while an example loads. The page is dark and a frame's own page is not, and Chrome paints a frame whose color scheme differs from its page's on opaque white; the frame now has the light scheme of its content, so the black of its container shows until the example draws, as before the new look** (0b4f361)
- **Example browser, a new look and easier use: the docs site's dark palette with a slim top bar in place of the title, the demo at 16:9 sized by the stylesheet, the example list as rows under sticky headings in place of the select, and a handle between the code and its write-up that drags to give one the other's space, by mouse, touch and the arrow keys, kept across reloads as a share of the editor's height, a double click putting the quarter back; on a narrow screen the columns stack by CSS alone, the example's name between Prev and Next opens a full screen picker with the search, and a pick or Done closes it; the Screenshot button and the GitHub corner are gone, a GitHub link in the bar in their place** (62675da)

### Fixes
- **npm audit fix: patch releases of minimatch, brace-expansion, markdown-it and @xmldom/xmldom in the dev tools; the 7 warnings left are Electron's, which needs a major version** (c89e890)

### Backend
- **1.24.2: the 2026-10-03 review fixes, tile sets from separate images, spotlight gels, faster smooth normals, loaders packing an image once, a release loop that goes on past an error and medals that keep every unlock; dist built for it** (0588a1f)
- **Tiled properties named as methods left out; release loop goes on past an error; loadSprite, loadTiles and loadAtlas packed once per image and settings; noise2D rows exact far out in y; FAQ browser line; package-lock.json committed and CI on npm ci; CodeMirror and three.js pinned by integrity hash** (85a2c69)
- **Mesh.computeNormals smooth in numbers: points grouped by place with a number checked against the place in place of a text key, the sums in typed arrays, no vector for a triangle or a corner; the same normals to the last bit, 5 to 7 times faster** (27731a9)
- **Medals keep the saved unlock of a medal not made this time, and one made after medalsInit reads its unlock, so a medal made late or behind a flag is never lost; medalsReset locks those too** (32e211e)
- **Review 2026-10-03 pass 7: raycastSphere in numbers and the pick's sphere test from the matrix into a kept vector, so a 3D pick makes no vectors for an object it misses** (af2a15f)
- **Review 2026-10-03 pass 7, low items: parseOBJ comments, CR line ends and continued lines; empty LDtk tile layers kept; editor property place and type kept, an undone made object layer left out of a save, unused layer ids; removed prefabs leave the game; 3D level parts saved in one order; writeSaveData checks its data and returns success; atlas duplicate names warned; nearestPowerOfTwo never below its value; effect names trimmed after the cut; doc examples that redeclared a const** (45696c0)
- **Review 2026-10-03 pass 7, allocations: objects sorted only when one is out of render order, destroyed ones filtered only when there are some, the collide lists made in one pass; no position copy for an object with mass that collides with nothing; outlines and regular polygons written into kept vectors, and drawPoly and drawLineList take their size as numbers** (a8d8a19)
- **Tests for what a mutation run found unchecked: math and Vector2 corners, lineTest heading left, formatTime, Color, a seeded RandomGenerator sequence, a paused Timer, tween ends, ground friction, landing, elastic and inelastic hits, PathFinder costs, refused diagonals and tie breaks, and the 2D editor's undo cap; each checked to fail on its mutant** (f12928d)
- **Review 2026-10-03 pass 7: editor cut, copy and stamps keep an object's fields, and selection drags and stamps put objects down to the digit; terrain paint rounds no heights; a slider let go as it moves takes the last place; a smaller gamepad in a slot holds none of the last one's buttons, a NaN axis is centered; a text input takes a keydown with no key** (7da663a)
- **Review 2026-10-03 pass 7: a click or tap outside the canvas, in the bars of a letterboxed one, presses nothing, where it pressed the canvas edge; showConfirmDialog while one is open gives the open one in release builds, where a second broke navigation for good** (7f9b00a)
- **iPhone silent switch: by default it mutes the game, as it does a ringtone, and the player's music plays on; soundIgnoreSilentSwitch and setSoundIgnoreSilentSwitch(true) have the game play through it as media** (fd6178d)
- **Review 2026-10-03 local pass 6: a tile layer's raycast is clipped to the layer and a cell around it, so a ray to a far point walks only the layer, and every ray hits as before; debugShowErrors shows its message as text; Canvas tints clamp as WebGL does; glTF file keys normalised, a uri above them refused, an accessor past its buffer refused before allocating; tweakables take no Infinity; the 3D Mesh write-up as the code is** (c51a608)
- **Review 2026-10-03 pass 6: the textures the engine makes itself (normal maps from heights, particle shapes, glows, flares, glTF's white texture, soft dots, plain voxel tiles) are made with no OffscreenCanvas too, through the canvas element fallback; a palette list names only tiles a sheet read by its columns has, and its draw passes by a tile with no info** (951f017)
- **Tests for the editor's tile past the end of a sheet and the flare's four lamps** (f8e7117)
- **Review 2026-10-03 pass 5: the engine starts on browsers with no OffscreenCanvas, Array.prototype.at or Object.hasOwn, as Safari 15 is, and the example browser's markdown has no lookbehind; on an iPhone the silent switch no longer mutes sound where audioSession is; the level editor reads a tile past the end of its sheet as nothing in the brush, ghost and palette, sharing the layer's lookup, and a tile set's palette fills in; the flare looks past four lamps; vector inputs take no Infinity** (fed19e1)
- **glTF drop, review 2026-10-03 pass 5: a .gltf finds its files from its own folder in the drop, a bare name only when one file has it, so another folder's file of the same name is never taken silently; with files only web and blob uris are fetched; an image that can not be read is warned of; the 3D Mesh viewer frees the model it replaces and reads the drop inside its try** (3b7ef84)
- **Reviews of 2026-10-03, third pass updated and fourth: a flare's lamp must also be thin, so a light close behind the wall of a level mesh is hidden; a tile set keeps its tiles on a map with a tileset margin or spacing; a tile past the end of a sheet read by its columns draws nothing, which a hidden LDtk IntGrid layer asserted on in the editor; tileLayersLoad checks every layer before making any; loadTiles packs the whole tiles of an image that is not whole tiles; the editor's palette draws each tile from its own sheet, skips tiles a set has not, writes no tileset for a set, and its number inputs take no Infinity; a gel may be a TileInfo; a tween with no time ends its loops; the Custom Editor's Room tool is on B, R being the editor's** (0fd55cb)
- **glTF dropped with its files: parseGLTF takes a Map of the .bin and image files a .gltf names, by path or name, and looks there before fetching; a file it can not find is named in the error; the 3D Mesh example gathers every file of a drop, a dropped folder's too, so a .gltf loads with its files** (63dcf09)
- **Review 2026-10-03, docs and the example browser: the FAQ's build sizes as measured and its plugin table complete, REFERENCE's setBlockType with doubleSided and debugText's font, the flare's visible doc as the code has it; the arrow keys take the focus with them so Enter keeps the example they went to, and Escape in the search stops there** (80102fb)
- **Review 2026-10-03: a light's lamp is told from a room around it by how near the light the ray meets its surface, so a globe is its own fixture and a small closed room hides it; a doubleSided voxel face's inside is split on the same diagonal as its outside; the changelog's 1.24.1 gets the breaking note for LDtk layer indices** (49b82b6)
- **Review 2026-10-03, loaders against small malformed files: Aseprite tags keep to the frames, a glTF node reached twice and a bufferless accessor of millions are refused, LDtk levels of millions of cells refused and tiles or entities with no place passed by; LDtk IntGrid values kept when its rule tiles are on another tileset; a missing collision layer name is said in release; 3D level colors must be strings and numbers finite** (5fc8aec)
- **Review 2026-10-03: a prefab that holds itself is caught by the prefabs being made, not only by depth, so one holding itself several times no longer makes thousands; tileLayersLoad throws for a map size that is not whole cells or tiles that do not fill it, in any build, and its loops count up** (eea5e63)
- **Tile sets from separate images: loadTiles packs tile images, or several tile sheets, onto the texture sheets as one tile set numbered in the order given, a TileInfo whose tiles list a tile layer, tileLayersLoad and the level editor's palette read tile n from; checked on pixels** (35fa439)
- **Spotlight gels: light.gel is a picture the shadow casting spotlight shines through, cast along its beam in its colors and upright as the light looks out, on a texture unit of its own, white with none so a scene draws pixel for pixel as before; checked on pixels in Chrome and Firefox; the 3D First Person flashlight gets a stained glass gel on G** (0378497)
- **Example browser: a button in the top bar switches between dark and light, the light theme the docs site's own, kept under the name the docs use so one choice holds for both, and set before the page paints; the code editor keeps its own Theme, and the error and console views stay with it** (aa83913)
- **Custom Editor short: a dungeon whose level editor is a class of the game's own, a Room tool laid out by a drag, a Clear button, a key and the torches' reach drawn over the level; listed in EDITOR.md's working examples** (a34f0f4)
- **Housekeeping from review 2026-10-02: the commented source lists of the shorts page and the starter follow the build's files; the changelog has the fixes 1.23.1 left out; the README says what the release zip holds; AGENTS describes the example browser's info box as it is now; addFlare takes the flare's color, and visible's doc says where it turns 0** (a643a15)
- **Site workflow: the right to deploy is the deploy job's alone, the build job that runs npm install reads only** (c897f20)
- **Example browser, review 2026-10-02: Enter on a focused example is its own click, no longer swallowed by the list; headings are not linked from write-ups; saved preferences that are blocked or broken are none, and a share of the info box out of 0 to 1 is not kept; the handle drags with the main button; the editor's change listener is added once, not on every load** (0a61402)
- **A light's flare is hidden by a room or a level mesh around it, only a lamp no wider than half the light's radius is passed by; a VoxelMap block type is doubleSided by its own option, set for water in 3D Voxels, so glass draws from outside only again** (ad771a1)
- **Level editors, review 2026-10-02 second pass: a resized autosave applied over a file that gained an object layer leaves it alone, an autosave whose tiles do not fit its size no longer resizes the map; the 3D editor passes by an autosave with no list of objects, which blocked every edit, and says when it brings back an older one** (9d52fc2)
- **LDtk: an IntGrid layer is always a hidden layer of its values under its own name, so collision is complete whatever its tiles stack or fade, and tileLayersLoad's collisionLayer takes a name that stacked layers can not move; several worlds, no tileset entry, a tileset of another size and a missing level in release are handled; a Tiled margin counts from the game's sheet in an atlas** (62a5414)
- **Box2D addRegularPoly ends with a side count that is not a whole number, as the engine's own polygon loops do; setGLCircleSides asserts at least 3 sides** (70bd944)
- **A VoxelMap's transparent blocks show from both sides, so water's surface shows from under it; the 3D Voxels player goes under water and walks on the bottom instead of floating** (34a5abb)

_Recap by [Repo Wrapped](https://repowrapped.com/gh/KilledByAPixel/LittleJS?utm_source=github-action)._