# Installation

> Add Apricot to an Expo app. You need a development build, the WebGPU and Reanimated peer libraries, the Apricot config plugin, and one line in metro.config.js.

> [!IMPORTANT]
> Apricot is in preview and **not published to npm yet**. Until `0.1.0` is released, install the packages from the Apricot repository (for example as a workspace or with `npm pack`). Everything else on this page applies unchanged.

## Requirements

| Requirement | Version | Why |
| --- | --- | --- |
| Expo SDK | 57 | Apricot targets the current SDK and its config plugins. |
| React Native | 0.86 or later, New Architecture | `react-native-webgpu` and Reanimated 4 need it. |
| React | 19 | |
| Development build | required | **Expo Go is not supported**: it cannot load the native WebGPU module. |
| iOS | a device or the simulator | The config plugin turns off Metal API validation for the simulator via `react-native-webgpu`. |
| Android | 8.0+ (API 26) | `react-native-webgpu` uses `AHardwareBuffer`. The config plugin raises `minSdkVersion` for you. |

## 1. Install the packages

```sh
npx expo install react-native-webgpu react-native-reanimated react-native-worklets expo-asset expo-file-system react-native-gesture-handler
npm install three@0.186
npm install @apricot/react @apricot/assets @apricot/core
npm install --save-dev @apricot/metro
```

| Package | Required | Used for |
| --- | --- | --- |
| `@apricot/react` | yes | Every component and hook. |
| `@apricot/core` | yes (installed with `@apricot/react`) | The engine; import utilities such as `seededRandom` from it. |
| `@apricot/assets` | optional | Ready-made objects (`MoneyStack`, `Apple`, `Car`, `Card`…). |
| `@apricot/metro` | yes, as a dev dependency | `withApricot()` for Metro, and the `apricot-models` CLI. |
| `react-native-webgpu` | yes | The GPU canvas (Dawn: Metal on iOS, Vulkan on Android). |
| `three` | yes, r186 | The renderer Apricot drives. Apps rarely import it directly. |
| `react-native-reanimated`, `react-native-worklets` | yes | Shared values: every animatable prop accepts one. |
| `expo-asset`, `expo-file-system` | yes | Loading bundled `.glb` models and images in release builds. |
| `react-native-gesture-handler` | for gestures | The recipes use it for swipes, drags and the joystick. |

Versions the Apricot playground is tested with: `expo` 57.0.27, `react-native` 0.86.3, `react` 19.2.3, `react-native-webgpu` 0.12.1, `three` 0.186.1, `react-native-reanimated` 4.5.1, `react-native-worklets` 0.10.1, `react-native-gesture-handler` 2.32.0.

## 2. Add the config plugin

The plugin applies `react-native-webgpu`'s own plugin, sets Android `minSdkVersion` to at least 26, and lets iOS ProMotion screens run at 120 Hz.

```js title="app.config.js"
module.exports = {
  expo: {
    name: "My App",
    slug: "my-app",
    plugins: ["@apricot/react"],
  },
};
```

With `app.json`, add `"@apricot/react"` to `expo.plugins` the same way.

## 3. Configure Metro

`withApricot` makes Metro bundle `.glb` and `.gltf` files as assets, and resolves every `three` import to the WebGPU build so the bundle holds one copy of three.

```js title="metro.config.js"
const { getDefaultConfig } = require("expo/metro-config");
const { withApricot } = require("@apricot/metro");

module.exports = withApricot(getDefaultConfig(__dirname));
```

## 4. Wrap the app for gestures

If you use gestures (the recipes do), wrap the root of the app once:

```tsx title="app/_layout.tsx"
import { Stack } from "expo-router";
import { GestureHandlerRootView } from "react-native-gesture-handler";

export default function Layout() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <Stack />
    </GestureHandlerRootView>
  );
}
```

No Babel changes are needed: `babel-preset-expo` already includes the Reanimated / worklets plugin.

## 5. Build and run

Native code changed, so build a development client:

```sh
npx expo prebuild
npx expo run:ios      # or: npx expo run:android
```

Then start Metro for later JavaScript changes:

```sh
npx expo start --dev-client
```

> [!TIP]
> Judge performance in a **release** build on a real device (`npx expo run:ios --configuration Release --device`, `npx expo run:android --variant release --device`). Debug builds and simulators are much slower and do not reflect what users see.

## 6. Check it works

Render a scene on any screen:

```tsx title="app/index.tsx"
import { Box, Scene, Spin } from "@apricot/react";

export default function Home() {
  return (
    <Scene style={{ flex: 1 }} debug>
      <Spin speed={1}>
        <Box size={1.6} color="#ff9f59" />
      </Spin>
    </Scene>
  );
}
```

You should see an orange cube turning on a cream background, and `debug` adds a small HUD with fps, render and present times. The first second shows only the background while shaders compile: that is expected (see [Scenes](https://matthiasbrandolin.dev/apricot/concepts/scenes#loading-and-the-first-frame)).

If something fails, see [Troubleshooting](https://matthiasbrandolin.dev/apricot/troubleshooting).

## Next

- [Quick start](https://matthiasbrandolin.dev/apricot/quick-start): build a scene step by step.
- [Building with AI](https://matthiasbrandolin.dev/apricot/ai): rules for AI assistants writing Apricot code.
