master 0398b735bdc1 cached
51 files
157.6 KB
41.1k tokens
148 symbols
1 requests
Download .txt
Repository: toxicFork/react-three-renderer-example
Branch: master
Commit: 0398b735bdc1
Files: 51
Total size: 157.6 KB

Directory structure:
gitextract_5jlez6np/

├── .eslintrc
├── .gitignore
├── .gitmodules
├── CONTRIBUTORS.md
├── README.md
├── assets/
│   ├── advanced.html
│   └── index.html
├── config/
│   ├── webpackCommonsChunkPluginConfig.js
│   └── webpackPluginsWithoutUglify.js
├── gulpfile.babel.js
├── package.json
├── src/
│   ├── examples/
│   │   ├── AdvancedExample/
│   │   │   ├── AdvancedComponent.js
│   │   │   └── index.js
│   │   ├── AnimationCloth/
│   │   │   ├── Cloth.js
│   │   │   ├── ClothGeometry.jsx
│   │   │   ├── Info.js
│   │   │   ├── Poles.js
│   │   │   ├── Sphere.js
│   │   │   ├── StaticWorld.js
│   │   │   ├── index.js
│   │   │   ├── index.jsx
│   │   │   └── shaders/
│   │   │       ├── depth.frag
│   │   │       └── depth.vert
│   │   ├── Benchmark/
│   │   │   ├── RotatingCube.js
│   │   │   ├── RotatingCubes.js
│   │   │   └── RotatingCubesDirectUpdates.js
│   │   ├── DraggableCubes/
│   │   │   ├── AllCubes.js
│   │   │   ├── DraggableCube.js
│   │   │   └── index.js
│   │   ├── ExampleBase.js
│   │   ├── ExampleBrowser.js
│   │   ├── ExampleViewer.js
│   │   ├── Geometries/
│   │   │   └── index.js
│   │   ├── GeometryShapes/
│   │   │   ├── Rect.js
│   │   │   ├── Resources.js
│   │   │   ├── Shape.js
│   │   │   ├── Shapes.js
│   │   │   └── index.js
│   │   ├── ManualRendering/
│   │   │   ├── Info.js
│   │   │   └── index.js
│   │   ├── Physics/
│   │   │   ├── index.js
│   │   │   ├── mousePick/
│   │   │   │   └── PickableMesh.js
│   │   │   └── mousePick.js
│   │   ├── Simple/
│   │   │   └── index.js
│   │   ├── WebGLCameraExample/
│   │   │   ├── Info.js
│   │   │   ├── PointCloud.js
│   │   │   └── index.js
│   │   └── inputs/
│   │       └── MouseInput.js
│   ├── index.jsx
│   └── ref/
│       └── trackball.js
└── webpack.config.babel.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc
================================================
// Use this file as a starting point for your project's .eslintrc.
// Copy this file, and add rule overrides as needed.
{
  "extends": "airbnb",
  "parser": "babel-eslint",
  "rules": {
    "id-length": 0,
    "no-bitwise": "off",
    "no-underscore-dangle": 0,
    "linebreak-style": "off",
    "no-mixed-operators": "off",
    "no-plusplus": [
      0
    ],
    "no-param-reassign": [
      2,
      {
        "props": false
      }
    ]
  }
}


================================================
FILE: .gitignore
================================================
/node_modules
.idea/dictionaries/
.idea/uiDesigner.xml
.idea/


================================================
FILE: .gitmodules
================================================
[submodule "pages"]
	path = pages
	url = git@github.com:toxicFork/react-three-renderer-example.git
	branch = gh-pages


================================================
FILE: CONTRIBUTORS.md
================================================
* [@toxicFork](https://github.com/toxicFork)
 * Original Author
* [@vkammerer](https://github.com/vkammerer)
 * Added installation instructions


================================================
FILE: README.md
================================================
react-three-renderer-example
============================

Examples for [react-three-renderer](https://github.com/toxicFork/react-three-renderer).

https://toxicfork.github.com/react-three-renderer-example/

#### Installation
``
npm install
``
#### Local server
``
npm start
``

Then visit [http://localhost:8080](http://localhost:8080) on your favorite webgl-enabled browser :)


================================================
FILE: assets/advanced.html
================================================
<!doctype html>
<html>
<head>
    <style>
        @font-face {
            font-family: 'inconsolata';
            src: url('files/inconsolata.woff') format('woff');
            font-weight: normal;
            font-style: normal;
        }

        * {
            box-sizing: border-box;
        }

        html {
            height: 100%;
        }

        body {
            background-color: #ffffff;
            margin: 0px;
            height: 100%;
            color: #555;
            font-family: 'inconsolata';
            font-size: 15px;
            line-height: 18px;
            overflow: hidden;
        }

        h1 {
            margin-top: 30px;
            margin-bottom: 40px;
            margin-left: 20px;
            font-size: 25px;
            font-weight: normal;
        }

        h2 {
            font-size: 20px;
            font-weight: normal;
        }

        a {
            color: #2194CE;
            text-decoration: none;
        }

        #panel {
            position: fixed;
            left: 0px;
            width: 310px;
            height: 100%;
            overflow: auto;
            background: #fafafa;
        }

        #panel #content {
            padding: 0px 20px;
        }

        #panel #content .link {
            color: #2194CE;
            text-decoration: none;
            cursor: pointer;
        }

        #panel #content .selected {
            color: #ff0000;
        }

        #panel #content .link:hover {
            text-decoration: underline;
        }

        #viewer {
            position: absolute;
            border: 0px;
            left: 310px;
            width: calc(100% - 310px);
            height: 100%;
            overflow: hidden;
        }

        #button {
            position: fixed;
            bottom: 20px;
            right: 20px;
            padding: 8px;
            color: #fff;
            background-color: #555;
            opacity: 0.7;
        }

        #button:hover {
            cursor: pointer;
            opacity: 1;
        }

        /* mobile */

        #expandButton {
            display: none;
            position: absolute;
            right: 20px;
            top: 12px;
            width: 32px;
            height: 32px;
        }

        #expandButton span {
            height: 2px;
            background-color: #2194CE;
            width: 16px;
            position: absolute;
            left: 8px;
            top: 10px;
        }

        #expandButton span:nth-child(1) {
            top: 16px;
        }

        #expandButton span:nth-child(2) {
            top: 22px;
        }

        @media all and ( max-width: 640px ) {
            h1 {
                margin-top: 20px;
                margin-bottom: 20px;
            }

            #panel {
                position: absolute;
                left: 0;
                top: 0;
                height: 480px;
                width: 100%;
                right: 0;
                z-index: 100;
                overflow: hidden;
                border-bottom: 1px solid #dedede;
            }

            #content {
                position: absolute;
                left: 0;
                top: 60px;
                right: 0;
                bottom: 0;
                font-size: 17px;
                line-height: 22px;
                overflow: auto;
            }

            #viewer {
                position: absolute;
                left: 0;
                top: 56px;
                width: 100%;
                height: calc(100% - 56px);
                overflow: hidden,
            }

            #expandButton {
                display: block;
            }

            #panel.collapsed {
                height: 56px;
            }
        }
    </style>
</head>
<body>
<div>
    <div style="padding: 20px;">
        <canvas id="canvas" width="800" height="600"></canvas>

        <br/>
        <br/>

        <a href="https://github.com/toxicFork/react-three-renderer-example/blob/master/src/examples/AdvancedExample/index.js">View
            Source</a>
    </div>
</div>
</body>
<script type="text/javascript" charset="utf-8" src="js/bundle-commons.js"></script>
<script type="text/javascript" charset="utf-8" src="js/bundle-advanced.js"></script>
<script type="text/javascript">
    var sc_project = 10775601;
    var sc_invisible = 1;
    var sc_security = "74e09d45";
    var sc_https = 1;
    var sc_remove_link = 1;
    var scJsHost = (("https:" == document.location.protocol) ?
            "https://secure." : "http://www.");
    document.write("<sc" + "ript type='text/javascript' src='" +
            scJsHost +
            "statcounter.com/counter/counter.js'></" + "script>");
</script>
<noscript>
    <div class="statcounter"><img class="statcounter"
                                  src="http://c.statcounter.com/10775601/0/74e09d45/1/"
                                  alt="stats"></div>
</noscript>
</html>


================================================
FILE: assets/index.html
================================================
<!doctype html>
<html>
<head>
    <style>
        @font-face {
            font-family: 'inconsolata';
            src: url('files/inconsolata.woff') format('woff');
            font-weight: normal;
            font-style: normal;
        }

        * {
            box-sizing: border-box;
        }

        html {
            height: 100%;
        }

        body {
            background-color: #ffffff;
            margin: 0px;
            height: 100%;
            color: #555;
            font-family: 'inconsolata';
            font-size: 15px;
            line-height: 18px;
            overflow: hidden;
        }

        h1 {
            margin-top: 30px;
            margin-bottom: 40px;
            margin-left: 20px;
            font-size: 25px;
            font-weight: normal;
        }

        h2 {
            font-size: 20px;
            font-weight: normal;
        }

        a {
            color: #2194CE;
            text-decoration: none;
        }

        #panel {
            position: fixed;
            left: 0px;
            width: 310px;
            height: 100%;
            overflow: auto;
            background: #fafafa;
        }

        #panel #content {
            padding: 0px 20px;
        }

        #panel #content .link {
            color: #2194CE;
            display: block;
            text-decoration: none;
            cursor: pointer;
        }

        #panel #content .selected {
            color: #ff0000;
        }

        #panel #content .link:hover {
            text-decoration: underline;
        }

        #viewer {
            position: absolute;
            border: 0px;
            left: 310px;
            width: calc(100% - 310px);
            height: 100%;
            overflow: hidden;
        }

        #button {
            position: fixed;
            bottom: 20px;
            right: 20px;
            padding: 8px;
            color: #fff;
            background-color: #555;
            opacity: 0.7;
        }

        #button:hover {
            cursor: pointer;
            opacity: 1;
        }

        /* mobile */

        #expandButton {
            display: none;
            position: absolute;
            right: 20px;
            top: 12px;
            width: 32px;
            height: 32px;
        }

        #expandButton span {
            height: 2px;
            background-color: #2194CE;
            width: 16px;
            position: absolute;
            left: 8px;
            top: 10px;
        }

        #expandButton span:nth-child(1) {
            top: 16px;
        }

        #expandButton span:nth-child(2) {
            top: 22px;
        }

        @media all and ( max-width: 640px ) {
            h1 {
                margin-top: 20px;
                margin-bottom: 20px;
            }

            #panel {
                position: absolute;
                left: 0;
                top: 0;
                height: 480px;
                width: 100%;
                right: 0;
                z-index: 100;
                overflow: hidden;
                border-bottom: 1px solid #dedede;
            }

            #content {
                position: absolute;
                left: 0;
                top: 60px;
                right: 0;
                bottom: 0;
                font-size: 17px;
                line-height: 22px;
                overflow: auto;
            }

            #viewer {
                position: absolute;
                left: 0;
                top: 56px;
                width: 100%;
                height: calc(100% - 56px);
                overflow: hidden,
            }

            #expandButton {
                display: block;
            }

            #panel.collapsed {
                height: 56px;
            }
        }
    </style>
</head>
<body>
<div id="content"></div>
</body>
<script type="text/javascript" charset="utf-8" src="js/bundle-commons.js"></script>
<script type="text/javascript" charset="utf-8" src="js/bundle-app.js"></script>
<script type="text/javascript">
    var sc_project = 10775601;
    var sc_invisible = 1;
    var sc_security = "74e09d45";
    var sc_https = 1;
    var sc_remove_link = 1;
    var scJsHost = (("https:" == document.location.protocol) ?
            "https://secure." : "http://www.");
    document.write("<sc" + "ript type='text/javascript' src='" +
            scJsHost +
            "statcounter.com/counter/counter.js'></" + "script>");
</script>
<noscript>
    <div class="statcounter"><img class="statcounter"
                                  src="http://c.statcounter.com/10775601/0/74e09d45/1/"
                                  alt="stats"></div>
</noscript>
</html>


================================================
FILE: config/webpackCommonsChunkPluginConfig.js
================================================
/* eslint-disable import/no-extraneous-dependencies */

import webpack from 'webpack';
import path from 'path';

// noinspection WebpackConfigHighlighting
module.exports = new webpack.optimize.CommonsChunkPlugin(
  {
    name: 'common',
    filename: path.join('js', 'bundle-commons.js'),
  });


================================================
FILE: config/webpackPluginsWithoutUglify.js
================================================
/* eslint-disable import/no-extraneous-dependencies */

import webpack from 'webpack';

import commonsChunkPluginConfig from './webpackCommonsChunkPluginConfig';

// noinspection WebpackConfigHighlighting
module.exports = [
  new webpack.DefinePlugin({
    'process.env': {
      NODE_ENV: '"production"',
    },
  }),
  commonsChunkPluginConfig,
];


================================================
FILE: gulpfile.babel.js
================================================
/* eslint-disable import/no-extraneous-dependencies */

import gulp from 'gulp';
import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';
import gutil from 'gulp-util';
import path from 'path';
import runSequence from 'run-sequence';
import del from 'del';

import webpackConfig from './webpack.config.babel';
import pluginsWithoutUglify from './config/webpackPluginsWithoutUglify';
import webpackCommonsChunkPluginConfig from './config/webpackCommonsChunkPluginConfig';

const cache = {};

const config = {
  prod: false,
  addon: false,
  noEval: false,
};

webpackConfig.output.devtoolModuleFilenameTemplate = info =>
  `wp:///${path.relative(__dirname, info.resourcePath)}`;

webpackConfig.output.devtoolFallbackModuleFilenameTemplate = info =>
  `wp:///${path.relative(__dirname, info.resourcePath)}?${info.hash}`;

require('webpack/lib/ModuleFilenameHelpers').createFooter = () => '';

// pretend it's prod ( still has sourcemaps )
// slowest compilation
gulp.task('webpack-dev-server-prod', () => {
  config.prod = true;
  config.addon = true;

  runSequence('webpack-dev-server');
});

// no eval, faster runtime, slower compilation
gulp.task('webpack-dev-server-no-eval', () => {
  config.noEval = true;

  runSequence('webpack-dev-server');
});

// fast compilation, low runtime performance
gulp.task('webpack-dev-server', () => {
  const host = '0.0.0.0';
  const port = 8080;

  webpackConfig.cache = cache;

  webpackConfig.entry.app = [
    `webpack-dev-server/client?http://${host}:${port}`, // WebpackDevServer host and port
    'webpack/hot/only-dev-server', // "only" prevents reload on syntax errors
  ].concat(webpackConfig.entry.app);

  webpackConfig.entry.advanced = [
    `webpack-dev-server/client?http://${host}:${port}`, // WebpackDevServer host and port
    'webpack/hot/only-dev-server', // "only" prevents reload on syntax errors
  ].concat(webpackConfig.entry.advanced);

  webpackConfig.module.loaders.forEach((loader) => {
    if (loader.loader === 'babel-loader') {
      loader.query.plugins.push('react-hot-loader/babel');
    }
  });

  if (config.prod) {
    webpackConfig.devtool = 'source-map';
  } else if (config.noEval) {
    webpackConfig.devtool = 'cheap-module-source-map';
  } else {
    webpackConfig.devtool = 'eval-cheap-module-source-map';
  }

  webpackConfig.plugins = [
    new webpack.HotModuleReplacementPlugin(),
    webpackCommonsChunkPluginConfig,
  ];

  if (config.prod) {
    webpackConfig.plugins.unshift(
      new webpack.DefinePlugin({
        'process.env': {
          NODE_ENV: '"production"',
          ENABLE_REACT_ADDON_HOOKS: config.addon ? '"true"' : '"false"',
        },
      }));

    webpackConfig.plugins.push(
      new webpack.optimize.UglifyJsPlugin({
        compress: {
          warnings: false,
        },
        mangle: true,
      }));
  }

  // Start a webpack-dev-server
  const compiler = webpack(webpackConfig);

  new WebpackDevServer(compiler, webpackConfig.devServer).listen(port, host, (err) => {
    if (err) {
      throw new gutil.PluginError('webpack-dev-server', err);
    }

    // Server listening
    gutil.log('[webpack-dev-server]', 'http://localhost:8080/webpack-dev-server/index.html');

    // keep the server alive or continue?
    // callback();
  });
});

// only enable addon integration, everything else in prod settings
gulp.task('build-prod-with-addon', (callback) => {
  webpackConfig.plugins.unshift(new webpack.DefinePlugin({
    'process.env': {
      ENABLE_REACT_ADDON_HOOKS: '"true"',
    },
  }));

  runSequence('build', callback);
});

// also adds sourceMaps too!
gulp.task('build-prod-with-addon-no-mangle', (callback) => {
  webpackConfig.devtool = 'source-map';

  webpackConfig.plugins = pluginsWithoutUglify.concat([
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false,
      },
      mangle: false,
    }),
  ]);

  runSequence('build-prod-with-addon', callback);
});

// build without production node env
gulp.task('build-dev', (callback) => {
  webpackConfig.plugins = [
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false,
      },
      mangle: true,
    }),
  ];

  runSequence('build', callback);
});

gulp.task('clean-pages', () => del('pages/**/!(.git|README.md)'));

gulp.task('copy-assets', () => gulp
  .src('assets/**/*')
  .pipe(gulp.dest('pages/')));

// just run webpack with default config (prod)
gulp.task('build', ['clean-pages'], (callback) => {
  webpack(webpackConfig, (err, stats) => {
    if (err) {
      throw new gutil.PluginError('webpack', err);
    }

    gutil.log('[webpack]', stats.toString({
      // output options
    }));

    runSequence('copy-assets', callback);
  });
});

gulp.task('default', ['webpack-dev-server']);


================================================
FILE: package.json
================================================
{
  "name": "react-three-renderer-example",
  "version": "1.0.0",
  "description": "An example showing how to use the react-three-renderer package",
  "main": "index.js",
  "scripts": {
    "start": "gulp webpack-dev-server",
    "eslint-internal": "eslint ./src/",
    "eslint": "npm run eslint-internal -loglevel silent || true",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "reactjs",
    "threejs",
    "renderer"
  ],
  "author": "Firtina \"toxicFork\" Ozbalikci",
  "license": "MIT",
  "dependencies": {
    "cannon": "^0.6.2",
    "history": "^4.6.3",
    "prop-types": "^15.5.10",
    "react": "^15.6.1",
    "react-dom": "^15.6.1",
    "react-router": "^4.1.2",
    "react-router-dom": "^4.1.2",
    "react-sizeme": "^2.3.4",
    "react-three-renderer": "^3.2.1",
    "stats.js": "^1.0.0",
    "three": "^0.86.0",
    "react-addons-perf": "^15.4.2"
  },
  "devDependencies": {
    "babel-eslint": "^7.1.1",
    "babel-cli": "^6.24.1",
    "babel-core": "^6.25.0",
    "babel-loader": "^7.1.1",
    "babel-plugin-transform-decorators-legacy": "^1.3.4",
    "eslint": "^3.11.1",
    "eslint-config-airbnb": "^13.0.0",
    "eslint-plugin-import": "^2.2.0",
    "eslint-plugin-jsx-a11y": "2.2.3",
    "eslint-plugin-react": "^6.7.1",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-polyfill": "^6.23.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "babel-runtime": "^6.25.0",
    "gulp": "^3.9.1",
    "gulp-babel": "^6.1.2",
    "gulp-util": "^3.0.8",
    "json-loader": "^0.5.7",
    "raw-loader": "^0.5.1",
    "react-hot-loader": "^3.0.0-beta.6",
    "run-sequence": "^2.1.0",
    "webpack": "^3.4.1",
    "webpack-dev-server": "^2.6.1",
    "del": "latest"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/toxicFork/react-three-renderer-example.git"
  },
  "bugs": {
    "url": "https://github.com/toxicFork/react-three-renderer-example/issues"
  },
  "babel": {
    "presets": [
      "es2015",
      "stage-0",
      "react"
    ],
    "plugins": [
      "transform-runtime",
      "transform-decorators-legacy"
    ]
  },
  "homepage": "https://github.com/toxicFork/react-three-renderer-example#readme"
}


================================================
FILE: src/examples/AdvancedExample/AdvancedComponent.js
================================================


================================================
FILE: src/examples/AdvancedExample/index.js
================================================
// see advanced.html :)

import React from 'react';
import React3Renderer from 'react-three-renderer/lib/React3Renderer';
import * as THREE from 'three';

// ^ Look mom, no react-dom!

const canvas = document.getElementById('canvas');

const react3Renderer = new React3Renderer();

const width = 800;
const height = 600;

const cameraPosition = new THREE.Vector3(0, 0, 5);

let cubeRotation = new THREE.Euler();

function onRecreateCanvas() {
  // no need to deal with this now, but here we'd need to create a new canvas and
  // re-render the scene there.
}

function animate() {
  cubeRotation = new THREE.Euler(
    cubeRotation.x + 0.1,
    cubeRotation.y + 0.1,
    0
  );

  react3Renderer.render(<react3
    width={width}
    height={height}

    onRecreateCanvas={onRecreateCanvas}

    context="3d"

    antialias
    mainCamera="camera"
  >
    <scene>
      <perspectiveCamera
        name="camera"
        fov={75}
        aspect={width / height}
        near={0.1}
        far={1000}

        position={cameraPosition}
      />
      <mesh
        rotation={cubeRotation}
      >
        <boxGeometry
          width={1}
          height={1}
          depth={1}
        />
        <meshBasicMaterial
          color={0xff0000}
        />
      </mesh>
    </scene>
  </react3>, canvas);

  requestAnimationFrame(animate);
}

animate();


================================================
FILE: src/examples/AnimationCloth/Cloth.js
================================================
/*
 * Cloth Simulation using a relaxed constrains solver
 */

// Suggested Readings

// Advanced Character Physics by Thomas Jakobsen Character
// http://freespace.virgin.net/hugo.elias/models/m_cloth.htm
// http://en.wikipedia.org/wiki/Cloth_modeling
// http://cg.alexandra.dk/tag/spring-mass-system/
// Real-time Cloth Animation http://www.darwin3d.com/gamedev/articles/col0599.pdf
import * as THREE from 'three';


function plane(width, height) {
  return (u, v) => {
    const x = (u - 0.5) * width;
    const y = (v + 0.5) * height;
    const z = 0;

    return new THREE.Vector3(x, y, z);
  };
}

const DAMPING = 0.03;
const DRAG = 1 - DAMPING;
const MASS = 0.1;
const restDistance = 25;

const xSegs = 10; //
const ySegs = 10; //

const clothFunction = plane(restDistance * xSegs, restDistance * ySegs);

class Particle {
  constructor(x, y, z, mass) {
    this.position = clothFunction(x, y); // position
    this.previous = clothFunction(x, y); // previous
    this.original = clothFunction(x, y);
    this.a = new THREE.Vector3(0, 0, 0); // acceleration
    this.mass = mass;
    this.invMass = 1 / mass;
    this.tmp = new THREE.Vector3();
    this.tmp2 = new THREE.Vector3();
  }

  // Force -> Acceleration
  addForce(force) {
    this.a.add(
      this.tmp2.copy(force).multiplyScalar(this.invMass),
    );
  }

  // Performs verlet integration
  integrate(timesQ) {
    const newPos = this.tmp.subVectors(this.position, this.previous);
    newPos.multiplyScalar(DRAG).add(this.position);
    newPos.add(this.a.multiplyScalar(timesQ));

    this.tmp = this.previous;
    this.previous = this.position;
    this.position = newPos;

    this.a.set(0, 0, 0);
  }
}

class Cloth {
  static clothFunction = clothFunction;
  static MASS = MASS;

  constructor(w = 10, h = 10) {
    this.w = w;
    this.h = h;

    const particles = [];
    const constrains = [];

    let u;
    let v;

    // Create particles
    for (v = 0; v <= h; ++v) {
      for (u = 0; u <= w; ++u) {
        particles.push(
          new Particle(u / w, v / h, 0, MASS),
        );
      }
    }

    function index(indexU, indexV) {
      return indexU + indexV * (w + 1);
    }

    // Structural

    for (v = 0; v < h; v++) {
      for (u = 0; u < w; u++) {
        constrains.push([
          particles[index(u, v)],
          particles[index(u, v + 1)],
          restDistance,
        ]);

        constrains.push([
          particles[index(u, v)],
          particles[index(u + 1, v)],
          restDistance,
        ]);
      }
    }

    for (u = w, v = 0; v < h; v++) {
      constrains.push([
        particles[index(u, v)],
        particles[index(u, v + 1)],
        restDistance,
      ]);
    }

    for (v = h, u = 0; u < w; u++) {
      constrains.push([
        particles[index(u, v)],
        particles[index(u + 1, v)],
        restDistance,
      ]);
    }


    this.particles = particles;
    this.constrains = constrains;

    this.index = index;
  }
}

export default Cloth;


================================================
FILE: src/examples/AnimationCloth/ClothGeometry.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';

import PureRenderMixin from 'react/lib/ReactComponentWithPureRenderMixin';

import Cloth from './Cloth';

class ClothGeometry extends React.Component {
  static propTypes = {
    cloth: PropTypes.instanceOf(Cloth).isRequired,
  };

  componentDidMount() {
    const geometry = this.geometry;

    geometry.computeFaceNormals();
  }

  _geometryRef = (geometry) => {
    this.geometry = geometry;
  };

  shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate;

  render() {
    const {
      cloth,
    } = this.props;

    return (<parametricGeometry
      ref={this._geometryRef}
      parametricFunction={Cloth.clothFunction}
      slices={cloth.w}
      stacks={cloth.h}
      dynamic
    />);
  }
}

export default ClothGeometry;


================================================
FILE: src/examples/AnimationCloth/Info.js
================================================
import React from 'react';

import PropTypes from 'prop-types';

class Info extends React.Component {
  static propTypes = {
    toggleWind: PropTypes.func.isRequired,
    toggleSphere: PropTypes.func.isRequired,
    togglePins: PropTypes.func.isRequired,
    toggleRotate: PropTypes.func.isRequired,
    onFrameChange: PropTypes.func.isRequired,
    minTimePerFrame: PropTypes.number.isRequired,
    rotating: PropTypes.bool.isRequired,
    winding: PropTypes.bool.isRequired,
    balling: PropTypes.bool.isRequired,
  };

  render() {
    const linkStyle = {
      textDecoration: 'underline',
      cursor: 'pointer',
    };

    const {
      toggleRotate,
      toggleWind,
      toggleSphere,
      togglePins,
      minTimePerFrame,
      onFrameChange,
      rotating,
      winding,
      balling,
    } = this.props;

    return (<div
      style={{
        textAlign: 'center',
        padding: 10,
        zIndex: 10,
        width: '100%',
        position: 'absolute',
        color: '#000',
      }}
    >
      <a
        href="http://threejs.org"
        style={{
          color: '#0080ff',
        }}
      >three.js</a> - Simple Cloth Simulation<br/>
      Verlet integration with Constrains relaxation<br/>
      Toggle: <a onClick={toggleRotate} style={linkStyle}>Camera{rotating ? '*' : null}</a> |
      <span> <a onClick={toggleWind} style={linkStyle}>Wind{winding ? '*' : null}</a></span> |
      <span> <a onClick={toggleSphere} style={linkStyle}>Ball{balling ? '*' : null}</a></span> |
      <span> <a onClick={togglePins} style={linkStyle}>Pins</a></span> |
      <span> Time between frames (ms): <input
        onChange={onFrameChange}
        value={minTimePerFrame}
        type="number"
        style={{ width: 40 }}
        min="0"
      /> </span>
      <br/>
      <span>Note: add some time between frames (e.g. 60ms)
        if you would like to inspect the scene through
        react devtools, because updating every frame kills the addon.</span>
    </div>);
  }
}

export default Info;


================================================
FILE: src/examples/AnimationCloth/Poles.js
================================================
import React from 'react';

import * as THREE from 'three';

import PureRenderMixin from 'react/lib/ReactComponentWithPureRenderMixin';

class Poles extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      poleMaterialColor: Number(0xffffff).toString(16),
      poleMaterialSpecular: Number(0x111111).toString(16),
      poleMaterialShininess: 100,
      sidePolePositions: [
        new THREE.Vector3(-125, -62, 0),
        new THREE.Vector3(125, -62, 0),
      ],
      boxPositions: [
        new THREE.Vector3(125, -250, 0),
        new THREE.Vector3(-125, -250, 0),
      ],
      topPolePosition: new THREE.Vector3(0, -250 + 750 / 2, 0),
      subResource: false,
    };
  }

  shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate;

  render() {
    return (<object3D>
      <resources>
        <boxGeometry
          resourceId="poleGeometry"
          width={5}
          height={375}
          depth={5}
        />
        <boxGeometry
          resourceId="boxGeometry"
          width={10}
          height={10}
          depth={10}
        />
        <meshPhongMaterial
          resourceId="poleMaterial"
          color={Number.parseInt(this.state.poleMaterialColor, 16)}
          specular={Number.parseInt(this.state.poleMaterialSpecular, 16)}
          shininess={this.state.poleMaterialShininess}
        />
      </resources>
      {this.state.sidePolePositions.map((position, i) =>
        (<mesh
          key={i}
          position={position}
          receiveShadow
          castShadow
        >
          <geometryResource
            resourceId="poleGeometry"
          />
          <materialResource
            resourceId="poleMaterial"
          />
        </mesh>))}
      <mesh
        position={this.state.topPolePosition}
        receiveShadow
        castShadow
      >
        <boxGeometry
          width={255}
          height={5}
          depth={5}
        />
        <materialResource
          resourceId="poleMaterial"
        />
      </mesh>
      <object3D>
        { this.state.subResource ? <resources>
          {this.state.subResource ? <meshPhongMaterial
            resourceId="poleMaterial"
            color={0x00ff00}
            specular={0x111111}
            shininess={100}
          /> : null}
          {
            <sphereGeometry
              resourceId="boxGeometry"
              radius={20}
            /> }
        </resources> : null }
        {this.state.boxPositions.map((position, i) =>
          (<mesh
            key={i}
            position={position}
            receiveShadow
            castShadow
          >
            <geometryResource
              resourceId="boxGeometry"
            />
            <materialResource
              resourceId="poleMaterial"
            />
          </mesh>))}
      </object3D>
    </object3D>);
  }
}

export default Poles;


================================================
FILE: src/examples/AnimationCloth/Sphere.js
================================================
import React from 'react';

import * as THREE from 'three';

import PureRenderMixin from 'react/lib/ReactComponentWithPureRenderMixin';

import PropTypes from 'prop-types';

const ballSize = 60; // 40

class Sphere extends React.Component {
  static propTypes = {
    visible: PropTypes.bool.isRequired,
    position: PropTypes.instanceOf(THREE.Vector3).isRequired,
  };

  constructor(props, context) {
    super(props, context);

    this.state = {
      color: '0xaaaaaa',
    };
  }

  shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate;

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

    return (<mesh
      castShadow
      receiveShadow
      visible={visible}
      position={position}
    >
      <sphereGeometry
        radius={ballSize}
        widthSegments={20}
        heightSegments={20}
      />
      <meshPhongMaterial
        color={Number.parseInt(this.state.color, 16)}
      />
    </mesh>);
  }
}

export default Sphere;


================================================
FILE: src/examples/AnimationCloth/StaticWorld.js
================================================
import React from 'react';
import * as THREE from 'three';
import PropTypes from 'prop-types';

import PureRenderMixin from 'react/lib/ReactComponentWithPureRenderMixin';

import fragmentShaderDepth from 'raw-loader!./shaders/depth.frag';
import vertexShaderDepth from 'raw-loader!./shaders/depth.vert';

import ClothGeometry from './ClothGeometry';
import Poles from './Poles';
import Cloth from './Cloth';


class StaticWorld extends React.Component {
  static propTypes = {
    clothRef: PropTypes.func.isRequired,
    cloth: PropTypes.instanceOf(Cloth).isRequired,
  };

  constructor(props, context) {
    super(props, context);

    this.directionalLightPosition = new THREE.Vector3(50, 200, 100).multiplyScalar(1.3);
    this.lightTarget = new THREE.Vector3(0, 0, 0);
    this.groundPosition = new THREE.Vector3(0, -250, 0);
    this.groundRotation = new THREE.Euler(-Math.PI / 2, 0, 0);
    this.groundRepeat = new THREE.Vector2(25, 25);

    this.state = {
      ambientLightColor: '666666',
      directionalLightColor: 'dfebff',
      fragmentShaderDepth,
      vertexShaderDepth,
    };

    // check if HMR is enabled
    if (module.hot) {
      // accept update of dependency
      module.hot.accept('raw-loader!./shaders/depth.frag', () => {
        this.setState({
          fragmentShaderDepth: require('raw-loader!./shaders/depth.frag'),
        });
      });

      module.hot.accept('raw-loader!./shaders/depth.vert', () => {
        this.setState({
          vertexShaderDepth: require('raw-loader!./shaders/depth.vert'),
        });
      });
    }
  }

  shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate;

  render() {
    const shadowCameraSize = 300;

    const {
      ambientLightColor,
      directionalLightColor,
      fragmentShaderDepth: frag,
      vertexShaderDepth: vert,
      } = this.state;

    return (<object3D>
      <resources>
        <texture
          url="textures/patterns/circuit_pattern.png"
          wrapS={THREE.RepeatWrapping}
          wrapT={THREE.RepeatWrapping}
          anisotropy={16}
          resourceId="clothTexture"
        />
      </resources>
      <ambientLight
        color={Number.parseInt(ambientLightColor, 16)}
      />
      <directionalLight
        color={Number.parseInt(directionalLightColor, 16)}
        intensity={1.75}
        position={this.directionalLightPosition}
        lookAt={this.lightTarget}
        castShadow
        shadowMapWidth={1024}
        shadowMapHeight={1024}
        shadowCameraLeft={-shadowCameraSize}
        shadowCameraRight={shadowCameraSize}
        shadowCameraTop={shadowCameraSize}
        shadowCameraBottom={-shadowCameraSize}
        shadowCameraFar={1000}
      />
      <mesh
        castShadow
        receiveShadow
      >
        <ClothGeometry
          ref={this.props.clothRef}
          cloth={this.props.cloth}
        />
        <meshPhongMaterial
          alphaTest={0.5}
          color={0xffffff}
          specular={0x030303}
          emissive={0x111111}
          shininess={10}
          side={THREE.DoubleSide}
        >
          <textureResource
            resourceId="clothTexture"
          />
        </meshPhongMaterial>
        <shaderMaterial
          slot="customDepthMaterial"
          fragmentShader={frag}
          vertexShader={vert}
        >
          <uniforms>
            <uniform
              name="texture"
              type="t"
            >
              <textureResource
                resourceId="clothTexture"
              />
            </uniform>
          </uniforms>
        </shaderMaterial>
      </mesh>
      { /* <arrowHelper
       direction={this.arrowDirection}
       origin={this.arrowOrigin}
       length={this.arrowLength}
       color={0xff0000}
       position={this.arrowPosition}
       /> */ }
      <mesh
        position={this.groundPosition}
        rotation={this.groundRotation}
        receiveShadow
      >
        <planeBufferGeometry
          width={20000}
          height={20000}
        />
        <meshPhongMaterial
          color={0xffffff}
          specular={0x111111}
        >
          <texture
            url="textures/terrain/grasslight-big.jpg"
            wrapS={THREE.RepeatWrapping}
            wrapT={THREE.RepeatWrapping}
            repeat={this.groundRepeat}
            anisotropy={16}
          />
        </meshPhongMaterial>
      </mesh>
      <Poles/>
    </object3D>);
  }
}

export default StaticWorld;


================================================
FILE: src/examples/AnimationCloth/index.js
================================================
import jsx from './index.jsx';

module.exports = jsx;

================================================
FILE: src/examples/AnimationCloth/index.jsx
================================================
import React from 'react';
import * as THREE from 'three';
import Stats from 'stats.js';

import React3 from 'react-three-renderer';

import ExampleBase from '../ExampleBase';

import Info from './Info';

import Cloth from './Cloth';
import StaticWorld from './StaticWorld';
import Sphere from './Sphere';

import TrackballControls from '../../ref/trackball';

const ballSize = 60; // 40

const GRAVITY = 981 * 1.4; //
const gravity = new THREE.Vector3(0, -GRAVITY, 0).multiplyScalar(Cloth.MASS);

const TIMESTEP = 18 / 1000;
const TIMESTEP_SQ = TIMESTEP * TIMESTEP;

const diff = new THREE.Vector3();


function satisfyConstrains(p1, p2, distance) {
  diff.subVectors(p2.position, p1.position);
  const currentDist = diff.length();
  if (currentDist === 0) {
    return;
  } // prevents division by 0
  const correction = diff.multiplyScalar(1 - distance / currentDist);
  const correctionHalf = correction.multiplyScalar(0.5);
  p1.position.add(correctionHalf);
  p2.position.sub(correctionHalf);
}

const tmpForce = new THREE.Vector3();

class AnimationCloth extends ExampleBase {
  constructor(props, context) {
    super(props, context);

    this.state = {
      ...this.state,
      minTimePerFrame: 0,
      rotate: true,
      wind: true,
      sphere: false,
    };

    const xSegs = 10; //
    const ySegs = 10; //

    this.cloth = new Cloth(xSegs, ySegs);

    const pinsFormation = [];
    let pins = [6];

    pinsFormation.push(pins);

    pins = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    pinsFormation.push(pins);

    pins = [0];
    pinsFormation.push(pins);

    pins = []; // cut the rope ;)
    pinsFormation.push(pins);

    pins = [0, this.cloth.w]; // classic 2 pins
    pinsFormation.push(pins);

    pins = pinsFormation[1];

    this.pins = pins;
    this.pinsFormation = pinsFormation;

    this.fog = new THREE.Fog(0xcce0ff, 500, 10000);

    this.windForce = new THREE.Vector3(0, 0, 0);

    this.state = {
      ...this.state,
      ballPosition: new THREE.Vector3(0, -45, 0),
      cameraPosition: new THREE.Vector3(0, 50, 1500),
    };

    this.scenePosition = new THREE.Vector3(0, 0, 0);
  }

  componentDidMount() {
    const controls = new TrackballControls(
      this.mainCamera, this.react3);
    controls.rotateSpeed = 1.0;
    controls.zoomSpeed = 1.2;
    controls.panSpeed = 0.8;

    controls.noZoom = false;
    controls.noPan = false;

    controls.staticMoving = true;
    controls.dynamicDampingFactor = 0.3;

    controls.addEventListener('change', () => {
      this.setState({
        cameraPosition: this.mainCamera.position,
      });
    });

    this.controls = controls;

    this.stats = new Stats();

    this.stats.domElement.style.position = 'absolute';
    this.stats.domElement.style.top = '0px';

    this.container.appendChild(this.stats.domElement);
  }

  componentWillUnmount() {
    delete this.stats;
    this.controls.dispose();
    delete this.controls;
  }

  _toggleRotate = () => {
    this.setState({ rotate: !this.state.rotate });
  };

  _toggleWind = () => {
    this.setState({ wind: !this.state.wind });
  };

  _toggleSphere = () => {
    this.setState({ sphere: !this.state.sphere });
  };

  _togglePins = () => {
    this.pins = this.pinsFormation[~~(Math.random() * this.pinsFormation.length)];
  };

  _simulate(time) {
    if (!this.lastTime) {
      this.lastTime = time;
      return;
    }

    let i;
    let il;
    let particles;
    let particle;
    let constrain;

    const clothGeometry = React3.findTHREEObject(this._clothGeometry);

    const sphere = React3.findTHREEObject(this.sphere);

    // Aerodynamics forces
    if (this.state.wind) {
      let face;
      const faces = clothGeometry.faces;
      let normal;

      particles = this.cloth.particles;

      for (i = 0, il = faces.length; i < il; i++) {
        face = faces[i];
        normal = face.normal;

        tmpForce.copy(normal).normalize().multiplyScalar(normal.dot(this.windForce));
        particles[face.a].addForce(tmpForce);
        particles[face.b].addForce(tmpForce);
        particles[face.c].addForce(tmpForce);
      }
    }

    for (particles = this.cloth.particles, i = 0, il = particles.length; i < il; i++) {
      particle = particles[i];
      particle.addForce(gravity);

      particle.integrate(TIMESTEP_SQ);
    }

    // Start Constrains

    const constrains = this.cloth.constrains;
    il = constrains.length;

    for (i = 0; i < il; i++) {
      constrain = constrains[i];
      satisfyConstrains(constrain[0], constrain[1], constrain[2]);
    }

    const ballPosition = this.state.ballPosition.clone();

    // Ball Constrains
    ballPosition.z = -Math.sin(Date.now() / 600) * 90; // + 40;
    ballPosition.x = Math.cos(Date.now() / 400) * 70;

    if (sphere.visible) {
      for (particles = this.cloth.particles,
             i = 0,
             il = particles.length; i < il; i++) {
        particle = particles[i];
        const pos = particle.position;
        diff.subVectors(pos, ballPosition);
        if (diff.length() < ballSize) {
          // collided
          diff.normalize().multiplyScalar(ballSize);
          pos.copy(ballPosition).add(diff);
        }
      }
    }

    // Floor Constraints
    for (particles = this.cloth.particles, i = 0, il = particles.length
      ; i < il; i++) {
      particle = particles[i];
      const pos = particle.position;
      if (pos.y < -250) {
        pos.y = -250;
      }
    }

    // Pin Constrains
    for (i = 0, il = this.pins.length; i < il; i++) {
      const xy = this.pins[i];
      const p = particles[xy];
      p.position.copy(p.original);
      p.previous.copy(p.original);
    }

    this.setState({
      ballPosition,
    });
  }

  _onAnimate = () => {
    this.controls.update();

    const {
      minTimePerFrame,
    } = this.state;

    let time;

    if (minTimePerFrame > 0) {
      time = Math.round(Date.now() / minTimePerFrame) * minTimePerFrame;
    } else {
      time = Date.now();
    }

    if (time === this.state.time) {
      return;
    }

    const windStrength = Math.cos(time / 7000) * 20 + 40;
    this.windForce.set(
      Math.sin(time / 2000),
      Math.cos(time / 3000),
      Math.sin(time / 1000)).normalize().multiplyScalar(windStrength);

    this._simulate(time);

    const clothGeometry = React3.findTHREEObject(this._clothGeometry);

    // render

    const timer = time * 0.0002;

    const p = this.cloth.particles;

    let il;
    let i;
    for (i = 0, il = p.length; i < il; ++i) {
      clothGeometry.vertices[i].copy(p[i].position);
    }

    clothGeometry.computeFaceNormals();
    clothGeometry.computeVertexNormals();

    clothGeometry.normalsNeedUpdate = true;
    clothGeometry.verticesNeedUpdate = true;

    const newState = {
      time,
      spherePosition: this.ballPosition,
    };

    if (this.state.rotate) {
      newState.cameraPosition = new THREE.Vector3(
        Math.cos(timer) * 1500,
        this.state.cameraPosition.y,
        Math.sin(timer) * 1500);
    }

    this.setState(newState);
    this.stats.update();
  };

  _clothRef = (ref) => {
    this._clothGeometry = ref;
  };

  _onFrameChange = (event) => {
    this.setState({
      minTimePerFrame: +event.target.value,
    });
  };

  _containerRef = (container) => {
    this.container = container;
  };

  _sphereRef = (sphere) => {
    this.sphere = sphere;
  };

  _react3Ref = (react3) => {
    this.react3 = react3;
  };

  _mainCameraRef = (mainCamera) => {
    this.mainCamera = mainCamera;
  };

  render() {
    const {
      width,
      height,
    } = this.props;

    const {
      minTimePerFrame,
    } = this.state;

    return (<div ref={this._containerRef}>
      <Info
        toggleRotate={this._toggleRotate}
        toggleWind={this._toggleWind}
        toggleSphere={this._toggleSphere}
        togglePins={this._togglePins}
        rotating={this.state.rotate}
        winding={this.state.wind}
        balling={this.state.sphere}
        onFrameChange={this._onFrameChange}
        minTimePerFrame={minTimePerFrame}
      />
      <React3
        canvasRef={this._react3Ref}
        width={width}
        height={height}
        antialias
        pixelRatio={window.devicePixelRatio}
        clearColor={this.fog.color}
        gammaInput
        gammaOutput
        shadowMapEnabled
        shadowMapDebug
        mainCamera="mainCamera"
        onAnimate={this._onAnimate}
      >
        <scene fog={this.fog}>
          <perspectiveCamera
            name="mainCamera"
            fov={30}
            aspect={width / height}
            ref={this._mainCameraRef}
            position={this.state.cameraPosition}
            near={1}
            far={10000}
            lookAt={this.state.rotate ? this.scenePosition : null}
          />
          <StaticWorld
            clothRef={this._clothRef}
            cloth={this.cloth}
          />
          <Sphere
            ref={this._sphereRef}
            visible={this.state.sphere}
            position={this.state.ballPosition}
          />
        </scene>
      </React3>
    </div>);
  }
}

export default AnimationCloth;


================================================
FILE: src/examples/AnimationCloth/shaders/depth.frag
================================================
uniform sampler2D texture;
varying vec2 vUV;

vec4 pack_depth( const in float depth ) {
  const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );
  const vec4 bit_mask  = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );
  vec4 res = fract( depth * bit_shift );
  res -= res.xxyz * bit_mask;

  return res;
}

void main() {
  vec4 pixel = texture2D( texture, vUV );

  if ( pixel.a < 0.5 ) discard;

  gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );
}


================================================
FILE: src/examples/AnimationCloth/shaders/depth.vert
================================================
varying vec2 vUV;

void main() {
  vUV = 0.75 * uv;

  vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );

  gl_Position = projectionMatrix * mvPosition;
}


================================================
FILE: src/examples/Benchmark/RotatingCube.js
================================================
import React from 'react';
import * as THREE from 'three';

import PropTypes from 'prop-types';

const meshScale = new THREE.Vector3(1, 1, 1).multiplyScalar(0.5);

class RotatingCube extends React.Component {
  static propTypes = {
    position: PropTypes.instanceOf(THREE.Vector3).isRequired,
    quaternion: PropTypes.instanceOf(THREE.Quaternion).isRequired,
  };

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

    return (<mesh
      position={position}
      quaternion={quaternion}
      scale={meshScale}

      castShadow
    >
      <geometryResource
        resourceId="cubeGeo"
      />
      <materialResource
        resourceId="cubeMaterial"
      />
    </mesh>);
  }
}

export default RotatingCube;


================================================
FILE: src/examples/Benchmark/RotatingCubes.js
================================================
import React from 'react';
import React3 from 'react-three-renderer';
import * as THREE from 'three';

import ExampleBase from '../ExampleBase';

import Stats from 'stats.js';

import RotatingCube from './RotatingCube';

class RotatingCubes extends ExampleBase {
  constructor(props, context) {
    super(props, context);

    const N = 200;

    this.fog = new THREE.Fog(0x001525, 10, 40);

    const d = 20;

    this.lightPosition = new THREE.Vector3(d, d, d);
    this.lightTarget = new THREE.Vector3(0, 0, 0);
    this.groundQuaternion = new THREE.Quaternion()
      .setFromAxisAngle(new THREE.Vector3(1, 0, 0), -Math.PI / 2);
    this.cameraPosition = new THREE.Vector3(10, 2, 0);
    this.cameraQuaternion = new THREE.Quaternion()
      .setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2);

    const bodies = [];
    bodies.length = N;

    this.bodies = bodies;

    this._createBodies();

    this.state = {
      numBodies: N,
      meshStates: this._getMeshStates(),
    };
  }

  _getMeshStates() {
    return this.bodies.map(({ position, quaternion }) => ({
      position: new THREE.Vector3().copy(position),
      quaternion: new THREE.Quaternion().copy(quaternion),
    }));
  }

  _onAnimate = () => {
    this._updatePhysics();

    this._updateGraphics();

    this.stats.update();
  };

  _updateGraphics() {
    this.setState({
      meshStates: this._getMeshStates(),
    });
  }

  _updatePhysics() {
    const time = new Date().getTime();
    const bodies = this.bodies;

    for (let i = 0; i < bodies.length; ++i) {
      const body = bodies[i];

      const sinTime = Math.sin(time * body.timeScale);

      body.quaternion.multiply(body.rotationDeltaPerFrame);

      const { movementPerFrame } = body;

      body.position.copy(body.startPosition.clone()
        .add(movementPerFrame.clone()
          .multiplyScalar(sinTime)));
    }
  }

  componentDidMount() {
    const {
      container,
    } = this.refs;

    this.stats = new Stats();

    this.stats.domElement.style.position = 'absolute';
    this.stats.domElement.style.top = '0px';

    container.appendChild(this.stats.domElement);
  }

  componentWillUnmount() {
    delete this.stats;
  }

  _createBodies() {
    const { bodies } = this;
    const N = bodies.length;

    for (let i = 0; i < N; ++i) {
      bodies[i] = this._createBody(i);
    }
  }

  _createBody() {
    const position = new THREE.Vector3(
      -2.5 + Math.random() * 5,
      0.5 + Math.random() * 5,
      -2.5 + Math.random() * 5);

    return {
      position,
      timeScale: Math.random() * 0.005,
      startPosition: position.clone(),
      movementPerFrame: new THREE.Vector3(Math.random(), Math.random(), Math.random()),
      rotationDeltaPerFrame: new THREE.Quaternion()
        .setFromEuler(new THREE.Euler(
          Math.random() * 0.05,
          Math.random() * 0.05,
          Math.random() * 0.05)),
      quaternion: new THREE.Quaternion(),
    };
  }

  _onBodiesSelectChange = (event) => {
    const numBodies = event.target.value;

    this.bodies.length = numBodies;
    this._createBodies();

    this.setState({
      numBodies,
      meshStates: this._getMeshStates(),
    });

    this._updateGraphics();
  };

  _getInputBox(title) {
    const { numBodies } = this.state;

    return (<div
      style={{
        position: 'absolute',
        top: 0,
        color: 'white',
        width: '100%',
        textAlign: 'center',
        background: 'rgba(1,1,1,0.75)',
      }}
    >
      <div>{title}</div>
      <label>Bodies: <select
        value={numBodies}
        onChange={this._onBodiesSelectChange}
      >
        {[10, 50, 100, 200, 300, 500, 1000, 1500, 2000, 2500, 3000]
          .map(val => <option value={val} key={val}>{val}</option>)}
      </select>
      </label>
    </div>);
  }

  render() {
    const {
      width,
      height,
    } = this.props;

    const {
      meshStates,
    } = this.state;

    const d = 20;

    const cubeMeshes = meshStates.map(({ position, quaternion }, i) =>
      (<RotatingCube
        key={i}

        position={position}
        quaternion={quaternion}

        bodyIndex={i}

        meshes={this.meshes}
      />));

    return (<div
      ref="container"
    >
      {this._getInputBox('Rotating Cubes - Through React')}
      <React3
        antialias
        mainCamera="camera"
        width={width}
        height={height}

        onAnimate={this._onAnimate}

        clearColor={this.fog.color}

        gammaInput
        gammaOutput
        shadowMapEnabled
      >
        <resources>
          <boxGeometry
            resourceId="cubeGeo"

            width={0.5}
            height={0.5}
            depth={0.5}

            widthSegments={10}
            heightSegments={10}
          />
          <meshPhongMaterial
            resourceId="cubeMaterial"

            color={0x888888}
          />
        </resources>
        <scene
          ref="scene"
          fog={this.fog}
        >
          <perspectiveCamera
            name="camera"
            fov={30}
            aspect={width / height}
            near={0.5}
            far={10000}

            position={this.cameraPosition}
            quaternion={this.cameraQuaternion}

            ref="camera"
          />
          <ambientLight
            color={0x666666}
          />
          <directionalLight
            color={0xffffff}
            intensity={1.75}

            castShadow

            shadowMapWidth={1024}
            shadowMapHeight={1024}

            shadowCameraLeft={-d}
            shadowCameraRight={d}
            shadowCameraTop={d}
            shadowCameraBottom={-d}

            shadowCameraFar={3 * d}
            shadowCameraNear={d}

            position={this.lightPosition}
            lookAt={this.lightTarget}
          />
          <mesh
            castShadow
            receiveShadow

            quaternion={this.groundQuaternion}
          >
            <planeBufferGeometry
              width={100}
              height={100}
              widthSegments={1}
              heightSegments={1}
            />
            <meshLambertMaterial
              color={0x777777}
            />
          </mesh>
          {cubeMeshes}
        </scene>

      </React3>
    </div>);
  }
}

export default RotatingCubes;


================================================
FILE: src/examples/Benchmark/RotatingCubesDirectUpdates.js
================================================
import React from 'react';
import React3 from 'react-three-renderer';
import * as THREE from 'three';

import RotatingCube from './RotatingCube';
import RotatingCubes from './RotatingCubes';

class RotatingCubesDirectUpdates extends RotatingCubes {
  _getMeshStates() {
    const { bodies } = this;

    return bodies.map(({ position, quaternion, ref }) => ({
      position: new THREE.Vector3().copy(position),
      quaternion: new THREE.Quaternion().copy(quaternion),
      ref,
    }));
  }

  _bodyRef(index, body) {
    if (body === null) {
      // dismounted
      return;
    }

    this.bodies[index].body = React3.findTHREEObject(body);
  }

  _updateGraphics() {
    const { bodies } = this;

    for (let i = 0; i < bodies.length; ++i) {
      const body = bodies[i];

      if (body.body) {
        body.body.position.copy(body.position);
        body.body.quaternion.copy(body.quaternion);
      }
    }
  }

  _createBody(i) {
    return {
      ...super._createBody(),

      ref: this._bodyRef.bind(this, i),
    };
  }

  render() {
    const {
      width,
      height,
    } = this.props;

    const {
      meshStates,
    } = this.state;

    const d = 20;

    const cubeMeshes = meshStates.map(({ position, quaternion, ref }, i) => (<RotatingCube
      key={i}

      position={position}
      quaternion={quaternion}

      ref={ref}

      meshes={this.meshes}
    />));

    return (<div
      ref="container"
    >
      {this._getInputBox('Rotating Cubes - Direct Updates')}
      <React3
        antialias
        mainCamera="camera"
        width={width}
        height={height}

        onAnimate={this._onAnimate}

        clearColor={this.fog.color}

        gammaInput
        gammaOutput
        shadowMapEnabled
      >
        <resources>
          <boxGeometry
            resourceId="cubeGeo"

            width={0.5}
            height={0.5}
            depth={0.5}

            widthSegments={10}
            heightSegments={10}
          />
          <meshPhongMaterial
            resourceId="cubeMaterial"

            color={0x888888}
          />
        </resources>
        <scene
          ref="scene"
          fog={this.fog}
        >
          <perspectiveCamera
            name="camera"
            fov={30}
            aspect={width / height}
            near={0.5}
            far={10000}

            position={this.cameraPosition}
            quaternion={this.cameraQuaternion}

            ref="camera"
          />
          <ambientLight
            color={0x666666}
          />
          <directionalLight
            color={0xffffff}
            intensity={1.75}

            castShadow

            shadowMapWidth={1024}
            shadowMapHeight={1024}

            shadowCameraLeft={-d}
            shadowCameraRight={d}
            shadowCameraTop={d}
            shadowCameraBottom={-d}

            shadowCameraFar={3 * d}
            shadowCameraNear={d}

            position={this.lightPosition}
            lookAt={this.lightTarget}
          />
          <mesh
            castShadow
            receiveShadow

            quaternion={this.groundQuaternion}
          >
            <planeBufferGeometry
              width={100}
              height={100}
              widthSegments={1}
              heightSegments={1}
            />
            <meshLambertMaterial
              color={0x777777}
            />
          </mesh>
          {cubeMeshes}
        </scene>

      </React3>
    </div>);
  }
}

export default RotatingCubesDirectUpdates;


================================================
FILE: src/examples/DraggableCubes/AllCubes.js
================================================
import React from 'react';
import DraggableCube from './DraggableCube';
import * as THREE from 'three';

import PureRenderMixin from 'react/lib/ReactComponentWithPureRenderMixin';

import PropTypes from 'prop-types';

import MouseInput from '../inputs/MouseInput';

class AllCubes extends React.Component {
  static propTypes = {
    mouseInput: PropTypes.instanceOf(MouseInput),
    camera: PropTypes.instanceOf(THREE.PerspectiveCamera),

    onCubesMounted: PropTypes.func.isRequired,
    onHoverStart: PropTypes.func.isRequired,
    onHoverEnd: PropTypes.func.isRequired,
    onDragStart: PropTypes.func.isRequired,
    onDragEnd: PropTypes.func.isRequired,

    cursor: PropTypes.any,
  };

  constructor(props, context) {
    super(props, context);

    const cubePositions = [];
    cubePositions.length = 200;

    for (let i = 0; i < 200; ++i) {
      cubePositions[i] = new THREE.Vector3(
        Math.random() * 1000 - 500,
        Math.random() * 600 - 300,
        Math.random() * 800 - 400
      );
    }

    const cubes = [];
    cubes.length = cubePositions.length;
    this.cubes = cubes;

    this.cubePositions = cubePositions;

    this._hoveredCubes = 0;
    this._draggingCubes = 0;
  }

  componentDidMount() {
    const {
      onCubesMounted,
    } = this.props;

    onCubesMounted(this.cubes);
  }

  shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate;

  _onCubeCreate = (index, cube) => {
    this.cubes[index] = cube;
  };

  _onCubeMouseEnter = () => {
    if (this._hoveredCubes === 0) {
      const {
        onHoverStart,
      } = this.props;

      onHoverStart();
    }

    this._hoveredCubes++;
  };

  _onCubeMouseLeave = () => {
    this._hoveredCubes--;

    if (this._hoveredCubes === 0) {
      const {
        onHoverEnd,
      } = this.props;

      onHoverEnd();
    }
  };

  _onCubeDragStart = () => {
    if (this._draggingCubes === 0) {
      const {
        onDragStart,
      } = this.props;

      onDragStart();
    }

    this._draggingCubes++;
  };

  _onCubeDragEnd = () => {
    this._draggingCubes--;

    if (this._draggingCubes === 0) {
      const {
        onDragEnd,
      } = this.props;

      onDragEnd();
    }
  };


  render() {
    const {
      mouseInput,
      camera,

      cursor,
    } = this.props;

    return (<group>
      {this.cubePositions.map((cubePosition, index) => {
        const onCreate = this._onCubeCreate.bind(this, index);
        return (<DraggableCube
          key={index}

          mouseInput={mouseInput}
          camera={camera}

          initialPosition={cubePosition}
          onCreate={onCreate}
          onMouseEnter={this._onCubeMouseEnter}
          onMouseLeave={this._onCubeMouseLeave}
          onDragStart={this._onCubeDragStart}
          onDragEnd={this._onCubeDragEnd}

          cursor={cursor}
        />);
      })}
    </group>);
  }
}

export default AllCubes;


================================================
FILE: src/examples/DraggableCubes/DraggableCube.js
================================================
import React from 'react';
import PropTypes from 'prop-types';

import * as THREE from 'three';
import PureRenderMixin from 'react/lib/ReactComponentWithPureRenderMixin';

import MouseInput from '../inputs/MouseInput';

// shared plane for dragging purposes
// it's good to share because you can drag only one cube at a time
const dragPlane = new THREE.Plane();

const backVector = new THREE.Vector3(0, 0, -1);

class DraggableCube extends React.Component {
  static propTypes = {
    initialPosition: PropTypes.instanceOf(THREE.Vector3).isRequired,

    mouseInput: PropTypes.instanceOf(MouseInput),
    camera: PropTypes.instanceOf(THREE.PerspectiveCamera),

    onCreate: PropTypes.func.isRequired,

    onMouseEnter: PropTypes.func.isRequired,
    onMouseLeave: PropTypes.func.isRequired,
    onDragStart: PropTypes.func.isRequired,
    onDragEnd: PropTypes.func.isRequired,

    cursor: PropTypes.any,
  };

  constructor(props, context) {
    super(props, context);

    this.rotation = new THREE.Euler(
      Math.random() * 2 * Math.PI,
      Math.random() * 2 * Math.PI,
      Math.random() * 2 * Math.PI
    );

    this.scale = new THREE.Vector3(
      Math.random() * 2 + 1,
      Math.random() * 2 + 1,
      Math.random() * 2 + 1
    );

    this.color = new THREE.Color(Math.random() * 0xffffff);

    const hsl = this.color.getHSL();

    hsl.s = Math.min(1, hsl.s * 1.1);
    hsl.l = Math.min(1, hsl.l * 1.1);

    const { h, s, l } = hsl;

    this.hoverColor = new THREE.Color().setHSL(h, s, l);
    this.pressedColor = 0xff0000;

    const {
      initialPosition,
    } = props;

    this.state = {
      hovered: false,
      pressed: false,
      position: initialPosition,
    };
  }

  shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate;

  componentWillUnmount() {
    document.removeEventListener('mouseup', this._onDocumentMouseUp);
  }

  _onMouseEnter = () => {
    this.setState({
      hovered: true,
    });

    const { onMouseEnter } = this.props;

    onMouseEnter();
  };

  _onMouseDown = (event, intersection) => {
    event.preventDefault();
    event.stopPropagation();

    const {
      position,
    } = this.state;

    const {
      onDragStart,
      camera,
    } = this.props;

    dragPlane.setFromNormalAndCoplanarPoint(backVector.clone()
      .applyQuaternion(camera.quaternion), intersection.point);

    this._offset = intersection.point.clone().sub(position);

    document.addEventListener('mouseup', this._onDocumentMouseUp);
    document.addEventListener('mousemove', this._onDocumentMouseMove);

    this.setState({
      pressed: true,
    });

    onDragStart();
  };

  _onDocumentMouseMove = (event) => {
    event.preventDefault();

    const {
      mouseInput,
    } = this.props;

    const ray:THREE.Ray = mouseInput.getCameraRay(new THREE
      .Vector2(event.clientX, event.clientY));

    const intersection = dragPlane.intersectLine(new THREE.Line3(
      ray.origin,
      ray.origin.clone()
        .add(ray.direction.clone().multiplyScalar(10000))
    ));

    if (intersection) {
      this.setState({
        position: intersection.sub(this._offset),
      });
    }
  };

  _onDocumentMouseUp = (event) => {
    event.preventDefault();

    document.removeEventListener('mouseup', this._onDocumentMouseUp);
    document.removeEventListener('mousemove', this._onDocumentMouseMove);

    const {
      onDragEnd,
    } = this.props;

    onDragEnd();

    this.setState({
      pressed: false,
    });
  };

  _onMouseLeave = () => {
    if (this.state.hovered) {
      this.setState({
        hovered: false,
      });
    }

    const {
      onMouseLeave,
    } = this.props;

    onMouseLeave();
  };

  _ref = (mesh) => {
    const {
      onCreate,
    } = this.props;

    onCreate(mesh);
  };

  render() {
    const {
      rotation,
      scale,
    } = this;

    const {
      cursor: {
        dragging,
      },
    } = this.props;

    const {
      hovered,
      pressed,
      position,
    } = this.state;

    let color;

    const hoverHighlight = (hovered && !dragging);
    if (pressed) {
      color = this.pressedColor;
    } else if (hoverHighlight) {
      color = this.hoverColor;
    } else {
      color = this.color;
    }

    return (<group
      position={position}
      rotation={rotation}
      scale={scale}
    >
      <mesh
        castShadow
        receiveShadow

        onMouseEnter={this._onMouseEnter}
        onMouseDown={this._onMouseDown}
        onMouseLeave={this._onMouseLeave}

        ref={this._ref}
      >
        <geometryResource
          resourceId="boxGeometry"
        />
        <meshLambertMaterial
          color={color}
        />
      </mesh>
      {hoverHighlight ? <mesh
        ignorePointerEvents
      >
        <geometryResource
          resourceId="boxGeometry"
        />
        <materialResource
          resourceId="highlightMaterial"
        />
      </mesh> : null}
    </group>);
  }
}

export default DraggableCube;


================================================
FILE: src/examples/DraggableCubes/index.js
================================================
import React from 'react';

import PureRenderMixin from 'react/lib/ReactComponentWithPureRenderMixin';

import * as THREE from 'three';
import Stats from 'stats.js';

import React3 from 'react-three-renderer';

import ExampleBase from '../ExampleBase';

import TrackballControls from '../../ref/trackball';

import MouseInput from '../inputs/MouseInput';

import AllCubes from './AllCubes';

class DraggableCubes extends ExampleBase {
  constructor(props, context) {
    super(props, context);

    this.state = {
      cameraPosition: new THREE.Vector3(0, 0, 1000),
      cameraRotation: new THREE.Euler(),
      mouseInput: null,
      hovering: false,
      dragging: false,
    };

    this._cursor = {
      hovering: false,
      dragging: false,
    };

    this.lightPosition = new THREE.Vector3(0, 500, 2000);
    this.lightTarget = new THREE.Vector3(0, 0, 0);
  }

  shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate;

  _onAnimate = () => {
    this._onAnimateInternal();
  };

  componentDidMount() {
    this.stats = new Stats();

    this.stats.domElement.style.position = 'absolute';
    this.stats.domElement.style.top = '0px';

    const {
      container,
      camera,
    } = this.refs;

    container.appendChild(this.stats.domElement);

    const controls = new TrackballControls(camera);

    controls.rotateSpeed = 1.0;
    controls.zoomSpeed = 1.2;
    controls.panSpeed = 0.8;
    controls.noZoom = false;
    controls.noPan = false;
    controls.staticMoving = true;
    controls.dynamicDampingFactor = 0.3;

    this.controls = controls;

    this.controls.addEventListener('change', this._onTrackballChange);
  }

  _onCubesMounted = (cubes) => {
    this.cubes = cubes;
  };

  _onHoverStart = () => {
    this.setState({
      hovering: true,
    });
  };

  _onHoverEnd = () => {
    this.setState({
      hovering: false,
    });
  };

  _onDragStart = () => {
    this.setState({
      dragging: true,
    });
  };

  _onDragEnd = () => {
    this.setState({
      dragging: false,
    });
  };


  componentDidUpdate(newProps) {
    const {
      mouseInput,
    } = this.refs;

    const {
      width,
      height,
    } = this.props;

    if (width !== newProps.width || height !== newProps.height) {
      mouseInput.containerResized();
    }
  }

  _onTrackballChange = () => {
    this.setState({
      cameraPosition: this.refs.camera.position.clone(),
      cameraRotation: this.refs.camera.rotation.clone(),
    });
  };

  componentWillUnmount() {
    this.controls.removeEventListener('change', this._onTrackballChange);

    this.controls.dispose();
    delete this.controls;

    delete this.stats;
  }

  _onAnimateInternal() {
    const {
      mouseInput,
      camera,
    } = this.refs;

    if (!mouseInput.isReady()) {
      const {
        scene,
        container,
      } = this.refs;

      mouseInput.ready(scene, container, camera);
      mouseInput.restrictIntersections(this.cubes);
      mouseInput.setActive(false);
    }

    if (this.state.mouseInput !== mouseInput) {
      this.setState({
        mouseInput,
      });
    }

    if (this.state.camera !== camera) {
      this.setState({
        camera,
      });
    }

    this.stats.update();
    this.controls.update();
  }

  render() {
    const {
      width,
      height,
    } = this.props;

    const {
      cameraPosition,
      cameraRotation,

      mouseInput,
      camera,

      hovering,
      dragging,
    } = this.state;

    const style = {};

    if (dragging) {
      style.cursor = 'move';
    } else if (hovering) {
      style.cursor = 'pointer';
    }

    this._cursor.hovering = hovering;
    this._cursor.dragging = dragging;

    return (<div
      ref="container"
      style={style}
    >
      <React3
        width={width}
        height={height}
        antialias
        pixelRatio={window.devicePixelRatio}
        mainCamera="mainCamera"
        onAnimate={this._onAnimate}
        sortObjects={false}
        shadowMapEnabled
        shadowMapType={THREE.PCFShadowMap}
        clearColor={0xf0f0f0}
      >
        <module
          ref="mouseInput"
          descriptor={MouseInput}
        />
        <resources>
          <boxGeometry
            resourceId="boxGeometry"

            width={40}
            height={40}
            depth={40}
          />
          <meshBasicMaterial
            resourceId="highlightMaterial"

            color={0xffff00}
            wireframe
          />
        </resources>
        <scene ref="scene">
          <perspectiveCamera
            fov={70}
            aspect={width / height}
            near={1}
            far={10000}
            name="mainCamera"
            ref="camera"
            position={cameraPosition}
            rotation={cameraRotation}
          />
          <ambientLight
            color={0x505050}
          />
          <spotLight
            color={0xffffff}
            intensity={1.5}
            position={this.lightPosition}
            lookAt={this.lightTarget}

            castShadow
            shadowCameraNear={200}
            shadowCameraFar={10000}
            shadowCameraFov={50}

            shadowBias={-0.00022}

            shadowMapWidth={2048}
            shadowMapHeight={2048}
          />
          <AllCubes
            mouseInput={mouseInput}
            camera={camera}

            onCubesMounted={this._onCubesMounted}

            onHoverStart={this._onHoverStart}
            onHoverEnd={this._onHoverEnd}
            onDragStart={this._onDragStart}
            onDragEnd={this._onDragEnd}

            cursor={this._cursor}
          />
        </scene>
      </React3>
    </div>);
  }
}

export default DraggableCubes;


================================================
FILE: src/examples/ExampleBase.js
================================================
import React from 'react';

import PropTypes from 'prop-types';

class ExampleBase extends React.Component {
  static propTypes = {
    width: PropTypes.number.isRequired,
    height: PropTypes.number.isRequired,
  };
}

export default ExampleBase;


================================================
FILE: src/examples/ExampleBrowser.js
================================================
import React from 'react';
import { NavLink } from 'react-router-dom';
import ExampleViewer from './ExampleViewer';

import SimpleExample from './Simple/index';
import ManualRenderingExample from './ManualRendering/index';
import ClothExample from './AnimationCloth/index';
import GeometriesExample from './Geometries/index';
import CameraExample from './WebGLCameraExample/index';
import GeometryShapesExample from './GeometryShapes/index';
import DraggableCubes from './DraggableCubes/index';
import Physics from './Physics/index';
import PhysicsMousePick from './Physics/mousePick';
import BenchmarkRotatingCubes from './Benchmark/RotatingCubes';
import RotatingCubesDirectUpdates from './Benchmark/RotatingCubesDirectUpdates';

const examples = [
  {
    name: 'Simple',
    component: SimpleExample,
    url: 'Simple/index',
    slug: 'webgl_simple',
  },
  {
    name: 'Cloth',
    component: ClothExample,
    url: 'AnimationCloth/index',
    slug: 'webgl_cloth',
  },
  {
    name: 'Camera',
    component: CameraExample,
    url: 'WebGLCameraExample/index',
    slug: 'webgl_camera',
  },
  {
    name: 'Geometries',
    component: GeometriesExample,
    url: 'Geometries/index',
    slug: 'webgl_geometries',
  },
  {
    name: 'Geometry Shapes',
    component: GeometryShapesExample,
    url: 'GeometryShapes/index',
    slug: 'webgl_geometry_shapes',
  },
  {
    name: 'Draggable Cubes',
    component: DraggableCubes,
    url: 'DraggableCubes/index',
    slug: 'webgl_draggable_cubes',
  },
  {
    name: 'Physics',
    component: Physics,
    url: 'Physics/index',
    slug: 'webgl_physics',
  },
  {
    name: 'Physics - MousePick',
    component: PhysicsMousePick,
    url: 'Physics/mousePick',
    slug: 'webgl_physics_mousepick',
  },
  {
    separator: true,
    name: 'Advanced',
  },
  {
    name: 'Without react-dom',
    advanced: true,
    page: 'advanced.html',
  },
  {
    name: 'Manual rendering',
    component: ManualRenderingExample,
    url: 'ManualRendering/index',
    slug: 'advanced_manual_rendering',
  },
  {
    separator: true,
    name: 'Benchmarks',
  },
  {
    name: 'RotatingCubes - Through React',
    component: BenchmarkRotatingCubes,
    url: 'Benchmark/RotatingCubes',
    slug: 'benchmarks_rotating_cubes_react',
  },
  {
    name: 'RotatingCubes - Direct Updates',
    component: RotatingCubesDirectUpdates,
    url: 'Benchmark/RotatingCubesDirectUpdates',
    slug: 'benchmarks_rotating_cubes_direct',
  },
];

const ExampleBrowser = ({ match }) => {
  const { params } = match;
  const activeExample = params.slug && examples.find(example => example.slug === params.slug);
  return (
    <div>
      <div id="panel" className="collapsed">
        <h1><a href="https://github.com/toxicFork/react-three-renderer/">react-three-renderer</a> / examples</h1>
        <div id="content">
          <div>
            <h2>webgl</h2>
            {examples.map((example, index) => {
              if (example.separator) {
                return (<h2 key={index}>{example.name}</h2>);
              }

              if (example.advanced) {
                return (<div key={index}>
                  <a href={example.page} target="blank">{example.name}</a> (new tab)
                </div>);
              }

              return (<NavLink
                to={`/${example.slug}`}
                key={index}
                className="link"
                activeClassName="selected"
              >
                {example.name}
              </NavLink>);
            })}
          </div>
        </div>
      </div>
      <ExampleViewer example={activeExample} />
    </div>
  );
};

ExampleBrowser.propTypes = {
  match: React.PropTypes.object.isRequired,
};

export default ExampleBrowser;


================================================
FILE: src/examples/ExampleViewer.js
================================================
import React from 'react';
import sizeMe from 'react-sizeme';

const ExampleViewer = ({ example, size }) => {
  let sourceButton = null;
  let exampleContent = null;

  if (example) {
    const {
      component: ExampleComponent,
      url,
    } = example;
    exampleContent = (<ExampleComponent width={size.width} height={size.height} />);
    sourceButton = (<div key="src" id="button">
      <a
        href={`https://github.com/toxicFork/react-three-renderer-example/blob/master/src/examples/${url}.js`}
        target="_blank"
      >
        View source
      </a>
    </div>);
  }

  return (
    <div id="viewer">
      {exampleContent}
      {sourceButton}
    </div>
  );
};

ExampleViewer.propTypes = {
  example: React.PropTypes.object,
  size: React.PropTypes.object,
};

export default sizeMe({ monitorHeight: true, refreshRate: 200 })(ExampleViewer);


================================================
FILE: src/examples/Geometries/index.js
================================================
import React from 'react';

import * as THREE from 'three';
import Stats from 'stats.js';

import React3 from 'react-three-renderer';

import ExampleBase from '../ExampleBase';


class Geometries extends ExampleBase {
  constructor(props, context) {
    super(props, context);

    this.directionalLightPosition = new THREE.Vector3(0, 1, 0);

    this.objectPositions = [
      new THREE.Vector3(-400, 0, 200),
      new THREE.Vector3(-200, 0, 200),
      new THREE.Vector3(0, 0, 200),
      new THREE.Vector3(200, 0, 200),
      new THREE.Vector3(-400, 0, 0),
      new THREE.Vector3(-200, 0, 0),
      new THREE.Vector3(0, 0, 0),
      new THREE.Vector3(200, 0, 0),
      new THREE.Vector3(400, 0, 0),

      new THREE.Vector3(-400, 0, -200),
      new THREE.Vector3(-200, 0, -200),
      new THREE.Vector3(0, 0, -200),
      new THREE.Vector3(200, 0, -200),
      new THREE.Vector3(400, 0, -200),
    ];

    this.lathePoints = [];

    for (let i = 0; i < 50; i++) {
      this.lathePoints.push(new THREE
        .Vector2(Math.sin(i * 0.2) * Math.sin(i * 0.1) * 15 + 50, (i - 5) * 2));
    }

    this.arrowDir = new THREE.Vector3(0, 1, 0);
    this.arrowOrigin = new THREE.Vector3(0, 0, 0);

    this.scenePosition = new THREE.Vector3(0, 0, 0);

    this.state = {
      ...this.state,
      timer: Date.now() * 0.0001,
    };
  }

  _onAnimate = () => {
    this._onAnimateInternal();
  };

  componentDidMount() {
    this.stats = new Stats();

    this.stats.domElement.style.position = 'absolute';
    this.stats.domElement.style.top = '0px';

    this.refs.container.appendChild(this.stats.domElement);
  }

  componentWillUnmount() {
    delete this.stats;
  }

  _onAnimateInternal() {
    const timer = Date.now() * 0.0001;

    this.setState({
      timer,
    });

    this.stats.update();
  }

  render() {
    const {
      width,
      height,
    } = this.props;

    const {
      timer,
    } = this.state;

    const objectRotation = new THREE.Euler(
      timer * 5,
      timer * 2.5,
      0
    );

    return (<div ref="container">
      <React3
        width={width}
        height={height}
        antialias
        pixelRatio={window.devicePixelRatio}
        mainCamera="mainCamera"
        onAnimate={this._onAnimate}
      >
        <resources>
          <texture
            resourceId="texture"
            url="textures/UV_Grid_Sm.jpg"
            wrapS={THREE.RepeatWrapping}
            wrapT={THREE.RepeatWrapping}
            anisotropy={16}
          />
          <meshLambertMaterial
            resourceId="material"
            side={THREE.DoubleSide}
          >
            <textureResource
              resourceId="texture"
            />
          </meshLambertMaterial>
        </resources>
        <scene>
          <perspectiveCamera
            fov={45}
            aspect={width / height}
            near={1}
            far={2000}
            lookAt={this.scenePosition}
            name="mainCamera"
            position={new THREE.Vector3(
              Math.cos(timer) * 800,
              400,
              Math.sin(timer) * 800
            )}
          />
          <ambientLight
            color={0x404040}
          />
          <directionalLight
            color={0xffffff}
            position={this.directionalLightPosition}
            lookAt={this.scenePosition}
          />
          <mesh
            position={this.objectPositions[0]}
            rotation={objectRotation}
          >
            <sphereGeometry
              radius={75}
              widthSegments={20}
              heightSegments={10}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <mesh
            position={this.objectPositions[1]}
            rotation={objectRotation}
          >
            <icosahedronGeometry
              radius={75}
              detail={1}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <mesh
            position={this.objectPositions[2]}
            rotation={objectRotation}
          >
            <octahedronGeometry
              radius={75}
              detail={2}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <mesh
            position={this.objectPositions[3]}
            rotation={objectRotation}
          >
            <tetrahedronGeometry
              radius={75}
              detail={0}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <mesh
            position={this.objectPositions[4]}
            rotation={objectRotation}
          >
            <planeBufferGeometry
              width={100}
              height={100}
              widthSegments={4}
              heightSegments={4}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <mesh
            position={this.objectPositions[5]}
            rotation={objectRotation}
          >
            <boxGeometry
              width={100}
              height={100}
              depth={100}
              widthSegments={4}
              heightSegments={4}
              depthSegments={4}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <mesh
            position={this.objectPositions[6]}
            rotation={objectRotation}
          >
            <circleGeometry
              radius={50}
              segments={20}
              thetaStart={0}
              thetaLength={Math.PI * 2}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <mesh
            position={this.objectPositions[7]}
            rotation={objectRotation}
          >
            <ringGeometry
              innerRadius={10}
              outerRadius={50}
              thetaSegments={20}
              phiSegments={5}
              thetaStart={0}
              thetaLength={Math.PI * 2}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <mesh
            position={this.objectPositions[8]}
            rotation={objectRotation}
          >
            <cylinderGeometry
              radiusTop={25}
              radiusBottom={75}
              height={100}
              radialSegments={40}
              heightSegments={5}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <mesh
            position={this.objectPositions[9]}
            rotation={objectRotation}
          >
            <latheGeometry
              points={this.lathePoints}
              segments={20}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <mesh
            position={this.objectPositions[10]}
            rotation={objectRotation}
          >
            <torusGeometry
              radius={50}
              tube={20}
              radialSegments={20}
              tubularSegments={20}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <mesh
            position={this.objectPositions[11]}
            rotation={objectRotation}
          >
            <torusKnotGeometry
              radius={50}
              tube={10}
              radialSegments={50}
              tubularSegments={20}
            />
            <materialResource
              resourceId="material"
            />
          </mesh>
          <axisHelper
            position={this.objectPositions[12]}
            size={50}
            rotation={objectRotation}
          />
          <arrowHelper
            dir={this.arrowDir}
            origin={this.arrowOrigin}
            length={50}
            position={this.objectPositions[13]}
            rotation={objectRotation}
          />
        </scene>
      </React3>
    </div>);
  }
}

export default Geometries;


================================================
FILE: src/examples/GeometryShapes/Rect.js
================================================
import React from 'react';
import PropTypes from 'react/lib/ReactPropTypes';

function Rect(props) {
  const {
    width,
    length,
    resourceId,
  } = props;

  return (<shape resourceId={resourceId}>
    <moveTo
      x={0}
      y={0}
    />
    <lineTo
      x={0}
      y={width}
    />
    <lineTo
      x={length}
      y={width}
    />
    <lineTo
      x={length}
      y={0}
    />
    <lineTo
      x={0}
      y={0}
    />
  </shape>);
}

Rect.propTypes = {
  width: PropTypes.number.isRequired,
  length: PropTypes.number.isRequired,
  resourceId: PropTypes.string.isRequired,
};

export default Rect;


================================================
FILE: src/examples/GeometryShapes/Resources.js
================================================
import React from 'react';
import * as THREE from 'three';

import Rect from './Rect';

class Resources extends React.Component {
  shouldComponentUpdate() {
    return false;
  }

  render() {
    this.textureRepeat = new THREE.Vector2(0.008, 0.008);

    const x = 0;
    const y = 0;

    const sqLength = 80;

    const rectLength = 120;
    const rectWidth = 40;

    const californiaPts = [];

    californiaPts.push(new THREE.Vector2(610, 320));
    californiaPts.push(new THREE.Vector2(450, 300));
    californiaPts.push(new THREE.Vector2(392, 392));
    californiaPts.push(new THREE.Vector2(266, 438));
    californiaPts.push(new THREE.Vector2(190, 570));
    californiaPts.push(new THREE.Vector2(190, 600));
    californiaPts.push(new THREE.Vector2(160, 620));
    californiaPts.push(new THREE.Vector2(160, 650));
    californiaPts.push(new THREE.Vector2(180, 640));
    californiaPts.push(new THREE.Vector2(165, 680));
    californiaPts.push(new THREE.Vector2(150, 670));
    californiaPts.push(new THREE.Vector2(90, 737));
    californiaPts.push(new THREE.Vector2(80, 795));
    californiaPts.push(new THREE.Vector2(50, 835));
    californiaPts.push(new THREE.Vector2(64, 870));
    californiaPts.push(new THREE.Vector2(60, 945));
    californiaPts.push(new THREE.Vector2(300, 945));
    californiaPts.push(new THREE.Vector2(300, 743));
    californiaPts.push(new THREE.Vector2(600, 473));
    californiaPts.push(new THREE.Vector2(626, 425));
    californiaPts.push(new THREE.Vector2(600, 370));
    californiaPts.push(new THREE.Vector2(610, 320));

    for (let i = 0; i < californiaPts.length; i++) californiaPts[i].multiplyScalar(0.25);

    this.californiaPts = californiaPts;

    return (
      <resources>
        <texture
          resourceId="texture"
          url="textures/UV_Grid_Sm.jpg"
          wrapS={THREE.RepeatWrapping}
          wrapT={THREE.RepeatWrapping}
          repeat={this.textureRepeat}
        />
        <meshBasicMaterial
          resourceId="hoverMaterial"
          color={0xff0000}
          side={THREE.DoubleSide}
        />
        <meshPhongMaterial
          resourceId="phongMaterial"
          side={THREE.DoubleSide}
        >
          <textureResource
            resourceId="texture"
          />
        </meshPhongMaterial>
        <shape
          resourceId="california"
          points={this.californiaPts}
        />
        <shape resourceId="triangle">
          <moveTo
            x={80}
            y={20}
          />
          <lineTo
            x={40}
            y={80}
          />
          <lineTo
            x={120}
            y={80}
          />
          <lineTo
            x={80}
            y={20}
          />
        </shape>
        <shape resourceId="heart">
          <moveTo
            x={x + 25}
            y={y + 25}
          />
          <bezierCurveTo
            cp1X={x + 25}
            cp1Y={y + 25}
            cp2X={x + 20}
            cp2Y={y}
            aX={x}
            aY={y}
          />
          <bezierCurveTo
            cp1X={x - 30}
            cp1Y={y}
            cp2X={x - 30}
            cp2Y={y + 35}
            aX={x - 30}
            aY={y + 35}
          />
          <bezierCurveTo
            cp1X={x - 30}
            cp1Y={y + 55}
            cp2X={x - 10}
            cp2Y={y + 77}
            aX={x + 25}
            aY={y + 95}
          />
          <bezierCurveTo
            cp1X={x + 60}
            cp1Y={y + 77}
            cp2X={x + 80}
            cp2Y={y + 55}
            aX={x + 80}
            aY={y + 35}
          />
          <bezierCurveTo
            cp1X={ x + 80}
            cp1Y={y + 35}
            cp2X={x + 80}
            cp2Y={y}
            aX={x + 50}
            aY={y}
          />
          <bezierCurveTo
            cp1X={x + 35}
            cp1Y={y}
            cp2X={x + 25}
            cp2Y={y + 25}
            aX={x + 25}
            aY={y + 25}
          />
        </shape>
        <Rect
          resourceId="square"
          width={sqLength}
          length={sqLength}
        />
        <Rect
          resourceId="rect"
          width={rectWidth}
          length={rectLength}
        />
        {((function roundedRect(rectX, rectY,
                                roundedRectWidth, roundedRectHeight,
                                radius) {
          return (<shape resourceId="roundedRect">
            <moveTo
              x={rectX}
              y={rectY + radius}
            />
            <lineTo
              x={rectX}
              y={rectY + roundedRectHeight - radius}
            />
            <quadraticCurveTo
              cpX={rectX}
              cpY={rectY + roundedRectHeight}
              x={rectX + radius}
              y={rectY + roundedRectHeight}
            />
            <lineTo
              x={rectX + roundedRectWidth - radius}
              y={rectY + roundedRectHeight}
            />
            <quadraticCurveTo
              cpX={rectX + roundedRectWidth}
              cpY={rectY + roundedRectHeight}
              x={rectX + roundedRectWidth}
              y={rectY + roundedRectHeight - radius}
            />
            <lineTo
              x={rectX + roundedRectWidth}
              y={rectY + radius}
            />
            <quadraticCurveTo
              cpX={rectX + roundedRectWidth}
              cpY={rectY}
              x={rectX + roundedRectWidth - radius}
              y={rectY}
            />
            <lineTo
              x={rectX + radius}
              y={rectY}
            />
            <quadraticCurveTo
              cpX={rectX}
              cpY={rectY}
              x={rectX}
              y={rectY + radius}
            />
          </shape>);
        })(0, 0, 50, 50, 20))}
        <shape
          resourceId="track"
        >
          <moveTo
            x={40}
            y={40}
          />
          <lineTo
            x={40}
            y={160}
          />
          <absArc
            x={60}
            y={160}
            radius={20}
            startAngle={Math.PI}
            endAngle={0}
            clockwise
          />
          <lineTo
            x={80}
            y={40}
          />
          <absArc
            x={60}
            y={40}
            radius={20}
            startAngle={2 * Math.PI}
            endAngle={Math.PI}
            clockwise
          />
        </shape>
        {((function circleShape() {
          const circleRadius = 40;

          return (<shape resourceId="circle">
            <moveTo
              x={0}
              y={circleRadius}
            />
            <quadraticCurveTo
              cpX={circleRadius}
              cpY={circleRadius}
              x={circleRadius}
              y={0}
            />
            <quadraticCurveTo
              cpX={circleRadius}
              cpY={-circleRadius}
              x={0}
              y={-circleRadius}
            />
            <quadraticCurveTo
              cpX={-circleRadius}
              cpY={-circleRadius}
              x={-circleRadius}
              y={0}
            />
            <quadraticCurveTo
              cpX={-circleRadius}
              cpY={circleRadius}
              x={0}
              y={circleRadius}
            />
          </shape>);
        })())}
        <shape resourceId="arc">
          <moveTo
            x={50}
            y={10}
          />
          <absArc
            x={10}
            y={10}
            radius={40}
            startAngle={0}
            endAngle={Math.PI * 2}
            clockwise={false}
          />
          <hole>
            <moveTo
              x={20}
              y={10}
            />
            <absArc
              x={10}
              y={10}
              radius={10}
              startAngle={0}
              endAngle={Math.PI * 2}
              clockwise
            />
          </hole>
        </shape>
        <shape resourceId="fish">
          <moveTo
            x={x}
            y={y}
          />
          <quadraticCurveTo
            cpX={x + 50}
            cpY={y - 80}
            x={x + 90}
            y={y - 10}
          />
          <quadraticCurveTo
            cpX={x + 100}
            cpY={y - 10}
            x={x + 115}
            y={y - 40}
          />
          <quadraticCurveTo
            cpX={x + 115}
            cpY={y}
            x={x + 115}
            y={y + 40}
          />
          <quadraticCurveTo
            cpX={x + 100}
            cpY={y + 10}
            x={x + 90}
            y={y + 10}
          />
          <quadraticCurveTo
            cpX={x + 50}
            cpY={y + 80}
            x={x}
            y={y}
          />
        </shape>
        <shape resourceId="smiley">
          <moveTo
            x={80}
            y={40}
          />
          <absArc
            x={40}
            y={40}
            radius={40}
            startAngle={0}
            endAngle={Math.PI * 2}
            clockwise={false}
          />
          <hole key="eye1">
            <moveTo
              x={35}
              y={20}
            />
            <absEllipse
              x={25}
              y={20}
              xRadius={10}
              yRadius={10}
              startAngle={0}
              endAngle={Math.PI * 2}
              clockwise
            />
          </hole>
          <hole key="eye2">
            <moveTo
              x={65}
              y={20}
            />
            <absArc
              x={55}
              y={20}
              radius={10}
              startAngle={0}
              endAngle={Math.PI * 2}
              clockwise
            />
          </hole>
          <hole key="mouth">
            <moveTo
              x={20}
              y={40}
            />
            <quadraticCurveTo
              cpX={40}
              cpY={60}
              x={60}
              y={40}
            />
            <bezierCurveTo
              cp1X={70}
              cp1Y={45}
              cp2X={70}
              cp2Y={50}
              aX={60}
              aY={60}
            />
            <quadraticCurveTo
              cpX={40}
              cpY={80}
              x={20}
              y={60}
            />
            <quadraticCurveTo
              cpX={5}
              cpY={50}
              x={20}
              y={40}
            />
          </hole>
        </shape>
        {((function splineShape() {
          const splinePoints = [];
          splinePoints.push(new THREE.Vector2(70, 20));
          splinePoints.push(new THREE.Vector2(80, 90));
          splinePoints.push(new THREE.Vector2(-30, 70));
          splinePoints.push(new THREE.Vector2(0, 0));

          return (<shape resourceId="spline">
            <moveTo
              x={0}
              y={0}
            />
            <splineThru
              points={splinePoints}
            />
          </shape>);
        })())}
      </resources>);
  }
}

export default Resources;


================================================
FILE: src/examples/GeometryShapes/Shape.js
================================================
import React from 'react';
import * as THREE from 'three';
import PropTypes from 'react/lib/ReactPropTypes';

import PureRenderMixin from 'react/lib/ReactComponentWithPureRenderMixin';

const extrudeSettings = {
  amount: 8,
  bevelEnabled: true,
  bevelSegments: 2,
  steps: 2,
  bevelSize: 1,
  bevelThickness: 1,
};

class Shape extends React.Component {
  static propTypes = {
    resourceId: PropTypes.string.isRequired,
    color: PropTypes.any.isRequired,
    x: PropTypes.number.isRequired,
    y: PropTypes.number.isRequired,
    z: PropTypes.number.isRequired,
    rx: PropTypes.number.isRequired,
    ry: PropTypes.number.isRequired,
    rz: PropTypes.number.isRequired,
    s: PropTypes.number.isRequired,
  };

  shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate;

  render() {
    const {
      rx,
      ry,
      rz,
      s,
      resourceId,
      color,
      x,
      y,
      z,
      } = this.props;

    const rotation = new THREE.Euler(rx, ry, rz);
    const scale = new THREE.Vector3(s, s, s);

    return (<group>
      <mesh
        // flat shape with texture
        position={new THREE.Vector3(x, y, z - 175)}
        rotation={rotation}
        scale={scale}
      >
        <shapeGeometryResource
          resourceId={resourceId}
          type="shape"
        />
        <materialResource
          resourceId={'phongMaterial'}
        />
      </mesh>
      <mesh
        // flat shape
        position={new THREE.Vector3(x, y, z - 125)}
        rotation={rotation}
        scale={scale}
      >
        <shapeGeometryResource
          resourceId={resourceId}
          type="shape"
        />
        <meshPhongMaterial
          color={color}
          side={THREE.DoubleSide}
        />
      </mesh>
      <mesh
        // 3d shape
        position={new THREE.Vector3(x, y, z - 75)}
        rotation={rotation}
        scale={scale}
      >
        <extrudeGeometry
          settings={extrudeSettings}
        >
          <shapeResource
            resourceId={resourceId}
          />
        </extrudeGeometry>
        <meshPhongMaterial
          color={color}
        />
      </mesh>
      <line
        // solid line
        position={new THREE.Vector3(x, y, z - 25)}
        rotation={rotation}
        scale={scale}
      >
        <shapeGeometryResource
          resourceId={resourceId}
          type="points"
        />
        <lineBasicMaterial
          color={color}
          // wireframe
        />
      </line>
      <points
        // vertices from real points
        position={new THREE.Vector3(x, y, z + 25)}
        rotation={rotation}
        scale={scale}
      >
        <shapeGeometryResource
          resourceId={resourceId}
          type="points"
        />
        <pointsMaterial
          color={color}
          size={4}
          // wireframe
        />
      </points>
      <line
        // line from equidistance sampled points
        position={new THREE.Vector3(x, y, z + 75)}
        rotation={rotation}
        scale={scale}
      >
        <shapeGeometryResource
          resourceId={resourceId}
          type="spacedPoints"
          divisions={50}
        />
        <lineBasicMaterial
          color={color}
          linewidth={3}
          // wireframe
        />
      </line>
      <points
        // equidistance sampled points
        position={new THREE.Vector3(x, y, z + 125)}
        rotation={rotation}
        scale={scale}
      >
        <shapeGeometryResource
          resourceId={resourceId}
          type="spacedPoints"
          divisions={50}
        />
        <pointsMaterial
          color={color}
          size={4}
          // wireframe
        />
      </points>
    </group>);
  }
}

export default Shape;


================================================
FILE: src/examples/GeometryShapes/Shapes.js
================================================
import React from 'react';
import Shape from './Shape';

class Shapes extends React.Component {
  shouldComponentUpdate() {
    return false;
  }

  render() {
    return (<group>
      <Shape
        resourceId="california"
        x={-300}
        y={-100}
        z={0}
        color={0xf08000}
        rx={0}
        ry={0}
        rz={0}
        s={1}
      />
      <Shape
        resourceId="triangle"
        color={0x8080f0}
        x={-180}
        y={0}
        z={0}
        rx={0}
        ry={0}
        rz={0}
        s={1}
      />
      <Shape
        resourceId="roundedRect"
        x={-150}
        y={150}
        z={0}
        color={0x008000}
        rx={0}
        ry={0}
        rz={0}
        s={1}
      />
      <Shape
        resourceId="track"
        x={200}
        y={-100}
        z={0}
        color={0x008080}
        rx={0}
        ry={0}
        rz={0}
        s={1}
      />
      <Shape
        resourceId="square"
        color={0x0040f0}
        x={150}
        y={100}
        z={0}
        rx={0}
        ry={0}
        rz={0}
        s={1}
      />
      <Shape
        resourceId="heart"
        color={0xf00000}
        x={60}
        y={100}
        z={0}
        rx={0}
        ry={0}
        rz={Math.PI}
        s={1}
      />
      <Shape
        resourceId="circle"
        color={0x00f000}
        x={120}
        y={250}
        z={0}
        rx={0}
        ry={0}
        rz={0}
        s={1}
      />
      <Shape
        resourceId="fish"
        color={0x404040}
        x={-60}
        y={200}
        z={0}
        rx={0}
        ry={0}
        rz={0}
        s={1}
      />
      <Shape
        resourceId="smiley"
        x={-200}
        y={250}
        z={0}
        color={0xf000f0}
        rx={0}
        ry={0}
        rz={Math.PI}
        s={1}
      />
      <Shape
        resourceId="arc"
        color={0x804000}
        x={150}
        y={0}
        z={0}
        rx={0}
        ry={0}
        rz={0}
        s={1}
      />
      <Shape
        resourceId="spline"
        color={0x808080}
        x={-50}
        y={-100}
        z={0}
        rx={0}
        ry={0}
        rz={0}
        s={1}
      />
    </group>);
  }
}

export default Shapes;


================================================
FILE: src/examples/GeometryShapes/index.js
================================================
import React from 'react';

import * as THREE from 'three';
import Stats from 'stats.js';

import React3 from 'react-three-renderer';

import ExampleBase from '../ExampleBase';

import Resources from './Resources';

import Shapes from './Shapes';

class GeometryShapes extends ExampleBase {
  constructor(props, context) {
    super(props, context);

    this.cameraPosition = new THREE.Vector3(0, 150, 500);
    this.groupPosition = new THREE.Vector3(0, 50, 0);

    this.targetRotationOnMouseDown = 0;

    this.mouseX = 0;
    this.mouseXOnMouseDown = 0;
    this.targetRotation = 0;

    this.state = {
      ...this.state,
      groupRotation: new THREE.Euler(0, 0, 0),
    };
  }

  componentDidMount() {
    this.stats = new Stats();

    const container = this.refs.container;

    this.stats.domElement.style.position = 'absolute';
    this.stats.domElement.style.top = '0px';

    container.appendChild(this.stats.domElement);

    container.addEventListener('mousedown', this._onDocumentMouseDown, false);
    container.addEventListener('touchstart', this._onDocumentTouchStart, false);
    document.addEventListener('touchmove', this._onDocumentTouchMove, false);
  }

  componentWillUnmount() {
    const container = this.refs.container;

    container.removeEventListener('mousedown', this._onDocumentMouseDown, false);
    container.removeEventListener('touchstart', this._onDocumentTouchStart, false);
    document.removeEventListener('touchmove', this._onDocumentTouchMove, false);
    document.removeEventListener('mousemove', this._onDocumentMouseMove, false);
    document.removeEventListener('mouseup', this._onDocumentMouseUp, false);
    document.removeEventListener('mouseout', this._onDocumentMouseOut, false);

    delete this.stats;
  }

  _onDocumentMouseDown = (event) => {
    event.preventDefault();

    document.addEventListener('mousemove', this._onDocumentMouseMove, false);
    document.addEventListener('mouseup', this._onDocumentMouseUp, false);
    document.addEventListener('mouseout', this._onDocumentMouseOut, false);

    const {
      width,
    } = this.props;

    const windowHalfX = width / 2;

    this.mouseXOnMouseDown = event.clientX - windowHalfX;
    this.targetRotationOnMouseDown = this.targetRotation;
  };

  _onDocumentMouseMove = (event) => {
    const {
      width,
    } = this.props;

    const windowHalfX = width / 2;

    this.mouseX = event.clientX - windowHalfX;
    this.targetRotation = this.targetRotationOnMouseDown +
      (this.mouseX - this.mouseXOnMouseDown) * 0.02;
  };

  _onDocumentMouseUp = () => {
    document.removeEventListener('mousemove', this._onDocumentMouseMove, false);
    document.removeEventListener('mouseup', this._onDocumentMouseUp, false);
    document.removeEventListener('mouseout', this._onDocumentMouseOut, false);
  };

  _onDocumentMouseOut = () => {
    document.removeEventListener('mousemove', this._onDocumentMouseMove, false);
    document.removeEventListener('mouseup', this._onDocumentMouseUp, false);
    document.removeEventListener('mouseout', this._onDocumentMouseOut, false);
  };

  _onDocumentTouchStart = (event) => {
    if (event.touches.length === 1) {
      event.preventDefault();

      const {
        width,
      } = this.props;

      const windowHalfX = width / 2;

      this.mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
      this.targetRotationOnMouseDown = this.targetRotation;
    }
  };

  _onDocumentTouchMove = (event) => {
    if (event.touches.length === 1) {
      event.preventDefault();

      const {
        width,
      } = this.props;

      const windowHalfX = width / 2;

      this.mouseX = event.touches[0].pageX - windowHalfX;
      this.targetRotation = this.targetRotationOnMouseDown +
        (this.mouseX - this.mouseXOnMouseDown) * 0.05;
    }
  };

  _onAnimate = () => {
    this._onAnimateInternal();
  };

  _onAnimateInternal() {
    const groupRotationY = this.state.groupRotation.y;

    if (Math.abs(groupRotationY - this.targetRotation) > 0.0001) {
      this.setState({
        groupRotation: new THREE.Euler(0, groupRotationY +
          (this.targetRotation - groupRotationY) * 0.05, 0),
      });
    }

    this.stats.update();
  }

  render() {
    const {
      width,
      height,
    } = this.props;

    const {
      groupRotation,
    } = this.state;

    return (<div ref="container">
      <div
        style={{
          color: 'black',
          position: 'absolute',
          top: '10px',
          width: '100%',
          textAlign: 'center',
        }}
      >
        Simple procedurally generated 3D shapes<br/>
        Drag to spin
      </div>
      <React3
        width={width}
        height={height}
        antialias
        pixelRatio={window.devicePixelRatio}
        mainCamera="mainCamera"
        clearColor={0xf0f0f0}
        onAnimate={this._onAnimate}
      >
        <scene ref="scene">
          <perspectiveCamera
            name="mainCamera"
            ref="camera"
            fov={50}
            aspect={width / height}
            near={1}
            far={1000}

            position={this.cameraPosition}
          >
            <pointLight
              color={0xffffff}
              intensity={0.8}
            />
          </perspectiveCamera>
          <Resources/>
          <group
            position={this.groupPosition}
            rotation={groupRotation}
          >
            <Shapes/>
          </group>
        </scene>
      </React3>
    </div>);
  }
}

export default GeometryShapes;


================================================
FILE: src/examples/ManualRendering/Info.js
================================================
import React from 'react';

import PropTypes from 'prop-types';

class Info extends React.Component {
  static propTypes = {
    onUpdateColorButtonPress: PropTypes.func.isRequired,
    onRenderButtonPress: PropTypes.func.isRequired,
    onManualButtonPress: PropTypes.func.isRequired,
    forceManual: PropTypes.bool,
    cubeColor: PropTypes.number.isRequired,
  };

  constructor(props, context) {
    super(props, context);

    this.state = {
      colorButtonPressed: false,
    };
  }

  _onColorButtonPress = () => {
    this.props.onUpdateColorButtonPress();

    this.setState({
      colorButtonPressed: true,
    });
  };

  _onTriggerPress = () => {
    this.setState({
      colorButtonPressed: false,
    });

    this.props.onRenderButtonPress();
  };

  _manualButtonPress = () => {
    this.setState({
      colorButtonPressed: false,
    });

    this.props.onManualButtonPress();
  };

  render() {
    const {
      forceManual,
      cubeColor,
    } = this.props;

    const {
      colorButtonPressed,
    } = this.state;

    const triggerButtonStyle = {};

    if (colorButtonPressed && forceManual) {
      triggerButtonStyle.fontWeight = 'bold';
    }

    return (<div
      style={{
        position: 'absolute',
        textAlign: 'center',
        top: 0,
        width: '100%',
        padding: 5,
        color: 'white',
        zIndex: 100,
      }}
    >
      <h2>Manual rendering</h2>
      If automatic rendering is off, the canvas will re-render only
      when you press the "Trigger render" button.<br/>
      This way you can save battery life
      or have finer controls for rendering.<br/>
      Check your CPU profiler with automatic rendering on/off :)<br/>
      <br/>
      <button onClick={this._onColorButtonPress}>Update cube color state</button>
      <span
        style={{
          width: 15,
          minHeight: 15,
          marginLeft: 5,
          display: 'inline-block',
          background: `rgb(
            ${(cubeColor >> 16 & 255)},
            ${(cubeColor >> 8 & 255)},
            ${(cubeColor & 255)})`,
        }}
      >&nbsp;</span>
      <br/>
      <button
        onClick={this._onTriggerPress}
        style={triggerButtonStyle}
        disabled={!forceManual}
      >{colorButtonPressed && forceManual ? 'TRIGGER RENDER' : 'Trigger render'}
      </button>
      <br/>
      <button onClick={this._manualButtonPress}>
        Turn automatic rendering {forceManual ? 'ON' : 'OFF'}
      </button>
    </div>);
  }
}

export default Info;


================================================
FILE: src/examples/ManualRendering/index.js
================================================
import React from 'react';
import React3 from 'react-three-renderer';
import * as THREE from 'three';

import ExampleBase from '../ExampleBase';

import Info from './Info';

class Manual extends ExampleBase {
  constructor(props, context) {
    super(props, context);

    this.cameraPosition = new THREE.Vector3(0, 0, 5);

    this._onManualRenderTriggerCreated = (renderTrigger) => {
      // assign to variable to be able to reuse the trigger
      this._renderTrigger = renderTrigger;
    };

    this.state = {
      cubeColor: 0x00ff00,
      forceManual: true,
    };
  }

  componentDidMount() {
    // render one frame to show initial scene
    this._renderTrigger();

    setTimeout(() => {
      // this should not be visible!
      this.setState({
        cubeColor: 0x0000ff,
      });
    }, 20);

    setTimeout(() => {
      // render again after updating color
      this.setState({
        cubeColor: 0xff0000,
      }, () => {
        this._renderTrigger();
      });
    }, 1000);
  }

  _onUpdateColorButtonPress = () => {
    this.setState({
      cubeColor: Math.floor(Math.random() * 0xffffff),
    });
  };

  _onRenderButtonPress = () => {
    this._renderTrigger();
  };

  _onManualButtonPress = () => {
    this.setState({
      forceManual: !this.state.forceManual,
    });
  };

  render() {
    const {
      width,
      height,
    } = this.props;

    const {
      forceManual,
      cubeColor,
    } = this.state;

    return (<div>
      <div>
        <Info
          onUpdateColorButtonPress={this._onUpdateColorButtonPress}
          onRenderButtonPress={this._onRenderButtonPress}
          onManualButtonPress={this._onManualButtonPress}
          forceManual={forceManual}
          cubeColor={cubeColor}
        />
      </div>
      <React3
        width={width}
        height={height}

        forceManualRender={forceManual}
        onManualRenderTriggerCreated={this._onManualRenderTriggerCreated}

        mainCamera="camera"
      >
        <scene>
          <perspectiveCamera
            name="camera"
            fov={75}
            aspect={width / height}
            near={0.1}
            far={1000}

            position={this.cameraPosition}
          />
          <mesh>
            <boxGeometry
              width={1}
              height={1}
              depth={1}
            />
            <meshBasicMaterial
              color={cubeColor}
            />
          </mesh>
        </scene>
      </React3></div>);
  }
}

export default Manual;


================================================
FILE: src/examples/Physics/index.js
================================================
import React from 'react';
import React3 from 'react-three-renderer';
import * as THREE from 'three';
import CANNON from 'cannon/src/Cannon';

import Stats from 'stats.js';

import ExampleBase from '../ExampleBase';

class Physics extends ExampleBase {
  constructor(props, context) {
    super(props, context);

    const world = new CANNON.World();
    this.world = world;
    world.gravity.set(0, 0, 0);
    world.broadphase = new CANNON.NaiveBroadphase();
    world.solver.iterations = 10;
    const shape = new CANNON.Box(new CANNON.Vec3(1, 1, 1));
    const mass = 1;
    const body = new CANNON.Body({
      mass,
    });
    body.addShape(shape);
    body.angularVelocity.set(0, 10, 0);
    body.angularDamping = 0.5;
    world.addBody(body);

    this._onMouseDown = () => {
      body.angularVelocity.y += 5;
    };

    this.cameraPosition = new THREE.Vector3(0, 0, 5);

    const timeStep = 1 / 60;

    const updatePhysics = () => {
      // Step the physics world
      world.step(timeStep);
      // Copy coordinates from Cannon.js to Three.js

      this.setState({
        // need to call new THREE.* in order to ensure an update goes through
        meshPosition: new THREE.Vector3().copy(body.position),
        meshQuaternion: new THREE.Quaternion().copy(body.quaternion),
      });
    };

    this._onAnimate = () => {
      updatePhysics();

      this.stats.update();
    };

    this.state = {
      meshPosition: new THREE.Vector3(),
      meshQuaternion: new THREE.Quaternion(),
    };
  }

  componentWillUnmount() {
    delete this.world;

    delete this.stats;
  }

  componentDidMount() {
    const {
      container,
      } = this.refs;

    this.stats = new Stats();

    this.stats.domElement.style.position = 'absolute';
    this.stats.domElement.style.top = '0px';

    container.appendChild(this.stats.domElement);
  }

  render() {
    const {
      width,
      height,
      } = this.props;

    const {
      meshPosition,
      meshQuaternion,
      } = this.state;

    return (<div
      ref="container"

      onMouseDown={this._onMouseDown}
    ><React3
      antialias
      mainCamera="camera"
      width={width}
      height={height}

      onAnimate={this._onAnimate}
    >
      <scene>
        <perspectiveCamera
          name="camera"
          fov={75}
          aspect={width / height}
          near={1}
          far={100}

          position={this.cameraPosition}
        />
        <mesh
          position={meshPosition}
          quaternion={meshQuaternion}
        >
          <boxGeometry
            width={2}
            height={2}
            depth={2}
          />
          <meshBasicMaterial
            color={0x00ff00}
            wireframe
          />
        </mesh>
      </scene>
    </React3>
    </div>);
  }
}

export default Physics;


================================================
FILE: src/examples/Physics/mousePick/PickableMesh.js
================================================
import React from 'react';
import * as THREE from 'three';

import PropTypes from 'prop-types';

class PickableMesh extends React.Component {
  static propTypes = {
    position: PropTypes.instanceOf(THREE.Vector3).isRequired,
    quaternion: PropTypes.instanceOf(THREE.Quaternion).isRequired,
    meshes: PropTypes.arrayOf(PropTypes.instanceOf(THREE.Mesh)).isRequired,
    bodyIndex: PropTypes.number.isRequired,

    onMouseDown: PropTypes.func.isRequired,
  };

  componentDidMount() {
    const {
      mesh,
    } = this.refs;

    const {
      bodyIndex,
      meshes,
    } = this.props;

    mesh.userData._bodyIndex = bodyIndex;

    meshes.push(mesh);
  }

  componentWillUnmount() {
    const {
      mesh,
    } = this.refs;

    const {
      meshes,
    } = this.props;

    meshes.splice(meshes.indexOf(mesh), 1);
  }

  _onMouseDown = (event, intersection) => {
    event.preventDefault();

    this.props.onMouseDown(this.refs.mesh.userData._bodyIndex, intersection);
  };

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

    return (<mesh
      position={position}
      quaternion={quaternion}

      ref="mesh"

      castShadow

      onMouseDown={this._onMouseDown}
    >
      <geometryResource
        resourceId="cubeGeo"
      />
      <materialResource
        resourceId="cubeMaterial"
      />
    </mesh>);
  }
}

export default PickableMesh;


================================================
FILE: src/examples/Physics/mousePick.js
================================================
import React from 'react';
import React3 from 'react-three-renderer';
import * as THREE from 'three';
import CANNON from 'cannon/src/Cannon';

import MouseInput from '../inputs/MouseInput';

import ExampleBase from '../ExampleBase';

import Stats from 'stats.js';

import PickableMesh from './mousePick/PickableMesh';

const backVector = new THREE.Vector3(0, 0, -1);
const dragPlane = new THREE.Plane();

class PhysicsMousePick extends ExampleBase {
  constructor(props, context) {
    super(props, context);

    const N = 100;

    this._raycaster = new THREE.Raycaster();

    this.fog = new THREE.Fog(0x001525, 10, 40);

    const d = 20;

    this.lightPosition = new THREE.Vector3(d, d, d);
    this.lightTarget = new THREE.Vector3(0, 0, 0);
    this.groundQuaternion = new THREE.Quaternion()
      .setFromAxisAngle(new THREE.Vector3(1, 0, 0), -Math.PI / 2);
    this.cameraPosition = new THREE.Vector3(10, 2, 0);
    this.cameraQuaternion = new THREE.Quaternion()
      .setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2);

    const world = new CANNON.World();

    const bodies = [];
    const meshRefs = [];

    let constrainedBody;
    let pivot;

    const initCannon = () => {
      world.quatNormalizeSkip = 0;
      world.quatNormalizeFast = false;

      world.gravity.set(0, -10, 0);
      world.broadphase = new CANNON.NaiveBroadphase();

      const mass = 5;

      const boxShape = new CANNON.Box(new CANNON.Vec3(0.25, 0.25, 0.25));

      for (let i = 0; i < N; ++i) {
        const boxBody = new CANNON.Body({
          mass,
        });

        boxBody.addShape(boxShape);
        boxBody.position.set(
          -2.5 + Math.random() * 5,
          2.5 + Math.random() * 5,
          -2.5 + Math.random() * 5);
        world.addBody(boxBody);
        bodies.push(boxBody);

        meshRefs.push((mesh) => {
          if (mesh) {
            mesh.userData._bodyIndex = i;

            this.meshes.push(mesh);
          }
        });
      }

      const groundShape = new CANNON.Plane();
      const groundBody = new CANNON.Body({ mass: 0 });

      groundBody.addShape(groundShape);
      groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2);

      // WAIT A MINUTE I CAN CREATE A REACT RENDERER FOR CANNON
      // patience is a virtue
      // breathe in breathe out breathe in breathe out
      // let's finish this one first

      world.addBody(groundBody);

      const shape = new CANNON.Sphere(0.1);
      const jointBody = new CANNON.Body({ mass: 0 });
      jointBody.addShape(shape);
      jointBody.collisionFilterGroup = 0;
      jointBody.collisionFilterMask = 0;

      world.addBody(jointBody);

      this.jointBody = jointBody;
    };

    initCannon();

    const timeStep = 1 / 60;
    const updatePhysics = () => {
      // Step the physics world
      world.step(timeStep);
    };

    const _getMeshStates = () => bodies
      .map(({ position, quaternion }, bodyIndex) => ({
        position: new THREE.Vector3().copy(position),
        quaternion: new THREE.Quaternion().copy(quaternion),
        ref: meshRefs[bodyIndex],
      }));

    this._onAnimate = () => {
      updatePhysics();

      this.setState({
        meshStates: _getMeshStates(),
      });

      this.stats.update();
    };

    this._addMouseConstraint = ({ x, y, z }, bodyIndex) => {
      // The cannon body constrained by the mouse joint
      constrainedBody = bodies[bodyIndex];
      // Vector to the clicked point, relative to the body
      const v1 = new CANNON.Vec3(x, y, z).vsub(constrainedBody.position);
      // Apply anti-quaternion to vector to transform it into the local body coordinate system
      const antiRot = constrainedBody.quaternion.inverse();
      pivot = antiRot.vmult(v1); // pivot is not in local body coordinates
      // Move the cannon click marker particle to the click position
      this.jointBody.position.set(x, y, z);
      // Create a new constraint
      // The pivot for the jointBody is zero
      this.mouseConstraint = new CANNON
        .PointToPointConstraint(
        constrainedBody,
        pivot,
        this.jointBody,
        new CANNON.Vec3(0, 0, 0)
      );
      // Add the t to world
      world.addConstraint(this.mouseConstraint);

      this.world = world;
    };

    this.state = {
      clickMarkerVisible: false,
      clickMarkerPosition: new THREE.Vector3(),

      meshStates: _getMeshStates(),
    };

    this.meshes = [];
  }

  _setClickMarker(x, y, z) {
    return {
      clickMarkerPosition: new THREE.Vector3(x, y, z),
      clickMarkerVisible: true,
    };
  }

  componentDidMount() {
    const {
      mouseInput,
      container,
    } = this.refs;

    this.stats = new Stats();

    this.stats.domElement.style.position = 'absolute';
    this.stats.domElement.style.top = '0px';

    container.appendChild(this.stats.domElement);

    if (!mouseInput.isReady()) {
      const {
        scene,
        camera,
      } = this.refs;

      mouseInput.ready(scene, container, camera);
      mouseInput.restrictIntersections(this.meshes);
      mouseInput.setActive(false);
    }
  }

  componentDidUpdate(newProps) {
    const {
      mouseInput,
    } = this.refs;

    const {
      width,
      height,
    } = this.props;

    if (width !== newProps.width || height !== newProps.height) {
      mouseInput.containerResized();
    }
  }

  componentWillUnmount() {
    delete this.world;
    delete this.stats;
  }

  _onMeshMouseDown = (bodyIndex, intersection) => {
    const {
      camera,
    } = this.refs;

    const pos = intersection.point;

    this.setState({
      // Set marker on contact point
      ...this._setClickMarker(pos.x, pos.y, pos.z),
    });

    dragPlane.setFromNormalAndCoplanarPoint(backVector.clone()
      .applyQuaternion(camera.quaternion), pos);

    this._addMouseConstraint(pos, bodyIndex);

    window.addEventListener('mousemove', this._onMouseMove, false);
    window.addEventListener('mouseup', this._onMouseUp, false);
  };

  _onMouseUp = () => {
    window.removeEventListener('mousemove', this._onMouseMove, false);
    window.removeEventListener('mouseup', this._onMouseUp, false);

    this.setState({
      clickMarkerVisible: false,
    });

    this.world.removeConstraint(this.mouseConstraint);
    this.mouseConstraint = false;
  };

  _onMouseMove = (event) => {
    const {
      mouseInput,
    } = this.refs;

    const ray:THREE.Ray = mouseInput.getCameraRay(new THREE.Vector2(event.clientX, event.clientY));

    const pos = dragPlane.intersectLine(
      new THREE.Line3(ray.origin, ray.origin
        .clone()
        .add(ray.direction
          .clone()
          .multiplyScalar(10000))));

    if (pos) {
      this.setState({
        ... this._setClickMarker(pos.x, pos.y, pos.z),
      });

      // Move the joint body to a new position
      this.jointBody.position.set(pos.x, pos.y, pos.z);
      this.mouseConstraint.update();
    }
  };

  render() {
    const {
      width,
      height,
    } = this.props;

    const {
      clickMarkerVisible,
      clickMarkerPosition,

      meshStates,
    } = this.state;

    const d = 20;

    const cubeMeshes = meshStates.map(({ position, quaternion }, i) =>
      (<PickableMesh
        key={i}

        position={position}
        quaternion={quaternion}

        bodyIndex={i}

        meshes={this.meshes}

        onMouseDown={this._onMeshMouseDown}
      />));

    return (<div
      ref="container"
    >
      <React3
        antialias
        mainCamera="camera"
        width={width}
        height={height}

        onAnimate={this._onAnimate}

        clearColor={this.fog.color}

        gammaInput
        gammaOutput
        shadowMapEnabled
      >
        <module
          ref="mouseInput"
          descriptor={MouseInput}
        />
        <resources>
          <boxGeometry
            resourceId="cubeGeo"

            width={0.5}
            height={0.5}
            depth={0.5}

            widthSegments={10}
            heightSegments={10}
          />
          <meshPhongMaterial
            resourceId="cubeMaterial"

            color={0x888888}
          />
        </resources>
        <scene
          ref="scene"
          fog={this.fog}
        >
          <perspectiveCamera
            name="camera"
            fov={30}
            aspect={width / height}
            near={0.5}
            far={10000}

            position={this.cameraPosition}
            quaternion={this.cameraQuaternion}

            ref="camera"
          />
          <ambientLight
            color={0x666666}
          />
          <directionalLight
            color={0xffffff}
            intensity={1.75}

            castShadow

            shadowMapWidth={1024}
            shadowMapHeight={1024}

            shadowCameraLeft={-d}
            shadowCameraRight={d}
            shadowCameraTop={d}
            shadowCameraBottom={-d}

            shadowCameraFar={3 * d}
            shadowCameraNear={d}

            position={this.lightPosition}
            lookAt={this.lightTarget}
          />
          <mesh
            castShadow
            receiveShadow

            quaternion={this.groundQuaternion}
          >
            <planeBufferGeometry
              width={100}
              height={100}
              widthSegments={1}
              heightSegments={1}
            />
            <meshLambertMaterial
              color={0x777777}
            />
          </mesh>
          {cubeMeshes}
          <mesh // click marker
            visible={clickMarkerVisible}

            position={clickMarkerPosition}
          >
            <sphereGeometry
              radius={0.2}
              widthSegments={8}
              heightSegments={8}
            />
            <meshLambertMaterial
              color={0x772211}
            />
          </mesh>
        </scene>

      </React3>
    </div>);
  }
}

export default PhysicsMousePick;


================================================
FILE: src/examples/Simple/index.js
================================================
import React from 'react';
import React3 from 'react-three-renderer';
import * as THREE from 'three';

class Simple extends React.Component {
  static propTypes = {
    width: React.PropTypes.number.isRequired,
    height: React.PropTypes.number.isRequired,
  };

  constructor(props, context) {
    super(props, context);

    this.cameraPosition = new THREE.Vector3(0, 0, 5);

    // construct the position vector here, because if we use 'new' within render,
    // React will think that things have changed when they have not.

    this.state = {
      cubeRotation: new THREE.Euler(),
    };

    this._onAnimate = () => {
      // we will get this callback every frame

      // pretend cubeRotation is immutable.
      // this helps with updates and pure rendering.
      // React will be sure that the rotation has now updated.
      this.setState({
        cubeRotation: new THREE.Euler(
          this.state.cubeRotation.x + 0.1,
          this.state.cubeRotation.y + 0.1,
          0
        ),
      });
    };
  }

  render() {
    const {
      width,
      height,
    } = this.props;

    // or you can use:
    // width = window.innerWidth
    // height = window.innerHeight

    return (<React3
      mainCamera="camera" // this points to the perspectiveCamera below
      width={width}
      height={height}

      onAnimate={this._onAnimate}
    >
      <scene>
        <perspectiveCamera
          name="camera"
          fov={75}
          aspect={width / height}
          near={0.1}
          far={1000}

          position={this.cameraPosition}
        />
        <mesh
          rotation={this.state.cubeRotation}
        >
          <boxGeometry
            width={1}
            height={1}
            depth={1}
          />
          <meshBasicMaterial
            color={0x00ff00}
          />
        </mesh>
      </scene>
    </React3>);
  }
}

export default Simple;


================================================
FILE: src/examples/WebGLCameraExample/Info.js
================================================
import React from 'react';

import PropTypes from 'prop-types';

class Info extends React.Component {
  static propTypes = {
    pause: PropTypes.func.isRequired,
    frame: PropTypes.func.isRequired,
  };

  render() {
    return (<div
      style={{
        position: 'absolute',
        textAlign: 'center',
        top: 0,
        width: '100%',
        padding: 5,
        color: 'white',
        zIndex: 100,
      }}
    >
      <a
        href="http://threejs.org"
        style={{
          color: '#0080ff',
        }}
      >three.js</a> - cameras<br/>
      <b
        style={{
          color: 'lightgreen',
        }}
      >O</b> orthographic &nbsp;
      <b
        style={{
          color: 'lightgreen',
        }}
      >P</b> perspective <br/>
      <button onClick={this.props.pause}>Pause</button>
      <button onClick={this.props.frame}>Frame</button>
    </div>);
  }
}

export default Info;


================================================
FILE: src/examples/WebGLCameraExample/PointCloud.js
================================================
import React from 'react';
import * as THREE from 'three';

class PointCloud extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.pointCloudVertices = [];

    for (let i = 0; i < 10000; i++) {
      const vertex = new THREE.Vector3();

      vertex.x = THREE.Math.randFloatSpread(2000);
      vertex.y = THREE.Math.randFloatSpread(2000);
      vertex.z = THREE.Math.randFloatSpread(2000);

      this.pointCloudVertices.push(vertex);
    }
  }

  shouldComponentUpdate() {
    return false;
  }

  render() {
    return (<points>
      <geometry vertices={this.pointCloudVertices}/>
      <pointsMaterial
        color={0x888888}
      />
    </points>);
  }
}

export default PointCloud;


================================================
FILE: src/examples/WebGLCameraExample/index.js
================================================
import React from 'react';
import ReactDOM from 'react-dom';

import * as THREE from 'three';
import ExampleBase from './../ExampleBase';

import React3 from 'react-three-renderer';

import Info from './Info';

import PointCloud from './PointCloud';

import TrackballControls from '../../ref/trackball';

const perspectiveCameraName = 'perspectiveCamera';
const orthographicCameraName = 'orthographicCamera';
const mainCameraName = 'mainCamera';

const perspectiveCameraRotation = new THREE.Euler(0, Math.PI, 0);
const orthographicCameraRotation = new THREE.Euler(0, Math.PI, 0);

const spherePosition = new THREE.Vector3(0, 0, 150);

class WebGLCameraExample extends ExampleBase {
  constructor(props, context) {
    super(props, context);

    const r = Date.now() * 0.0005;

    this.state = {
      ... this.state,
      meshPosition: new THREE.Vector3(Math.cos(r), Math.sin(r), Math.sin(r)).multiplyScalar(700),
      childPosition: new THREE.Vector3(70 * Math.cos(2 * r), 150, 70 * Math.sin(r)),
      activeCameraName: perspectiveCameraName,
      paused: false,
      mainCameraPosition: new THREE.Vector3(0, 0, 2500),
    };
  }

  componentDidMount() {
    document.addEventListener('keydown', this._onKeyDown, false);

    const controls = new TrackballControls(this.refs.mainCamera,
      ReactDOM.findDOMNode(this.refs.react3));

    controls.rotateSpeed = 1.0;
    controls.zoomSpeed = 1.2;
    controls.panSpeed = 0.8;

    controls.noZoom = false;
    controls.noPan = false;

    controls.staticMoving = true;
    controls.dynamicDampingFactor = 0.3;

    controls.addEventListener('change', () => {
      this.setState({
        mainCameraPosition: this.refs.mainCamera.position,
      });
    });

    this.controls = controls;
  }

  componentWillUnmount() {
    document.removeEventListener('keydown', this._onKeyDown, false);

    this.controls.dispose();
    delete this.controls;
  }

  _onKeyDown = (event) => {
    switch (event.keyCode) {
      default:
        break;
      case 79: // O
        this.setState({
          activeCameraName: orthographicCameraName,
        });
        break;
      case 80: // P
        this.setState({
          activeCameraName: perspectiveCameraName,
        });

        break;
    }
  };

  _onAnimate = () => {
    this.controls.update();

    if (this.state.paused) {
      return;
    }

    const r = Date.now() * 0.0005;

    this.setState({
      r,
      meshPosition: new THREE.Vector3(Math.cos(r), Math.sin(r), Math.sin(r)).multiplyScalar(700),
      childPosition: new THREE.Vector3(70 * Math.cos(2 * r), 150, 70 * Math.sin(r)),
    });
  };

  _pause = () => {
    this.setState({
      paused: !this.state.paused,
    });
  };

  _frame = () => {
    this.setState({
      paused: false,
    }, () => {
      this._onAnimate();
      this.setState({
        paused: true,
      });
    });
  };

  render() {
    const {
      width,
      height,
    } = this.props;

    const {
      meshPosition,
      childPosition,
      r,
    } = this.state;

    const aspectRatio = 0.5 * width / height;

    return (<div>
      <Info
        pause={this._pause}
        frame={this._frame}
      />
      <React3
        ref="react3"
        width={width}
        height={height}
        antialias
        onAnimate={this._onAnimate}
      >
        <viewport
          x={0}
          y={0}
          width={width / 2}
          height={height}
          cameraName={this.state.activeCameraName}
        />
        <viewport
          x={width / 2}
          y={0}
          width={width / 2}
          height={height}
          cameraName={mainCameraName}
        />
        <scene>
          <perspectiveCamera
            ref="mainCamera"
            name={mainCameraName}
            fov={50}
            aspect={aspectRatio}
            near={1}
            far={10000}
            position={this.state.mainCameraPosition}
          />
          <object3D
            lookAt={meshPosition}
          >
            <perspectiveCamera
              name={perspectiveCameraName}
              fov={35 + 30 * Math.sin(0.5 * r)}
              aspect={aspectRatio}
              near={150}
              far={meshPosition.length()}
              rotation={perspectiveCameraRotation}
            />
            <orthographicCamera
              name={orthographicCameraName}
              left={0.5 * width / -2}
              right={0.5 * width / 2}
              top={height / 2}
              bottom={height / -2}
              near={150}
              far={meshPosition.length()}
              rotation={orthographicCameraRotation}
            />
            <mesh
              position={spherePosition}
            >
              <sphereGeometry
                radius={5}
                widthSegments={16}
                heightSegments={8}
              />
              <meshBasicMaterial
                color={0x0000ff}
                wireframe
              />
            </mesh>
          </object3D>
          <cameraHelper
            cameraName={this.state.activeCameraName}
          />
          <object3D
            position={meshPosition}
          >
            <mesh>
              <sphereGeometry
                radius={100}
                widthSegments={16}
                heightSegments={8}
              />
              <meshBasicMaterial
                color={0xffffff}
                wireframe
              />
            </mesh>
            <mesh
              position={childPosition}
            >
              <sphereGeometry
                radius={50}
                widthSegments={16}
                heightSegments={8}
              />
              <meshBasicMaterial
                color={0x00ff00}
                wireframe
              />
            </mesh>
          </object3D>
          {
            <PointCloud/>
          }
        </scene>
      </React3>
    </div>);
  }
}

export default WebGLCameraExample;


================================================
FILE: src/examples/inputs/MouseInput.js
================================================
import React3 from 'react-three-renderer';
import * as THREE from 'three';
import ReactUpdates from 'react-dom/lib/ReactUpdates';

import SyntheticMouseEvent from 'react-dom/lib/SyntheticMouseEvent';

import Module from 'react-three-renderer/lib/Module';

import PropTypes from 'react/lib/ReactPropTypes';

const tempVector2 = new THREE.Vector2();

const listenerCallbackNames = {
  mousedown: 'onMouseDown',
  mouseup: 'onMouseUp',
};

const mouseEvents = [
  'onMouseEnter',
  'onMouseLeave',
  'onMouseDown',
  'onMouseUp',
  'onClick',
];

const boolProps = {
  ignorePointerEvents: false,
};

class MouseInput extends Module {
  constructor() {
    super();

    this._isReady = false;
    this._active = true;
    this._restrictIntersections = false;
    this._objectsToIntersect = null;

    this._restrictedIntersectionRecursive = false;

    this._patchedDescriptors = [];
  }

  // noinspection JSUnusedGlobalSymbols
  setup(react3RendererInstance) {
    super.setup(react3RendererInstance);

    const Object3DDescriptor = react3RendererInstance.threeElementDescriptors.object3D.constructor;

    Object.values(react3RendererInstance.threeElementDescriptors).forEach(elementDescriptor => {
      if (elementDescriptor instanceof Object3DDescriptor) {
        mouseEvents.forEach(eventName => {
          elementDescriptor.hasEvent(eventName);
        });

        Object.keys(boolProps).forEach(propName => {
          elementDescriptor.hasProp(propName, {
            type: PropTypes.bool,
            update(threeObject, value, hasProp) {
              if (hasProp) {
                threeObject.userData[propName] = value;
              } else {
                threeObject.userData[propName] = boolProps[propName];
              }
            },
            default: boolProps[propName],
          });
        });

        this._patchedDescriptors.push(elementDescriptor);
      }
    });
  }

  isReady() {
    return this._isReady;
  }

  setActive(active) {
    this._active = active;
  }

  restrictIntersections(objects, recursive = false) {
    this._restrictIntersections = true;
    this._objectsToIntersect = objects;

    this._restrictedIntersectionRecursive = recursive;
  }

  ready(scene, container, camera) {
    this._isReady = true;

    this._scene = scene;
    this._container = container;
    this._camera = camera;

    this._raycaster = new THREE.Raycaster();
    this._mouse = new THREE.Vector2();

    this._onMouseMove = (event) => {
      this._mouse.set(event.clientX, event.clientY);

      if (!this._active) {
        this._updateEnterLeave();
      }
    };

    this._containerRect = this._container.getBoundingClientRect();

    this._hoverObjectMap = {};

    document.addEventListener('mousemove', this._onMouseMove, false);

    this._intersectionsForClick = null;

    this._caughtListenersCleanupFunctions = [];

    Object.keys(listenerCallbackNames).forEach(eventName => {
      let boundListener;

      const listenerCallbackName = listenerCallbackNames[eventName];
      switch (eventName) {
        case 'mousedown':
          boundListener = this._onMouseDown.bind(this, listenerCallbackName);
          break;
        case 'mouseup':
          boundListener = this._onMouseUp.bind(this, listenerCallbackName);
          break;
        default:
          break;
      }

      if (boundListener) {
        container.addEventListener(eventName, boundListener, true);

        this._caughtListenersCleanupFunctions.push(() => {
          container.removeEventListener(eventName, boundListener, true);
        });
      }
    });
  }

  _onMouseDown = (callbackName, mouseEvent) => {
    ReactUpdates.batchedUpdates(() => {
      const {
        event,
        intersections,
      } = this._intersectAndDispatch(callbackName, mouseEvent);

      if (event.isDefaultPrevented() || event.isPropagationStopped()) {
        this._intersectionsForClick = null;
      } else {
        this._intersectionsForClick = intersections;
      }
    });
  };

  _onMouseUp = (callbackName, mouseEvent) => {
    ReactUpdates.batchedUpdates(() => {
      const {
        event,
        intersections,
      } = this._intersectAndDispatch(callbackName, mouseEvent);

      if (!(event.isDefaultPrevented() || event.isPropagationStopped())) {
        if (this._intersectionsForClick === null) {
          return;
        }

        // intersect current intersections with the intersections for click
        //   call xzibit ASAP we have a good one son
        //     it wasn't that good

        const intersectionUUIDMap = this._intersectionsForClick.reduce((map, intersection) => {
          map[intersection.object.uuid] = intersection;

          return map;
        }, {});

        for (let i = 0; i < intersections.length; ++i) {
          if (event.isDefaultPrevented() || event.isPropagationStopped()) {
            return;
          }

          const intersection = intersections[i];

          const object = intersection.object;

          const uuid = object.uuid;

          if (intersectionUUIDMap[uuid]) {
            // oh boy oh boy here we go, we got a clicker

            React3.eventDispatcher
              .dispatchEvent(object, 'onClick',
                this._createSyntheticMouseEvent('click', event), intersection);
          }
        }
      }
    });

    this._intersectionsForClick = null;
  };

  _createSyntheticMouseEvent(eventType, prototype) {
    return SyntheticMouseEvent.getPooled(null, null,
      new MouseEvent(eventType, prototype), prototype.target);
  }

  _intersectAndDispatch(callbackName, mouseEvent) {
    const event = SyntheticMouseEvent.getPooled(null, null, mouseEvent, mouseEvent.target);

    const intersections = this._getIntersections(tempVector2.set(event.clientX, event.clientY));

    ReactUpdates.batchedUpdates(() => {
      for (let i = 0; i < intersections.length; ++i) {
        const intersection = intersections[i];

        if (event.isDefaultPrevented() || event.isPropagationStopped()) {
          return;
        }

        const object = intersection.object;

        React3.eventDispatcher.dispatchEvent(object, callbackName, event, intersection);
      }
    });

    return {
      event,
      intersections,
    };
  }

  _getIntersections(mouseCoords) {
    const relativeMouseCoords = this._getRelativeMouseCoords(mouseCoords);

    this._raycaster.setFromCamera(relativeMouseCoords, this._camera);

    if (this._restrictIntersections) {
      return this._raycaster.intersectObjects(this._objectsToIntersect,
        this._restrictedIntersectionRecursive);
    }

    return this._raycaster.intersectObject(this._scene, true);
  }

  // noinspection JSUnusedGlobalSymbols
  /**
   *
   * @param {THREE.Vector2} mouseCoords usually an event's clientX and clientY
   * @returns {THREE.Ray}
   */
  getCameraRay(mouseCoords) {
    const relativeMouseCoords = this._getRelativeMouseCoords(mouseCoords);

    const originalRay = this._raycaster.ray.clone();

    this._raycaster.setFromCamera(relativeMouseCoords, this._camera);

    const resultRay = this._raycaster.ray.clone();

    this._raycaster.ray.copy(originalRay);

    return resultRay;
  }

  // noinspection JSUnusedGlobalSymbols
  intersectObject(mouseCoords, object, recursive = false) {
    const relativeMouseCoords = this._getRelativeMouseCoords(mouseCoords);

    const originalRay = this._raycaster.ray.clone();

    this._raycaster.setFromCamera(relativeMouseCoords, this._camera);

    const intersections = this._raycaster.intersectObject(object, recursive);

    this._raycaster.ray.copy(originalRay);

    return intersections;
  }

  containerResized() {
    this._containerRect = this._container.getBoundingClientRect();
  }

  update() {
    if (!this._isReady) {
      return;
    }

    if (this._active) {
      this._updateEnterLeave();
    }
  }

  _updateEnterLeave() {
    const intersections = this._getIntersections(this._mouse);

    const hoverMapToUpdate = {
      ...this._hoverObjectMap,
    };

    const mouseEnterEvent = this._createSyntheticMouseEvent('mouseEnter', {
      target: this._container,
      clientX: this._mouse.x,
      clientY: this._mouse.y,
    });

    // find first intersection that does not ignore pointer events
    for (let depth = 0; depth < intersections.length; ++depth) {
      const intersection = intersections[depth];
      const object = intersection.object;

      if (object.userData && object.userData.ignorePointerEvents) {
        continue;
      }

      const uuid = object.uuid;

      if (this._hoverObjectMap[uuid]) {
        delete hoverMapToUpdate[uuid];

        // just update that intersection
        this._hoverObjectMap[uuid].intersection = intersection;
      } else {
        this._hoverObjectMap[uuid] = {
          object,
          intersection,
        };

        if (!(mouseEnterEvent.isDefaultPrevented() || mouseEnterEvent.isPropagationStopped())) {
          React3.eventDispatcher.dispatchEvent(object, 'onMouseEnter',
            mouseEnterEvent, intersection, depth);
        }
      }

      // we have found the first solid intersection, don't go further
      break;
    }

    const mouseLeaveEvent = this._createSyntheticMouseEvent('mouseLeave', {
      target: this._container,
      clientX: this._mouse.x,
      clientY: this._mouse.y,
    });

    // delete all unseen uuids in hover map
    const unseenUUIDs = Object.keys(hoverMapToUpdate);

    for (let i = 0; i < unseenUUIDs.length; ++i) {
      const uuid = unseenUUIDs[i];

      if (!(mouseLeaveEvent.isDefaultPrevented() || mouseLeaveEvent.isPropagationStopped())) {
        React3.eventDispatcher.dispatchEvent(this._hoverObjectMap[uuid].object,
          'onMouseLeave', mouseLeaveEvent);
      }

      delete this._hoverObjectMap[uuid];
    }
  }

  _getRelativeMouseCoords(screenMouseCoords) {
    const containerRect = this._containerRect;

    const relativeMouseCoords = screenMouseCoords.clone()
      .sub(tempVector2.set(containerRect.left, containerRect.top))
      .divide(tempVector2.set(containerRect.width, containerRect.height));

    // mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    // mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

    relativeMouseCoords.x = relativeMouseCoords.x * 2 - 1;
    relativeMouseCoords.y = -relativeMouseCoords.y * 2 + 1;

    return relativeMouseCoords;
  }

  // noinspection JSUnusedGlobalSymbols
  dispose() {
    document.removeEventListener('mousemove', this._onMouseMove, false);

    this._caughtListenersCleanupFunctions.forEach(cleanupFunction => cleanupFunction());
    delete this._caughtListenersCleanupFunctions;

    delete this._onMouseMove;

    this._patchedDescriptors.forEach(elementDescriptor => {
      const allProps = Object.keys(boolProps)
        .concat(mouseEvents);

      allProps.forEach(propName => {
        elementDescriptor.removeProp(propName);
      });
    });
  }
}

export default MouseInput;


================================================
FILE: src/index.jsx
================================================
/* eslint-disable no-undef */

import React from 'react';
import ReactDOM from 'react-dom';
import {
  HashRouter as Router,
  Route,
} from 'react-router-dom';
import Perf from 'react-addons-perf';
import createHashHistory from 'history/createHashHistory';

import ExampleBrowser from './examples/ExampleBrowser';

const customHistory = createHashHistory();
window.Perf = Perf;

ReactDOM.render(
  <Router history={customHistory}>
    <div>
      <Route path="/:slug?" component={ExampleBrowser} />
    </div>
  </Router>,
  document.getElementById('content'),
);


================================================
FILE: src/ref/trackball.js
================================================
/* eslint-disable */

import * as THREE from 'three';

/**
 * @author Eberhard Graether / http://egraether.com/
 * @author Mark Lundin  / http://mark-lundin.com
 * @author Simone Manini / http://daron1337.github.io
 * @author Luca Antiga  / http://lantiga.github.io
 */

class TrackballControls extends THREE.EventDispatcher {
  constructor(object, domElement) {
    super();

    const _this = this;
    const STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 };

    this.object = object;
    this.domElement = ( domElement !== undefined ) ? domElement : document;

    // API

    this.enabled = true;

    this.screen = { left: 0, top: 0, width: 0, height: 0 };

    this.rotateSpeed = 1.0;
    this.zoomSpeed = 1.2;
    this.panSpeed = 0.3;

    this.noRotate = false;
    this.noZoom = false;
    this.noPan = false;

    this.staticMoving = false;
    this.dynamicDampingFactor = 0.2;

    this.minDistance = 0;
    this.maxDistance = Infinity;

    this.keys = [
      65/* A */,
      83/* S */,
      68/* D */,
    ];

    // internals

    this.target = new THREE.Vector3();

    const EPS = 0.000001;

    const lastPosition = new THREE.Vector3();

    let _state = STATE.NONE;
    let _prevState = STATE.NONE;

    const _eye = new THREE.Vector3();
    const _movePrev = new THREE.Vector2();
    const _moveCurr = new THREE.Vector2();
    const _lastAxis = new THREE.Vector3();

    let _lastAngle = 0;

    const _zoomStart = new THREE.Vector2();
    const _zoomEnd = new THREE.Vector2();

    let _touchZoomDistanceStart = 0;
    let _touchZoomDistanceEnd = 0;
    const _panStart = new THREE.Vector2();
    const _panEnd = new THREE.Vector2();

    // for reset

    this.target0 = this.target.clone();
    this.position0 = this.object.position.clone();
    this.up0 = this.object.up.clone();

    // events

    const changeEvent = { type: 'change' };
    const startEvent = { type: 'start' };
    const endEvent = { type: 'end' };

    // methods

    this.handleResize = () => {
      if (this.domElement === document) {
        this.screen.left = 0;
        this.screen.top = 0;
        this.screen.width = window.innerWidth;
        this.screen.height = window.innerHeight;
      } else {
        const box = this.domElement.getBoundingClientRect();
        // adjustments come from similar code in the jquery offset() function
        const d = this.domElement.ownerDocument.documentElement;
        this.screen.left = box.left + window.pageXOffset - d.clientLeft;
        this.screen.top = box.top + window.pageYOffset - d.clientTop;
        this.screen.width = box.width;
        this.screen.height = box.height;
      }
    };

    this.handleEvent = (event) => {
      if (typeof this[event.type] === 'function') {
        this[event.type](event);
      }
    };

    const getMouseOnScreen = ( function wrapper() {
      const vector = new THREE.Vector2();

      return (pageX, pageY) => {
        vector.set(
          ( pageX - _this.screen.left ) / _this.screen.width,
          ( pageY - _this.screen.top ) / _this.screen.height
        );

        return vector;
      };
    }() );

    const getMouseOnCircle = ( function wrapper() {
      const vector = new THREE.Vector2();

      return (pageX, pageY) => {
        vector.set(
          ( ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / ( _this.screen.width * 0.5 ) ),
          ( ( _this.screen.height + 2 * ( _this.screen.top - pageY ) ) / _this.screen.width ) // screen.width intentional
        );

        return vector;
      };
    }() );

    this.rotateCamera = ( function wrapper() {
      const axis = new THREE.Vector3();
      const quaternion = new THREE.Quaternion();
      const eyeDirection = new THREE.Vector3();
      const objectUpDirection = new THREE.Vector3();
      const objectSidewaysDirection = new THREE.Vector3();
      const moveDirection = new THREE.Vector3();

      let angle;

      return function rotateCamera() {
        moveDirection.set(_moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0);
        angle = moveDirection.length();

        if (angle) {
          _eye.copy(_this.object.position).sub(_this.target);

          eyeDirection.copy(_eye).normalize();
          objectUpDirection.copy(_this.object.up).normalize();
          objectSidewaysDirection.crossVectors(objectUpDirection, eyeDirection).normalize();

          objectUpDirection.setLength(_moveCurr.y - _movePrev.y);
          objectSidewaysDirection.setLength(_moveCurr.x - _movePrev.x);

          moveDirection.copy(objectUpDirection.add(objectSidewaysDirection));

          axis.crossVectors(moveDirection, _eye).normalize();

          angle *= _this.rotateSpeed;
          quaternion.setFromAxisAngle(axis, angle);

          _eye.applyQuaternion(quaternion);
          _this.object.up.applyQuaternion(quaternion);

          _lastAxis.copy(axis);
          _lastAngle = angle;
        } else if (!_this.staticMoving && _lastAngle) {
          _lastAngle *= Math.sqrt(1.0 - _this.dynamicDampingFactor);
          _eye.copy(_this.object.position).sub(_this.target);
          quaternion.setFromAxisAngle(_lastAxis, _lastAngle);
          _eye.applyQuaternion(quaternion);
          _this.object.up.applyQuaternion(quaternion);
        }

        _movePrev.copy(_moveCurr);
      };
    }() );

    this.zoomCamera = () => {
      let factor;

      if (_state === STATE.TOUCH_ZOOM_PAN) {
        factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
        _touchZoomDistanceStart = _touchZoomDistanceEnd;
        _eye.multiplyScalar(factor);
      } else {
        factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;

        if (factor !== 1.0 && factor > 0.0) {
          _eye.multiplyScalar(factor);

          if (_this.staticMoving) {
            _zoomStart.copy(_zoomEnd);
          } else {
            _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;
          }
        }
      }
    };

    this.panCamera = ( function wrapper() {
      const mouseChange = new THREE.Vector2();
      const objectUp = new THREE.Vector3();
      const pan = new THREE.Vector3();

      return function panCamera() {
        mouseChange.copy(_panEnd).sub(_panStart);

        if (mouseChange.lengthSq()) {
          mouseChange.multiplyScalar(_eye.length() * _this.panSpeed);

          pan.copy(_eye).cross(_this.object.up).setLength(mouseChange.x);
          pan.add(objectUp.copy(_this.object.up).setLength(mouseChange.y));

          _this.object.position.add(pan);
          _this.target.add(pan);

          if (_this.staticMoving) {
            _panStart.copy(_panEnd);
          } else {
            _panStart.add(mouseChange.subVectors(_panEnd, _panStart).multiplyScalar(_this.dynamicDampingFactor));
          }
        }
      };
    }() );

    this.checkDistances = () => {
      if (!_this.noZoom || !_this.noPan) {
        if (_eye.lengthSq() > _this.maxDistance * _this.maxDistance) {
          _this.object.position.addVectors(_this.target, _eye.setLength(_this.maxDistance));
          _zoomStart.copy(_zoomEnd);
        }

        if (_eye.lengthSq() < _this.minDistance * _this.minDistance) {
          _this.object.position.addVectors(_this.target, _eye.setLength(_this.minDistance));
          _zoomStart.copy(_zoomEnd);
        }
      }
    };

    this.update = () => {
      _eye.subVectors(_this.object.position, _this.target);

      if (!_this.noRotate) {
        _this.rotateCamera();
      }

      if (!_this.noZoom) {
        _this.zoomCamera();
      }

      if (!_this.noPan) {
        _this.panCamera();
      }

      _this.object.position.addVectors(_this.target, _eye);

      _this.checkDistances();

      _this.object.lookAt(_this.target);

      if (lastPosition.distanceToSquared(_this.object.position) > EPS) {
        _this.dispatchEvent(changeEvent);

        lastPosition.copy(_this.object.position);
      }
    };

    this.reset = () => {
      _state = STATE.NONE;
      _prevState = STATE.NONE;

      _this.target.copy(_this.target0);
      _this.object.position.copy(_this.position0);
      _this.object.up.copy(_this.up0);

      _eye.subVectors(_this.object.position, _this.target);

      _this.object.lookAt(_this.target);

      _this.dispatchEvent(changeEvent);

      lastPosition.copy(_this.object.position);
    };

    // listeners

    function keydown(event) {
      if (_this.enabled === false) return;

      window.removeEventListener('keydown', keydown);

      _prevState = _state;

      if (_state !== STATE.NONE) {
        return;
      }

      if (event.keyCode === _this.keys[STATE.ROTATE] && !_this.noRotate) {
        _state = STATE.ROTATE;
      } else if (event.keyCode === _this.keys[STATE.ZOOM] && !_this.noZoom) {
        _state = STATE.ZOOM;
      } else if (event.keyCode === _this.keys[STATE.PAN] && !_this.noPan) {
        _state = STATE.PAN;
      }
    }

    function keyup() {
      if (_this.enabled === false) return;

      _state = _prevState;

      window.addEventListener('keydown', keydown, false);
    }


    function mousemove(event) {
      if (_this.enabled === false) return;

      event.preventDefault();
      event.stopPropagation();

      if (_state === STATE.ROTATE && !_this.noRotate) {
        _movePrev.copy(_moveCurr);
        _moveCurr.copy(getMouseOnCircle(event.pageX, event.pageY));
      } else if (_state === STATE.ZOOM && !_this.noZoom) {
        _zoomEnd.copy(getMouseOnScreen(event.pageX, event.pageY));
      } else if (_state === STATE.PAN && !_this.noPan) {
        _panEnd.copy(getMouseOnScreen(event.pageX, event.pageY));
      }
    }

    function mouseup(event) {
      if (_this.enabled === false) return;

      event.preventDefault();
      event.stopPropagation();

      _state = STATE.NONE;

      document.removeEventListener('mousemove', mousemove);
      document.removeEventListener('mouseup', mouseup);
      _this.dispatchEvent(endEvent);
    }

    function mousedown(event) {
      if (_this.enabled === false) return;

      event.preventDefault();
      event.stopPropagation();

      if (_state === STATE.NONE) {
        _state = event.button;
      }

      if (_state === STATE.ROTATE && !_this.noRotate) {
        _moveCurr.copy(getMouseOnCircle(event.pageX, event.pageY));
        _movePrev.copy(_moveCurr);
      } else if (_state === STATE.ZOOM && !_this.noZoom) {
        _zoomStart.copy(getMouseOnScreen(event.pageX, event.pageY));
        _zoomEnd.copy(_zoomStart);
      } else if (_state === STATE.PAN && !_this.noPan) {
        _panStart.copy(getMouseOnScreen(event.pageX, event.pageY));
        _panEnd.copy(_panStart);
      }

      document.addEventListener('mousemove', mousemove, false);
      document.addEventListener('mouseup', mouseup, false);

      _this.dispatchEvent(startEvent);
    }


    function mousewheel(event) {
      if (_this.enabled === false) return;

      event.preventDefault();
      event.stopPropagation();

      let delta = 0;

      if (event.wheelDelta) {
        // WebKit / Opera / Explorer 9

        delta = event.wheelDelta / 40;
      } else if (event.detail) {
        // Firefox

        delta = -event.detail / 3;
      }

      _zoomStart.y += delta * 0.01;
      _this.dispatchEvent(startEvent);
      _this.dispatchEvent(endEvent);
    }

    function touchstart(event) {
      if (_this.enabled === false) return;

      switch (event.touches.length) {
        case 1:
          _state = STATE.TOUCH_ROTATE;
          _moveCurr.copy(getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY));
          _movePrev.copy(_moveCurr);
          break;

        case 2:
          _state = STATE.TOUCH_ZOOM_PAN;
          const dx = event.touches[0].pageX - event.touches[1].pageX;
          const dy = event.touches[0].pageY - event.touches[1].pageY;
          _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt(dx * dx + dy * dy);

          const x = ( event.touches[0].pageX + event.touches[1].pageX ) / 2;
          const y = ( event.touches[0].pageY + event.touches[1].pageY ) / 2;
          _panStart.copy(getMouseOnScreen(x, y));
          _panEnd.copy(_panStart);
          break;

        default:
          _state = STATE.NONE;

      }
      _this.dispatchEvent(startEvent);
    }

    function touchmove(event) {
      if (_this.enabled === false) return;

      event.preventDefault();
      event.stopPropagation();

      switch (event.touches.length) {

        case 1:
          _movePrev.copy(_moveCurr);
          _moveCurr.copy(getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY));
          break;

        case 2:
          const dx = event.touches[0].pageX - event.touches[1].pageX;
          const dy = event.touches[0].pageY - event.touches[1].pageY;
          _touchZoomDistanceEnd = Math.sqrt(dx * dx + dy * dy);

          const x = ( event.touches[0].pageX + event.touches[1].pageX ) / 2;
          const y = ( event.touches[0].pageY + event.touches[1].pageY ) / 2;
          _panEnd.copy(getMouseOnScreen(x, y));
          break;

        default:
          _state = STATE.NONE;
      }
    }

    function touchend(event) {
      if (_this.enabled === false) return;

      switch (event.touches.length) {
        default:
          // no touches
          break;
        case 1:
          _moveCurr.copy(getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY));
          _movePrev.copy(_moveCurr);
          break;

        case 2:
          _touchZoomDistanceStart = _touchZoomDistanceEnd = 0;

          const x = ( event.touches[0].pageX + event.touches[1].pageX ) / 2;
          const y = ( event.touches[0].pageY + event.touches[1].pageY ) / 2;
          _panEnd.copy(getMouseOnScreen(x, y));
          _panStart.copy(_panEnd);
          break;

      }

      _state = STATE.NONE;
      _this.dispatchEvent(endEvent);
    }

    function contextmenu(event) {
      event.preventDefault();
    }

    this.dispose = () => {
      this.domElement.removeEventListener('contextmenu', contextmenu, false);
      this.domElement.removeEventListener('mousedown', mousedown, false);
      this.domElement.removeEventListener('mousewheel', mousewheel, false);
      this.domElement.removeEventListener('DOMMouseScroll', mousewheel, false); // firefox

      this.domElement.removeEventListener('touchstart', touchstart, false);
      this.domElement.removeEventListener('touchend', touchend, false);
      this.domElement.removeEventListener('touchmove', touchmove, false);

      document.removeEventListener('mousemove', mousemove, false);
      document.removeEventListener('mouseup', mouseup, false);

      window.removeEventListener('keydown', keydown, false);
      window.removeEventListener('keyup', keyup, false);
    };

    this.domElement.addEventListener('contextmenu', contextmenu, false);
    this.domElement.addEventListener('mousedown', mousedown, false);
    this.domElement.addEventListener('mousewheel', mousewheel, false);
    this.domElement.addEventListener('DOMMouseScroll', mousewheel, false); // firefox

    this.domElement.addEventListener('touchstart', touchstart, false);
    this.domElement.addEventListener('touchend', touchend, false);
    this.domElement.addEventListener('touchmove', touchmove, false);

    window.addEventListener('keydown', keydown, false);
    window.addEventListener('keyup', keyup, false);

    this.handleResize();

    // force an update at start
    this.update();
  }
}

export default TrackballControls;

/* eslint-enable */


================================================
FILE: webpack.config.babel.js
================================================
/* eslint-disable import/no-extraneous-dependencies */

import path from 'path';
import webpack from 'webpack';
import pluginsWithoutUglify from './config/webpackPluginsWithoutUglify';

import packageJson from './package.json';

const outPath = path.join(__dirname, 'pages');

const plugins = pluginsWithoutUglify.concat([
  new webpack.optimize.UglifyJsPlugin({
    compress: {
      warnings: false,
    },
    mangle: true,
  }),
]);

const babelLoaderConfigShared = {
  test: /\.jsx?$/,
  loader: 'babel-loader',
  query: {
    ...packageJson.babel,
    cacheDirectory: true,
  },
};

export default {
  entry: {
    app: [
      './src/index.jsx',
    ],
    advanced: [
      './src/examples/AdvancedExample/index.js',
    ],
  },
  output: {
    path: outPath,
    filename: path.join('js', 'bundle-[name].js'),
  },
  module: {
    loaders: [
      {
        loader: 'json-loader',
        test: /\.json$/,
      },
      {
        exclude: /node_modules/,
        ...babelLoaderConfigShared,
      },
      {
        include: /react-three-renderer[\\/]src/,
        ...babelLoaderConfigShared,
      },
    ],
  },
  resolve: {
    extensions: ['.js', '.jsx'],
    alias: {
      // use the source files
      'react-three-renderer': path.join(
        __dirname, 'node_modules', 'react-three-renderer', 'src'),
    },
  },
  devServer: {
    contentBase: path.join(__dirname, 'assets'),
    // noInfo: true, //  --no-info option
    hot: true,
    inline: true,
    stats: { colors: true },
  },
  plugins,
};
Download .txt
gitextract_5jlez6np/

├── .eslintrc
├── .gitignore
├── .gitmodules
├── CONTRIBUTORS.md
├── README.md
├── assets/
│   ├── advanced.html
│   └── index.html
├── config/
│   ├── webpackCommonsChunkPluginConfig.js
│   └── webpackPluginsWithoutUglify.js
├── gulpfile.babel.js
├── package.json
├── src/
│   ├── examples/
│   │   ├── AdvancedExample/
│   │   │   ├── AdvancedComponent.js
│   │   │   └── index.js
│   │   ├── AnimationCloth/
│   │   │   ├── Cloth.js
│   │   │   ├── ClothGeometry.jsx
│   │   │   ├── Info.js
│   │   │   ├── Poles.js
│   │   │   ├── Sphere.js
│   │   │   ├── StaticWorld.js
│   │   │   ├── index.js
│   │   │   ├── index.jsx
│   │   │   └── shaders/
│   │   │       ├── depth.frag
│   │   │       └── depth.vert
│   │   ├── Benchmark/
│   │   │   ├── RotatingCube.js
│   │   │   ├── RotatingCubes.js
│   │   │   └── RotatingCubesDirectUpdates.js
│   │   ├── DraggableCubes/
│   │   │   ├── AllCubes.js
│   │   │   ├── DraggableCube.js
│   │   │   └── index.js
│   │   ├── ExampleBase.js
│   │   ├── ExampleBrowser.js
│   │   ├── ExampleViewer.js
│   │   ├── Geometries/
│   │   │   └── index.js
│   │   ├── GeometryShapes/
│   │   │   ├── Rect.js
│   │   │   ├── Resources.js
│   │   │   ├── Shape.js
│   │   │   ├── Shapes.js
│   │   │   └── index.js
│   │   ├── ManualRendering/
│   │   │   ├── Info.js
│   │   │   └── index.js
│   │   ├── Physics/
│   │   │   ├── index.js
│   │   │   ├── mousePick/
│   │   │   │   └── PickableMesh.js
│   │   │   └── mousePick.js
│   │   ├── Simple/
│   │   │   └── index.js
│   │   ├── WebGLCameraExample/
│   │   │   ├── Info.js
│   │   │   ├── PointCloud.js
│   │   │   └── index.js
│   │   └── inputs/
│   │       └── MouseInput.js
│   ├── index.jsx
│   └── ref/
│       └── trackball.js
└── webpack.config.babel.js
Download .txt
SYMBOL INDEX (148 symbols across 32 files)

FILE: src/examples/AdvancedExample/index.js
  function onRecreateCanvas (line 20) | function onRecreateCanvas() {
  function animate (line 25) | function animate() {

FILE: src/examples/AnimationCloth/Cloth.js
  function plane (line 15) | function plane(width, height) {
  constant DAMPING (line 25) | const DAMPING = 0.03;
  constant DRAG (line 26) | const DRAG = 1 - DAMPING;
  constant MASS (line 27) | const MASS = 0.1;
  class Particle (line 35) | class Particle {
    method constructor (line 36) | constructor(x, y, z, mass) {
    method addForce (line 48) | addForce(force) {
    method integrate (line 55) | integrate(timesQ) {
  class Cloth (line 68) | class Cloth {
    method constructor (line 72) | constructor(w = 10, h = 10) {

FILE: src/examples/AnimationCloth/ClothGeometry.jsx
  class ClothGeometry (line 8) | class ClothGeometry extends React.Component {
    method componentDidMount (line 13) | componentDidMount() {
    method render (line 25) | render() {

FILE: src/examples/AnimationCloth/Info.js
  class Info (line 5) | class Info extends React.Component {
    method render (line 18) | render() {

FILE: src/examples/AnimationCloth/Poles.js
  class Poles (line 7) | class Poles extends React.Component {
    method constructor (line 8) | constructor(props, context) {
    method render (line 30) | render() {

FILE: src/examples/AnimationCloth/Sphere.js
  class Sphere (line 11) | class Sphere extends React.Component {
    method constructor (line 17) | constructor(props, context) {
    method render (line 27) | render() {

FILE: src/examples/AnimationCloth/StaticWorld.js
  class StaticWorld (line 15) | class StaticWorld extends React.Component {
    method constructor (line 21) | constructor(props, context) {
    method render (line 56) | render() {

FILE: src/examples/AnimationCloth/index.jsx
  constant GRAVITY (line 19) | const GRAVITY = 981 * 1.4;
  constant TIMESTEP (line 22) | const TIMESTEP = 18 / 1000;
  constant TIMESTEP_SQ (line 23) | const TIMESTEP_SQ = TIMESTEP * TIMESTEP;
  function satisfyConstrains (line 28) | function satisfyConstrains(p1, p2, distance) {
  class AnimationCloth (line 42) | class AnimationCloth extends ExampleBase {
    method constructor (line 43) | constructor(props, context) {
    method componentDidMount (line 94) | componentDidMount() {
    method componentWillUnmount (line 123) | componentWillUnmount() {
    method _simulate (line 145) | _simulate(time) {
    method render (line 330) | render() {

FILE: src/examples/Benchmark/RotatingCube.js
  class RotatingCube (line 8) | class RotatingCube extends React.Component {
    method render (line 14) | render() {

FILE: src/examples/Benchmark/RotatingCubes.js
  class RotatingCubes (line 11) | class RotatingCubes extends ExampleBase {
    method constructor (line 12) | constructor(props, context) {
    method _getMeshStates (line 42) | _getMeshStates() {
    method _updateGraphics (line 57) | _updateGraphics() {
    method _updatePhysics (line 63) | _updatePhysics() {
    method componentDidMount (line 82) | componentDidMount() {
    method componentWillUnmount (line 95) | componentWillUnmount() {
    method _createBodies (line 99) | _createBodies() {
    method _createBody (line 108) | _createBody() {
    method _getInputBox (line 142) | _getInputBox(title) {
    method render (line 167) | render() {

FILE: src/examples/Benchmark/RotatingCubesDirectUpdates.js
  class RotatingCubesDirectUpdates (line 8) | class RotatingCubesDirectUpdates extends RotatingCubes {
    method _getMeshStates (line 9) | _getMeshStates() {
    method _bodyRef (line 19) | _bodyRef(index, body) {
    method _updateGraphics (line 28) | _updateGraphics() {
    method _createBody (line 41) | _createBody(i) {
    method render (line 49) | render() {

FILE: src/examples/DraggableCubes/AllCubes.js
  class AllCubes (line 11) | class AllCubes extends React.Component {
    method constructor (line 25) | constructor(props, context) {
    method componentDidMount (line 49) | componentDidMount() {
    method render (line 112) | render() {

FILE: src/examples/DraggableCubes/DraggableCube.js
  class DraggableCube (line 15) | class DraggableCube extends React.Component {
    method constructor (line 32) | constructor(props, context) {
    method componentWillUnmount (line 72) | componentWillUnmount() {
    method render (line 176) | render() {

FILE: src/examples/DraggableCubes/index.js
  class DraggableCubes (line 18) | class DraggableCubes extends ExampleBase {
    method constructor (line 19) | constructor(props, context) {
    method componentDidMount (line 45) | componentDidMount() {
    method componentDidUpdate (line 102) | componentDidUpdate(newProps) {
    method componentWillUnmount (line 124) | componentWillUnmount() {
    method _onAnimateInternal (line 133) | _onAnimateInternal() {
    method render (line 166) | render() {

FILE: src/examples/ExampleBase.js
  class ExampleBase (line 5) | class ExampleBase extends React.Component {

FILE: src/examples/Geometries/index.js
  class Geometries (line 11) | class Geometries extends ExampleBase {
    method constructor (line 12) | constructor(props, context) {
    method componentDidMount (line 57) | componentDidMount() {
    method componentWillUnmount (line 66) | componentWillUnmount() {
    method _onAnimateInternal (line 70) | _onAnimateInternal() {
    method render (line 80) | render() {

FILE: src/examples/GeometryShapes/Rect.js
  function Rect (line 4) | function Rect(props) {

FILE: src/examples/GeometryShapes/Resources.js
  class Resources (line 6) | class Resources extends React.Component {
    method shouldComponentUpdate (line 7) | shouldComponentUpdate() {
    method render (line 11) | render() {

FILE: src/examples/GeometryShapes/Shape.js
  class Shape (line 16) | class Shape extends React.Component {
    method render (line 31) | render() {

FILE: src/examples/GeometryShapes/Shapes.js
  class Shapes (line 4) | class Shapes extends React.Component {
    method shouldComponentUpdate (line 5) | shouldComponentUpdate() {
    method render (line 9) | render() {

FILE: src/examples/GeometryShapes/index.js
  class GeometryShapes (line 14) | class GeometryShapes extends ExampleBase {
    method constructor (line 15) | constructor(props, context) {
    method componentDidMount (line 33) | componentDidMount() {
    method componentWillUnmount (line 48) | componentWillUnmount() {
    method _onAnimateInternal (line 137) | _onAnimateInternal() {
    method render (line 150) | render() {

FILE: src/examples/ManualRendering/Info.js
  class Info (line 5) | class Info extends React.Component {
    method constructor (line 14) | constructor(props, context) {
    method render (line 46) | render() {

FILE: src/examples/ManualRendering/index.js
  class Manual (line 9) | class Manual extends ExampleBase {
    method constructor (line 10) | constructor(props, context) {
    method componentDidMount (line 26) | componentDidMount() {
    method render (line 63) | render() {

FILE: src/examples/Physics/index.js
  class Physics (line 10) | class Physics extends ExampleBase {
    method constructor (line 11) | constructor(props, context) {
    method componentWillUnmount (line 61) | componentWillUnmount() {
    method componentDidMount (line 67) | componentDidMount() {
    method render (line 80) | render() {

FILE: src/examples/Physics/mousePick.js
  class PhysicsMousePick (line 17) | class PhysicsMousePick extends ExampleBase {
    method constructor (line 18) | constructor(props, context) {
    method _setClickMarker (line 162) | _setClickMarker(x, y, z) {
    method componentDidMount (line 169) | componentDidMount() {
    method componentDidUpdate (line 194) | componentDidUpdate(newProps) {
    method componentWillUnmount (line 209) | componentWillUnmount() {
    method render (line 272) | render() {

FILE: src/examples/Physics/mousePick/PickableMesh.js
  class PickableMesh (line 6) | class PickableMesh extends React.Component {
    method componentDidMount (line 16) | componentDidMount() {
    method componentWillUnmount (line 31) | componentWillUnmount() {
    method render (line 49) | render() {

FILE: src/examples/Simple/index.js
  class Simple (line 5) | class Simple extends React.Component {
    method constructor (line 11) | constructor(props, context) {
    method render (line 39) | render() {

FILE: src/examples/WebGLCameraExample/Info.js
  class Info (line 5) | class Info extends React.Component {
    method render (line 11) | render() {

FILE: src/examples/WebGLCameraExample/PointCloud.js
  class PointCloud (line 4) | class PointCloud extends React.Component {
    method constructor (line 5) | constructor(props, context) {
    method shouldComponentUpdate (line 21) | shouldComponentUpdate() {
    method render (line 25) | render() {

FILE: src/examples/WebGLCameraExample/index.js
  class WebGLCameraExample (line 24) | class WebGLCameraExample extends ExampleBase {
    method constructor (line 25) | constructor(props, context) {
    method componentDidMount (line 40) | componentDidMount() {
    method componentWillUnmount (line 65) | componentWillUnmount() {
    method render (line 123) | render() {

FILE: src/examples/inputs/MouseInput.js
  class MouseInput (line 30) | class MouseInput extends Module {
    method constructor (line 31) | constructor() {
    method setup (line 45) | setup(react3RendererInstance) {
    method isReady (line 75) | isReady() {
    method setActive (line 79) | setActive(active) {
    method restrictIntersections (line 83) | restrictIntersections(objects, recursive = false) {
    method ready (line 90) | ready(scene, container, camera) {
    method _createSyntheticMouseEvent (line 205) | _createSyntheticMouseEvent(eventType, prototype) {
    method _intersectAndDispatch (line 210) | _intersectAndDispatch(callbackName, mouseEvent) {
    method _getIntersections (line 235) | _getIntersections(mouseCoords) {
    method getCameraRay (line 254) | getCameraRay(mouseCoords) {
    method intersectObject (line 269) | intersectObject(mouseCoords, object, recursive = false) {
    method containerResized (line 283) | containerResized() {
    method update (line 287) | update() {
    method _updateEnterLeave (line 297) | _updateEnterLeave() {
    method _getRelativeMouseCoords (line 363) | _getRelativeMouseCoords(screenMouseCoords) {
    method dispose (line 380) | dispose() {

FILE: src/ref/trackball.js
  class TrackballControls (line 12) | class TrackballControls extends THREE.EventDispatcher {
    method constructor (line 13) | constructor(object, domElement) {
Condensed preview — 51 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (172K chars).
[
  {
    "path": ".eslintrc",
    "chars": 448,
    "preview": "// Use this file as a starting point for your project's .eslintrc.\n// Copy this file, and add rule overrides as needed.\n"
  },
  {
    "path": ".gitignore",
    "chars": 62,
    "preview": "/node_modules\n.idea/dictionaries/\n.idea/uiDesigner.xml\n.idea/\n"
  },
  {
    "path": ".gitmodules",
    "chars": 118,
    "preview": "[submodule \"pages\"]\n\tpath = pages\n\turl = git@github.com:toxicFork/react-three-renderer-example.git\n\tbranch = gh-pages\n"
  },
  {
    "path": "CONTRIBUTORS.md",
    "chars": 144,
    "preview": "* [@toxicFork](https://github.com/toxicFork)\n * Original Author\n* [@vkammerer](https://github.com/vkammerer)\n * Added in"
  },
  {
    "path": "README.md",
    "chars": 379,
    "preview": "react-three-renderer-example\n============================\n\nExamples for [react-three-renderer](https://github.com/toxicF"
  },
  {
    "path": "assets/advanced.html",
    "chars": 4950,
    "preview": "<!doctype html>\n<html>\n<head>\n    <style>\n        @font-face {\n            font-family: 'inconsolata';\n            src: "
  },
  {
    "path": "assets/index.html",
    "chars": 4694,
    "preview": "<!doctype html>\n<html>\n<head>\n    <style>\n        @font-face {\n            font-family: 'inconsolata';\n            src: "
  },
  {
    "path": "config/webpackCommonsChunkPluginConfig.js",
    "chars": 295,
    "preview": "/* eslint-disable import/no-extraneous-dependencies */\n\nimport webpack from 'webpack';\nimport path from 'path';\n\n// noin"
  },
  {
    "path": "config/webpackPluginsWithoutUglify.js",
    "chars": 350,
    "preview": "/* eslint-disable import/no-extraneous-dependencies */\n\nimport webpack from 'webpack';\n\nimport commonsChunkPluginConfig "
  },
  {
    "path": "gulpfile.babel.js",
    "chars": 4782,
    "preview": "/* eslint-disable import/no-extraneous-dependencies */\n\nimport gulp from 'gulp';\nimport webpack from 'webpack';\nimport W"
  },
  {
    "path": "package.json",
    "chars": 2270,
    "preview": "{\n  \"name\": \"react-three-renderer-example\",\n  \"version\": \"1.0.0\",\n  \"description\": \"An example showing how to use the re"
  },
  {
    "path": "src/examples/AdvancedExample/AdvancedComponent.js",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/examples/AdvancedExample/index.js",
    "chars": 1349,
    "preview": "// see advanced.html :)\n\nimport React from 'react';\nimport React3Renderer from 'react-three-renderer/lib/React3Renderer'"
  },
  {
    "path": "src/examples/AnimationCloth/Cloth.js",
    "chars": 2987,
    "preview": "/*\n * Cloth Simulation using a relaxed constrains solver\n */\n\n// Suggested Readings\n\n// Advanced Character Physics by Th"
  },
  {
    "path": "src/examples/AnimationCloth/ClothGeometry.jsx",
    "chars": 806,
    "preview": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nimport PureRenderMixin from 'react/lib/ReactComponentWit"
  },
  {
    "path": "src/examples/AnimationCloth/Info.js",
    "chars": 2027,
    "preview": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nclass Info extends React.Component {\n  static propTypes"
  },
  {
    "path": "src/examples/AnimationCloth/Poles.js",
    "chars": 2907,
    "preview": "import React from 'react';\n\nimport * as THREE from 'three';\n\nimport PureRenderMixin from 'react/lib/ReactComponentWithPu"
  },
  {
    "path": "src/examples/AnimationCloth/Sphere.js",
    "chars": 988,
    "preview": "import React from 'react';\n\nimport * as THREE from 'three';\n\nimport PureRenderMixin from 'react/lib/ReactComponentWithPu"
  },
  {
    "path": "src/examples/AnimationCloth/StaticWorld.js",
    "chars": 4452,
    "preview": "import React from 'react';\nimport * as THREE from 'three';\nimport PropTypes from 'prop-types';\n\nimport PureRenderMixin f"
  },
  {
    "path": "src/examples/AnimationCloth/index.js",
    "chars": 53,
    "preview": "import jsx from './index.jsx';\n\nmodule.exports = jsx;"
  },
  {
    "path": "src/examples/AnimationCloth/index.jsx",
    "chars": 9118,
    "preview": "import React from 'react';\nimport * as THREE from 'three';\nimport Stats from 'stats.js';\n\nimport React3 from 'react-thre"
  },
  {
    "path": "src/examples/AnimationCloth/shaders/depth.frag",
    "chars": 480,
    "preview": "uniform sampler2D texture;\nvarying vec2 vUV;\n\nvec4 pack_depth( const in float depth ) {\n  const vec4 bit_shift = vec4( 2"
  },
  {
    "path": "src/examples/AnimationCloth/shaders/depth.vert",
    "chars": 164,
    "preview": "varying vec2 vUV;\n\nvoid main() {\n  vUV = 0.75 * uv;\n\n  vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\n  gl_"
  },
  {
    "path": "src/examples/Benchmark/RotatingCube.js",
    "chars": 748,
    "preview": "import React from 'react';\nimport * as THREE from 'three';\n\nimport PropTypes from 'prop-types';\n\nconst meshScale = new T"
  },
  {
    "path": "src/examples/Benchmark/RotatingCubes.js",
    "chars": 6307,
    "preview": "import React from 'react';\nimport React3 from 'react-three-renderer';\nimport * as THREE from 'three';\n\nimport ExampleBas"
  },
  {
    "path": "src/examples/Benchmark/RotatingCubesDirectUpdates.js",
    "chars": 3533,
    "preview": "import React from 'react';\nimport React3 from 'react-three-renderer';\nimport * as THREE from 'three';\n\nimport RotatingCu"
  },
  {
    "path": "src/examples/DraggableCubes/AllCubes.js",
    "chars": 2898,
    "preview": "import React from 'react';\nimport DraggableCube from './DraggableCube';\nimport * as THREE from 'three';\n\nimport PureRend"
  },
  {
    "path": "src/examples/DraggableCubes/DraggableCube.js",
    "chars": 4991,
    "preview": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nimport * as THREE from 'three';\nimport PureRenderMixin f"
  },
  {
    "path": "src/examples/DraggableCubes/index.js",
    "chars": 5705,
    "preview": "import React from 'react';\n\nimport PureRenderMixin from 'react/lib/ReactComponentWithPureRenderMixin';\n\nimport * as THRE"
  },
  {
    "path": "src/examples/ExampleBase.js",
    "chars": 249,
    "preview": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nclass ExampleBase extends React.Component {\n  static pr"
  },
  {
    "path": "src/examples/ExampleBrowser.js",
    "chars": 3737,
    "preview": "import React from 'react';\nimport { NavLink } from 'react-router-dom';\nimport ExampleViewer from './ExampleViewer';\n\nimp"
  },
  {
    "path": "src/examples/ExampleViewer.js",
    "chars": 869,
    "preview": "import React from 'react';\nimport sizeMe from 'react-sizeme';\n\nconst ExampleViewer = ({ example, size }) => {\n  let sour"
  },
  {
    "path": "src/examples/Geometries/index.js",
    "chars": 8183,
    "preview": "import React from 'react';\n\nimport * as THREE from 'three';\nimport Stats from 'stats.js';\n\nimport React3 from 'react-thr"
  },
  {
    "path": "src/examples/GeometryShapes/Rect.js",
    "chars": 619,
    "preview": "import React from 'react';\nimport PropTypes from 'react/lib/ReactPropTypes';\n\nfunction Rect(props) {\n  const {\n    width"
  },
  {
    "path": "src/examples/GeometryShapes/Resources.js",
    "chars": 10930,
    "preview": "import React from 'react';\nimport * as THREE from 'three';\n\nimport Rect from './Rect';\n\nclass Resources extends React.Co"
  },
  {
    "path": "src/examples/GeometryShapes/Shape.js",
    "chars": 3739,
    "preview": "import React from 'react';\nimport * as THREE from 'three';\nimport PropTypes from 'react/lib/ReactPropTypes';\n\nimport Pur"
  },
  {
    "path": "src/examples/GeometryShapes/Shapes.js",
    "chars": 2223,
    "preview": "import React from 'react';\nimport Shape from './Shape';\n\nclass Shapes extends React.Component {\n  shouldComponentUpdate("
  },
  {
    "path": "src/examples/GeometryShapes/index.js",
    "chars": 5535,
    "preview": "import React from 'react';\n\nimport * as THREE from 'three';\nimport Stats from 'stats.js';\n\nimport React3 from 'react-thr"
  },
  {
    "path": "src/examples/ManualRendering/Info.js",
    "chars": 2519,
    "preview": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nclass Info extends React.Component {\n  static propTypes"
  },
  {
    "path": "src/examples/ManualRendering/index.js",
    "chars": 2512,
    "preview": "import React from 'react';\nimport React3 from 'react-three-renderer';\nimport * as THREE from 'three';\n\nimport ExampleBas"
  },
  {
    "path": "src/examples/Physics/index.js",
    "chars": 2818,
    "preview": "import React from 'react';\nimport React3 from 'react-three-renderer';\nimport * as THREE from 'three';\nimport CANNON from"
  },
  {
    "path": "src/examples/Physics/mousePick/PickableMesh.js",
    "chars": 1406,
    "preview": "import React from 'react';\nimport * as THREE from 'three';\n\nimport PropTypes from 'prop-types';\n\nclass PickableMesh exte"
  },
  {
    "path": "src/examples/Physics/mousePick.js",
    "chars": 9939,
    "preview": "import React from 'react';\nimport React3 from 'react-three-renderer';\nimport * as THREE from 'three';\nimport CANNON from"
  },
  {
    "path": "src/examples/Simple/index.js",
    "chars": 1900,
    "preview": "import React from 'react';\nimport React3 from 'react-three-renderer';\nimport * as THREE from 'three';\n\nclass Simple exte"
  },
  {
    "path": "src/examples/WebGLCameraExample/Info.js",
    "chars": 917,
    "preview": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nclass Info extends React.Component {\n  static propTypes"
  },
  {
    "path": "src/examples/WebGLCameraExample/PointCloud.js",
    "chars": 732,
    "preview": "import React from 'react';\nimport * as THREE from 'three';\n\nclass PointCloud extends React.Component {\n  constructor(pro"
  },
  {
    "path": "src/examples/WebGLCameraExample/index.js",
    "chars": 5946,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\n\nimport * as THREE from 'three';\nimport ExampleBase from '."
  },
  {
    "path": "src/examples/inputs/MouseInput.js",
    "chars": 10961,
    "preview": "import React3 from 'react-three-renderer';\nimport * as THREE from 'three';\nimport ReactUpdates from 'react-dom/lib/React"
  },
  {
    "path": "src/index.jsx",
    "chars": 565,
    "preview": "/* eslint-disable no-undef */\n\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport {\n  HashRouter as Rou"
  },
  {
    "path": "src/ref/trackball.js",
    "chars": 15552,
    "preview": "/* eslint-disable */\n\nimport * as THREE from 'three';\n\n/**\n * @author Eberhard Graether / http://egraether.com/\n * @auth"
  },
  {
    "path": "webpack.config.babel.js",
    "chars": 1520,
    "preview": "/* eslint-disable import/no-extraneous-dependencies */\n\nimport path from 'path';\nimport webpack from 'webpack';\nimport p"
  }
]

About this extraction

This page contains the full source code of the toxicFork/react-three-renderer-example GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 51 files (157.6 KB), approximately 41.1k tokens, and a symbol index with 148 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!