# Asset Hooks

PlayCanvas React provides hooks for loading and managing different assets. These hooks simplify the process of loading assets and allow you to handle loading and error states.

The general signature of every hook looks something like the following.

```tsx
const { asset, loading, error } = useModel(src, props);
```

Where `src` is the URL of the asset and `props` are additional properties to pass to the asset loader.

```tsx copy filename="render-glb.tsx"
import { useModel } from '@playcanvas/react/hooks';

export function RenderAsset() {
    const { asset, loading, error } = useModel('model.glb');

    if (loading) return <LoadingSpinner />;
    if (error) return <ErrorMessage message={error} />;
    if (!asset) return null;

    return <Render asset={asset} />;
}
```

## Loading Progress

The `useAsset` hook supports loading progress via the `subscribe` callback. This is useful if you want to show a loading indicator or update a progress bar. Not all asset types return a progress value during load, so this is not guaranteed to be available for all asset types.

```tsx copy filename="render-splat.tsx"
import { useSplat } from '@playcanvas/react/hooks';

export function RenderSplat() {
  const [progress, setProgress] = useState(0);
  const { asset, loading, error, subscribe } = useSplat('splat.ply');

  // Subscribe to loading progress
  useEffect(() => {
    const unsubscribe = subscribe(({ progress }) => setProgress(progress));
    return () => unsubscribe();
  }, [subscribe]);

  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage message={error} />;
  if (!asset) return null;

  return (<Entity>
    <GSplat asset={asset} />
  </Entity>);
}
```

### All Hooks

The following hooks are available:

- [`useModel`](https://developer.playcanvas.com/user-manual/react/api/hooks/use-asset.md#usemodel) - Load a 3D model asset
- [`useSplat`](https://developer.playcanvas.com/user-manual/react/api/hooks/use-asset.md#usesplat) - Load a Gaussian Splat asset
- [`useTexture`](https://developer.playcanvas.com/user-manual/react/api/hooks/use-asset.md#usetexture) - Load a texture asset
- [`useEnvAtlas`](https://developer.playcanvas.com/user-manual/react/api/hooks/use-asset.md#useenvatlas) - Load an environment atlas texture
- [`useAsset`](https://developer.playcanvas.com/user-manual/react/api/hooks/use-asset.md#useasset) - Generic hook for loading any type of asset

## API

This is the full response of an asset hook.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `asset` | `Asset<string> \| null` | `null` | The loaded asset, or null if not loaded or failed |
| `loading` | `boolean` | `true` | Whether the asset is currently loading, or false if it has loaded or failed |
| `error` | `string \| null` | `null` | Error message if loading failed, or null if successful |
| `subscribe` | `(cb: AssetResultCallback) => () => void` | - | Use this to subscribe to loading progress events |

## useModel

A specialized hook for loading 3D model assets (GLB/GLTF). Pass the source URL of the model file and any additional properties to pass to the asset loader and use the resulting asset in the `<Render/>` component.

```tsx copy filename="render-model.tsx"
import { useModel } from '@playcanvas/react/hooks';

export function RenderModel() {
  const { asset, loading, error } = useModel('model.glb');

  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage message={error} />;
  if (!asset) return null;

  return <Render asset={asset} />;
}
```

### Draco Decoding

The `useModel` hook also supports Draco decoding out of the box with zero configuration. @playcanvas/react will use the latest version of the Draco decoder ([1.5.7](https://github.com/google/draco?tab=readme-ov-file#version-157-release)) and lazy load it from the Google CDN.

Alternatively if you want to self-host the library you can manually configure the decoder using `dracoInitialize`.

```tsx copy filename="render-draco.tsx"
import { dracoInitialize } from 'playcanvas';

dracoInitialize({
  jsUrl: '/draco_decoder.js',
  wasmUrl: '/draco_decoder.wasm',
  lazyInit: true
});
```

## useSplat

A specialized hook for loading Gaussian Splat assets. Pass the source URL of the splat file and any additional properties to pass to the asset loader and use the resulting asset in the [`<GSplat/>`](https://developer.playcanvas.com/user-manual/react/api/gsplat.md) component.

```tsx copy filename="render-splat.tsx"
import { useSplat } from '@playcanvas/react/hooks';

export function RenderSplat() {
  const { asset, loading, error } = useSplat('splat.ply');
  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage message={error} />;
  if (!asset) return null;

  return (<Entity>
    <GSplat asset={asset} />
  </Entity>);
}
```

See the [`<GSplat/>`](https://developer.playcanvas.com/user-manual/react/api/gsplat.md) component for more information.

## useTexture

A specialized hook for loading texture assets. Pass the source URL of the texture file and any additional properties to pass to the asset loader and use the resulting asset in any component that accepts a texture.

```tsx copy filename="render-texture.tsx"
import { useTexture } from '@playcanvas/react/hooks';
import { useMaterial } from '@playcanvas/react/hooks';

export function RenderTexture() {
  const { asset, loading, error } = useTexture('texture.jpg');
  const material = useMaterial({ diffuseMap: asset?.resource });

  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage message={error} />;
  if (!asset) return null;

  return <Render type="box" material={material} />;
}
```

See the [useMaterial](https://developer.playcanvas.com/user-manual/react/api/hooks/use-material.md) hook and [Render](https://developer.playcanvas.com/user-manual/react/api/render.md) component for more information.

## useEnvAtlas

A specialized hook for loading environment atlas textures. Pass the source URL of the texture file and any additional properties to pass to the asset loader and use the resulting asset in the [`<Environment/>`](https://developer.playcanvas.com/user-manual/react/api/environment.md) component.

```tsx copy filename="render-env-atlas.tsx"
import { useEnvAtlas } from '@playcanvas/react/hooks';
import { Environment } from '@playcanvas/react/components';

export function RenderEnvAtlas() {
  const { asset, loading, error } = useEnvAtlas('env.jpg');

  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage message={error} />;
  if (!asset) return null;

  return <Environment envAtlas={asset} />;
}
```

See the [Environment](https://developer.playcanvas.com/user-manual/react/api/environment.md) component for more information.

## useFont

Text in PlayCanvas is drawn with multi-channel signed distance field (MSDF) fonts, so a TTF or OTF font is first converted into a font asset: a `.json` file and one or more `.png` textures. Create them with [font-tools](https://github.com/playcanvas/font-tools), in its [web app](https://playcanvas.github.io/font-tools/) or from the command line, and serve them with your app, for example from the `public` folder of a Vite project:

```bash
npx @playcanvas/font-tools Inconsolata.ttf --charset latin -o public/fonts/inconsolata
```

Then load the `.json` file with `useFont`, which loads its textures too, and give the asset to a text element:

```tsx copy filename="render-font.tsx"
import { Entity } from '@playcanvas/react';
import { Element } from '@playcanvas/react/components';
import { useFont } from '@playcanvas/react/hooks';

export function RenderText() {
  const { asset, loading, error } = useFont('fonts/inconsolata.json');

  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage message={error} />;
  if (!asset) return null;

  return (
    <Entity name="label">
      <Element type="text" fontAsset={asset} text="Hello, World!" />
    </Entity>
  );
}
```

See [Fonts](https://developer.playcanvas.com/user-manual/user-interface/fonts.md) for choosing the characters that a font holds, and [Text Elements](https://developer.playcanvas.com/user-manual/user-interface/text-elements.md) for drawing text on a screen.

## useAsset

This is a generic hook for loading any type of asset. You can use it to load any asset type that PlayCanvas supports which is sometimes useful if you need to load an asset dynamically.

```tsx copy filename="use-dynamic-asset.tsx"
import { useAsset } from '@playcanvas/react/hooks';

const assetTypeToLoadType = {
    'ply': useSplat,
    'jpg': useTexture,
    'png': useTexture,
    'glb': useModel,
    'gltf': useModel,
}

export function useDynamicAsset(src: string, props: Record<string, unknown> = {}) {

  const mimeType = src.split('.').pop();
  const loadType = assetTypeToLoadType[mimeType];

  if (!loadType) {
    throw new Error(`Unsupported asset type: ${mimeType}`);
  }

  return useAsset(src, loadType, props);
}
```
