Migration Guide
Migrating from 0.8.x to 0.9.x
SAGE 0.9.0 includes several breaking changes from the 0.8.x series. This guide walks through each change with before/after code examples.
1. Update Dependencies
SAGE now requires BabylonJS 9.0 and @babylonjs/loaders as a peer dependency:
npm install @babylonjs/core@^9.0.0 @babylonjs/havok@^1.3.10 @babylonjs/loaders@^9.0.0If you had import '@babylonjs/loaders/glTF' in your own code, remove it. SAGE now registers all loaders automatically via registerBuiltInLoaders().
2. Rename SkewedAspectGameEngine to GameEngine
// Before
import { SkewedAspectGameEngine } from '@skewedaspect/sage';
// After
import { GameEngine } from '@skewedaspect/sage';3. Update Event Bus Usage
TypedEventBus was merged into GameEventBus:
// Before
import { TypedEventBus } from '@skewedaspect/sage';
const bus = new TypedEventBus<MyEvents>();
// After
import { GameEventBus } from '@skewedaspect/sage';
const bus = new GameEventBus<MyEvents>();4. Update Behavior Definitions
Behaviors switched to array-based registration with constructor identification:
// Before (0.8.x)
const entity = entityManager.createEntity('player', {
behaviors: {
movement: new MovementBehavior(),
combat: new CombatBehavior(),
},
});
// After (0.9.x)
const entity = entityManager.createEntity('player', {
behaviors: [ MovementBehavior, CombatBehavior ],
});5. Update LevelContext Access
Level subclasses now access services through this.gameEngine instead of individual injected references:
// Before
class MyLevel extends Level
{
async buildScene()
{
const scene = this.sceneEngine.createScene();
await this.entityManager.createEntity('player', {});
}
}
// After
class MyLevel extends Level
{
async buildScene()
{
const scene = this.gameEngine.engines.sceneEngine.createScene();
await this.gameEngine.managers.entityManager.createEntity('player', {});
}
}6. Update onNodeAttached Signature
The behavior lifecycle hook now receives gameEngine as a second parameter:
// Before
onNodeAttached(node : TransformNode) : void
{
const scene = node.getScene();
}
// After
onNodeAttached(node : TransformNode, gameEngine : GameEngine) : void
{
const scene = node.getScene();
const physics = gameEngine.physics;
}7. Rename ChannelState to ChannelInfo
// Before
import type { ChannelState } from '@skewedaspect/sage';
// After
import type { ChannelInfo } from '@skewedaspect/sage';8. Update getBindingsForAction Calls
The parameter order changed to accommodate device type filtering:
// Before
const bindings = bindingManager.getBindingsForAction('jump', 'gameplay');
// After — insert undefined for deviceType
const bindings = bindingManager.getBindingsForAction('jump', undefined, 'gameplay');
// Or filter by device type
const kbBindings = bindingManager.getBindingsForAction('jump', 'keyboard', 'gameplay');9. Replace SceneLoader Usage
If you used SceneLoader.ImportMeshAsync directly, switch to the module-level function:
// Before
import { SceneLoader } from '@babylonjs/core';
const result = await SceneLoader.ImportMeshAsync('', '/assets/', 'model.glb', scene);
// After
import { ImportMeshAsync } from '@babylonjs/core';
const result = await ImportMeshAsync('/assets/model.glb', scene);New Features Available After Migration
Once you've completed the migration, you can optionally adopt these new features:
- Large World Rendering —
largeWorldRendering: trueinSageOptions - Clustered Lighting —
clustering:section in level YAML - Entity Highlighting —
outlines:section in level YAML +entity.highlight() - Frame Graph Rendering —
renderer: 'frameGraph'inpostProcessing:config - Geospatial Camera —
type: 'geospatial'in camera config - Entity Messaging —
entity.send()/entity.request() - Input Capture —
bindingManager.captureInput()for key rebinding
