Skip to content

About

a library to create 2.5d realtime graphics and pixelart with three.js

Topics

Resources

Stars

26 stars

Watchers

1 watching

Forks

Latest commit

 

History

1,584 Commits

Folders and files

Repository files navigation


A javascript side project about rendering 2.5D realtime graphics on the web.

ultra fast rendering of 2D sprites in 3D space • billboards • texture atlas • frame-based animations • parallax • tiled 2D maps • pixelart

npm (scoped) continuous integration status License

twopoint5d cover

Introduction

It all started with the desire to render 2d sprites (lots of them!) in the browser. it has been a long way, starting with a naive html-canvas-based solution. the second iteration used a custom webgl renderer, which turned out to be quite complex in the long run. today, in its current form, the library uses three.js as the rendering layer.

A declarative description (called a "vertex object description") is used to describe the sprite properties (how many vertices, indices, texture coords, etc.).

Using the vertex object description, the library can create javascript objects that provide getters and setters for the respective sprite properties. the actual data ends up in internal buffers that three.js renders efficiently in batches, usually via instanced rendering — through its WebGPURenderer, which falls back to WebGL 2 where WebGPU is missing.

While the developer can use the "sprites" / vertex objects comfortably and conveniently via javascript objects, the "backend" of the library ensures that the GPU can render the current sprite pool with high performance with a single draw call. the cumbersome handling of GPU buffers and state setup becomes transparent for the developer.

Whether a "sprite" is a classic quad with a texture or a freeform polygon with special properties read by a custom material is completely up to the creator of the vertex object description and of the material that uses those properties — a three.js NodeMaterial whose shader is written in TSL (three/tsl).

🚀 In other words, this library wants to empower the developer's creativity by allowing him to quickly and easily create his own sprites, particles or whatever using instanced rendering and his own custom shaders, without having to study the documentation every time to understand the boring details of WebGPU and WebGL.

Of course, this library offers several ready-to-use sprite shaders (better known as Mesh in three.js) based on this. the developer can just use them and doesn't have to worry about how.

There are sprite shaders that render textured quads as billboards or on a plane in the 3d space. there is also a sprite shader that uses animated textures (using frame-based animations). and there are other highly specialized sprite shaders that are used for rendering tiled 2d maps, among other things.

Obviously, textures can be loaded from texture atlases or tilesets.

‼️ However, the developer should not expect an all-encompassing sprite engine, that is not the intention of this library, it rather wants to reduce and speed up the developer's workload to do what he wants to do (but without hiding the rendering API three.js).

There are a few more features that this library offers to make the life of a creative web developer easier, but not to take all the fun out of discovering them, let's just mention them here 😉

What's in this repository 👀

twopoint5d is a monorepo that contains the following javascript / typescript libraries:

Usage

npm install @spearwolf/twopoint5d three @spearwolf/eventize @spearwolf/signalize

three, @spearwolf/eventize and @spearwolf/signalize are peer dependencies: the application installs them next to the library. three has to lie in the peer range of the installed release, which npm view @spearwolf/twopoint5d peerDependencies prints — the library follows the 0.x minors of three.js one at a time, and a three outside that range is a peer conflict. A TypeScript project adds @types/three from the same range as a development dependency; it is the one optional peer.

The library renders through the WebGPURenderer of three.js, which falls back to WebGL 2 where the browser has no WebGPU; a WebGLRenderer is not supported. Import three.js from three/webgpu and its shader nodes (TSL) from three/tsl, as the library itself does.

One textured sprite, drawn by a Display with a scene and a camera of its own:

import {Display, FeatureSprites, TextureFactory, TexturedSpriteKind} from '@spearwolf/twopoint5d';
import {PerspectiveCamera, Scene} from 'three/webgpu';

// the display owns the renderer and drives the frame loop
const display = new Display(document.getElementById('canvas')!);

const scene = new Scene();
const camera = new PerspectiveCamera(60);

display.onResize(({width, height}) => {
  camera.aspect = width / height;
  // the field of view is vertical: a window taller than wide moves the camera back, so
  // the sprite fits across as well
  camera.position.z = 400 / Math.min(1, camera.aspect);
  camera.updateProjectionMatrix();
});

display.onInit(async ({renderer}) => {
  const texture = await new TextureFactory(renderer).loadAsync('sprite.png');

  // a mesh with room for one sprite, drawn with the texture
  const sprites = new FeatureSprites(TexturedSpriteKind, {capacity: 1, textures: {colorMap: texture}});

  const sprite = sprites.createSprite()!;
  sprite.setSize(256, 256);
  // s, t, u, v: the whole image
  sprite.setTexCoords(0, 0, 1, 1);

  // upload what the sprite wrote into the buffers of the mesh
  sprites.update();
  scene.add(sprites);
});

display.onRenderFrame(({renderer}) => renderer.render(scene, camera));

await display.start();

#canvas is a <canvas> on the page, or an element the display puts a canvas into. The same sprite, with a frame of a texture atlas in place of the whole image, is the first demo of the lookbook — its source; in a clone of this repository, pnpm lookbook serves it at http://localhost:4321/lookbook/demos/first-sprite. TexturedSpriteKind is one of the sprite presets; Sprites shows how to compose a kind of your own from features. From there:

📖 Documentation

Some features have been around for a long time and are stable, others are in flux and highly experimental. as an independent solo developer, it is not possible for me to create detailed written documentation and keep it up to date. this is a living open source project and is subject to constant change. therefore, the developer is advised to do the following

"Read the source, Luke!"

To take this to the extreme, there is a LOOKBOOK app with lots of code examples, all of which can be used as a starting point for new projects or as documentation for one or the other feature.

🚀 The LOOKBOOK app can easily be started locally using pnpm lookbook. See next section Development Setup for details.

And of course there are one or two READMEs in the **/src/* subdirectories that provide a high-level overview of the features. Enjoy exploring!

Development Setup

This repository is structured as a monorepo; based on nx !

1. Install dependencies

First, you need node ^24.16.0 || >=26.3.0 — a 24.16 or newer, or a 26.3 or newer; the 25.x line is out — and pnpm >=10.22.0, both ranges as engines in the root package.json states them. An .nvmrc and a mise.toml are checked in, both naming 24, so nvm install, fnm use --install-if-missing or mise install fetches the newest 24.x for you. Install the dependencies with:

$ pnpm install

The browser tests in pnpm cbt need Chromium and Firefox from Playwright. pnpm install does not download them, so fetch them once, and again after every Playwright bump (on Linux, add --with-deps if system libraries are missing):

$ pnpm exec playwright install chromium firefox

2. Build and test everything

# clean, lint, build, type-check, check the package types and that every published
# type can be named, lint the manifest, then the script tests, the Vitest suite with
# coverage, the allocation specs and the browser tests
$ pnpm cbt

3. Run the local LOOKBOOK app

$ pnpm lookbook

Getting involved

Everyone is welcome to contribute to this project, no matter if it's just bug-fixes, new features, ideas or documentation or graphics!

Copyright and License

Copyright © 2021-2026 by Wolfger Schramm.

The source code is licensed under the Apache-2.0 License.

About

a library to create 2.5d realtime graphics and pixelart with three.js

Topics

Resources

Stars

26 stars

Watchers

1 watching

Forks

Used by

Contributors

Languages