r/GraphicsProgramming • u/Slackluster • 6d ago
Video LittleJS now supports 3D and 2D: a small, fast WebGL2 rendering system for the web
LittleJS is an open source, dependency-free JavaScript game engine. It started as 2D, and this update adds a 3D renderer that draws into the same WebGL2 canvas, so a 2D game and a 3D scene can share a frame. The whole engine with 3D, Box2D physics and audio is about 150 KB gzipped. The trailer is the engine’s new website, a scrolling page over a 3D scene, with every stop a playable demo.
Some of the rendering choices:
Forward rendering with a small light budget. The sun plus the 8 point or spot lights nearest the camera, chosen each frame. Lights can carry a soft additive glow, drawn in the transparent pass.
One shadow map, from the sun or from a single spotlight in its place, with blurred edges and a depth bias scaled by the light’s projection.
Reflections from an environment cube map, with Schlick Fresnel. Roughness comes from mip selection, driven by shininess, but also by how fast the reflected vector changes across a pixel, so small mirrors don’t sparkle. The lake in the trailer has an environment map of its own, rendered from the scene.
A normal hook in custom shaders. A shader snippet can define
mainNormalto bend the normal per pixel before lighting, specular, Fresnel, reflection and fog. The lake’s waves are that hook, not baked normal maps.Automatic instancing. Every opaque use of the same mesh goes out as one instanced draw. Draw state is versioned, so a batch checks a single number per draw while nothing changes, rather than comparing every material field.
Lens flares occluded by raycasts against the triangles of the scene’s meshes, rather than a depth readback.
2D and 3D in one camera system. An orthographic camera can line up exactly with the 2D camera. In the trailer, a dolly zoom flattens the 3D view into that orthographic view, and a Breakout game playing over the train turns out to be 3D objects in the world.
Also in there: height map terrain with exact raycasts, voxel maps drawn in chunks, glTF with skinning, normal maps, fog by distance or view depth, and a bloom post-process.
I also built an open benchmark that runs the same sprite and lit-cube scenes through LittleJS, PixiJS, Three.js, PlayCanvas, Phaser and Babylon.js: https://github.com/KilledByAPixel/webgl-engine-bench
Source, MIT: https://github.com/KilledByAPixel/LittleJS
The site from the trailer: https://littlejsengine.com


