Appearance
@carrot/engine-vue ​
tsvue
Vue 3 composables for integrating the Carrot WebGL engine into Vue applications.
Installation ​
bash
npm install @carrot/engine-vueRequires vue@^3.4.0 as a peer dependency.
Architecture / How It Works ​
This package provides a thin reactive layer between the Carrot engine and Vue 3's reactivity system. It exposes three composables:
useEngine- The primary entry point. Takes a canvas ref and engine configuration, creates aGameinstance on mount, and tears it down on unmount. Exposes reactivefpsandrunningstate, plusstart/stopcontrols. TheGameinstance is created insideonMounted(since it needs the DOM canvas element), and cleanup happens inonUnmounted.useScene- Watches aGameref and subscribes to scene switch events. Provides reactive access to the currentSceneand its entity list, plus aswitchTofunction.useInput- Watches anEngineref and subscribes to input device change events. Tracks the active device category and whether a gamepad is connected.
All composables use shallowRef for engine objects (which are large, mutable class instances - deep reactivity would be wasteful and broken) and ref for primitive state like fps and running.
Lifecycle ​
onMounted → new Game(canvas) → autoStart? → game.start(scene)
↕
useScene watches game
useInput watches engine
onUnmounted → stop() → clearInterval(fpsInterval)Dependencies ​
| Package | Role |
|---|---|
@carrot/engine | Core WebGL engine (Engine class, Input system) |
@carrot/engine-framework | High-level framework (Game, Scene, Entity, SceneTemplate) |
@carrot/signals | Event system used by engine internals |
@carrot/logging | Log interface for optional logging |
Peer dependency: vue@^3.4.0
Build ​
bash
npm run build # runs tscOutput goes to dist/. The package ships ES modules with TypeScript declarations.
Usage Guide ​
Vue 3 composables for embedding and controlling the Carrot engine in your components.
Import ​
ts
import { useEngine, useScene, useInput } from '@carrot/engine-vue';Common Patterns ​
1. Basic engine setup ​
Mount the engine on a canvas element with auto-start (default behaviour):
vue
<script setup lang="ts">
import { ref } from 'vue';
import { useEngine } from '@carrot/engine-vue';
const canvasRef = ref<HTMLCanvasElement>();
const { fps, running } = useEngine({ canvas: canvasRef });
</script>
<template>
<canvas ref="canvasRef" width="1280" height="720" />
<p>FPS: {{ fps }} | Running: {{ running }}</p>
</template>2. Manual start with a custom scene ​
Disable auto-start and launch with your own scene when ready:
vue
<script setup lang="ts">
import { ref } from 'vue';
import { useEngine } from '@carrot/engine-vue';
import { Scene } from '@carrot/engine-framework';
const canvasRef = ref<HTMLCanvasElement>();
const { start, stop, running } = useEngine({
canvas: canvasRef,
autoStart: false,
assetBasePath: '/game-assets/',
});
const myScene = new Scene('Level1');
function onPlay() {
start(myScene);
}
</script>
<template>
<canvas ref="canvasRef" />
<button v-if="!running" @click="onPlay">Start</button>
<button v-else @click="stop">Stop</button>
</template>3. Scene management ​
Use useScene to reactively track and switch scenes:
vue
<script setup lang="ts">
import { ref } from 'vue';
import { useEngine, useScene } from '@carrot/engine-vue';
import { Scene } from '@carrot/engine-framework';
const canvasRef = ref<HTMLCanvasElement>();
const { game } = useEngine({ canvas: canvasRef });
const { scene, entities, switchTo } = useScene(game);
const menuScene = new Scene('Menu');
const gameScene = new Scene('Game');
async function goToGame() {
await switchTo(gameScene);
}
</script>
<template>
<canvas ref="canvasRef" />
<div>
<p>Current scene: {{ scene?.name }}</p>
<p>Entity count: {{ entities.length }}</p>
<button @click="goToGame">Start Game</button>
</div>
</template>4. Input device tracking ​
React to controller/keyboard changes in the UI:
vue
<script setup lang="ts">
import { ref } from 'vue';
import { useEngine, useInput } from '@carrot/engine-vue';
const canvasRef = ref<HTMLCanvasElement>();
const { engine } = useEngine({ canvas: canvasRef });
const { isGamepadActive, activeDevice } = useInput(engine);
</script>
<template>
<canvas ref="canvasRef" />
<p v-if="isGamepadActive">Gamepad connected - press A to continue</p>
<p v-else>Using {{ activeDevice }}</p>
</template>5. Full integration ​
Combining all three composables:
vue
<script setup lang="ts">
import { ref } from 'vue';
import { useEngine, useScene, useInput } from '@carrot/engine-vue';
import { Scene } from '@carrot/engine-framework';
const canvasRef = ref<HTMLCanvasElement>();
const { game, engine, fps, running, stop } = useEngine({
canvas: canvasRef,
scene: new Scene('Main'),
});
const { scene, entities, switchTo } = useScene(game);
const { activeDevice } = useInput(engine);
</script>
<template>
<canvas ref="canvasRef" />
<div class="hud">
<span>{{ fps }} FPS</span>
<span>{{ activeDevice }}</span>
<span>{{ entities.length }} entities</span>
<button @click="stop">Quit</button>
</div>
</template>