# Troubleshooting

> Fixes for common Apricot problems, from setup (Expo Go, minSdk, simulators, Metro) to blank or slow scenes, models that fail to load, objects too small or missing, scenes that do not update, gestures inside scroll views, and every error message Apricot throws.

## Error messages

| Message | Cause | Fix |
| --- | --- | --- |
| `useScene() must be used inside <Scene>` | A hook ran in the component that **renders** `<Scene>`, or outside any scene | Move the hook into a child component rendered inside `<Scene>` ([Hooks](https://matthiasbrandolin.dev/apricot/reference/hooks)) |
| `Apricot components must be used inside <Scene>` | A shape, light, camera or model is rendered outside `<Scene>` | Put it inside a `<Scene>` |
| `Unknown material preset "x". Known: …` | A typo, or a custom preset used before `definePreset` ran | Use a listed name, or register the preset at startup ([Materials](https://matthiasbrandolin.dev/apricot/reference/materials)) |
| `Unknown environment "x". Known: …` | As above, for environments | `"studio"`, `"soft"`, `"sunset"`, `"night"`, `"none"`, or `defineEnvironment` first |
| `Unknown camera view "x". Known: …` | `view` names a view that is neither built-in nor in `views` | Add it to `views`, or pass a view object |
| `Unknown hinge word "x"` | A joint's `hinge` has a word other than `front`, `back`, `top`, `bottom`, `left`, `right`, `center` | Fix the word, or give a point `[x, y, z]` |
| `No animation "x" in this model. It has: …` | `animations` names a clip that is not in the file | Use a listed name (`npx apricot-models inspect`) |
| ``<Model> needs `src` or `kit` `` | Neither was given | Pass one |
| `A trip needs at least two stops` | `useTrip` with fewer than two `stops` | Give two or more distances |
| `A "loop" trip needs the path length` | `pattern: "loop"` without `path` | Pass `path` to `useTrip` |
| `A path needs at least two points` | `usePath` with fewer than two points | |
| `Pile needs at least one item to drop` | `<Pile>` has no mesh children | Give it a shape or asset |
| `mergeColoredParts: color "vertex" needs a color attribute` | A part uses `"vertex"` but its geometry has no colours | Give a colour instead |
| `WebGPU canvas context not available` | The canvas never got a size, or WebGPU is unavailable | Give the scene a size (`flex: 1` inside a sized parent, or a `height`); use a dev build |

Warnings (logged, not thrown):

| Warning | Meaning |
| --- | --- |
| `Material override "x" matches no part` | A `materials` key matches nothing: check names with `inspect` |
| `Joint "x" matches no part` | A joint's `select` matches nothing |
| `No shape key "x" in this model` | A `morphs` key is not in the file |
| `<Pile> drops meshes only; ignoring "x"` | A `<Pile>` child is a group or model. Use a single mesh |
| `Shader warm-up failed` | Shaders will compile on first draw instead; the scene still works |

## Setup

### The app crashes or shows nothing in Expo Go

Expo Go is not supported: react-native-webgpu needs native code. Build a development build: `npx expo prebuild`, then `npx expo run:ios` or `npx expo run:android`. See [Installation](https://matthiasbrandolin.dev/apricot/installation).

### Android build fails on `minSdkVersion`

react-native-webgpu needs Android 8.0 (API 26). Add `"@apricot/react"` to your config plugins (it raises `minSdkVersion` to 26), then run `npx expo prebuild` again.

### The iOS simulator crashes on start

The simulator needs Metal API validation off; the config plugin does this through react-native-webgpu. Check that `"@apricot/react"` is in `plugins` and prebuild again. Simulators are much slower than devices: judge performance on a phone, in a release build.

### `require("./model.glb")` fails to resolve

Metro does not bundle `.glb` files by default. Wrap your config with `withApricot` in `metro.config.js` and restart Metro with `--clear`.

### Two copies of three.js, or "multiple instances of three" warnings

`withApricot` resolves `three` and `three/webgpu` to one build. Make sure it wraps your final Metro config, and that only one `three` version is installed (`npm ls three`).

## Blank, black or slow scenes

### The scene is blank for a moment after it mounts

Normal: the GPU starts, then shaders compile in the background (about a second on a phone, up to 4 s), and frames show only the background meanwhile. Show your own placeholder with `loading={…}` or wait for `onReady`.

### The scene stays blank

- The scene has no size. A `<Scene style={{ flex: 1 }}>` inside a parent without a height is 0 tall. Give the parent `flex: 1` or the scene a `height`.
- The camera is inside or behind the object. The default camera is at `[0, 0, 6]` looking at the origin; an object larger than about 4 units fills or passes it. Move the camera back or use `<FitCamera>` / `<CameraRig>`.
- The object is beyond the camera's `far` plane (default 200). Raise `camera.far`.
- `look="none"` with no lights, environment or `<Daylight>`: everything is black. Add one.

### Metal objects look black or flat

Metals reflect their surroundings; the looks use plain lights. Add `environment="studio"` (or another) to the scene, usually with `look="none"`.

### Glass is invisible

Glass shows what is behind it; over a plain background it shows nothing. Put `<Backdrop>` or other objects behind it.

### Objects are too small or too big

Units are metres: a 1-unit box is a metre wide, seen from 6 m away by default. Scale your models in Blender to real size, or frame them with `<CameraRig>` inside the `<Model>` (it fits the subject at any size). For a `<Pile>`, `scale` is relative to each child, and with the recipe's camera the screen is about 10 units tall.

### A model appears lying down, upside down or facing away

Apricot expects y up and the front facing +z. Fix it in Blender, or wrap it: `<Group rotation={[-Math.PI / 2, 0, 0]}><Model … /></Group>`. To stand it on the floor, use `ground`.

### The frame rate is low

Count draw calls: every separate mesh costs about 80 µs per frame on a mid-range phone. Use `<Instances>` for repeats, merge model parts in Blender, keep models under 150,000 triangles, and use `frameloop="demand"` (the default) so idle scenes do not render. Turn on `debug` to see fps and render time. See [Performance](https://matthiasbrandolin.dev/apricot/concepts/performance).

## Models and textures

### A model never appears

`<Model>` renders nothing until it has loaded, and its children wait too. Add `onError={(e) => console.warn(e)}` to see why:

- Draco, meshopt or KTX2 compression: Hermes cannot decode them. Run the file through `npx apricot-models`, which decodes them on your computer.
- A `.gltf` with a separate `.bin` file: convert it to `.glb` with `apricot-models`.
- A URL that needs headers, or a path typed as a string instead of `require(...)`. Bundled files must use `require`.

### Material overrides or joints do nothing

The selector matches nothing (a warning is logged). List the real names with `npx apricot-models inspect file.glb`, or tap parts with `<Model inspect>`. `material:` selectors match the material name in the file; plain patterns match node **or** material names.

### A door turns around the wrong edge

`hinge` words refer to the part's bounds with the model facing +z: `front` is +z, `left` is +x. Try the opposite word, swap the sign of `range`, or give an exact point.

### A texture shows the wrong colours or is black

Use `color: "#ffffff"` with `map` (the image multiplies the colour). For masks and data images, pass `colorSpace: NoColorSpace`. PNG and JPEG only.

## Updates and animation

### Changing a three.js object does nothing

With `frameloop="demand"`, the scene renders only when Apricot knows something changed. After changing an object through a ref outside `useFrame`, call `useScene().invalidate()`. Or drive it with props, shared values or `useFrame`, which wake the scene themselves.

### An animation in `useFrame` stops after a moment

The callback returned `false` or nothing. Return `true` while it should keep moving.

### Changing a `<Scene>` prop has no effect

Scene options are read once, at mount (except `frameloop`). Change the scene's `key` to remount it, or use `<Environment>`, `<Daylight>` or a camera component, which change live. The same applies to `<Vehicle>` and `<FollowCamera>` options.

### Shared value props jitter or lag

Use `useSharedValue` / `useDerivedValue` from Reanimated (not React state) for values that change every frame, and type tuples as `readonly [number, number, number]`.

## Gestures

### Orbiting does not work inside a `ScrollView` on iOS

iOS cannot block a scroll view from JavaScript. Turn scrolling off while a finger is on the scene: `onOrbitStart={() => setScrolls(false)}` and `onOrbitEnd={() => setScrolls(true)}` with `<ScrollView scrollEnabled={scrolls}>`. See [Camera](https://matthiasbrandolin.dev/apricot/guides/camera#inside-a-scrollview-or-pager).

### Gestures do nothing

Wrap the app root in `GestureHandlerRootView` from react-native-gesture-handler, with `style={{ flex: 1 }}`.

### Taps do not reach the screen behind an overlay scene

Give the overlay `transparent` and `pointerEvents="none"`.

## Still stuck

Turn on `<Scene debug>` and use the Share button (or `shareDiagnostics(scene)`) to export a performance report with frame times, scene contents and GPU details.
