├── .gitignore ├── ARAnimatedProvider.js ├── ARMonoView.js ├── ARPositionProvider.js ├── ARProjectedView.js ├── ARSessionProvider.js ├── ARTouchProvider.js ├── ARTouchableMonoView.js ├── ARTrackingProvider.js ├── README.md ├── RNSwiftBridge.js ├── _config.yml ├── components ├── ARBox.js ├── ARCapsule.js ├── ARCone.js ├── ARCylinder.js ├── ARGeometry.js ├── ARLight.js ├── ARMaterial.js ├── ARMaterialProperty.js ├── ARMaterials.js ├── ARModel.js ├── ARNode.js ├── ARPlane.js ├── ARProjectedPointProvider.js ├── ARPyramid.js ├── ARSKLabel.js ├── ARSKScene.js ├── ARSKVideo.js ├── ARScene.js ├── ARShape.js ├── ARSphere.js ├── ARText.js ├── ARTorus.js ├── ARTube.js ├── ARZoomResponder.js ├── old │ └── ARSprite.js └── propTypes.js ├── index.js ├── ios ├── react_native-arkit-swift-Bridging-Header.h ├── react_native-arkit-swift.xcodeproj │ ├── bob │ └── project.pbxproj ├── react_native-arkit-swift │ ├── ARExtension.swift │ ├── ARMonoview.swift │ ├── ARMonoviewManager.swift │ ├── ARPrimaryView.swift │ ├── ARPrimaryViewManager.swift │ ├── ARProjectedView.swift │ ├── ARProjectedViewManager.swift │ ├── ARSceneManager.swift │ ├── ARSecondaryView.swift │ └── ARSecondaryViewManager.swift └── rn-swift-bridge.m ├── package.json └── yarn-error.log /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | ios/.DS_Store 4 | *.xcworkspacedata 5 | *.xcuserstate 6 | *.xcbkptlist 7 | ios/react_native-arkit-swift.xcodeproj/xcuserdata/ray.xcuserdatad/xcschemes/xcschememanagement.plist 8 | ios/react_native-arkit-swift/.DS_Store 9 | .DS_Store 10 | yarn-error.log 11 | *.log 12 | yarn-error.log 13 | convert.js 14 | -------------------------------------------------------------------------------- /ARAnimatedProvider.js: -------------------------------------------------------------------------------- 1 | import React, { createContext, Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { setAnimation } from "./RNSwiftBridge"; 4 | const { Provider, Consumer } = createContext({}); 5 | class ARAnimatedProvider extends Component { 6 | providerValue = { 7 | willNativeUpdate: this.willNativeUpdate.bind(this), 8 | didNativeUpdate: this.didNativeUpdate.bind(this) 9 | }; 10 | render() { 11 | return ; 12 | } 13 | async willNativeUpdate() { 14 | await setAnimation( 15 | parseFloat(this.props.milliseconds) / 1000.0, 16 | this.props.easing 17 | ); 18 | } 19 | async didNativeUpdate() { 20 | //Do nothing 21 | } 22 | } 23 | ARAnimatedProvider.defaultProps = { 24 | milliseconds: 250, 25 | easing: "inout" 26 | }; 27 | ARAnimatedProvider.propTypes = { 28 | milliseconds: PropTypes.number, 29 | easing: PropTypes.string 30 | }; 31 | export { ARAnimatedProvider, Consumer as ARAnimatedConsumer }; 32 | export default ARAnimatedProvider; 33 | -------------------------------------------------------------------------------- /ARMonoView.js: -------------------------------------------------------------------------------- 1 | import { ARMonoView as NativeMonoView } from "./RNSwiftBridge"; 2 | import PropTypes from "prop-types"; 3 | import React, { Component } from "react"; 4 | import { ARSessionConsumer, ARSessionProvider } from "./ARSessionProvider"; 5 | class ARBaseMonoView extends Component { 6 | render() { 7 | return ( 8 | 9 | {value => { 10 | const { isStarted } = value; 11 | if (typeof isStarted === "undefined") { 12 | return ( 13 | 20 | 21 | 22 | ); 23 | } else 24 | return [ 25 | , 30 | typeof this.props.children == "function" ? ( 31 | 32 | {value => { 33 | return this.props.children(value); 34 | }} 35 | 36 | ) : this.props.children ? ( 37 | this.props.children 38 | ) : null 39 | ]; 40 | }} 41 | 42 | ); 43 | } 44 | componentDidMount() { 45 | if (typeof this.props.start == "function") this.props.start(); 46 | } 47 | componentWillUnmount() { 48 | if (typeof this.props.stop == "function") this.props.stop(); 49 | } 50 | } 51 | ARBaseMonoView.propTypes = { 52 | preview: PropTypes.bool, 53 | start: PropTypes.func, 54 | stop: PropTypes.func, 55 | debugMode: PropTypes.bool 56 | }; 57 | ARBaseMonoView.defaultProps = { 58 | preview: true, 59 | debugMode: false 60 | }; 61 | const ARMonoView = props => ( 62 | 63 | {({ start, stop }) => ( 64 | 65 | )} 66 | 67 | ); 68 | ARMonoView.propTypes = { ...ARBaseMonoView.propTypes }; 69 | export default ARMonoView; 70 | -------------------------------------------------------------------------------- /ARPositionProvider.js: -------------------------------------------------------------------------------- 1 | import React, { Component, createContext } from "react"; 2 | import { 3 | subscribeToARPositionChange, 4 | setPOVSensitivity, 5 | setPOVOrientationSensitivity 6 | } from "./RNSwiftBridge"; 7 | import PropTypes from "prop-types"; 8 | const { Provider, Consumer: ARPositionConsumer } = createContext({ 9 | position: { x: 0, y: 0, z: 0 }, 10 | orientation: {} 11 | }); 12 | class ARPositionProvider extends Component { 13 | state = { 14 | providerValue: { 15 | position: { x: 0, y: 0, z: 0 }, 16 | orientation: { x: 0 } 17 | }, 18 | positionSensitivity: -1, 19 | orientationSensitivity: -1 20 | }; 21 | positionChange = null; 22 | componentDidMount() { 23 | this.positionChange = subscribeToARPositionChange( 24 | this.onPositionChange.bind(this) 25 | ); 26 | } 27 | componentWillUnmount() { 28 | if (this.positionChange) this.positionChange.remove(); 29 | } 30 | onPositionChange(data) { 31 | this.setState({ providerValue: data }); 32 | if (typeof this.props.onPositionChange == "function") 33 | this.props.onPositionChange(data); 34 | } 35 | render() { 36 | return ( 37 | 38 | {typeof this.props.children == "function" ? ( 39 | 40 | {value => { 41 | return this.props.children(value); 42 | }} 43 | 44 | ) : ( 45 | this.props.children 46 | )} 47 | 48 | ); 49 | } 50 | static getDerivedStateFromProps(nextProps, prevState) { 51 | var ret = prevState; 52 | if (prevState.positionSensitivity != nextProps.positionSensitivity) { 53 | setPOVSensitivity(nextProps.positionSensitivity); 54 | ret.positionSensitivity = nextProps.positionSensitivity; 55 | } 56 | if (prevState.orientationSensitivity != nextProps.orientationSensitivity) { 57 | setPOVOrientationSensitivity(nextProps.orientationSensitivity); 58 | ret.orientationSensitivity = nextProps.orientationSensitivity; 59 | } 60 | return ret; 61 | } 62 | } 63 | ARPositionProvider.defaultProps = { 64 | positionSensitivity: 0.01, 65 | orientationSensitivity: 0.05 66 | }; 67 | ARPositionProvider.propTypes = { 68 | onPositionChange: PropTypes.func, 69 | positionSensitivity: PropTypes.number, 70 | orientationSensitivity: PropTypes.number 71 | }; 72 | export { ARPositionProvider, ARPositionConsumer }; 73 | export default ARPositionProvider; 74 | -------------------------------------------------------------------------------- /ARProjectedView.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import React from "react"; 3 | import { ARSessionConsumer } from "./ARSessionProvider"; 4 | import { ARNodeConsumer } from "./components/ARNode"; 5 | import { adopt } from "react-adopt"; 6 | import { ARProjectedView as SwiftARProjectedView } from "./RNSwiftBridge"; 7 | 8 | const ARBaseProjectedView = props => ( 9 | 13 | ); 14 | const Adoptee = adopt({ 15 | session: , 16 | node: 17 | }); 18 | const ARProjectedView = props => { 19 | return ( 20 | 21 | {({ session: { isStarted }, node: { nodeID } }) => { 22 | if (!isStarted) return null; 23 | return ; 24 | }} 25 | 26 | ); 27 | }; 28 | ARProjectedView.propTypes = { 29 | parentNode: PropTypes.string 30 | }; 31 | export default ARProjectedView; 32 | -------------------------------------------------------------------------------- /ARSessionProvider.js: -------------------------------------------------------------------------------- 1 | import React, { Component, createContext } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { clear, pause, resume, setWorldTracking } from "./RNSwiftBridge"; 4 | const { Provider, Consumer: ARSessionConsumer } = createContext({}); 5 | class ARSessionProvider extends Component { 6 | state = { 7 | providerValue: this.setProviderValue(true), 8 | alignment: "gravity", 9 | isStarted: false 10 | }; 11 | constructor(props) { 12 | super(props); 13 | this.state.providerValue = this.setProviderValue(true); 14 | } 15 | start() { 16 | (async () => { 17 | try { 18 | await resume(); 19 | } catch (e) {} 20 | try { 21 | await clear(); 22 | } catch (e) {} 23 | this.setState({ isStarted: true }, () => { 24 | this.setProviderValue(); 25 | }); 26 | })(); 27 | } 28 | stop() { 29 | pause(); 30 | } 31 | setProviderValue(skipState) { 32 | const providerValue = { 33 | isStarted: !!(this.state && this.state.isStarted), 34 | start: this.start.bind(this), 35 | stop: this.stop.bind(this) 36 | }; 37 | if (!skipState) this.setState({ providerValue }); 38 | return providerValue; 39 | } 40 | static getDerivedStateFromProps(nextProps, prevState) { 41 | var ret = prevState; 42 | if (nextProps.alignment && nextProps.alignment != prevState.alignment) { 43 | if (prevState.isStarted) { 44 | ret.alignment = nextProps.alignment; 45 | setWorldTracking(ret.alignment); 46 | } 47 | } 48 | return ret; 49 | } 50 | render() { 51 | return ( 52 | 53 | {typeof this.props.children == "function" ? ( 54 | {this.props.children} 55 | ) : ( 56 | this.props.children 57 | )} 58 | 59 | ); 60 | } 61 | } 62 | ARSessionProvider.propTypes = { 63 | alignment: PropTypes.string 64 | }; 65 | ARSessionProvider.defaultProps = { 66 | alignment: "gravity" 67 | }; 68 | export { ARSessionProvider, ARSessionConsumer }; 69 | export default ARSessionProvider; 70 | -------------------------------------------------------------------------------- /ARTouchProvider.js: -------------------------------------------------------------------------------- 1 | import React, { Component, createContext } from "react"; 2 | import { doTap } from "./RNSwiftBridge"; 3 | const { Provider, Consumer: ARTouchConsumer } = createContext({}); 4 | class ARTouchProvider extends Component { 5 | registeredNodes = {}; 6 | constructor(props) { 7 | super(props); 8 | this.state = { 9 | providerValue: { 10 | registerNode: this.registerNode.bind(this), 11 | removeNode: this.removeNode.bind(this), 12 | triggerAtLocation: this.triggerAtLocation.bind(this) 13 | } 14 | }; 15 | } 16 | async getNodesFromLocation(x, y) { 17 | const out = await doTap(x, y); 18 | return out; 19 | } 20 | async triggerAtLocation(prop, x, y) { 21 | const out = await this.getNodesFromLocation(x, y); 22 | if (out.nodes && out.nodes.length) { 23 | for (var x = 0; x < out.nodes.length; x++) { 24 | if (this.triggerProp(out.nodes[x], prop)) break; 25 | } 26 | } 27 | } 28 | triggerProp(nodeID, propName) { 29 | const node = this.registeredNodes[nodeID]; 30 | if ( 31 | node && 32 | node.props && 33 | node.props[propName] && 34 | typeof node.props[propName] == "function" 35 | ) { 36 | node.props[propName](); 37 | return true; 38 | } 39 | return false; 40 | } 41 | registerNode(id, node) { 42 | this.registeredNodes[id] = node; 43 | } 44 | removeNode(id) { 45 | delete this.registeredNodes[id]; 46 | } 47 | render() { 48 | return ( 49 | 50 | {typeof this.props.children == "function" ? ( 51 | {this.props.children} 52 | ) : ( 53 | this.props.children 54 | )} 55 | 56 | ); 57 | } 58 | } 59 | export { ARTouchProvider, ARTouchConsumer }; 60 | export default ARTouchProvider; 61 | -------------------------------------------------------------------------------- /ARTouchableMonoView.js: -------------------------------------------------------------------------------- 1 | import { TouchableWithoutFeedback } from "react-native"; 2 | import React, { Component } from "react"; 3 | import ARMonoView from "./ARMonoView"; 4 | import { ARTouchProvider } from "./ARTouchProvider"; 5 | const ARTouchableMonoView = props => ( 6 | 7 | {({ triggerAtLocation }) => { 8 | return ( 9 | { 11 | if (triggerAtLocation) 12 | triggerAtLocation("onPress", locationX, locationY); 13 | }} 14 | onPressIn={({ nativeEvent: { locationX, locationY } }) => { 15 | if (triggerAtLocation) 16 | triggerAtLocation("onPressIn", locationX, locationY); 17 | }} 18 | onPressOut={({ nativeEvent: { locationX, locationY } }) => { 19 | if (triggerAtLocation) 20 | triggerAtLocation("onPressOut", locationX, locationY); 21 | }} 22 | > 23 | 24 | 25 | ); 26 | }} 27 | 28 | ); 29 | ARTouchableMonoView.propTypes = ARMonoView.propTypes; 30 | export default ARTouchableMonoView; 31 | -------------------------------------------------------------------------------- /ARTrackingProvider.js: -------------------------------------------------------------------------------- 1 | import React, { Component, createContext } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { 4 | getAnchors, 5 | setImageDetection, 6 | subscribeToARImageEvent, 7 | subscribeToARPlaneEvent, 8 | setPlaneDetection, 9 | addRecognizerImage, 10 | removeRecognizerImage, 11 | subscribeToARCameraState 12 | } from "./RNSwiftBridge"; 13 | const { Provider, Consumer: ARTrackingConsumer } = createContext(); 14 | class ARTrackingProvider extends Component { 15 | state = { 16 | planeDetection: "none", 17 | imageDetection: false, 18 | transition: 0, 19 | anchors: {}, 20 | providerValue: this.setProviderValue(true), 21 | trackingLevel: "notAvailable" 22 | }; 23 | constructor(props) { 24 | super(props); 25 | this.state.providerValue = this.setProviderValue(true); 26 | } 27 | setProviderValue(skipState) { 28 | const providerValue = { 29 | anchors: this.state ? this.state.anchors : {}, 30 | trackingLevel: this.state ? this.state.trackingLevel : "notAvailable" 31 | }; 32 | if (!skipState) 33 | this.setState({ providerValue }, () => { 34 | if (this.props.onUpdateAnchors) 35 | this.props.onUpdateAnchors(this.state.providerValue.anchors); 36 | }); 37 | return providerValue; 38 | } 39 | render() { 40 | return ( 41 | 42 | {typeof this.props.children == "function" ? ( 43 | {this.props.children} 44 | ) : ( 45 | this.props.children 46 | )} 47 | 48 | ); 49 | } 50 | static getDerivedStateFromProps(nextProps, prevState) { 51 | const ret = prevState ? prevState : {}; 52 | if (!ret.todos) ret.todos = {}; 53 | if (nextProps.planeDetection != prevState.planeDetection) { 54 | ret.todos["setPlaneDetection"] = nextProps.planeDetection; 55 | ret.planeDetection = nextProps.planeDetection; 56 | } 57 | if (nextProps.imageDetection != prevState.imageDetection) { 58 | ret.todos["setImageDetection"] = nextProps.imageDetection; 59 | ret.imageDetection = nextProps.imageDetection; 60 | } 61 | if (ret.imageDetection && propDiff(nextProps.images, prevState.images)) { 62 | ret.todos["setImages"] = true; 63 | ret.images = nextProps.images; 64 | } 65 | if (!ret.todos || Object.keys(ret.todos) == 0) { 66 | delete ret.todos; 67 | } 68 | return ret; 69 | } 70 | cameraStateDetection = null; 71 | componentDidUpdate() { 72 | this.manageTodos(); 73 | this.cameraStateDetection = subscribeToARCameraState( 74 | this.updateCameraState.bind(this) 75 | ); 76 | } 77 | componentDidMount() { 78 | this.manageTodos(); 79 | if (this.cameraStateDetection) this.cameraStateDetection.remove(); 80 | this.cameraStateDetection = null; 81 | } 82 | manageTodos() { 83 | if (this.state.todos) { 84 | Object.keys(this.state.todos).forEach(k => { 85 | if (typeof this[k] == "function") { 86 | this[k](this.state.todos[k]); 87 | } 88 | }); 89 | this.setState({ todos: null }, () => { 90 | this.setProviderValue(); 91 | }); 92 | } 93 | } 94 | planeDetection = null; 95 | async setPlaneDetection(newValue) { 96 | if (["horizontal", "vertical", "both"].indexOf(newValue) > -1) { 97 | await setPlaneDetection(newValue); 98 | this.planeDetection = subscribeToARPlaneEvent( 99 | this.updatePlanes.bind(this) 100 | ); 101 | } else if (this.planeDetection) { 102 | await setPlaneDetection("none"); 103 | this.planeDetection.remove(); 104 | this.planeDetection = null; 105 | } 106 | } 107 | imageDetection = null; 108 | async setImageDetection(newValue) { 109 | await setImageDetection(!!newValue); 110 | if (newValue) { 111 | this.imageDetection = subscribeToARImageEvent( 112 | this.updateImages.bind(this) 113 | ); 114 | } 115 | if (newValue) addImageDetection(this.updateImages.bind(this)); 116 | else if (this.imageDetection) { 117 | this.imageDetection.remove(); 118 | this.imageDetection = null; 119 | } 120 | } 121 | registeredImages = {}; 122 | setImages() { 123 | const newKeys = this.state.images 124 | ? Object.keys(this.state.images).filter(k => { 125 | return !this.registeredImages[k]; 126 | }) 127 | : []; 128 | const deadKeys = this.registeredImages 129 | ? Object.keys(this.registeredImages).filter(k => { 130 | return !this.state.images[k]; 131 | }) 132 | : []; 133 | (async () => { 134 | await Promise.all( 135 | newKeys.map(k => { 136 | const { width, url } = this.state.images[k]; 137 | return addRecognizerImage(url, k, width); 138 | }) 139 | ); 140 | newKeys.forEach(k => { 141 | this.registeredImages[k] = this.state.images[k]; 142 | }); 143 | if (deadKeys.length) { 144 | await Promise.all( 145 | deadKeys.map(k => { 146 | return removeRecognizerImage(k); 147 | }) 148 | ); 149 | this.setState(({ images }) => { 150 | deadKeys.forEach(k => { 151 | delete images[k]; 152 | }); 153 | return { images: { ...images } }; 154 | }); 155 | } 156 | })(); 157 | } 158 | async updatePlanes(planeData) { 159 | const data = planeData && planeData.data; 160 | if (!data) { 161 | const anchors = cleanAnchors(await getAnchors(data)); 162 | this.setState({ anchors: anchors }, () => { 163 | this.setProviderValue(); 164 | }); 165 | } else 166 | switch (data.key) { 167 | case "planeAnchorAdded": 168 | case "planeAnchorChanged": 169 | const k = data.id; 170 | const anchor = cleanAnchor(data.anchor); 171 | if ( 172 | !this.state.anchors[k] || 173 | propDiff(this.state.anchors[k], anchor, cleanAnchor) 174 | ) { 175 | this.setState( 176 | ({ anchors }) => { 177 | return { anchors: { ...anchors, [k]: anchor } }; 178 | }, 179 | () => { 180 | this.setProviderValue(); 181 | } 182 | ); 183 | } 184 | break; 185 | case "planeAnchorRemoved": 186 | default: 187 | const anchors = cleanAnchors(await getAnchors(data)); 188 | this.setState({ anchors: anchors }, () => { 189 | this.setProviderValue(); 190 | }); 191 | } 192 | } 193 | async updateImages(data) { 194 | const anchors = await getAnchors(data); 195 | this.setState({ anchors: anchors }, () => { 196 | this.setProviderValue(); 197 | }); 198 | } 199 | async updateCameraState(data) { 200 | this.setState({ trackingLevel: data }, () => { 201 | this.setProviderValue(); 202 | }); 203 | } 204 | } 205 | ARTrackingProvider.propTypes = { 206 | planeDetection: PropTypes.string, 207 | imageDetection: PropTypes.bool, 208 | onUpdateAnchors: PropTypes.func, 209 | images: PropTypes.object 210 | }; 211 | export { ARTrackingProvider, ARTrackingConsumer }; 212 | export default ARTrackingProvider; 213 | const cleanAnchors = o => { 214 | var out = {}; 215 | if (!o) return out; 216 | Object.keys(o).forEach(k => { 217 | const v = o[k]; 218 | out[k] = cleanAnchor(v); 219 | }); 220 | return out; 221 | }; 222 | const cleanAnchor = v => { 223 | var out = {}; 224 | if (!v) return out; 225 | if (v.plane) { 226 | if (v.plane.width) 227 | v.plane.width = parseFloat(parseFloat(v.plane.width).toFixed(1)); 228 | if (v.plane.height) 229 | v.plane.height = parseFloat(parseFloat(v.plane.height).toFixed(1)); 230 | } 231 | return v; 232 | }; 233 | const propDiff = (a, b, filterFunc) => { 234 | if (a === b) return false; 235 | if ((a && !b) || (!a && b)) return true; 236 | if (!a && !b) return false; 237 | const af = filterFunc ? filterFunc(a) : a; 238 | const bf = filterFunc ? filterFunc(b) : b; 239 | 240 | const afk = Object.keys(af); 241 | const bfk = Object.keys(bf); 242 | if (afk.length != bfk.length) return true; 243 | if ( 244 | afk.filter(k => { 245 | return bfk.indexOf(k) === -1; 246 | }).length 247 | ) 248 | return true; 249 | if ( 250 | afk.filter(k => { 251 | return bf[k] != af[k]; 252 | }).length 253 | ) 254 | return true; 255 | }; 256 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-reality 2 | 3 | A React-based, JSX-centric way of interacting with Augmented Reality. Make the world your provider. 4 | 5 | Currently IOS-Only, but SceneForm may change that! 6 | 7 | ## Key Features 8 | 9 | - Primitives to give high control over every aspect. Makes animations so much easier to have nodes not attached to geometries 10 | - Layout Animations via `` 11 | - Provider-based (render prop!) tracking of self ``, screen-touch on `` and both images and planes via `` 12 | - Support for touch events at the node level via onPress, onPressIn, and onPressOut events. Registered only if using a touchablemonoview 13 | - Support for mixing in scenes and models. Import Scenekit-compatible SCN and DAE via `` and add models (like from Google Poly) via ``. 14 | - Support for mixing in multiple 2-D SpriteKit `` with composed primitives and adding them to an ``. A great way for rendering images, video and text(!) in space and performantly. 15 | 16 | ## 15-second installation: `react-reality-cli` 17 | 18 | ```bash 19 | yarn global add rhdeck/react-reality-cli # or npm i g react-reality-cli 20 | react-reality init myreality # of course, replace myreality with your preferred name 21 | cd myreality 22 | react-reality run-ios --device # react-reality acts like react-native inside a RR/RN project 23 | code . 24 | ``` 25 | 26 | _Note_ This installer utilizes [react-native-setdevteam](https://npmjs.com/package/react-native-setdevteam). If you have not used it before, it will ask you either to input your developer team ID or to give permission to find it for you in another project. This is necessary to sign your app and test on the phone. 27 | 28 | _Another Note_ This installer utilizes [react-native-bundlebase](https://npmjs.com/pacakge/react-native-bundlebase). If you have not used this package before, it will ask you for the base name you want to use for your app bundles. Your bundle then becomes [projectname].[bundle base]. This maintains uniqueness that allows you to more easily deploy to your device. 29 | 30 | Happy AR coding. 31 | 32 | ## 1-minute Installation: `react-native link` 33 | 34 | ``` 35 | react-native init myreality 36 | cd myreality 37 | yarn add \ 38 | rhdeck/react-reality \ 39 | react-native-swift \ 40 | react-native-pod 41 | react-native link 42 | ``` 43 | 44 | Since ARKit development requires iOS 11, the camera, and signing privileges to get onto device, I also recommend: 45 | 46 | ``` 47 | yarn add \ 48 | react-native-fix-ios-version \ 49 | react-native-camera-ios-enable \ 50 | react-native-setdevteam 51 | react-native setdevteam 52 | react-native link 53 | ``` 54 | 55 | Copy the sample code at the bottom of this file to your App.js to try it out. But the `react-reality-cli` approach is a lot cleaner. 56 | 57 | ## Extensions 58 | 59 | - [`react-reality-cli`](https://github.com/rhdeck/react-reality-cli): Command line interface for rapidly spinning up and managing react-reality projects 60 | - [`react-reality-holokit`](https://github.com/rhdeck/react-reality-holokit): Implementation of headset view to use the holokit by Amber Garage 61 | - [`react-reality-rnarkit-bridge`](https://github.com/rhdeck/react-reality-rnarkit-bridge): Implementing the `react-native-arkit` API on top of the `react-reality` framework. 62 | 63 | # Reference 64 | 65 | ## Views 66 | 67 | ### ARMonoView 68 | 69 | A "magic glass" renderer of both the real and virtual space from your point of view. 70 | 71 | Will auto-create a `` if it is not already the child of one. 72 | 73 | #### Props 74 | 75 | If implemented without a wrapping `` it takes the props of `` most importantly `alignment`. 76 | 77 | Otherwise, it's a View. No special (public) props. 78 | 79 | #### Sample 80 | 81 | ```javascript 82 | 83 | 84 | 85 | ``` 86 | 87 | ### ARTouchableMonoView 88 | 89 | Like `ARMonoView` but adds touchability, so that descendant nodes can implement touch event handlers. 90 | 91 | Will auto-create a `` if it is not already the child of one. 92 | 93 | #### Props 94 | 95 | If implemented without a wrapping `` it takes the props of `` most importantly `alignment`. 96 | 97 | Otherwise, it's a View. No special (public) props. 98 | 99 | #### Sample 100 | 101 | ```xml 102 | 103 | 104 | ...Other nodes rendered 105 | {console.log("I got pressed"}> 106 | ...Geometries, etc 107 | 108 | 109 | 110 | ``` 111 | 112 | ### ARProjectedView 113 | 114 | Mount to a node in the 3D space, it will show a view with the origin tied to that point. So if you turn away from that direction it will hide, and otherwise it floats on top where you want it. 115 | 116 | _Note_ that it sets the origin and does not clip boundaries, so if you want to "center" on the target point in space, set your "top" and "left" of the view to be negative, as in the sample. 117 | 118 | _Also Note_ Any view will show **on top** of virtual 3-d objects, even when the node the view is mounted on is "behind" them. For diagetic fidelity, use a plane mounted in space instead, such as the `` from `react-reality-components` 119 | 120 | #### Props 121 | 122 | - `parentNode`: ID of the node to which it should attach. Note that just putting the component as child/descendant of an `` will take care of this. 123 | 124 | #### Sample 125 | 126 | ```javascript 127 | 128 | 129 | 130 | See me over here, but not anywhere else 131 | 132 | 133 | ``` 134 | 135 | ## Providers 136 | 137 | React Reality is built with React 16.3 contexts implemented as a first-class design pattern. All providers allow you to control how the environment will operate, and by default they include their own consumer if their child is a function. 138 | 139 | ### ARSessionProvider 140 | 141 | Manages the augmented reality session. Note that no nodes are rendered until the session starts. 142 | 143 | #### Props 144 | 145 | - `alignment`: How the system should think about x/y/z when start up the AR environment. The device will be the origin - the question is whether the other axes are based on: 146 | - `gravity` in which case y is down-to-up relative to Earth's gravity but x and z are relative to whichever way the phone is pointing at the start of the session, 147 | - `compass` in which z is south-to-north and x is west-to-east or 148 | - `camera` in which they are all based on the orientation of the device itself. 149 | (Default: `gravity`) 150 | 151 | #### Sample 152 | 153 | ```xml 154 | 155 | {Well-aligned nodes!} 156 | 157 | ``` 158 | 159 | ### ARPositionProvider 160 | 161 | Tracks changes in the position of the primary point of view For ``, this is just the position of the device itself. 162 | 163 | If the immediate child is a function, the provider will wrap it in an `` to pass the function those arguments. 164 | 165 | #### Props 166 | 167 | - `sensitivity`: the required observed change, in meters, in any direction to trigger either the `onPositionChange` prop or a re-fire of the `` render prop. (Default: 0.01 - one centimeter) 168 | - `onPositionChange`: fires every time the position changes by more the designated sensitivity. Contains one argument with a `position` object (x,y,z) and an `orientation` (x,y,z,w) 169 | 170 | #### Sample 171 | 172 | ```javascript 173 | { 176 | console.log("my new lateral position is ", position.x); 177 | }} 178 | > {({position, orientation})=>{ 179 | // ... Nodes that are dependant on where I am... 180 | }} 181 | ``` 182 | 183 | ### ARTrackingProvider 184 | 185 | Detects and tracks planes and images (markers) in space, providing what's found via `` 186 | 187 | #### Props 188 | 189 | - `planeDetection`: Whether to detect planes and if so what kind., Values: "horizontal", "vertical", "both", "none" (Default: "none") 190 | - `imageDetection`: Whether to detect images defined in the images prop. Note that if there are no images in the images prop, this is not helpful. (Default: false) 191 | - `images`: Object as key-value store of the name of the image you want to hear about, and the an object with members `{url, width}`. `url` is URL to an ordinary image file. `width` is the width of the image in the real world, in meters. (it figures out height from the size ratio of the image itself). Note that this does not require any of the precompiled referenceImage stuff to work - just pass a PNG or something. 192 | - `onUpdateAnchors`: event to fire whenever the provider gets notice of a change, addition or removal of a plane or image, depending on what detection is activated. Basically fires with the same argument and under the same circumstances as the ``. 193 | 194 | #### Sample 195 | 196 | ```javascript 197 | { 207 | console.log("my current anchor list is", anchors); 208 | }} 209 | /> 210 | ``` 211 | 212 | ### ARAnimatedProvider 213 | 214 | Layout animations for AR! Declaratively define a transition time for going from one declared layout state to another. Applies to materials, geometries and nodes descending from this node. 215 | 216 | _Note_: A good way to set animation at one point but not for other descendants is to implement another intervening `` below it 217 | 218 | #### Properties 219 | 220 | - `milliseconds` Transition time in ms (Default: 250 - a quarter of a second) 221 | - `easing` Easing acceleration curve. String value with four possibilities: 222 | - "in": Start slow and speed up in the beginning of the animation. (This usually looks most natural) 223 | - "out": Go at normal speed but slow down the animation at the end. 224 | - "both": Start slow, speed up, then slow down at the end. 225 | - "none": Just move at the same speed the whole time. Has the virtue of being easy to predict where everything will be at any time. 226 | (Default: "inout") 227 | 228 | #### Sample 229 | 230 | ```javascript 231 | setInterval(()=>{ this.setState({Ypos})=> return { Ypos: Ypos + 1}}, 5000) 232 | ... 233 | 234 | 237 | 238 | 239 | 242 | > 243 | 244 | 245 | 246 | 247 | 248 | ``` 249 | 250 | ## Consumers 251 | 252 | ### ARPositionConsumer 253 | 254 | Context consumer for an ancestor ``. A good way to wrap the one node you want to act as your buddy. 255 | 256 | #### Argument members 257 | 258 | - `position`: Location of current POV (relative to initial origin) 259 | - `orientation`: Orientation of current POV in quaternion format (x,y,z,w) 260 | 261 | #### Sample 262 | 263 | ```javascript 264 | 265 | // ... intervening generations... 266 | 267 | {({ position, orientation }) => { 268 | return ( 269 | 273 | 274 | 275 | ); 276 | }} 277 | 278 | 279 | ``` 280 | 281 | ### ARTrackingConsumer 282 | 283 | Consumer for the `` above. 284 | 285 | #### Argument members 286 | 287 | - `anchors`: Key-value pairs of anchors detected with names and relevant information. The key will be the name of the node you can specify as a parentNode for mounting any additional nodes. The value will contain information relevant to the anchor: 288 | - `type`: "plane" or "image" 289 | - `plane`: Size of the plane for the identified anchor (be it an image or a detected surface) as {width, height} 290 | Note that the anchors can and should be referenced as parents to nodes to anchor a node to a particular reference point. 291 | - `name`: name of the image identified (maps to the key in the images object passed to the ``(only provided for image anchors) 292 | - `alignment`: Whether the detected plane is horizontal or vertical. This informs what orientation change you might want to apply to mounted nodes. (only provided for plane anchors) 293 | 294 | #### Sample 295 | 296 | ```javascript 297 | 298 | // ... intervening nodes 299 | 300 | {({anchors})=>{ 301 | if(anchors.starwars) { 302 | //Render a cube two meters above a galaxy far far away 303 | return ( 304 | 305 | 306 | 307 | ) 308 | } 309 | }} 310 | 311 | 312 | ``` 313 | 314 | ## Nodes 315 | 316 | A node represents position in space relative to their parent. A node need not have anything visible attached to it - in fact, that can be really desirable to manage animations through space, as you set up a node as a reference point and have other nodes position and move in relationship to it. 317 | 318 | ### ARNode 319 | 320 | Position in space relative to its identified parent. 321 | 322 | #### Props 323 | 324 | - `parentNode`: Node to be parent to this node in space. If not provided, assumes the nearest ancestor ``. If there is none, mounts relative to egocentric origin. (Note: this is usually only specified when you are establishing a node tree that is mounting to an exocentric anchor, like provided by the ``) 325 | - `position`: location of the node in meters relative to its parent. object of {x,y,z} (default: {x: 0, y: 0, z: 0}) 326 | - `scale`: resizing this node and its descendants relative to parent node. A positive value where 1.0 means scale is same as parent. (Default: 1.0) 327 | - `opacity`: Whether this node and its descendants should be see-through. Values from 0-1.0 inclusive. 0 means invisible and 1 means opaque. (Default: 1.0) 328 | - `id`: name for the node. Referenced for parentNode publicly. Most of the time you are not setting this. (Default: randomly assigned UUID) 329 | 330 | The following all describe the pose of the node. Usually you want to use one but not all three. Orientation is most robust as a quaternion, but rotation and eulerAngles are easier to work with for newcomers. 331 | 332 | - `orientation`: pose of the node expressed as a quaternion {x,y,z,w} 333 | - `rotation`: pose of the node expressed with three degrees of freedom {x,y,z} 334 | - `eulerAngles`: pose of the node expressed as euler angles {x,y,z}. (_Hint_ while they can cause rotation lock problems in complex situations, these are easier to use than orientation quaternions for those less versed in 3D programming) 335 | 336 | The following props only work when mounted inside a ``: 337 | 338 | - `onPress`: event fired with a finger comes down and comes up again over this node on a `` 339 | - `onPressIn`: event fired when finger is pressed on a `` over this node. (usually requires a geometry mounted on this node for detection to work) 340 | - `onPressOut`: event fired when the finger is lifted from a `` over this node. (usually requires a geometry mounted on this node for detection to work) 341 | 342 | ## Geometries 343 | 344 | Geometries are generally simple shapes that can be attached to nodes. Only one geometry per node. 345 | 346 | _Note_: All size measurements are in meters. Chamfer is the concept of rounding a 3-d corner. 347 | 348 | ### ARBox 349 | 350 | Creates a rectangular hexahedron geometry. C'mon. You know what a box is. Sides: 6 351 | 352 | #### Props 353 | 354 | - `height`: Height (y-axis) of the box, in meters (default: 1.0) 355 | - `width`: Width (x-axis) of the box, in meters (default: 1.0) 356 | - `length`: Length (z-axis) of the box, in meters (default: 1.0) 357 | - `chamfer`: How much to round the corners of the box (default: 0) 358 | 359 | ### ARCapsule 360 | 361 | A pill shape. Sides: 3 362 | 363 | #### Props 364 | 365 | - `capR`: Radius of the cap on the end of the pill. (default: 0.5) 366 | - `height`: Length of the cap (basically the "tube" part would be height - (capR \* 2) (default: 1) 367 | 368 | ### ARCone 369 | 370 | Cone or a cropped/partial cone. Sides: 2 if it goes to a point, and 3 if it is cropped (e.g. if `topR` and `bottomR` are greater than 0) 371 | 372 | #### Props 373 | 374 | - `topR`: Radius exposed at top of cone. Set to 0 for the full dunce-hat (Default: 0) 375 | - `bottomR`: Radius at bottom of cone. Set to 0 for an upside-down cone. (Default: 0.5) 376 | - `height`: Height of the cone. (Default: 1) 377 | 378 | ### ARCylinder 379 | 380 | A cylinder. Sides: 3 381 | 382 | #### Props 383 | 384 | - `radius`: radius of the cylinder. (Default: 0.5) 385 | - `height`: length of the cylinder. (Default: 1) 386 | 387 | ### ARPlane 388 | 389 | A single-sided plane. Note that this is invisible from one side. Sides: 1 390 | 391 | _Hint_: This is a great geometry for mounting `` content 392 | 393 | #### Props 394 | 395 | - `width`: width of plane. (Default: 1) 396 | - `height`: height of plane. (Default: 1) 397 | - `cornerRadius`: radius of a rounded corner. (Default: 0) 398 | 399 | #### Sample 400 | 401 | ```javascript 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | ``` 412 | 413 | ### ARPyramid 414 | 415 | A Pyramid. Sides: 5 416 | 417 | #### Props 418 | 419 | - `width`: x axis of the base. (Default: 1) 420 | - `length`: z axis of the base. (Default: 1) 421 | - `height`: height (y axis) (Default: 1) 422 | 423 | ### ARShape 424 | 425 | A bezier path-based 2D shape defined with SVG and extruded into 3D space. Sides: 1 if there is no extrusion, 3 if there is no chamfer, 4 if chamfer is front or back only, and 5 if there is chamfer both front and back. 426 | 427 | This is the most complicated of the basic geometries, and most of the time you won't need to use it anyway, so don't sweat if it looks like a bit much. 428 | 429 | #### Props 430 | 431 | - `pathSvg`: SVG text representation of the path to be displayed. Required throw error if this text is not provided. 432 | - `extrusion`: depth of the extrusion. (default: 1) 433 | - `chamferMode`: Whether to apply chamfer to front (1), back, (2) both (3) or neither (0). (Default: 0) 434 | - `chamferRadius`: Radius of the chamfer if chamferMode is not 0 (default: 0) 435 | 436 | _Note_: Setting a custom bezier path for the chamfer is not supported at this time. 437 | 438 | ### ARSphere 439 | 440 | A ball. Sides: 1 441 | 442 | #### Props 443 | 444 | - `radius`: Radius of the sphere. (Default: 0.5) 445 | 446 | ### ARText 447 | 448 | Extruded text in space. Sides: 3 if no chamfer, otherwise 4 449 | 450 | #### Props 451 | 452 | - `text`: Text to be rendered 453 | - `fontName`: Name of font to be used (Defaults to system default font) 454 | - `size`: Size of the font to use (usually effects how geometrically complex the text objects will be) (Default: 12) 455 | - `depth`: z-axis of the extrusion of the text (default: 0.1) 456 | - `chamfer`: chamfer/rounding of the edges from font face to the extrusion (Default: 0) 457 | 458 | _Note_: This creates complex shapes that are highly computationally expensive to render and maintain. If you want to display diagetic text, the `` is higher-quality and lower-cost. 459 | 460 | ### ARTorus 461 | 462 | A donut. Mmm, donuts. Sides: 1 463 | 464 | #### Props 465 | 466 | - `ringR`: radius of the ring (how wide is the donut sitting on a table?) (Default: 0.5) 467 | - `pipeR`: radius of the pipe itself (how tall is the donut on the table?) (Default: 0.25) 468 | 469 | ### ARTube 470 | 471 | A tube. Sides: 4 if there is any thickness to it (e.g. a difference between `innerR` and `outerR`) , otherwise 2 472 | 473 | #### Props 474 | 475 | - `innerR`: Radius of the inside of the tube. (Default: 0.25) 476 | - `outerR`: Outer radius of the tube (Default: 0.5) 477 | - `height`: Height/length of the tube. (Default: 1) 478 | 479 | _Note_ As implied by the `height` prop, the default position of a tube is vertical. Reorient by changing orentation/rotation/eulerAngles of the containing node. 480 | 481 | ## Models 482 | 483 | Mounting complex models that come from other sources makes developing interesting AR experiences much much easier. Scenes and models get mounted to nodes of interest (such as a detected anchor) and the animations etc just work. 484 | 485 | ### ARScene 486 | 487 | A wrapper for importing pre-build SCN scenes and iOS-compatible DAE ensembles. 488 | 489 | _Note_ ARKit seems a little skittish about properly mounting textures for these scenes. 490 | 491 | Animate, move it around etc by manipulating a parent node. 492 | 493 | Comes with animations running right from the point of mount. 494 | 495 | #### Props 496 | 497 | - `path`: Local file path to the downloaded SCN or DAE file. 498 | 499 | #### Sample 500 | 501 | ```javascript 502 | 503 | 504 | 505 | ``` 506 | 507 | ### ARModel 508 | 509 | A wrapper for downloaded OBJ models, such as those you can get from Google Poly. Note that it will load textures for a downloaded model from the path relative to that model, whihc means if you get the OBJ and MTL file in the same directory, you probably get all your texture goodness without further work. 510 | 511 | #### Props 512 | 513 | - `path`: Local file path to the downloaded OBJ file. 514 | 515 | #### Sample 516 | 517 | ```javascript 518 | 519 | 520 | 521 | ``` 522 | 523 | ## Materials 524 | 525 | ### ARMaterial 526 | 527 | Control over the material applied to a side of a geometry. Directly calling this element is going to be much less common than just using `` for simple application to relevant sides. 528 | 529 | #### Props 530 | 531 | - `index`: the index number of the side of the geometry that this material will apply to. 532 | 533 | The rest of these props are for more advanced/subtle manipulation. Most of your control is in the `` component. 534 | 535 | - `metalness`: Number 0-1 536 | - `roughness`: Number 0-1 537 | - `blendMode`: "Add", "Subtract", "Multiply", "Screen", "Replace" 538 | - `lightingModel`: "Constant", "Blinn", "Phong", "Lambert", "PhysicallyBased" 539 | - `shaders`: Object {Geometry, Surface, LightingModel, Fragment} 540 | - `writesToDepthBuffer`: Boolean 541 | - `colorBufferWriteMask`: "All", "None", "Alpha", "Blue", "Red", "Green 542 | - `doubleSided`: Boolean 543 | - `litPerPixel`: Boolean 544 | - `transparency`: 0-1 545 | - `fillMode`: "Fill" or "Lines" 546 | 547 | **@TODO** fill in smarter descriptions of these 548 | 549 | ### ARMaterials 550 | 551 | An affordance that applies all the ARMaterialProperty child components to every face of the material. (so you can make a red cube without having to specify each side) 552 | 553 | #### Props 554 | 555 | Inherits all props from `` except for `index`. 556 | 557 | #### Sample 558 | 559 | ```xml 560 | 561 | 562 | 563 | 564 | 565 | ``` 566 | 567 | ### ARMaterialProperty 568 | 569 | Material Properties define how a material interacts with light. The most common use is setting a color that will cause it to refract that spectrum. A second common use is setting an image that will be used as texture (e.g. a poster of an image). 570 | 571 | `` nodes are also where you mount your `` for placing dynamic 2-d content 572 | 573 | #### Props 574 | 575 | - `id`: Type of material property. Valid string values include "diffuse", "specular", "normal" (Default, because this is the one you will want to use most often: **diffuse**) 576 | - `color`: Color to be applied. Takes a string or a number 577 | - `path`: Path to file with texture to apply, as an alternative to setting a flat color 578 | - `intensity`: How much to apply this property (basically lower values wash out the effect/color/texture) 0.0-1.0 579 | 580 | #### Sample 581 | 582 | ```xml 583 | 584 | 585 | 586 | 587 | 588 | ``` 589 | 590 | ## 2-D Content 591 | 592 | Mounting 2-D content on 3-D objects in space creates cool effects for far less compuational cost, making a smoother experience. 593 | 594 | Note all dimensions here are in pixels - the scene is stretched or compressed based on the size of the face of geometry (e.g. the `` it is mounted on. 595 | 596 | ### ARSKScene 597 | 598 | Wrapper for a 2-D scene that uses SpriteKit technology on iOS. 599 | 600 | Must be mounted to a `` See sample. 601 | 602 | #### Props 603 | 604 | - `height`: Pixel height of the SKScene. NOte that this is scaled/stretched based on the geometry this is mounted on. A small "height" on a huge plane will look fuzzy. A big "height" on a tiny plane will look sharp,but be more computational intensive than is really visible. 605 | - `width`: Pixel width of SKScene 606 | - `color`: Background color of the scene 607 | 608 | #### Sample 609 | 610 | ```javascript 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | ``` 623 | 624 | ### ARSKLabel 625 | 626 | A text label to be rendered in a ``. 627 | 628 | #### Props 629 | 630 | - `text`: Text to be rendered as a string 631 | - `position`: Offset of the center of the text box from parent SK element {x, y} 632 | - `fontName`: Font to use (Default: system default) 633 | - `fontSize`: Size of font to use. Number, not string. (Default: system default) 634 | - `fontColor`: Color to draw with 635 | - `width`: Pixel width to allocate to the text (will wrap within this pixel constraint) 636 | - `lines`: Number of lines to display in the text label (default: 1) 637 | - `lineBreak`: How to handle wrapping between lines. One of `word`, `ellipsis`, `char`. (Default: `word` for multiple-line labels and `ellipsis` when it is one line) 638 | - `allowScaling`: Whether to allow the text to scale when it is too big for the space. Basically means you can apply an arbitrarily big `fontSize` and have it fit. Boolean. (Default: true) 639 | 640 | #### Sample 641 | 642 | ```javascript 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | ``` 655 | 656 | ### ARSKVideo 657 | 658 | Play a local video. Rendered in a ``. Not super-powerful as yet, but cool to have floating TV effect! 659 | 660 | #### Props 661 | 662 | - `url`: Source of the video or stream 663 | - `path`: Path to a locally stored video (handy if managing with RNFS) (overridden by `url` if the other is specified) 664 | - `isPlaying` whether the video should be playing or not 665 | - `height` target height of the video in pixels 666 | - `width` target width of the video 667 | - `position` Offset of the center of the vide from the parent SK element {x, y} 668 | 669 | #### Sample 670 | 671 | ```javascript 672 | 673 | 674 | 675 | 676 | 677 | 683 | 684 | 685 | 686 | 687 | 688 | ``` 689 | 690 | # 2-D Enhancements 691 | 692 | ## ARButton 693 | 694 | Quickly create a 2-d tappable button floating in space. It is a node, but is best mounted on a node with a bit of distance to the user. Requires viewing through `` - otherwise how would you tap it? 695 | 696 | ### Props 697 | 698 | Inherits props from `` and adds: 699 | 700 | - `title`: Title text for the button 701 | - `pressDepth`: How much to change z-position when pressed. (negative for "press-in") (Default -0.2 meters) 702 | - `highlightColor`: Color to change to when pressed. (default: purple) 703 | 704 | ## ARSign 705 | 706 | Quickly create a 2-d sign with text floating in space. Acts as a geometry. (E.g. you mount it on a node) 707 | 708 | ### Props 709 | 710 | Inherits props from `` and adds 711 | `text`: The text to display 712 | 713 | ### Example 714 | 715 | ```jsx 716 | 717 | 718 | 719 | ``` 720 | 721 | **Note** An even higher-level implementation that smushes the node props in is available as `` 722 | 723 | ## ARPlaneScene 724 | 725 | A more generalized implementation that mounts an `` on a `` to speed up generation of 2-D content floating in space. Acts as a geometry. 726 | 727 | ### Props 728 | 729 | Inherits from `` and `` and adds 730 | `ppm`: The pixels-per-meter (roughly DPI x 38) to define detail level of your sign. 731 | 732 | **Note** An even higher-level implementation that smushes the node props in is available as `` 733 | 734 | ## ARCenteredSKLabel 735 | 736 | Creates a text label with horizontal and vertical centering. 737 | 738 | ### Props 739 | 740 | Other props inherited from `` 741 | 742 | ### Example 743 | 744 | ```jsx 745 | 746 | 747 | 748 | 749 | ``` 750 | 751 | # Enhanced Geometries 752 | 753 | ## Colored Geometries 754 | 755 | These components apply a `color` prop to the diffuse property of all sides of the geometry. 756 | 757 | - ARColoredBox 758 | - ARColoredCapsule 759 | - ARColoredCone 760 | - ARColoredCapsule 761 | - ARColoredPlane 762 | - ARColoredPyramid 763 | - ARColoredShape 764 | - ARColoredSphere 765 | - ARColoredText 766 | - ARColoredTorus 767 | - ARColoredTube 768 | 769 | ## Textured Geometries 770 | 771 | These components apply a `path` prop containing a path to a locally saved texture to all sides of the geometry. 772 | 773 | - ARTexturedBox 774 | - ARTexturedCapsule 775 | - ARTexturedCone 776 | - ARTexturedCapsule 777 | - ARTexturedPlane 778 | - ARTexturedPyramid 779 | - ARTexturedShape 780 | - ARTexturedSphere 781 | - ARTexturedText 782 | - ARTexturedTorus 783 | - ARTexturedTube 784 | 785 | # Enhanced Nodes 786 | 787 | ## Basic Geometry-Node Combinations 788 | 789 | The following components smush the properties of the node with the properties of the geometry. Materials can be applied as children. 790 | 791 | - ARBoxNode 792 | - ARCapsuleNode 793 | - ARConeNode 794 | - ARCapsuleNode 795 | - ARPlaneNode 796 | - ARPyramidNode 797 | - ARShapeNode 798 | - ARSphereNode 799 | - ARTextNode 800 | - ARTorusNode 801 | - ARTubeNode 802 | - ARSignNode 803 | - ARPlaneSceneNode 804 | 805 | ## Colored Geometry-Node Combinations 806 | 807 | The following smush the properties of the node together with the properties of the geometry and add a prop `color` to trigger the diffuse color of the geometry across all surfaces. No material components need to be added. 808 | 809 | - ARColoredBoxNode 810 | - ARColoredCapsuleNode 811 | - ARColoredConeNode 812 | - ARColoredCapsuleNode 813 | - ARColoredPlaneNode 814 | - ARColoredPyramidNode 815 | - ARColoredShapeNode 816 | - ARColoredSphereNode 817 | - ARColoredTextNode 818 | - ARColoredTorusNode 819 | - ARColoredTubeNode 820 | 821 | ## Textured Geometry-Node Combinations 822 | 823 | The following components smush the props of the node and the geometry but allo add a prop `path` to a path texture to be used as the diffuse material. No material components need to be added 824 | 825 | - ARTexturedBoxNode 826 | - ARTexturedCapsuleNode 827 | - ARTexturedConeNode 828 | - ARTexturedCapsuleNode 829 | - ARTexturedPlaneNode 830 | - ARTexturedPyramidNode 831 | - ARTexturedShapeNode 832 | - ARTexturedSphereNode 833 | - ARTexturedTextNode 834 | - ARTexturedTorusNode 835 | - ARTexturedTubeNode 836 | 837 | ## ARMeNode 838 | 839 | Component that represents current user position. Implements the details of a `` so you don't have to. 840 | 841 | # Enhanced Materials 842 | 843 | ## ARColor 844 | 845 | Higher-order component to apply a `color` prop as the material to the geometry you are attaching to. 846 | 847 | ```jsx 848 | 849 | 850 | 851 | ``` 852 | 853 | If prop `index` is specified, the color is applied only to that face of the geometry. 854 | 855 | ```jsx 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | ``` 865 | 866 | ## ARTexture 867 | 868 | Higher-order component to apply a `path` prop as the path to the texture image for the geometry you are attaching to. 869 | 870 | ```jsx 871 | 872 | 873 | 874 | ``` 875 | 876 | If prop `index` is specified, the texture is applied only to that face of the geometry. 877 | 878 | ```jsx 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | ``` 888 | 889 | # Enhanced Context Providers 890 | 891 | ## ARNoSession 892 | 893 | Component whose children are displayed when the AR session is not spun up yet. Use for placeholder views. 894 | 895 | ## ARIsSession 896 | 897 | Component whose chidren are displayed when the AR sesison is loaded 898 | 899 | ## ARNoTracking 900 | 901 | Component that shows children when you have no planes or images are detected. Requires `` ancestor in tree 902 | 903 | ## ARIsTracking 904 | 905 | Component that shows only when at least one plane or image detecrted. Requires `` ancestor in tree 906 | 907 | # App.js sample 908 | 909 | ```javascript 910 | import React, { Component } from "react"; 911 | import { 912 | ARTouchableMonoView, 913 | ARNode, 914 | ARBox, 915 | ARMaterial, 916 | ARMaterials, 917 | ARMaterialProperty, 918 | ARText, 919 | ARSessionProvider 920 | } from "react-reality"; 921 | export default class ARTest extends Component { 922 | state = { 923 | showPreview: true, 924 | fatColor: "blue", 925 | tallColor: "purple" 926 | }; 927 | render() { 928 | return ( 929 | 930 | 931 | { 934 | this.setState({ fatColor: "green" }); 935 | }} 936 | onPressOut={() => { 937 | this.setState({ fatColor: "blue" }); 938 | }} 939 | > 940 | 941 | 942 | 943 | 944 | 945 | { 949 | this.setState(({ tallColor }) => { 950 | return { 951 | tallColor: tallColor == "yellow" ? "purple" : "yellow" 952 | }; 953 | }); 954 | }} 955 | > 956 | 957 | 958 | 962 | 963 | 964 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | ); 990 | } 991 | } 992 | ``` 993 | 994 | # Credit-Where-Credit-Is-Due 995 | 996 | The idea for this package was as a Swift port of [react-native-arkit](https://github.com/react-native-ar/react-native-arkit), a cool project written in Objective-C, which is not a cool language. Major props to @macrozone for a heck of a lot of work. 997 | -------------------------------------------------------------------------------- /RNSwiftBridge.js: -------------------------------------------------------------------------------- 1 | import { PropTypes } from "prop-types"; 2 | import React, { Component } from "react"; 3 | import { 4 | NativeModules, 5 | NativeEventEmitter, 6 | requireNativeComponent, 7 | ViewPropTypes 8 | } from "react-native"; 9 | //#region Code for object ARMonoViewManager 10 | const NativeARMonoViewManager = NativeModules.ARMonoViewManager; 11 | const doTap = async (x, y) => { 12 | return await NativeARMonoViewManager.doTap(x, y); 13 | }; 14 | //#endregion 15 | const NativeARMonoView = requireNativeComponent("ARMonoView", ARMonoView); 16 | class ARMonoView extends Component { 17 | render() { 18 | return ; 19 | } 20 | } 21 | ARMonoView.propTypes = { 22 | preview: PropTypes.bool, 23 | debugMode: PropTypes.bool, 24 | ...ViewPropTypes 25 | }; 26 | const NativeARPrimaryView = requireNativeComponent( 27 | "ARPrimaryView", 28 | ARPrimaryView 29 | ); 30 | class ARPrimaryView extends Component { 31 | render() { 32 | return ; 33 | } 34 | } 35 | ARPrimaryView.propTypes = { 36 | interPupilaryDistance: PropTypes.number, 37 | holoOffsetY: PropTypes.number, 38 | holoOffsetZ: PropTypes.number, 39 | holoOffsetX: PropTypes.number, 40 | fieldOfView: PropTypes.number, 41 | ...ViewPropTypes 42 | }; 43 | const NativeARProjectedView = requireNativeComponent( 44 | "ARProjectedView", 45 | ARProjectedView 46 | ); 47 | class ARProjectedView extends Component { 48 | render() { 49 | return ; 50 | } 51 | } 52 | ARProjectedView.propTypes = { 53 | parentNode: PropTypes.string, 54 | ...ViewPropTypes 55 | }; 56 | //#region Code for object ARSceneManager 57 | const NativeARSceneManager = NativeModules.ARSceneManager; 58 | const addNode = async (node, parentID) => { 59 | return await NativeARSceneManager.addNode(node, parentID); 60 | }; 61 | const removeNode = async id => { 62 | return await NativeARSceneManager.removeNode(id); 63 | }; 64 | const updateNode = async (forNode, newProps) => { 65 | return await NativeARSceneManager.updateNode(forNode, newProps); 66 | }; 67 | const setBox = async (g, forNode) => { 68 | return await NativeARSceneManager.setBox(g, forNode); 69 | }; 70 | const setCapsule = async (g, forNode) => { 71 | return await NativeARSceneManager.setCapsule(g, forNode); 72 | }; 73 | const setCone = async (g, forNode) => { 74 | return await NativeARSceneManager.setCone(g, forNode); 75 | }; 76 | const setCylinder = async (g, forNode) => { 77 | return await NativeARSceneManager.setCylinder(g, forNode); 78 | }; 79 | const setPlane = async (g, forNode) => { 80 | return await NativeARSceneManager.setPlane(g, forNode); 81 | }; 82 | const setPyramid = async (g, forNode) => { 83 | return await NativeARSceneManager.setPyramid(g, forNode); 84 | }; 85 | const setSphere = async (g, forNode) => { 86 | return await NativeARSceneManager.setSphere(g, forNode); 87 | }; 88 | const setText = async (g, forNode) => { 89 | return await NativeARSceneManager.setText(g, forNode); 90 | }; 91 | const setTorus = async (g, forNode) => { 92 | return await NativeARSceneManager.setTorus(g, forNode); 93 | }; 94 | const setTube = async (g, forNode) => { 95 | return await NativeARSceneManager.setTube(g, forNode); 96 | }; 97 | const setShape = async (g, forNode) => { 98 | return await NativeARSceneManager.setShape(g, forNode); 99 | }; 100 | const setGeometry = async (geometry, forNode) => { 101 | return await NativeARSceneManager.setGeometry(geometry, forNode); 102 | }; 103 | const setLight = async (light, forNode) => { 104 | return await NativeARSceneManager.setLight(light, forNode); 105 | }; 106 | const removeLight = async forNode => { 107 | return await NativeARSceneManager.removeLight(forNode); 108 | }; 109 | const setMaterial = async (material, forNode, atPosition) => { 110 | return await NativeARSceneManager.setMaterial(material, forNode, atPosition); 111 | }; 112 | const setMaterialProperty = async ( 113 | json, 114 | propertyName, 115 | forMaterialAtPosition, 116 | forNode 117 | ) => { 118 | return await NativeARSceneManager.setMaterialProperty( 119 | json, 120 | propertyName, 121 | forMaterialAtPosition, 122 | forNode 123 | ); 124 | }; 125 | const removeGeometry = async forNode => { 126 | return await NativeARSceneManager.removeGeometry(forNode); 127 | }; 128 | const removeMaterial = async (forNode, atPosition) => { 129 | return await NativeARSceneManager.removeMaterial(forNode, atPosition); 130 | }; 131 | const setScene = async (forNode, sourcePath) => { 132 | return await NativeARSceneManager.setScene(forNode, sourcePath); 133 | }; 134 | const setModel = async (forNode, sourcePath) => { 135 | return await NativeARSceneManager.setModel(forNode, sourcePath); 136 | }; 137 | const addSKSceneReference = async scene => { 138 | return await NativeARSceneManager.addSKSceneReference(scene); 139 | }; 140 | const addSKSceneByReference = async ( 141 | sceneName, 142 | forNode, 143 | atPosition, 144 | withType 145 | ) => { 146 | return await NativeARSceneManager.addSKSceneByReference( 147 | sceneName, 148 | forNode, 149 | atPosition, 150 | withType 151 | ); 152 | }; 153 | const addSKScene = async (scene, forNode, atPosition, withType) => { 154 | return await NativeARSceneManager.addSKScene( 155 | scene, 156 | forNode, 157 | atPosition, 158 | withType 159 | ); 160 | }; 161 | const updateSKScene = async (scene, forNode, atPosition, withType) => { 162 | return await NativeARSceneManager.updateSKScene( 163 | scene, 164 | forNode, 165 | atPosition, 166 | withType 167 | ); 168 | }; 169 | const setSKLabelNode = async (node, toParent) => { 170 | return await NativeARSceneManager.setSKLabelNode(node, toParent); 171 | }; 172 | const updateSKLabelNode = async json => { 173 | return await NativeARSceneManager.updateSKLabelNode(json); 174 | }; 175 | const setSKVideoNode = async (node, toParent) => { 176 | return await NativeARSceneManager.setSKVideoNode(node, toParent); 177 | }; 178 | const updateSKVideoNode = async json => { 179 | return await NativeARSceneManager.updateSKVideoNode(json); 180 | }; 181 | const setSKNode = async (node, toParent) => { 182 | return await NativeARSceneManager.setSKNode(node, toParent); 183 | }; 184 | const removeSKNode = async name => { 185 | return await NativeARSceneManager.removeSKNode(name); 186 | }; 187 | const removeSKScene = async (forNode, atPosition, withType) => { 188 | return await NativeARSceneManager.removeSKScene( 189 | forNode, 190 | atPosition, 191 | withType 192 | ); 193 | }; 194 | const addSKLabelNode = async (node, toParent) => { 195 | return await NativeARSceneManager.addSKLabelNode(node, toParent); 196 | }; 197 | const addSKNode = async (node, toParent) => { 198 | return await NativeARSceneManager.addSKNode(node, toParent); 199 | }; 200 | const clear = async () => { 201 | return await NativeARSceneManager.clear(); 202 | }; 203 | const resume = async () => { 204 | return await NativeARSceneManager.resume(); 205 | }; 206 | const pause = async () => { 207 | return await NativeARSceneManager.pause(); 208 | }; 209 | const setAnimation = async (seconds, type) => { 210 | return await NativeARSceneManager.setAnimation(seconds, type); 211 | }; 212 | const setAnimationDuration = async seconds => { 213 | return await NativeARSceneManager.setAnimationDuration(seconds); 214 | }; 215 | const setAnimationType = async type => { 216 | return await NativeARSceneManager.setAnimationType(type); 217 | }; 218 | const setPlaneDetection = async detectPlanes => { 219 | return await NativeARSceneManager.setPlaneDetection(detectPlanes); 220 | }; 221 | const getAnchors = async () => { 222 | return await NativeARSceneManager.getAnchors(); 223 | }; 224 | const removeAnchor = async id => { 225 | return await NativeARSceneManager.removeAnchor(id); 226 | }; 227 | const addRecognizerImage = async (url, name, width) => { 228 | return await NativeARSceneManager.addRecognizerImage(url, name, width); 229 | }; 230 | const removeRecognizerImage = async name => { 231 | return await NativeARSceneManager.removeRecognizerImage(name); 232 | }; 233 | const setImageDetection = async doDetect => { 234 | return await NativeARSceneManager.setImageDetection(doDetect); 235 | }; 236 | const projectNode = async nodeID => { 237 | return await NativeARSceneManager.projectNode(nodeID); 238 | }; 239 | const projectWorldPoint = async v => { 240 | return await NativeARSceneManager.projectWorldPoint(v); 241 | }; 242 | const setPOVSensitivity = async newSensitivity => { 243 | return await NativeARSceneManager.setPOVSensitivity(newSensitivity); 244 | }; 245 | const setPOVOrientationSensitivity = async newSensitivity => { 246 | return await NativeARSceneManager.setPOVOrientationSensitivity( 247 | newSensitivity 248 | ); 249 | }; 250 | const getPOV = async () => { 251 | return await NativeARSceneManager.getPOV(); 252 | }; 253 | const setWorldTracking = async trackingMode => { 254 | return await NativeARSceneManager.setWorldTracking(trackingMode); 255 | }; 256 | const hitTestPlane = async (point, detectType) => { 257 | return await NativeARSceneManager.hitTestPlane(point, detectType); 258 | }; 259 | //#endregion 260 | //#region events for object ARSceneManager 261 | var _getNativeARSceneManagerEventEmitter = null; 262 | const getNativeARSceneManagerEventEmitter = () => { 263 | if (!_getNativeARSceneManagerEventEmitter) 264 | _getNativeARSceneManagerEventEmitter = new NativeEventEmitter( 265 | NativeARSceneManager 266 | ); 267 | return _getNativeARSceneManagerEventEmitter; 268 | }; 269 | const subscribeToARSessionError = cb => { 270 | return getNativeARSceneManagerEventEmitter().addListener( 271 | "ARSessionError", 272 | cb 273 | ); 274 | }; 275 | const subscribeToAREvent = cb => { 276 | return getNativeARSceneManagerEventEmitter().addListener("AREvent", cb); 277 | }; 278 | const subscribeToARPlaneEvent = cb => { 279 | return getNativeARSceneManagerEventEmitter().addListener("ARPlaneEvent", cb); 280 | }; 281 | const subscribeToARImageEvent = cb => { 282 | return getNativeARSceneManagerEventEmitter().addListener("ARImageEvent", cb); 283 | }; 284 | const subscribeToARCameraState = cb => { 285 | return getNativeARSceneManagerEventEmitter().addListener("ARCameraState", cb); 286 | }; 287 | const subscribeToARPositionChange = cb => { 288 | return getNativeARSceneManagerEventEmitter().addListener( 289 | "ARPositionChange", 290 | cb 291 | ); 292 | }; 293 | //#endregion 294 | const NativeARSecondaryView = requireNativeComponent( 295 | "ARSecondaryView", 296 | ARSecondaryView 297 | ); 298 | class ARSecondaryView extends Component { 299 | render() { 300 | return ; 301 | } 302 | } 303 | ARSecondaryView.propTypes = { 304 | ...ViewPropTypes 305 | }; 306 | //#region Event marshalling object 307 | const RNSEvents = { 308 | ARSessionError: subscribeToARSessionError, 309 | AREvent: subscribeToAREvent, 310 | ARPlaneEvent: subscribeToARPlaneEvent, 311 | ARImageEvent: subscribeToARImageEvent, 312 | ARCameraState: subscribeToARCameraState, 313 | ARPositionChange: subscribeToARPositionChange 314 | }; 315 | //#endregion 316 | //#region Exports 317 | export { 318 | doTap, 319 | ARMonoView, 320 | ARPrimaryView, 321 | ARProjectedView, 322 | addNode, 323 | removeNode, 324 | updateNode, 325 | setBox, 326 | setCapsule, 327 | setCone, 328 | setCylinder, 329 | setPlane, 330 | setPyramid, 331 | setSphere, 332 | setText, 333 | setTorus, 334 | setTube, 335 | setShape, 336 | setGeometry, 337 | setLight, 338 | removeLight, 339 | setMaterial, 340 | setMaterialProperty, 341 | removeGeometry, 342 | removeMaterial, 343 | setScene, 344 | setModel, 345 | addSKSceneReference, 346 | addSKSceneByReference, 347 | addSKScene, 348 | updateSKScene, 349 | setSKLabelNode, 350 | updateSKLabelNode, 351 | setSKVideoNode, 352 | updateSKVideoNode, 353 | setSKNode, 354 | removeSKNode, 355 | removeSKScene, 356 | addSKLabelNode, 357 | addSKNode, 358 | clear, 359 | resume, 360 | pause, 361 | setAnimation, 362 | setAnimationDuration, 363 | setAnimationType, 364 | setPlaneDetection, 365 | getAnchors, 366 | removeAnchor, 367 | addRecognizerImage, 368 | removeRecognizerImage, 369 | setImageDetection, 370 | projectNode, 371 | projectWorldPoint, 372 | setPOVSensitivity, 373 | setPOVOrientationSensitivity, 374 | getPOV, 375 | setWorldTracking, 376 | hitTestPlane, 377 | subscribeToARSessionError, 378 | subscribeToAREvent, 379 | subscribeToARPlaneEvent, 380 | subscribeToARImageEvent, 381 | subscribeToARCameraState, 382 | subscribeToARPositionChange, 383 | ARSecondaryView, 384 | RNSEvents 385 | }; 386 | //#endregion 387 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /components/ARBox.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | import { setBox } from "../RNSwiftBridge"; 4 | export default ARGeometry( 5 | setBox, 6 | { 7 | width: PropTypes.number, 8 | height: PropTypes.number, 9 | length: PropTypes.number, 10 | chamfer: PropTypes.number 11 | }, 12 | 6, 13 | { 14 | height: 1, 15 | width: 1, 16 | length: 1, 17 | chamfer: 0 18 | } 19 | ); 20 | -------------------------------------------------------------------------------- /components/ARCapsule.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | 4 | import { setCapsule } from "../RNSwiftBridge"; 5 | export default ARGeometry( 6 | setCapsule, 7 | { 8 | capR: PropTypes.number, 9 | height: PropTypes.number 10 | }, 11 | 3, 12 | { 13 | capR: 0.5, 14 | height: 1 15 | } 16 | ); 17 | -------------------------------------------------------------------------------- /components/ARCone.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | 4 | import { setCone } from "../RNSwiftBridge"; 5 | export default ARGeometry( 6 | setCone, 7 | { 8 | topR: PropTypes.number, 9 | bottomR: PropTypes.number, 10 | height: PropTypes.number 11 | }, 12 | ({ topR, bottomR }) => { 13 | if (topR > 0 && bottomR > 0) { 14 | return 3; 15 | } 16 | return 2; 17 | }, 18 | { 19 | topR: 0, 20 | bottomR: 0.5, 21 | height: 1 22 | } 23 | ); 24 | -------------------------------------------------------------------------------- /components/ARCylinder.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | import { setCylinder } from "../RNSwiftBridge"; 4 | export default ARGeometry( 5 | setCylinder, 6 | { 7 | radius: PropTypes.number, 8 | height: PropTypes.number 9 | }, 10 | 2, 11 | { 12 | radius: 0.5, 13 | height: 1 14 | } 15 | ); 16 | -------------------------------------------------------------------------------- /components/ARGeometry.js: -------------------------------------------------------------------------------- 1 | import React, { Component, createContext } from "react"; 2 | import PropTypes from "prop-types"; 3 | import filter from "lodash/filter"; 4 | import pickBy from "lodash/pickBy"; 5 | import { adopt } from "react-adopt"; 6 | import { removeGeometry } from "../RNSwiftBridge"; 7 | import { ARNodeConsumer } from "./ARNode"; 8 | import { ARAnimatedConsumer } from "../ARAnimatedProvider"; 9 | const { Provider, Consumer: ARGeometryConsumer } = createContext({}); 10 | 11 | const ARGeometry = (mountFunc, geomProps, numSides, defaults) => { 12 | const ARBaseGeometry = class extends Component { 13 | state = { 14 | updateState: "doMount" // Finite state: shouldMount, doMount, Mounting, doNext, do, doing, done 15 | }; 16 | constructor(props) { 17 | super(props); 18 | this.state.providerValue = { 19 | numSides: typeof numSides == "function" ? numSides(props) : numSides 20 | }; 21 | } 22 | async nativeUpdate() { 23 | if (this.state.updateState == "doMount") { 24 | if (!this.props.parentNode) 25 | throw new Error("Cannot mount a Geometry without a parent Node"); 26 | this.setState({ updateState: "Mounting" }); 27 | try { 28 | if (this.props.willNativeUpdate) await this.props.willNativeUpdate(); 29 | await mountFunc(this.state.geomProps, this.props.parentNode); 30 | if (this.props.didNativeUpdate) await this.props.didNativeUpdate(); 31 | this.setState(({ updateState }) => { 32 | return { updateState: updateState == "doNext" ? "do" : "done" }; 33 | }); 34 | } catch (e) { 35 | this.setState({ updateState: "doMount" }); 36 | console.log("I got an error", e); 37 | } 38 | } else if (this.state.updateState == "do") { 39 | if (!this.props.parentNode) 40 | throw new Error("Cannot mount a Geometry without a parent Node"); 41 | this.setState({ updateState: "doing" }); 42 | try { 43 | if (this.props.willNativeUpdate) await this.props.willNativeUpdate(); 44 | await mountFunc(this.state.geomProps, this.props.parentNode); 45 | if (this.props.didNativeUpdate) await this.props.didNativeUpdate(); 46 | //DO something 47 | this.setState(({ updateState }) => { 48 | return { updateState: updateState == "doNext" ? "do" : "done" }; 49 | }); 50 | } catch (e) { 51 | console.log("I got an error", e); 52 | this.setState({ updateState: "doMount" }); 53 | } 54 | } 55 | } 56 | componentWillUnmount() { 57 | if (!this.props.parentNode) 58 | throw new Error("Cannot mount a Geometry without a parent Node"); 59 | async () => { 60 | try { 61 | await removeGeometry(this.props.parentNode); 62 | } catch (e) {} 63 | }; 64 | } 65 | render() { 66 | if (!this.props.children) return null; 67 | if ( 68 | ["shouldMount", "doMount", "Mounting", "doing"].indexOf( 69 | this.state.updateState 70 | ) > -1 71 | ) 72 | return null; 73 | return ( 74 | 75 | {this.props.children} 76 | 77 | ); 78 | } 79 | componentDidMount() { 80 | this.nativeUpdate(); 81 | } 82 | componentDidUpdate() { 83 | this.nativeUpdate(); 84 | } 85 | static getDerivedStateFromProps(nextProps, prevState) { 86 | var ret = prevState; 87 | if (propDiff(prevState.geomProps, nextProps)) { 88 | if (["shouldMount", "doMount"].indexOf(ret.updateState) == -1) 89 | ret.updateState = 90 | ["doing", "Mounting"].indexOf(prevState.updateState) > -1 91 | ? "doNext" 92 | : "do"; 93 | ret.geomProps = propFilter(nextProps); 94 | } 95 | return ret; 96 | } 97 | }; 98 | const propFilter = props => { 99 | return pickBy(props, (v, k) => { 100 | return geomPropKeys.indexOf(k) > -1; 101 | }); 102 | }; 103 | const propDiff = (a, b) => { 104 | if (a === b) return false; 105 | if (a & !b || !a & b) return true; 106 | const af = propFilter(a); 107 | const bf = propFilter(b); 108 | 109 | const afk = Object.keys(af); 110 | const bfk = Object.keys(bf); 111 | if (afk.length != bfk.length) return true; 112 | if ( 113 | afk.filter(k => { 114 | return bfk.indexOf(k) === -1; 115 | }).length 116 | ) 117 | return true; 118 | if ( 119 | afk.filter(k => { 120 | return bf[k] != af[k]; 121 | }).length 122 | ) 123 | return true; 124 | }; 125 | ARBaseGeometry.propTypes = { 126 | ...geomProps, 127 | parentNode: PropTypes.string, 128 | willNativeUpdate: PropTypes.func, 129 | didNativeUpdate: PropTypes.func 130 | }; 131 | if (defaults) { 132 | ARBaseGeometry.defaultProps = defaults; 133 | } 134 | const geomPropKeys = Object.keys(ARBaseGeometry.propTypes); 135 | const Adoptee = adopt({ 136 | animated: , 137 | node: 138 | }); 139 | const ARGeometry = props => { 140 | return ( 141 | 142 | {({ 143 | animated: { willNativeUpdate, didNativeUpdate }, 144 | node: { nodeID } 145 | }) => { 146 | return ( 147 | 153 | ); 154 | }} 155 | 156 | ); 157 | }; 158 | return ARGeometry; 159 | }; 160 | export { ARGeometry, ARGeometryConsumer, Provider as ARGeometryProvider }; 161 | export default ARGeometry; 162 | -------------------------------------------------------------------------------- /components/ARLight.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { adopt } from "react-adopt"; 4 | import { processColor } from "react-native"; 5 | import pickBy from "lodash/pickBy"; 6 | import includes from "lodash/includes"; 7 | import { ARNodeConsumer } from "./ARNode"; 8 | import { ARAnimatedConsumer } from "../ARAnimatedProvider"; 9 | import { setLight, removeLight } from "../RNSwiftBridge"; 10 | import { ARGeometryProvider } from "./ARGeometry"; 11 | class ARBaseLight extends Component { 12 | state = { updateState: "doMount" }; 13 | render() { 14 | if (!this.props.children) return null; 15 | if ( 16 | ["shouldMount", "doMount", "Mounting", "doing"].indexOf( 17 | this.state.updateState 18 | ) > -1 19 | ) 20 | return null; 21 | //Setting no-op geometryprovider so if someone adds materials underneath, they get ignored. 22 | return ( 23 | 24 | {this.props.children} 25 | 26 | ); 27 | } 28 | componentWillUnmount() { 29 | if (!this.props.parentNode) 30 | throw new Error("Cannot mount a Geometry without a parent Node"); 31 | async () => { 32 | try { 33 | await removeLight(this.props.parentNode); 34 | } catch (e) {} 35 | }; 36 | } 37 | componentDidMount() { 38 | this.nativeUpdate(); 39 | } 40 | componentDidUpdate() { 41 | this.nativeUpdate(); 42 | } 43 | static getDerivedStateFromProps(nextProps, prevState) { 44 | var ret = prevState; 45 | if (propDiff(prevState.lightProps, nextProps)) { 46 | if (["shouldMount", "doMount"].indexOf(ret.updateState) == -1) { 47 | ret.updateState = 48 | ["doing", "Mounting"].indexOf(prevState.updateState) > -1 49 | ? "doNext" 50 | : "do"; 51 | } 52 | ret.lightProps = propFilter(nextProps); 53 | } 54 | return ret; 55 | } 56 | async nativeUpdate() { 57 | if (this.state.updateState == "doMount") { 58 | if (!this.props.parentNode) 59 | throw new Error("Cannot mount a Geometry without a parent Node"); 60 | this.setState({ updateState: "Mounting" }); 61 | try { 62 | if (this.props.willNativeUpdate) await this.props.willNativeUpdate(); 63 | await setLight(this.state.lightProps, this.props.parentNode); 64 | if (this.props.didNativeUpdate) await this.props.didNativeUpdate(); 65 | this.setState(({ updateState }) => { 66 | return { updateState: updateState == "doNext" ? "do" : "done" }; 67 | }); 68 | } catch (e) { 69 | this.setState({ updateState: "doMount" }); 70 | console.log("I got an error", e); 71 | } 72 | } else if (this.state.updateState == "do") { 73 | if (!this.props.parentNode) 74 | throw new Error("Cannot mount a Geometry without a parent Node"); 75 | this.setState({ updateState: "doing" }); 76 | try { 77 | if (this.props.willNativeUpdate) await this.props.willNativeUpdate(); 78 | await setLight(this.state.lightProps, this.props.parentNode); 79 | if (this.props.didNativeUpdate) await this.props.didNativeUpdate(); 80 | //DO something 81 | this.setState(({ updateState }) => { 82 | return { updateState: updateState == "doNext" ? "do" : "done" }; 83 | }); 84 | } catch (e) { 85 | console.log("I got an error", e); 86 | this.setState({ updateState: "doMount" }); 87 | } 88 | } 89 | } 90 | } 91 | const Adoptee = adopt({ 92 | animated: , 93 | node: 94 | }); 95 | const ARLight = props => { 96 | return ( 97 | 98 | {({ 99 | animated: { willNativeUpdate, didNativeUpdate }, 100 | node: { nodeID } 101 | }) => { 102 | return ( 103 | 109 | ); 110 | }} 111 | 112 | ); 113 | }; 114 | const propFilter = props => { 115 | const temp = pickBy( 116 | props, 117 | (v, k) => 118 | materialPropertyPropTypeKeys.indexOf(k) > -1 && 119 | !includes( 120 | ["updateMaterial", "id", "willNativeUpdate", "didNativeUpdate"], 121 | k 122 | ) 123 | ); 124 | if (typeof temp.color == "string") temp.color = processColor(temp.color); 125 | return temp; 126 | }; 127 | const propDiff = (a, b) => { 128 | if (a === b) return false; 129 | if (a & !b || !a & b) return true; 130 | const af = propFilter(a); 131 | const bf = propFilter(b); 132 | 133 | const afk = Object.keys(af); 134 | const bfk = Object.keys(bf); 135 | if (afk.length != bfk.length) return true; 136 | if ( 137 | afk.filter(k => { 138 | return bfk.indexOf(k) === -1; 139 | }).length 140 | ) 141 | return true; 142 | if ( 143 | afk.filter(k => { 144 | return bf[k] != af[k]; 145 | }).length 146 | ) 147 | return true; 148 | }; 149 | 150 | export default ARLight; 151 | -------------------------------------------------------------------------------- /components/ARMaterial.js: -------------------------------------------------------------------------------- 1 | import React, { Component, createContext } from "react"; 2 | import { processColor } from "react-native"; 3 | import { adopt } from "react-adopt"; 4 | import { 5 | setMaterial, 6 | setMaterialProperty, 7 | removeMaterial 8 | } from "../RNSwiftBridge"; 9 | import PropTypes from "prop-types"; 10 | import { 11 | blendMode, 12 | lightingModel, 13 | shaders, 14 | colorBufferWriteMask, 15 | fillMode 16 | } from "./propTypes"; 17 | import pickBy from "lodash/pickBy"; 18 | import { ARNodeConsumer } from "./ARNode"; 19 | import { ARAnimatedConsumer } from "../ARAnimatedProvider"; 20 | const { Provider, Consumer: ARMaterialConsumer } = createContext({}); 21 | class ARBaseMaterial extends Component { 22 | state = { 23 | updateState: "doMount" // States: doMount, Mounting, (doNext, doing,) done 24 | }; 25 | constructor(props) { 26 | super(props); 27 | this.state.materialPropertyProps = { 28 | updateMaterial: this.updateMaterial.bind(this), 29 | parentNode: this.props.parentNode, 30 | index: this.props.index 31 | }; 32 | } 33 | async nativeUpdate() { 34 | if (this.state.updateState == "doMount") { 35 | const filteredProps = pickBy( 36 | this.props, 37 | (v, k) => materialPropKeys.indexOf(k) > -1 38 | ); 39 | const index = this.props.index ? this.props.index : 0; 40 | this.setState({ updateState: "Mounting" }); 41 | try { 42 | if (this.props.willNativeUpdate) await this.props.willNativeUpdate(); 43 | setMaterial(filteredProps, this.props.parentNode, index); 44 | if (this.props.didNativeUpdate) await this.props.didNativeUpdate(); 45 | this.setState({ updateState: "done" }); 46 | } catch (e) { 47 | this.setState({ updateState: "doMount" }); 48 | } 49 | } 50 | } 51 | componentDidMount() { 52 | this.nativeUpdate(); 53 | } 54 | componentDidUpdate() { 55 | this.nativeUpdate(); 56 | } 57 | async updateMaterial(id, property) { 58 | try { 59 | if (this.props.willNativeUpdate) await this.props.willNativeUpdate(); 60 | const filteredProperty = { 61 | ...property, 62 | color: 63 | typeof property.color == "string" 64 | ? processColor(property.color) 65 | : property.color 66 | }; 67 | await setMaterialProperty( 68 | filteredProperty, 69 | id, 70 | this.props.index, 71 | this.props.parentNode 72 | ); 73 | if (this.props.didNativeUpdate) await this.props.didNativeUpdate(); 74 | } catch (e) { 75 | console.log("Uh oh , mp error", e); 76 | } 77 | } 78 | render() { 79 | if (["doMount", "Mounting"].indexOf(this.state.updateState) > -1) 80 | return null; 81 | if (!this.props.children) return null; 82 | return ( 83 | 84 | {this.props.children} 85 | 86 | ); 87 | } 88 | componentWillUnmount() { 89 | async () => { 90 | try { 91 | removeMaterial(this.props.parentNode, this.props.index); 92 | } catch (e) {} 93 | }; 94 | } 95 | } 96 | ARBaseMaterial.propTypes = { 97 | parentNode: PropTypes.string, 98 | index: PropTypes.number, 99 | metalness: PropTypes.number, 100 | roughness: PropTypes.number, 101 | blendMode, 102 | lightingModel, 103 | shaders, 104 | writesToDepthBuffer: PropTypes.bool, 105 | colorBufferWriteMask, 106 | doubleSided: PropTypes.bool, 107 | litPerPixel: PropTypes.bool, 108 | transparency: PropTypes.number, 109 | fillMode, 110 | willNativeUpdate: PropTypes.func, 111 | didNativeUpdate: PropTypes.func 112 | }; 113 | const materialPropKeys = Object.keys(ARBaseMaterial.propTypes); 114 | const Adoptee = adopt({ 115 | animated: , 116 | node: 117 | }); 118 | const ARMaterial = props => { 119 | return ( 120 | 121 | {({ 122 | animated: { willNativeUpdate, didNativeUpdate }, 123 | node: { nodeID } 124 | }) => { 125 | return ( 126 | 132 | ); 133 | }} 134 | 135 | ); 136 | }; 137 | export { ARMaterial, ARMaterialConsumer }; 138 | export default ARMaterial; 139 | -------------------------------------------------------------------------------- /components/ARMaterialProperty.js: -------------------------------------------------------------------------------- 1 | import React, { Component, createContext } from "react"; 2 | import PropTypes from "prop-types"; 3 | import pickBy from "lodash/pickBy"; 4 | import includes from "lodash/includes"; 5 | import { adopt } from "react-adopt"; 6 | import { ARMaterialConsumer } from "./ARMaterial"; 7 | import { ARAnimatedConsumer } from "../ARAnimatedProvider"; 8 | const { Provider, Consumer: ARMaterialPropertyConsumer } = createContext({}); 9 | class ARBaseMaterialProperty extends Component { 10 | state = { 11 | updateState: "doMount" // valid states: doMount, Mounting, doNext, do, doing, done 12 | }; 13 | constructor(props) { 14 | super(props); 15 | this.state.providerValue = { 16 | parentNode: this.props.parentNode, 17 | index: this.props.index, 18 | materialProperty: this.props.id 19 | }; 20 | this.state.filteredProps = propFilter(this.props); 21 | } 22 | 23 | render() { 24 | if (!this.props.children) return null; 25 | if (["doMount", "Mounting"].indexOf(this.state.updateState) > -1) 26 | return null; 27 | return ( 28 | 29 | {this.props.children} 30 | 31 | ); 32 | } 33 | async nativeUpdate() { 34 | if (this.state.updateState == "doMount") { 35 | this.setState({ updateState: "Mounting" }); 36 | try { 37 | if (typeof this.props.willNativeUpdate == "function") 38 | await this.props.willNativeUpdate(); 39 | await this.props.updateMaterial( 40 | this.props.id, 41 | this.state.filteredProps 42 | ); 43 | if (typeof this.props.didNativeUpdate == "function") 44 | await this.props.didNativeUpdate(); 45 | this.setState(({ updateState }) => { 46 | return { updateState: updateState == "doNext" ? "do" : "done" }; 47 | }); 48 | } catch (e) { 49 | console.log("Hit error mounting property", this.state.filteredProps, e); 50 | this.setState({ updateState: "doMount" }); 51 | } 52 | } 53 | if (this.state.updateState == "do") { 54 | this.setState({ updateState: "doing" }); 55 | try { 56 | if (typeof this.props.willNativeUpdate == "function") 57 | await this.props.willNativeUpdate(); 58 | await this.props.updateMaterial( 59 | this.props.id, 60 | this.state.filteredProps 61 | ); 62 | if (typeof this.props.didNativeUpdate == "function") 63 | await this.props.didNativeUpdate(); 64 | this.setState(({ updateState }) => { 65 | return { updateState: updateState == "doNext" ? "do" : "done" }; 66 | }); 67 | } catch (e) { 68 | console.log("hit error updating property", e); 69 | this.setState({ updateState: "do" }); 70 | } 71 | } 72 | } 73 | componentDidMount() { 74 | this.nativeUpdate(); 75 | } 76 | componentDidUpdate() { 77 | this.nativeUpdate(); 78 | } 79 | static getDerivedStateFromProps(nextProps, prevState) { 80 | const ret = prevState; 81 | if (propDiff(prevState.filteredProps, nextProps, propFilter)) { 82 | ret.filteredProps = propFilter(nextProps); 83 | if (prevState.updateState != "doMount") { 84 | ret.updateState = 85 | ["doing", "mounting"].indexOf(prevState.updateState) > -1 86 | ? "doNext" 87 | : "do"; 88 | } 89 | } 90 | return ret; 91 | } 92 | } 93 | ARBaseMaterialProperty.propTypes = { 94 | updateMaterial: PropTypes.func, 95 | id: PropTypes.string, 96 | path: PropTypes.string, 97 | color: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 98 | intensity: PropTypes.number, 99 | willNativeUpdate: PropTypes.func, 100 | didNativeUpdate: PropTypes.func 101 | }; 102 | ARBaseMaterialProperty.defaultProps = { 103 | id: "diffuse" 104 | }; 105 | materialPropertyPropTypeKeys = Object.keys(ARBaseMaterialProperty.propTypes); 106 | const Adoptee = adopt({ 107 | animated: , 108 | material: 109 | }); 110 | const ARMaterialProperty = props => { 111 | return ( 112 | 113 | {({ 114 | animated: { willNativeUpdate, didNativeUpdate }, 115 | material: { updateMaterial, parentNode, index } 116 | }) => { 117 | return ( 118 | 126 | ); 127 | }} 128 | 129 | ); 130 | }; 131 | const propFilter = props => { 132 | return pickBy( 133 | props, 134 | (v, k) => 135 | materialPropertyPropTypeKeys.indexOf(k) > -1 && 136 | !includes( 137 | ["updateMaterial", "id", "willNativeUpdate", "didNativeUpdate"], 138 | k 139 | ) 140 | ); 141 | }; 142 | const propDiff = (a, b) => { 143 | if (a === b) return false; 144 | if (a & !b || !a & b) return true; 145 | const af = propFilter(a); 146 | const bf = propFilter(b); 147 | 148 | const afk = Object.keys(af); 149 | const bfk = Object.keys(bf); 150 | if (afk.length != bfk.length) return true; 151 | if ( 152 | afk.filter(k => { 153 | return bfk.indexOf(k) === -1; 154 | }).length 155 | ) 156 | return true; 157 | if ( 158 | afk.filter(k => { 159 | return bf[k] != af[k]; 160 | }).length 161 | ) 162 | return true; 163 | }; 164 | export { ARMaterialProperty, ARMaterialPropertyConsumer }; 165 | export default ARMaterialProperty; 166 | -------------------------------------------------------------------------------- /components/ARMaterials.js: -------------------------------------------------------------------------------- 1 | import React, { Component, Children } from "react"; 2 | import PropTypes from "prop-types"; 3 | import pickBy from "lodash/pickBy"; 4 | import ARMaterial from "./ARMaterial"; 5 | import { ARGeometryConsumer } from "./ARGeometry"; 6 | const ARMaterials = props => { 7 | if (props.children == null) return null; 8 | return ( 9 | 10 | {({ numSides }) => { 11 | var out = []; 12 | if (!numSides) return null; 13 | for (var s = 0; s < numSides; s++) { 14 | var c = null; 15 | c = Children.map(props.children, child => { 16 | return React.cloneElement(child); 17 | }); 18 | out.push(); 19 | } 20 | return out; 21 | }} 22 | 23 | ); 24 | }; 25 | ARMaterials.propTypes = pickBy( 26 | ARMaterial.propTypes, 27 | (v, k) => ["index"].indexOf(k) === -1 28 | ); 29 | export default ARMaterials; 30 | -------------------------------------------------------------------------------- /components/ARModel.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | import { setModel } from "../RNSwiftBridge"; 4 | export default ARGeometry( 5 | async ({ path }, nodeID) => { 6 | return await setModel(nodeID, path); 7 | }, 8 | { 9 | path: PropTypes.string 10 | }, 11 | 0 12 | ); 13 | -------------------------------------------------------------------------------- /components/ARNode.js: -------------------------------------------------------------------------------- 1 | import React, { Component, createContext } from "react"; 2 | import PropTypes from "prop-types"; 3 | import pickBy from "lodash/pickBy"; 4 | import { adopt } from "react-adopt"; 5 | import { ARSessionConsumer } from "../ARSessionProvider"; 6 | import { ARAnimatedConsumer } from "../ARAnimatedProvider"; 7 | import { ARTouchConsumer } from "../ARTouchProvider"; 8 | import { 9 | eulerAngles, 10 | orientation, 11 | position, 12 | rotation, 13 | scale, 14 | opacity, 15 | renderingOrder 16 | } from "./propTypes"; 17 | import UUID from "uuid/v4"; 18 | import { addNode, removeNode, updateNode } from "../RNSwiftBridge"; 19 | const { Provider, Consumer: ARNodeConsumer } = createContext({}); 20 | //#region BaseNode 21 | class ARBaseNode extends Component { 22 | state = { 23 | updateState: "shouldmount", // Valid values: "shouldmount", "domount", "mounting", "donext", "do", "doing", "done" 24 | identifier: null 25 | }; 26 | constructor(props) { 27 | super(props); 28 | this.state.identifier = props.id ? props.id : UUID(); 29 | this.state.providerValue = { nodeID: this.state.identifier }; 30 | } 31 | componentDidMount() { 32 | this.nativeUpdate(); 33 | if (this.props.registerNode) 34 | this.props.registerNode(this.state.identifier, this); 35 | } 36 | render() { 37 | if (!this.props.children) return null; 38 | if ( 39 | ["shouldmount", "domount", "mounting"].indexOf(this.state.updateState) > 40 | -1 41 | ) { 42 | return null; 43 | } 44 | return ( 45 | 46 | {this.props.children} 47 | 48 | ); 49 | } 50 | static getDerivedStateFromProps(nextProps, prevState) { 51 | var ret = prevState; 52 | if (propDiff(prevState.nodeProps, nextProps, filterObj)) { 53 | //Change to node 54 | if (prevState.updateState != "donext") { 55 | ret.updateState = 56 | prevState.updateState == "shouldmount" 57 | ? "domount" 58 | : ["mounting", "doing"].indexOf(prevState.updateState) > -1 59 | ? "donext" 60 | : "do"; 61 | } 62 | ret.nodeProps = filterObj(nextProps); 63 | } 64 | return ret; 65 | } 66 | componentDidUpdate() { 67 | this.nativeUpdate(); 68 | } 69 | async nativeUpdate() { 70 | if (this.state.updateState == "domount") { 71 | this.setState({ updateState: "mounting" }); 72 | try { 73 | const parentNode = this.props.parentNode ? this.props.parentNode : ""; 74 | const np = { ...this.state.nodeProps, id: this.state.identifier }; 75 | if (typeof this.props.willNativeUpdate == "function") 76 | await this.props.willNativeUpdate(); 77 | await addNode(np, parentNode); 78 | if (typeof this.props.didNativeUpdate == "function") 79 | await this.props.didNativeUpdate(); 80 | this.setState(({ updateState }) => { 81 | return { updateState: updateState == "donext" ? "do" : "done" }; 82 | }); 83 | } catch (e) { 84 | this.setState({ updateState: "domount" }); 85 | } 86 | } else if (this.state.updateState == "do") { 87 | this.setState({ updateState: "doing" }); 88 | try { 89 | if (typeof this.props.willNativeUpdate == "function") 90 | await this.props.willNativeUpdate(); 91 | await updateNode(this.state.identifier, this.state.nodeProps); 92 | if (typeof this.props.didNativeUpdate == "function") 93 | await this.props.didNativeUpdate(); 94 | this.setState(({ updateState }) => { 95 | return { updateState: updateState == "donext" ? "do" : "done" }; 96 | }); 97 | } catch (e) { 98 | this.setState({ updateState: "do" }); 99 | } 100 | } 101 | } 102 | componentWillUnmount() { 103 | try { 104 | removeNode(this.state.identifier); 105 | if (this.props.removeNode) this.props.removeNode(this.state.identifier); 106 | } catch (e) {} 107 | } 108 | } 109 | corePropTypes = { 110 | eulerAngles, 111 | orientation, 112 | position, 113 | rotation, 114 | scale, 115 | renderingOrder, 116 | opacity, 117 | id: PropTypes.string, 118 | parentNode: PropTypes.string 119 | }; 120 | const nodeProps = Object.keys(corePropTypes); 121 | ARBaseNode.propTypes = { 122 | ...corePropTypes, 123 | onPress: PropTypes.func, 124 | onPressIn: PropTypes.func, 125 | onPressOut: PropTypes.func, 126 | willNativeUpdate: PropTypes.func, 127 | didNativeUpdate: PropTypes.func 128 | }; 129 | //#endregion 130 | //#region ARNode 131 | const Adoptee = adopt({ 132 | session: , 133 | touch: , 134 | node: , 135 | animated: 136 | }); 137 | const ARNode = props => { 138 | return ( 139 | 140 | {({ 141 | session: { isStarted }, 142 | touch: { registerNode, removeNode }, 143 | node: { nodeID }, 144 | animated: { willNativeUpdate, didNativeUpdate } 145 | }) => { 146 | return isStarted ? ( 147 | 155 | ) : null; 156 | }} 157 | 158 | ); 159 | }; 160 | ARNode.propTypes = { 161 | ...ARBaseNode.propTypes 162 | }; 163 | //#endregion 164 | //#region Utility functions 165 | const filterObj = obj => { 166 | return pickBy(obj, (v, k) => nodeProps.indexOf(k) > -1); 167 | }; 168 | 169 | const propDiff = (a, b, func) => { 170 | if (a === b) return false; 171 | if (a & !b || !a & b) return true; 172 | const af = func ? func(a) : a; 173 | const bf = func ? func(b) : b; 174 | const afk = Object.keys(af); 175 | const bfk = Object.keys(bf); 176 | if (afk.length != bfk.length) return true; 177 | if ( 178 | afk.filter(k => { 179 | return bfk.indexOf(k) === -1; 180 | }).length 181 | ) 182 | return true; 183 | if ( 184 | afk.filter(k => { 185 | if (bf[k] == af[k]) return false; 186 | if (typeof af[k] == "object") { 187 | return propDiff(af[k], bf[k]); 188 | } 189 | return true; 190 | }).length 191 | ) 192 | return true; 193 | }; 194 | //#endregion 195 | export { ARNode, ARNodeConsumer }; 196 | export default ARNode; 197 | -------------------------------------------------------------------------------- /components/ARPlane.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | import { setPlane } from "../RNSwiftBridge"; 4 | export default ARGeometry( 5 | setPlane, 6 | { 7 | width: PropTypes.number, 8 | height: PropTypes.number, 9 | cornerRadius: PropTypes.number, 10 | cornerSegmentCount: PropTypes.number, 11 | widthSegmentCount: PropTypes.number, 12 | heightSegmentCount: PropTypes.number 13 | }, 14 | 1, 15 | { 16 | width: 1, 17 | height: 1, 18 | cornerRadius: 0 19 | } 20 | ); 21 | -------------------------------------------------------------------------------- /components/ARProjectedPointProvider.js: -------------------------------------------------------------------------------- 1 | import React, { Component, createContext } from "react"; 2 | import { ARPositionConsumer } from "../ARPositionProvider"; 3 | import { ARNodeConsumer } from "./ARNode"; 4 | import { ARSessionConsumer } from "../ARSessionProvider"; 5 | import { adopt } from "react-adopt"; 6 | import { projectNode } from "../RNSwiftBridge"; 7 | 8 | const { Provider, Consumer } = createContext({ position: {}, orientation: {} }); 9 | //#region ARBaseProjectedPointProvider 10 | class ARBaseProjectedPointProvider extends Component { 11 | state = { providerValue: { position: {}, orientation: {} } }; 12 | render() { 13 | return ( 14 | 15 | {typeof this.props.children == "function" 16 | ? this.props.children(this.state.providerValue) 17 | : this.props.children} 18 | 19 | ); 20 | } 21 | static getDerivedStateFromProps(nextProps, prevState) { 22 | const ret = prevState; 23 | ret.todos = {}; 24 | if (nextProps.newPosition) { 25 | if ( 26 | !prevState.position || 27 | JSON.stringify(prevState.position) != 28 | JSON.stringify(nextProps.newPosition) 29 | ) { 30 | ret.todos.updatePosition = true; 31 | ret.position = nextProps.newPosition; 32 | } 33 | } 34 | return ret; 35 | } 36 | componentDidMount() { 37 | this.manageTodos(); 38 | } 39 | componentDidUpdate() { 40 | this.manageTodos(); 41 | } 42 | manageTodos() { 43 | if (!this.state.todos) return; 44 | Object.keys(this.state.todos).forEach(k => { 45 | const v = this.state.todos[k]; 46 | if (typeof this[k] == "function") { 47 | this[k](v); 48 | } 49 | this.setState({ todos: null }); 50 | }); 51 | } 52 | async updatePosition() { 53 | try { 54 | const pos = await projectNode(this.props.nodeID); 55 | this.setState(({ providerValue }) => { 56 | if (pos.z > 1) { 57 | console.log("hiding because pos is behind me"); 58 | if (providerValue.position.x) { 59 | return { providerValue: { position: {}, orientation: {} } }; 60 | } else return { providerValue }; 61 | } 62 | const z = pos.z; 63 | const x = parseInt(pos.x); 64 | if (x == providerValue.position.x) return { providerValue }; 65 | const y = parseInt(pos.y); 66 | if (y == providerValue.position.y) return { providerValue }; 67 | return { providerValue: { ...providerValue, position: { x, y, z } } }; 68 | }); 69 | } catch (e) { 70 | console.log("Error in updatePosition", e); 71 | } 72 | } 73 | } 74 | //#endregion 75 | //#region ARProjectedPointProvider 76 | const Adoptee = adopt({ 77 | session: , 78 | position: , 79 | node: 80 | }); 81 | const ARProjectedPointProvider = props => ( 82 | 83 | {({ 84 | session: { isStarted }, 85 | position: { position, orientation }, 86 | node: { nodeID } 87 | }) => { 88 | if (!isStarted) return null; 89 | if (!nodeID) return null; 90 | return ( 91 | 97 | ); 98 | }} 99 | 100 | ); 101 | //#endregion 102 | export default ARProjectedPointProvider; 103 | export { ARProjectedPointProvider, Consumer as ARProjectedPointConsumer }; 104 | -------------------------------------------------------------------------------- /components/ARPyramid.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | 4 | import { setPyramid } from "../RNSwiftBridge"; 5 | export default ARGeometry( 6 | setPyramid, 7 | { 8 | width: PropTypes.number, 9 | length: PropTypes.number, 10 | height: PropTypes.number 11 | }, 12 | 5, 13 | { 14 | width: 1, 15 | length: 1, 16 | height: 1 17 | } 18 | ); 19 | -------------------------------------------------------------------------------- /components/ARSKLabel.js: -------------------------------------------------------------------------------- 1 | import React, { Component, Children } from "react"; 2 | import { processColor } from "react-native"; 3 | import { 4 | removeSKNode, 5 | setSKLabelNode, 6 | updateSKLabelNode 7 | } from "../RNSwiftBridge"; 8 | import PropTypes from "prop-types"; 9 | import pickBy from "lodash/pickBy"; 10 | import UUID from "uuid/v4"; 11 | import { ARSKNodeProvider, ARSKNodeConsumer } from "./ARSKScene"; 12 | class ARBaseSKLabel extends Component { 13 | state = { 14 | identifier: UUID(), 15 | updateState: "doMount" 16 | }; 17 | constructor(props) { 18 | super(props); 19 | this.state.providerValue = { SKNodeID: this.state.identifier }; 20 | } 21 | async nativeUpdate() { 22 | if (this.state.updateState == "doMount") { 23 | this.setState({ updateState: "Mounting" }); 24 | try { 25 | const label = { 26 | ...propFilter(this.props), 27 | name: this.state.identifier 28 | }; 29 | const result = await setSKLabelNode(label, this.props.parentSKNode); 30 | this.setState(({ updateState }) => { 31 | return { updateState: updateState == "donext" ? "do" : "done" }; 32 | }); 33 | } catch (e) { 34 | this.setState({ updateState: "doMount" }); 35 | } 36 | } else if (this.state.updateState == "do") { 37 | this.setState({ updateState: "doing" }); 38 | try { 39 | const label = { 40 | ...propFilter(this.props), 41 | name: this.state.identifier 42 | }; 43 | const result = await updateSKLabelNode(label); 44 | this.setState(({ updateState }) => { 45 | return { updateState: updateState == "donext" ? "do" : "done" }; 46 | }); 47 | } catch (e) { 48 | this.setState({ updateState: "do" }); 49 | } 50 | } 51 | } 52 | componentDidMount() { 53 | this.nativeUpdate(); 54 | } 55 | componentDidUpdate() { 56 | this.nativeUpdate(); 57 | } 58 | render() { 59 | if (["doMount", "Mounting"].indexOf(this.state.updateState) > -1) 60 | return null; 61 | if (!this.props.children) return null; 62 | return ( 63 | 64 | {this.props.children} 65 | 66 | ); 67 | } 68 | componentWillUnmount() { 69 | const result = removeSKNode(this.state.identifier); 70 | } 71 | static getDerivedStateFromProps(nextProps, prevState) { 72 | var ret = prevState; 73 | if (propDiff(nextProps, prevState.SKProps)) { 74 | ret.SKProps = propFilter(nextProps); 75 | if (["doMount", "Mounting"].indexOf(prevState.updateState) == -1) { 76 | ret.updateState = prevState.updateState == "doing" ? "donext" : "do"; 77 | } 78 | } 79 | return ret; 80 | } 81 | } 82 | ARBaseSKLabel.propTypes = { 83 | position: PropTypes.shape({ 84 | x: PropTypes.number, 85 | y: PropTypes.number 86 | }), 87 | parentSKNode: PropTypes.string, 88 | text: PropTypes.string, 89 | id: PropTypes.string, 90 | fontName: PropTypes.string, 91 | fontSize: PropTypes.number, 92 | fontColor: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), // Note this requires a preprocessed color 93 | width: PropTypes.number, 94 | horizontalAlignment: PropTypes.string, 95 | verticalAlignment: PropTypes.string, 96 | allowScaling: PropTypes.bool, 97 | lineBreak: PropTypes.string, 98 | lines: PropTypes.number 99 | }; 100 | 101 | const SKLabelKeys = Object.keys(ARBaseSKLabel.propTypes); 102 | const ARSKLabel = props => { 103 | return ( 104 | 105 | {({ SKNodeID, height, width }) => { 106 | return ( 107 | 113 | ); 114 | }} 115 | 116 | ); 117 | }; 118 | ARSKLabel.defaultProps = { 119 | allowScaling: true 120 | }; 121 | 122 | const propFilter = props => { 123 | const temp = { 124 | ...pickBy(props, (v, k) => SKLabelKeys.indexOf(k) > -1) 125 | }; 126 | if (typeof temp.fontColor == "string") 127 | temp.fontColor = processColor(temp.fontColor); 128 | return temp; 129 | }; 130 | 131 | const propDiff = (a, b) => { 132 | if (a === b) return false; 133 | if (a & !b || !a & b) { 134 | return true; 135 | } 136 | const af = propFilter(a); 137 | const bf = propFilter(b); 138 | 139 | const afk = Object.keys(af); 140 | const bfk = Object.keys(bf); 141 | if (afk.length != bfk.length) { 142 | return true; 143 | } 144 | if ( 145 | afk.filter(k => { 146 | return bfk.indexOf(k) === -1; 147 | }).length 148 | ) { 149 | return true; 150 | } 151 | if ( 152 | afk.filter(k => { 153 | const t1 = bf[k] == af[k]; 154 | if (t1) return false; 155 | if (typeof bf[k] === "object") { 156 | return JSON.stringify(bf[k]) != JSON.stringify(af[k]); 157 | } else { 158 | return true; 159 | } 160 | }).length 161 | ) { 162 | return true; 163 | } 164 | }; 165 | 166 | ARSKLabel.propTypes = { ...ARBaseSKLabel.propTypes }; 167 | export { ARSKLabel, ARSKNodeConsumer }; 168 | export default ARSKLabel; 169 | -------------------------------------------------------------------------------- /components/ARSKScene.js: -------------------------------------------------------------------------------- 1 | import React, { Component, createContext } from "react"; 2 | import { addSKScene, removeSKScene, updateSKScene } from "../RNSwiftBridge"; 3 | import { processColor } from "react-native"; 4 | import PropTypes from "prop-types"; 5 | import pickBy from "lodash/pickBy"; 6 | import UUID from "uuid/v4"; 7 | import { ARMaterialPropertyConsumer } from "./ARMaterialProperty"; 8 | const { 9 | Provider: ARSKNodeProvider, 10 | Consumer: ARSKNodeConsumer 11 | } = createContext({}); 12 | class ARBaseSKScene extends Component { 13 | state = { 14 | identifier: UUID(), 15 | updateState: "doMount" // "doMount", "Mounting", "donext", "do", "doing", "done" 16 | }; 17 | updateProviderValue() { 18 | this.setState({ 19 | providerValue: { 20 | SKNodeID: this.state.identifier, 21 | height: this.props.height, 22 | width: this.props.width 23 | }, 24 | todos: {} 25 | }); 26 | } 27 | constructor(props) { 28 | super(props); 29 | this.state.providerValue = { 30 | SKNodeID: this.state.identifier, 31 | height: this.props.height, 32 | width: this.props.width 33 | }; 34 | } 35 | async nativeUpdate() { 36 | if (this.state.updateState == "doMount") { 37 | this.setState({ updateState: "Mounting" }); 38 | try { 39 | const filteredProps = propFilter(this.props); 40 | const scene = { 41 | ...propFilter(this.props), 42 | name: this.state.identifier 43 | }; 44 | const result = await addSKScene( 45 | scene, 46 | this.props.parentNode, 47 | this.props.index, 48 | this.props.materialProperty 49 | ); 50 | this.setState(({ updateState }) => { 51 | return { updateState: updateState == "donext" ? "do" : "done" }; 52 | }); 53 | } catch (e) { 54 | this.setState({ updateState: "doMount" }); 55 | } 56 | } else if (this.state.updateState == "do") { 57 | this.setState({ updateState: "doing" }); 58 | try { 59 | const scene = { 60 | ...propFilter(this.props), 61 | name: this.state.identifier 62 | }; 63 | await updateSKScene( 64 | scene, 65 | this.props.parentNode, 66 | this.props.index, 67 | this.props.materialProperty 68 | ); 69 | this.setState(({ updateState }) => { 70 | return { updateState: updateState == "donext" ? "do" : "done" }; 71 | }); 72 | } catch (e) { 73 | this.setState({ updateState: "do" }); 74 | } 75 | const scene = {}; 76 | } 77 | } 78 | static getDerivedStateFromProps(nextProps, prevState) { 79 | var ret = prevState; 80 | ret.todos = {}; 81 | if (nextProps.id && prevState.identifier != nextProps.id) { 82 | ret.identifier = nextProps.id; 83 | if (["doMount", "Mounting"].indexOf(ret.updateState) == -1) 84 | ret.updateState = 85 | ["doing", "Mounting"].indexOf(ret.updateState) == -1 86 | ? "do" 87 | : "donext"; 88 | } 89 | if (propDiff(prevState.sceneProps, nextProps, propFilter)) { 90 | ret.sceneProps = propFilter(nextProps); 91 | if (["doMount", "Mounting"].indexOf(ret.updateState) == -1) 92 | ret.updateState = 93 | ["doing", "Mounting"].indexOf(ret.updateState) == -1 94 | ? "do" 95 | : "donext"; 96 | } 97 | if ( 98 | nextProps.height != prevState.providerValue.height || 99 | nextProps.width != prevState.providerValue.width 100 | ) { 101 | ret.todos["updateProviderValue"] = true; 102 | } 103 | return ret; 104 | } 105 | componentDidMount() { 106 | this.manageTodos(); 107 | this.nativeUpdate(); 108 | } 109 | componentDidUpdate() { 110 | this.manageTodos(); 111 | this.nativeUpdate(); 112 | } 113 | manageTodos() { 114 | if (this.state.todos && Object.keys(this.state.todos).length) { 115 | Object.keys(this.state.todos).forEach(k => { 116 | if (typeof this[k] == "function") this[k](this.state.todos[k]); 117 | }); 118 | this.setState({ todos: {} }); 119 | } 120 | } 121 | render() { 122 | if (!this.props.children) return null; 123 | if (["doMount", "Mounting"].indexOf(this.state.updateState) > -1) 124 | return null; 125 | return ( 126 | 127 | {typeof this.props.children == "function" ? ( 128 | 129 | {value => { 130 | return this.props.children(value); 131 | }} 132 | 133 | ) : ( 134 | this.props.children 135 | )} 136 | 137 | ); 138 | } 139 | componentWillUnmount() { 140 | removeSKScene( 141 | this.props.parentNode, 142 | this.props.index, 143 | this.props.materialProperty 144 | ); 145 | } 146 | } 147 | 148 | ARBaseSKScene.propTypes = { 149 | height: PropTypes.number, 150 | width: PropTypes.number, 151 | id: PropTypes.string, 152 | color: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), 153 | parentNode: PropTypes.string, 154 | index: PropTypes.number, 155 | materialProperty: PropTypes.string 156 | }; 157 | 158 | ARBaseSKScene.defaultProps = { 159 | height: 100, 160 | width: 100 161 | }; 162 | const sceneKeys = Object.keys(ARBaseSKScene.propTypes); 163 | 164 | const ARSKScene = props => { 165 | return ( 166 | 167 | {({ parentNode, materialProperty, index }) => { 168 | return ( 169 | 172 | ); 173 | }} 174 | 175 | ); 176 | }; 177 | export { ARSKScene, ARSKNodeConsumer, ARSKNodeProvider }; 178 | export default ARSKScene; 179 | 180 | const propFilter = props => { 181 | const temp = { 182 | ...pickBy(props, (v, k) => sceneKeys.indexOf(k) > -1) 183 | }; 184 | if (typeof temp.color == "string") temp.color = processColor(temp.color); 185 | return temp; 186 | }; 187 | 188 | const propDiff = (a, b) => { 189 | if (a === b) return false; 190 | if (a & !b || !a & b) return true; 191 | const af = propFilter(a); 192 | const bf = propFilter(b); 193 | 194 | const afk = Object.keys(af); 195 | const bfk = Object.keys(bf); 196 | if (afk.length != bfk.length) return true; 197 | if ( 198 | afk.filter(k => { 199 | return bfk.indexOf(k) === -1; 200 | }).length 201 | ) 202 | return true; 203 | if ( 204 | afk.filter(k => { 205 | return bf[k] != af[k]; 206 | }).length 207 | ) 208 | return true; 209 | }; 210 | -------------------------------------------------------------------------------- /components/ARSKVideo.js: -------------------------------------------------------------------------------- 1 | import React, { Component, Children } from "react"; 2 | import { processColor } from "react-native"; 3 | import { 4 | removeSKNode, 5 | setSKVideoNode, 6 | updateSKVideoNode 7 | } from "../RNSwiftBridge"; 8 | import PropTypes from "prop-types"; 9 | import pickBy from "lodash/pickBy"; 10 | import UUID from "uuid/v4"; 11 | import { ARSKNodeProvider, ARSKNodeConsumer } from "./ARSKScene"; 12 | class ARBaseSKVideo extends Component { 13 | state = { 14 | identifier: UUID(), 15 | updateState: "doMount" 16 | }; 17 | constructor(props) { 18 | super(props); 19 | this.state.providerValue = { SKNodeID: this.state.identifier }; 20 | } 21 | async nativeUpdate() { 22 | if (this.state.updateState == "doMount") { 23 | this.setState({ updateState: "Mounting" }); 24 | try { 25 | const label = { 26 | ...propFilter(this.props), 27 | name: this.state.identifier 28 | }; 29 | const result = await setSKVideoNode(label, this.props.parentSKNode); 30 | this.setState(({ updateState }) => { 31 | return { updateState: updateState == "donext" ? "do" : "done" }; 32 | }); 33 | } catch (e) { 34 | this.setState({ updateState: "doMount" }); 35 | } 36 | } else if (this.state.updateState == "do") { 37 | this.setState({ updateState: "doing" }); 38 | try { 39 | const label = { 40 | ...propFilter(this.props), 41 | name: this.state.identifier 42 | }; 43 | const result = await updateSKVideoNode(label); 44 | this.setState(({ updateState }) => { 45 | return { updateState: updateState == "donext" ? "do" : "done" }; 46 | }); 47 | } catch (e) { 48 | this.setState({ updateState: "do" }); 49 | } 50 | } 51 | } 52 | componentDidMount() { 53 | this.nativeUpdate(); 54 | } 55 | componentDidUpdate() { 56 | this.nativeUpdate(); 57 | } 58 | render() { 59 | if (["doMount", "Mounting"].indexOf(this.state.updateState) > -1) 60 | return null; 61 | if (!this.props.children) return null; 62 | return ( 63 | 64 | {this.props.children} 65 | 66 | ); 67 | } 68 | componentWillUnmount() { 69 | const result = removeSKNode(this.state.identifier); 70 | } 71 | static getDerivedStateFromProps(nextProps, prevState) { 72 | var ret = prevState; 73 | if (propDiff(nextProps, prevState.SKProps)) { 74 | ret.SKProps = propFilter(nextProps); 75 | if (["doMount", "Mounting"].indexOf(prevState.updateState) == -1) { 76 | ret.updateState = prevState.updateState == "doing" ? "donext" : "do"; 77 | } 78 | } 79 | return ret; 80 | } 81 | } 82 | ARBaseSKVideo.propTypes = { 83 | //General to Nodes 84 | position: PropTypes.shape({ 85 | x: PropTypes.number, 86 | y: PropTypes.number 87 | }), 88 | parentSKNode: PropTypes.string, 89 | text: PropTypes.string, 90 | id: PropTypes.string, 91 | //Specific to video node 92 | width: PropTypes.number, 93 | height: PropTypes.number, 94 | url: PropTypes.string, 95 | path: PropTypes.string, 96 | isPlaying: PropTypes.bool 97 | }; 98 | 99 | const SKVideoKeys = Object.keys(ARBaseSKVideo.propTypes); 100 | const ARSKVideo = props => { 101 | return ( 102 | 103 | {({ SKNodeID, height, width }) => { 104 | return ( 105 | 111 | ); 112 | }} 113 | 114 | ); 115 | }; 116 | ARSKVideo.defaultProps = { 117 | isPlaying: true 118 | }; 119 | 120 | const propFilter = props => { 121 | const temp = { 122 | ...pickBy(props, (v, k) => SKVideoKeys.indexOf(k) > -1) 123 | }; 124 | return temp; 125 | }; 126 | 127 | const propDiff = (a, b) => { 128 | if (a === b) return false; 129 | if (a & !b || !a & b) { 130 | return true; 131 | } 132 | const af = propFilter(a); 133 | const bf = propFilter(b); 134 | 135 | const afk = Object.keys(af); 136 | const bfk = Object.keys(bf); 137 | if (afk.length != bfk.length) { 138 | return true; 139 | } 140 | if ( 141 | afk.filter(k => { 142 | return bfk.indexOf(k) === -1; 143 | }).length 144 | ) { 145 | return true; 146 | } 147 | if ( 148 | afk.filter(k => { 149 | const t1 = bf[k] == af[k]; 150 | if (t1) return false; 151 | if (typeof bf[k] === "object") { 152 | return JSON.stringify(bf[k]) != JSON.stringify(af[k]); 153 | } else { 154 | return true; 155 | } 156 | }).length 157 | ) { 158 | return true; 159 | } 160 | }; 161 | 162 | ARSKVideo.propTypes = { ...ARBaseSKVideo.propTypes }; 163 | export { ARSKVideo, ARSKNodeConsumer }; 164 | export default ARSKVideo; 165 | -------------------------------------------------------------------------------- /components/ARScene.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | import { setScene } from "../RNSwiftBridge"; 4 | export default ARGeometry( 5 | async ({ path }, nodeID) => { 6 | return await setScene(nodeID, path); 7 | }, 8 | { 9 | path: PropTypes.string 10 | }, 11 | 0 12 | ); 13 | -------------------------------------------------------------------------------- /components/ARShape.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | 4 | import { setShape } from "../RNSwiftBridge"; 5 | export default ARGeometry( 6 | setShape, 7 | { 8 | extrusion: PropTypes.number, 9 | pathSvg: PropTypes.string.isRequired, 10 | pathFlatness: PropTypes.number, 11 | chamferMode: PropTypes.number, 12 | chamferRadius: PropTypes.number, 13 | chamferProfilePathSvg: PropTypes.string, 14 | chamferProfilePathFlatness: PropTypes.number 15 | }, 16 | props => { 17 | var temp = 4; // Default where there is extrusion and chamfer but only one side - bezeled extruded disc 18 | if (!props.extrusion) { 19 | temp = 1; // Basically a plane 20 | } else if (!props.chamferRadius) { 21 | temp = 3; // There is extrusion but no chamfer - like an extruded disc 22 | } else if (props.chamferMode == 0) { 23 | temp = 5; // THere is extrusion and double-chamfer - extruded disc with bezeling front and back 24 | } 25 | return temp; 26 | }, 27 | { 28 | extrusion: 1.0, 29 | chamferMode: 0 30 | } 31 | ); 32 | -------------------------------------------------------------------------------- /components/ARSphere.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | 4 | import { setSphere } from "../RNSwiftBridge"; 5 | export default ARGeometry( 6 | setSphere, 7 | { 8 | radius: PropTypes.number 9 | }, 10 | 1, 11 | { 12 | radius: 0.5 13 | } 14 | ); 15 | -------------------------------------------------------------------------------- /components/ARText.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | 4 | import { setText } from "../RNSwiftBridge"; 5 | export default ARGeometry( 6 | setText, 7 | { 8 | text: PropTypes.string, 9 | fontName: PropTypes.string, 10 | // weight: PropTypes.string, 11 | size: PropTypes.number, 12 | depth: PropTypes.number, 13 | chamfer: PropTypes.number 14 | }, 15 | ({ chamfer }) => { 16 | if (chamfer) return 4; 17 | return 3; 18 | }, 19 | { 20 | size: 12, 21 | depth: 0.1, 22 | chamfer: 0 23 | } 24 | ); 25 | -------------------------------------------------------------------------------- /components/ARTorus.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | 4 | import { setTorus } from "../RNSwiftBridge"; 5 | export default ARGeometry( 6 | setTorus, 7 | { 8 | ringR: PropTypes.number, 9 | pipeR: PropTypes.number 10 | }, 11 | 1, 12 | { 13 | ringR: 0.5, 14 | pipeR: 0.25 15 | } 16 | ); 17 | -------------------------------------------------------------------------------- /components/ARTube.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import ARGeometry from "./ARGeometry"; 3 | 4 | import { setTube } from "../RNSwiftBridge"; 5 | export default ARGeometry( 6 | setTube, 7 | { 8 | innerR: PropTypes.number, 9 | outerR: PropTypes.number, 10 | height: PropTypes.number 11 | }, 12 | ({ innerR, outerR }) => { 13 | if (innerR == outerR) return 2; 14 | return 4; 15 | }, 16 | { 17 | innerR: 0.25, 18 | outerR: 0.5, 19 | height: 1 20 | } 21 | ); 22 | -------------------------------------------------------------------------------- /components/ARZoomResponder.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from "react"; 2 | import { Text, View, PanResponder, Image } from "react-native"; 3 | 4 | function calcDistance(x1, y1, x2, y2) { 5 | let dx = Math.abs(x1 - x2); 6 | let dy = Math.abs(y1 - y2); 7 | return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); 8 | } 9 | 10 | function calcCenter(x1, y1, x2, y2) { 11 | function middle(p1, p2) { 12 | return p1 > p2 ? p1 - (p1 - p2) / 2 : p2 - (p2 - p1) / 2; 13 | } 14 | 15 | return { 16 | x: middle(x1, x2), 17 | y: middle(y1, y2) 18 | }; 19 | } 20 | 21 | function maxOffset(offset, windowDimension, imageDimension) { 22 | let max = windowDimension - imageDimension; 23 | if (max >= 0) { 24 | return 0; 25 | } 26 | return offset < max ? max : offset; 27 | } 28 | 29 | function calcOffsetByZoom(width, height, imageWidth, imageHeight, zoom) { 30 | let xDiff = imageWidth * zoom - width; 31 | let yDiff = imageHeight * zoom - height; 32 | return { 33 | left: -xDiff / 2, 34 | top: -yDiff / 2 35 | }; 36 | } 37 | 38 | class ARZoomResponder extends Component { 39 | constructor(props) { 40 | super(props); 41 | 42 | this._onLayout = this._onLayout.bind(this); 43 | 44 | this.state = { 45 | zoom: null, 46 | minZoom: null, 47 | layoutKnown: false, 48 | isZooming: false, 49 | isMoving: false, 50 | initialDistance: null, 51 | initialX: null, 52 | initalY: null, 53 | offsetTop: 0, 54 | offsetLeft: 0, 55 | initialTop: 0, 56 | initialLeft: 0, 57 | initialTopWithoutZoom: 0, 58 | initialLeftWithoutZoom: 0, 59 | initialZoom: 1, 60 | top: 0, 61 | left: 0 62 | }; 63 | } 64 | 65 | processPinch(x1, y1, x2, y2) { 66 | let distance = calcDistance(x1, y1, x2, y2); 67 | let center = calcCenter(x1, y1, x2, y2); 68 | 69 | if (!this.state.isZooming) { 70 | let offsetByZoom = calcOffsetByZoom( 71 | this.state.width, 72 | this.state.height, 73 | this.props.imageWidth, 74 | this.props.imageHeight, 75 | this.state.zoom 76 | ); 77 | this.setState({ 78 | isZooming: true, 79 | initialDistance: distance, 80 | initialX: center.x, 81 | initialY: center.y, 82 | initialTop: this.state.top, 83 | initialLeft: this.state.left, 84 | initialZoom: this.state.zoom, 85 | initialTopWithoutZoom: this.state.top - offsetByZoom.top, 86 | initialLeftWithoutZoom: this.state.left - offsetByZoom.left 87 | }); 88 | } else { 89 | let touchZoom = distance / this.state.initialDistance; 90 | let zoom = 91 | touchZoom * this.state.initialZoom > this.state.minZoom 92 | ? touchZoom * this.state.initialZoom 93 | : this.state.minZoom; 94 | 95 | let offsetByZoom = calcOffsetByZoom( 96 | this.state.width, 97 | this.state.height, 98 | this.props.imageWidth, 99 | this.props.imageHeight, 100 | zoom 101 | ); 102 | let left = 103 | this.state.initialLeftWithoutZoom * touchZoom + offsetByZoom.left; 104 | let top = this.state.initialTopWithoutZoom * touchZoom + offsetByZoom.top; 105 | 106 | this.setState({ 107 | zoom: zoom, 108 | left: 0, 109 | top: 0, 110 | left: 111 | left > 0 112 | ? 0 113 | : maxOffset(left, this.state.width, this.props.imageWidth * zoom), 114 | top: 115 | top > 0 116 | ? 0 117 | : maxOffset(top, this.state.height, this.props.imageHeight * zoom) 118 | }); 119 | } 120 | } 121 | 122 | processTouch(x, y) { 123 | if (!this.state.isMoving) { 124 | this.setState({ 125 | isMoving: true, 126 | initialX: x, 127 | initialY: y, 128 | initialTop: this.state.top, 129 | initialLeft: this.state.left 130 | }); 131 | } else { 132 | let left = this.state.initialLeft + x - this.state.initialX; 133 | let top = this.state.initialTop + y - this.state.initialY; 134 | 135 | this.setState({ 136 | left: 137 | left > 0 138 | ? 0 139 | : maxOffset( 140 | left, 141 | this.state.width, 142 | this.props.imageWidth * this.state.zoom 143 | ), 144 | top: 145 | top > 0 146 | ? 0 147 | : maxOffset( 148 | top, 149 | this.state.height, 150 | this.props.imageHeight * this.state.zoom 151 | ) 152 | }); 153 | } 154 | } 155 | 156 | _onLayout(event) { 157 | let layout = event.nativeEvent.layout; 158 | 159 | if ( 160 | layout.width === this.state.width && 161 | layout.height === this.state.height 162 | ) { 163 | return; 164 | } 165 | 166 | let zoom = layout.width / this.props.imageWidth; 167 | 168 | let offsetTop = 169 | layout.height > this.props.imageHeight * zoom 170 | ? (layout.height - this.props.imageHeight * zoom) / 2 171 | : 0; 172 | 173 | this.setState({ 174 | layoutKnown: true, 175 | width: layout.width, 176 | height: layout.height, 177 | zoom: zoom, 178 | offsetTop: offsetTop, 179 | minZoom: zoom 180 | }); 181 | } 182 | 183 | componentWillMount() { 184 | this._panResponder = PanResponder.create({ 185 | onStartShouldSetPanResponder: (evt, gestureState) => true, 186 | onStartShouldSetPanResponderCapture: (evt, gestureState) => true, 187 | onMoveShouldSetPanResponder: (evt, gestureState) => true, 188 | onMoveShouldSetPanResponderCapture: (evt, gestureState) => true, 189 | onPanResponderGrant: (evt, gestureState) => {}, 190 | onPanResponderMove: (evt, gestureState) => { 191 | let touches = evt.nativeEvent.touches; 192 | if (touches.length == 2) { 193 | let touch1 = touches[0]; 194 | let touch2 = touches[1]; 195 | 196 | this.processPinch( 197 | touches[0].pageX, 198 | touches[0].pageY, 199 | touches[1].pageX, 200 | touches[1].pageY 201 | ); 202 | } else if (touches.length == 1 && !this.state.isZooming) { 203 | this.processTouch(touches[0].pageX, touches[0].pageY); 204 | } 205 | }, 206 | 207 | onPanResponderTerminationRequest: (evt, gestureState) => true, 208 | onPanResponderRelease: (evt, gestureState) => { 209 | this.setState({ 210 | isZooming: false, 211 | isMoving: false 212 | }); 213 | }, 214 | onPanResponderTerminate: (evt, gestureState) => {}, 215 | onShouldBlockNativeResponder: (evt, gestureState) => true 216 | }); 217 | } 218 | 219 | render() { 220 | return ( 221 | 226 | 236 | 237 | ); 238 | } 239 | } 240 | 241 | ZoomableImage.propTypes = { 242 | imageWidth: PropTypes.number.isRequired, 243 | imageHeight: PropTypes.number.isRequired, 244 | source: PropTypes.object.isRequired 245 | }; 246 | export default ZoomableImage; 247 | -------------------------------------------------------------------------------- /components/old/ARSprite.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import withAnimationFrame from "@panter/react-animation-frame"; 3 | 4 | import { NativeModules, Animated } from "react-native"; 5 | 6 | import { position } from "./lib/propTypes"; 7 | 8 | const ARKitManager = NativeModules.ARARViewManager; 9 | 10 | const ARSprite = withAnimationFrame( 11 | class extends Component { 12 | constructor(props) { 13 | super(props); 14 | this.state = { 15 | zIndex: new Animated.Value(), 16 | pos2D: new Animated.ValueXY() // inits to zero 17 | }; 18 | } 19 | onAnimationFrame() { 20 | ARKitManager.projectPoint(this.props.position).then( 21 | Animated.event([ 22 | { 23 | x: this.state.pos2D.x, 24 | y: this.state.pos2D.y, 25 | z: this.state.zIndex 26 | } 27 | ]) 28 | ); 29 | } 30 | 31 | render() { 32 | return ( 33 | 40 | {this.props.children} 41 | 42 | ); 43 | } 44 | } 45 | ); 46 | 47 | ARSprite.propTypes = { 48 | position 49 | }; 50 | 51 | export default ARSprite; 52 | -------------------------------------------------------------------------------- /components/propTypes.js: -------------------------------------------------------------------------------- 1 | import { NativeModules } from "react-native"; 2 | import { values } from "lodash"; 3 | import PropTypes from "prop-types"; 4 | 5 | const { ARSceneManager } = NativeModules; 6 | 7 | export const position = PropTypes.shape({ 8 | x: PropTypes.number, 9 | y: PropTypes.number, 10 | z: PropTypes.number 11 | }); 12 | 13 | export const scale = PropTypes.number; 14 | export const categoryBitMask = PropTypes.number; 15 | export const transition = PropTypes.shape({ 16 | duration: PropTypes.number 17 | }); 18 | export const eulerAngles = PropTypes.shape({ 19 | x: PropTypes.number, 20 | y: PropTypes.number, 21 | z: PropTypes.number 22 | }); 23 | 24 | export const rotation = PropTypes.shape({ 25 | x: PropTypes.number, 26 | y: PropTypes.number, 27 | z: PropTypes.number, 28 | w: PropTypes.number 29 | }); 30 | 31 | export const orientation = PropTypes.shape({ 32 | x: PropTypes.number, 33 | y: PropTypes.number, 34 | z: PropTypes.number, 35 | w: PropTypes.number 36 | }); 37 | export const shaders = PropTypes.shape({ 38 | [ARSceneManager.ShaderModifierEntryPoint.Geometry]: PropTypes.string, 39 | [ARSceneManager.ShaderModifierEntryPoint.Surface]: PropTypes.string, 40 | [ARSceneManager.ShaderModifierEntryPoint.LightingModel]: PropTypes.string, 41 | [ARSceneManager.ShaderModifierEntryPoint.Fragment]: PropTypes.string 42 | }); 43 | 44 | export const lightingModel = PropTypes.oneOf( 45 | values(ARSceneManager.LightingModel) 46 | ); 47 | 48 | export const castsShadow = PropTypes.bool; 49 | export const renderingOrder = PropTypes.number; 50 | export const blendMode = PropTypes.oneOf(values(ARSceneManager.BlendMode)); 51 | export const chamferMode = PropTypes.oneOf(values(ARSceneManager.ChamferMode)); 52 | export const color = PropTypes.string; 53 | export const fillMode = PropTypes.oneOf(values(ARSceneManager.FillMode)); 54 | 55 | export const lightType = PropTypes.oneOf(values(ARSceneManager.LightType)); 56 | export const shadowMode = PropTypes.oneOf(values(ARSceneManager.ShadowMode)); 57 | export const colorBufferWriteMask = PropTypes.oneOf( 58 | values(ARSceneManager.ColorMask) 59 | ); 60 | 61 | export const opacity = PropTypes.number; 62 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import ARBox from "./components/ARBox"; 2 | import ARCapsule from "./components/ARCapsule"; 3 | import ARCone from "./components/ARCone"; 4 | import ARCylinder from "./components/ARCylinder"; 5 | import ARMonoView from "./ARMonoView"; 6 | import ARPlane from "./components/ARPlane"; 7 | import ARPyramid from "./components/ARPyramid"; 8 | import ARSphere from "./components/ARSphere"; 9 | import ARText from "./components/ARText"; 10 | import ARTorus from "./components/ARTorus"; 11 | import ARTube from "./components/ARTube"; 12 | import ARNode from "./components/ARNode"; 13 | import ARMaterial from "./components/ARMaterial"; 14 | import ARMaterialProperty from "./components/ARMaterialProperty"; 15 | import ARMaterials from "./components/ARMaterials"; 16 | import ARTouchableMonoView from "./ARTouchableMonoView"; 17 | import { ARSKScene, ARSKNodeConsumer } from "./components/ARSKScene"; 18 | import ARSKLabel from "./components/ARSKLabel"; 19 | import ARAnimatedProvider from "./ARAnimatedProvider"; 20 | import ARScene from "./components/ARScene"; 21 | import ARModel from "./components/ARModel"; 22 | import { ARSessionConsumer, ARSessionProvider } from "./ARSessionProvider"; 23 | import { ARPositionProvider, ARPositionConsumer } from "./ARPositionProvider"; 24 | import { ARTrackingConsumer, ARTrackingProvider } from "./ARTrackingProvider"; 25 | import ARShape from "./components/ARShape"; 26 | import ARLight from "./components/ARLight"; 27 | import ARSKVideo from "./components/ARSKVideo"; 28 | import { 29 | ARProjectedPointProvider, 30 | ARProjectedPointConsumer 31 | } from "./components/ARProjectedPointProvider"; 32 | import ARProjectedView from "./ARProjectedView"; 33 | export { 34 | ARMonoView, 35 | ARBox, 36 | ARSphere, 37 | ARCylinder, 38 | ARCone, 39 | ARPyramid, 40 | ARTube, 41 | ARTorus, 42 | ARCapsule, 43 | ARPlane, 44 | ARText, 45 | ARNode, 46 | ARMaterial, 47 | ARMaterialProperty, 48 | ARMaterials, 49 | ARTouchableMonoView, 50 | ARSKScene, 51 | ARSKLabel, 52 | ARSessionConsumer, 53 | ARSessionProvider, 54 | ARAnimatedProvider, 55 | ARPositionProvider, 56 | ARPositionConsumer, 57 | ARTrackingConsumer, 58 | ARTrackingProvider, 59 | ARScene, 60 | ARModel, 61 | ARShape, 62 | ARLight, 63 | ARSKVideo, 64 | ARSKNodeConsumer, 65 | ARProjectedPointConsumer, 66 | ARProjectedPointProvider, 67 | ARProjectedView 68 | }; 69 | import React, { Component } from "react"; 70 | import PropTypes from "prop-types"; 71 | //#region Materials 72 | export const ARColor = ({ color, index }) => { 73 | if (typeof index == "undefined") { 74 | return ( 75 | 76 | 77 | 78 | ); 79 | } else { 80 | return ( 81 | 82 | 83 | 84 | ); 85 | } 86 | }; 87 | export const ARTexture = ({ path, index }) => { 88 | if (typeof index == "undefined") { 89 | return ( 90 | 91 | 92 | 93 | ); 94 | } else { 95 | return ( 96 | 97 | 98 | 99 | ); 100 | } 101 | }; 102 | //#endregion 103 | const ARColoredGeometry = G => props => { 104 | return ( 105 | 106 | 107 | 108 | ); 109 | }; 110 | const ARTexturedGeometry = G => props => { 111 | return ( 112 | 113 | 114 | 115 | ); 116 | }; 117 | //#region Geometries 118 | export const ARColoredBox = ARColoredGeometry(ARBox); 119 | export const ARColoredCylinder = ARColoredGeometry(ARCylinder); 120 | export const ARColoredCone = ARColoredGeometry(ARCone); 121 | export const ARColoredCapsule = ARColoredGeometry(ARCapsule); 122 | export const ARColoredPlane = ARColoredGeometry(ARPlane); 123 | export const ARColoredPyramid = ARColoredGeometry(ARPyramid); 124 | export const ARColoredShape = ARColoredGeometry(ARShape); 125 | export const ARColoredSphere = ARColoredGeometry(ARSphere); 126 | export const ARColoredText = ARColoredGeometry(ARText); 127 | export const ARColoredTorus = ARColoredGeometry(ARTorus); 128 | export const ARColoredTube = ARColoredGeometry(ARTube); 129 | 130 | export const ARTexturedBox = ARTexturedGeometry(ARBox); 131 | export const ARTexturedCylinder = ARTexturedGeometry(ARCylinder); 132 | export const ARTexturedCone = ARTexturedGeometry(ARCone); 133 | export const ARTexturedCapsule = ARTexturedGeometry(ARCapsule); 134 | export const ARTexturedPlane = ARTexturedGeometry(ARTexturedPlane); 135 | export const ARTexturedPyramid = ARTexturedGeometry(ARTexturedPyramid); 136 | export const ARTexturedShape = ARTexturedGeometry(ARShape); 137 | export const ARTexturedSphere = ARTexturedGeometry(ARSphere); 138 | export const ARTexturedText = ARTexturedGeometry(ARText); 139 | export const ARTexturedTorus = ARTexturedGeometry(ARTorus); 140 | export const ARTexturedTube = ARTexturedGeometry(ARTube); 141 | //#endregion 142 | //#region adding geometries to nodes 143 | const GeoNode = G => props => { 144 | return ( 145 | 146 | 147 | 148 | ); 149 | }; 150 | 151 | export const ARBoxNode = GeoNode(ARBox); 152 | export const ARCapsuleNode = GeoNode(ARCapsule); 153 | export const ARConeNode = GeoNode(ARCone); 154 | export const ARCylinderNode = GeoNode(ARCylinder); 155 | export const ARPlaneNode = GeoNode(ARPlane); 156 | export const ARPyramidNode = GeoNode(ARPyramid); 157 | export const ARShapeNode = GeoNode(ARShape); 158 | export const ARSphereNode = GeoNode(ARSphere); 159 | export const ARTorusNode = GeoNode(ARTorus); 160 | export const ARTubeNode = GeoNode(ARTube); 161 | export const ARTextNode = GeoNode(ARText); 162 | export const ARColoredBoxNode = GeoNode(ARColoredBox); 163 | export const ARColoredCapsuleNode = GeoNode(ARColoredCapsule); 164 | export const ARColoredConeNode = GeoNode(ARColoredCone); 165 | export const ARColoredCylinderNode = GeoNode(ARColoredCylinder); 166 | export const ARColoredPlaneNode = GeoNode(ARColoredPlane); 167 | export const ARColoredPyramidNode = GeoNode(ARColoredPyramid); 168 | export const ARColoredShapeNode = GeoNode(ARColoredShape); 169 | export const ARColoredSphereNode = GeoNode(ARColoredSphere); 170 | export const ARColoredTorusNode = GeoNode(ARColoredTorus); 171 | export const ARColoredTubeNode = GeoNode(ARColoredTube); 172 | export const ARColoredTextNode = GeoNode(ARColoredText); 173 | export const ARTexturedBoxNode = GeoNode(ARTexturedBox); 174 | export const ARTexturedCapsuleNode = GeoNode(ARTexturedCapsule); 175 | export const ARTexturedConeNode = GeoNode(ARTexturedCone); 176 | export const ARTexturedCylinderNode = GeoNode(ARTexturedCylinder); 177 | export const ARTexturedPlaneNode = GeoNode(ARTexturedPlane); 178 | export const ARTexturedPyramidNode = GeoNode(ARTexturedPyramid); 179 | export const ARTexturedShapeNode = GeoNode(ARTexturedShape); 180 | export const ARTexturedSphereNode = GeoNode(ARTexturedSphere); 181 | export const ARTexturedTorusNode = GeoNode(ARTexturedTorus); 182 | export const ARTexturedTubeNode = GeoNode(ARTexturedTube); 183 | export const ARTexturedTextNode = GeoNode(ARTexturedText); 184 | //#endregion 185 | 186 | export const ARPlaneScene = props => { 187 | return ( 188 | 189 | 190 | 191 | 196 | 197 | 198 | 199 | ); 200 | }; 201 | //#sign 202 | 203 | export const ARCenteredSKLabel = props => { 204 | return ( 205 | 206 | {({ height, width }) => { 207 | return ( 208 | 216 | ); 217 | }} 218 | 219 | ); 220 | }; 221 | export const ARSign = props => { 222 | const { height, width, ...labelProps } = props; 223 | return ( 224 | 225 | 226 | 227 | ); 228 | }; 229 | ARPlaneScene.defaultProps = { 230 | ppm: 10 * 38, // 10 dpi, 231 | height: 1, 232 | width: 1 233 | }; 234 | ARPlaneScene.propTypes = { 235 | ...ARPlane.propTypes, 236 | ...ARSKScene.propTypes, 237 | ppm: PropTypes.number 238 | }; 239 | ARSign.propTypes = { 240 | ...ARPlaneScene.propTypes, 241 | text: PropTypes.string.isRequired 242 | }; 243 | ARSign.defaultProps = { 244 | ...ARPlaneScene.defaultProps 245 | }; 246 | export const ARSignNode = GeoNode(ARSign); 247 | export const ARPlaneSceneNode = GeoNode(ARPlaneSceneNode); 248 | 249 | export const ARNoSession = props => { 250 | return ( 251 | 252 | {({ isStarted }) => { 253 | if (typeof isStarted == undefined) 254 | throw new Error( 255 | "ARNoSession must be a descendent of ARSessionProvider" 256 | ); 257 | if (!isStarted) { 258 | return props.children; 259 | } 260 | return null; 261 | }} 262 | 263 | ); 264 | }; 265 | export const ARIsSession = props => { 266 | return ( 267 | 268 | {({ isStarted }) => { 269 | if (typeof isStarted == undefined) 270 | throw new Error( 271 | "ARNoSession must be a descendent of ARSessionProvider" 272 | ); 273 | if (isStarted) { 274 | return props.children; 275 | } 276 | return null; 277 | }} 278 | 279 | ); 280 | }; 281 | export const ARNoTracking = props => { 282 | return ( 283 | 284 | {({ anchors }) => { 285 | if (!anchors || !Object.keys(anchors).length) { 286 | return props.children; 287 | } 288 | }} 289 | 290 | ); 291 | }; 292 | export const ARIsTracking = props => { 293 | return ( 294 | 295 | {({ anchors }) => { 296 | if (anchors && Object.keys(anchors).length) { 297 | return props.children; 298 | } 299 | }} 300 | 301 | ); 302 | }; 303 | 304 | export const ARMeNode = props => { 305 | return ( 306 | 307 | {({ position, orientation }) => { 308 | if (typeof orientation.x === "undefined") { 309 | return ( 310 | 311 | 312 | 313 | ); 314 | } 315 | return ; 316 | }} 317 | 318 | ); 319 | }; 320 | 321 | export class ARButton extends Component { 322 | state = { 323 | zPos: 0, 324 | color: "red" 325 | }; 326 | componentWillMount() { 327 | this.setState({ color: this.props.color && "blue" }); 328 | } 329 | render() { 330 | return ( 331 | 332 | { 335 | this.setState({ 336 | zPos: this.props.pressDepth, 337 | color: this.props.highlightColor 338 | }); 339 | this.props.onPressIn && this.props.onPressIn(); 340 | }} 341 | onPressOut={() => { 342 | this.setState({ zPos: 0, color: this.props.color }); 343 | this.props.onPressOut && this.props.onPressOut(); 344 | }} 345 | onPress={this.props.onPress} 346 | > 347 | 356 | 357 | 358 | ); 359 | } 360 | } 361 | ARButton.defaultProps = { 362 | width: 1, 363 | height: 0.5, 364 | color: "blue", 365 | highlightColor: "purple", 366 | fontColor: "white", 367 | onPress: () => {}, 368 | pressDepth: -0.2 369 | }; 370 | -------------------------------------------------------------------------------- /ios/react_native-arkit-swift-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import "SVGBezierPath.h" 7 | -------------------------------------------------------------------------------- /ios/react_native-arkit-swift.xcodeproj/bob: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhdeck/react-reality/0bb17e4fac6b2b521a7e2557004124d2d10f493f/ios/react_native-arkit-swift.xcodeproj/bob -------------------------------------------------------------------------------- /ios/react_native-arkit-swift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | /* Begin PBXBuildFile section */ 9 | 712815C32026480B00C460CB /* ARExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 712815C22026480B00C460CB /* ARExtension.swift */; }; 10 | 714545D92034E50D00E44E8D /* ARSceneManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 714545D82034E50D00E44E8D /* ARSceneManager.swift */; }; 11 | 714545DB2034EA9000E44E8D /* ARMonoview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 714545DA2034EA9000E44E8D /* ARMonoview.swift */; }; 12 | 714545DD2034EC9600E44E8D /* ARMonoviewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 714545DC2034EC9600E44E8D /* ARMonoviewManager.swift */; }; 13 | 714DC6E12050C55100BACAE8 /* ARPrimaryViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 714DC6E02050C55100BACAE8 /* ARPrimaryViewManager.swift */; }; 14 | 714DC6E32050C56500BACAE8 /* ARSecondaryViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 714DC6E22050C56400BACAE8 /* ARSecondaryViewManager.swift */; }; 15 | 719D02A3204DCC020096F3C1 /* ARSecondaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 719D02A2204DCC020096F3C1 /* ARSecondaryView.swift */; }; 16 | 719D02A5204DD2E90096F3C1 /* ARPrimaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 719D02A4204DD2E90096F3C1 /* ARPrimaryView.swift */; }; 17 | 71A4399620E654B50071F29C /* ARProjectedViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71A4399520E654B50071F29C /* ARProjectedViewManager.swift */; }; 18 | 71A4399820E654C80071F29C /* ARProjectedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71A4399720E654C80071F29C /* ARProjectedView.swift */; }; 19 | AAD78BA0AC6447529D3057BE /* rn-swift-bridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E00DCA45E7447438EF2917A /* rn-swift-bridge.m */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXCopyFilesBuildPhase section */ 23 | 71D8F37A1FB7A97B0000973C /* CopyFiles */ = { 24 | isa = PBXCopyFilesBuildPhase; 25 | buildActionMask = 2147483647; 26 | dstPath = "include/$(PRODUCT_NAME)"; 27 | dstSubfolderSpec = 16; 28 | files = ( 29 | ); 30 | runOnlyForDeploymentPostprocessing = 0; 31 | }; 32 | /* End PBXCopyFilesBuildPhase section */ 33 | 34 | /* Begin PBXFileReference section */ 35 | 712815C22026480B00C460CB /* ARExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARExtension.swift; sourceTree = ""; }; 36 | 714545D82034E50D00E44E8D /* ARSceneManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARSceneManager.swift; sourceTree = ""; }; 37 | 714545DA2034EA9000E44E8D /* ARMonoview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARMonoview.swift; sourceTree = ""; }; 38 | 714545DC2034EC9600E44E8D /* ARMonoviewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARMonoviewManager.swift; sourceTree = ""; }; 39 | 714DC6E02050C55100BACAE8 /* ARPrimaryViewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARPrimaryViewManager.swift; sourceTree = ""; }; 40 | 714DC6E22050C56400BACAE8 /* ARSecondaryViewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARSecondaryViewManager.swift; sourceTree = ""; }; 41 | 719D02A2204DCC020096F3C1 /* ARSecondaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARSecondaryView.swift; sourceTree = ""; }; 42 | 719D02A4204DD2E90096F3C1 /* ARPrimaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARPrimaryView.swift; sourceTree = ""; }; 43 | 71A4399520E654B50071F29C /* ARProjectedViewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARProjectedViewManager.swift; sourceTree = ""; }; 44 | 71A4399720E654C80071F29C /* ARProjectedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARProjectedView.swift; sourceTree = ""; }; 45 | 71D8F37C1FB7A97B0000973C /* libreact_native-arkit-swift.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libreact_native-arkit-swift.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 71D8F3881FB7AA9D0000973C /* react_native-arkit-swift-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "react_native-arkit-swift-Bridging-Header.h"; sourceTree = ""; }; 47 | 8E00DCA45E7447438EF2917A /* rn-swift-bridge.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; path = "rn-swift-bridge.m"; sourceTree = ""; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | 71D8F3791FB7A97B0000973C /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXFrameworksBuildPhase section */ 59 | 60 | /* Begin PBXGroup section */ 61 | 712815D92029E82300C460CB /* Recovered References */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | ); 65 | name = "Recovered References"; 66 | sourceTree = ""; 67 | }; 68 | 71D8F3731FB7A97B0000973C = { 69 | isa = PBXGroup; 70 | children = ( 71 | 71D8F37E1FB7A97B0000973C /* react_native-arkit-swift */, 72 | 71D8F37D1FB7A97B0000973C /* Products */, 73 | 8E00DCA45E7447438EF2917A /* rn-swift-bridge.m */, 74 | 71D8F3881FB7AA9D0000973C /* react_native-arkit-swift-Bridging-Header.h */, 75 | 712815D92029E82300C460CB /* Recovered References */, 76 | ); 77 | sourceTree = ""; 78 | }; 79 | 71D8F37D1FB7A97B0000973C /* Products */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 71D8F37C1FB7A97B0000973C /* libreact_native-arkit-swift.a */, 83 | ); 84 | name = Products; 85 | sourceTree = ""; 86 | }; 87 | 71D8F37E1FB7A97B0000973C /* react_native-arkit-swift */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 712815C22026480B00C460CB /* ARExtension.swift */, 91 | 714545DA2034EA9000E44E8D /* ARMonoview.swift */, 92 | 714545DC2034EC9600E44E8D /* ARMonoviewManager.swift */, 93 | 719D02A4204DD2E90096F3C1 /* ARPrimaryView.swift */, 94 | 714DC6E02050C55100BACAE8 /* ARPrimaryViewManager.swift */, 95 | 714545D82034E50D00E44E8D /* ARSceneManager.swift */, 96 | 719D02A2204DCC020096F3C1 /* ARSecondaryView.swift */, 97 | 714DC6E22050C56400BACAE8 /* ARSecondaryViewManager.swift */, 98 | 71A4399520E654B50071F29C /* ARProjectedViewManager.swift */, 99 | 71A4399720E654C80071F29C /* ARProjectedView.swift */, 100 | ); 101 | path = "react_native-arkit-swift"; 102 | sourceTree = ""; 103 | }; 104 | /* End PBXGroup section */ 105 | 106 | /* Begin PBXNativeTarget section */ 107 | 71D8F37B1FB7A97B0000973C /* react_native-arkit-swift */ = { 108 | isa = PBXNativeTarget; 109 | buildConfigurationList = 71D8F3851FB7A97B0000973C /* Build configuration list for PBXNativeTarget "react_native-arkit-swift" */; 110 | buildPhases = ( 111 | 71D8F3781FB7A97B0000973C /* Sources */, 112 | 71D8F3791FB7A97B0000973C /* Frameworks */, 113 | 71D8F37A1FB7A97B0000973C /* CopyFiles */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = "react_native-arkit-swift"; 120 | productName = "react_native-arkit-swift"; 121 | productReference = 71D8F37C1FB7A97B0000973C /* libreact_native-arkit-swift.a */; 122 | productType = "com.apple.product-type.library.static"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 71D8F3741FB7A97B0000973C /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 930; 131 | ORGANIZATIONNAME = "Ray Deck"; 132 | TargetAttributes = { 133 | 71D8F37B1FB7A97B0000973C = { 134 | CreatedOnToolsVersion = 9.2; 135 | LastSwiftMigration = 920; 136 | ProvisioningStyle = Automatic; 137 | }; 138 | }; 139 | }; 140 | buildConfigurationList = 71D8F3771FB7A97B0000973C /* Build configuration list for PBXProject "react_native-arkit-swift" */; 141 | compatibilityVersion = "Xcode 8.0"; 142 | developmentRegion = en; 143 | hasScannedForEncodings = 0; 144 | knownRegions = ( 145 | en, 146 | ); 147 | mainGroup = 71D8F3731FB7A97B0000973C; 148 | productRefGroup = 71D8F37D1FB7A97B0000973C /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 71D8F37B1FB7A97B0000973C /* react_native-arkit-swift */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXSourcesBuildPhase section */ 158 | 71D8F3781FB7A97B0000973C /* Sources */ = { 159 | isa = PBXSourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 71A4399620E654B50071F29C /* ARProjectedViewManager.swift in Sources */, 163 | 712815C32026480B00C460CB /* ARExtension.swift in Sources */, 164 | 714DC6E12050C55100BACAE8 /* ARPrimaryViewManager.swift in Sources */, 165 | 719D02A5204DD2E90096F3C1 /* ARPrimaryView.swift in Sources */, 166 | 719D02A3204DCC020096F3C1 /* ARSecondaryView.swift in Sources */, 167 | 714545DB2034EA9000E44E8D /* ARMonoview.swift in Sources */, 168 | 71A4399820E654C80071F29C /* ARProjectedView.swift in Sources */, 169 | 714545D92034E50D00E44E8D /* ARSceneManager.swift in Sources */, 170 | 714DC6E32050C56500BACAE8 /* ARSecondaryViewManager.swift in Sources */, 171 | AAD78BA0AC6447529D3057BE /* rn-swift-bridge.m in Sources */, 172 | 714545DD2034EC9600E44E8D /* ARMonoviewManager.swift in Sources */, 173 | ); 174 | runOnlyForDeploymentPostprocessing = 0; 175 | }; 176 | /* End PBXSourcesBuildPhase section */ 177 | 178 | /* Begin XCBuildConfiguration section */ 179 | 71D8F3831FB7A97B0000973C /* Debug */ = { 180 | isa = XCBuildConfiguration; 181 | buildSettings = { 182 | ALWAYS_SEARCH_USER_PATHS = NO; 183 | CLANG_ANALYZER_NONNULL = YES; 184 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 185 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 186 | CLANG_CXX_LIBRARY = "libc++"; 187 | CLANG_ENABLE_MODULES = YES; 188 | CLANG_ENABLE_OBJC_ARC = YES; 189 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 190 | CLANG_WARN_BOOL_CONVERSION = YES; 191 | CLANG_WARN_COMMA = YES; 192 | CLANG_WARN_CONSTANT_CONVERSION = YES; 193 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 194 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 195 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 196 | CLANG_WARN_EMPTY_BODY = YES; 197 | CLANG_WARN_ENUM_CONVERSION = YES; 198 | CLANG_WARN_INFINITE_RECURSION = YES; 199 | CLANG_WARN_INT_CONVERSION = YES; 200 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 201 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 202 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 203 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 204 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 205 | CLANG_WARN_STRICT_PROTOTYPES = YES; 206 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 207 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 208 | CLANG_WARN_UNREACHABLE_CODE = YES; 209 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 210 | CODE_SIGN_IDENTITY = "iPhone Developer"; 211 | COPY_PHASE_STRIP = NO; 212 | DEBUG_INFORMATION_FORMAT = dwarf; 213 | ENABLE_STRICT_OBJC_MSGSEND = YES; 214 | ENABLE_TESTABILITY = YES; 215 | GCC_C_LANGUAGE_STANDARD = gnu11; 216 | GCC_DYNAMIC_NO_PIC = NO; 217 | GCC_NO_COMMON_BLOCKS = YES; 218 | GCC_OPTIMIZATION_LEVEL = 0; 219 | GCC_PREPROCESSOR_DEFINITIONS = ( 220 | "DEBUG=1", 221 | "$(inherited)", 222 | ); 223 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 224 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 225 | GCC_WARN_UNDECLARED_SELECTOR = YES; 226 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 227 | GCC_WARN_UNUSED_FUNCTION = YES; 228 | GCC_WARN_UNUSED_VARIABLE = YES; 229 | HEADER_SEARCH_PATHS = ""; 230 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 231 | MTL_ENABLE_DEBUG_INFO = YES; 232 | ONLY_ACTIVE_ARCH = YES; 233 | SDKROOT = iphoneos; 234 | }; 235 | name = Debug; 236 | }; 237 | 71D8F3841FB7A97B0000973C /* Release */ = { 238 | isa = XCBuildConfiguration; 239 | buildSettings = { 240 | ALWAYS_SEARCH_USER_PATHS = NO; 241 | CLANG_ANALYZER_NONNULL = YES; 242 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 243 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 244 | CLANG_CXX_LIBRARY = "libc++"; 245 | CLANG_ENABLE_MODULES = YES; 246 | CLANG_ENABLE_OBJC_ARC = YES; 247 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 248 | CLANG_WARN_BOOL_CONVERSION = YES; 249 | CLANG_WARN_COMMA = YES; 250 | CLANG_WARN_CONSTANT_CONVERSION = YES; 251 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 252 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 253 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 254 | CLANG_WARN_EMPTY_BODY = YES; 255 | CLANG_WARN_ENUM_CONVERSION = YES; 256 | CLANG_WARN_INFINITE_RECURSION = YES; 257 | CLANG_WARN_INT_CONVERSION = YES; 258 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 259 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 260 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 261 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 262 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 263 | CLANG_WARN_STRICT_PROTOTYPES = YES; 264 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 265 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 266 | CLANG_WARN_UNREACHABLE_CODE = YES; 267 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 268 | CODE_SIGN_IDENTITY = "iPhone Developer"; 269 | COPY_PHASE_STRIP = NO; 270 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 271 | ENABLE_NS_ASSERTIONS = NO; 272 | ENABLE_STRICT_OBJC_MSGSEND = YES; 273 | GCC_C_LANGUAGE_STANDARD = gnu11; 274 | GCC_NO_COMMON_BLOCKS = YES; 275 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 276 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 277 | GCC_WARN_UNDECLARED_SELECTOR = YES; 278 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 279 | GCC_WARN_UNUSED_FUNCTION = YES; 280 | GCC_WARN_UNUSED_VARIABLE = YES; 281 | HEADER_SEARCH_PATHS = ""; 282 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 283 | MTL_ENABLE_DEBUG_INFO = NO; 284 | SDKROOT = iphoneos; 285 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 286 | VALIDATE_PRODUCT = YES; 287 | }; 288 | name = Release; 289 | }; 290 | 71D8F3861FB7A97B0000973C /* Debug */ = { 291 | isa = XCBuildConfiguration; 292 | buildSettings = { 293 | CLANG_ENABLE_MODULES = YES; 294 | CODE_SIGN_STYLE = Automatic; 295 | DEVELOPMENT_TEAM = 3UK2WGC8YX; 296 | FRAMEWORK_SEARCH_PATHS = ( 297 | "$(inherited)", 298 | "/Users/ray/Documents/artesta/ios/Pods/**", 299 | "/Users/ray/Documents/artestb/ios/Pods/**", 300 | ); 301 | HEADER_SEARCH_PATHS = ( 302 | "$(inherited)", 303 | "$(SRCROOT)/../../../ios/Pods/**", 304 | "/Users/ray/Documents/artesta/ios/Pods/**", 305 | "/Users/ray/Documents/artestb/ios/Pods/**", 306 | ); 307 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 308 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 309 | OTHER_LDFLAGS = "-ObjC"; 310 | PRODUCT_NAME = "$(TARGET_NAME)"; 311 | SKIP_INSTALL = YES; 312 | SWIFT_OBJC_BRIDGING_HEADER = "react_native-arkit-swift-Bridging-Header.h"; 313 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 314 | SWIFT_VERSION = 3.0; 315 | TARGETED_DEVICE_FAMILY = "1,2"; 316 | }; 317 | name = Debug; 318 | }; 319 | 71D8F3871FB7A97B0000973C /* Release */ = { 320 | isa = XCBuildConfiguration; 321 | buildSettings = { 322 | CLANG_ENABLE_MODULES = YES; 323 | CODE_SIGN_STYLE = Automatic; 324 | DEVELOPMENT_TEAM = 3UK2WGC8YX; 325 | FRAMEWORK_SEARCH_PATHS = ( 326 | "$(inherited)", 327 | "/Users/ray/Documents/artesta/ios/Pods/**", 328 | "/Users/ray/Documents/artestb/ios/Pods/**", 329 | ); 330 | HEADER_SEARCH_PATHS = ( 331 | "$(inherited)", 332 | "$(SRCROOT)/../../../ios/Pods/**", 333 | "/Users/ray/Documents/artesta/ios/Pods/**", 334 | "/Users/ray/Documents/artestb/ios/Pods/**", 335 | ); 336 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 337 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 338 | OTHER_LDFLAGS = "-ObjC"; 339 | PRODUCT_NAME = "$(TARGET_NAME)"; 340 | SKIP_INSTALL = YES; 341 | SWIFT_OBJC_BRIDGING_HEADER = "react_native-arkit-swift-Bridging-Header.h"; 342 | SWIFT_VERSION = 3.0; 343 | TARGETED_DEVICE_FAMILY = "1,2"; 344 | }; 345 | name = Release; 346 | }; 347 | /* End XCBuildConfiguration section */ 348 | 349 | /* Begin XCConfigurationList section */ 350 | 71D8F3771FB7A97B0000973C /* Build configuration list for PBXProject "react_native-arkit-swift" */ = { 351 | isa = XCConfigurationList; 352 | buildConfigurations = ( 353 | 71D8F3831FB7A97B0000973C /* Debug */, 354 | 71D8F3841FB7A97B0000973C /* Release */, 355 | ); 356 | defaultConfigurationIsVisible = 0; 357 | defaultConfigurationName = Release; 358 | }; 359 | 71D8F3851FB7A97B0000973C /* Build configuration list for PBXNativeTarget "react_native-arkit-swift" */ = { 360 | isa = XCConfigurationList; 361 | buildConfigurations = ( 362 | 71D8F3861FB7A97B0000973C /* Debug */, 363 | 71D8F3871FB7A97B0000973C /* Release */, 364 | ); 365 | defaultConfigurationIsVisible = 0; 366 | defaultConfigurationName = Release; 367 | }; 368 | /* End XCConfigurationList section */ 369 | }; 370 | rootObject = 71D8F3741FB7A97B0000973C /* Project object */; 371 | } 372 | -------------------------------------------------------------------------------- /ios/react_native-arkit-swift/ARExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SceneKit 3 | import SpriteKit 4 | typealias jsonType = [String:Any] 5 | @objc extension RCTConvert { 6 | @objc class func SCNMaterial(_ json:jsonType) -> SCNMaterial { 7 | let m:SCNMaterial = SceneKit.SCNMaterial() 8 | setMaterialProperties(m, properties: json) 9 | return m 10 | } 11 | @objc class func SCNVector3(_ json:jsonType) -> SCNVector3 { 12 | let x = json["x"] as? Double ?? 0 13 | let y = json["y"] as? Double ?? 0 14 | let z = json["z"] as? Double ?? 0 15 | return SceneKit.SCNVector3(x, y, z) 16 | } 17 | 18 | @objc class func SCNVector4(_ json: jsonType) -> SCNVector4 { 19 | let x = json["x"] as? Double ?? 0 20 | let y = json["y"] as? Double ?? 0 21 | let z = json["z"] as? Double ?? 0 22 | let w = json["w"] as? Double ?? 0 23 | return SceneKit.SCNVector4(x, y, z, w) 24 | } 25 | @objc class func SCNNode(_ json: jsonType) -> SCNNode { 26 | let n = SceneKit.SCNNode() 27 | if let name = json["id"] as? String { 28 | n.name = name 29 | } 30 | setNodeProperties(n, properties: json) 31 | return n 32 | } 33 | @objc class func SCNBox(_ json:jsonType)-> SCNBox { 34 | guard 35 | let w = json["width"] as? CGFloat, 36 | let h = json["height"] as? CGFloat, 37 | let l = json["length"] as? CGFloat 38 | else { return SceneKit.SCNBox() } 39 | let chamfer = json["chamfer"] as? CGFloat ?? 0 40 | let g = SceneKit.SCNBox(width: w, height: h, length: l, chamferRadius: chamfer) 41 | return g 42 | } 43 | @objc class func SCNCapsule(_ json: jsonType) -> SCNCapsule { 44 | guard 45 | let tr = json["capR"] as? CGFloat, 46 | let h = json["height"] as? CGFloat 47 | else { return SceneKit.SCNCapsule() } 48 | let g = SceneKit.SCNCapsule(capRadius: tr, height: h) 49 | return g 50 | } 51 | @objc class func SCNCone(_ json:jsonType)-> SCNCone { 52 | guard 53 | let tr = json["topR"] as? CGFloat, 54 | let br = json["bottomR"] as? CGFloat, 55 | let h = json["height"] as? CGFloat 56 | else { return SceneKit.SCNCone() } 57 | let g = SceneKit.SCNCone(topRadius: tr, bottomRadius: br, height: h) 58 | return g 59 | } 60 | @objc class func SCNCylinder(_ json:jsonType)-> SCNCylinder { 61 | guard 62 | let r = json["radius"] as? CGFloat, 63 | let h = json["height"] as? CGFloat 64 | else { return SceneKit.SCNCylinder() } 65 | let g = SceneKit.SCNCylinder(radius: r, height: h) 66 | return g 67 | } 68 | @objc class func SCNPlane(_ json: jsonType) -> SCNPlane { 69 | guard 70 | let w = json["width"] as? CGFloat, 71 | let h = json["height"] as? CGFloat 72 | else { return SceneKit.SCNPlane() } 73 | let g = SceneKit.SCNPlane(width: w, height: h) 74 | if let cr = json["cornerRadius"] as? CGFloat { g.cornerRadius = cr } 75 | if let i = json["cornerSegmentCount"] as? Int { g.cornerSegmentCount = i } 76 | if let i = json["widthSegmentCount"] as? Int { g.widthSegmentCount = i } 77 | if let i = json["heightSegmentCount"] as? Int { g.heightSegmentCount = i } 78 | return g 79 | } 80 | @objc class func SCNPyramid(_ json: jsonType) -> SCNPyramid { 81 | guard 82 | let w = json["width"] as? CGFloat, 83 | let h = json["height"] as? CGFloat, 84 | let l = json["length"] as? CGFloat 85 | else { return SceneKit.SCNPyramid() } 86 | let g = SceneKit.SCNPyramid(width: w, height: h, length: l) 87 | return g 88 | } 89 | @objc class func SCNSphere(_ json:jsonType)-> SCNSphere { 90 | guard 91 | let r = json["radius"] as? CGFloat 92 | else { return SceneKit.SCNSphere() } 93 | let g = SceneKit.SCNSphere(radius: r) 94 | return g 95 | } 96 | @objc class func SCNTorus(_ json: jsonType) -> SCNTorus { 97 | guard 98 | let tr = json["ringR"] as? CGFloat, 99 | let br = json["pipeR"] as? CGFloat 100 | else { return SceneKit.SCNTorus() } 101 | let g = SceneKit.SCNTorus(ringRadius: tr, pipeRadius: br) 102 | return g 103 | } 104 | @objc class func SCNTube(_ json: jsonType) -> SCNTube { 105 | guard 106 | let tr = json["innerR"] as? CGFloat, 107 | let br = json["outerR"] as? CGFloat, 108 | let h = json["height"] as? CGFloat 109 | else { return SceneKit.SCNTube() } 110 | let g = SceneKit.SCNTube(innerRadius: tr, outerRadius: br, height: h) 111 | return g 112 | } 113 | @objc class func SCNText(_ json: jsonType) -> SCNText { 114 | let baseFontSize:CGFloat = 12.0; 115 | let text = json["text"] as? String ?? "(null)" 116 | let depth = json["depth"] as? CGFloat ?? 0.0 117 | let fontSize = json["size"] as? CGFloat ?? baseFontSize 118 | let size:CGFloat = fontSize / baseFontSize; 119 | let st = SceneKit.SCNText(string: text, extrusionDepth: (depth / size)) 120 | st.flatness = 0.1 121 | var f = UIFont.systemFont(ofSize: baseFontSize) 122 | if let fontName = json["fontName"] as? String { 123 | if let tf = UIFont(name: fontName, size: baseFontSize) { f = tf } 124 | } 125 | if let cf = json["chamfer"] as? CGFloat { st.chamferRadius = cf / size } 126 | st.font = f 127 | return st 128 | } 129 | @objc class func SCNLight(_ json: jsonType) -> SCNLight { 130 | let l = SceneKit.SCNLight() 131 | setLightProperties(l, properties: json) 132 | return l 133 | } 134 | @objc class func SCNShape(_ json: jsonType) -> SCNShape { 135 | guard 136 | let svg = json["pathSvg"] as? String 137 | else { return SceneKit.SCNShape()} 138 | let extrusion = json["extrusion"] as? CGFloat ?? 0.0 139 | let path = svgStringToBezier(svg) 140 | if let f = json["pathFlatness"] as? CGFloat { path.flatness = f } 141 | let uib = UIBezierPath(cgPath: path.cgPath) 142 | let g = SceneKit.SCNShape(path: uib, extrusionDepth: extrusion) 143 | if let e = json["chamferMode"] as? SCNChamferMode { g.chamferMode = e } 144 | if let f = json["chamferRadius"] as? CGFloat { g.chamferRadius = f } 145 | if let csvg = json["chamferProfilePathSvg"] as? String { 146 | let cpath = svgStringToBezier(csvg) 147 | if let f = json["chamferProfilePathFlatness"] as? CGFloat { cpath.flatness = f } 148 | let bb:CGRect = cpath.bounds 149 | if bb.size.width > 0 && bb.size.height > 0 { 150 | let scalex = 1 / bb.size.width 151 | let scaley = 1 / bb.size.height 152 | let transform = CGAffineTransform(scaleX: scalex, y: scaley) 153 | cpath.apply(transform) 154 | let cgpath = cpath.cgPath 155 | let upath = UIBezierPath(cgPath: cgpath) 156 | // g.chamferProfile = upath //Disabled chamfer for now because it keeps crashing @TODO 157 | } 158 | } 159 | return g 160 | } 161 | @objc class func SKLabelNode(_ json: jsonType) -> SKLabelNode { 162 | let skln = SpriteKit.SKLabelNode() 163 | doUpdateSKLabelNode(skln, json: json); 164 | skln.yScale = -1 165 | return skln 166 | } 167 | @objc class func SKScene(_ json: jsonType) -> SKScene { 168 | let s = SpriteKit.SKScene() 169 | doUpdateSKScene(s, json: json) 170 | return s 171 | } 172 | @objc class func SKVideoNode(_ json: jsonType) -> SKVideoNode { 173 | var svn: SpriteKit.SKVideoNode? 174 | if let s = json["url"] as? String { 175 | if let u = URL(string: s) { 176 | svn = SpriteKit.SKVideoNode(url: u) 177 | } 178 | } else if let s = json["path"] as? String { 179 | let u = URL(fileURLWithPath: s) 180 | NSLog("Loading video from path " + s) 181 | svn = SpriteKit.SKVideoNode(url: u) 182 | } 183 | if svn == nil { svn = SpriteKit.SKVideoNode() ; return svn! } 184 | doUpdateSKVideoNode(svn!, json: json) 185 | return svn! 186 | } 187 | } 188 | func doUpdateSKVideoNode(_ node:SKVideoNode, json: jsonType) { 189 | doUpdateSKNode(node, json: json) 190 | let h = json["height"] as? Double ?? 100 191 | let w = json["width"] as? Double ?? 100 192 | NSLog("Updating SKVideo to height " + String(h) + " and width " + String(w)) 193 | node.size = CGSize(width: CGFloat(w), height: CGFloat(h)) 194 | if json["isPlaying"] as? Bool ?? false { 195 | NSLog("Starting video...") 196 | DispatchQueue.main.async() { 197 | node.play() 198 | } 199 | } else { 200 | DispatchQueue.main.async() { 201 | node.pause() 202 | } 203 | } 204 | } 205 | func doUpdateSKNode(_ node: SKNode, json: jsonType) { 206 | if let s = json["name"] as? String { node.name = s } 207 | if let j = json["position"] as? jsonType { 208 | let x = j["x"] as? Double ?? 0 209 | let y = j["y"] as? Double ?? 0 210 | node.position = CGPoint(x: x, y: y) 211 | } 212 | } 213 | func doUpdateSKScene(_ scene:SKScene, json:jsonType) { 214 | if let s = json["name"] as? String { scene.name = s } 215 | if let i = json["color"] { scene.backgroundColor = RCTConvert.uiColor(i) } 216 | let h = json["height"] as? Double ?? 100 217 | let w = json["width"] as? Double ?? 100 218 | NSLog("Updating scene to height of " + String(h) + " and width of " + String(w) ) 219 | print(json) 220 | scene.size = CGSize(width: CGFloat(w), height: CGFloat(h)) 221 | } 222 | func doUpdateSKLabelNode(_ skln:SKLabelNode, json: jsonType) { 223 | doUpdateSKNode(skln, json: json) 224 | if let s = json["text"] as? String { skln.text = s } 225 | skln.numberOfLines = json["lines"] as? Int ?? 1 226 | switch json["lineBreak"] as? String { 227 | case "char": skln.lineBreakMode = .byCharWrapping 228 | case "ellipsis": skln.lineBreakMode = .byTruncatingTail 229 | case "word": skln.lineBreakMode = .byWordWrapping 230 | case nil: skln.lineBreakMode = skln.numberOfLines == 1 ? .byTruncatingTail : .byWordWrapping 231 | default:skln.lineBreakMode = skln.numberOfLines == 1 ? .byTruncatingTail : .byWordWrapping 232 | } 233 | skln.lineBreakMode = .byWordWrapping 234 | if let s = json["fontName"] as? String { skln.fontName = s } 235 | if let d = json["fontSize"] as? Double { skln.fontSize = CGFloat(d) } 236 | if let c = json["fontColor"] { skln.fontColor = RCTConvert.uiColor(c) } 237 | skln.verticalAlignmentMode = .top 238 | if let s = json["verticalAlignment"] as? String { 239 | switch s { 240 | case "top": 241 | skln.verticalAlignmentMode = .top 242 | case "baseline": 243 | skln.verticalAlignmentMode = .baseline 244 | case "bottom": 245 | skln.verticalAlignmentMode = .bottom 246 | case "center": 247 | skln.verticalAlignmentMode = .center 248 | default: 249 | print("Invalid verticalalignmentmode passed: " + s) 250 | } 251 | } 252 | skln.horizontalAlignmentMode = .left 253 | if let s = json["horizontalAlignment"] as? String { 254 | switch s { 255 | case "left": 256 | skln.horizontalAlignmentMode = .left 257 | case "center": 258 | skln.horizontalAlignmentMode = .center 259 | case "right": 260 | skln.horizontalAlignmentMode = .right 261 | default: 262 | print("Invalid horizontalalignmentmode passed " + s) 263 | } 264 | } 265 | if let d = json["width"] as? Double { skln.preferredMaxLayoutWidth = CGFloat(d) } 266 | if json["allowScaling"] as? Bool ?? true { 267 | let scalingFactor = skln.preferredMaxLayoutWidth / skln.frame.width 268 | if(scalingFactor < 1) { 269 | skln.fontSize = skln.fontSize * scalingFactor 270 | } 271 | } 272 | } 273 | func addMaterials(_ g:SCNGeometry, json: jsonType, sides:Int) { 274 | guard let mj = json["material"] as? jsonType else { return } 275 | let m = RCTConvert.SCNMaterial(mj) 276 | var ms:[SceneKit.SCNMaterial] = []; 277 | for _ in 1...sides { 278 | ms.append(m) 279 | } 280 | g.materials = ms 281 | } 282 | func setMaterialProperties(_ material:SCNMaterial, properties: jsonType) { 283 | material.isDoubleSided = properties["doubleSided"] as? Bool ?? true 284 | if let i = properties["blendMode"] as? SCNBlendMode { material.blendMode = i } 285 | if let lm = properties["lightingModel"] as? SCNMaterial.LightingModel { material.lightingModel = lm } 286 | if let f = properties["transparency"] as? CGFloat { material.transparency = f} 287 | if let f = properties["metalness"] as? Double { material.lightingModel = .physicallyBased; material.metalness.contents = f} 288 | if let f = properties["roughness"] as? Double { material.lightingModel = .physicallyBased; material.roughness.contents = f} 289 | if let x = properties["shaders"] as? [SCNShaderModifierEntryPoint: String] { material.shaderModifiers = x} 290 | if let b = properties["writesToDepthBuffer"] as? Bool { material.writesToDepthBuffer = b } 291 | if let i = properties["colorBufferWriteMask"] as? SCNColorMask { material.colorBufferWriteMask = i} 292 | if let i = properties["fillMode"] as? SCNFillMode { material.fillMode = i} 293 | if let b = properties["litPerPixel"] as? Bool { material.isLitPerPixel = b} 294 | material.transparencyMode = .aOne 295 | } 296 | func setNodeProperties(_ node:SCNNode, properties: jsonType) { 297 | if let i = properties["categoryBitMask"] as? Int { node.categoryBitMask = i } 298 | if let i = properties["renderingOrder"] as? Int { node.renderingOrder = i } 299 | if let b = properties["castsShadow"] as? Bool { node.castsShadow = b } 300 | if let d = properties["position"] as? jsonType { node.position = RCTConvert.SCNVector3(d) } 301 | if let f = properties["scale"] as? Double { node.scale = SCNVector3(f, f, f) } 302 | if let d = properties["eulerAngles"] as? jsonType { node.eulerAngles = RCTConvert.SCNVector3(d) } 303 | if let d = properties["orientation"] as? jsonType { node.orientation = RCTConvert.SCNVector4(d) } 304 | if let d = properties["rotation"] as? jsonType { node.rotation = RCTConvert.SCNVector4(d) } 305 | if let f = properties["opacity"] as? CGFloat { node.opacity = f } 306 | } 307 | func setMaterialPropertyContents(_ properties: jsonType, materialProperty: SCNMaterialProperty) { 308 | if let path = properties["path"] { materialProperty.contents = path } 309 | else if let color = properties["color"] { materialProperty.contents = RCTConvert.uiColor(color) } 310 | if let intensity = properties["intensity"] as? CGFloat { materialProperty.intensity = intensity } 311 | } 312 | func setShapeProperties(_ g:SCNGeometry, properties: jsonType) { 313 | properties.forEach() {k, v in 314 | guard 315 | let vs = v as? String, 316 | !specialShapeProperties.contains(vs), 317 | let f = Float(vs) 318 | else { return } 319 | g.setValue(f, forKey: k) 320 | } 321 | guard let shapeGeometry = g as? SCNShape else { return } 322 | if let s = properties["pathSvg"] as? String { 323 | let path = svgStringToBezier(s) 324 | if let f = properties["pathFlatness"] as? CGFloat { path.flatness = f } 325 | shapeGeometry.path = path 326 | } 327 | if let d = properties["chamferProfilesPathSvg"] as? jsonType { setChamferProfilePathSvg(shapeGeometry, properties: d) } 328 | } 329 | func svgStringToBezier(_ path:String) -> SVGBezierPath { 330 | NSLog("Starting with path " + path) 331 | guard let paths:[SVGBezierPath] = SVGBezierPath.paths(fromSVGString: path) as? [SVGBezierPath] else { return SVGBezierPath() } 332 | NSLog("I am continuing with interpreted paths: " + String(paths.count)) 333 | let fullPath = paths[0]; 334 | NSLog("Fullpath") 335 | NSLog(fullPath.svgRepresentation) 336 | NSLog("that's all she wrote") 337 | if(paths.count > 1) { 338 | for x in 2...paths.count { 339 | let p = paths[x-1] 340 | fullPath.append(p) 341 | } 342 | } 343 | return fullPath 344 | } 345 | func setChamferProfilePathSvg(_ g:SCNShape, properties: jsonType) { 346 | guard let svg = properties["chamferProfilePathSvg"] as? String else { return } 347 | let path = svgStringToBezier(svg) 348 | let cgpath = path.cgPath 349 | let upath = UIBezierPath(cgPath: cgpath) 350 | if let f = properties["chamferProfilePathFlatness"] as? CGFloat { upath.flatness = f } 351 | let bb:CGRect = upath.bounds 352 | if bb.size.width > 0 && bb.size.height > 0 { 353 | let scalex = 1 / bb.size.width 354 | let scaley = 1 / bb.size.height 355 | let transform = CGAffineTransform(scaleX: scalex, y: scaley) 356 | upath.apply(transform) 357 | g.chamferProfile = upath 358 | } 359 | } 360 | func setLightProperties(_ light:SCNLight, properties: jsonType) { 361 | if let i = properties["lightCategoryBitMask"] as? Int { light.categoryBitMask = i } 362 | if let e = properties["type"] as? SCNLight.LightType { light.type = e } 363 | if let c = properties["color"], let rc = RCTConvert.cgColor(c) { light.color = rc } 364 | if let f = properties["temperature"] as? CGFloat { light.temperature = f } 365 | if let f = properties["intensity"] as? CGFloat { light.intensity = f } 366 | if let f = properties["attenuationStartDistance"] as? CGFloat { light.attenuationStartDistance = f} 367 | if let f = properties["attenuationEndDistance"] as? CGFloat { light.attenuationEndDistance = f} 368 | if let f = properties["spotInnerAngle"] as? CGFloat { light.spotInnerAngle = f} 369 | if let f = properties["spotOuterAngle"] as? CGFloat { light.spotOuterAngle = f} 370 | if let b = properties["castsShadow"] as? Bool { light.castsShadow = b } 371 | if let f = properties["shadowRadius"] as? CGFloat { light.shadowRadius = f } 372 | if let c = properties["shadowColor"], let rc = RCTConvert.cgColor(c) { light.shadowColor = rc } 373 | if let i = properties["shadowSampleCount"] as? Int { light.shadowSampleCount = i } 374 | if let f = properties["shadowBias"] as? CGFloat { light.shadowBias = f } 375 | if let e = properties["shadowMode"] as? SCNShadowMode { light.shadowMode = e } 376 | if let f = properties["orthographicScale"] as? CGFloat { light.orthographicScale = f } 377 | if let f = properties["zFar"] as? CGFloat { light.zFar = f } 378 | if let f = properties["zNear"] as? CGFloat { light.orthographicScale = f } 379 | } 380 | let specialShapeProperties:Set = [ 381 | "pathSvg", 382 | "chamferProfilePathSvg" 383 | ] 384 | func vector3ToJson(_ v:SCNVector3) -> jsonType { 385 | return ["x": v.x, "y": v.y, "z": v.z] 386 | } 387 | func vector_float3ToJson(_ v:vector_float3) -> jsonType { 388 | return ["x": v.x, "y": v.y, "z": v.z] 389 | } 390 | func vector4ToJson(_ v:SCNVector4) -> jsonType { 391 | return ["x": v.x, "y": v.y, "z": v.z, "w": v.w] 392 | } 393 | func vector_float4ToVector3(_ v:vector_float4) -> SCNVector3 { 394 | return SCNVector3(v.x, v.y, v.z) 395 | } 396 | -------------------------------------------------------------------------------- /ios/react_native-arkit-swift/ARMonoview.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ARKit 3 | @objc(ARMonoView) 4 | class ARMonoView: UIView, ARSCNViewDelegate { 5 | var arview: ARSCNView? 6 | var _preview:Bool = true 7 | var cachedPreview: Any? 8 | var _debugMode: Bool = false 9 | @objc var preview:Bool { 10 | get { 11 | return _preview 12 | } 13 | set(newVal) { 14 | if cachedPreview == nil { 15 | cachedPreview = arview?.scene.background.contents 16 | } 17 | _preview = newVal 18 | if(_preview) { 19 | arview?.scene.background.contents = cachedPreview 20 | 21 | } else { 22 | arview?.scene.background.contents = UIColor.black 23 | } 24 | } 25 | } 26 | @objc var debugMode: Bool { 27 | get { 28 | return _debugMode 29 | } 30 | set(newVal) { 31 | _debugMode = newVal 32 | arview?.debugOptions = newVal ? .showFeaturePoints : .init(rawValue: 0) 33 | } 34 | } 35 | func start() -> ARMonoView { 36 | if Thread.isMainThread { 37 | let a = ARSCNView() 38 | arview = a 39 | a.delegate = self 40 | guard let sm = ARSceneManager.sharedInstance else { return self } 41 | a.session.delegate = sm 42 | sm.scene = a.scene 43 | sm.session = a.session 44 | sm.pv = a 45 | a.automaticallyUpdatesLighting = true 46 | a.autoenablesDefaultLighting = true 47 | addSubview(a) 48 | sm.doResume() 49 | } 50 | return self 51 | } 52 | override func layoutSubviews() { 53 | super.layoutSubviews() 54 | arview?.frame = self.bounds 55 | } 56 | func handleTap(point: CGPoint, resolve:RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) { 57 | guard let v = arview else { reject("no_view", "No AR View", nil); return } 58 | let r = v.hitTest(point, options: nil) 59 | let m = r.map() { h in 60 | return h.node.name 61 | } 62 | resolve(["nodes": m]); 63 | } 64 | func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) { 65 | guard let scene = ARSceneManager.sharedInstance else { return } 66 | scene.updateAnchor(anchor, withNode: node) 67 | } 68 | func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { 69 | guard let scene = ARSceneManager.sharedInstance else { return } 70 | scene.addAnchor(anchor, withNode: node) 71 | 72 | } 73 | func renderer(_ renderer: SCNSceneRenderer, didRenderScene scene: SCNScene, atTime time: TimeInterval) { 74 | guard let scene = ARSceneManager.sharedInstance else { return } 75 | if let pov = renderer.pointOfView { scene.updatePOV(pov) } 76 | scene.updateRegisteredViews() 77 | 78 | } 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /ios/react_native-arkit-swift/ARMonoviewManager.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | @objc(ARMonoViewManager) 3 | class ARMonoViewManager:RCTViewManager { 4 | var v: ARMonoView? 5 | override func view() -> ARMonoView { 6 | v = (ARMonoView()).start() 7 | return v! 8 | } 9 | override class func requiresMainQueueSetup() -> Bool { 10 | return false 11 | } 12 | @objc func doTap(_ x: Double, y: Double, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) { 13 | guard let v = self.v else { reject("no_view", "No View loaded", nil); return } 14 | v.handleTap(point: CGPoint(x: CGFloat(x), y: CGFloat(y)), resolve:resolve, reject: reject) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ios/react_native-arkit-swift/ARPrimaryView.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ARKit 3 | 4 | @objc(ARPrimaryView) 5 | class ARPrimaryView: UIView, ARSCNViewDelegate { 6 | var arview: ARSCNView? 7 | var pview: SCNView? 8 | var onStart:RCTBubblingEventBlock? 9 | @objc var interPupilaryDistance:Float = 0.066 10 | @objc var holoOffsetY: Float = 0.08 11 | @objc var holoOffsetZ: Float = -0.08 12 | @objc var holoOffsetX: Float = 0.033 13 | @objc var fieldOfView: Float = 60 14 | func start() -> ARPrimaryView { 15 | if Thread.isMainThread { 16 | let a = ARSCNView() 17 | let p = SCNView() 18 | pview = p 19 | p.scene = a.scene 20 | p.isPlaying = true 21 | p.autoenablesDefaultLighting = true 22 | arview = a 23 | a.delegate = self 24 | guard let sm = ARSceneManager.sharedInstance else { return self } 25 | a.session.delegate = sm 26 | sm.addScene(a.scene) 27 | sm.session = a.session 28 | p.backgroundColor = UIColor.yellow 29 | p.scene?.background.contents = UIColor.black 30 | a.autoenablesDefaultLighting = true 31 | addSubview(a) 32 | addSubview(p) 33 | sm.doResume() 34 | self.clipsToBounds = true 35 | } else { 36 | DispatchQueue.main.async(){ 37 | let _ = self.start(); 38 | } 39 | } 40 | return self 41 | } 42 | override func layoutSubviews() { 43 | super.layoutSubviews() 44 | pview?.frame = self.bounds 45 | arview?.frame = self.bounds 46 | arview?.isHidden = true 47 | } 48 | func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { 49 | DispatchQueue.main.async() { 50 | guard 51 | let sm = ARSceneManager.sharedInstance, 52 | let sv = sm.secondaryView, 53 | let ppv = self.pview, 54 | let pv = self.arview, 55 | let PVpointOfView = pv.pointOfView?.clone() 56 | else { return } 57 | 58 | let orientation : SCNQuaternion = PVpointOfView.orientation 59 | let YPos = SCNQToSCN3(orientation, v:SCNVector3Make( 0, 1, 0)) 60 | PVpointOfView.position = applyOffset(v: PVpointOfView.position, withV: YPos, byScalar: self.holoOffsetY) 61 | let ZPos = SCNQToSCN3(orientation, v: SCNVector3Make(0,0,1)) 62 | PVpointOfView.position = applyOffset(v: PVpointOfView.position, withV: ZPos , byScalar: self.holoOffsetZ) 63 | let XPos = SCNQToSCN3(orientation, v:SCNVector3Make( 1, 0, 0)) 64 | PVpointOfView.position = applyOffset(v: PVpointOfView.position, withV: XPos, byScalar: self.holoOffsetX) 65 | PVpointOfView.camera?.fieldOfView = CGFloat(self.fieldOfView) 66 | ppv.pointOfView = PVpointOfView 67 | // Determine Adjusted Position for Right Eye 68 | let SVPointOfView = PVpointOfView.clone() 69 | SVPointOfView.position = applyOffset(v: SVPointOfView.position, withV: XPos, byScalar:1.0 * self.interPupilaryDistance) 70 | SVPointOfView.camera?.fieldOfView = CGFloat(self.fieldOfView) 71 | sv.pointOfView = SVPointOfView 72 | if let pov = renderer.pointOfView { sm.updatePOV(pov) } 73 | sm.updateRegisteredViews() 74 | } 75 | } 76 | func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) { 77 | guard let scene = ARSceneManager.sharedInstance else { return } 78 | scene.updateAnchor(anchor, withNode: node) 79 | } 80 | func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { 81 | guard let scene = ARSceneManager.sharedInstance else { return } 82 | scene.addAnchor(anchor, withNode: node) 83 | 84 | } 85 | func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) { 86 | guard let scene = ARSceneManager.sharedInstance else { return } 87 | scene.removeAnchor(anchor, withNode: node) 88 | } 89 | } 90 | func GLK3ToSCN3(_ g:GLKVector3) -> SCNVector3 { 91 | return SCNVector3Make(g.x, g.y, g.z) 92 | } 93 | func SCN3ToGLK3(_ s:SCNVector3) -> GLKVector3 { 94 | return GLKVector3Make(s.x, s.y, s.z) 95 | } 96 | func GQToSCN3(_ q: GLKQuaternion, v: GLKVector3) -> SCNVector3 { 97 | let gv = GLKQuaternionRotateVector3(q, v) 98 | return GLK3ToSCN3(gv) 99 | } 100 | func SCNQToGQ(_ q: SCNQuaternion) -> GLKQuaternion { 101 | return GLKQuaternionMake(q.x, q.y, q.z, q.w); 102 | } 103 | func SCNQToSCN3(_ q: SCNQuaternion, v: SCNVector3) -> SCNVector3 { 104 | let gq = SCNQToGQ(q) 105 | return GQToSCN3(gq, v: SCN3ToGLK3(v)); 106 | } 107 | func applyOffset(v: SCNVector3, withV:SCNVector3, byScalar: Float) -> SCNVector3 { 108 | var v2 = SCNVector3Make(v.x, v.y, v.z) 109 | v2.x += withV.x * byScalar 110 | v2.y += withV.y * byScalar 111 | v2.z += withV.z * byScalar 112 | return v2 113 | } 114 | -------------------------------------------------------------------------------- /ios/react_native-arkit-swift/ARPrimaryViewManager.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | @objc(ARPrimaryViewManager) 3 | class ARPrimaryViewManager : RCTViewManager { 4 | override func view() -> ARPrimaryView { 5 | return (ARPrimaryView()).start() 6 | } 7 | override class func requiresMainQueueSetup() -> Bool { 8 | return false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ios/react_native-arkit-swift/ARProjectedView.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | @objc(ARProjectedView) 3 | class ARProjectedView: UIView { 4 | var _parentNode:String? 5 | @objc var parentNode:String? { 6 | get { return _parentNode } 7 | set(newNode) { 8 | _parentNode = newNode 9 | guard let s = ARSceneManager.sharedInstance else { return } 10 | s.registerView(newNode, view: self) 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/react_native-arkit-swift/ARProjectedViewManager.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | @objc(ARProjectedViewManager) 4 | class ARProjectedViewManager: RCTViewManager { 5 | override func view() -> ARProjectedView { 6 | let v = ARProjectedView() 7 | return v 8 | } 9 | override class func requiresMainQueueSetup() -> Bool { 10 | return false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ios/react_native-arkit-swift/ARSecondaryView.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SceneKit 3 | 4 | @objc(ARSecondaryView) 5 | class ARSecondaryView: UIView { 6 | var sview: SCNView? 7 | var isStarted:Bool = false 8 | 9 | func start() -> ARSecondaryView { 10 | guard !isStarted else { return self } 11 | if Thread.isMainThread { 12 | guard let sm = ARSceneManager.sharedInstance else { return self } 13 | let v = SCNView() 14 | sview = v 15 | v.scene = sm.scene 16 | v.isPlaying = true 17 | v.autoenablesDefaultLighting = true 18 | sm.secondaryView = v 19 | addSubview(v) 20 | isStarted = true 21 | } else { 22 | DispatchQueue.main.async() { 23 | let _ = self.start() 24 | } 25 | } 26 | return self 27 | } 28 | override func layoutSubviews() { 29 | super.layoutSubviews() 30 | guard let v = sview else { return } 31 | v.frame = self.bounds 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ios/react_native-arkit-swift/ARSecondaryViewManager.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | @objc(ARSecondaryViewManager) 3 | class ARSecondaryViewManager : RCTViewManager { 4 | override func view() -> ARSecondaryView { 5 | return (ARSecondaryView()).start() 6 | } 7 | override class func requiresMainQueueSetup() -> Bool { 8 | return false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ios/rn-swift-bridge.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | @interface RCT_EXTERN_MODULE(ARMonoViewManager, RCTViewManager) 5 | RCT_EXTERN_METHOD(doTap:(double)x y:(double)y resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 6 | RCT_EXPORT_VIEW_PROPERTY(preview, BOOL); 7 | RCT_EXPORT_VIEW_PROPERTY(debugMode, BOOL); 8 | @end 9 | @interface RCT_EXTERN_MODULE(ARPrimaryViewManager, RCTViewManager) 10 | RCT_EXPORT_VIEW_PROPERTY(interPupilaryDistance, float); 11 | RCT_EXPORT_VIEW_PROPERTY(holoOffsetY, float); 12 | RCT_EXPORT_VIEW_PROPERTY(holoOffsetZ, float); 13 | RCT_EXPORT_VIEW_PROPERTY(holoOffsetX, float); 14 | RCT_EXPORT_VIEW_PROPERTY(fieldOfView, float); 15 | @end 16 | @interface RCT_EXTERN_MODULE(ARProjectedViewManager, RCTViewManager) 17 | RCT_EXPORT_VIEW_PROPERTY(parentNode, NSString *); 18 | @end 19 | @interface RCT_EXTERN_MODULE(ARSceneManager, RCTEventEmitter) 20 | RCT_EXTERN_METHOD(addNode:(SCNNode *)node parentID:(NSString *)parentID resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 21 | RCT_EXTERN_METHOD(removeNode:(NSString *)id resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 22 | RCT_EXTERN_METHOD(updateNode:(NSString *)forNode newProps:(NSDictionary *)newProps resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 23 | RCT_EXTERN_METHOD(setBox:(SCNBox *)g forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 24 | RCT_EXTERN_METHOD(setCapsule:(SCNCapsule *)g forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 25 | RCT_EXTERN_METHOD(setCone:(SCNCone *)g forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 26 | RCT_EXTERN_METHOD(setCylinder:(SCNCylinder *)g forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 27 | RCT_EXTERN_METHOD(setPlane:(SCNPlane *)g forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 28 | RCT_EXTERN_METHOD(setPyramid:(SCNPyramid *)g forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 29 | RCT_EXTERN_METHOD(setSphere:(SCNSphere *)g forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 30 | RCT_EXTERN_METHOD(setText:(SCNText *)g forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 31 | RCT_EXTERN_METHOD(setTorus:(SCNTorus *)g forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 32 | RCT_EXTERN_METHOD(setTube:(SCNTube *)g forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 33 | RCT_EXTERN_METHOD(setShape:(SCNShape *)g forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 34 | RCT_EXTERN_METHOD(setGeometry:(SCNGeometry *)geometry forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 35 | RCT_EXTERN_METHOD(setLight:(SCNLight *)light forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 36 | RCT_EXTERN_METHOD(removeLight:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 37 | RCT_EXTERN_METHOD(setMaterial:(SCNMaterial *)material forNode:(NSString *)forNode atPosition:(NSInteger)atPosition resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 38 | RCT_EXTERN_METHOD(setMaterialProperty:(NSDictionary *)json propertyName:(NSString *)propertyName forMaterialAtPosition:(NSInteger)forMaterialAtPosition forNode:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 39 | RCT_EXTERN_METHOD(removeGeometry:(NSString *)forNode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 40 | RCT_EXTERN_METHOD(removeMaterial:(NSString *)forNode atPosition:(NSInteger)atPosition resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 41 | RCT_EXTERN_METHOD(setScene:(NSString *)forNode sourcePath:(NSString *)sourcePath resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 42 | RCT_EXTERN_METHOD(setModel:(NSString *)forNode sourcePath:(NSString *)sourcePath resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 43 | RCT_EXTERN_METHOD(addSKSceneReference:(SKScene *)scene resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 44 | RCT_EXTERN_METHOD(addSKSceneByReference:(NSString *)sceneName forNode:(NSString *)forNode atPosition:(NSInteger)atPosition withType:(NSString *)withType resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 45 | RCT_EXTERN_METHOD(addSKScene:(SKScene *)scene forNode:(NSString *)forNode atPosition:(NSInteger)atPosition withType:(NSString *)withType resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 46 | RCT_EXTERN_METHOD(updateSKScene:(NSDictionary *)scene forNode:(NSString *)forNode atPosition:(NSInteger)atPosition withType:(NSString *)withType resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 47 | RCT_EXTERN_METHOD(setSKLabelNode:(SKLabelNode *)node toParent:(NSString *)toParent resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 48 | RCT_EXTERN_METHOD(updateSKLabelNode:(NSDictionary *)json resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 49 | RCT_EXTERN_METHOD(setSKVideoNode:(SKVideoNode *)node toParent:(NSString *)toParent resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 50 | RCT_EXTERN_METHOD(updateSKVideoNode:(NSDictionary *)json resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 51 | RCT_EXTERN_METHOD(setSKNode:(SKNode *)node toParent:(NSString *)toParent resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 52 | RCT_EXTERN_METHOD(removeSKNode:(NSString *)name resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 53 | RCT_EXTERN_METHOD(removeSKScene:(NSString *)forNode atPosition:(NSInteger)atPosition withType:(NSString *)withType resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 54 | RCT_EXTERN_METHOD(addSKLabelNode:(SKLabelNode *)node toParent:(NSString *)toParent resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 55 | RCT_EXTERN_METHOD(addSKNode:(SKNode *)node toParent:(NSString *)toParent resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 56 | RCT_EXTERN_METHOD(clear:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 57 | RCT_EXTERN_METHOD(resume:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 58 | RCT_EXTERN_METHOD(pause:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 59 | RCT_EXTERN_METHOD(setAnimation:(double)seconds type:(NSString *)type resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 60 | RCT_EXTERN_METHOD(setAnimationDuration:(double)seconds resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 61 | RCT_EXTERN_METHOD(setAnimationType:(NSString *)type resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 62 | RCT_EXTERN_METHOD(setPlaneDetection:(NSString *)detectPlanes resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 63 | RCT_EXTERN_METHOD(getAnchors:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 64 | RCT_EXTERN_METHOD(removeAnchor:(NSString *)id resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 65 | RCT_EXTERN_METHOD(addRecognizerImage:(NSString *)url name:(NSString *)name width:(double)width resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 66 | RCT_EXTERN_METHOD(removeRecognizerImage:(NSString *)name resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 67 | RCT_EXTERN_METHOD(setImageDetection:(BOOL)doDetect resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 68 | RCT_EXTERN_METHOD(projectNode:(NSString *)nodeID resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 69 | RCT_EXTERN_METHOD(projectWorldPoint:(SCNVector3 *)v resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 70 | RCT_EXTERN_METHOD(setPOVSensitivity:(double)newSensitivity resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 71 | RCT_EXTERN_METHOD(setPOVOrientationSensitivity:(double)newSensitivity resolve:(RCTPromiseResolveBlock)resolve recject:(RCTPromiseRejectBlock)recject); 72 | RCT_EXTERN_METHOD(getPOV:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 73 | RCT_EXTERN_METHOD(setWorldTracking:(NSString *)trackingMode resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 74 | RCT_EXTERN_METHOD(hitTestPlane:(CGPoint *)point detectType:(NSString *)detectType resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); 75 | @end 76 | @interface RCT_EXTERN_MODULE(ARSecondaryViewManager, RCTViewManager) 77 | @end -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-reality", 3 | "version": "1.1.0", 4 | "peerDependencies": { 5 | "react-native-pod": "^1.6.0", 6 | "react-native-swift": "^0.10.0" 7 | }, 8 | "main": "index.js", 9 | "scripts": { 10 | "bridge": "react-native-swift-bridge", 11 | "watch": "react-native-swift-bridge --watch" 12 | }, 13 | "dependencies": { 14 | "fast-deep-equal": "^1.0.0", 15 | "lodash": "^4.17.5", 16 | "prop-types": "^15.6.0", 17 | "react-adopt": "^0.6.0", 18 | "react-native-swift-bridge": "^2.4.2", 19 | "uuid": "^3.2.1" 20 | }, 21 | "pods": { 22 | "PocketSVG": "*" 23 | }, 24 | "devDependencies": { 25 | "react": "^16.3.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /yarn-error.log: -------------------------------------------------------------------------------- 1 | Arguments: 2 | /usr/local/Cellar/node/9.6.1/bin/node /usr/local/Cellar/yarn/1.5.1/libexec/bin/yarn.js watch 3 | 4 | PATH: 5 | /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/element55/published/tools/ 6 | 7 | Yarn version: 8 | 1.5.1 9 | 10 | Node version: 11 | 9.6.1 12 | 13 | Platform: 14 | darwin x64 15 | 16 | npm manifest: 17 | { 18 | "name": "react-native-arkit-swift", 19 | "version": "0.0.1", 20 | "peerDependencies": { 21 | "react-native-pod": "^1.6.0", 22 | "react-native-swift": "^0.10.0" 23 | }, 24 | "main": "index.js", 25 | "scripts": { 26 | "bridge": "react-native-swift-bridge", 27 | "watch": "react-native-swift-bridge --watch" 28 | }, 29 | "dependencies": { 30 | "@panter/react-animation-frame": "^0.3.7", 31 | "fast-deep-equal": "^1.0.0", 32 | "lodash": "^4.17.5", 33 | "prop-types": "^15.6.0", 34 | "react-native-xcode": "^1.0.0", 35 | "uuid": "^3.2.1" 36 | }, 37 | "pods": { 38 | "PocketSVG": "*" 39 | }, 40 | "devDependencies": { 41 | "react": "^16.2.0" 42 | } 43 | } 44 | 45 | yarn manifest: 46 | No manifest 47 | 48 | Lockfile: 49 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 50 | # yarn lockfile v1 51 | 52 | 53 | "@panter/react-animation-frame@^0.3.7": 54 | version "0.3.7" 55 | resolved "https://registry.npmjs.org/@panter/react-animation-frame/-/react-animation-frame-0.3.7.tgz#31a0d7683e4a8d2e1b29ff512cad36513bd43d00" 56 | dependencies: 57 | react "15.4.2" 58 | 59 | asap@~2.0.3: 60 | version "2.0.6" 61 | resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" 62 | 63 | balanced-match@^1.0.0: 64 | version "1.0.0" 65 | resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 66 | 67 | brace-expansion@^1.1.7: 68 | version "1.1.8" 69 | resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" 70 | dependencies: 71 | balanced-match "^1.0.0" 72 | concat-map "0.0.1" 73 | 74 | concat-map@0.0.1: 75 | version "0.0.1" 76 | resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 77 | 78 | core-js@^1.0.0: 79 | version "1.2.7" 80 | resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" 81 | 82 | encoding@^0.1.11: 83 | version "0.1.12" 84 | resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" 85 | dependencies: 86 | iconv-lite "~0.4.13" 87 | 88 | fast-deep-equal@^1.0.0: 89 | version "1.0.0" 90 | resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" 91 | 92 | fbjs@^0.8.16, fbjs@^0.8.4: 93 | version "0.8.16" 94 | resolved "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" 95 | dependencies: 96 | core-js "^1.0.0" 97 | isomorphic-fetch "^2.1.1" 98 | loose-envify "^1.0.0" 99 | object-assign "^4.1.0" 100 | promise "^7.1.1" 101 | setimmediate "^1.0.5" 102 | ua-parser-js "^0.7.9" 103 | 104 | fs.realpath@^1.0.0: 105 | version "1.0.0" 106 | resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 107 | 108 | glob@^7.1.2: 109 | version "7.1.2" 110 | resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 111 | dependencies: 112 | fs.realpath "^1.0.0" 113 | inflight "^1.0.4" 114 | inherits "2" 115 | minimatch "^3.0.4" 116 | once "^1.3.0" 117 | path-is-absolute "^1.0.0" 118 | 119 | iconv-lite@~0.4.13: 120 | version "0.4.19" 121 | resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" 122 | 123 | inflight@^1.0.4: 124 | version "1.0.6" 125 | resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 126 | dependencies: 127 | once "^1.3.0" 128 | wrappy "1" 129 | 130 | inherits@2: 131 | version "2.0.3" 132 | resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 133 | 134 | is-stream@^1.0.1: 135 | version "1.1.0" 136 | resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 137 | 138 | isomorphic-fetch@^2.1.1: 139 | version "2.2.1" 140 | resolved "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" 141 | dependencies: 142 | node-fetch "^1.0.1" 143 | whatwg-fetch ">=0.10.0" 144 | 145 | js-tokens@^3.0.0: 146 | version "3.0.2" 147 | resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" 148 | 149 | lodash@^4.17.5: 150 | version "4.17.5" 151 | resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" 152 | 153 | loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: 154 | version "1.3.1" 155 | resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" 156 | dependencies: 157 | js-tokens "^3.0.0" 158 | 159 | minimatch@^3.0.4: 160 | version "3.0.4" 161 | resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 162 | dependencies: 163 | brace-expansion "^1.1.7" 164 | 165 | node-fetch@^1.0.1: 166 | version "1.7.3" 167 | resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" 168 | dependencies: 169 | encoding "^0.1.11" 170 | is-stream "^1.0.1" 171 | 172 | object-assign@^4.1.0, object-assign@^4.1.1: 173 | version "4.1.1" 174 | resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 175 | 176 | once@^1.3.0: 177 | version "1.4.0" 178 | resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 179 | dependencies: 180 | wrappy "1" 181 | 182 | path-is-absolute@^1.0.0: 183 | version "1.0.1" 184 | resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 185 | 186 | promise@^7.1.1: 187 | version "7.3.1" 188 | resolved "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" 189 | dependencies: 190 | asap "~2.0.3" 191 | 192 | prop-types@^15.6.0: 193 | version "15.6.0" 194 | resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" 195 | dependencies: 196 | fbjs "^0.8.16" 197 | loose-envify "^1.3.1" 198 | object-assign "^4.1.1" 199 | 200 | react-native-xcode@^1.0.0: 201 | version "1.0.0" 202 | resolved "https://registry.npmjs.org/react-native-xcode/-/react-native-xcode-1.0.0.tgz#e6385a7e114cf7361fa855608d33c90a1d2c07c6" 203 | dependencies: 204 | glob "^7.1.2" 205 | 206 | react@15.4.2: 207 | version "15.4.2" 208 | resolved "https://registry.npmjs.org/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef" 209 | dependencies: 210 | fbjs "^0.8.4" 211 | loose-envify "^1.1.0" 212 | object-assign "^4.1.0" 213 | 214 | react@^16.2.0: 215 | version "16.2.0" 216 | resolved "https://registry.npmjs.org/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" 217 | dependencies: 218 | fbjs "^0.8.16" 219 | loose-envify "^1.1.0" 220 | object-assign "^4.1.1" 221 | prop-types "^15.6.0" 222 | 223 | setimmediate@^1.0.5: 224 | version "1.0.5" 225 | resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" 226 | 227 | ua-parser-js@^0.7.9: 228 | version "0.7.17" 229 | resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" 230 | 231 | uuid@^3.2.1: 232 | version "3.2.1" 233 | resolved "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" 234 | 235 | whatwg-fetch@>=0.10.0: 236 | version "2.0.3" 237 | resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" 238 | 239 | wrappy@1: 240 | version "1.0.2" 241 | resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 242 | 243 | Trace: 244 | Error: Command failed. 245 | Exit signal: SIGTERM 246 | Command: sh 247 | Arguments: -c react-native-swift-bridge --watch 248 | Directory: /Users/ray/Documents/react-native-arkit-swift 249 | Output: 250 | 251 | at ProcessTermError.MessageError (/usr/local/Cellar/yarn/1.5.1/libexec/lib/cli.js:186:110) 252 | at new ProcessTermError (/usr/local/Cellar/yarn/1.5.1/libexec/lib/cli.js:226:113) 253 | at ChildProcess. (/usr/local/Cellar/yarn/1.5.1/libexec/lib/cli.js:30281:17) 254 | at ChildProcess.emit (events.js:127:13) 255 | at maybeClose (internal/child_process.js:933:16) 256 | at Process.ChildProcess._handle.onexit (internal/child_process.js:220:5) 257 | --------------------------------------------------------------------------------