Havok 516,349 began in 1998 as a Trinity College Dublin spin-off, was bought by Intel in 2007 and by Microsoft in 2015, and is licensed commercially for console and PC games. The web build is not: the npm 2,036 package @babylonjs/havok (1.3.14, 29 Jul 2026) carries an MIT LICENSE ("Copyright (c) 2023 Babylon.js 89,603 "), and Babylon's documentation calls the engine "free to use under the MIT license", WebAssembly and all. It needs WebAssembly SIMD (iOS 16.4+).
With npm, npm install @babylonjs/havok and import HavokPhysics from '@babylonjs/havok'. The UMD build defines a global HavokPhysics() that fetches HavokPhysics.wasm (2,094,563 bytes) from its own folder and resolves to the engine, which you pass to the plugin. The helper file l2-physics.js does this:
const HAVOK_URL = 'https://cdn.jsdelivr.net/npm/@babylonjs/havok@1.3.14/lib/umd/';
async function enableHavok(scene, fixedStep = true) { // Section 7.14.2
if (!window.HavokPhysics) { // the UMD script defines HavokPhysics()
await BABYLON.Tools.LoadScriptAsync(HAVOK_URL + 'HavokPhysics_umd.js');
}
const havok = await HavokPhysics(); // fetches and compiles the .wasm beside it
const plugin = new BABYLON.HavokPlugin(!fixedStep, havok); // false: 1/60 s per frame
scene.enablePhysics(new BABYLON.Vector3(0, -9.81, 0), plugin); // meters, seconds
return plugin;
}Loading and compiling both files took 400 ms on a shared test machine. HavokPlugin's first argument, useDeltaForWorldStep, defaults to true, advancing by each frame's measured time; false advances exactly 1/60 s (getTimeStep()) per scene.render(), repeatable but slower than real time when frames drop.
<!doctype html>
<style>
body { margin: 0; background: #f7f3ec; font: 13px system-ui, sans-serif; color: #333; }
canvas { width: 100%; max-width: 600px; height: 360px; display: block; touch-action: none; outline: none; }
</style>
<canvas id="view"></canvas>
<script src="https://cdn.jsdelivr.net/npm/babylonjs@9.28.0/babylon.js"></script>
<script src="https://cdn.jsdelivr.net/npm/babylonjs-gui@9.28.0/babylon.gui.min.js"></script>
<script>
/*
Loading Havok in a normal page (the sandboxed preview blocks the .wasm download):
await BABYLON.Tools.LoadScriptAsync('https://cdn.jsdelivr.net/npm/@babylonjs/havok@1.3.14/lib/umd/HavokPhysics_umd.js');
const havok = await HavokPhysics(); // fetches and compiles HavokPhysics.wasm
const plugin = new BABYLON.HavokPlugin(false, havok); // false: exactly 1/60 s per frame
scene.enablePhysics(new BABYLON.Vector3(0, -9.81, 0), plugin);
*/
const canvas = document.getElementById('view');
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
scene.clearColor = BABYLON.Color4.FromHexString('#f7f3ecff');
const camera = new BABYLON.ArcRotateCamera('cam', -Math.PI / 2, 1.25, 11.5, new BABYLON.Vector3(0.3, 1.2, 0), scene);
camera.attachControl(canvas, true);
new BABYLON.HemisphericLight('sky', new BABYLON.Vector3(0.3, 1, -0.6), scene);
const ui = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI('ui');
const EVENTS = [
[1998, 'Trinity College\nDublin spin-off', '#9e9e9e'],
[2007, 'bought by Intel', '#1f5f8b'],
[2015, 'bought by Microsoft', '#3f7d3a'],
[2023, 'Babylon 6.0: Physics V2,\nHavok web build (MIT)', '#e09a10'],
[2026, '@babylonjs/havok 1.3.14\n29 Jul 2026', '#b5452f'],
];
const xOf = (year) => (year - 2012) * 0.36;
const axis = BABYLON.MeshBuilder.CreateBox('axis', { width: 10.5, height: 0.06, depth: 0.25 }, scene);
axis.position.x = xOf(2012.3);
EVENTS.forEach(([year, text, hex], i) => {
const height = 0.6 + (i % 2) * 0.9;
const post = BABYLON.MeshBuilder.CreateCylinder('post', { height, diameter: 0.1 }, scene);
post.position.set(xOf(year), height / 2, 0);
const ball = BABYLON.MeshBuilder.CreateSphere('ball', { diameter: 0.3 }, scene);
ball.position.set(xOf(year), height, 0);
post.material = ball.material = new BABYLON.StandardMaterial(hex, scene);
ball.material.diffuseColor = BABYLON.Color3.FromHexString(hex);
const anchor = new BABYLON.TransformNode('anchor' + i, scene); // labels alternate above and below
anchor.position.set(xOf(year), i % 2 ? height : 0, 0);
const label = new BABYLON.GUI.TextBlock('', `${year}\n${text}`);
Object.assign(label, { color: '#222', fontSize: 11, resizeToFit: true });
ui.addControl(label);
label.linkWithMesh(anchor);
label.linkOffsetY = i % 2 ? -34 : 30;
});
// Loading cost, as measured in the book: the script plus a 2,094,563-byte .wasm, about 400 ms
const bar = (text, width, top, hex) => {
const rect = Object.assign(new BABYLON.GUI.Rectangle(), { width: `${width}px`, height: '20px', top, left: '14px',
background: hex, thickness: 0, horizontalAlignment: 0, verticalAlignment: 0 });
ui.addControl(rect);
const label = Object.assign(new BABYLON.GUI.TextBlock('', text), { top, left: `${width + 22}px`, height: '20px',
fontSize: 12, color: '#333', resizeToFit: true, horizontalAlignment: 0, verticalAlignment: 0 });
ui.addControl(label);
};
bar('HavokPhysics.wasm: 2.09 MB, MIT', 200, '12px', '#b5452f');
bar('load + compile: ~400 ms', 40, '38px', '#e09a10');
engine.runRenderLoop(() => scene.render());
addEventListener('resize', () => engine.resize());
</script>