# Hooks

> Reference for every Apricot hook: useScene, useFrame, useAnimatable, useSceneTouches, useParent, useAttach, useTransform, plus the material, model, texture, path and trip hooks, and the diagnostics helpers. Where each must be called and what it returns.

```ts
import { useAnimatable, useAttach, useFrame, useParent, useScene, useSceneTouches, useTransform } from "@apricot/react";
```

> [!IMPORTANT]
> Hooks marked **inside Scene** must run in a component rendered **inside** `<Scene>`, not in the component that renders the `<Scene>`. Split the scene's content into its own component:
>
> ```tsx
> function Content() {
>   useFrame(() => false); // fine: Content is inside <Scene>
>   return <Box />;
> }
> export const Screen = () => (
>   <Scene style={{ flex: 1 }}>
>     <Content />
>   </Scene>
> );
> ```

## Index

| Hook | Where | Returns |
| --- | --- | --- |
| [`useScene()`](#usescene) | inside Scene | `ApricotScene` |
| [`useFrame(callback)`](#useframe) | inside Scene | `void` |
| [`useAnimatable(value)`](#useanimatable) | inside Scene | `() => T` |
| [`useSceneTouches(listener, active?)`](#usescenetouches) | inside Scene | `void` |
| [`useParent()` / `useAttach(object)`](#useparent-and-useattach) | inside Scene | `Object3D` / `void` |
| [`useTransform(object, props)`](#usetransform) | inside Scene | `void` |
| `useMaterial`, `useMaterialInput`, `useMaterialOverrides` | inside Scene | see [Materials](https://matthiasbrandolin.dev/apricot/reference/materials#hooks) |
| `useModel`, `useTexture`, `useTextureState` | anywhere | see [Model](https://matthiasbrandolin.dev/apricot/reference/model) |
| `usePath`, `useTrip`, `useTripStatus` | anywhere | see [Motion](https://matthiasbrandolin.dev/apricot/reference/motion#paths) |

## `useScene`

Returns the closest scene's `ApricotScene`: `invalidate()`, `camera`, `scene`, `size`, `onResize()`, `ready`, `onReady()`, `report()`, `threeRenderer`. Throws outside `<Scene>`. See [Scene reference](https://matthiasbrandolin.dev/apricot/reference/scene#apricotscene).

Call `invalidate()` after changing three.js objects outside `useFrame` (in an event handler, a timer) when `frameloop="demand"`.

## `useFrame`

```ts
useFrame((state: { time: number; delta: number; frame: number }) => boolean | undefined)
```

Runs the callback before every rendered frame. `time` is seconds since the loop started; `delta` is seconds since the previous frame, **capped at 0.1** (so a pause does not make objects jump); `frame` counts rendered frames.

Return `true` while animating, to keep the scene rendering; return `false` (or nothing) to let it sleep until something else changes. The callback can change between renders without re-subscribing.

## `useAnimatable`

```ts
const read = useAnimatable(value); // value: T | SharedValue<T>
useFrame(() => { const now = read(); … });
```

Returns a reader for a prop that is a plain value or a Reanimated shared value (including `useDerivedValue`). Shared values are mirrored from the UI thread without blocking it, and every change wakes the scene. A new plain value wakes it too. Use it to make your own components' props accept shared values, the way Apricot's do.

`type Animatable<T> = T | DerivedValue<T>`.

## `useSceneTouches`

```ts
useSceneTouches(listener: SceneTouchListener, active = true)
```

Receives the fingers on the enclosing scene while `active`; the scene then claims touches that start on it (drags stop reaching views behind it). Taps on objects keep working.

| Listener method | Description |
| --- | --- |
| `touch(points, time)` | On every start and move. `points`: the fingers down now, `{ x, y }` in points. `time` in ms |
| `release(time)` | All fingers lifted. Return how far they moved, in points (taps barely move) |
| `wheel(deltaY)` | Optional. Mouse wheel on the web; `deltaY` > 0 is away from the user |

## `useParent` and `useAttach`

`useParent()` returns the three.js object new children attach to: the scene root or the closest `<Group>`, shape, model or behavior. `useAttach(object)` adds `object` to it while the component is mounted, requests a frame and warms up its shaders. Provide `ParentContext` with your object to make it the parent of your component's children.

## `useTransform`

```ts
useTransform(object, { position, rotation, scale })
```

Keeps a three.js object's transform in sync with transform props (plain or shared values). Unset values are left alone. `applyTransform(object, values)` does it once, outside React.

## Diagnostics

| Export | Description |
| --- | --- |
| `<Scene debug>` | fps, render and present time, and a Share button |
| `DebugHud` | The overlay itself: `<DebugHud stats={scene.stats} scene={scene} />` |
| `diagnosticsJson(scene, extra?)` | The scene's performance report with device details, as JSON text |
| `shareDiagnostics(scene, extra?)` | Opens the share sheet with that report (logs it where sharing is unavailable) |

## Related

- [Animation and shared values](https://matthiasbrandolin.dev/apricot/concepts/animation).
- [Custom geometry and behaviors](https://matthiasbrandolin.dev/apricot/guides/custom#your-own-scene-components).
