open-index/open-npm huggingface dataset:
npm package: @netless/appliance-extend-auto-draw-plugin
Description: 一个智能自动绘图插件，用于 Netless Appliance，可自动识别手绘草图并推荐匹配的图标。
Author: hqer
Latest version: 0.0.2

# @netless/appliance-extend-auto-draw-plugin

一个智能自动绘图插件，用于 Netless Appliance，可自动识别手绘草图并推荐匹配的图标。

## 功能特性

- 🎨 **自动草图识别**：使用铅笔工具绘制时自动分析手绘草图
- 🤖 **双重识别模式**：
  - Google 手写识别 API，基于笔迹数据快速识别
  - OpenRouter 多模态 AI 模型，基于图像的高级识别
- 🎯 **图标推荐**：根据识别结果从 Iconify 获取匹配的图标
- ⚡ **智能替换**：一键将手绘草图替换为专业图标
- ⏱️ **可配置延迟**：可自定义识别触发前的延迟时间（默认：2000ms）

## 安装

```bash
npm install @netless/appliance-extend-auto-draw-plugin
# 或
pnpm add @netless/appliance-extend-auto-draw-plugin
# 或
yarn add @netless/appliance-extend-auto-draw-plugin
```

## 使用方法

### 基础用法

```typescript
import { AutoDrawPlugin } from '@netless/appliance-extend-auto-draw-plugin';

// 创建一个容器用于显示图标建议
const iconsContainer = document.createElement('div');
document.body.appendChild(iconsContainer);

// 初始化插件
const autoDrawPlugin = new AutoDrawPlugin({
  container: iconsContainer,
  delay: 2000, // 可选：识别前的延迟时间（毫秒）
});

// 将插件挂载到你的 appliance control
control.pluginManager.addPlugin(autoDrawPlugin);
autoDrawPlugin.mount();
```

### 使用 OpenRouter API 的高级用法

使用 AI 视觉模型进行更准确的识别：

```typescript
import { AutoDrawPlugin } from '@netless/appliance-extend-auto-draw-plugin';

const iconsContainer = document.createElement('div');
document.body.appendChild(iconsContainer);

const autoDrawPlugin = new AutoDrawPlugin({
  container: iconsContainer,
  apiKey: 'your-openrouter-api-key',
  customModel: 'openai/gpt-4o', // 可选：指定自定义模型
  delay: 2000,
  uploadFile: async (file: File) => {
    // 将文件上传到你的 OSS 服务器并返回 URL
    const formData = new FormData();
    formData.append('file', file);
    const response = await fetch('https://your-oss-server.com/upload', {
      method: 'POST',
      body: formData,
    });
    const data = await response.json();
    return data.url; // 返回图片 URL
  },
});

control.pluginManager.addPlugin(autoDrawPlugin);
autoDrawPlugin.mount();
```

## API

### `AutoDrawPlugin`

#### 构造函数选项

```typescript
interface AutoDrawOptions {
  /** 用于访问 OpenRouter 所有模型的 API 密钥 */
  apiKey?: string;
  /** 自定义使用的模型 */
  customModel?: string;
  /** 用于渲染图标的容器 */
  container: HTMLDivElement;
  /** 渲染图标的延迟时间，默认为 2000ms */
  delay?: number;
  /**
   * 将文件上传到 OSS 服务器并返回 URL 地址，如果返回 undefined 则不会使用此功能
   * @param file 文件对象
   * @returns 图片 URL 字符串
   */
  uploadFile?: (file: File) => Promise<string | undefined>;
}
```

#### 方法

- `mount()`: 挂载插件并开始监听绘制事件
- `unMount()`: 卸载插件并清理资源
- `onDestroy()`: 插件销毁时调用

## 工作原理

1. **绘制检测**：插件监控铅笔工具的使用并跟踪手绘笔触
2. **识别触发**：绘制停止后，经过可配置的延迟时间（默认 2000ms）后触发识别
3. **识别过程**：
   - **模式 1（Google API）**：直接使用 Google 手写识别 API 分析笔迹数据
   - **模式 2（OpenRouter）**：捕获绘制区域的快照，上传后使用 AI 视觉模型识别内容
4. **图标获取**：根据识别结果，从 Iconify 获取匹配的图标
5. **图标显示**：在提供的容器中显示建议的图标
6. **图标选择**：用户点击图标时，手绘草图会被替换为选中的图标

## 依赖要求

- `@netless/appliance-plugin` >= 1.1.26

## 许可证

MIT
npm package: @netless/canvas-polyfill
Description: a polyfill for canvas getTransform, ellipse, resetTransform API
Author: leavesster
Latest version: 0.0.4

# @netless/canvas-polyfill

`@netless/canvas-polyfill` is a polyfill for `resetTransform`,`ellipse`,`getTransform`. It is inspired by [canvas-5-polyfill](https://github.com/google/canvas-5-polyfill), [canvas-currentTransform](https://github.com/goessner/canvas-currentTransform/blob/master/currentTransform.js).

This polyfill can work in Android 19 WebView and iOS 10 WKWebView.

## different from these

[canvas-5-polyfill](https://github.com/google/canvas-5-polyfill) implement polyfill for `Path2D` objects and `ellipse()` on `CanvasRenderingContext2D` which doesn't implement `getTransform`. `@netless/canvas-polyfill` doesn't implement `Path2D`, but implement `getTransform`.

[canvas-currentTransform](https://github.com/goessner/canvas-currentTransform/blob/master/currentTransform.js) 's `setTransform` has some problem. `@netless/canvas-polyfill` just fix it and `canvas-currentTransform` not implement `getTransform`. But the `currentTransform` 's `getter` is same as `getTransform`.

## Installation

```shell
yarn install @netless/canvas-polyfill
# or
npm install @netless/canvas-polyfill
```

Use:

```javascript
import "@netless/canvas-polyfill";
```

## Publish

```shell
npm publish --access public
```

## the implement for getTransform

The matrix calculation is just copy from [canvas-currentTransform](https://github.com/goessner/canvas-currentTransform/blob/master/currentTransform.js) for `currentTransform`.  I just fix `setTransform` method which has two forms of parameters:

```ts
interface CanvasTransform {
    setTransform(a: number, b: number, c: number, d: number, e: number, f: number): void;
    setTransform(transform?: DOMMatrix2DInit): void;
}
```
npm package: @netless/css-line-break
Description: css-line-break ==============
Author: Niklas von Hertzen
Latest version: 2.0.1

css-line-break
==============

![CI](https://github.com/niklasvh/html2canvas/workflows/CI/badge.svg?branch=master)
[![NPM Downloads](https://img.shields.io/npm/dm/css-line-break.svg)](https://www.npmjs.org/package/css-line-break)
[![NPM Version](https://img.shields.io/npm/v/css-line-break.svg)](https://www.npmjs.org/package/css-line-break)

A JavaScript library for Line Breaking and identifying Word Boundaries, 
[implementing the Unicode Line Breaking Algorithm (UAX #14)](http://unicode.org/reports/tr14/)  

>> Line breaking, also known as word wrapping, is the process of breaking a section of text into 
lines such that it will fit in the available width of a page, window or other display area. 
The Unicode Line Breaking Algorithm performs part of this process. Given an input text, 
it produces a set of positions called "break opportunities" that are appropriate points to 
begin a new line. The selection of actual line break positions from the set of break opportunities 
is not covered by the Unicode Line Breaking Algorithm, but is in the domain of higher level 
software with knowledge of the available width and the display size of the text.

In addition, the module implements CSS specific tailoring options to line breaking as 
defined in [CSS Text Module Level 3](https://www.w3.org/TR/css-text-3/#line-breaking).

### Installing
You can install the module via npm:

    npm install css-line-break
  
### Usage
The `LineBreaker` creates an [iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators) that returns `Break`s for a given text.

    LineBreaker(text, [options]);
    
### Example
[JSFiddle](https://jsfiddle.net/ofd3752k)
```javascript
import {LineBreaker} from 'css-line-break';

const breaker = LineBreaker('Lorem ipsum lol.', {
    lineBreak: 'strict',
    wordBreak: 'normal'
});

const words = [];
let bk;

while (!(bk = breaker.next()).done) {
    words.push(bk.value.slice());
}

assert.deepEqual(words, ['Lorem ', 'ipsum ', 'lol.']);
```    
### Options
The following parameters are available for the options:

 - `lineBreak`: `normal` | `strict`
 - `wordBreak`: `normal` | `break-all` | `break-word` | `keep-all`
 
For more information how they affect the line breaking algorithms, 
check out [CSS Text Module Level 3](https://www.w3.org/TR/css-text-3/#line-breaking).

### Testing
You can run the test suite with:

    npm test

The library implements all the [LineBreakTest.txt tests](http://www.unicode.org/Public/10.0.0/ucd/auxiliary/LineBreakTest.txt) 
 and a number of CSS web-platform-tests.
npm package: @netless/cursor-icon
Description: > https://www.npmjs.com/package/@netless/white-video-plugin
Author: netless
Latest version: 0.0.1

# white-video-plugin

> https://www.npmjs.com/package/@netless/white-video-plugin

## 一、在白板初始化的时候注册 plugin

**初始化 SDK 的时候注入 plugin 代码**

```typescript
whiteWebSdk = new WhiteWebSdk({ 
deviceType: "desktop",
handToolKey: " ",
plugins: [WhiteVideoPlugin] // 在 new WhiteWebSdk 对象的时候注册完成
});
```

## 二、声明身份

**什么身份，以便控制 plugin 的编辑操作权限，目前声明后不再支持改变**

userId：string // 必填
identity："host" | "guest" // 必填，有操作权限者为 "host"，观看者为 "guest"

代码
```typescript
whiteWebSdk.joinRoom({
                    uuid: uuid,
                    roomToken: roomToken,
                    cursorAdapter: this.cursor,
                    userPayload: {
                        userId: userId, // 必填
                        identity: identity,// 必填
                        name: userName,
                        avatar: userAvatarUrl,
                   
                    }}）
```

## 二、声明身份

**什么身份，以便控制 plugin 的编辑操作权限，目前声明后不再支持改变**

userId：string // 必填
identity："host" | "guest" // 必填，有操作权限者为 "host"，观看者为 "guest"

## 三、插入 plugin

**将 plugin 插入白板**

```typescript
room.insertPlugin({
                protocal: "video", // 视频必须填写为 Video
                centerX: 0, // 插入位置 x
                centerY: 0, // 插入位置 y
                width: 480, // 宽 witdh
                height: 270, // gao height
                props: {
                    videoUrl: url, // 视频地址
                },
            });
```
npm package: @netless/cursor-tool
Description: ## 实时房间装载
Author: netless
Latest version: 0.1.1

# Cursor Tool

## 实时房间装载

```typescript
    const cursorAdapter = new CursorTool(); // Step1：初始化（必选）
    const room = await whiteWebSdk.joinRoom({
            uuid: uuid,
            roomToken: roomToken,
            cursorAdapter: cursorAdapter, // Step2：载入（必选）
            userPayload: {
                userId: userId,
                cursorName: cursorName, // Step4：cursorName 显示名称
                avatar: "url", // Step5：avatar 显示头像地址
            },
            ...
        },
        {
            onPhaseChanged: phase => {
                this.setState({phase: phase});
            },
            ...
        });
    cursorAdapter.setRoom(room); // Step3：装载 room 实例（必选）
```

## 回放房间装载


```typescript
        const cursorAdapter = new CursorTool(); // Step1：初始化（必选）
        const player = await whiteWebSdk.replayRoom(
            {
                room: uuid,
                roomToken: roomToken,
                cursorAdapter: cursorAdapter, // Step2：载入（必选）
                ...
            }, {
                onPhaseChanged: phase => {
                    this.setState({phase: phase});
                },
                ...
            });
        cursorAdapter.setPlayer(player); // Step3：装载 player 实例（必选）
```
npm package: @netless/devops-scripts
Description: ## How to use
Author: leavesster
Latest version: 0.0.7

# docker-scripts

## How to use

* develop

```typescript
const docker = new Docker({auth: 'https://registry.domain.com', namespace: "mynamespace"});
docker.buildAndPush("dockerfilePath", "imageName", "latest" || ["latest", "1.0.0-commit"], true);

// if you image not change, you need patch, deployK8s do patch for you
deployK8s("k8s-dev", "repo", "/app.yaml", "deployment-name","namespace");
// or just patch, because image not change
patchDeployment("k8s-cluster", "demo", "default");
```

* yaml repo

```typescript
import {gitDiff, applyDiff, SSHConfig} from "./src";

const config: SSHConfig = {host: "k8s-cluster"};
(async () => {
    await applyDiff(config, gitDiff());
})();
```

## TODO:

- [ ] delete `D` yaml's deployment statefulset ingress service
- [ ] support handle all yaml kind, not just first
- [ ] check kind support operation
- [ ] deployK8s not need deployment and name, just need yaml.
npm package: @netless/docker-script
Description: 构建私有仓库的 docker image 以及 k8s 部署的命令。
Author: leavesster
Latest version: 0.0.4

## docker-scripts

构建私有仓库的 docker image 以及 k8s 部署的命令。

涉及 docker 时，需要传入 docker Registry 信息：

```ts
docker tag IMAGE[:TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]
```

## How to use

```js
import {Docker, buildAndPush, deployK8s, patchDeployment} from "@netless/docker-script";

const docker = new Docker({registry: "registry", namespace: "命名空间"});
buildAndPush(docker, dockerfilePath, imageName, tag | tags, deleteAfter);

deployK8s(cluster, dirInCluster, ymlPath, deployment, namespace);
// or
patchDeployment(cluster, deployment, namespace);
```
npm package: @netless/electron-extension-vendor
Description: ## Usage
Author: Black-Hole1
Latest version: 1.0.3

# electron-extension-vendor

## Usage

```typescript
import { REACT_DEVTOOLS } from "@netless/electron-extension-vendor";

// return extension folder path
console.log(REACT_DEVTOOLS);
```

## Add New Extension

```shell
# this is example
$ yarn run add fmkadmapgofadopljbjfkapdkoienihi --name react-devtools
```
npm package: @netless/eslint-plugin
Description: The coding style used by the netless development team
Author: Black-Hole
Latest version: 2.0.0

# @netless/eslint-plugin

The coding style used by the netless development team

## Rule:

case-curly-brace: [docs](https://github.com/netless-io/eslint-plugin/blob/master/docs/rules/case-curly-brace.md)

static-resources-variable-name: [docs](https://github.com/netless-io/eslint-plugin/blob/master/docs/rules/static-resources-variable-name.md)
npm package: @netless/eslint-plugin-netless
Description: The coding style used by the netless development team
Author: Black-Hole
Latest version: 1.0.0

# eslint-plugin-netless

The coding style used by the netless development team


## Rule:

case-curly-brace: [docs](https://github.com/netless-io/eslint-plugin-netless/blob/master/docs/rules/case-curly-brace.md)
npm package: @netless/extension-flat
Description: download and unzip crx file
Author: Black-Hole1
Latest version: 1.0.1

# extension-flat

Download and unzip crx file

## CLI

```txt
Usage: extension-flat hash --name=NAME [option ...]

  Download and unzip crx file

    --help         display this usage info
    --name         folder name
    --remove       delete crx file after unzip complate
    --crxDir       crx folder
    --output       output path
```

## API

```javascript
/**
 * @param {object} config
 * @param {string} config.extensionHash - extension id (e.g. fmkadmapgofadopljbjfkapdkoienihi)
 * @param {string} config.outputFolder - output folder
 * @param {boolean} [config.deleteCRX] - delete crx file after unzip complate
 * @param {string} [config.crxFolder] - crx folder
 * @param {string} config.folderName - folder name
 */
```
npm package: @netless/i18n-react-router
Description: a react router middleware
Author: alwaysmavs
Latest version: 1.0.9

# @netless/i18n-react-router

> a react router middleware

[![NPM](https://img.shields.io/npm/v/@netless/i18n-react-router.svg)](https://www.npmjs.com/package/@netless/i18n-react-router) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)

## Install

```bash
npm install --save @netless/i18n-react-router
```

## Usage

```tsx
import * as React from 'react'

import MyComponent from '@netless/i18n-react-router'

class Example extends React.Component {
  render () {
    return (
      <MyComponent />
    )
  }
}
```

## License

MIT © [alwaysmavs](https://github.com/alwaysmavs)
npm package: @netless/mini-sdk
Description: white-web-sdk without videojs
Author: Tao Zeyu
Latest version: 2.3.6

# white-web-sdk

white-web-sdk 对外发布仓库。

`release-umd`: 发布 npm 包，不包括在 `externals.js` 申明的依赖，通过 npm 管理引用。
`release-var`: 整体打包，包含 `externals.js` 依赖，通过 script 引用，直接使用全局变量访问。
`dist`: tsc 输出文件夹。
`build`: webpack 输出文件夹。`umd` 与 `var` 都会导出在 `dist` 文件。
npm package: @netless/mp-component-webpack-plugin
Description: a webpack plugin for kbone component
Author: netless
Latest version: 1.0.10

# mp-component-webpack-plugin

## 介绍

一个用于将 react 组件转化成小程序组件的 webpack 插件。

## 安装

```
yarn add @netless/mp-component-webpack-plugin -D
```

## 使用

[查看文档](https://github.com/wechat-miniprogram/kbone/blob/master/docs/quickstart.md)。
npm package: @netless/nolyfill-mathjs
Description: Replace mathjs with noop.
Author: hyrious
Latest version: 0.1.0

# @netless/nolyfill-mathjs

Helper package to nolyfill (invalidate) `mathjs` from `white-web-sdk`'s dependencies.

Because `mathjs` is used to render the legacy PPT. Using this package can be
helpful when you do not want to use legacy PPT and to include `mathjs` in your final bundle.

## Usage

Edit your `package.json`.

### NPM

https://docs.npmjs.com/cli/v10/configuring-npm/package-json#overrides

```js
{
  "overrides": {
    "white-web-sdk": {
      "mathjs": "npm:@netless/nolyfill-mathjs@0.1.0"
    }
  }
}
```

Then run `npm install`.

### PNPM

https://pnpm.io/package_json#pnpmoverrides

```js
{
  "pnpm": {
    "overrides": {
      "white-web-sdk>mathjs": "npm:@netless/nolyfill-mathjs@0.1.0"
    }
  }
}
```

Then run `pnpm install`.

### Yarn (v1)

https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/#toc-how-to-use-it

```js
{
  "resolutions": {
    "white-web-sdk/mathjs": "npm:@netless/nolyfill-mathjs@0.1.0"
  }
}
```

Then run `yarn install`.

## License

MIT @ [netless](https://github.com/netless-io)
npm package: @netless/react-loading-bar
Description: a loading bar
Author: wushuang
Latest version: 1.0.1

# @netless/react-loading-bar

> a loading bar

[![NPM](https://img.shields.io/npm/v/@netless/react-loading-bar.svg)](https://www.npmjs.com/package/@netless/react-loading-bar) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)

## 1. 说明

本项目技术选型为：`React` `Typescript`
打包工具为： `rollup`  



## 2. 安装

```bash
npm install --save @netless/react-loading-bar

或者

yarn add @netless/react-loading-bar
```



## 3. 接口说明

| 参数                       | 说明               | 类型                                         | 默认值 |
| :------------------------- | :----------------- | :------------------------------------------- | :----: |
| loadingPercent                | 载入百分比 （1 -100）   | number                                  |        |
| style?             | 进度条样式 | React.CSSProperties |        |



## 4. 使用概览

```tsx
import * as React from "react";
import TopLoadingBar from "@netless/react-loading-bar";

export default class TopLoadingBarBoxExample extends React.Component<{}, {}> 
  render () {
    return (
      <TopLoadingBar
        loadingPercent={percent}/>
    )
  }
}
```

## 5. 启动项目

1. 获取源码

    ```bash
    git clone git@github.com:netless-io/netless-react-loading-bar.git
    ```

2. 进入项目并安装库文件依赖

    ```bash
    cd netless-react-loading-bar
    yarn
    ```

3. 启动库文件项目

    ```bash
        yarn start
    ```

4. 进入项目并安装 `example` 文件依赖

    ```bash
        cd example
        yarn
    ```

5. 启动 `example` 项目

    ```bash
        yarn start
    ```

## 6. 项目截图

![loading-bar-898](https://ohuuyffq2.qnssl.com/loading-bar-898.png)

## License

MIT © [wushuang](https://github.com/wushuang)
npm package: @netless/react-mb-tool-box
Description: netless whiteboard react tool mobile box
Author: alwaysmavs
Latest version: 1.0.3

# @netless/react-tool-box

> 一个和 `netless` 白板的工具切换组件，可以在您的白板项目中直接使用，也可以参考其中的代码逻辑自己实现。

[![NPM](https://img.shields.io/npm/v/@netless/react-tool-box.svg)](https://www.npmjs.com/package/@netless/react-tool-box) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)

## 1. 说明

本项目技术选型为：`React` `Typescript `
打包工具为： `rollup`  

## 2. 安装

```bash
npm install --save @netless/react-tool-box

或者

yarn add @netless/react-tool-box
```

## 3. 接口说明

**自定义类型说明**

```typescript
export type Color = [number, number, number];
export type MemberState = {
    currentApplianceName: string;
    strokeColor: Color;
    strokeWidth: number;
    textSize: number;
};

export enum customerComponentPositionType {
    middle = "middle",
    end = "end",
    head = "head",
}
```

| 参数                       | 说明               | 类型                                         | 默认值 |
| :------------------------- | :----------------- | :------------------------------------------- | :----: |
| memberState                | 教具状态           | MemberState                                  |        |
| setMemberState             | 设置教具状态       | (modifyState: Partial<MemberState>) => void; |        |
| customerComponent?         | 三方按钮           | React.ReactNode[]                            |        |
| customerComponentPosition? | 三方按钮插入的位置 | customerComponentPositionType                |        |



## 4. 使用概览

```tsx
import * as React from "react";
import ToolBox from "@netless/react-tool-box";

export default class ToolBoxExample extends React.Component<{}, {}> 
  render () {
    return (
      <ToolBox
        // 用于教具条更新教具的状态
      	memberState={this.state.memberState}
        // 点击教具条可以更新教具
        setMemberState={this.setMemberState}
        // 在教具栏目中插入自定义的按钮，比如上次按钮
        customerComponent={[
          <UploadBtn/>,
        ]}/>
    )
  }
}
```

## 5. 启动项目测试案例

   后续补充

## 6. 项目截图

![react-tool-box-1](https://ohuuyffq2.qnssl.com/react-tool-box-1.png)

## License

MIT © [alwaysmavs](https://github.com/alwaysmavs)
npm package: @netless/react-native-bridge
Description: 配合`@netless/webview-bridge`一起使用，可以实现 web 端和 React-Native 端的通信。 `@netless/react-native-bridge`为 ReactNative 端使用，`@netless/webview-bridge`为 web 端使用。`@netless/react-native-bridge`依赖部分`@netless/webview-bridge`代码，确保两边处理和构建消息逻辑一致。
Author: leavesster
Latest version: 0.0.8

# @netless/react-native-bridge

配合`@netless/webview-bridge`一起使用，可以实现 web 端和 React-Native 端的通信。
`@netless/react-native-bridge`为 ReactNative 端使用，`@netless/webview-bridge`为 web 端使用。`@netless/react-native-bridge`依赖部分`@netless/webview-bridge`代码，确保两边处理和构建消息逻辑一致。
npm package: @netless/react-native-fastboard
Description: interactive whiteboard with user interface for react-native
Author: vince
Latest version: 0.0.2

# @netless/react-native-fastboard

Interactive whiteboard with user interface

## Installation

```sh
npm install --save @netless/react-native-fastboard @netless/react-native-whiteboard react-native-webview
```

## Usage

``` ts
import { FastRoom } from '@netless/react-native-fastboard';

<FastRoom  
    sdkParams={{
        appIdentifier: "whiteboard-appid",
        region: "us-sv", // "cn-hz" | "us-sv" | "sg" | "in-mum" | "gb-lon"
    }}
    roomParams={{
        uid: "unique_id_for_each_client",
        uuid: "room-uuid",
        roomToken: "NETLESSROOM_...",
    }}
/>
```

## Contributing

Suggest to submit pr or issue.

## License

MIT

---

Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
npm package: @netless/react-native-webview-bridge
Description: 配合`@netless/webview-bridge`中的`react-native`部分实现，进行 webview 内部 js 与 react-native 外部环境进行通信并调用。
Author: leavesster
Latest version: 0.0.4

# react-native-webview-bridge

配合`@netless/webview-bridge`中的`react-native`部分实现，进行 webview 内部 js 与 react-native 外部环境进行通信并调用。
npm package: @netless/react-native-whiteboard
Description: interactive whiteboard for react-native
Author: netless-io
Latest version: 0.0.14

# @netless/react-native-whiteboard

interactive whiteboard for react-native

[![TSC](https://github.com/netless-io/react-native-whiteboard/actions/workflows/tsc.yml/badge.svg)](https://github.com/netless-io/react-native-whiteboard/actions/workflows/tsc.yml)
[![pages-build-deployment](https://github.com/netless-io/react-native-whiteboard/actions/workflows/pages/pages-build-deployment/badge.svg)](https://github.com/netless-io/react-native-whiteboard/actions/workflows/pages/pages-build-deployment)

## Installation

### 1. Add dependencies

```sh
$ npm install --save react-native-webview
$ npm install --save @netless/react-native-whiteboard
```

### 2. Link native dependencies

From react-native 0.60 autolinking will take care of the link step but don't forget to run pod install

## Usage

```ts
import { WhiteboardView } from '@netless/react-native-whiteboard';

<WhiteboardView 
    sdkConfig={{
        appIdentifier: 'some-appIdentifier'
    }}
    roomConfig={{
        uid: 'some-uid', 
        uuid: 'some-uuid', 
        roomToken: 'some-token'
    }}
/>
```

For more api details, can see typedoc [here](https://netless-io.github.io/react-native-whiteboard/)

## Contributing

Suggest to submit pr or issue.

## License

MIT
npm package: @netless/react-scale-controller
Description: a whiteboard scale controller
Author: alwaysmavs
Latest version: 1.0.2

# netless-scale-controller

> a whiteboard scale controller

[![NPM](https://img.shields.io/npm/v/@netless/react-scale-controller".svg)](https://www.npmjs.com/package/@netless/react-scale-controller") [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)

## 1. 说明

本项目技术选型为：`React` `Typescript`
打包工具为： `rollup`  


## 2. 安装

```bash
npm install --save @netless/react-scale-controller"

或者

yarn add @netless/react-scale-controller"
```
## 3. 接口说明

| 参数                       | 说明               | 类型                                         | 默认值 |
| :------------------------- | :----------------- | :------------------------------------------- | :----: |
| zoomScale       | 缩放比例 | number                            |        |
| zoomChange   | 缩放变换回调 | (scale: number) => void |        |
| style? | 样式 | (React.CSSProperties |        |

## 4. 使用概览

```tsx
import * as React from "react";
import ScaleController from "@netless/react-scale-controller";

export default class ScaleControllerExample extends React.Component<{}, {}> 
  render () {
    return (
        <ScaleController
            zoomScale={room.state.zoomScale}
            zoomChange={this.zoomChange}/>
    )
  }
}
```

## 5. 启动项目

1. 获取源码

    ```bash
    git clone git@github.com:netless-io/netless-react-scale-controller.git
    ```

2. 进入项目并安装库文件依赖

    ```bash
    cd netless-react-scale-controller
    yarn
    ```

3. 启动库文件项目

    ```bash
        yarn start
    ```

4. 进入项目并安装 `example` 文件依赖

    ```bash
        cd example
        yarn
    ```

5. 启动 `example` 项目

    ```bash
        yarn start
    ```

## 5. 项目截图

![scale-1-2-3](https://ohuuyffq2.qnssl.com/scale-1-2-3.png)

## License

MIT © [alwaysmavs](https://github.com/alwaysmavs)
npm package: @netless/react-seek-slider
Description: a seek slider
Author: wushuang
Latest version: 1.0.4

# @netless/seek-slider

> a seek slider

[![NPM](https://img.shields.io/npm/v/@netless/seek-slider.svg)](https://www.npmjs.com/package/@netless/seek-slider) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)



## 1. 说明

本项目技术选型为：`React` `Typescript`
打包工具为： `rollup`  



## 2. 安装

```bash
npm install --save @netless/seek-slider

或者

yarn add @netless/seek-slider
```



## 3. 接口说明

| 参数                       | 说明               | 类型                                         | 默认值 |
| :------------------------- | :----------------- | :------------------------------------------- | :----: |
| fullTime                | 总时长    | number                                  |        |
| currentTime             | 目前时间 | number |        |
| onChange | 变化回调 | (time: number, offsetTime: number) => void |        |
| offset | 起始时间 | number | 0 |
| bufferProgress? | buffer 进度 | number          |        |
| hideHoverTime? | 是否开启 hover 显示时间功能 | boolen         | false |
| secondsPrefix? | 秒的显示 | string         | "00:" |
| minutesPrefix? | 分的显示 | string          | "00:" |
| limitTimeTooltipBySides? | 三方按钮插入的位置 | boolean         |        |
| sliderColor? | 进度条颜色 | string          |        |
| sliderHoverColor? | hover 显示的进度条颜色 | string          |        |
| thumbColor? | thumb 颜色 | string          |        |
| bufferColor? | buffer 的颜色 | string          |        |



## 4. 使用概览

```tsx
import * as React from "react";
import ToolBox from "@netless/react-tool-box";

export default class ToolBoxExample extends React.Component<{}, {}> 
  render () {
    return (
      <SeekSlider
          // 全部时间
         fullTime={player.timeDuration}
          // 目前时间
         currentTime={this.getCurrentTime(this.state.currentTime)}
          // 时间变化的回调
         onChange={(time: number, offsetTime: number) => {
             if (this.state.player) {
                 this.setState({currentTime: time});
                this.state.player.seekToScheduleTime(time);
             }
         }}
         // hover 显示时间
         hideHoverTime={true}
         limitTimeTooltipBySides={true}
        />
    )
  }
}
```

## 5. 启动项目

1. 获取源码

    ```bash
    git clone git@github.com:netless-io/netless-react-seek-slider.git
    ```

2. 进入项目并安装库文件依赖

    ```bash
    cd netless-react-seek-slider
    yarn
    ```

3. 启动库文件项目

    ```bash
        yarn start
    ```

4. 进入项目并安装 `example` 文件依赖

    ```bash
        cd example
        yarn
    ```

5. 启动 `example` 项目

    ```bash
        yarn start
    ```

## 6. 项目截图

![slider](https://ohuuyffq2.qnssl.com/WeChat9c5904e21b183e907841753055f7d650.png)

## License

MIT © [wushuang](https://github.com/wushuang)
npm package: @netless/react-tool-box
Description: netless whiteboard react tool box
Author: alwaysmavs
Latest version: 1.0.6

# @netless/react-tool-box

> 一个和 `netless` 白板的工具切换组件，可以在您的白板项目中直接使用，也可以参考其中的代码逻辑自己实现。

[![NPM](https://img.shields.io/npm/v/@netless/react-tool-box.svg)](https://www.npmjs.com/package/@netless/react-tool-box) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)

## 1. 说明

本项目技术选型为：`React` `Typescript `
打包工具为： `rollup`  

## 2. 安装

```bash
npm install --save @netless/react-tool-box

或者

yarn add @netless/react-tool-box
```

## 3. 接口说明

**自定义类型说明**

```typescript
export type Color = [number, number, number];
export type MemberState = {
    currentApplianceName: string;
    strokeColor: Color;
    strokeWidth: number;
    textSize: number;
};

export enum customerComponentPositionType {
    middle = "middle",
    end = "end",
    head = "head",
}
```

| 参数                       | 说明               | 类型                                         | 默认值 |
| :------------------------- | :----------------- | :------------------------------------------- | :----: |
| memberState                | 教具状态           | MemberState                                  |        |
| setMemberState             | 设置教具状态       | (modifyState: Partial<MemberState>) => void; |        |
| customerComponent?         | 三方按钮           | React.ReactNode[]                            |        |
| customerComponentPosition? | 三方按钮插入的位置 | customerComponentPositionType                |        |



## 4. 使用概览

```tsx
import * as React from "react";
import ToolBox from "@netless/react-tool-box";

export default class ToolBoxExample extends React.Component<{}, {}> 
  render () {
    return (
      <ToolBox
        // 用于教具条更新教具的状态
      	memberState={this.state.memberState}
        // 点击教具条可以更新教具
        setMemberState={this.setMemberState}
        // 在教具栏目中插入自定义的按钮，比如上次按钮
        customerComponent={[
          <UploadBtn/>,
        ]}/>
    )
  }
}
```

## 5. 启动项目测试案例

   后续补充

## 6. 项目截图

![react-tool-box-1](https://ohuuyffq2.qnssl.com/react-tool-box-1.png)

## License

MIT © [alwaysmavs](https://github.com/alwaysmavs)
npm package: @netless/slide-prefetch
Description: Simple script to prefetch packed slide data on navigation.
Author: hyrious
Latest version: 0.2.1

# @netless/slide-prefetch

Simple script to prefetch packed slide data on navigation.

### Usage

- [Web](./docs/Web.md)
- [Electron](./docs/Electron.md)

### Additional Steps to Use it in Webpack 4

If you are using old bundlers which does not support new javascript syntax.
You may encounter errors when use this library. Especially these two:

- Logical OR Operator.

  ```ts
  // in ./src/utils.ts
  export function openCache(cacheName: string) {
    return (cachePromise ||= caches.open(cacheName));
  }
  ```

- `import.meta`

  ```js
  // in ./node_modules/@zip.js/zip.js/lib/core/codecs/codec-pool-worker.js
  workerData.worker = new Worker(new URL(workerData.scripts[0], import.meta.url));
  ```

While it is encouraged to use new bundlers (vite, webpack5, etc.),
here is a workaround.

```bash
npm i -D \
  babel-loader @babel/core @babel/preset-env \
  @babel/plugin-proposal-logical-assignment-operators \
  @open-wc/webpack-import-meta-loader
```

**webpack.config.js**

```js
{
  resolve: {
    extensions: ['js', '.mjs', 'ts', 'tsx']
  },
  module:{
    rules: [
      {
        test: /slide-prefetch\/dist\/index\.mjs$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            plugins: ['@babel/plugin-proposal-logical-assignment-operators']
          }
        }
      },
      {
        test: /@zip\.js\/zip\.js\/lib\/core\/codecs\/codec-pool-worker\.js$/,
        use: {
          loader: '@open-wc/webpack-import-meta-loader'
        }
      }
    }
  }
}
```

### Develop

```bash
npm run build
npm run test:web
npm run test:electron
```

## License

The MIT License.
npm package: @netless/tablestore-dictionary-db
Description: ## 开发
Author: Tao Zeyu
Latest version: 0.2.4

# tablestore-db

## 开发

```shell
# tablestore-db 依赖 dictionary-db，需要先在根目录执行 build
pnpm build
```

## 测试

根据情况，选择性注释 `packages/tablestore-db/test/Models.ts` 的数据库。
测试文件中数据数据库 schema，需要在特定的账号和集群中使用。
如果是 netless 开发人员：
    1. tablestore 可以在阿里云的测试账号中使用，region 为 cn-hangzhou。
    2. dynamodb 可以在 netless 测试账号中使用，region 为 ap-northeast-1。
这里缺少表结构的创建脚本，所以测试代码，并不通用，外部使用需要自己创建。

测试阿里云 tablestore 数据库需要配置以下环境变量
```shell
export TABLESTORE_AK=***
export TABLESTORE_SK=***
export TABLESTORE_INSTANCE_NAME=***
export TABLESTORE_ENDPOINT=***
```

测试 dynamodb 需要在本地配置好 `~/.aws/credentials` 和 `~/.aws/config`，前者是鉴权信息，后者是 region 信息。

~/.aws/credentials

```ini
[default]
aws_access_key_id = 
aws_secret_access_key = 
```


~/.aws/config

```ini
[default]
region = ap-northeast-1
output = json
```

```shell
cd packages/tablestore-db
pnpm test
```
npm package: @netless/video-js-plugin
Description: a video/audio plugin for white-web-sdk using video.js.
Author: netless
Latest version: 0.3.8

## @netless/video-js-plugin

Requires `white-web-sdk >= 2.13.8` to work properly.

### Usage

```ts
import "video.js/dist/video-js.css";
import { videoJsPlugin } from "@netless/video-js-plugin";
import { createPlugins } from "white-web-sdk";

const plugins = createPlugins({ "video.js": videoJsPlugin() });

plugins.setPluginContext("video.js", { enable: true, verbose: true });

const sdk = new WhiteWebSdk({ appIdentifier, plugins });

const room = await sdk.joinRoom({ uuid, roomToken });

room.insertPlugin("video.js", {
    originX: -width / 2,
    originY: -height / 2,
    width,
    height,
    attributes: { src: "url/to/a.mp4" },
});
```

If you are using `<script>`, here is an example:

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/video.js/dist/video-js.css" />
<script src="https://cdn.jsdelivr.net/npm/react/umd/react.development.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.development.js"></script>
<script src="https://cdn.jsdelivr.net/npm/video.js/dist/video.js"></script>
<script src="https://sdk.netless.link/white-web-sdk/2.13.10.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@netless/video-js-plugin/dist/index.iife.js"></script>
<script>
    const { createPlugins } = WhiteWebSdk;
    const { videoJsPlugin } = WhiteWebSdkVideoJsPlugin;
    // there you go
</script>
```

### Options

<dl>
    <dt>context</dt>
    <dd>local config, does not affect other ones.</dd>
    <dt>attributes</dt>
    <dd>sync with everyone.</dd>
</dl>

```ts
export interface PluginContext {
    /**
     * Chrome prevents video play sound on video.play().
     * Set `hideMuteAlert: true` to hide the muted mask covering the player.
     * @default false
     */
    hideMuteAlert?: boolean;

    /**
     * @deprecated use `enable` or `room.setWritable()` instead.
     * @default "guest"
     */
    identity?: "host" | "publisher" | "guest" | "observer";

    /**
     * If set false, videojs plugins will not be controlled by the user input.
     * @default false
     */
    enable?: boolean;

    /**
     * For debug.
     * @default false
     */
    verbose?: boolean;
}
```

```ts
export interface VideoJsPluginAttributes {
    /** whether to show [X], default `true` */
    close?: boolean;
    /** text at top-left corner */
    title?: string;
    /** mime type */
    type?: string;

    /** video url */
    src: string;
    /** poster */
    poster: string;
    /** current `room.calibrationTimestamp` */
    hostTime: number;
    /** current play time */
    currentTime: number;
    /** is paused, default `false` */
    paused: boolean;
    /** is muted, default `false` */
    muted: boolean;
    /** volume (0..1), default `1` */
    volume: number;
}

```

### Develop

Requires Node.js 16. See .env.example first.

```bash
npm run build
npm t
```

### License

MIT @ [netless](https://github.com/netless-io)
npm package: @netless/webview-bridge
Description: bridge in web for webview react-native and future for native and flutter
Author: leavesster
Latest version: 0.2.1

# @netless/webview-bridge

不同平台的 webview 都会提供各种方式，使得 web 端的代码，可以与平台代码交互。iOS，Android，flutter，React-Native 都存在这种通信方式。两端通信，不仅仅需要 web 端做一些配置，还需要平台端做一些配置。这里只包含 web 端的配置。
由于 React-Native 的特性，所以这个库中的一些代码，逻辑，类型，可以提供给 React-Native 使用，达到一定程度的复用，同时提高维护性。

该库目前桥接的目标为 React-Native。  
iOS，Android 的 web 桥接，可以通过 [dsbridge](https://www.npmjs.com/package/dsbridge) 实现，该库在对应的 iOS 和 Android 端有对应的实现

## install

```shell
# uuid 版本过多，所以只标识为 peer dependency
npm install @netless/webview-bridge uuid
```

## TODO

- [ ] 提供 flutter webview 中的桥接
- [x] 提供 dsbridge webview 中的桥接替换

## 接口设计

1. js 端调用 native 时，同步和异步的 api 应该分开，而不是像 dsbridge 那样，都是用同一个 call API，非常容易混淆。应该分为 callSync 和 callAsync 两种，而且由于同步的阻塞性，默认应该是 callAsync。
2. js 注册 API 时，不应该是 register 和 registerAsync，实际上这两个 api 对于 native 而言，都是异步的，这个命名会让人非常困惑。两者的不同点在于后者的回调可以重复调用，也就是可以不断回调，通常作为进度回调使用。所以应该注册为 register 和 registerProgress
npm package: @netless/white-audio-plugin
Description: a audio plugin for white-web-sdk which can play audio in whiteboard room and sync to everyone in room
Author: netless
Latest version: 1.2.23

# white-video-plugin

> https://www.npmjs.com/package/@netless/white-video-plugin

## 一、在白板初始化的时候注册 plugin

**初始化 SDK 的时候注入 plugin 代码**

```typescript
whiteWebSdk = new WhiteWebSdk({ 
deviceType: "desktop",
handToolKey: " ",
plugins: [WhiteVideoPlugin] // 在 new WhiteWebSdk 对象的时候注册完成
});
```

## 二、声明身份

**什么身份，以便控制 plugin 的编辑操作权限，目前声明后不再支持改变**

userId：string // 必填
identity："host" | "guest" // 必填，有操作权限者为 "host"，观看者为 "guest"

代码
```typescript
whiteWebSdk.joinRoom({
                    uuid: uuid,
                    roomToken: roomToken,
                    cursorAdapter: this.cursor,
                    userPayload: {
                        userId: userId, // 必填
                        identity: identity,// 必填
                        name: userName,
                        avatar: userAvatarUrl,
                   
                    }}）
```

## 二、声明身份

**什么身份，以便控制 plugin 的编辑操作权限，目前声明后不再支持改变**

userId：string // 必填
identity："host" | "guest" // 必填，有操作权限者为 "host"，观看者为 "guest"

## 三、插入 plugin

**将 plugin 插入白板**

```typescript
room.insertPlugin({
                protocal: "video", // 视频必须填写为 Video
                centerX: 0, // 插入位置 x
                centerY: 0, // 插入位置 y
                width: 480, // 宽 witdh
                height: 270, // gao height
                props: {
                    videoUrl: url, // 视频地址
                },
            });
```
npm package: @netless/white-audio-plugin-cdn
Description: > https://www.npmjs.com/package/@netless/white-video-plugin
Author: netless
Latest version: 0.0.2

# white-video-plugin

> https://www.npmjs.com/package/@netless/white-video-plugin

## 一、在白板初始化的时候注册 plugin

**初始化 SDK 的时候注入 plugin 代码**

```typescript
whiteWebSdk = new WhiteWebSdk({ 
deviceType: "desktop",
handToolKey: " ",
plugins: [WhiteVideoPlugin] // 在 new WhiteWebSdk 对象的时候注册完成
});
```

## 二、声明身份

**什么身份，以便控制 plugin 的编辑操作权限，目前声明后不再支持改变**

userId：string // 必填
identity："host" | "guest" // 必填，有操作权限者为 "host"，观看者为 "guest"

代码
```typescript
whiteWebSdk.joinRoom({
                    uuid: uuid,
                    roomToken: roomToken,
                    cursorAdapter: this.cursor,
                    userPayload: {
                        userId: userId, // 必填
                        identity: identity,// 必填
                        name: userName,
                        avatar: userAvatarUrl,
                   
                    }}）
```

## 二、声明身份

**什么身份，以便控制 plugin 的编辑操作权限，目前声明后不再支持改变**

userId：string // 必填
identity："host" | "guest" // 必填，有操作权限者为 "host"，观看者为 "guest"

## 三、插入 plugin

**将 plugin 插入白板**

```typescript
room.insertPlugin({
                protocal: "video", // 视频必须填写为 Video
                centerX: 0, // 插入位置 x
                centerY: 0, // 插入位置 y
                width: 480, // 宽 witdh
                height: 270, // gao height
                props: {
                    videoUrl: url, // 视频地址
                },
            });
```
npm package: @netless/white-audio-plugin2
Description: a audio plugin for white-web-sdk which can play audio in whiteboard room and sync to everyone in room
Author: netless
Latest version: 2.0.5

# white-audio-plugin

https://www.npmjs.com/package/@netless/white-audio-plugin

**注**：以下是 `1.x` 版本的接口文档，和 `2.x` 不兼容。如果你没有需要兼容 `1.x` 的项目，强烈建议升级到 `2.x`。

`1.x` 有以下 bug, _won't fix_:

- 同步时间戳可能由于网络延迟，差距变得很大
- 必须和 white-web-sdk 使用 **同一份** mobx

## 用法

```typescript
// 创建 plugins
const plugins = createPlugins({ "audio": audioPlugin });
plugins.setPluginContext("audio", {
    identity: identity === Identity.creator ? "host" : ""
});
// 初始化 sdk 时添加 plugins
let sdk = new WhiteWebSdk({ plugins });

let room = await sdk.joinRoom(...);
// 在房间内添加插件教具
room.insertPlugin("audio", {
    originX: -240, originY: -43, width: 480, height: 86,
    attributes: { pluginAudioUrl: url, isNavigationDisable: false },
});
```

## 参数

```ts
interface Context {
    /** 必填，有操作权限者为 "host"，观看者为 "guest" */
    identity："host" | "guest";
}

// 注意：这些类型并没有存在于 d.ts 中，需要使用者用 as any 混过去
interface Attributes {
    /** 音频地址 */
    pluginAudioUrl: string;
    /** 是否隐藏标题栏 */
    isNavigationDisable?: boolean;
}
```

## License

The MIT License.
npm package: @netless/white-snapshot
Description: Take a snapshot of a white-web-sdk scene.
Author: netless
Latest version: 0.4.2

## @netless/white-snapshot

Take a snapshot of a white-web-sdk scene.

Requires white-web-sdk &ge; 2.16.20.

### Usage

```js
import { snapshot } from "@netless/white-snapshot";
// room = await sdk.joinRoom(...)
snapshot(room).then(canvas => {
  document.body.append(canvas);
});
```

### Options

```ts
snapshot(room, {
  scenePath: "/init",
  padding: 5,
  background: 'transparent',
  crop: null,
  crossorigin: false,
  src2dataurl: undefined,
}): Promise<HTMLCanvasElement | null>;
```

Returns `null` if failed.

| Option      | Type                                       | Default       | Description                                                                                             |
| ----------- | ------------------------------------------ | ------------- | ------------------------------------------------------------------------------------------------------- |
| scenePath   | string                                     | current scene | Default is `displayer.state.sceneState.scenePath`.                                                      |
| padding     | number                                     | 5             | Pixels to the border of canvas.                                                                         |
| background  | string                                     |               | Background color.                                                                                       |
| crop        | Rectangle                                  | null          | Apply crop on the snapshot. Note that the snapshot includes padding.                                    |
| crossorigin | boolean                                    | false         | Apply hack to `document.createElement('img')` to enable crossorigin images.                             |
| src2dataurl | (src: string) &rArr; Promise&lt;string&gt; |               | Due to a [limitation][1] in `html2canvas`, we must convert images to dataurl before feeding them to it. |

[1]: https://github.com/niklasvh/html2canvas/issues/592#issuecomment-727540799

### Develop

```bash
pnpm dev
```

### [Changelog](./CHANGELOG.md)

## License

MIT @ [netless](https://github.com/netless-io/white-snapshot)
npm package: @netless/white-video-plugin
Description: a video plugin for white-web-sdk which can play video in whiteboard room and sync to everyone in room
Author: netless
Latest version: 1.2.23

# white-video-plugin

> https://www.npmjs.com/package/@netless/white-video-plugin

## 一、在白板初始化的时候注册 plugin

**初始化 SDK 的时候注入 plugin 代码**

```typescript
whiteWebSdk = new WhiteWebSdk({ 
deviceType: "desktop",
handToolKey: " ",
plugins: [WhiteVideoPlugin] // 在 new WhiteWebSdk 对象的时候注册完成
});
```

## 二、声明身份

**什么身份，以便控制 plugin 的编辑操作权限，目前声明后不再支持改变**

userId：string // 必填
identity："host" | "guest" // 必填，有操作权限者为 "host"，观看者为 "guest"

代码
```typescript
whiteWebSdk.joinRoom({
                    uuid: uuid,
                    roomToken: roomToken,
                    cursorAdapter: this.cursor,
                    userPayload: {
                        userId: userId, // 必填
                        identity: identity,// 必填
                        name: userName,
                        avatar: userAvatarUrl,
                   
                    }}）
```

## 二、声明身份

**什么身份，以便控制 plugin 的编辑操作权限，目前声明后不再支持改变**

userId：string // 必填
identity："host" | "guest" // 必填，有操作权限者为 "host"，观看者为 "guest"

## 三、插入 plugin

**将 plugin 插入白板**

```typescript
room.insertPlugin({
                protocal: "video", // 视频必须填写为 Video
                centerX: 0, // 插入位置 x
                centerY: 0, // 插入位置 y
                width: 480, // 宽 witdh
                height: 270, // gao height
                props: {
                    videoUrl: url, // 视频地址
                },
            });
```
npm package: @netless/white-video-plugin-cdn
Description: > https://www.npmjs.com/package/@netless/white-video-plugin
Author: netless
Latest version: 0.0.1

# white-video-plugin

> https://www.npmjs.com/package/@netless/white-video-plugin

## 一、在白板初始化的时候注册 plugin

**初始化 SDK 的时候注入 plugin 代码**

```typescript
whiteWebSdk = new WhiteWebSdk({ 
deviceType: "desktop",
handToolKey: " ",
plugins: [WhiteVideoPlugin] // 在 new WhiteWebSdk 对象的时候注册完成
});
```

## 二、声明身份

**什么身份，以便控制 plugin 的编辑操作权限，目前声明后不再支持改变**

userId：string // 必填
identity："host" | "guest" // 必填，有操作权限者为 "host"，观看者为 "guest"

代码
```typescript
whiteWebSdk.joinRoom({
                    uuid: uuid,
                    roomToken: roomToken,
                    cursorAdapter: this.cursor,
                    userPayload: {
                        userId: userId, // 必填
                        identity: identity,// 必填
                        name: userName,
                        avatar: userAvatarUrl,
                   
                    }}）
```

## 二、声明身份

**什么身份，以便控制 plugin 的编辑操作权限，目前声明后不再支持改变**

userId：string // 必填
identity："host" | "guest" // 必填，有操作权限者为 "host"，观看者为 "guest"

## 三、插入 plugin

**将 plugin 插入白板**

```typescript
room.insertPlugin({
                protocal: "video", // 视频必须填写为 Video
                centerX: 0, // 插入位置 x
                centerY: 0, // 插入位置 y
                width: 480, // 宽 witdh
                height: 270, // gao height
                props: {
                    videoUrl: url, // 视频地址
                },
            });
```
npm package: @netless/white-video-plugin2
Description: a video plugin for white-web-sdk which can play video in whiteboard room and sync to everyone in room
Author: netless
Latest version: 2.1.2

# white-video-plugin2

https://www.npmjs.com/package/@netless/white-video-plugin2

**注**：注意包名为 `@netless/white-video-plugin2`，为了兼容 `1.x` 发了个新包。

**注**：以下是 `2.x` 版本的接口，和 `1.x` 不兼容。如果你有回放中使用了 `1.x`，可以参考 [本项目](https://github.com/netless-io/flat-web/blob/7db5a0bf2e351999c1b330eb99cf74de12628022/whiteboard/src/WhiteboardPage.tsx#L186-L193) 做兼容性处理。

## 用法

```typescript
// 创建 plugins
const plugins = createPlugins({ "video2": videoPlugin2 });
plugins.setPluginContext("video2", {
    identity: identity === Identity.creator ? "host" : ""
});
// 初始化 sdk 时添加 plugins
let sdk = new WhiteWebSdk({ plugins });

let room = await sdk.joinRoom(...);
// 在房间内添加插件教具
room.insertPlugin("video2", {
    originX: -240, originY: -43, width: 480, height: 86,
    attributes: { src: url, poster: url2, isNavigationDisable: false },
});
```

## 参数

```ts
interface Context {
    /** 必填，有操作权限者为 "host"，观看者为 "guest" */
    identity："host" | "guest";
}

interface Attributes {
    /** 视频地址 */
    src: string;
    /** 封面地址 */
    poster?: string;
    /** 是否隐藏标题栏 */
    isNavigationDisable?: boolean;
}
```

## License

The MIT License.