How to Properly Load HavokPhysics.wasm in a Nuxt/Vite Project

If you’re using Babylon.js with Havok Physics in a Nuxt (Vue 3) project, you might encounter an error when trying to initialize physics. The console might show something like this:

Uncaught (in promise) RuntimeError: Aborted(CompileError: WebAssembly.instantiate(): expected magic word 00 61 73 6d, found 3c 21 44 4f @+0).

Additionally, in the Network tab, you might see that Vite is trying to load HavokPhysics.wasm from an incorrect location, such as:

http://localhost:3200/_nuxt/node_modules/.cache/vite/client/deps/HavokPhysics.wasm

This happens because Nuxt/Vite does not automatically handle .wasm files correctly, causing the browser to receive an HTML response instead of the actual WebAssembly file.


Possible Fix: Modify nuxt.config.js

Before applying the solution in your code, you can try modifying nuxt.config.js to explicitly tell Vite to handle .wasm files:

export default defineNuxtConfig({
  vite: {
    build: {
      target: 'esnext',
    },
    assetsInclude: ['**/*.wasm'],  // Ensure Vite includes .wasm files in the build
  }
});

After modifying nuxt.config.js, restart your Nuxt server with:

rm -rf .nuxt
rm -rf node_modules/.cache
yarn install
yarn dev

If the issue persists, proceed with the following solution.


Solution: Manually Specify the .wasm File Location

  1. Move HavokPhysics.wasm to the static/ folder in your Nuxt project. This makes it directly accessible at /havoc.wasm.
  2. Modify the initialization of HavokPhysics to explicitly set the correct path using the locateFile function.

:white_check_mark: Full Implementation Example in Babylon.js (with Havok imports)

import * as BABYLON from "@babylonjs/core";
import HavokPhysics from "@babylonjs/havok";

export class Main {
  private engine: BABYLON.Engine;
  private scene: BABYLON.Scene | null = null;

  constructor(canvas: HTMLCanvasElement) {
    this.engine = new BABYLON.Engine(canvas, true);
    this.createScene().then((scene) => {
      this.scene = scene;
      this.engine.runRenderLoop(() => {
        this.scene!.render();
      });
    });
  }

  private async createScene(): Promise<BABYLON.Scene> {
    // Load Havok Physics and set the correct path for the .wasm file
    const havokInterface = await HavokPhysics({
      locateFile: (file: string) => {
        if (file.endsWith('.wasm')) {
          return '/havoc.wasm';  // Path to the .wasm file inside static/
        }
        return file;
      }
    });

    // Create Babylon.js scene
    const scene = new BABYLON.Scene(this.engine);

    // Import Havok Plugin and enable physics
    const hk = new BABYLON.HavokPlugin(true, havokInterface);
    scene.enablePhysics(new BABYLON.Vector3(0, -9.81, 0), hk);

    return scene;
  }
}

Why This Works:

  • Nuxt’s static/ folder serves files as-is, meaning any file placed there is accessible directly via the root URL.
  • The locateFile function allows us to override how Havok Physics finds the .wasm file, ensuring it loads from the correct location.
  • Havok is properly initialized before Babylon.js enables physics, preventing errors during scene setup.

Debugging Tip:

If you still experience issues, open the browser DevTools (F12 → Network tab) and check if HavokPhysics.wasm is being loaded correctly. If it’s missing or returns an HTML page instead of a .wasm file, make sure the file is in the static/ folder and that the path in locateFile matches.

This solution worked perfectly for my Nuxt project. Hope it helps others facing the same issue!

2 Likes