# Needle Engine — Framework Integration
## React
### Listen for 3D events in a component
```tsx
import { useEffect, useState } from "react";
function ScoreDisplay() {
const [score, setScore] = useState(0);
useEffect(() => {
const ne = document.querySelector("needle-engine");
const handler = (e: CustomEvent) => setScore(e.detail.score);
ne?.addEventListener("score-changed", handler as EventListener);
return () => ne?.removeEventListener("score-changed", handler as EventListener);
}, []);
return
Score: {score}
;
}
```
### Call into the 3D scene from React
```tsx
function GameControls() {
const addScore = async () => {
const { findObjectOfType } = await import("@needle-tools/engine");
const { MyScoreManager } = await import("./scripts/MyScoreManager.js");
findObjectOfType(MyScoreManager)?.addScore(10);
};
return ;
}
```
### Use engine hooks from React
```tsx
useEffect(() => {
import("@needle-tools/engine").then(({ onStart }) => {
onStart((ctx) => {
// safe to access components here
});
});
}, []);
```
---
## Svelte / SvelteKit
```svelte
Score: {score}
```
---
## Vue / Nuxt
```vue
Score: {{ score }}
```
---
## Vanilla JS / No Framework
```html
```
---
## Engine Hooks Reference
These standalone functions from `@needle-tools/engine` mirror the component lifecycle but work outside of a class:
| Hook | When it fires |
|---|---|
| `onInitialized(cb)` | Once after context creation and first content load |
| `onStart(cb)` | Once when the context/scene is ready |
| `onUpdate(cb)` | Every frame (before rendering) |
| `onBeforeRender(cb)` | Just before Three.js renders |
| `onAfterRender(cb)` | Just after Three.js renders |
| `onClear(cb)` | Before context is cleared (e.g. when `src` changes) |
| `onDestroy(cb)` | When the context is torn down |
All callbacks receive `(ctx: Context)` as their argument.
### Client-only (no SSR)
When server-side rendering is **disabled**, import and call hooks directly:
```ts
import { onStart, onUpdate, onBeforeRender, onDestroy } from "@needle-tools/engine";
onStart((ctx) => { /* setup */ });
onUpdate((ctx) => { /* per-frame logic */ });
onDestroy((ctx) => { /* cleanup */ });
```
### With SSR (Next.js, SvelteKit, Nuxt, etc.)
`@needle-tools/engine` depends on WebGL / browser APIs and **cannot be imported on the server**. Use a dynamic import so the module is only loaded client-side (same pattern as with any three.js-based engine):
```ts
import("@needle-tools/engine").then(({ onStart, onUpdate, onDestroy }) => {
onStart((ctx) => { /* setup */ });
onUpdate((ctx) => { /* per-frame logic */ });
onDestroy((ctx) => { /* cleanup */ });
});
```