Babylon.js

Babylon.js 89,603 (github.com/BabylonJS/Babylon.js (https://github.com/BabylonJS/Babylon.js 26,113 ), Apache-2.0, 9.28.0) is the closest rival and the subject of Babylon.js. Where Three.js 30,815 leaves physics and UI to third parties, Babylon.js ships them as first-party packages on one version number: Havok 516,349 physics (Physics with Havok), a 2D and 3D GUI (2D GUI and The 3D GUI), an inspector (Inspector and Tools), WebXR (WebXR) and a visual node material editor (The Node Material Editor). Its WebGPU engine and WebGL engine share one API, as Three.js's two renderers do. It also keeps its public API stable between yearly majors (Release Cadence), where any Three.js rNNN may break code. The cost is size: a bundled one-box scene weighs over twice the Three.js equivalent (OGL and Choosing a Library). Babylon.js Versus Three.js compares the two in depth.

What ships first-party with Babylon.js versus Three.js, as a rotating 3D scorecardHTMLLive
<!doctype html>
<style>
  body { margin: 0; background: #f5f1e8; font: 13px system-ui, sans-serif; color: #263238; }
  canvas { display: block; max-width: 100%; }
  p { margin: 4px 8px; }
</style>
<script type="importmap">
{ "imports": {
  "three": "https://cdn.jsdelivr.net/npm/three@0.186.1/build/three.module.js",
  "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.186.1/examples/jsm/" } }
</script>
<p>Green: built in, first party. Amber: third-party or add-on. Hover a tile for details.</p>
<p id="out">&nbsp;</p>
<script type="module">
import * as THREE from 'three';

// [feature, Three.js, Babylon.js] — 2 built in, 1 via add-on or third party
const ROWS = [
  ['Physics', 1, 2, 'Three.js: Rapier or cannon-es · Babylon.js: Havok plugin'],
  ['2D / 3D GUI', 1, 2, 'Three.js: DOM or libraries · Babylon.js: babylonjs-gui'],
  ['Inspector', 1, 2, 'Three.js: Inspector add-on, Spector.js · Babylon.js: built-in Inspector'],
  ['WebXR', 2, 2, 'Both ship WebXR support'],
  ['Node material editor', 1, 2, 'Three.js: TSL in code · Babylon.js: visual Node Material Editor'],
  ['Stable API', 1, 2, 'Three.js: any rNNN may break · Babylon.js: stable between yearly majors'],
  ['Small bundle', 2, 1, 'One-box app gzip: Three.js 139 KB · Babylon.js 352 KB'],
];

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(600, 300);
document.body.insertBefore(renderer.domElement, document.body.firstChild);
const scene = new THREE.Scene();
scene.background = new THREE.Color('#fbf8f2');
const camera = new THREE.PerspectiveCamera(35, 2, 0.1, 50);
camera.position.set(0, 0.4, 7);
scene.add(new THREE.HemisphereLight('#ffffff', '#8d6e63', 1.5));
const sun = new THREE.DirectionalLight('#ffffff', 1.5);
sun.position.set(2, 3, 4);
scene.add(sun);

function textPlane(text, w, h, { bold = true, size = 44, align = 'left' } = {}) {
  const canvas = Object.assign(document.createElement('canvas'), { width: 512, height: Math.round(512 * h / w) });
  const g = canvas.getContext('2d');
  g.font = `${bold ? 'bold ' : ''}${size}px system-ui, sans-serif`;
  g.fillStyle = '#263238';  g.textAlign = align;  g.textBaseline = 'middle';
  g.fillText(text, align === 'left' ? 10 : 256, canvas.height / 2);
  const map = new THREE.CanvasTexture(canvas);
  map.colorSpace = THREE.SRGBColorSpace;
  return new THREE.Mesh(new THREE.PlaneGeometry(w, h), new THREE.MeshBasicMaterial({ map, transparent: true }));
}

const board = new THREE.Group();
scene.add(board);
const header = [['Three.js', 0.6], ['Babylon.js', 1.9]];
header.forEach(([t, x]) => { const p = textPlane(t, 1.2, 0.3, { align: 'center' }); p.position.set(x, 1.55, 0); board.add(p); });
const tiles = [];
ROWS.forEach(([name, three, babylon, detail], r) => {
  const y = 1.15 - r * 0.42;
  const label = textPlane(name, 2.2, 0.36, { size: 40 });
  label.position.set(-1.6, y, 0);
  board.add(label);
  [three, babylon].forEach((score, c) => {
    const tile = new THREE.Mesh(new THREE.BoxGeometry(1.1, 0.34, 0.12),
      new THREE.MeshStandardMaterial({ color: score === 2 ? '#3f7d3a' : '#e09a10', roughness: 0.5 }));
    tile.position.set(0.6 + c * 1.3, y, 0);
    tile.userData.detail = detail;
    board.add(tile);
    tiles.push(tile);
  });
});

// Hover a tile to read the detail line
const raycaster = new THREE.Raycaster();
let hovered = null;
renderer.domElement.addEventListener('pointermove', (e) => {
  const r = renderer.domElement.getBoundingClientRect();
  raycaster.setFromCamera(new THREE.Vector2((e.clientX - r.left) / r.width * 2 - 1, 1 - (e.clientY - r.top) / r.height * 2), camera);
  const hit = raycaster.intersectObjects(tiles)[0]?.object ?? null;
  if (hovered) hovered.material.emissive.set(0);
  hovered = hit;
  if (hit) { hit.material.emissive.set('#333'); document.getElementById('out').textContent = hit.userData.detail; }
});

renderer.setAnimationLoop((t) => {
  board.rotation.y = Math.sin(t / 2500) * 0.25;
  renderer.render(scene, camera);
});
</script>