# Basic Usage

Fusion Player is a higher-level wrapper built on top of the [Lite Player](/en/miniapp/solution-ai/ability/camera-solution/ipc/lite-player/base). It supports pluggable Widget components and comes with a set of built-in control methods — ready to use out of the box.

## Business Fit

> If your business scenario requires built-in features like snapshot, recording, two-way talk, PTZ control, battery status display, etc., with no need to develop them from scratch, **Fusion Player** is your best choice.  
> Additionally, **Fusion Player** supports customization and extension to meet your personalized needs.

### Install Dependency

```bash
yarn add @ray-js/ipc-player-integration
```

### Basic Usage Example

```jsx
import { useCtx, IPCPlayerIntegration, Features } from '@ray-js/ipc-player-integration';

function Page() {
  const deviceId = '1234567890xxxxxx';
  
  const instance = useCtx({
    devId: deviceId,
  });
  return (
    <IPCPlayerIntegration
      instance={instance}
      devId={deviceId}
      style={{
        width: '100%',
        height: '300px'
      }}
    />
  )
}


```

### Accessing Player State

The player exposes a variety of data externally, such as whether it is currently in fullscreen mode, or whether two-way talk is active.  
For details, please refer to the `RetAtom` type data in the return value of the [useCtx](/en/miniapp/solution-ai/ability/camera-solution/ipc/fusion-player/api/01-instance#return-parameters-ctx) API.

To avoid unnecessary updates caused by unrelated data changes, the exposed data is wrapped with `jotai`.  

To access the actual state values, you need to use `useStore`.

```jsx
import { useEffect } from 'react'
import { useCtx, useStore, IPCPlayerIntegration } from '@ray-js/ipc-player-integration';
import '@ray-js/ipc-player-integration/iconfont/iconfont.css';
 
function Page() {
  const deviceId = '1234567890xxxxxx';

  const instance = useCtx({
    devId: deviceId,
  });
  
  const { screenType } = useStore({ screenType: instance.screenType });

  return (
    <IPCPlayerIntegration
      instance={instance}
      devId={deviceId}
    />
  )
}
```

## Widget

**Widget** is a customizable component rendered on top of the player.  
You can dynamically insert or remove widgets using instance methods like `addContent` and `deleteContent` returned from the `useCtx` hook.

The props of each **Widget** automatically receive the context object from the [useCtx hook](/en/miniapp/solution-ai/ability/camera-solution/ipc/fusion-player/api/01-instance#return-parameters-ctx), making it easy to access player state and control APIs within the component.

### Widget Zones


<Image  width="400px" src="https://static1.tuyacn.com/static/tuya-miniapp-doc/_next/static/images/panel/fusion-player-demo.png" />

**Widgets** are grouped into five main display areas:

1. **topLeft**: Top-left area  
2. **topRight**: Top-right area  
3. **bottomLeft**: Bottom-left area  
4. **bottomRight**: Bottom-right area  
5. **absolute**: Absolute positioning area

Widgets shown in the diagram — such as battery level, temperature & humidity, two-way talk, and fullscreen toggle — are common widgets provided by the platform.  
You can insert them easily via API, as demonstrated below:

### Usage Example

```jsx
import { useEffect } from 'react'
import { useCtx, IPCPlayerIntegration, Features } from '@ray-js/ipc-player-integration';
import '@ray-js/ipc-player-integration/iconfont/iconfont.css';
 
function Page() {
  const deviceId = '1234567890xxxxxx';
  const instance = useCtx({
    devId: deviceId,
  });

  useEffect(() => {
    // Initialize Widgets  
    // Calling this method will add all the widgets used in the project to the player
    Features.initPlayerWidgets(instance);
  }, [])

  return (
    <IPCPlayerIntegration
      instance={instance}
      devId={deviceId}
    />
  )
}
```

Calling `Features.initPlayerWidgets` will add the same **widgets** to the player as those on the current component.

The `Features.initPlayerWidgets` method accepts some parameters. For details, please refer to: [initPlayerWidgets](/en/miniapp/solution-ai/ability/camera-solution/ipc/fusion-player/api/04-initPlayerWidgets)


### Add Custom Widget

In real business scenarios, you may not use all built-in `Widgets`, but prefer one of the following approaches:

- ✅ Use only some functional components (e.g., intercom, screenshot)  
- 🔧 Extend custom features based on built-in components  
- 🛠️ Fully customize to meet specific business needs  

Next, we will build a **Demo** to help you get started quickly:

- ✅ Use the built-in **Voice Intercom Widget** of the player  
- 🛠️ Custom implement a **Screenshot Widget**  
- 📸 Show a **Toast notification** in the player after a successful screenshot  

```jsx
// index.tsx
import React, { useEffect, useRef } from 'react';
import { View } from '@ray-js/components';
import {
  IPCPlayerIntegration,
  useCtx,
  useStore,
  Widgets,
  ComponentConfigProps,
} from '@ray-js/ipc-player-integration';
import Styles from './index.module.less';
// Manually import the icons required by the Widget CSS
import '@ray-js/ipc-player-integration/iconfont/iconfont.css';

// Screenshot Button Widget
function ShotScreen(props: ComponentConfigProps) {
  const {
    IPCPlayerInstance,
    saveToAlbum,
    deleteContent,
    screenType: screenTypeAtom,
    addContent,
  } = props;
  const { screenType } = useStore({
    screenType: screenTypeAtom,
  });
  const timer = useRef(null);
  const timeToCloseToast = () => {
    clearInterval(timer.current);
    // @ts-ignore
    timer.current = setTimeout(() => {
      deleteContent('absolute', 'plugin-screenshot-toast');
    }, 5000);
  };

  const showShotToast = () => {
    // To ensure only one plugin-screenshot-toast is added, delete it first before adding
    deleteContent('absolute', 'plugin-screenshot-toast');

    // Add an absolutely positioned Widget,
    // Positioning is defined by the absolutePosition property and absoluteContentClassName type   
    addContent('absolute', {
      id: 'plugin-screenshot-toast',
      absoluteContentClassName: 'css name',
      absolutePosition: {
        position: 'absolute',
        top: '12px',
        left: '16px',
        right: '16px',
      },
      content: () => {
        return (
          <View
            style={{ color: '#fff', backgroundColor: '#000', width: '100%', textAlign: 'center' }}
          >
            ScreenShot Success
          </View>
        );
      },
    });

    // Remove plugin-screenshot-toast from the player after 5 seconds
    timeToCloseToast();
  };

  const handClick = () => {
    ty.authorize({
      scope: 'scope.writePhotosAlbum',
      success: success => {
        IPCPlayerInstance.snapshot({
          saveToAlbum,
          success: res => {
            console.log(res, 'res');
            showShotToast();
          },
        });
      },
    });
  };

  return (
    <View onClick={handClick} style={{ color: '#fff' }}>
      ScreenShot
    </View>
  );
}

export default function Page(props) {
  const devId = props.location.query.deviceId;
  const instance = useCtx({
    devId,
  });

  useEffect(() => {
    // Add the Widget provided by the component
    instance.addContent('topLeft', {
      id: 'Intercom',
      content: Widgets.VerticalSmallIntercom,
    });
    // Add the custom implemented Widget
    instance.addContent('bottomLeft', {
      id: 'ScreenShot',
      content: ShotScreen,
    });
  }, []);

  return (
    <View className={Styles.container}>
      <View className={Styles.playerWarp} style={{ marginTop: 300 }}>
        <IPCPlayerIntegration
          style={{ width: '100%', height: '300px' }}
          playerFit="cover"
          instance={instance}
          devId={instance.devId}
        />
      </View>
    </View>
  );
}

```

### Demo Preview

<Image width="400px" src="https://static1.tuyacn.com/static/tuya-miniapp-doc/_next/static/images/panel/player-widget-demo.png" />

For more advanced widget functionalities, please refer to: [Animation Widget](/en/miniapp/solution-ai/ability/camera-solution/ipc/fusion-player/advanced-guide/animation-widget)

## Event System

The event system is implemented using a **publish-subscribe** model.  
It allows communication between **Widgets**, or external components to receive information from **Widgets**, while keeping them decoupled.

The event system instance can be accessed from the return value of **useCtx**.  
Each player instance has its own independent event system.

```jsx
import { useCtx, IPCPlayerIntegration, Features } from '@ray-js/ipc-player-integration';
 
function Page() {

  const deviceId = '1234567890xxxxxx';

  const instance = useCtx({
    devId: deviceId,
  });
  const { event } = instance;
  
}
```
### Type Definition

```typescript
type Task = (...args) => void;

export type EventInstance = {
  on: (type: string, cb: Task) => void;
  off: (type: string, cb: Task) => void;
  emit: (type: string, ...args) => void;
};
```

### Usage Example

The following two Widgets are both registered to the player.

**Widget1**

```jsx
import React, { useEffect } from 'react';
import { View } from '@ray-js/components';
import {
  ComponentConfigProps,
} from '@ray-js/ipc-player-integration';
function Widget1(props: ComponentConfigProps) {
  const { event } = props;
  const handClick = () => {
    // Emit an event
    event.emit('event1', 'hello')
  }
  return (
    <View onClick={handClick}></View>
  )
}
```
**Widget2**

```jsx
import React, { useEffect } from 'react';
import { View } from '@ray-js/components';
import {
  ComponentConfigProps,
} from '@ray-js/ipc-player-integration';
function Widget2(props: ComponentConfigProps) {
  const { event } = props;
  const listen = (e) => {
    console.log(e) // hello
  }
  useEffect(() => {
    // Listen to an event
    event.on('event1', listen)
    return () => {
      event.off('event1', listen)
    }
  }, [listen])
  return (
    <View>hello world</View>
  )
}
```