Tiny fast 2D/3D HTML5 game engine with many features and no dependencies.
LittleJS shipped major performance and correctness work this week. A new collision grid system handles 2D object collisions far faster when scenes have 64 or more solids—benchmarks show roughly 100× speedup on large scenes. Shader code was reorganized to prevent user defines from accidentally…
Get this in your inbox every Monday →A deterministic 0–100 hygiene score — README, license, CI, tests, docs, and freshness.
Who ships this repo — author concentration and the bus factor across the last 300 mainline commits.
How welcoming this repo is to contributors — issue throughput, close time, responsiveness, and good-first-issue count.
What this project is built on — dependency count by ecosystem, the license mix, and anything worth a legal look before you adopt it.
Whether this project's CI can be trusted — pass rate, run times, flaky runs, and which workflow is the weak link.
Grounded in LittleJS's README, structure, and recent commits — answers won't invent code they haven't seen.
A Monday email with what shipped, in plain English — no account needed.
Showing raw commit titles for the newest commits. Sign in to generate AI summaries.
The built in video capture removed: key 8, debugVideoCaptureStart, Stop and IsActive, debugRenderPost, the loop's render after every update while capturing; the FAQ shows recording frame by frame at an exact 60 fps with setEngineManualStep and engineStep, the snippet run in headless Chrome first
Bench: PixiJS and Phaser pinned to 8.22.0 and 3.90.0 with sha384 integrity, as three.js and CodeMirror already were, so a CDN change can not run new code on the site or shift the numbers
Medals unlocked before the first medalsInit are kept and saved by it (a later medalsInit with another save name starts from its own), the debug assert on an early unlock gone; Node 22.12 or later for the package's build and tests, as CI runs
Open lows, the rest: drawTextureWrapped keeps its tinted bake per image (bakeTintedImage into a context of its own) and honors TextureInfo.pixelated; the 2D editor's Save sets the baseline outside the write's catch, retires code made layers' records once gone, and judges a point or rectangle by its top in a shrink; docs for align2D, prefab export, timeScale, the engineStep example, Box2D's unused EngineObject fields and restart determinism
Open lows, plugins: a tween that throws stops no others (its step in tweenStep, the first error rethrown after the walk); parseGLTF takes typed arrays and Node Buffers; glTF accessors off alignment and sparse ones past their buffer named; getRotation from atan2 of the pitch's sine and cosine; getNearestClearNode walks the ring only, in the same order; ParticleEmitter3D's particleCall and particleCollide private; parseAtlas's return typed
Open lows, core: a release and press in one frame keep both, a non-repeat keydown of a held key is not a press; fullscreen's promise caught; Canvas2D honors TextureInfo.pixelated; tile layer shadows from solid cells only; the main canvas's alpha, filter and shadow reset each frame; mainCanvasSize set in place; NaN colors black in release; glDeleteTexture does its own cleanup
2D object collision through a grid once there are 64 solids or more (engineCollideGridMin): a mover gets the solids near it in list order, found again when a push moves it; the grid follows each solid after its physics and the other object after a collision callback; every contact resolves exactly as checking every pair, tests run scenes both ways and compare every value, callbacks that throw the other far away or destroy it included; 2000 movers about 1.3 s to 12 ms a frame in the vm
Examples: the raycaster walks on a phone; raycasting, hill glide, vibrate, nine slice, animation and parallax size from the view; the shorts that need tile padding set it themselves; the module and TypeScript examples match the starter again; htmlMenu finds its elements by id; four 3D shorts share one mesh; the 3D puzzle shows SOLVED once the last block lands; fillStyle written one way
JSDoc polish: first description lines without a closing period where the description ends there or a list follows, the Box2D joint getters and setters and Box2dObject's debug draw say what their values do, and the engine's own fields that reached the d.ts as any typed (render3D.uniforms, VoxelMap.chunksChanged and tiles, GLTFModel.nodeTree, Prefab3D.parts and partObjects, the Newgrounds lists)
Shader code after the engine's main in the 2D Shader, the 3D Shader and the post process, mainImage declared ahead, so a define in a game's code can not rewrite the engine's names (smoke checks with a define of d in 2D and C in 3D, which drew black before); the 3D discard moved to the end of main, after the normal map's derivatives and the emissive sample
A floor, not a guess: counts only commits whose author, co-author trailer, or message explicitly credits an AI tool (Claude, Copilot, Cursor, aider, Codex…). Based on 30 mainline commits. Unattributed AI code isn't counted here — the full audit estimates that separately.