2026-07-01 03:24:43 +00:00
# MaskSegmentCanvas Example
2026-07-02 02:07:32 +00:00
A Demo project that **fully simulates real-world business integration** , showing how to integrate `react-native-mask-segment-canvas` into your React Native project.
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
## Difference from the Library's Own Demo
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
| Project | Import Method | Purpose |
2026-07-01 03:24:43 +00:00
| ---- | -------- | ---- |
2026-07-02 02:07:32 +00:00
| Root `App.tsx` | `import ... from './src'` (internal source) | Library author self-testing |
| **This example/** | `import ... from 'react-native-mask-segment-canvas'` (public API) | **Business integration reference** |
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
This example only depends on the library's public API and does not touch any `src/` internals. It serves as a template you can directly copy into your project.
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
## Quick Start
2026-07-01 03:24:43 +00:00
```bash
2026-07-02 02:07:32 +00:00
# 1. Enter the example directory
2026-07-01 03:24:43 +00:00
cd example
2026-07-02 02:07:32 +00:00
# 2. Install dependencies (auto-links the parent library)
2026-07-01 03:24:43 +00:00
npm install
2026-07-02 02:07:32 +00:00
# 3. Apply postinstall patches (patch-package patches react-native-fast-opencv)
# Automatically runs after npm install. If it didn't, run manually:
2026-07-01 03:24:43 +00:00
npx patch-package
2026-07-02 02:07:32 +00:00
# 4. iOS: Install native dependencies
2026-07-01 03:24:43 +00:00
cd ios & & pod install & & cd ..
2026-07-02 02:07:32 +00:00
# 5. Start Metro
2026-07-01 03:24:43 +00:00
npm start
2026-07-02 02:07:32 +00:00
# 6. In another terminal, run
2026-07-01 03:24:43 +00:00
npm run ios
2026-07-02 02:07:32 +00:00
# or
2026-07-01 03:24:43 +00:00
npm run android
```
2026-07-02 02:07:32 +00:00
## File Overview
2026-07-01 03:24:43 +00:00
```
example/
2026-07-02 02:07:32 +00:00
├── App.tsx # ★ Core: Complete integration example page
├── index.js # RN entry (registers gesture-handler + Buffer polyfill)
├── app.json # App name config
├── package.json # Standalone dependency config, "react-native-mask-segment-canvas": "file:.."
├── metro.config.js # Metro config (watchFolders pointing to parent directory)
├── babel.config.js # Babel config (includes reanimated plugin)
├── tsconfig.json # TypeScript config
└── README.md # This file
2026-07-01 03:24:43 +00:00
```
2026-07-02 02:07:32 +00:00
## Features Covered in App.tsx
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
`App.tsx` is a complete page you can reference directly, covering:
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
| Feature | Relevant Code Location |
2026-07-01 03:24:43 +00:00
| ---- | ------------ |
2026-07-02 02:07:32 +00:00
| **PNG pre-warming** | `useEffect` → `prewarmPngBgrCacheAsync` |
| **State management** | `watchState` / `isInteractive` / `isOutlineReady` derived states |
| **onWatch callback** | `handleWatch` — tracks initialization stages |
| **onPaintCallback** | `handlePaintCallback` — handles both successful paint and missing-brush scenarios |
| **onError callback** | `handleError` — captures segmentation/load failures |
| **Ref operations** | `save` / `reset` / `swap` / `clearAllPaint` / `session` |
| **setPaintColor** | Preset brush colors via `ref.setPaintColor` |
| **Custom semantic color table** | `GYM_CUSTOM_COLORS` example + mode toggle UI |
| **Pipeline resolution toggle** | `pipelinePreset` low/medium/high resolution switching |
| **Toast notifications** | `brush_required` callback when no brush is selected + custom Toast |
| **Loading/error UI** | PNG pre-warm loading, initialization Loading, error display |
| **Draft recovery** | `sessionDraft` state + `initialSession` prop |
## Integrating into Your Own Project
### Option 1: npm install (recommended for production)
2026-07-01 03:24:43 +00:00
```bash
npm install react-native-mask-segment-canvas
```
2026-07-02 02:07:32 +00:00
### Option 2: Local development
2026-07-01 03:24:43 +00:00
```bash
2026-07-02 02:07:32 +00:00
# In the library directory
2026-07-01 03:24:43 +00:00
npm link
2026-07-02 02:07:32 +00:00
# In your project
2026-07-01 03:24:43 +00:00
npm link react-native-mask-segment-canvas
```
2026-07-02 02:07:32 +00:00
Your `metro.config.js` needs to add:
2026-07-01 03:24:43 +00:00
```js
const path = require('path');
module.exports = mergeConfig(getDefaultConfig(__dirname), {
watchFolders: [path.resolve(__dirname, '../MaskSegmentApp')],
resolver: {
nodeModulesPaths: [path.resolve(__dirname, 'node_modules')],
},
});
```
2026-07-02 02:07:32 +00:00
### Option 3: file: dependency (used by this example)
2026-07-01 03:24:43 +00:00
```json
{
"dependencies": {
"react-native-mask-segment-canvas": "file:../MaskSegmentApp"
}
}
```
2026-07-02 02:07:32 +00:00
### Required peerDependencies
2026-07-01 03:24:43 +00:00
```bash
npm install @shopify/react -native-skia react-native-reanimated react-native-fast-opencv react-native-fs buffer
2026-07-02 02:07:32 +00:00
# If using photo library picker
2026-07-01 03:24:43 +00:00
npm install react-native-image-picker
2026-07-02 02:07:32 +00:00
# Safe area insets
2026-07-01 03:24:43 +00:00
npm install react-native-safe-area-context
```
2026-07-02 02:07:32 +00:00
### postinstall Configuration
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
Your `package.json` needs:
2026-07-01 03:24:43 +00:00
```json
{
"scripts": {
"postinstall": "patch-package"
},
"devDependencies": {
"patch-package": "^8.0.1"
}
}
```
2026-07-02 02:07:32 +00:00
## Common Issues
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
**Getting "module not found" after `npm install` ?**
- Make sure `postinstall` ran (`npx patch-package`)
- Check that Metro config's `watchFolders` includes the library directory
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
**`pod install` fails?**
2026-07-01 03:24:43 +00:00
```bash
cd ios
bundle install
bundle exec pod install --repo-update
```
2026-07-02 02:07:32 +00:00
**Android build errors?**
2026-07-01 03:24:43 +00:00
```bash
cd android & & ./gradlew clean & & cd ..
```
2026-07-02 02:07:32 +00:00
**Duplicate module errors at runtime (most common)**
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
In monorepo, npm link, or `file:..` setups, you'll frequently encounter these "similar-looking" errors:
2026-07-01 03:24:43 +00:00
- `SkiaPictureView must be a function (received 'undefined')`
2026-07-02 02:07:32 +00:00
- `createAnimatedNode: Animated node[...] already exists` (including UIFrameGuarded variants)
- Other Fabric ViewManager / native module singleton conflicts
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
**Root cause**: Metro is loading multiple copies of `@shopify/react-native-skia` , `react-native-reanimated` , `react-native-gesture-handler` , `react-native-fast-opencv` , `react-native-safe-area-context` , and other peer dependencies.
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
**Recommended complete solution** (copy directly into your project):
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
1. **At the very top of index.js** (must come first):
2026-07-01 03:24:43 +00:00
```js
import 'react-native-gesture-handler';
import 'react-native-reanimated';
import '@shopify/react-native-skia';
```
2026-07-02 02:07:32 +00:00
2. **metro.config.js** (use extraNodeModules + blockList for double safety):
2026-07-01 03:24:43 +00:00
```js
const path = require('path');
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const yourNodeModules = path.resolve(__dirname, 'node_modules');
const singletons = [
'react', 'react-native',
'react-native-reanimated',
'@shopify/react-native-skia',
'react-native-gesture-handler',
'react-native-fast-opencv',
'react-native-safe-area-context',
'react-native-fs',
'react-native-image-picker',
];
module.exports = mergeConfig(getDefaultConfig(__dirname), {
watchFolders: [path.resolve(__dirname, '../MaskSegmentApp')],
resolver: {
nodeModulesPaths: [yourNodeModules],
extraNodeModules: singletons.reduce((acc, p) => (acc[p] = path.resolve(yourNodeModules, p), acc), {}),
blockList: singletons.map(p => new RegExp(`/MaskSegmentApp/node_modules/${p.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$& ')}/`)),
},
});
```
2026-07-02 02:07:32 +00:00
> `example/metro.config.js` is already written following this standard template. You can reference it directly.
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
After completing the two steps above, you **must** :
- Restart Metro (`npx react-native start --reset-cache`)
- Reinstall the app (recommend `cd android && ./gradlew clean` first, or re-run after iOS pod install)
2026-07-01 03:24:43 +00:00
2026-07-02 02:07:32 +00:00
This will resolve all "similar" duplicate-module runtime errors in one shot.