Giter Site home page Giter Site logo

supermedium / aframe-react Goto Github PK

View Code? Open in Web Editor NEW
1.4K 49.0 155.0 1.08 MB

:atom: Build virtual reality experiences with A-Frame and React.

Home Page: https://ngokevin.github.io/aframe-react-boilerplate/

License: MIT License

JavaScript 100.00%
react vr aframe virtual-reality webvr

aframe-react's Introduction

aframe-react

I recommend using vanilla A-Frame and aframe-state-component with static templating over aframe-react. React wastes a lot of cycles and incurs a lot of memory garbage. aframe-react is often abused where it is too easy to place 3D/real-time logic at the React layer, causing poor performance (e.g., doing React renders on ticks). aframe-react applications frequently ignore the prescribed ECS framework of A-Frame. Internally, React does tons of computation to compute what changed, and flushes it to the entire application. It is apparent React ecosystem does not care much about memory as most examples allocate functions and objects in the render method, and where immutables are popular. With only ~10ms per frame to do all computation, there is little room for React's massive system.


Build virtual reality experiences with A-Frame and React.

Examples

Fear of the Sky by Amnesty International UK Snowboards MathworldVR

Installation

Install with npm or yarn.

npm install --save aframe aframe-react react react-dom
yarn add aframe aframe-react react react-dom

Example

import 'aframe';
import 'aframe-particle-system-component';
import {Entity, Scene} from 'aframe-react';
import React from 'react';
import ReactDOM from 'react-dom';

class VRScene extends React.Component {
  render () {
    return (
      <Scene>
        <Entity geometry={{primitive: 'box'}} material={{color: 'red'}} position={{x: 0, y: 0, z: -5}}/>
        <Entity particle-system={{preset: 'snow'}}/>
        <Entity light={{type: 'point'}}/>
        <Entity gltf-model={{src: 'virtualcity.gltf'}}/>
        <Entity text={{value: 'Hello, WebVR!'}}/>
      </Scene>
    );
  }
}

ReactDOM.render(<VRScene/>, document.querySelector('#sceneContainer'));

See aframe-react-boilerplate for a basic example.

Introduction

A-Frame

A-Frame is a web framework for building virtual reality experiences. Since A-Frame is built on top of the DOM, web libraries such as React, Vue.js, Angular, Ember.js, d3.js are able to sit cleanly on top of A-Frame.

A-Frame is an entity-component-system (ECS) framework exposed through HTML. ECS is a pattern used in game development that favors composability over inheritance, which is more naturally suited to 3D scenes where objects are built of complex appearance, behavior, and functionality. In A-Frame, HTML attributes map to components which are composable modules that are plugged into <a-entity>s to attach appearance, behavior, and functionality.

Released on the same day as A-Frame, aframe-react is a very thin layer on top of A-Frame to bridge with React. aframe-react passes React props to directly A-Frame using refs and .setAttribute(), bypassing the DOM. This works since A-Frame's .setAttribute()s are able to take non-string data such as objects, arrays, or elements and synchronously modify underlying 3D scene graph.

// aframe-react's <Entity/> React Component
<Entity geometry={{primitive: 'box', width: 5}} position="0 0 -5"/>

// renders
<a-entity>

// and then applies the data directly to the underlying 3D scene graph, bypassing the DOM.
<a-entity>.setAttribute('geometry', {primitive: 'box', width: 5});
<a-entity>.setAttribute('position', '0 0 -5');

aframe-react provides the best of both worlds between A-Frame and React, the 3D and VR-oriented entity-component architecture of A-Frame, and the view and state management ergonomics of React, without penalties of attempting to use React for a VR application.

Making React Viable

A-Frame and aframe-react gives some viability for React to use in VR applications. The value proposition of React is limited to the 2D Web:

  • Improve rendering performance for 2D web pages by reducing calls to the browser's 2D layout engine via the virtual DOM.
  • Provide an predictable application structure for large 2D web applications through a structured nesting of React components, data binding, and one-way data flow.

However, these propositions fall short in 3D and VR applications:

  • In 3D and VR applications, including A-Frame, the 2D browser layout engine is not touched. Thus React's reconciliation engine can become an unpredictable performance liability for little benefit.
  • In 3D and VR applications, objects are not structured in a top-down hierarchy like 2D web applications. 3D objects can exist anywhere and interact with any other 3D object in a many-to-many manner. But React's paradigm prescribes data flow from parent-to-child, which makes it restrictive for 3D and VR applications.

A-Frame and aframe-react gives meaning and purpose to React: A-Frame provides an actual DOM for React to reconcile, diff, and bind to.

React also raises questions around performance; React is a very large library designed for a 60fps 2D Web, is it equipped to handle 90fps VR applications? 90 prop updates per second per object for many objects through React's engine causes concern in the overhead added for each operation.

aframe-react lets A-Frame handle the heavy lifting 3D and VR rendering and behavior. A-Frame is optimized from the ground up for WebVR with a 3D-oriented entity-component architecture. And aframe-react lets React focus on what it's good at: views, state management, and data binding.

Entity-Component Meets React

A-Frame's entity-component-system (ECS) pattern is tailored for 3D and VR applications. What React did for 2D web applications is what ECS did for 3D applications in terms of providing a useful abstraction. ECS promotes composability over hierarchy. In 3D applications, composability refers to composition of appearance, behavior, and logic rather than having fixed blocks. This lets us do things like define a flying robot that explodes on contact and makes robot sounds by snapping together a pre-existing model component, explode component, event handler component, sound component, and flying component.

Unfortunately, React (and the 2D web for that matter) is heavily hierarchical, which is not suited for 3D. Whereas 2D web development consisted of structuring and laying out from an assorted set of fixed 2D elements (e.g., <p>, <a>, <img>, <form>), 3D development involves objects that are infinite in complexity and type. ECS provides an easy way of defining those objects by mixing and matching plug-and-play components.

With aframe-react, we get the best of both worlds. The 3D and VR architecture of A-Frame, and the view and state ergonomics of React. React can be used to bind application and state data to the values of A-Frame components. And we still have access to all the features and performance of A-Frame as well as A-Frame's community component ecosystem.

API

aframe-react's API is very thin on top of A-Frame, less than 200 lines of source code. The API consists of just two React Components: <Entity/> and <Scene/>.

<Entity {...components}/>

<Entity/> wraps <a-entity>, the entity piece of the entity-component-system pattern. Plug in A-Frame components as React props to attach appearance, behavior, or functionality to the <Entity/>.

<Scene>
  <Entity
    geometry={{primitive: 'box', width: 5}}
    material={{color: red, roughness: 0.5, src: texture.png}}
    scale={{x: 2, y: 2, z: 2}}
    position={{x: 0, y: 0, z: -5}}/>
</Scene>

Community A-Frame components can be imported and installed through npm:

import 'aframe-particle-system-component';
import 'aframe-mountain-component';

// ...

<Scene>
  <Entity mountain/>
  <Entity particle-system={{preset: 'snow', particleCount: 5000}}/>
</Scene>

primitive

To use A-Frame primitives, provide the primitive prop with the primitive's element name (e.g., a-sphere). Mappings can be applied the same as in HTML through React props:

<Entity primitive='a-box' color="red" position="0 0 -5"/>
<Entity primitive='a-sphere' color="green" position="-2 0 -3"/>
<Entity primitive='a-cylinder' color="blue" position="2 0 -3"/>
<Entity primitive='a-sky' src="sechelt.jpg"/>

events

To register event handlers, use the events prop. events takes a mapping of event names to event handler(s). Multiple event handlers can be provided for a single event name by providing an array of functions. Try not to pass in inline functions to not trigger unnecessary React renders. Pass in binded functions instead.

For example, using the synthetic click event provided by A-Frame's cursor component, or a collided event possibly provided by a physics component.

handleClick = () => {
  console.log('Clicked!');
}

handleCollide = () => {
  console.log('Collided!');
}

render() {
  return (
    <Scene>
      <Entity events={{
        click: this.handleClick,
        collided: [this.handleCollide]}}/>
    </Scene>
  );
}

aframe-react does not support React-style onXXX event handlers (e.g., onClick). Unlike 2D web pages, VR sites are composed entirely of custom synthetic event names (which could have hyphens, be all lowercase, be camelCase, all uppercase, camel case, etc.,). The possible event names are infinite. The events prop makes it explicit what the event names to handle are.

_ref

Use aframe-react's _ref prop to add a callback to the underlying <a-entity> DOM node:

<Entity _ref={this.entityCallback}/>

<Scene {...components}/>

<Scene/> extends <Entity/> and renders <a-scene> instead of <a-entity>. Place all <Entity/>s as a child of the <Scene/> Component. There should only be one <Scene/> per page:

<Scene>
  <Entity/>
</Scene>

Best Practices

Let A-Frame and three.js handle the heavy lifting of 3D rendering and behavior, and delegate React to what it was meant for: views, state management, and data binding.

For example, don't create requestAnimationFrames to continuously throw React prop updates to A-Frame. Instead, create an A-Frame component with a tick handler such that everything is done in memory with little overhead. Do however use React to set up initial state and data binding that might configure that A-Frame component.

Using with Preact

aframe-react works with Preact. Since aframe-react uses React.Component, we have to tell Webpack to alias that to Preact.Component:

resolve: {
  alias: {
    react: 'preact'
  }
}

aframe-react's People

Contributors

atj1979 avatar calrk avatar davesnx avatar fouad avatar ip avatar jesstelford avatar jhsu avatar jonasfj avatar jsantell avatar liubinyi avatar ltfschoen avatar mayognaise avatar meatwallace avatar meta-meta avatar michaltakac avatar mokargas avatar naeramarth7 avatar ngokevin avatar nikgraf avatar robinnorth avatar rspace avatar vincentdesmares avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aframe-react's Issues

How to create own mouse-control component

Hello! I'm try to work some mouse look component but have a problem.
(component: https://github.com/alexrkass/no-click-look-controls)
When i try get canvas element i have undefined. but a-scene i get it perfectly.

var sceneEl = this.el.sceneEl;
var canvasEl = sceneEl.canvas;
console.log(canvasEl,sceneEl);

in react component i have:

              <Scene className="aframebox" embedded={true} >
                <a-entity  camera no-click-look-controls="maxyaw:0.5ฯ€; maxpitch:0.2ฯ€;" ></a-entity>
                <a-sky src="images/city.jpg" rotation="0 -130 0"></a-sky>
              </Scene>

image

Thank u for any help!

What is the recommended way to load and use ply models?

I seem to not be able to get a simple PLY model loaded up. This is one of the stock models that comes with MagicaVoxel. My network traffic shows the file getting loaded. It does indeed appear to be downloaded correctly by the browser, but no rendering occurs. Aframe inspector shows that an entity does indeed exist.

First I import extras like this: import 'aframe-extras';

Then I added my model as an asset

<a-assets>
          <a-asset-item id="castle" src="/assets/castle.bake.ply"></a-asset-item>
</a-assets>

Finally I add it to the scene, using Entity

<Entity plyModel="src: #castle" rotation="-90 0 0" position="0 0 0" />

Any obvious issues here?

Removed props are not being actually removed

For example, if I remove "geometry" prop from an Entity element, aframe-react doesn't call removeAttribute and the geometry stays. This seems to be an easy fix, or am I missing something?

Canvas invisible on second render

Apologies for submitting a very custom issue that likely is not the fault of aframe-react, but I could really use a second pair of eyes on this. I've built a small example of switching between a normal html/css rendering and an aframe rendering of the same data using aframe-react starting from the boilerplate.

The example is running here: http://immersionftw.com/meetup-vr/
The code is here: https://github.com/RSpace/aframe-meetup-example

If you:

  1. Switch to "VR mode" by clicking the button
  2. Switch back to "2d mode" by looking down and clicking the red sphere with the cursor
  3. Switch to "VR mode" once again by clicking the button

... you will see that the canvas is not shown the second time "VR mode" is entered. By profiling the canvas in Firefox it is clear that the canvas is indeed rendered the second time, so it might be something as simple as a styling issue. But I just can't figure out why it's different the second, and if the problem is on my code, aframe-react or aframe-core.

Any ideas?

Some components cannot be used until React Component is mounted

When adding a raycaster and cursor component (to represent an <a-cursor>) to an entity, the element gets created before mounted to the DOM, causing the raycaster component's this.el.sceneEl to be undefined (as it has yet to be mounted), throwing an error and causing the scene to fail to render. A work around is to wait until the component is mounted to DOM and then adding more components, but this took some time to figure out. Similar to assumptions in #50 of when things are mounted and initialized, I wonder if there's a general way of handling this for all components.

import React, { Component, PropTypes } from 'react';
import { Entity } from 'aframe-react';

class CameraComponent extends Component {
  constructor() {
    super();
    this.state = {
      mounted: false,
    };
  }

  componentDidMount() {
    this.setState({ mounted: true });
  }

  render() {
    const mountedProps = {};

    if (this.state.mounted) {
      mountedProps.cursor = 'maxDistance: 100; fuse: true; fuseTimeout: 1000'
    };

    return (
      <Entity id='camera-container' {...this.props}>
        <Entity camera>
          <Entity
            {...mountedProps}
            raycaster='objects: .action'    
            geometry='primitive: plane'>
          </Entity>
        </Entity>
      </Entity>
    );
  }
};

export default CameraComponent;

Dynamically adding Entities sometimes results in invisible Entities

To recreate this bug, pull my repo here: https://github.com/cakenggt/bonsai/tree/block-missing-bug then do npm install and npm start and you can view the display on localhost:4000

To start out with, you will probably want to move back from the scene by holding down s. Every time you click in the scene, a new block is supposed to be attached to the existing tree (don't click on the existing blocks for this test, as multiple blocks get added when you do that due to some other bug). Pretty reliably, a few clicks in, you will see some of the already-added blocks disappear, which should not happen as Entities are only being added.

If you then go into aframe inspector with ctrl+alt+i, you can see the entity tree looks like this

block-bug

Notice that some of the Entities, particularly the highlighted one in the picture, have no geometry or material. However, in the react plugin for chrome, they appear to have been added normally with the correct material and geometry components.

I am unsure what the problem is, and have tried to condense the code down in that bug branch so that all of the necessary code is in app/components/treeView.jsx

peerDependency: 'aframe'

Hello @ngokevin

As I talked in the #issues channel on Slack and as I said here: #62

Could be a good idea to make a-frame as a peerDependency of aframe-react?
I open a issue instead of a PR in case there's some reason that I don't know about!

Thanks!

Primitives turn into geometry={{primitive:box}} when updating any geometry attribute with react state

Hi,
I'm working on a small aframe-react app where I need to update different geometry attributes via react state (like this: geometry={{ width: this.state.width }}).

When I'm using the geometry.primitive property everything works as expected, but when I'm using Primitives or the aframe-react-components module, all aframe-primitives are getting updated to geometry={{ primitive: 'box' }} when I update the react state.

This works as expected:

<Entity
  geometry={{ primitive: 'plane', width: this.state.width, height: '2' }}
  material={{color: 'blue' }}
  position='-4 -1.5 -8'
  onClick={this.changeWidth.bind(this)} />

This works onload, but when I update this.state.width the geometry.primitive of the <a-plane />-Element changes to 'box'

<Entity
   primitive='a-plane'
   geometry={{ width: this.state.width, height: '2' }}
   material={{color: 'blue' }}
   position='-4 2.5 -8'
   onClick={this.changeWidth.bind(this)} />

I used the aframe-react-boilerplate to build a basic demo of the bug. The upper row uses aframe Primitives, the lower row uses the geometry.primitive property. Live Demo with v0.4.0 (Code)

onload after this.setState({})
before-state-update after-state-update

Merge component props when overridden.

For example:

const material = {color: 'red', side: 'double'}
<Entity material={{metalness: 1, roughness: 0}} {...material}/>

That should combine all the material component properties together. Currently, the second instance of material will overwrite the first one.

Do not discard non-component properties when using primitives

Hacking on a short hand library for using aframe react's primitives in aframe-react-components. Essentially mapping:

<Sphere radius={5} />
to
<Entity primitive='a-sphere' radius={5} />
which should map to
<a-sphere radius='5' />

But currently, the short hand properties provided by primitives are discarded, requiring a user to define with the full component mapping, like <Entity primitive='a-sphere' geometry={{ radius: 5 }} />.

Is it possible to know these mappings for stock primitives? Dug around a bit, and couldn't seem to find a way to expose these via the AFRAME global. Still new to aframe-react, so I might be missing something, but if this sounds good (and it's possible to get these mappings), I'll work on a PR

Pass array or object as position instead of "0 1 -5"?

I'm wondering if you have any strong opinions on how this should work. It's inconvenient to have to convert a Vector3 into a string that a-frame can work with. Should this be handled by aframe-react? Or should this be some external utility function? Likewise for rotation and scale, maybe even color: convert RGB to Hex?

I currently do this:

let {x,y,z} = someVectorObject
position={`${x} ${y} ${z}`}

would be nice to be able to do this:

position={someVectorObject}

and/or

position={[x, y, z]}

<Entity> implicitly expects React to be defined

This code:

import {Entity} from 'aframe-react'
import {Component} from 'react'

class Avatars extends Component {
  render () {
    return (
      <Entity>
      </Entity>
    );
  }
}

results in this error: Uncaught ReferenceError: React is not defined in the line where it tries to render <Entity>. Seems like this component implicitly expects React to be imported be the parent component, as changing line 2 to import React, {Component} from 'react' fixes the problem.

But that shouldn't really be necessary, should it?

Remove props passed with null

It would be nice, if the Entity component filters received props to exclude null values and instead uses to the default A-Frame value. IMHO this would more conform with the way React handles null values.

This would also make it simpler to add default props passed to entities. For example:

class Camera extends Component {
  static defaultProps = {
    position: null,
  };

  render() {
    const { position } = this.props;

    const camera = {
      userHeight: 1.6,
    };

    return (
      <Entity
        position={position}
        camera={camera}
        look-controls
      />
    );
  }
}

At the moment this produces the following error at https://github.com/ngokevin/aframe-react/blob/master/src/index.js#L104:
Uncaught TypeError: Cannot read property 'constructor' of null

With a okay from you @ngokevin I could build a small PR for this.

Event Cleanup

I might be missing something fundamental here, but can you explain to me how event handlers are cleaned up in this lib?

core:schema:warn about component/system 'undefined' when using <a-primitives>

I get that the gist of aframe-react is that we're not supposed to be using stuff like <a-sphere> in lieu of always using the <Entity> component. But being able to call <a-sphere> A) saves a lot of typing, and B) seems to work.

I figured the problem would be that React has patchy support for custom attributes, but as it turns out:

<Scene embedded>
   <a-sphere position="0 0 -15" color="red" radius="1"/>
</Scene>

renders perfectly fine. The only problem I get are these warning in the console:

core:schema:warn Unknown property `color` for component/system `undefined`. +2ms
core:schema:warn Unknown property `radius` for component/system `undefined`. +3ms

I don't think I've run into any other issues besides that, so far. But what are these warnings about? They don't show up when I build my spheres with <Entity>

Issue with text-component not being rendered

Hello, Im trying to put some text on my aframe-react project but the following:

<Entity bmfont-text={{text: 'HELLO WORLD'}} position="{[0, 1, -5]}"/>

Does nothing... I have the components imported as necessary and I dont receive any errors.. it just does not render. I have also tried this with the standard text-component as part of kframe. Same result.

Detach Events

We need a way to remove the events that get attached to the element.

            <Entity
                onMouseEnter={this.onMouseEnter}
                onMouseLeave={this.onMouseLeave}
                onClick={this.onClick}
                >

PropTypes deprecated warnings with React 15.5.0

Hi, any plan to fix the warning with React 15.5.0:

Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead

https://facebook.github.io/react/blog/2017/04/07/react-v15.5.0.html

In 15.5, instead of accessing PropTypes from the main React object, install the prop-types package and import them from there:

// Before (15.4 and below)
import React from 'react';

class Component extends React.Component {
  render() {
    return <div>{this.props.text}</div>;
  }
}

Component.propTypes = {
  text: React.PropTypes.string.isRequired,
}

// After (15.5)
import React from 'react';
import PropTypes from 'prop-types';

class Component extends React.Component {
  render() {
    return <div>{this.props.text}</div>;
  }
}

Component.propTypes = {
  text: PropTypes.string.isRequired,
};

Not wrapping render return value in <Entity> makes entire aframe rendering fail silently

I'm making a few stupid, yet time consuming, mistakes with aframe-react. One of them is this code:

import { Component } from 'react'
import Avatar from '../components/Avatar'

class Avatars extends Component {
  render () {
    let members = this.props.members
    return (
      <div>
        {members.map(member => {
          return <Avatar key={member.id} id={member.id} name={member.name} photoUrl={member.photo_url}/>
        })}
      </div>
    )
  }
}

It works when I replace my stupid <div></div> wrapper with <Entity></Entity>, but with the code above, I got nothing rendered at all, and no error. It would be really nice with an exception explaining the problem and how to fix it.

a-collada-model - model does not appear

I'm trying to run the "Anime UI" example from aframe on aframe-react, but I'm unable to load engine.dae. It just does not appear.

My Scene contains the following code:

<a-assets>
  <a-asset-item id="engine" src="models/engine.dae" />
</a-assets>

<Entity primitive="a-entity" position="1.75 0 1.2" rotation="0 28 0">
  <Entity primitive="a-camera" near="0.1" user-height="0" />
</Entity>

<Entity primitive="a-entity" position="0 0 -3">
  <Entity primitive="a-collada-model" src="#engine" rotation="90 0 0" scale="18 18 18" />
</Entity>

Can anyone please tell me what I'm doing wrong and why the model is not appearing.

Thanks!

Stop animations

Doing some testing with this and was not able to stop an animation by removing it from the DOM.

  onEnter(){
    this.setState({animate:true});
  },
  onExit(){
    this.setState({animate:false});
  },
  render() {
    let animate = this.state && this.state.animate ? (<Animation attribute="rotation" dur="5000" to="0 360 360"/>) : false;
... 
          <Entity onMouseEnter={this.onEnter} onMouseLeave={this.onExit} geometry={{primitive: 'box'}} material="color: red" position="0 0 -5">
            {animate}
          </Entity>.... ```

Aframe using lots of memory.

CODE: https://github.com/itsakt/aframe-react-test

App.js

Memory Usage
This sample code contains five 360 degree images. ( ~600KB - ~1.8MB, 8192x4096 )

Initial memory usage:
Google Chrome
chrome initial

Firefox Developer Edition
ff initial

After switching through five images
Google Chrome
chrome after five

Firefox Developer Edition
ff after five

My actual project has 24 images

After switching through 24 images
Google Chrome after 20 images (chrome tab crashed after that)
chrome after 24

Firefox Developer Edition after 24 images.
ff after 24

EDIT: Memory usage also increases if I reload the page.

Incorrect check for non-entity prop names

The check for which entity prop names to skip calling setAttribute on is currently broken in v4.0.2, resulting in entities with children having children="[object Object]" attributes set on them, amongst other things.

The indexOf check in

function doSetAttributes (el, props) {
  // Set attributes.
  const nonEntityPropNames = ['children', 'events', 'primitive'];
  Object.keys(props).filter(
    propName => propName.indexOf(nonEntityPropNames) === -1
  ).forEach(propName => { doSetAttribute(el, props, propName); });
}

needs to be reversed.

I'll submit a pull request to fix this soon.

Idea: React Native component

Main purpose is to bring aframe to native apps and download assets into local storage.

Combining three.js/webgl with react native is not a new idea at all.
https://discuss.reactjs.org/t/webgl-in-react-native/2123
https://github.com/ProjectSeptemberInc/gl-react-native
http://jlongster.com/First-Impressions-using-React-Native
http://stackoverflow.com/questions/37167090/react-native-and-three-js-webgl-library-integration

I think aframe-reactnative would a great approach to connect to native device api and resolve the large assets long loading time issue.

@ngokevin Any suggestion?

Performance

I like the concept of the type of coding patterns that aframe-react allows us to use in defining 3D scenes,

but it seems like there is a performance concern: props (f.e. position) can be passed to the React components as arrays of numbers, which get converted into strings to be passed into the custom elements, which get converted back into numbers for use internally by A-Frame/Three.js.

That 3-step conversion will happen on every tick while animating a component's prop like position repeatedly.

Is it something to be concerned about? How do you recommend handling animations?

<Entity> turns into a blue 1x1x1 box when React re-renders it (unknown circumstances)

When my React app re-renders some of my components, some of the <Entities> seem to lose their geometry, turning into 1x1x1 boxes. They also turn blue, for some reason.

I'm unclear on the exact circumstances, but these entities always reside deep in the component hierarchy and possibly have events bound to them.

I've managed to jury rig together an example of this happening by stripping down my app as much as possible, but you'll sadly need to jump through some hoops:

  1. Open https://world-vufbpyzwci.now.sh/
  2. Use the sticky cursor to click on the lone white hex and wait a sec.
  3. You should now see a green box surrounded by white hexes. Click one of the hexes.
  4. The white hexes on the opposite side of where you clicked should turn into blue boxes.

This is an early build of a hex-based game. What's happening is that the green box is moving onto the hex you clicked, meaning React is:

  • Mounting new hexes (now white) in the direction you clicked
  • Unmounting some of the hexes in the opposite direction (now invisible)
  • Re-rendering the rest of the hexes (now blue boxes)

If you open the A-Frame inspector, you can see all mounted hexes with IDs like clickable-thing-x-y. And here's the source of the React component containing the hex <Entity>: https://github.com/jonikorpi/world/blob/blue-box-debugging/components/Action.js#L162

I've had this issue for months but haven't filed an issue since I can't pinpoint what makes it occur. Let me know if I can do anything else to help figure this out.

P.S. This issue could be related? #57

Raycaster events not triggered on second render

I just updated my A-Frame app's aframe-react version from 3.5.0 to 4.2.4. I believe I have made all the changes required from the upgrade (events, vector properties, _ref), although the lack of a changelog makes it hard to say exactly.

I have everything working as it did before I updated aframe-react, except for one thing: I have a menu that can be toggled on and off. The menu is initially visible, and initially raycaster events such as click and mouseover work fine. However, when I toggle the menu off and on again the raycaster events are no longer triggered in 4.2.4. If I roll back to 3.5.0 - all other code and dependencies being equal - it works again.

I don't toggle the visibility of the menu being setting the visible property. Instead I pass a prop to the React component rendering the menu telling it whether it should render or not. If the prop is true, the component returns an <Entity>, if it is false, it returns null. This setup is due to a number factors, related to how I use Redux to manage state and use of animations.

For performance reasons I have the configured the raycaster to only intersect with specific elements:

         <Entity
            primitive="a-cursor"
            raycaster='objects: .interactable'
          />

If I remove raycaster='objects: .interactable', the menu works every time, but I get worse performance.

I have reproduced the issue here:
https://www.webpackbin.com/bins/-KkkMiVwnvG9MVsuq0us

The box toggles a sphere (a stand-in for the menu in my actual code). The first time the sphere is shown, it changes color when clicked. Once it has been hidden and is shown again, it no longer changes color.

From debugging, it seems like the Three.js raycaster simply doesn't match the sphere on subsequent renders. I just can't figure out how any of changes made in aframe-react affects this. It doesn't seem to be related to the changes event system, since the problem is the same if I manually attach event handlers to the element. Rather, it seems like the intersected elements are somehow cached, or like the className is not properly included on subsequent renders.

But I have nothing solid, just this example reproducing the issue above. Any help would be appreciated.

Interop with DOM components

Hey @ngokevin, what do you think of some API like:

render () {
  return <Scene>
    <Entity>
      <div>
        Hello World
      </div>
    </Entity>
  </Scene>;
}

I'd be rather excited to do this if you can point me in the right direction. I'm not totally sure of the perf impact (the current method of blending WebGL and HTML seems to be a CSS trick), but might be fun

it looks like React is already adding the correct DOM to the tree, just need to make the aframe entity aware of the children.

screen shot 2015-12-22 at 3 20 13 pm

I have some intuition on how to do this:

  1. Create a new aframe component based on the boilerplate
  2. The aframe component is basially an aframe plane
  3. we create a THREE.CSS3DObject in update(), bound to the plane's position and rotation, using the first child DOM element (which is what React creates for us)

that sound right? any gotchas I'm missing?

Main source of inspiration is this comment and [the linked post](http://learningthreejs.com/blog/2013/04/30/closing-the-gap-between-html-and-webgl/

Add support for animations

Currently, there's no support for this in aframe-react and going back to 'a-animation' tag doesn't work well either because there's no setAttribute/removeAttribute for dynamic props.

The distribute version is on the repo?

Hey @ngokevin

I open this because I saw a user complaining about master being not syncronized with npm.
The potentiall issue could be that master is bug-free meanwhile the registry could have some bug (related with a-asset-items or others...) If it's true.

For now I only can see that there's no diff between

diff
https://raw.githubusercontent.com/ngokevin/aframe-react/master/dist/index.js
vs
https://unpkg.com/[email protected]

unpkg is a cdn of the npm registry

Well... going back to the issue, I would like to have the dist out of the repo basically for have the distribute version in a CDN and atomic (be able to re-create the dist version), as well we would have cleaner PRs.

I can see the benefit of having the dist in the repo as a shareable URL, but since there's options like unpkg, we can provide this URLs as a direct asset.

Thanks!
PS: I didn't express very well on this issue :(

Invoke .emit() on a ref for Animation?

As from the docs, following this pattern:

<Entity ref="box" geometry="primitive: box" material="opacity: 1">
  <Animation attribute="material.opacity" begin="fade" to="2 2 2" />
</Entity>
this.refs.box.emit("fade");
Uncaught TypeError: _this.refs.box.emit is not a function

How does one properly implement this?

Enable composability while using components.

Would like to be able to create something like:

<Light type="directional"/>

while still being able to mix in arbitrary components:

<Light type="directional" geometry="primitive: sphere" material={sphereColor}/>

Can do this by having a React component that detects a main schema and expanding the properties of the schema onto the main component, and then applying the rest of the components as attributes.

<a-entity light="{lightSchemaProperties}" {...otherComponents}>

Update to react v15.3.0?

I'm getting UNMET PEER DEPENDENCY when trying to use with the latest react.

are there any breaking changes that would make it not work with newest react?

I'll try to bump versions and see for myself, can PR if I get it to work

Is it possible to render Sky Entity with image ?

I know Sky entity can be rendered like below:
<Entity geometry={{primitive: 'sphere', radius: 5000}} material={{color: props.color || '#73CFF0', shader: 'flat', src: '#sky'}} scale="1 1 -1"/>

But when I tried to render image instead of color, the image is not rendered.
<Entity geometry={{primitive: 'sphere', radius: 5000}} material={{ src: "./skyimage.png" }} scale="1 1 -1"/>

I wonder if it is possible to render Sky Entity with image using aframe-react.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.