canvas-js-3d
v1.0.1
Published
A lightweight, dependency-free 3D graphics library built on the HTML Canvas API and designed to run in web browsers.
Downloads
927
Maintainers
Readme
canvas-js-3d
canvas-js-3d is a lightweight, dependency-free 3D graphics JavaScript library built on the HTML Canvas API and designed to run in web browsers. It makes it easy to load Wavefront OBJ files and render external 3D models directly to the canvas, without using WebGL, Three.js, or any other third-party libraries. The entire codebase is written in pure, vanilla JavaScript.
Great for learning, 3D web page visuals, small browser games (especially with synthwave/arcade visuals), and experimentation.
Demo
Demo Link: https://sebastianbathrick.github.io/canvas-js-3d/
Features
Rendering
- Wireframe rendering (edges only)
- Flat-shaded face colors (solid objects / non-wireframe)
- Depth sorting (using painter's algorithm)
- Back-face culling
- Edge color gradients
- Bloom
- Distance‑based fog (rendered per-face)
- Background color or vertical gradient
- FPS counter
Scene & Math
- Vector3 + Vector2 math
- Transform with position/rotation/scale
- Scene containing SceneObjects, each with their own mesh, material, & transform
- Camera with adjustable FOV and transform
Assets
- Wavefront OBJ loading (vertices + faces)
- Load from URL, File, file dialog, or raw text
Quick Start
Installation
Install the canvas-js-3d package using the npm package manager. The npm package page is at this link: https://www.npmjs.com/package/canvas-js-3d.
npm install canvas-js-3dindex.html
<!DOCTYPE html>
<html>
<head>
<script type="importmap">
{
"imports": {
"canvas-js-3d": "./node_modules/canvas-js-3d/src/index.js"
}
}
</script>
</head>
<body>
<canvas id="canvas" width="800" height="600"></canvas>
<script type="module" src="app.js"></script>
</body>
</html>app.js
import { Engine, Mesh, SceneObject, Transform, Vector3, Material } from 'canvas-js-3d';
const canvas = document.getElementById('canvas');
const engine = new Engine(canvas);
// Define the geometry of a cube (or load a .obj file via WavefrontMeshConverter)
const vertices = [
new Vector3(-1, -1, -1), // 0: back-bottom-left
new Vector3( 1, -1, -1), // 1: back-bottom-right
new Vector3( 1, 1, -1), // 2: back-top-right
new Vector3(-1, 1, -1), // 3: back-top-left
new Vector3(-1, -1, 1), // 4: front-bottom-left
new Vector3( 1, -1, 1), // 5: front-bottom-right
new Vector3( 1, 1, 1), // 6: front-top-right
new Vector3(-1, 1, 1) // 7: front-top-left
];
const faces = [
[1, 0, 3, 2], // back
[4, 5, 6, 7], // front
[0, 4, 7, 3], // left
[1, 2, 6, 5], // right
[3, 7, 6, 2], // top
[0, 1, 5, 4], // bottom
];
const mesh = new Mesh(vertices, faces);
const cubeSceneObj = new SceneObject(
mesh,
new Transform(
new Vector3(0, 0, 5), // Position
Vector3.zero(), // Rotation (in radians)
Vector3.one() // Scale
),
new Material(
'#ffffff', // Edge color
null, // Optional gradient color (e.g. '#0000ff' for blue)
'#333333' // Optional face color (null for wireframe)
)
);
// Smoothly rotate the cube (gets called each frame)
engine.onFrameUpdate = (deltaTime) => {
// deltaTime = time since last frame
cubeSceneObj.transform.rotate(new Vector3(0, deltaTime, 0));
};
engine.scene.addSceneObject(cubeSceneObj);
engine.start();Run a dev server:
npx http-server -c-1This library uses native ES modules. You must run it from a local server (not file://).
Feature Usage
These snippets assume you already have an Engine, a SceneObject called cubeSceneObj, and a running render loop. They’re meant to be drop-in additions to the minimal setup above.
Depth Sorting (Solid Meshes)
engine.isDepthSorting = true; // Already enabled by defaultBack-Face Culling
engine.camera.isBackFaceCulling = true; // Already enabled by defaultCamera Transform
engine.camera.transform.setPosition(0, 0, -3);
engine.camera.transform.setRotation(0, 0, 0); // in radiansCamera Field of View (FOV)
engine.camera.setFov(90); // 90 degrees (60 degrees by default)Background Color vs. Gradient
// Solid color
engine.backgroundColor = '#add8e6';
engine.backgroundGradientColor = null;
// Vertical gradient
engine.backgroundColor = '#000000';
engine.backgroundGradientColor = '#1a1a2e';Default Edge Color (Fallback)
engine.defaultEdgeColor = '#00ff00';Materials: Edges, Gradients, Faces
// Edges only
cubeSceneObj.material = new Material('#ffffff');
// Gradient edges
cubeSceneObj.material = new Material('#ff00ff', '#00ffff');
// Face fill (depth sorting must be enabled)
engine.isDepthSorting = true;
// Swap material before/after/during runtime
cubeSceneObj.material = new Material('#ff00ff', '#00ffff', '#222222');Fog
engine.depthFog = {
enabled: true,
color: '#000000',
near: 5,
far: 40
};Bloom
engine.bloom = {
enabled: true,
blur: 5,
color: null // null = use edge color
};FPS Counter
engine.isFrameRateCounter = true;
engine.debugTextColor = '#ffffff';Screen Resize Handling
import { Vector2 } from 'canvas-js-3d';
engine.screenSize = new Vector2(
500, // Width 500px
500 // Height 500px
);Loading an OBJ Mesh
import { WavefrontMeshConverter } from 'canvas-js-3d';
const mesh2 = await WavefrontMeshConverter.fromUrl('./model.obj');
const obj = new SceneObject(
mesh2,
new Transform(new Vector3(4, 0, 4), Vector3.zero(), Vector3.one()),
new Material('#ffffff', null, '#222222')
);
engine.scene.addSceneObject(obj);Supported File Sources:
WavefrontMeshConverter.fromUrl(url);WavefrontMeshConverter.fromFile(file);WavefrontMeshConverter.fromFileDialog();WavefrontMeshConverter.fromText(objString);
Only vertex positions and face indices are parsed. Normals and UVs are ignored.
Stop Engine
engine.stop();Directory Structure
src/
├─ math/ # Vectors & transform math
├─ core/ # Scene, mesh, engine, material, scene object
├─ rendering/ # Camera, renderer, post effects
└─ wavefront-loading/ # OBJ loader pipelineLicense
MIT © 2026 Sebastian Bathrick
