Skip to content

Installation

Prerequisites

  • Node.js 18+ and npm (or your preferred package manager)
  • TypeScript knowledge -- SAGE is written in TypeScript and expects you to use it
  • A bundler like Vite (recommended), Webpack, or similar

Install Packages

SAGE requires BabylonJS and Havok as peer dependencies:

bash
npm install @skewedaspect/sage @babylonjs/core @babylonjs/havok

If you are building a Vue application, also install the Vue integration package:

bash
npm install @skewedaspect/sage-vue

TypeScript Configuration

Make sure your tsconfig.json includes these settings:

json
{
    "compilerOptions": {
        "target": "ES2023",
        "module": "ESNext",
        "moduleResolution": "bundler",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "lib": ["ESNext", "DOM", "DOM.Iterable"]
    }
}

Quick Start: Spinning Cube

The fastest way to verify your setup is to get a cube on screen and spinning. This uses SAGE's createGameEngine() factory and BabylonJS directly for scene setup.

HTML

Create an index.html with a full-viewport canvas:

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SAGE - Hello Cube</title>
    <style>
        html, body {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }
        #gameCanvas {
            width: 100%;
            height: 100%;
            touch-action: none;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas"></canvas>
    <script type="module" src="./src/main.ts"></script>
</body>
</html>

Game Code

Create src/main.ts:

typescript
import { createGameEngine } from '@skewedaspect/sage';
import {
    ArcRotateCamera,
    Color3,
    Color4,
    HemisphericLight,
    MeshBuilder,
    StandardMaterial,
    Vector3,
} from '@babylonjs/core';

async function main() : Promise<void>
{
    const canvas = document.getElementById('gameCanvas') as HTMLCanvasElement;

    // Create the engine -- no entity definitions needed for this demo
    const engine = await createGameEngine(canvas, []);

    // Create a scene with physics enabled
    const scene = engine.engines.sceneEngine.createScene();
    scene.clearColor = new Color4(0.12, 0.12, 0.14, 1);

    // Camera
    const camera = new ArcRotateCamera(
        'camera',
        Math.PI / 4,
        Math.PI / 3,
        5,
        Vector3.Zero(),
        scene
    );
    camera.attachControl(canvas, true);

    // Light
    new HemisphericLight('light', new Vector3(0, 1, 0), scene).intensity = 0.8;

    // Cube
    const cube = MeshBuilder.CreateBox('cube', { size: 1.5 }, scene);
    const material = new StandardMaterial('cubeMat', scene);
    material.diffuseColor = new Color3(0.5, 0.17, 0.17);
    cube.material = material;

    // Spin the cube every frame
    engine.managers.gameManager.registerFrameCallback((dt : number) =>
    {
        cube.rotation.x += 0.3 * dt;
        cube.rotation.y += 0.6 * dt;
        scene.render();
    });

    // Start the game loop
    engine.managers.gameManager.start();
}

main();

Run it with Vite:

bash
npx vite

You should see a dark scene with a red cube rotating. Click and drag to orbit the camera.

Vue Integration

If you are using Vue 3, the @skewedaspect/sage-vue package provides a SageCanvas component that handles engine creation, canvas management, and resize handling for you.

vue
<template>
    <SageCanvas @engine-ready="onEngineReady" :options="{ logLevel: 'info' }" />
</template>

<!--------------------------------------------------------------------------------------------------------------------->

<style scoped>
    /* SageCanvas fills its parent, so size the parent */
</style>

<!--------------------------------------------------------------------------------------------------------------------->

<script setup lang="ts">
    import type { GameEngine } from '@skewedaspect/sage';
    import { SageCanvas } from '@skewedaspect/sage-vue';

    function onEngineReady(engine : GameEngine) : void
    {
        // Set up your scene and start the game loop here.
        // The engine is fully initialized -- create scenes,
        // register frame callbacks, and call start().
    }
</script>

<!--------------------------------------------------------------------------------------------------------------------->

SageCanvas provides a scoped slot with loading, error, and engine properties, so you can overlay UI on top of the canvas:

vue
<SageCanvas @engine-ready="onEngineReady">
    <template #default="{ loading }">
        <div v-if="loading">Loading...</div>
    </template>
</SageCanvas>

You can also pass entity definitions directly via the :entity-definitions prop instead of registering them manually after engine creation.

TIP

Child components can access the engine instance using the useSageEngine() composable from @skewedaspect/sage-vue, without needing to pass it as a prop.

Next Steps

This page got you from zero to spinning cube. For the full walkthrough with explanations of every piece, see the Hello Cube Guide. From there:

  • Architecture -- understand how the engine is put together
  • Entities -- learn the entity-behavior composition system
  • Input & Bindings -- set up keyboard, mouse, and gamepad input
  • Levels -- load scenes from YAML and GLB files

Released under the MIT License.