@penabt/pixi-expo 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +202 -0
- package/package.json +98 -0
- package/src/adapter/ExpoAdapter.ts +343 -0
- package/src/adapter/ExpoCanvasElement.ts +479 -0
- package/src/adapter/index.ts +52 -0
- package/src/adapter/loadExpoAsset.ts +211 -0
- package/src/adapter/loadExpoFont.ts +143 -0
- package/src/adapter/polyfills.ts +362 -0
- package/src/components/PixiView.tsx +375 -0
- package/src/example/App.tsx +207 -0
- package/src/index.ts +284 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Pena Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# @penabt/pixi-expo
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@penabt/pixi-expo)
|
|
4
|
+
[](https://github.com/penabt/pixi-expo/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
**PixiJS v8 adapter for React Native Expo.** Enables hardware-accelerated 2D graphics in your Expo applications using the expo-gl WebGL context.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🚀 **PixiJS v8 Support** - Full compatibility with the latest PixiJS version
|
|
11
|
+
- 📱 **Expo Integration** - Works seamlessly with Expo managed and bare workflows
|
|
12
|
+
- ⚡ **60 FPS Performance** - Hardware-accelerated WebGL rendering via expo-gl
|
|
13
|
+
- 🎮 **Game Ready** - Perfect for 2D games, animations, and interactive graphics
|
|
14
|
+
- 📦 **Easy Setup** - Drop-in PixiView component with simple API
|
|
15
|
+
- 🔧 **Customizable** - Access to full PixiJS API and expo-gl context
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Install the package
|
|
21
|
+
npm install @penabt/pixi-expo
|
|
22
|
+
|
|
23
|
+
# Install peer dependencies
|
|
24
|
+
npx expo install expo-gl expo-asset expo-font pixi.js
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import React from 'react';
|
|
31
|
+
import { View, StyleSheet } from 'react-native';
|
|
32
|
+
import { PixiView, Graphics, Application } from '@penabt/pixi-expo';
|
|
33
|
+
|
|
34
|
+
export default function GameScreen() {
|
|
35
|
+
const handleAppCreate = (app: Application) => {
|
|
36
|
+
// Create a red circle
|
|
37
|
+
const circle = new Graphics()
|
|
38
|
+
.circle(0, 0, 50)
|
|
39
|
+
.fill({ color: 0xff0000 });
|
|
40
|
+
|
|
41
|
+
circle.position.set(200, 300);
|
|
42
|
+
app.stage.addChild(circle);
|
|
43
|
+
|
|
44
|
+
// Animate with the ticker
|
|
45
|
+
app.ticker.add(() => {
|
|
46
|
+
circle.rotation += 0.01;
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<View style={styles.container}>
|
|
52
|
+
<PixiView
|
|
53
|
+
style={styles.game}
|
|
54
|
+
backgroundColor={0x1099bb}
|
|
55
|
+
onApplicationCreate={handleAppCreate}
|
|
56
|
+
/>
|
|
57
|
+
</View>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const styles = StyleSheet.create({
|
|
62
|
+
container: { flex: 1 },
|
|
63
|
+
game: { flex: 1 },
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## API Reference
|
|
68
|
+
|
|
69
|
+
### PixiView Component
|
|
70
|
+
|
|
71
|
+
The main component for rendering PixiJS content.
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
<PixiView
|
|
75
|
+
style={ViewStyle} // Container styles
|
|
76
|
+
backgroundColor={0x000000} // Background color (hex)
|
|
77
|
+
resolution={1} // Device pixel ratio
|
|
78
|
+
antialias={true} // Enable antialiasing
|
|
79
|
+
onApplicationCreate={(app) => {}} // Called when app is ready
|
|
80
|
+
onContextCreate={(gl) => {}} // Called when GL context created
|
|
81
|
+
onError={(error) => {}} // Called on initialization error
|
|
82
|
+
/>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### PixiView Ref Handle
|
|
86
|
+
|
|
87
|
+
Access the PixiJS Application imperatively:
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
const pixiRef = useRef<PixiViewHandle>(null);
|
|
91
|
+
|
|
92
|
+
// Get the application
|
|
93
|
+
const app = pixiRef.current?.getApplication();
|
|
94
|
+
|
|
95
|
+
// Get the stage
|
|
96
|
+
const stage = pixiRef.current?.getStage();
|
|
97
|
+
|
|
98
|
+
// Force render
|
|
99
|
+
pixiRef.current?.render();
|
|
100
|
+
|
|
101
|
+
// Take screenshot
|
|
102
|
+
const base64 = await pixiRef.current?.takeSnapshot();
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Re-exported from PixiJS
|
|
106
|
+
|
|
107
|
+
For convenience, common PixiJS exports are available directly:
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import {
|
|
111
|
+
// Display Objects
|
|
112
|
+
Application,
|
|
113
|
+
Container,
|
|
114
|
+
Sprite,
|
|
115
|
+
Graphics,
|
|
116
|
+
Text,
|
|
117
|
+
TilingSprite,
|
|
118
|
+
AnimatedSprite,
|
|
119
|
+
Mesh,
|
|
120
|
+
NineSliceSprite,
|
|
121
|
+
|
|
122
|
+
// Textures
|
|
123
|
+
Texture,
|
|
124
|
+
RenderTexture,
|
|
125
|
+
Assets,
|
|
126
|
+
|
|
127
|
+
// Geometry
|
|
128
|
+
Matrix,
|
|
129
|
+
Point,
|
|
130
|
+
Rectangle,
|
|
131
|
+
Circle,
|
|
132
|
+
Polygon,
|
|
133
|
+
|
|
134
|
+
// Filters
|
|
135
|
+
Filter,
|
|
136
|
+
BlurFilter,
|
|
137
|
+
ColorMatrixFilter,
|
|
138
|
+
|
|
139
|
+
// Animation
|
|
140
|
+
Ticker,
|
|
141
|
+
|
|
142
|
+
// And more...
|
|
143
|
+
} from '@penabt/pixi-expo';
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Loading Assets
|
|
147
|
+
|
|
148
|
+
### Bundled Assets (require)
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import { loadTexture, Sprite } from '@penabt/pixi-expo';
|
|
152
|
+
|
|
153
|
+
// Load a bundled image
|
|
154
|
+
const texture = await loadTexture(require('./assets/bunny.png'));
|
|
155
|
+
const sprite = new Sprite(texture);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Remote Assets (URL)
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
// Load from URL
|
|
162
|
+
const texture = await Assets.load('https://example.com/sprite.png');
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Performance Tips
|
|
166
|
+
|
|
167
|
+
1. **Use Shared Ticker** - PixiView enables `sharedTicker` by default for optimal performance
|
|
168
|
+
|
|
169
|
+
2. **Batch Rendering** - Group similar sprites using `ParticleContainer` for many objects
|
|
170
|
+
|
|
171
|
+
3. **Texture Atlases** - Use spritesheets instead of individual images
|
|
172
|
+
|
|
173
|
+
4. **Avoid Text Updates** - Cache text objects, don't create new ones every frame
|
|
174
|
+
|
|
175
|
+
5. **Production Builds** - Run `npx expo run:ios --configuration Release` for best performance
|
|
176
|
+
|
|
177
|
+
## Limitations
|
|
178
|
+
|
|
179
|
+
- **No Canvas 2D** - expo-gl only supports WebGL, not Canvas 2D context
|
|
180
|
+
- **No HTMLText** - HTML-based text rendering is not available
|
|
181
|
+
- **Font Loading** - Use expo-font for loading custom fonts
|
|
182
|
+
|
|
183
|
+
## Compatibility
|
|
184
|
+
|
|
185
|
+
| Package | Version |
|
|
186
|
+
|---------|---------|
|
|
187
|
+
| pixi.js | ≥ 8.0.0 |
|
|
188
|
+
| expo | ≥ 50.0.0 |
|
|
189
|
+
| expo-gl | ≥ 14.0.0 |
|
|
190
|
+
| react-native | ≥ 0.73.0 |
|
|
191
|
+
|
|
192
|
+
## Contributing
|
|
193
|
+
|
|
194
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
MIT © [Pena Team](https://github.com/penabt)
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
Made with ❤️ by [Pena Team](https://github.com/penabt)
|
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@penabt/pixi-expo",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "PixiJS v8 adapter for React Native Expo. Enables hardware-accelerated 2D graphics using expo-gl WebGL context.",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"module": "src/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
|
+
"source": "src/index.ts",
|
|
9
|
+
"sideEffects": [
|
|
10
|
+
"./src/adapter/polyfills.ts",
|
|
11
|
+
"./lib/adapter/polyfills.js",
|
|
12
|
+
"./lib/adapter/polyfills.mjs"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"main": "lib/index.js",
|
|
16
|
+
"module": "lib/index.mjs",
|
|
17
|
+
"types": "lib/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"import": "./lib/index.mjs",
|
|
21
|
+
"require": "./lib/index.js",
|
|
22
|
+
"types": "./lib/index.d.ts"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"lib",
|
|
28
|
+
"src",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
34
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
35
|
+
"prepublishOnly": "npm run build",
|
|
36
|
+
"clean": "rm -rf lib",
|
|
37
|
+
"typecheck": "tsc --noEmit",
|
|
38
|
+
"lint": "eslint src --ext .ts,.tsx"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"pena",
|
|
42
|
+
"pixi",
|
|
43
|
+
"pixijs",
|
|
44
|
+
"pixi.js",
|
|
45
|
+
"expo",
|
|
46
|
+
"expo-gl",
|
|
47
|
+
"react-native",
|
|
48
|
+
"webgl",
|
|
49
|
+
"2d",
|
|
50
|
+
"graphics",
|
|
51
|
+
"game",
|
|
52
|
+
"animation",
|
|
53
|
+
"canvas",
|
|
54
|
+
"renderer"
|
|
55
|
+
],
|
|
56
|
+
"author": {
|
|
57
|
+
"name": "Pena Team",
|
|
58
|
+
"url": "https://github.com/penabt"
|
|
59
|
+
},
|
|
60
|
+
"repository": {
|
|
61
|
+
"type": "git",
|
|
62
|
+
"url": "https://github.com/penabt/pixi-expo.git"
|
|
63
|
+
},
|
|
64
|
+
"bugs": {
|
|
65
|
+
"url": "https://github.com/penabt/pixi-expo/issues"
|
|
66
|
+
},
|
|
67
|
+
"homepage": "https://github.com/penabt/pixi-expo#readme",
|
|
68
|
+
"license": "MIT",
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=18.0.0"
|
|
71
|
+
},
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"expo": ">=50.0.0",
|
|
74
|
+
"expo-asset": ">=10.0.0",
|
|
75
|
+
"expo-font": ">=12.0.0",
|
|
76
|
+
"expo-gl": ">=14.0.0",
|
|
77
|
+
"pixi.js": ">=8.0.0",
|
|
78
|
+
"react": ">=18.0.0",
|
|
79
|
+
"react-native": ">=0.73.0"
|
|
80
|
+
},
|
|
81
|
+
"peerDependenciesMeta": {
|
|
82
|
+
"expo-asset": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"expo-font": {
|
|
86
|
+
"optional": true
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"dependencies": {
|
|
90
|
+
"@xmldom/xmldom": "^0.8.10"
|
|
91
|
+
},
|
|
92
|
+
"devDependencies": {
|
|
93
|
+
"@types/react": "^19.2.13",
|
|
94
|
+
"@types/react-native": "^0.72.8",
|
|
95
|
+
"tsup": "^8.5.1",
|
|
96
|
+
"typescript": "^5.9.3"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview PixiJS DOMAdapter implementation for expo-gl.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the core adapter that bridges PixiJS's browser-based
|
|
5
|
+
* architecture to React Native's expo-gl WebGL implementation.
|
|
6
|
+
*
|
|
7
|
+
* @module @penabt/pixi-expo/ExpoAdapter
|
|
8
|
+
* @author Pena Team
|
|
9
|
+
* @license MIT
|
|
10
|
+
*
|
|
11
|
+
* @description
|
|
12
|
+
* PixiJS uses a DOMAdapter pattern to abstract browser APIs. This adapter
|
|
13
|
+
* implements that interface for React Native:
|
|
14
|
+
*
|
|
15
|
+
* - createCanvas: Returns ExpoCanvasElement wrapping expo-gl context
|
|
16
|
+
* - createImage: Returns image-like object for texture loading
|
|
17
|
+
* - getWebGLRenderingContext: Returns WebGL constructor
|
|
18
|
+
* - fetch: Handles remote and local asset URLs
|
|
19
|
+
* - parseXML: Uses @xmldom/xmldom for SVG and other XML parsing
|
|
20
|
+
*
|
|
21
|
+
* @example Setting up the adapter
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { ExpoAdapter, setActiveGLContext } from '@penabt/pixi-expo';
|
|
24
|
+
* import { DOMAdapter } from 'pixi.js';
|
|
25
|
+
*
|
|
26
|
+
* // Set adapter before creating Application
|
|
27
|
+
* DOMAdapter.set(ExpoAdapter);
|
|
28
|
+
*
|
|
29
|
+
* // In GLView.onContextCreate:
|
|
30
|
+
* const canvas = setActiveGLContext(gl, width, height);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import type { ExpoWebGLRenderingContext } from 'expo-gl';
|
|
35
|
+
import { ExpoCanvasElement } from './ExpoCanvasElement';
|
|
36
|
+
import { DOMParser } from '@xmldom/xmldom';
|
|
37
|
+
|
|
38
|
+
// =============================================================================
|
|
39
|
+
// MODULE STATE
|
|
40
|
+
// Tracks the currently active GL context for PixiJS rendering.
|
|
41
|
+
// =============================================================================
|
|
42
|
+
|
|
43
|
+
/** Currently active canvas element wrapper */
|
|
44
|
+
let activeCanvas: ExpoCanvasElement | null = null;
|
|
45
|
+
|
|
46
|
+
/** Currently active expo-gl WebGL context */
|
|
47
|
+
let activeGL: ExpoWebGLRenderingContext | null = null;
|
|
48
|
+
|
|
49
|
+
// =============================================================================
|
|
50
|
+
// CONTEXT MANAGEMENT FUNCTIONS
|
|
51
|
+
// Public API for managing the active GL context.
|
|
52
|
+
// =============================================================================
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Set the active GL context from expo-gl's GLView.
|
|
56
|
+
*
|
|
57
|
+
* This function must be called in GLView's onContextCreate callback
|
|
58
|
+
* before creating any PixiJS Application or renderer.
|
|
59
|
+
*
|
|
60
|
+
* @param gl - The WebGL context from expo-gl
|
|
61
|
+
* @param width - Canvas width in pixels
|
|
62
|
+
* @param height - Canvas height in pixels
|
|
63
|
+
* @returns ExpoCanvasElement configured with the GL context
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```tsx
|
|
67
|
+
* <GLView
|
|
68
|
+
* onContextCreate={(gl) => {
|
|
69
|
+
* const canvas = setActiveGLContext(
|
|
70
|
+
* gl,
|
|
71
|
+
* gl.drawingBufferWidth,
|
|
72
|
+
* gl.drawingBufferHeight
|
|
73
|
+
* );
|
|
74
|
+
* // canvas is now ready for PixiJS
|
|
75
|
+
* }}
|
|
76
|
+
* />
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export function setActiveGLContext(
|
|
80
|
+
gl: ExpoWebGLRenderingContext,
|
|
81
|
+
width: number,
|
|
82
|
+
height: number
|
|
83
|
+
): ExpoCanvasElement {
|
|
84
|
+
activeCanvas = new ExpoCanvasElement(width, height);
|
|
85
|
+
activeCanvas.setGLContext(gl);
|
|
86
|
+
activeGL = gl;
|
|
87
|
+
return activeCanvas;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get the currently active canvas element.
|
|
92
|
+
*
|
|
93
|
+
* @returns The active ExpoCanvasElement, or null if none is set
|
|
94
|
+
*/
|
|
95
|
+
export function getActiveCanvas(): ExpoCanvasElement | null {
|
|
96
|
+
return activeCanvas;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get the currently active expo-gl WebGL context.
|
|
101
|
+
*
|
|
102
|
+
* @returns The active GL context, or null if none is set
|
|
103
|
+
*/
|
|
104
|
+
export function getActiveGL(): ExpoWebGLRenderingContext | null {
|
|
105
|
+
return activeGL;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Clear the active context.
|
|
110
|
+
*
|
|
111
|
+
* Should be called when the GLView unmounts to prevent memory leaks
|
|
112
|
+
* and stale references.
|
|
113
|
+
*/
|
|
114
|
+
export function clearActiveContext(): void {
|
|
115
|
+
activeCanvas = null;
|
|
116
|
+
activeGL = null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// EXPO ADAPTER
|
|
121
|
+
// Main adapter object implementing PixiJS's Adapter interface.
|
|
122
|
+
// =============================================================================
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* PixiJS DOMAdapter implementation for React Native Expo.
|
|
126
|
+
*
|
|
127
|
+
* This object provides the bridge between PixiJS's browser expectations
|
|
128
|
+
* and React Native's expo-gl environment. It's set as the active adapter
|
|
129
|
+
* via `DOMAdapter.set(ExpoAdapter)`.
|
|
130
|
+
*
|
|
131
|
+
* @remarks
|
|
132
|
+
* Key differences from browser adapter:
|
|
133
|
+
* - Canvas 2D context is not supported (WebGL only)
|
|
134
|
+
* - FontFaceSet is not available (use expo-font)
|
|
135
|
+
* - Base URL is empty (use expo-asset for bundled resources)
|
|
136
|
+
* - XML parsing uses @xmldom/xmldom instead of DOMParser
|
|
137
|
+
*/
|
|
138
|
+
export const ExpoAdapter = {
|
|
139
|
+
// ===========================================================================
|
|
140
|
+
// CANVAS CREATION
|
|
141
|
+
// ===========================================================================
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Create a canvas element for rendering.
|
|
145
|
+
*
|
|
146
|
+
* If an active canvas exists (from setActiveGLContext), returns it.
|
|
147
|
+
* Otherwise creates a new ExpoCanvasElement that will need a GL context.
|
|
148
|
+
*
|
|
149
|
+
* @param width - Canvas width in pixels
|
|
150
|
+
* @param height - Canvas height in pixels
|
|
151
|
+
* @returns ExpoCanvasElement instance
|
|
152
|
+
*/
|
|
153
|
+
createCanvas: (width?: number, height?: number): ExpoCanvasElement => {
|
|
154
|
+
if (activeCanvas) {
|
|
155
|
+
// Update dimensions if provided
|
|
156
|
+
if (width !== undefined) activeCanvas.width = width;
|
|
157
|
+
if (height !== undefined) activeCanvas.height = height;
|
|
158
|
+
return activeCanvas;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Create placeholder canvas (will need GL context later)
|
|
162
|
+
return new ExpoCanvasElement(width ?? 1, height ?? 1);
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
// ===========================================================================
|
|
166
|
+
// IMAGE CREATION
|
|
167
|
+
// ===========================================================================
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Create an image element for texture loading.
|
|
171
|
+
*
|
|
172
|
+
* Returns a minimal HTMLImageElement-like object. For actual texture
|
|
173
|
+
* loading, use the loadExpoAsset loader extension which integrates
|
|
174
|
+
* with expo-asset.
|
|
175
|
+
*
|
|
176
|
+
* @returns Object mimicking HTMLImageElement interface
|
|
177
|
+
*/
|
|
178
|
+
createImage: (): any => {
|
|
179
|
+
const image = {
|
|
180
|
+
src: '',
|
|
181
|
+
width: 0,
|
|
182
|
+
height: 0,
|
|
183
|
+
naturalWidth: 0,
|
|
184
|
+
naturalHeight: 0,
|
|
185
|
+
complete: false,
|
|
186
|
+
crossOrigin: '' as string | null,
|
|
187
|
+
onload: null as ((this: any, ev: Event) => any) | null,
|
|
188
|
+
onerror: null as OnErrorEventHandler | null,
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Setting source would trigger image loading.
|
|
192
|
+
* Full implementation uses expo-asset or react-native Image.
|
|
193
|
+
*/
|
|
194
|
+
set source(value: string) {
|
|
195
|
+
this.src = value;
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
return image;
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
// ===========================================================================
|
|
203
|
+
// RENDERING CONTEXT ACCESS
|
|
204
|
+
// ===========================================================================
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get the Canvas 2D rendering context constructor.
|
|
208
|
+
*
|
|
209
|
+
* @returns null - Canvas 2D is not supported in expo-gl
|
|
210
|
+
*
|
|
211
|
+
* @remarks
|
|
212
|
+
* expo-gl only provides WebGL contexts. For 2D canvas operations,
|
|
213
|
+
* consider using @shopify/react-native-skia as an alternative.
|
|
214
|
+
*/
|
|
215
|
+
getCanvasRenderingContext2D: (): any => {
|
|
216
|
+
console.warn('ExpoAdapter: 2D context is not supported in expo-gl');
|
|
217
|
+
return null;
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get the WebGL rendering context constructor.
|
|
222
|
+
*
|
|
223
|
+
* @returns WebGLRenderingContext constructor
|
|
224
|
+
*/
|
|
225
|
+
getWebGLRenderingContext: (): typeof WebGLRenderingContext => {
|
|
226
|
+
return WebGLRenderingContext;
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
// ===========================================================================
|
|
230
|
+
// BROWSER API SHIMS
|
|
231
|
+
// ===========================================================================
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get navigator information.
|
|
235
|
+
*
|
|
236
|
+
* Returns minimal navigator object for feature detection.
|
|
237
|
+
* GPU access is not available in React Native.
|
|
238
|
+
*
|
|
239
|
+
* @returns Navigator-like object
|
|
240
|
+
*/
|
|
241
|
+
getNavigator: (): { userAgent: string; gpu: GPU | null } => {
|
|
242
|
+
return {
|
|
243
|
+
userAgent: 'expo-gl/react-native',
|
|
244
|
+
gpu: null,
|
|
245
|
+
};
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get the base URL for relative resource loading.
|
|
250
|
+
*
|
|
251
|
+
* @returns Empty string - React Native has no traditional base URL
|
|
252
|
+
*
|
|
253
|
+
* @remarks
|
|
254
|
+
* For bundled assets, use expo-asset's Asset.fromModule(require('./file'))
|
|
255
|
+
* instead of relative URLs.
|
|
256
|
+
*/
|
|
257
|
+
getBaseUrl: (): string => {
|
|
258
|
+
return '';
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Get the FontFaceSet for CSS font loading.
|
|
263
|
+
*
|
|
264
|
+
* @returns null - FontFaceSet is not available in React Native
|
|
265
|
+
*
|
|
266
|
+
* @remarks
|
|
267
|
+
* Use expo-font's Font.loadAsync() for font loading in Expo apps.
|
|
268
|
+
* The loadExpoFont loader extension provides PixiJS integration.
|
|
269
|
+
*/
|
|
270
|
+
getFontFaceSet: (): FontFaceSet | null => {
|
|
271
|
+
return null;
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
// ===========================================================================
|
|
275
|
+
// NETWORK REQUESTS
|
|
276
|
+
// ===========================================================================
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Fetch a resource from network or local storage.
|
|
280
|
+
*
|
|
281
|
+
* Handles different URL schemes:
|
|
282
|
+
* - http:// / https:// - Standard network fetch
|
|
283
|
+
* - file:// - Local file (requires expo-file-system)
|
|
284
|
+
* - asset:// - Bundled asset (requires expo-asset)
|
|
285
|
+
*
|
|
286
|
+
* @param url - Resource URL or Request object
|
|
287
|
+
* @param options - Fetch options
|
|
288
|
+
* @returns Promise resolving to Response
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```ts
|
|
292
|
+
* const response = await ExpoAdapter.fetch('https://example.com/data.json');
|
|
293
|
+
* const json = await response.json();
|
|
294
|
+
* ```
|
|
295
|
+
*/
|
|
296
|
+
fetch: async (url: RequestInfo, options?: RequestInit): Promise<Response> => {
|
|
297
|
+
const requestUrl = typeof url === 'string' ? url : (url as Request).url;
|
|
298
|
+
|
|
299
|
+
// Remote URL - use standard fetch
|
|
300
|
+
if (requestUrl.startsWith('http://') || requestUrl.startsWith('https://')) {
|
|
301
|
+
return fetch(requestUrl, options);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Local file URL
|
|
305
|
+
if (requestUrl.startsWith('file://')) {
|
|
306
|
+
console.warn('ExpoAdapter: Local file loading requires expo-file-system');
|
|
307
|
+
return fetch(requestUrl, options);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Asset URL or require() number
|
|
311
|
+
if (requestUrl.startsWith('asset://') || typeof url === 'number') {
|
|
312
|
+
console.warn('ExpoAdapter: Asset loading requires expo-asset');
|
|
313
|
+
throw new Error('Asset loading not implemented');
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Default - try standard fetch
|
|
317
|
+
return fetch(requestUrl, options);
|
|
318
|
+
},
|
|
319
|
+
|
|
320
|
+
// ===========================================================================
|
|
321
|
+
// XML PARSING
|
|
322
|
+
// ===========================================================================
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Parse an XML string into a Document.
|
|
326
|
+
*
|
|
327
|
+
* Uses @xmldom/xmldom since native DOMParser is not available
|
|
328
|
+
* in React Native. Required for SVG and other XML asset parsing.
|
|
329
|
+
*
|
|
330
|
+
* @param xml - XML string to parse
|
|
331
|
+
* @returns Parsed Document object
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```ts
|
|
335
|
+
* const svg = '<svg>...</svg>';
|
|
336
|
+
* const doc = ExpoAdapter.parseXML(svg);
|
|
337
|
+
* ```
|
|
338
|
+
*/
|
|
339
|
+
parseXML: (xml: string): Document => {
|
|
340
|
+
const parser = new DOMParser();
|
|
341
|
+
return parser.parseFromString(xml, 'text/xml') as unknown as Document;
|
|
342
|
+
},
|
|
343
|
+
};
|