geildanke.com @fischaelameer
MICHAELA LEHR
Founder · Geil,Danke! · Frontend Developer, UX Designer
@fischaelameer
Goodbye, Flatland!
An introduction to React VR
and what it means for web developers
geildanke.com @fischaelameer
You should care about WebVR.
geildanke.com @fischaelameer
VR Concepts
geildanke.com @fischaelameer
VR Concepts ReactVR
geildanke.com @fischaelameer
VR Concepts ReactVR UX Design & VR
geildanke.com @fischaelameer
Virtual Reality is tricking our eyes and
brain to think of a 2D image to be in 3D.
geildanke.com @fischaelameer
Virtual Reality changes the 

way we relate to technology.
geildanke.com @fischaelameer
Virtual Reality Concepts
geildanke.com @fischaelameer
Stereoscopic Images
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
IPD – Interpupillary distance
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
Tracking
geildanke.com @fischaelameer
geildanke.com @fischaelameer
Rotation
geildanke.com @fischaelameer
Rotation
Position
geildanke.com @fischaelameer
geildanke.com @fischaelameer
Rotation
Position
geildanke.com @fischaelameer
Browser
https://github.com/mrdoob/three.js
geildanke.com @fischaelameer
Browser
WebGL
https://github.com/mrdoob/three.js
geildanke.com @fischaelameer
Browser
WebVRWebGL
https://github.com/mrdoob/three.js
geildanke.com @fischaelameer
Browser
WebVRWebGL
https://github.com/mrdoob/three.js
three.js
Ricardo Cabello
geildanke.com @fischaelameer
Browser
WebVRWebGL
https://facebookincubator.github.io/react-vr/index.html
three.js
ReactVR
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
x: 0, y: 0, z: 0
geildanke.com @fischaelameer
x: 0, y: 0, z: 0
geildanke.com @fischaelameer
geildanke.com @fischaelameer
npm install -g react-vr-cli
react-vr init GEILDANKE_REACTVR_PANO
cd GEILDANKE_REACTVR_PANORAMA
npm start
geildanke.com @fischaelameer
/GEILDANKE_REACTVR_PANO
!"" index.vr.js
!"" node_modules
!"" package.json
!"" postinstall.js
!"" rn-cli.config.js
!"" static_assets
#   %"" vr-mountain.jpg
%"" vr
!"" client.js
%"" index.html
geildanke.com @fischaelameer
import React from 'react';
import { AppRegistry, asset, Pano, View } from 'react-vr';
class GEILDANKE_REACTVR_PANO extends React.Component {
render() {
return (
<View>
<Pano source = { asset('vr-mountain.jpg') }/>
</View>
);
}
};
AppRegistry.registerComponent('GEILDANKE_REACTVR_PANO', () => GEILDANKE_REACTVR_PANO);
index.vr.js
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
It was the pioneer days; people had to make their own interrogation rooms. Out of
cornmeal. These endless days are finally ending in a blaze. When I say, 'I love you,'
it's not because I want you or because I can't have you. It's my estimation that every
man ever got a statue made of him was one kind of sommbitch or another. Oh my god you
will never believe what happened at school today. From beneath you, it devours. I am
never gonna see a merman, ever.
It was supposed to confuse him, but it just made him peppy. It was like the Heimlich,
with stripes! How did your brain even learn human speech? I'm just so curious.
Apocalypse, we've all been there; the same old trips, why should we care? Frankly, it's
ludicrous to have these interlocking bodies and not...interlock. I just don't see why
everyone's always picking on Marie-Antoinette. You're the one freaky thing in my freaky
world that still makes sense to me. You are talking crazy-person talk.
http://www.commercekitchen.com/whedon-ipsum/
geildanke.com @fischaelameer
It was the pioneer days; people had to make their own interrogation rooms. Out of
cornmeal. These endless days are finally ending in a blaze. When I say, 'I love you,'
it's not because I want you or because I can't have you. It's my estimation that every
man ever got a statue made of him was one kind of sommbitch or another. Oh my god you
will never believe what happened at school today. From beneath you, it devours. I am
never gonna see a merman, ever.
It was supposed to confuse him, but it just made him peppy. It was like the Heimlich,
with stripes! How did your brain even learn human speech? I'm just so curious.
Apocalypse, we've all been there; the same old trips, why should we care? Frankly, it's
ludicrous to have these interlocking bodies and not...interlock. I just don't see why
everyone's always picking on Marie-Antoinette. You're the one freaky thing in my freaky
world that still makes sense to me. You are talking crazy-person talk.
http://www.commercekitchen.com/whedon-ipsum/
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
Goodbye, UX metaphors!
geildanke.com @fischaelameer
Goodbye, UX metaphors!
geildanke.com @fischaelameer
Goodbye, UX metaphors!
geildanke.com @fischaelameer
Lightning
UI
Button
GalleryImages
GalleryImage
Room
Wall
index.vr.js
geildanke.com @fischaelameer
import React from 'react';
import { AppRegistry, asset, View } from 'react-vr';
import Images from './Images';
import Lightning from './Lightning';
import Room from './Room';
import UI from './UI';
import World from './World';
class GEILDANKE_REACTVR_GALLERY extends React.Component {
render() {
return (
<View>
<Lightning />
<World />
<Room />
<Images />
<UI />
</View>
);
}
};
AppRegistry.registerComponent('GEILDANKE_REACTVR_GALLERY', () => GEILDANKE_REACTVR_GALLERY);
index.vr.js
geildanke.com @fischaelameer
import React from 'react';
import { AmbientLight, PointLight, View } from 'react-vr';
class Lightning extends React.Component {
render() {
return(
<View>
<AmbientLight intensity = { 1.2 } />
<PointLight intensity = { 0.25 }
style = {{
color: '#ffffff',
transform: [{ translate : [ 0, 4, 0.25 ] }] }} />
</View>
);
}
}
module.exports = Lightning;
Lightning.js
geildanke.com @fischaelameer
import React from 'react';
import { AmbientLight, PointLight, View } from 'react-vr';
class Lightning extends React.Component {
render() {
return(
<View>
<AmbientLight intensity = { 1.2 } />
<PointLight intensity = { 0.25 }
style = {{
color: '#ffffff',
transform: [{ translate : [ 0, 4, 0.25 ] }] }} />
</View>
);
}
}
module.exports = Lightning;
Lightning.js
geildanke.com @fischaelameer
import React from 'react';
import { AmbientLight, PointLight, View } from 'react-vr';
class Lightning extends React.Component {
render() {
return(
<View>
<AmbientLight intensity = { 1.2 } />
<PointLight intensity = { 0.25 }
style = {{
color: '#ffffff',
transform: [{ translate : [ 0, 4, 0.25 ] }] }} />
</View>
);
}
}
module.exports = Lightning;
Lightning.js
geildanke.com @fischaelameer
…
render() {
let scale = this.props.scale,
translate = this.props.translate,
wall = null,
wallMat = {mesh:asset('wall.obj'), mtl:asset('wall.mtl'), lit: true},
windowMat = {mesh:asset('window.obj'), mtl:asset('window.mtl'), lit: true};
if (this.props.hasWindow && this.props.hasWindow === true) {
wall = <Mesh style={{transform: [{translate: translate}, {scale: scale},],}} source={windowMat} />;
} else {
wall = <Mesh style={{transform: [{translate: translate}, {scale: scale},],}} source={wallMat} />;
}
return (
wall
);
}
…
Wall.js
geildanke.com @fischaelameer
…
import Wall from './Wall';
class Room extends React.Component {
render() {
return(
<View>
<Wall scale={[5, 0.2, 10]} translate={[0, -2.9, -5.02]} />
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
<Wall hasWindow scale={[5, 3, 0.02]} translate={[0, 0, 4.98]} />
<Wall hasWindow scale={[0.02, 3, 10]} translate={[-5.02, 0, -5.02]} />
<Wall hasWindow scale={[0.02, 3, 10]} translate={[5.02, 0, -5.02]} />
</View>
);
}
}
…
Room.js
geildanke.com @fischaelameer
…
import Wall from './Wall';
class Room extends React.Component {
render() {
return(
<View>
<Wall scale={[5, 0.2, 10]} translate={[0, -2.9, -5.02]} />
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
<Wall hasWindow scale={[5, 3, 0.02]} translate={[0, 0, 4.98]} />
<Wall hasWindow scale={[0.02, 3, 10]} translate={[-5.02, 0, -5.02]} />
<Wall hasWindow scale={[0.02, 3, 10]} translate={[5.02, 0, -5.02]} />
</View>
);
}
}
…
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
Room.js
geildanke.com @fischaelameer
…
import Wall from './Wall';
class Room extends React.Component {
render() {
return(
<View>
<Wall scale={[5, 0.2, 10]} translate={[0, -2.9, -5.02]} />
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
<Wall hasWindow scale={[5, 3, 0.02]} translate={[0, 0, 4.98]} />
<Wall hasWindow scale={[0.02, 3, 10]} translate={[-5.02, 0, -5.02]} />
<Wall hasWindow scale={[0.02, 3, 10]} translate={[5.02, 0, -5.02]} />
</View>
);
}
}
…
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
Room.js
geildanke.com @fischaelameer
…
import Wall from './Wall';
class Room extends React.Component {
render() {
return(
<View>
<Wall scale={[5, 0.2, 10]} translate={[0, -2.9, -5.02]} />
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
<Wall hasWindow scale={[5, 3, 0.02]} translate={[0, 0, 4.98]} />
<Wall hasWindow scale={[0.02, 3, 10]} translate={[-5.02, 0, -5.02]} />
<Wall hasWindow scale={[0.02, 3, 10]} translate={[5.02, 0, -5.02]} />
</View>
);
}
}
…
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
Room.js
geildanke.com @fischaelameer
x
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
geildanke.com @fischaelameer
y
x
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
geildanke.com @fischaelameer
y
x
z
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
geildanke.com @fischaelameer
y
x
z
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
geildanke.com @fischaelameer
y
x
z 1 unit = 1 meter
1
1
1
<Wall scale={[5, 3, 0.2]} translate={[0, 0, -5]} />
geildanke.com @fischaelameer
3D Coordinate System, Units & Scaling
Flexbox Layout
Animations (Animated API)
React VR Components
geildanke.com @fischaelameer
3D Coordinate System, Units & Scaling
Flexbox Layout
Animations (Animated API)
React VR Components
geildanke.com @fischaelameer
…
let texture = this.props.texture,
imageWidth = this.props.width;
<Image
style={{
margin: 0.05,
width: imageWidth,
height: imageWidth,
}}
source={texture}
/>
…
GalleryImage.js
geildanke.com @fischaelameer
…
for (let i = 0; i < iMax; i += 1) {
images.push(
<GalleryImage
key={i}
texture={config[i].texture}
index={i}
length={this.numberOfImages}
width={this.imageWidth} />
);
}
…
GalleryImages.js
geildanke.com @fischaelameer
…
for (let i = 0; i < iMax; i += 1) {
images.push(
<GalleryImage
key={i}
texture={config[i].texture}
index={i}
length={this.numberOfImages}
width={this.imageWidth} />
);
}
…
…
<View>
{images}
</View>
…
GalleryImages.js
geildanke.com @fischaelameer
…
for (let i = 0; i < iMax; i += 1) {
images.push(
<GalleryImage
key={i}
texture={config[i].texture}
index={i}
length={this.numberOfImages}
width={this.imageWidth} />
);
}
…
…
<View
style={{
flexDirection: 'row',
}}
>
{images}
</View>
…
GalleryImages.js
geildanke.com @fischaelameer
geildanke.com @fischaelameer
3D Coordinate System, Units & Scaling
Flexbox Layout
Animations (Animated API)
React VR Components
geildanke.com @fischaelameer
3D Coordinate System, Units & Scaling
Flexbox Layout
Animations (Animated API)
React VR Components
geildanke.com @fischaelameer
GalleryImages.js
…
class GalleryImages extends React.Component {
constructor(props) {
super();
this.state = {
scrollValue: new Animated.Value(0),
};
}
componentWillMount() {
Animated.timing(
this.state.scrollValue,
{
toValue: 60,
duration: 2000,
easing: Easing.linear,
}
).start();
}
…
geildanke.com @fischaelameer
GalleryImages.js
…
class GalleryImages extends React.Component {
constructor(props) {
super();
this.state = {
scrollValue: new Animated.Value(0),
};
}
componentWillMount() {
Animated.timing(
this.state.scrollValue,
{
toValue: 60,
duration: 2000,
easing: Easing.linear,
}
).start();
}
…
…
<Animated.View
style={{
flexDirection: 'row',
transform: [
{translateX: this.state.scrollValue},
],
}}
>
{images}
</Animated.View>
…
geildanke.com @fischaelameer
3D Coordinate System, Units & Scaling
Flexbox Layout
Animations (Animated API)
React VR Components
geildanke.com @fischaelameer
View
Image
Core Components
Pano
Mesh
React VR Components
AmbientLight, PointLight,
geildanke.com @fischaelameer
View
Image
Text
Core Components
Pano
Mesh
React VR Components
AmbientLight, PointLight,
geildanke.com @fischaelameer
View
Image
Text
Core Components
Pano
Mesh
React VR Components
AmbientLight, PointLight,
DirectionalLight, SpotLight
geildanke.com @fischaelameer
View
Image
Text
Core Components
Pano
Mesh
React VR Components
VrButton
AmbientLight, PointLight,
DirectionalLight, SpotLight
geildanke.com @fischaelameer
View
Image
Text
Core Components
Pano
Mesh
React VR Components
VrButton
AmbientLight, PointLight,
DirectionalLight, SpotLight
Sound
geildanke.com @fischaelameer
UX Design for VR
geildanke.com @fischaelameer
Comfort
Interpretability
Usefulness
Delight
Beau Cronin
https://medium.com/@beaucronin/the-hierarchy-of-needs-in-virtual-reality-development-4333a4833acc
geildanke.com @fischaelameer
Presence
Comfort
Interpretability
Usefulness
Delight
Beau Cronin
https://medium.com/@beaucronin/the-hierarchy-of-needs-in-virtual-reality-development-4333a4833acc
geildanke.com @fischaelameer
Ergonomics
geildanke.com @fischaelameer
It was the pioneer days; people had to make their own interrogation rooms. Out of
cornmeal. These endless days are finally ending in a blaze. When I say, 'I love you,'
it's not because I want you or because I can't have you. It's my estimation that every
man ever got a statue made of him was one kind of sommbitch or another. Oh my god you
will never believe what happened at school today. From beneath you, it devours. I am
never gonna see a merman, ever.
It was supposed to confuse him, but it just made him peppy. It was like the Heimlich,
with stripes! How did your brain even learn human speech? I'm just so curious.
Apocalypse, we've all been there; the same old trips, why should we care? Frankly, it's
ludicrous to have these interlocking bodies and not...interlock. I just don't see why
everyone's always picking on Marie-Antoinette. You're the one freaky thing in my freaky
world that still makes sense to me. You are talking crazy-person talk.
http://www.commercekitchen.com/whedon-ipsum/
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
70°
geildanke.com @fischaelameer
130°
Comfortably bending 30° to each side
geildanke.com @fischaelameer
230°
Stretching 80° to each side
https://www.youtube.com/watch?v=00vzW2-PvvE
geildanke.com @fischaelameer
0.5m
20m
https://www.youtube.com/watch?v=00vzW2-PvvE
geildanke.com @fischaelameer
~20px
~10ppd
< 20px
60ppd
geildanke.com @fischaelameer
avoid eyestrain: use darker colors
avoid focussing on different depths
do not trigger phobias
use correct scales
do not move things fast towards the camera
do not attach things near the camera
make the user comfortable
geildanke.com @fischaelameer
avoid eyestrain: use darker colors
avoid focussing on different depths
do not trigger phobias
use correct scales
do not move things fast towards the camera
do not attach things near the camera
make the user comfortable
geildanke.com @fischaelameer
avoid eyestrain: use darker colors
avoid focussing on different depths
do not trigger phobias
use correct scales
do not move things fast towards the camera
do not attach things near the camera
make the user comfortable
geildanke.com @fischaelameer
avoid eyestrain: use darker colors
avoid focussing on different depths
do not trigger phobias
use correct scales
do not move things fast towards the camera
do not attach things near the camera
make the user comfortable
geildanke.com @fischaelameer
avoid eyestrain: use darker colors
avoid focussing on different depths
do not trigger phobias
use correct scales
do not move things fast towards the camera
do not attach things near the camera
make the user comfortable
geildanke.com @fischaelameer
avoid eyestrain: use darker colors
avoid focussing on different depths
do not trigger phobias
use correct scales
do not move things fast towards the camera
do not attach things near the camera
make the user comfortable
geildanke.com @fischaelameerIcon made by Freepik from www.flaticon.com
geildanke.com @fischaelameerIcon made by Freepik from www.flaticon.com
geildanke.com @fischaelameer
geildanke.com @fischaelameer
geildanke.com @fischaelameer
no acceleration
do not move the horizon or the camera
always keep a low latency and a high frame rate
avoid flicker and blur
add a stable focus point
support short usage
abstract design is better than realistic
do not make your users sick!
geildanke.com @fischaelameer
no acceleration
do not move the horizon or the camera
always keep a low latency and a high frame rate
avoid flicker and blur
add a stable focus point
support short usage
abstract design is better than realistic
do not make your users sick!
geildanke.com @fischaelameer
no acceleration
do not move the horizon or the camera
always keep a low latency and a high frame rate
avoid flicker and blur
add a stable focus point
support short usage
abstract design is better than realistic
do not make your users sick!
geildanke.com @fischaelameer
no acceleration
do not move the horizon or the camera
always keep a low latency and a high frame rate
avoid flicker and blur
add a stable focus point
support short usage
abstract design is better than realistic
do not make your users sick!
geildanke.com @fischaelameer
no acceleration
do not move the horizon or the camera
always keep a low latency and a high frame rate
avoid flicker and blur
add a stable focus point
support short usage
abstract design is better than realistic
do not make your users sick!
geildanke.com @fischaelameer
no acceleration
do not move the horizon or the camera
always keep a low latency and a high frame rate
avoid flicker and blur
add a stable focus point
support short usage
abstract design is better than realistic
do not make your users sick!
geildanke.com @fischaelameer
no acceleration
do not move the horizon or the camera
always keep a low latency and a high frame rate
avoid flicker and blur
add a stable focus point
support short usage
abstract design is better than realistic
do not make your users sick!
geildanke.com @fischaelameer
You are responsible for the 

well-being of your users!
geildanke.com @fischaelameer
http://www.uxofvr.com/
https://iswebvrready.org/
General information
https://webvr-slack.herokuapp.com/
https://www.reddit.com/r/reactvr/
Community
https://www.reddit.com/r/WebVR/
https://w3c.github.io/webvr/
https://github.com/googlevr/webvr-polyfill
https://threejs.org/
API, frameworks, libraries
https://facebookincubator.github.io/react-vr/index.html
https://facebookincubator.github.io/react-vr/docs/getting-started.html
https://github.com/facebookincubator/react-vr
geildanke.com @fischaelameer
https://geildanke.com/en/vr
Thank you!
@fischaelameer

Goodbye, Flatland! An introduction to React VR and what it means for web developers