Opening the Inspector

Opening the Inspector at Runtime

The Inspector is not in the engine bundle. scene.debugLayer.show(options), the original API, downloads it on the first call (options include embedMode, overlay and initialTab); hide() closes it. Put it behind a shortcut so visitors never download it:

Toggling the Inspector with Ctrl+Shift+Alt+I, downloaded on first useJavaScript
window.addEventListener('keydown', async (event) => {
  if (!(event.ctrlKey && event.shiftKey && event.altKey && event.code === 'KeyI')) return;
  if (scene.debugLayer.isVisible()) return scene.debugLayer.hide();
  const started = performance.now();
  await scene.debugLayer.show({ embedMode: true });
  const bundle = document.querySelector('script[src*="inspector"]').src;
  console.log(`${Math.round(performance.now() - started)} ms from ${bundle}`);
});
Output
BJS - [18:13:40]: Babylon.js v9.28.0 - WebGL2 - Parallel shader compilation
1006 ms from https://cdn.babylonjs.com/v9.28.0/inspector/babylon.inspector.bundle.js

The UMD build fetched the classic Inspector for its version from Babylon 89,603 's CDN (2.27 MB); a second press hid it. Since 8.49.0 (29 January 2026) the npm 2,036 packages ship its successor, Inspector V2, rebuilt on React 7,897 and Microsoft's Fluent UI: babylonjs-inspector (UMD, global INSPECTOR) or @babylonjs/inspector, both 9.28.0 and Apache-2.0. ShowInspector(scene, options) returns a token whose dispose() closes it, and once V2 is loaded, debugLayer.show() opens V2 through a compatibility layer. The UMD bundle needs the babylonjs-addons, -loaders and -materials scripts first; without them it threw "Cannot read properties of undefined (reading 'NONE')".

BookNest's room with the Inspector behind a keyboard shortcut, so visitors never download itHTMLLive
<!doctype html>
<style>
  body { margin: 0; background: #f7f3ec; font: 13px system-ui, sans-serif; color: #333; }
  canvas { width: 100%; max-width: 600px; height: 300px; display: block; touch-action: none; outline: none; }
  #bar { max-width: 600px; display: flex; gap: 10px; align-items: center; padding: 6px 8px; } button { font: inherit; padding: 3px 10px; } #info { font-size: 12px; color: #555; }
</style>
<canvas id="view"></canvas>
<div id="bar"><button id="open">Open the Inspector</button><span id="info">or press Ctrl+Shift+Alt+I</span></div>
<script src="https://cdn.jsdelivr.net/npm/babylonjs@9.28.0/babylon.js"></script>
<script>
// ---- BookNest's bookstore: the helpers the book keeps in bookstore.js ----
const ROOM = { width: 8, depth: 6, height: 3, wall: 0.15 };
const BOOKS = [
  { id: 1, title: 'The Quiet Harbor', author: 'Mara Ellison', color: '#1f5f8b', pages: 312, price: 14.99, rating: 4.6, inStock: true },
  { id: 2, title: 'Patterns of the Deep Web', author: 'Tomas Reyes', color: '#5b3f99', pages: 428, price: 32.5, rating: 4.4, inStock: true },
  { id: 3, title: 'Salt and Saffron', author: 'Priya Nair', color: '#e09a10', pages: 256, price: 24, rating: 4.8, inStock: false },
  { id: 4, title: 'Small Steps to Big Summits', author: 'Dana Whitfield', color: '#3f7d3a', pages: 198, price: 18.5, rating: 4.3, inStock: true },
  { id: 5, title: "The Clockmaker's Paradox", author: 'Julian Voss', color: '#b5452f', pages: 344, price: 16.75, rating: 4.7, inStock: true },
  { id: 6, title: 'Gardens in Glass', author: 'Lena Hart', color: '#2a9d8f', pages: 176, price: 21.3, rating: 4.5, inStock: true },
];
function createScene(engine) {
  const scene = new BABYLON.Scene(engine);
  scene.clearColor = BABYLON.Color4.FromHexString('#cfd8dcff');
  const sky = new BABYLON.HemisphericLight('sky', new BABYLON.Vector3(0.3, 1, -0.4), scene);
  sky.groundColor = new BABYLON.Color3(0.35, 0.32, 0.3);
  return scene;
}
function paint(scene, name, hex) {                  // a matte color
  const material = new BABYLON.StandardMaterial(name, scene);
  material.diffuseColor = BABYLON.Color3.FromHexString(hex);
  material.specularColor = BABYLON.Color3.Black();
  return material;
}
function createRoom(scene) {                        // floor and three walls, front open
  const room = new BABYLON.TransformNode('room', scene);
  const floor = BABYLON.MeshBuilder.CreateGround('floor', { width: ROOM.width, height: ROOM.depth }, scene);
  floor.material = paint(scene, 'oak', '#b08d6a');
  floor.parent = room;
  const plaster = paint(scene, 'plaster', '#fff3e0');
  for (const [name, width, x, z] of [['backWall', 8, 0, 3], ['leftWall', 6, -4, 0], ['rightWall', 6, 4, 0]]) {
    const wall = BABYLON.MeshBuilder.CreateBox(name, { width, height: ROOM.height, depth: ROOM.wall }, scene);
    wall.position.set(x, ROOM.height / 2, z);
    wall.rotation.y = x ? Math.PI / 2 : 0;
    wall.material = plaster;
    wall.parent = room;
  }
  return room;
}
function createBookcase(scene, name, x) {           // 8 boxes merged into 1 mesh
  const [w, h, d, t] = [3, 2.2, 0.35, 0.04];
  const parts = [[t, h, d, -w / 2, h / 2, 0], [t, h, d, w / 2, h / 2, 0], [w, h, t, 0, h / 2, d / 2 - t / 2]];
  for (let i = 0; i < 5; i++) parts.push([w, t, d, 0, 0.1 + i * 0.5, 0]);
  const bookcase = BABYLON.Mesh.MergeMeshes(parts.map(([width, height, depth, px, py, pz]) => {
    const part = BABYLON.MeshBuilder.CreateBox('part', { width, height, depth }, scene);
    part.position.set(px, py, pz);
    return part;
  }), true);
  bookcase.name = name;
  bookcase.material = paint(scene, 'walnut', '#6d4c33');
  bookcase.position.set(x, 0, ROOM.depth / 2 - ROOM.wall / 2 - d / 2);   // against the back wall
  return bookcase;
}
function drawCover(scene, book) {                   // cover art painted on a canvas
  const tex = new BABYLON.DynamicTexture('cover' + book.id, { width: 256, height: 384 }, scene);
  const c = tex.getContext();
  c.fillStyle = book.color; c.fillRect(0, 0, 256, 384);
  c.fillStyle = 'rgba(0,0,0,0.4)'; c.fillRect(0, 0, 18, 384);         // the dark left edge
  c.strokeStyle = '#fff8e1'; c.lineWidth = 3; c.strokeRect(34, 24, 202, 336);
  c.fillStyle = '#fff8e1'; c.textAlign = 'center'; c.font = 'bold 30px Georgia';
  const lines = [''];
  for (const word of book.title.split(' ')) {
    const test = (lines[lines.length - 1] + ' ' + word).trim();
    if (c.measureText(test).width > 180) lines.push(word); else lines[lines.length - 1] = test;
  }
  lines.forEach((line, i) => c.fillText(line, 135, 110 + i * 38));
  c.font = '20px Georgia'; c.fillText(book.author, 135, 330);
  tex.update();
  return tex;
}
function placeBooks(scene, bookcase, shelf = 2) {   // six books, spines out, covers on +x
  const strip = new BABYLON.Vector4(0, 0, 0.07, 1);
  const faceUV = [strip, strip, new BABYLON.Vector4(0, 0, 1, 1), strip, strip, strip];
  let x = -0.35;                                    // left end of the row, local to the bookcase
  return BOOKS.map((record) => {
    const width = record.pages / 4000 + 0.02;       // spine thickness from page count
    const book = BABYLON.MeshBuilder.CreateBox(`book${record.id}`, { width, height: 0.3, depth: 0.22, faceUV, wrap: true }, scene);
    book.parent = bookcase;
    book.position.set(x + width / 2, 0.12 + shelf * 0.5 + 0.15, -0.02);
    x += width + 0.012;
    book.material = new BABYLON.StandardMaterial(record.title, scene);
    book.material.diffuseTexture = drawCover(scene, record);
    book.material.specularColor = new BABYLON.Color3(0.15, 0.15, 0.15);
    book.metadata = record;                         // the record, for picking
    return book;
  });
}
// The book cuts the storefront with CSG2 (Manifold WebAssembly); this sandbox cannot download
// the .wasm, so the older pure-JavaScript BABYLON.CSG makes the same cuts here.
function createFrontWall(scene) {
  const box = (width, height, depth, x, y) => {
    const mesh = BABYLON.MeshBuilder.CreateBox('cut', { width, height, depth }, scene);
    mesh.position.set(x, y, -ROOM.depth / 2);
    return mesh;
  };
  const solid = box(ROOM.width, ROOM.height, ROOM.wall, 0, ROOM.height / 2);
  const windowHole = box(3.2, 1.6, 1, -1.4, 1.6), doorHole = box(1.1, 2.2, 1, 2.3, 1.1);
  const wall = BABYLON.CSG.FromMesh(solid).subtract(BABYLON.CSG.FromMesh(windowHole))
    .subtract(BABYLON.CSG.FromMesh(doorHole)).toMesh('frontWall', scene.getMaterialByName('plaster'), scene);
  [solid, windowHole, doorHole].forEach((mesh) => mesh.dispose());
  return wall;
}
// ---- end of the bookstore helpers ----

const canvas = document.getElementById('view');
const engine = new BABYLON.Engine(canvas, true, {}, true);
const scene = createScene(engine);
createRoom(scene);
placeBooks(scene, createBookcase(scene, 'bookcaseLeft', -1.8));
createBookcase(scene, 'bookcaseRight', 1.8);
const camera = new BABYLON.ArcRotateCamera('overview', -Math.PI / 2, 1.1, 9, new BABYLON.Vector3(0, 1, 0), scene);
camera.attachControl(canvas, true);
const info = document.getElementById('info');

// The Inspector is not in babylon.js: debugLayer.show() downloads it (2.27 MB) on first use.
// (Inside this sandboxed preview it may refuse to start; run the page on its own to try it.)
async function toggleInspector() {
  if (scene.debugLayer.isVisible()) return scene.debugLayer.hide();
  const started = performance.now();
  info.textContent = 'downloading the Inspector…';
  try {
    await scene.debugLayer.show({ embedMode: true });
    const bundle = document.querySelector('script[src*="inspector"]')?.src ?? '';
    info.textContent = `${Math.round(performance.now() - started)} ms from ${bundle.split('/').slice(-3).join('/')}`;
  } catch (error) {
    info.textContent = `could not open it here: ${error.message}`;
  }
}
window.addEventListener('keydown', (event) => {
  if (event.ctrlKey && event.shiftKey && event.altKey && event.code === 'KeyI') toggleInspector();
});
document.getElementById('open').addEventListener('click', toggleInspector);
engine.runRenderLoop(() => scene.render());
addEventListener('resize', () => engine.resize());
</script>