├── .babelrc ├── .eslintrc ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .travis.yml ├── LICENSE ├── README-PerceptionNeuron.md ├── README.md ├── docker ├── Dockerfile ├── Dockerfile_example └── README.md ├── package.json ├── server ├── config_example.js ├── dataServer.js ├── fileServer.js └── sockets │ ├── Gamepads.js │ ├── KinectTransport.js │ ├── MidiController.js │ ├── OSCServer.js │ ├── PerceptionNeuron.js │ ├── PoseNet.js │ └── iPhoneX.js ├── src ├── camera │ ├── animations │ │ └── animateAlongSpline.js │ └── cameraControl.js ├── config │ └── index.js ├── effects │ ├── group │ │ ├── Line.js │ │ └── index.js │ └── performer │ │ ├── ClonerArmy.js │ │ ├── DataTags.js │ │ ├── Drawing.js │ │ ├── Ghosting.js │ │ ├── MidiStream.js │ │ ├── MovementSculpture.js │ │ ├── ParticleSystem.js │ │ ├── Ribbons.js │ │ ├── Vogue.js │ │ ├── bmFont │ │ ├── index.js │ │ ├── lib │ │ │ ├── utils.js │ │ │ └── vertices.js │ │ └── shaders │ │ │ └── msdf.js │ │ └── index.js ├── environments │ ├── emptyEnvironment.js │ ├── forestEnvironment.js │ ├── gridEnvironment.js │ ├── index.js │ ├── spacedEnvironment.js │ └── waterEnvironment.js ├── html │ └── index.html ├── index.jsx ├── inputs │ ├── README.md │ ├── index.js │ ├── presets │ │ ├── Default.js │ │ ├── Duality.js │ │ ├── ExamplePreset.txt │ │ ├── MeshCombustible.js │ │ ├── MeshFreshFest.js │ │ ├── NewDefault.js │ │ └── TransformWork.js │ └── types │ │ ├── ExampleInput.txt │ │ ├── Gamepads.js │ │ ├── Keyboard.js │ │ ├── KinectTransport.js │ │ ├── MidiController.js │ │ ├── Mouse.js │ │ ├── Myo.js │ │ ├── NeuroSky.js │ │ ├── OSCController.js │ │ ├── PerceptionNeuron.js │ │ ├── PoseNet.js │ │ └── iPhoneX.js ├── libs │ ├── BufferGeometryMerge.js │ ├── inflate.min.js │ ├── three.ar.min.js │ ├── three │ │ └── loaders │ │ │ └── SceneLoader.js │ └── trail.js ├── materials │ ├── ShaderToyLoader.js │ └── shaders │ │ ├── MdBfzm.json │ │ ├── MsBfzm.json │ │ ├── Mtdyzf.json │ │ ├── Xds3zN.json │ │ ├── XsX3RB.json │ │ ├── XtlSD7.json │ │ └── shaders.json ├── outputs │ ├── README.md │ ├── index.js │ ├── presets │ │ ├── Default.js │ │ └── ExamplePreset.txt │ └── types │ │ ├── ExampleInput.txt │ │ └── MidiController.js ├── performers │ ├── BVHPlayer.js │ ├── Head.js │ ├── Materials.js │ ├── Performer.js │ ├── Performers.js │ └── SkeletalTranslator.js ├── react │ ├── effects │ │ ├── DataTagsMenu.jsx │ │ ├── ParticlesMenu.jsx │ │ └── RibbonsMenu.jsx │ ├── inputs │ │ └── NumberInput.jsx │ ├── menus │ │ ├── ARMenu.jsx │ │ ├── CameraMenu.jsx │ │ ├── DebugMenu.jsx │ │ ├── EnvironmentMenu.jsx │ │ ├── HelpMenu.jsx │ │ ├── IOMenu.jsx │ │ ├── InfoMenu.jsx │ │ ├── PerformerMenu.jsx │ │ ├── RenderStyleMenu.jsx │ │ ├── VRMenu.jsx │ │ ├── camera │ │ │ └── PerformerCameraMenu.jsx │ │ ├── controls │ │ │ └── PerformerControlsMenu.jsx │ │ ├── effects │ │ │ ├── DataTagsMenu.jsx │ │ │ ├── GhostingMenu.jsx │ │ │ ├── MovementSculptureMenu.jsx │ │ │ ├── ParticlesMenu.jsx │ │ │ ├── PartsPickerMenu.jsx │ │ │ ├── PerformerEffectsMenu.jsx │ │ │ └── RibbonsMenu.jsx │ │ ├── environment │ │ │ ├── EmptyMenu.jsx │ │ │ ├── ForestMenu.jsx │ │ │ ├── GridMenu.jsx │ │ │ ├── SpaceMenu.jsx │ │ │ └── WaterMenu.jsx │ │ ├── options │ │ │ └── PerformerTranslateMenu.jsx │ │ ├── render │ │ │ ├── AfterImageSettingsMenu.jsx │ │ │ ├── BloomSettingsMenu.jsx │ │ │ ├── DotShiftSettingsMenu.jsx │ │ │ ├── EdgesSettingsMenu.jsx │ │ │ ├── HalftoneSettingsMenu.jsx │ │ │ ├── PixelSettingsMenu.jsx │ │ │ └── SketchSettingsMenu.jsx │ │ └── styles │ │ │ ├── EnvironmentStylesMenu.jsx │ │ │ └── PerformerStylesMenu.jsx │ ├── modals │ │ ├── BVHChooserModal.jsx │ │ └── KeyboardHelpModal.jsx │ └── pages │ │ └── Main.jsx ├── renderStyles │ ├── AfterImageStyle.js │ ├── BloomStyle.js │ ├── DotShiftStyle.js │ ├── EdgesStyle.js │ ├── HalftoneStyle.js │ ├── PixelStyle.js │ ├── SketchStyle.js │ └── index.js ├── shaders │ ├── WaterShader.js │ ├── morphTargetFragment.glsl │ ├── morphTargetVertex.glsl │ ├── performerFragment.glsl │ ├── performerVertex.glsl │ └── sketch │ │ ├── drawFragment.glsl │ │ ├── drawVertex.glsl │ │ └── finalFragment.glsl ├── static │ ├── animations │ │ └── bvh │ │ │ ├── dai_cmp_edit.bvh │ │ │ ├── duality_edit.bvh │ │ │ ├── freya_edit.bvh │ │ │ ├── juliet_edit.bvh │ │ │ ├── movie-1_1.bvh │ │ │ ├── sean_edit.bvh │ │ │ └── wei_edit.bvh │ ├── bmFonts │ │ ├── lato-bold.json │ │ ├── lato-bold.png │ │ ├── lato-regular.json │ │ └── lato-regular.png │ ├── fonts │ │ ├── lato-thin-webfont.eot │ │ ├── lato-thin-webfont.svg │ │ ├── lato-thin-webfont.ttf │ │ ├── lato-thin-webfont.woff │ │ └── lato-thin-webfont.woff2 │ ├── images │ │ ├── credits.jpg │ │ ├── op_logo.png │ │ ├── op_logo_lockup.png │ │ ├── performer_outline.jpg │ │ ├── preview.gif │ │ ├── title.jpg │ │ ├── vr_active.png │ │ └── vr_inactive.png │ ├── models │ │ ├── dae │ │ │ └── neuron-bones.dae │ │ ├── fbx │ │ │ ├── Characters │ │ │ │ ├── Materials.meta │ │ │ │ ├── Materials │ │ │ │ │ ├── GunMaterial.mat │ │ │ │ │ └── GunMaterial.mat.meta │ │ │ │ ├── Player.fbx │ │ │ │ └── Player.fbx.meta │ │ │ ├── JohnSmithHead.fbx │ │ │ ├── JohnSmithHead.json │ │ │ └── SlothCharacter │ │ │ │ ├── Materials.meta │ │ │ │ ├── Materials │ │ │ │ ├── sloth_all_1001_AlbedoTransparency.mat │ │ │ │ └── sloth_all_1001_AlbedoTransparency.mat.meta │ │ │ │ ├── Textures.meta │ │ │ │ ├── Textures │ │ │ │ ├── sloth_all_1001_AlbedoTransparency.png │ │ │ │ ├── sloth_all_1001_AlbedoTransparency.png.meta │ │ │ │ ├── sloth_all_1001_MetallicSmoothness.png │ │ │ │ ├── sloth_all_1001_MetallicSmoothness.png.meta │ │ │ │ ├── sloth_all_1001_Normal.png │ │ │ │ └── sloth_all_1001_Normal.png.meta │ │ │ │ ├── sloth_head_blendshapes5.fbx │ │ │ │ └── sloth_head_blendshapes5.fbx.meta │ │ ├── gltf │ │ │ ├── basicFace.bin │ │ │ ├── basicFace.gltf │ │ │ └── mars │ │ │ │ ├── scene.bin │ │ │ │ ├── scene.gltf │ │ │ │ └── textures │ │ │ │ ├── 01_-_Default_baseColor.jpeg │ │ │ │ ├── 01_-_Default_normal.png │ │ │ │ ├── 02_-_Default_baseColor.jpeg │ │ │ │ ├── 02_-_Default_normal.png │ │ │ │ ├── 03_-_Default_baseColor.jpeg │ │ │ │ └── 03_-_Default_normal.png │ │ ├── json │ │ │ └── avatar.json │ │ ├── mtl │ │ │ └── forest.mtl │ │ ├── obj │ │ │ ├── forest.obj │ │ │ ├── hand.obj │ │ │ └── head.obj │ │ └── textures │ │ │ ├── sloth_all_1001_AlbedoTransparency.png │ │ │ ├── sloth_all_1001_MetallicSmoothness.png │ │ │ └── sloth_all_1001_Normal.png │ └── textures │ │ ├── grasslight-big.jpg │ │ ├── newmoon.png │ │ ├── noise.png │ │ ├── particle2.png │ │ ├── pebbledwall.png │ │ ├── perlin-512.png │ │ ├── skyb.png │ │ ├── skybox.png │ │ ├── skyboxsun25degtest.png │ │ ├── skyboxsun25degtest.txt │ │ ├── skyboxsun25degtest2.png.png │ │ ├── sleepyhollow │ │ ├── sleepyhollow_bk.jpg │ │ ├── sleepyhollow_dn.jpg │ │ ├── sleepyhollow_ft.jpg │ │ ├── sleepyhollow_lf.jpg │ │ ├── sleepyhollow_rt.jpg │ │ └── sleepyhollow_up.jpg │ │ ├── tears │ │ ├── tears_bk.jpg │ │ ├── tears_dn.jpg │ │ ├── tears_ft.jpg │ │ ├── tears_lf.jpg │ │ ├── tears_rt.jpg │ │ └── tears_up.jpg │ │ └── waternormals.jpg ├── styles │ ├── colors.css │ ├── fonts.css │ ├── login.css │ ├── lowerDisplay.css │ ├── main.css │ └── upperDisplay.css ├── three │ ├── ar │ │ └── ARPlanes.js │ ├── displayComponents │ │ └── DepthDisplay.js │ ├── scene.js │ └── vr │ │ ├── VRControls.js │ │ ├── VREffect.js │ │ ├── WebVR.js │ │ ├── tools │ │ ├── paint.js │ │ └── sculpt.js │ │ └── vr.js └── util │ ├── Common.js │ ├── Loader.js │ └── Logger.js ├── test └── test.js ├── webpack-gh-pages.config.js ├── webpack-production.config.js ├── webpack.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["es2015", {"modules": false}], // webpack understands the native import syntax, and uses it for tree shaking 4 | "react" // Transpile React components to JavaScript 5 | ], 6 | "plugins": [ 7 | "react-hot-loader/babel" 8 | // Enables React code to work with HMR. 9 | ], 10 | "compact": true 11 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "env": { 4 | "browser": true, 5 | "node": true 6 | }, 7 | "rules": { 8 | "no-console": "off", 9 | "prefer-template": "off", 10 | "no-plusplus": "off", 11 | "class-methods-use-this": "off" 12 | } 13 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | docs 4 | config.js 5 | yarn-error.log 6 | package-lock.json 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10.15.0" 4 | 5 | install: 6 | - npm i -g yarn && yarn 7 | 8 | before_script: 9 | - cp ./server/config_example.js ./server/config.js 10 | - npm run build-gh-pages 11 | 12 | deploy: 13 | local-dir: ./dist 14 | provider: pages 15 | skip-cleanup: true 16 | github-token: $GITHUB_TOKEN # Set in the settings page of your repository, as a secure variable 17 | keep-history: true 18 | on: 19 | branch: master -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright © 2010-2017 openPerform authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README-PerceptionNeuron.md: -------------------------------------------------------------------------------- 1 | This document shows how to hook the Percpetion Neuron motion capture suit to OpenPerform. 2 | 3 | # Setup Motion Streaming Software 4 | These two pieces of software enable the suit software to talk to OpenPerform. 5 | 6 | 1. Download and install the Axis Neuron software 7 | * > https://neuronmocap.com/downloads 8 | 2. Download, build, the PN Translator App (Windows Only) 9 | * > https://github.com/kinetecharts/PNTransformer 10 | 11 | 12 | # Configure Open Perform 13 | OpenPeform needs to know where the suit data is coming from. So, find the target IP address and add it to the server config. 14 | 15 | 1. Enable Perception Neuron data streaming 16 | * > /server/config.js, line 53 17 | 18 | > enabled: true 19 | 2. Add target IP address to the server config 20 | * > /server/config.js, line 54 21 | 22 | > If PNTransformer is running on same computer, use 127.0.0.1 23 | 24 | 3. Restart OpenPerform Server 25 | 26 | 27 | # First Run (Pre-recorded File) 28 | 29 | 1. Open Axis Neuron app. 30 | 31 | 2. Load a recorded capture session, hit play, and set it to loop. 32 | 33 | 3. Open PNTransformer app. 34 | 35 | * Click "Broadcast" (You should see the numbers start changing rapidly) 36 | 37 | # Live Motion Streaming 38 | 39 | Once the the Axis Neuron and PNTranformer apps are connected to the OpenPerform server, swapping sources is easy. 40 | 41 | 1. Power up suit 42 | 43 | 2. Connect suit to the same network as the computer running Axis Neuron and PNTranformer apps. 44 | 45 | 3. In Axis Neuron app, click Connect. 46 | 47 | 4. Select suit from list of available devices 48 | 49 | 5. That's it! If the OpenPerform server is still connected, it will display the live avatar as soon as it's connected. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/kinetecharts/openPerform.svg)](https://travis-ci.org/kinetecharts/openPerform) 2 | [![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/kinetecharts/openPerform.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/kinetecharts/openPerform/context:javascript) 3 | [![dependencies Status](https://david-dm.org/kinetecharts/openPerform/status.svg)](https://david-dm.org/kinetecharts/openPerform) 4 | [![devDependencies Status](https://david-dm.org/kinetecharts/openPerform/dev-status.svg)](https://david-dm.org/kinetecharts/openPerform?type=dev) 5 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 6 | 7 | ![alt text](https://github.com/kinetecharts/openPerform/raw/master/src/static/images/preview.gif "OpenPerform Preview") 8 | 9 | OpenPerform brings real-time motion capture to artists and performers excluded by the high barriers to entry of expensive or "closed" systems. Our open source javascript performance framework enables artists to take direct control of the medium, to quickly collaborate with others, and to easily craft new experiences for all web-based platforms (including AR and VR). 10 | 11 | Visit [OpenPerform.org](https://www.openperform.org) for more information. 12 | 13 | Demo 14 | ------------ 15 | Check out the various styles and effects OpenPerform has to offer with our BVH animation [demo!](https://kinetecharts.github.io/openPerform/) 16 | 17 | Built With 18 | ------------ 19 | * Node v10.15.0 20 | * Yarn 1.13.0 21 | * Webpack 4.29.3 22 | 23 | Note: These versions are a recommendation. New versions may or may not work properly. 24 | 25 | Install Dependancies 26 | ------------ 27 | 28 | > yarn 29 | 30 | Create Server Config 31 | ------------ 32 | 1. Navigate to 'server' directory 33 | 2. Copy 'config_example.js' 34 | 3. Rename your new file to 'config.js' 35 | 36 | Hot Development 37 | ------------ 38 | 39 | > npm run dev 40 | 41 | Once built, open 'http://localhost:8080' in your browser 42 | 43 | Build for Production 44 | ------------ 45 | 46 | > npm run build 47 | 48 | Once built, start produciton servers 49 | 50 | Start Production Servers 51 | ------------ 52 | 53 | > npm run start 54 | 55 | Once servers are running, open 'http://localhost:8080' in your browser -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | MAINTAINER Travis Bennett "travis@kineviz.com" 3 | 4 | #Increment before building or updating image 5 | LABEL version="1.0" 6 | 7 | # Open internal port (This is the port the node.js server is running on.) 8 | EXPOSE 8000 9 | 10 | # Clone our private GitHub Repository (Temporary solution. Needs encyrption key.) 11 | RUN git clone https://Jerknose:ZV9-Jf5-pkv-koP@bitbucket.org/kineviz/lobbycallglobe.git /home/node/app 12 | 13 | # Change to new repo directory 14 | WORKDIR /home/node/app 15 | 16 | # Install dependancies 17 | RUN npm install gulp -g 18 | RUN npm install 19 | 20 | # Copy default server conifig (Temporary solution. Config may need to be updated.) 21 | RUN cp server/config_example.js server/config.js 22 | 23 | # Build and run project 24 | RUN gulp build 25 | CMD ["node", "server/server.js"] -------------------------------------------------------------------------------- /docker/Dockerfile_example: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | MAINTAINER name "email@kineviz.com" 3 | 4 | #Increment before building or updating image 5 | LABEL version="1.0" 6 | 7 | # Open internal port (This is the port the node.js server is running on.) 8 | EXPOSE internal_port 9 | 10 | # Clone our private GitHub Repository (Temporary solution. Needs encyrption key.) 11 | RUN git clone https://bitbucket_username:bitbucket_password@bitbucket.org/kineviz/lobbycallglobe.git /home/node/app 12 | 13 | # Change to new repo directory 14 | WORKDIR /home/node/app 15 | 16 | # Install dependancies 17 | RUN npm install gulp -g 18 | RUN npm install 19 | 20 | # Copy default server conifig (Temporary solution. Config may need to be updated.) 21 | RUN cp server/config_example.js server/config.js 22 | 23 | # Build and run project 24 | RUN gulp build 25 | CMD ["node", "server/server.js"] -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | Requires Docker: https://www.docker.com/products/overview 2 | 3 | Build new Docker Image from this repo 4 | 1. Copy Dockerfile_example to Dockerfile 5 | 2. Edit Dockerfile 6 | a. Replace 'name' and 'email' with yours in the 'MAINTAINER' entry 7 | b. Replace 'internal_port' with your Node.js server port in teh 'EXPOSE' 8 | c. add your 'bitbucket_username' and 'bitbucket_password' to 'RUN git clone' url 9 | 3. Open Terminal 10 | a. navigate to this directory (with the Dockerfile) 11 | b. Run 'docker build -t docker_hub_organization/repo_name .' 12 | c. Wait... for a while 13 | 4. Verify Image was created by running 'docker images' 14 | a. (You can also verify the Image was created in the Kitematic app) 15 | 16 | Start Container from Docker Image 17 | 1. Open Terminal 18 | a. Run 'docker run -d -p external_port:internal_port docker_hub_organization/repo_name' 19 | 2. Verify Container is running by running 'docker ps' 20 | a. (You can also verify the Container is running in the Kitematic app) 21 | 3. Open browser 22 | a. Navigate to 'http://localhost:external_port' 23 | 24 | Upload Docker Image to Docker Hub 25 | 1. Go to hub.docker.com 26 | a. Create new repository 27 | i. Enter repo_name 28 | 2. Open Terminal 29 | a. Run 'docker commit repo_name' 30 | b. Run 'docker tag repo_name docker_hub_organization/repo_name' 31 | c. Run 'docker login --username="docker_hub_username"' 32 | d. Enter your Docker Hub password 33 | e. Run 'docker push docker_hub_organization/repo_name' 34 | f. Wait... for a while 35 | 36 | Deploy on AWS 37 | 1. Log in to AWS Console 38 | 2. Create New Instance 39 | a. Find "Amazon ECS-Optimized Amazon Linux AMI" on AWS Marketplace. It has Docker preinstalled. 40 | b. Security group must have external_port on the incoming port list 41 | 3. Download and install Docker Container from Docker Hub 42 | a. SSH into new AWS instance 43 | b. Run 'docker pull docker_hub_organization/repo_name' 44 | c. Wait... for a while 45 | c. Run 'docker run -d -p external_port:internal_port docker_hub_organization/repo_name' 46 | 47 | Handy Docker Commands 48 | 1. Remove all Images 49 | a. Run 'docker rmi $(docker images -q)' 50 | 2. Remove all Containers 51 | b. Run 'docker rm $(docker ps -a -q)' -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open_perform", 3 | "version": "0.0.2", 4 | "description": "", 5 | "main": "index.jsx", 6 | "scripts": { 7 | "webpack": "webpack-dev-server --history-api-fallback --watch-poll --progress --colors", 8 | "data": "node server/dataServer.js", 9 | "build": "webpack --config webpack-production.config.js --progress --profile --colors", 10 | "build-gh-pages": "webpack --config webpack-gh-pages.config.js --progress --profile --colors", 11 | "file": "node ./server/fileServer.js", 12 | "start": "npm run file | npm run data", 13 | "dev": "npm run webpack | npm run data", 14 | "test": "mocha" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/kinetecharts/openPerform.git" 19 | }, 20 | "author": "Kinecth Arts", 21 | "license": "ISC", 22 | "homepage": "https://github.com/kinetecharts/openPerform/#readme", 23 | "devDependencies": { 24 | "babel-core": "^6.26.0", 25 | "babel-loader": "^7.1.2", 26 | "babel-polyfill": "^6.26.0", 27 | "babel-preset-env": "^1.6.0", 28 | "babel-preset-es2015": "^6.24.1", 29 | "babel-preset-react": "^6.24.1", 30 | "base64-image-loader": "^1.2.1", 31 | "copy-webpack-plugin": "^4.3.1", 32 | "css-loader": "^2.1.0", 33 | "enzyme": "^3.0.0", 34 | "eslint": "^5.14.1", 35 | "eslint-config-airbnb": "^17.1.0", 36 | "eslint-config-airbnb-base": "^13.1.0", 37 | "eslint-friendly-formatter": "^4.0.1", 38 | "eslint-loader": "^2.1.2", 39 | "eslint-plugin-import": "^2.8.0", 40 | "eslint-plugin-jsx-a11y": "^6.0.2", 41 | "eslint-plugin-react": "^7.4.0", 42 | "expose-loader": "^0.7.3", 43 | "express": "^4.16.3", 44 | "extract-text-webpack-plugin": "^3.0.0", 45 | "file-loader": "^3.0.1", 46 | "html-webpack-plugin": "^3.2.0", 47 | "img-loader": "^3.0.1", 48 | "imports-loader": "^0.8.0", 49 | "mocha": "^6.0.0", 50 | "multer": "^1.3.0", 51 | "react-hot-loader": "^4.7.0", 52 | "style-loader": "^0.23.1", 53 | "terser": "^3.14.1", 54 | "url-loader": "^1.1.2", 55 | "webapp-webpack-plugin": "^2.6.0", 56 | "webpack": "^4.0.0", 57 | "webpack-cli": "^3.2.1", 58 | "webpack-dev-server": ">=3.1.11", 59 | "webpack-glsl-loader": "^1.0.1" 60 | }, 61 | "dependencies": { 62 | "bootstrap": "^3.3.7", 63 | "comment-regex": "^1.0.1", 64 | "console-log-html": "^2.0.2", 65 | "dat-gui": "^0.5.0", 66 | "jquery": "^3.2.1", 67 | "layout-bmfont-text": "^1.3.4", 68 | "load-bmfont": "^1.3.1", 69 | "lodash-keyarrange": "^1.1.0", 70 | "mousetrap": "^1.6.1", 71 | "myo": "^3.0.0", 72 | "net": "^1.0.2", 73 | "node-neurosky": "0.0.1", 74 | "node-osc": "^3.0.0", 75 | "os": "^0.1.1", 76 | "quad-indices": "^2.0.1", 77 | "rc-input-number": "^4.0.2", 78 | "react": "^16.7.0", 79 | "react-bootstrap": "^0.32.0", 80 | "react-color": "^2.13.8", 81 | "react-dat-gui": "^2.1.0", 82 | "react-dom": "^16.0.0", 83 | "react-dropzone": "^5.0.1", 84 | "react-fa": "^5.0.0", 85 | "react-list-select": "^0.4.0", 86 | "react-select": "^1.0.0-rc.10", 87 | "react-simple-select": "^1.2.2", 88 | "three": "^0.101.1", 89 | "three-buffer-vertex-data": "^1.1.0", 90 | "three-orbit-controls": "^82.1.0", 91 | "three-shadertoy-material": "^1.2.6", 92 | "tls": "^0.0.1", 93 | "tween": "^0.9.0", 94 | "tween.js": "^16.6.0", 95 | "ws": "^6.1.4" 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /server/config_example.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const config = { 4 | app: { 5 | port: 8000, 6 | }, 7 | browserSync: { 8 | port: 8080, 9 | }, 10 | favicon: path.resolve(__dirname, './../docs/images/favicon.ico'), 11 | shaderToy: { 12 | key: '', 13 | }, 14 | copy: { 15 | all: { 16 | src: './src/static/', 17 | } 18 | }, 19 | fileUpload: { 20 | port: 8888, 21 | }, 22 | // input sockets 23 | kinectTransport: { 24 | enabled: false, 25 | ports: { 26 | incoming: 3000, 27 | outgoing: 9999, 28 | }, 29 | }, 30 | perceptionNeuron: { 31 | enabled: false, 32 | ip: '127.0.0.1', // ip the Axis Neuron translation app is broadcasting from 33 | ports: { 34 | incoming: 9000, // port the Axis Neuron translation app is broadcasting on 35 | outgoing: 9100, // port the browser connects on 36 | }, 37 | }, 38 | gamepads: { 39 | enabled: false, 40 | ports: { 41 | outgoing: 9101, // port the browser connects on 42 | }, 43 | }, 44 | midiController: { 45 | enabled: false, 46 | ports: { 47 | outgoing: 9301, // port the browser connects on 48 | }, 49 | }, 50 | oscController: { 51 | enabled: false, 52 | ports: { 53 | incoming: 9400, 54 | outgoing: 9401, // port the browser connects on 55 | }, 56 | }, 57 | poseNet: { 58 | enabled: false, 59 | ports: { 60 | incoming: 9500, 61 | outgoing: 9501, // port the browser connects on 62 | }, 63 | }, 64 | iPhoneX: { 65 | enabled: false, 66 | ports: { 67 | incoming: 9600, 68 | outgoing: 9601, // port the browser connects on 69 | }, 70 | }, 71 | kinectron: { 72 | enabled: false, 73 | ports: { 74 | incoming: 9700, 75 | }, 76 | }, 77 | }; 78 | 79 | module.exports = config; 80 | -------------------------------------------------------------------------------- /server/dataServer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 07:43:36 5 | * @modify date 2018-08-26 07:43:36 6 | * @desc [The data server listens to various sockets and rebroadcasts data to each client.] 7 | */ 8 | 9 | const config = require('./config.js'); 10 | 11 | // init kinect server 12 | if (config.kinectTransport.enabled) { 13 | require('./sockets/KinectTransport'); 14 | } 15 | 16 | // init perception neuron server 17 | if (config.perceptionNeuron.enabled) { 18 | const PNServer = require('./sockets/PerceptionNeuron'); 19 | new PNServer(); 20 | } 21 | 22 | // init gamepad server 23 | if (config.gamepads.enabled) { 24 | const GPServer = require('./sockets/Gamepads'); 25 | new GPServer(); 26 | } 27 | 28 | // init midi controller server 29 | if (config.midiController.enabled) { 30 | const MidiController = require('./sockets/MidiController'); 31 | new MidiController(); 32 | } 33 | 34 | // init osc server 35 | if (config.oscController.enabled) { 36 | const OSCServer = require('./sockets/OSCServer'); 37 | new OSCServer(); 38 | } 39 | 40 | // init poseNet server 41 | if (config.poseNet.enabled) { 42 | const PoseNetServer = require('./sockets/PoseNet'); 43 | new PoseNetServer(); 44 | } 45 | 46 | // init iPhoneX server 47 | if (config.iPhoneX.enabled) { 48 | const IPhoneXServer = require('./sockets/iPhoneX'); 49 | new IPhoneXServer(); 50 | } -------------------------------------------------------------------------------- /server/fileServer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 07:42:28 5 | * @modify date 2018-08-26 07:42:28 6 | * @desc [The file server serves the static, production version of the app. ] 7 | */ 8 | 9 | const path = require('path'); 10 | const express = require('express') 11 | const serveStatic = require('serve-static') 12 | 13 | const config = require('./config'); 14 | 15 | const app = express() 16 | 17 | app.use(serveStatic(path.join(__dirname, './../dist'))) 18 | 19 | const server = app.listen(config.browserSync.port, () => { 20 | var host = server.address().address; 21 | var port = server.address().port; 22 | 23 | console.log('listening at http://%s:%s', host, port); 24 | }); -------------------------------------------------------------------------------- /server/sockets/Gamepads.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 07:49:09 5 | * @modify date 2018-08-26 07:49:09 6 | * @desc [Listen for and rebroadcast gamepad data.] 7 | */ 8 | 9 | const WebSocket = require('ws'); 10 | 11 | const config = require('./../config.js').gamepads; 12 | 13 | class Gamepads { 14 | constructor() { 15 | console.log('Gamepad Server broadasting on ' + config.ports.outgoing); 16 | this.wss = new WebSocket.Server({ port: config.ports.outgoing }); 17 | this.wss.on('connection', this.onBroadcastConnection.bind(this)); 18 | this.wss.on('error', this.onBroadcastError.bind(this)); 19 | this.wss.on('listening', this.onBroadcastListening.bind(this)); 20 | } 21 | onBroadcastConnection(ws) { 22 | console.log('Gamepad Server Connected!'); 23 | ws.on('message', this.onBroadcastMessage.bind(this)); 24 | } 25 | onBroadcastError(err) { 26 | console.log('Gamepad Server Error! ', err); 27 | } 28 | 29 | onBroadcastListening() { 30 | console.log('Gamepad Server Listening!'); 31 | } 32 | 33 | onBroadcastMessage(data) { 34 | this.broadcast(data); 35 | } 36 | 37 | broadcast(data) { 38 | this.wss.clients.forEach((client) => { 39 | if (client.readyState === WebSocket.OPEN) { 40 | try { 41 | client.send(data, this.onBroadcastError); 42 | } catch (err) { 43 | this.onBroadcastError(err); 44 | } finally { 45 | console.log('Something broke. :('); 46 | } 47 | } 48 | }); 49 | } 50 | } 51 | 52 | module.exports = Gamepads; 53 | -------------------------------------------------------------------------------- /server/sockets/MidiController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 07:50:43 5 | * @modify date 2018-08-26 07:50:43 6 | * @desc [Listen for and rebroadcast Midi data.] 7 | */ 8 | 9 | const WebSocket = require('ws'); 10 | 11 | const config = require('./../config.js').midiController; 12 | 13 | class MidiController { 14 | constructor() { 15 | console.log('Midi Controller broadasting on ' + config.ports.outgoing); 16 | this.wss = new WebSocket.Server({ port: config.ports.outgoing }); 17 | this.wss.on('connection', this.onBroadcastConnection.bind(this)); 18 | this.wss.on('error', this.onBroadcastError.bind(this)); 19 | this.wss.on('listening', this.onBroadcastListening.bind(this)); 20 | } 21 | onBroadcastConnection(ws) { 22 | console.log('Midi Controller Connected!'); 23 | ws.on('message', this.onBroadcastMessage.bind(this)); 24 | } 25 | onBroadcastError(err) { 26 | console.log('Midi Controller Error! ', err); 27 | } 28 | 29 | onBroadcastListening() { 30 | console.log('Midi Controller Listening!'); 31 | } 32 | 33 | onBroadcastMessage(data) { 34 | this.broadcast(data); 35 | } 36 | 37 | broadcast(data) { 38 | this.wss.clients.forEach((client) => { 39 | if (client.readyState === WebSocket.OPEN) { 40 | try { 41 | client.send(data, this.onBroadcastError); 42 | } catch (err) { 43 | this.onBroadcastError(err); 44 | } finally { 45 | console.log('Something broke. :('); 46 | } 47 | } 48 | }); 49 | } 50 | } 51 | 52 | module.exports = MidiController; 53 | -------------------------------------------------------------------------------- /server/sockets/OSCServer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 07:50:57 5 | * @modify date 2018-08-26 07:50:57 6 | * @desc [Listen for and rebroadcast OSC data.] 7 | */ 8 | 9 | const osc = require('node-osc'); 10 | const WebSocket = require('ws'); 11 | 12 | const config = require('./../config.js').oscController; 13 | 14 | class OSCServer { 15 | constructor() { 16 | this.oscServer = new osc.Server(config.ports.incoming, '0.0.0.0'); 17 | 18 | this.wss = new WebSocket.Server({ port: config.ports.outgoing }); 19 | this.wss.on('connection', this.onBroadcastConnection.bind(this)); 20 | this.wss.on('error', this.onBroadcastError.bind(this)); 21 | this.wss.on('listening', this.onBroadcastListening.bind(this)); 22 | } 23 | 24 | onBroadcastConnection(ws) { 25 | console.log('OSC Controller Connected!'); 26 | this.oscServer.on('message', this.onBroadcastMessage.bind(this)); 27 | } 28 | 29 | onBroadcastError(err) { 30 | // console.log('OSC Controller Error! ', err); 31 | } 32 | 33 | onBroadcastListening() { 34 | console.log('OSC Controller Listening!'); 35 | } 36 | 37 | onBroadcastMessage(data) { 38 | this.broadcast(data); 39 | } 40 | 41 | broadcast(data, rinfo) { 42 | this.wss.clients.forEach((client) => { 43 | if (client.readyState === WebSocket.OPEN) { 44 | try { 45 | client.send(JSON.stringify(data), this.onBroadcastError); 46 | } catch (err) { 47 | // this.onBroadcastError(err); 48 | } finally { 49 | // console.log('Something broke. :(', client); 50 | } 51 | } 52 | }); 53 | } 54 | } 55 | 56 | module.exports = OSCServer; 57 | -------------------------------------------------------------------------------- /server/sockets/PerceptionNeuron.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 07:51:12 5 | * @modify date 2018-08-26 07:51:12 6 | * @desc [Listen for and rebroadcast Perception Neuron data.] 7 | */ 8 | 9 | var WebSocket = require('ws'); 10 | var _ = require('lodash'); 11 | 12 | var config = require('./../config.js').perceptionNeuron; 13 | 14 | class PerceptionNeuron { 15 | constructor() { 16 | this.url = 'ws://' + config.ip + ':' + config.ports.incoming + "/service"; 17 | 18 | this.createListenServer(); 19 | this.createBroadcastServer(); 20 | } 21 | 22 | createBroadcastServer() { 23 | console.log('Perception Neuron Server broadasting on ' + config.ports.outgoing); 24 | this.wss = new WebSocket.Server({ port: config.ports.outgoing }); 25 | this.wss.on('connection', this.onBroadcastConnection.bind(this)); 26 | this.wss.on('error', this.onBroadcastError.bind(this)); 27 | this.wss.on('listening', this.onBroadcastListening.bind(this)); 28 | } 29 | 30 | createListenServer() { 31 | console.log('Connecting to the Perception Neuron at ' + this.url); 32 | this.ws = new WebSocket(this.url); 33 | this.ws.on('open', this.onListenOpen.bind(this)); 34 | this.ws.on('message', this.onListenMessage.bind(this)); 35 | this.ws.on('error', this.onListenError.bind(this)); 36 | } 37 | 38 | onBroadcastConnection() { 39 | console.log('Perception Neuron Server Connected!'); 40 | } 41 | 42 | onBroadcastError() { 43 | console.log('Perception Neuron Server Error!'); 44 | } 45 | 46 | onBroadcastListening() { 47 | console.log('Perception Neuron Server Listening!'); 48 | } 49 | 50 | onListenOpen() { 51 | console.log('Perception Neuron Connected!'); 52 | } 53 | 54 | onListenClose() { 55 | console.log('Perception Neuron Disconnected!'); 56 | } 57 | 58 | onListenError(err) { 59 | console.log('Perception Neuron Error ', err); 60 | } 61 | 62 | onListenMessage(msg) { 63 | this.broadcast(msg); 64 | } 65 | 66 | broadcast(data) { 67 | this.wss.clients.forEach(function each(client) { 68 | if (client.readyState === WebSocket.OPEN) { 69 | try { 70 | client.send(data, this.onError); 71 | } 72 | catch(err) { 73 | this.onError(err); 74 | } 75 | finally {} 76 | } 77 | }.bind(this)); 78 | } 79 | } 80 | 81 | module.exports = PerceptionNeuron; -------------------------------------------------------------------------------- /server/sockets/PoseNet.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 07:53:23 5 | * @modify date 2018-08-26 07:53:23 6 | * @desc [Listen for and rebroadcast PoseNet data.] 7 | */ 8 | 9 | const WebSocket = require('ws'); 10 | 11 | const config = require('./../config.js').poseNet; 12 | 13 | class PoseNet { 14 | constructor() { 15 | console.log('PoseNet listening on ' + config.ports.incoming); 16 | this.wssIncoming = new WebSocket.Server({ port: config.ports.incoming }); 17 | this.wssIncoming.on('connection', this.onIncomingConnection.bind(this)); 18 | this.wssIncoming.on('error', this.onIncomingError.bind(this)); 19 | this.wssIncoming.on('listening', this.onIncomingListening.bind(this)); 20 | 21 | console.log('PoseNet broadcasting on ' + config.ports.outgoing); 22 | this.wssOutgoing = new WebSocket.Server({ port: config.ports.outgoing }); 23 | this.wssOutgoing.on('connection', this.onOutgoingConnection.bind(this)); 24 | this.wssOutgoing.on('error', this.onOutgoingError.bind(this)); 25 | this.wssOutgoing.on('listening', this.onOutgoingListening.bind(this)); 26 | } 27 | 28 | onIncomingConnection(ws) { 29 | console.log('PoseNet Incoming Connected!'); 30 | this.wsIncoming = ws; 31 | this.wsIncoming.on('error', this.onIncomingSocketError.bind(this)); 32 | this.wsIncoming.on('message', this.onIncomingMessage.bind(this)); 33 | } 34 | 35 | onIncomingSocketError(err) { 36 | console.log('PoseNet Incoming Socket Error! ', err); 37 | } 38 | 39 | onIncomingError(err) { 40 | console.log('PoseNet Incoming Error! ', err); 41 | } 42 | 43 | onIncomingListening() { 44 | console.log('PoseNet Incoming Listening!'); 45 | } 46 | 47 | onIncomingMessage(data) { 48 | this.broadcast(data); 49 | } 50 | 51 | onOutgoingConnection(ws) { 52 | console.log('PoseNet Outgoing Connected!'); 53 | this.wsOutgoing = ws; 54 | this.wsOutgoing.on('message', this.onOutgoingMessage.bind(this)); 55 | } 56 | 57 | onOutgoingError(err) { 58 | console.log('PoseNet Outgoing Error! ', err); 59 | } 60 | 61 | onOutgoingListening() { 62 | console.log('PoseNet Outgoing Listening!'); 63 | } 64 | 65 | onOutgoingMessage(data) { 66 | console.log(data); 67 | // this.broadcast(data); 68 | } 69 | 70 | broadcast(data) { 71 | this.wssOutgoing.clients.forEach((client) => { 72 | if (client.readyState === WebSocket.OPEN) { 73 | try { 74 | client.send(data, this.onBroadcastError); 75 | } catch (err) { 76 | this.onBroadcastError(err); 77 | } finally { 78 | console.log('Something broke. :('); 79 | } 80 | } 81 | }); 82 | } 83 | } 84 | 85 | module.exports = PoseNet; 86 | -------------------------------------------------------------------------------- /server/sockets/iPhoneX.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 07:49:39 5 | * @modify date 2018-08-26 07:49:39 6 | * @desc [Listen for and rebroadcast iPhoneX ARFace data.] 7 | */ 8 | 9 | const WebSocket = require('ws'); 10 | const net = require('net'); 11 | 12 | const config = require('./../config.js').iPhoneX; 13 | 14 | class IPhoneX { 15 | constructor() { 16 | console.log('IPhoneX listening on ' + config.ports.incoming); 17 | this.listen(config.ports.incoming); 18 | 19 | console.log('IPhoneX broadcasting on ' + config.ports.outgoing); 20 | this.wssOutgoing = new WebSocket.Server({ port: config.ports.outgoing }); 21 | this.wssOutgoing.on('connection', this.onOutgoingConnection.bind(this)); 22 | this.wssOutgoing.on('error', this.onOutgoingError.bind(this)); 23 | this.wssOutgoing.on('listening', this.onOutgoingListening.bind(this)); 24 | 25 | this.dataBuffer = ''; 26 | } 27 | 28 | onOutgoingConnection(ws) { 29 | console.log('IPhoneX Outgoing Connected!'); 30 | this.wsOutgoing = ws; 31 | this.wsOutgoing.on('message', this.onOutgoingMessage.bind(this)); 32 | } 33 | 34 | onOutgoingError(err) { 35 | console.log('IPhoneX Outgoing Error! ', err); 36 | } 37 | 38 | onOutgoingListening() { 39 | console.log('IPhoneX Outgoing Listening!'); 40 | } 41 | 42 | onOutgoingMessage(data) { 43 | console.log(data); 44 | // this.broadcast(data); 45 | } 46 | 47 | broadcast(data) { 48 | this.wssOutgoing.clients.forEach((client) => { 49 | if (client.readyState === WebSocket.OPEN) { 50 | try { 51 | client.send(JSON.stringify(data), this.onBroadcastError); 52 | } catch (err) { 53 | this.onBroadcastError(err); 54 | } finally { 55 | console.log('Something broke. :('); 56 | } 57 | } 58 | }); 59 | } 60 | 61 | listen(port) { 62 | net.createServer((conn) => { 63 | conn.setEncoding('utf8'); 64 | 65 | conn.on('message', (m) => { 66 | console.log('MESSAGE: ' + m); 67 | }); 68 | 69 | conn.on('data', (data) => { 70 | this.dataBuffer += data; 71 | if (data.charAt(data.length-1) == 'a') { // a == end of packet 72 | this.broadcast(this.dataBuffer.slice(1, -1)); 73 | this.dataBuffer = ''; 74 | } 75 | }); 76 | }).listen(port, '0.0.0.0'); 77 | } 78 | } 79 | 80 | module.exports = IPhoneX; 81 | -------------------------------------------------------------------------------- /src/effects/group/index.js: -------------------------------------------------------------------------------- 1 | 2 | import Line from './Line'; 3 | 4 | class GroupEffects { 5 | constructor(parent, colors, guiFolder) { 6 | this.parent = parent; 7 | this.effects = []; 8 | this.colors = colors; 9 | this.guiFolder = guiFolder; 10 | } 11 | 12 | add(effect) { 13 | switch (effect) { 14 | case 'line': 15 | this.effects.push(new Line(this.parent, this.colors[0], this.guiFolder)); 16 | break; 17 | } 18 | console.log(this.effects); 19 | } 20 | 21 | update(data) { 22 | _.each(this.effects, (effect) => { 23 | effect.update(data); 24 | }); 25 | } 26 | } 27 | 28 | module.exports = GroupEffects; 29 | -------------------------------------------------------------------------------- /src/effects/performer/MidiStream.js: -------------------------------------------------------------------------------- 1 | 2 | import TWEEN from 'tween.js'; 3 | 4 | import config from './../../config'; 5 | 6 | import Common from './../../util/Common' 7 | 8 | class MidiStream { 9 | constructor(effectId, parent, color, guiFolder) { 10 | this.id = effectId; 11 | this.name = 'midiStream'; 12 | this.parent = parent; 13 | this.color = color; 14 | this.guiFolder = guiFolder; 15 | this.performer = null; 16 | 17 | // this.addToDatGui(this.guiFolder); 18 | this.handDistanceRange = [1000, -1000]; 19 | this.handDistance = 1000; 20 | 21 | this.headYPos = 0; 22 | 23 | this.streamData = false; 24 | this.streamInterval = null; 25 | } 26 | 27 | update(performer, currentPose, distances) { 28 | this.performer = performer; 29 | // if (distances.hands < this.handDistanceRange[0]) { 30 | // this.handDistanceRange[0] = distances.hands; 31 | // } 32 | // if (distances.hands > this.handDistanceRange[1]) { 33 | // this.handDistanceRange[1] = distances.hands; 34 | // } 35 | 36 | // if (distances.hands < this.handDistance) { 37 | if (this.streamInterval == null) { 38 | this.streamInterval = setTimeout(() => { 39 | this.performer.outputManager.outputs.midicontroller.sendMidiNoteOn(60, 127); 40 | setTimeout(() => { 41 | this.performer.outputManager.outputs.midicontroller.sendMidiNoteOff(60, 127); 42 | this.handDistance = 1000; 43 | clearInterval(this.streamInterval); 44 | this.streamInterval = null; 45 | }, Common.mapRange( 46 | distances.hands, 47 | this.handDistanceRange[0], 48 | this.handDistanceRange[1], 49 | 250, 50 | 1000, 51 | ) / 4); 52 | }, Common.mapRange( 53 | distances.hands, 54 | this.handDistanceRange[0], 55 | this.handDistanceRange[1], 56 | 250, 57 | 1000, 58 | )); 59 | } 60 | // } 61 | } 62 | } 63 | 64 | module.exports = MidiStream; 65 | -------------------------------------------------------------------------------- /src/effects/performer/bmFont/lib/utils.js: -------------------------------------------------------------------------------- 1 | var itemSize = 2 2 | var box = { min: [0, 0], max: [0, 0] } 3 | 4 | function bounds (positions) { 5 | var count = positions.length / itemSize 6 | box.min[0] = positions[0] 7 | box.min[1] = positions[1] 8 | box.max[0] = positions[0] 9 | box.max[1] = positions[1] 10 | 11 | for (var i = 0; i < count; i++) { 12 | var x = positions[i * itemSize + 0] 13 | var y = positions[i * itemSize + 1] 14 | box.min[0] = Math.min(x, box.min[0]) 15 | box.min[1] = Math.min(y, box.min[1]) 16 | box.max[0] = Math.max(x, box.max[0]) 17 | box.max[1] = Math.max(y, box.max[1]) 18 | } 19 | } 20 | 21 | module.exports.computeBox = function (positions, output) { 22 | bounds(positions) 23 | output.min.set(box.min[0], box.min[1], 0) 24 | output.max.set(box.max[0], box.max[1], 0) 25 | } 26 | 27 | module.exports.computeSphere = function (positions, output) { 28 | bounds(positions) 29 | var minX = box.min[0] 30 | var minY = box.min[1] 31 | var maxX = box.max[0] 32 | var maxY = box.max[1] 33 | var width = maxX - minX 34 | var height = maxY - minY 35 | var length = Math.sqrt(width * width + height * height) 36 | output.center.set(minX + width / 2, minY + height / 2, 0) 37 | output.radius = length / 2 38 | } 39 | -------------------------------------------------------------------------------- /src/effects/performer/bmFont/lib/vertices.js: -------------------------------------------------------------------------------- 1 | module.exports.pages = function pages (glyphs) { 2 | var pages = new Float32Array(glyphs.length * 4 * 1) 3 | var i = 0 4 | glyphs.forEach(function (glyph) { 5 | var id = glyph.data.page || 0 6 | pages[i++] = id 7 | pages[i++] = id 8 | pages[i++] = id 9 | pages[i++] = id 10 | }) 11 | return pages 12 | } 13 | 14 | module.exports.uvs = function uvs (glyphs, texWidth, texHeight, flipY) { 15 | var uvs = new Float32Array(glyphs.length * 4 * 2) 16 | var i = 0 17 | glyphs.forEach(function (glyph) { 18 | var bitmap = glyph.data 19 | var bw = (bitmap.x + bitmap.width) 20 | var bh = (bitmap.y + bitmap.height) 21 | 22 | // top left position 23 | var u0 = bitmap.x / texWidth 24 | var v1 = bitmap.y / texHeight 25 | var u1 = bw / texWidth 26 | var v0 = bh / texHeight 27 | 28 | if (flipY) { 29 | v1 = (texHeight - bitmap.y) / texHeight 30 | v0 = (texHeight - bh) / texHeight 31 | } 32 | 33 | // BL 34 | uvs[i++] = u0 35 | uvs[i++] = v1 36 | // TL 37 | uvs[i++] = u0 38 | uvs[i++] = v0 39 | // TR 40 | uvs[i++] = u1 41 | uvs[i++] = v0 42 | // BR 43 | uvs[i++] = u1 44 | uvs[i++] = v1 45 | }) 46 | return uvs 47 | } 48 | 49 | module.exports.positions = function positions (glyphs) { 50 | var positions = new Float32Array(glyphs.length * 4 * 2) 51 | var i = 0 52 | glyphs.forEach(function (glyph) { 53 | var bitmap = glyph.data 54 | 55 | // bottom left position 56 | var x = glyph.position[0] + bitmap.xoffset 57 | var y = glyph.position[1] + bitmap.yoffset 58 | 59 | // quad size 60 | var w = bitmap.width 61 | var h = bitmap.height 62 | 63 | // BL 64 | positions[i++] = x 65 | positions[i++] = y 66 | // TL 67 | positions[i++] = x 68 | positions[i++] = y + h 69 | // TR 70 | positions[i++] = x + w 71 | positions[i++] = y + h 72 | // BR 73 | positions[i++] = x + w 74 | positions[i++] = y 75 | }) 76 | return positions 77 | } 78 | -------------------------------------------------------------------------------- /src/effects/performer/bmFont/shaders/msdf.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function createMSDFShader(o) { 3 | const opt = o || {}; 4 | const opacity = typeof opt.opacity === 'number' ? opt.opacity : 1; 5 | const alphaTest = typeof opt.alphaTest === 'number' ? opt.alphaTest : 0.0001; 6 | const precision = opt.precision || 'highp'; 7 | const color = opt.color; 8 | const map = opt.map; 9 | 10 | // remove to satisfy r73 11 | delete opt.map; 12 | delete opt.color; 13 | delete opt.precision; 14 | delete opt.opacity; 15 | 16 | return Object.assign({ 17 | uniforms: { 18 | opacity: { 19 | type: 'f', 20 | value: opacity, 21 | }, 22 | map: { 23 | type: 't', 24 | value: map || new THREE.Texture(), 25 | }, 26 | color: { 27 | type: 'c', 28 | value: new THREE.Color(color), 29 | }, 30 | }, 31 | vertexShader: [ 32 | 'attribute vec2 uv;', 33 | 'attribute vec4 position;', 34 | 'uniform mat4 projectionMatrix;', 35 | 'uniform mat4 modelViewMatrix;', 36 | 'varying vec2 vUv;', 37 | 'varying float distToCamera;', 38 | 'void main() {', 39 | 'vUv = uv;', 40 | 'vec4 cs_position = modelViewMatrix * position;', 41 | 'distToCamera = -cs_position.z;', 42 | 'gl_Position = projectionMatrix * cs_position;', 43 | '//gl_Position = projectionMatrix * modelViewMatrix * position;', 44 | '}', 45 | ].join('\n'), 46 | fragmentShader: [ 47 | '#ifdef GL_OES_standard_derivatives', 48 | '#extension GL_OES_standard_derivatives : enable', 49 | '#endif', 50 | 'precision ' + precision + ' float;', 51 | 'uniform float opacity;', 52 | 'uniform vec3 color;', 53 | 'uniform sampler2D map;', 54 | 'varying vec2 vUv;', 55 | 'varying float distToCamera;', 56 | 57 | 'float median(float r, float g, float b) {', 58 | ' return max(min(r, g), min(max(r, g), b));', 59 | '}', 60 | 61 | 'void main() {', 62 | ' vec3 sample = 1.0 - texture2D(map, vUv).rgb;', 63 | ' float sigDist = median(sample.r, sample.g, sample.b) - 0.5;', 64 | ' float compensate = abs(distToCamera) * 0.3;', 65 | ' float lighten = abs(distToCamera) * 0.01;', 66 | ' // float alpha = clamp(sigDist/fwidth(sigDist) + 0.5 + compensate, 0.0, 1.0);', 67 | ' float alpha = clamp(sigDist/fwidth(sigDist) / (1.0+compensate) + 0.5 + lighten, 0.0, 1.0);', 68 | ' // alpha = clamp(sigDist + 0.5, 0.0, 1.0);', 69 | ' gl_FragColor = vec4(color.xyz, alpha * opacity);', 70 | alphaTest === 0 71 | ? '' 72 | : ' if (gl_FragColor.a < ' + alphaTest + ') discard;', 73 | '}', 74 | ].join('\n'), 75 | }, opt); 76 | }; 77 | -------------------------------------------------------------------------------- /src/effects/performer/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import Ribbons from './Ribbons'; 4 | import ParticleSystem from './ParticleSystem'; 5 | import Vogue from './Vogue'; 6 | import MovementSculpture from './MovementSculpture'; 7 | import Ghosting from './Ghosting'; 8 | import Drawing from './Drawing'; 9 | import DataTags from './DataTags'; 10 | import MidiStream from './MidiStream'; 11 | 12 | import config from './../../config'; 13 | 14 | class PerformerEffects { 15 | constructor(parent, color) { 16 | this.parent = parent; 17 | this.effects = []; 18 | this.color = color; 19 | } 20 | 21 | add(effect) { 22 | if (_.filter(this.effects, eff => eff.name == effect).length > 0) { 23 | console.log('Effect is already loaded...'); 24 | return false; 25 | } 26 | switch (effect) { 27 | case 'Ghosting': 28 | this.effects.push(new Ghosting(effect, this.parent, this.color)); 29 | break; 30 | case 'Vogue': 31 | this.effects.push(new Vogue(effect, this.parent, this.color)); 32 | break; 33 | case 'Movement Sculpture': 34 | this.effects.push(new MovementSculpture(effect, this.parent, this.color)); 35 | break; 36 | case 'Particles': 37 | this.effects.push(new ParticleSystem(effect, this.parent, this.color)); 38 | break; 39 | case 'Ribbons': 40 | this.effects.push(new Ribbons(effect, this.parent, this.color)); 41 | break; 42 | case 'Drawing': 43 | this.effects.push(new Drawing(effect, this.parent, this.color)); 44 | break; 45 | case 'Data Tags': 46 | this.effects.push(new DataTags(effect, this.parent, this.color)); 47 | break; 48 | case 'Midi Stream': 49 | this.effects.push(new MidiStream(effect, this.parent, this.color)); 50 | break; 51 | } 52 | console.log(this.effects); 53 | } 54 | 55 | remove(effect) { 56 | const matches = _.filter(this.effects, eff => eff.name == effect); 57 | if (matches.length > 0) { 58 | this.effects[0].remove(); 59 | _.remove(this.effects, eff => eff.name == effect); 60 | } 61 | } 62 | 63 | removeAll() { 64 | _.each(this.effects, (effect) => { 65 | effect.remove(); 66 | _.remove(this.effects, eff => eff.name == effect); 67 | }); 68 | this.effects = []; 69 | } 70 | 71 | updateParameters(data) { 72 | _.each(this.effects, (effects) => { 73 | effects.updateParameters(data); 74 | }); 75 | } 76 | 77 | update(data, currentPose, distances) { 78 | _.each(this.effects, (effect) => { 79 | effect.update(data, currentPose, distances); 80 | }); 81 | } 82 | } 83 | 84 | module.exports = PerformerEffects; 85 | -------------------------------------------------------------------------------- /src/environments/emptyEnvironment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 03:41:26 5 | * @modify date 2018-09-02 03:41:26 6 | * @desc [description] 7 | */ 8 | 9 | import EmptyMenu from '../react/menus/environment/EmptyMenu'; 10 | 11 | class EmptyEnvironment { 12 | constructor(renderer, parent, performers, defaults) { 13 | this.renderer = renderer; 14 | this.parent = parent; 15 | this.performers = performers; 16 | this.defaults = defaults; 17 | 18 | this.name = "Empty"; 19 | 20 | this.elements = []; 21 | this.lights = []; 22 | 23 | this.visible = true; 24 | 25 | this.options = {}; 26 | 27 | this.spotLight = null; 28 | 29 | this.initFloor(200); 30 | this.initLights(); 31 | } 32 | 33 | toggleVisible() { 34 | this.setVisible(!this.getVisible()); 35 | } 36 | 37 | getVisible() { 38 | return this.visible; 39 | } 40 | 41 | setVisible(val) { 42 | this.visible = val; 43 | this.elements.forEach((element) => { 44 | element.visible = val; 45 | }); 46 | } 47 | 48 | initFloor(size) { 49 | this.floor = new THREE.Mesh( 50 | new THREE.PlaneBufferGeometry(size, size, 1), 51 | new THREE.ShadowMaterial({ 52 | opacity: 0.9, 53 | }), 54 | ); 55 | this.floor.rotation.x = -Math.PI / 2; 56 | this.floor.receiveShadow = true; 57 | this.parent.add(this.floor); 58 | this.elements.push(this.floor); 59 | } 60 | 61 | initLights() { 62 | const directionalLight = new THREE.DirectionalLight(0xffffff, 0.75); 63 | directionalLight.position.set(-5, 10, 10); 64 | directionalLight.castShadow = true; 65 | this.parent.add(directionalLight); 66 | 67 | directionalLight.shadow.mapSize.width = 512; // default 68 | directionalLight.shadow.mapSize.height = 512; // default 69 | directionalLight.shadow.camera.near = 0.5; // default 70 | directionalLight.shadow.camera.far = 500; // default 71 | } 72 | 73 | removeElements() { 74 | this.elements.forEach((element) => { 75 | this.parent.remove(element); 76 | }); 77 | } 78 | 79 | removeLights() { 80 | this.lights.forEach((light) => { 81 | this.parent.remove(light); 82 | }); 83 | } 84 | 85 | remove() { 86 | this.removeElements(); 87 | this.removeLights(); 88 | } 89 | 90 | update(timeDelta) { 91 | // put frame updates here. 92 | } 93 | 94 | // updated options from gui 95 | updateOptions(data) { 96 | this.options = data; 97 | } 98 | 99 | // returns react gui object when effect is selected 100 | getGUI() { 101 | return ; 103 | } 104 | } 105 | 106 | module.exports = EmptyEnvironment; 107 | -------------------------------------------------------------------------------- /src/environments/spacedEnvironment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 03:46:15 5 | * @modify date 2018-09-02 03:46:15 6 | * @desc [description] 7 | */ 8 | 9 | import FileLoader from '../util/Loader.js'; 10 | import SpaceMenu from '../react/menus/environment/SpaceMenu'; 11 | 12 | class SpacedEnvironment { 13 | constructor(renderer, parent, performers, defaults) { 14 | this.renderer = renderer; 15 | this.parent = parent; 16 | this.performers = performers; 17 | this.defaults = defaults; 18 | 19 | this.name = "Space"; 20 | 21 | this.elements = []; 22 | this.lights = []; 23 | 24 | this.visible = true; 25 | 26 | this.options = {}; 27 | 28 | this.loader = new FileLoader(); 29 | 30 | this.initSpace(); 31 | this.initLights(); 32 | } 33 | 34 | toggleVisible(val) { 35 | this.setVisible(!this.getVisible()); 36 | } 37 | 38 | getVisible() { 39 | return this.visible; 40 | } 41 | 42 | setVisible(val) { 43 | console.log(val); 44 | this.visible = val; 45 | this.elements.forEach((element) => { 46 | element.visible = val; 47 | }); 48 | } 49 | 50 | initSpace() { 51 | this.loader.loadGLTF('../models/gltf/mars/scene.gltf', {}, (gltf) => { 52 | // const s = 0.1; 53 | // gltf.scene.scale.set(s, s, s); 54 | window.gltf = gltf.scene; 55 | gltf.scene.position.y = -50; 56 | 57 | this.elements.push(gltf.scene); 58 | this.parent.add(gltf.scene); 59 | }); 60 | } 61 | 62 | initFloor(size) { 63 | this.floor = new THREE.Mesh( 64 | new THREE.PlaneBufferGeometry( size, size, 1 ), 65 | new THREE.ShadowMaterial({ opacity: 0.9 }) 66 | ); 67 | this.floor.rotation.x = -Math.PI/2; 68 | this.floor.receiveShadow = true; 69 | 70 | this.elements.push(this.floor); 71 | this.parent.add(this.floor); 72 | } 73 | 74 | initLights() { 75 | const directionalLight = new THREE.DirectionalLight(0xffffff, 0.75); 76 | 77 | directionalLight.position.set( -5, 10, 10 ); 78 | directionalLight.castShadow = true; 79 | 80 | directionalLight.shadow.mapSize.width = 512; // default 81 | directionalLight.shadow.mapSize.height = 512; // default 82 | directionalLight.shadow.camera.near = 0.5; // default 83 | directionalLight.shadow.camera.far = 500; // default 84 | 85 | this.lights.push(directionalLight); 86 | this.parent.add(directionalLight); 87 | } 88 | 89 | removeElements() { 90 | this.elements.forEach((element) => { 91 | this.parent.remove(element); 92 | }); 93 | } 94 | 95 | removeLights() { 96 | this.lights.forEach((light) => { 97 | this.parent.remove(light); 98 | }); 99 | } 100 | 101 | remove() { 102 | this.removeLights(); 103 | this.removeElements(); 104 | } 105 | 106 | update(timeDelta) { 107 | // put frame updates here. 108 | } 109 | 110 | // updated options from gui 111 | updateOptions(data) { 112 | this.options = data; 113 | this.remove(); 114 | } 115 | 116 | // returns react gui object when effect is selected 117 | getGUI() { 118 | return ; 120 | } 121 | } 122 | 123 | module.exports = SpacedEnvironment; 124 | -------------------------------------------------------------------------------- /src/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 |
9 | 10 | -------------------------------------------------------------------------------- /src/index.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 07:54:30 5 | * @modify date 2018-08-26 07:54:30 6 | * @desc [Init React app. Attach to DOM.] 7 | */ 8 | 9 | 10 | import ReactDOM from 'react-dom'; 11 | 12 | import { AppContainer } from 'react-hot-loader'; 13 | // AppContainer is a necessary wrapper component for HMR 14 | 15 | import App from './react/pages/Main'; 16 | 17 | const render = (Component) => { 18 | ReactDOM.render( 19 | 20 | 21 | , 22 | document.getElementById('App'), 23 | ); 24 | }; 25 | 26 | render(App); 27 | 28 | // Hot Module Replacement API 29 | if (module.hot) { 30 | module.hot.accept('./', () => { 31 | console.info('-------Re-render React app-----'); 32 | render(App); 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /src/inputs/README.md: -------------------------------------------------------------------------------- 1 | Create a new Input 2 | 1. Copy inputs/ExampleInput.txt 3 | 2. Rename ExampleInput.txt to YourInputName.js 4 | 3. Open YourInputName.js in your favorite editor 5 | 4. Change 'class InputName' (first line) to 'class YourInputName' 6 | 5. Change 'module.exports = InputName' (last line) to 'module.exports = YourInputName' 7 | 6. Recompile OpenPerform 8 | 7. Select new preset from GUI 9 | 10 | Create a new Preset 11 | 1. Copy presets/ExamplePreset.txt 12 | 2. Rename ExamplePreset.txt to YourPresetName.js 13 | 3. Open YourPresetName.js in your favorite editor 14 | 4. Change 'class PresetName' (first line) to 'class YourPresetName' 15 | 5. Change 'module.exports = PresetName' (last line) to 'module.exports = YourPresetName' 16 | 6. Recompile OpenPerform 17 | 7. Select new preset from GUI 18 | -------------------------------------------------------------------------------- /src/inputs/types/ExampleInput.txt: -------------------------------------------------------------------------------- 1 | class InputName { 2 | constructor() { 3 | this.callbacks = {}; 4 | this.events = []; 5 | this.labels = []; 6 | } 7 | 8 | on(name, cb, event, label) { 9 | this.callbacks[name] = cb; 10 | this.events.push(event); 11 | this.labels.push(label); 12 | this.initCallbacks(); 13 | } 14 | 15 | clearCallbacks() { 16 | this.callbacks = {}; 17 | this.events = []; 18 | this.labels = []; 19 | } 20 | 21 | initCallbacks() { 22 | _.forEach(this.callbacks, this.initCallback.bind(this)); 23 | } 24 | 25 | initCallback(cb, name) { 26 | } 27 | } 28 | 29 | module.exports = InputName; 30 | -------------------------------------------------------------------------------- /src/inputs/types/Keyboard.js: -------------------------------------------------------------------------------- 1 | // Mousetrap Source: https://github.com/ccampbell/mousetrap 2 | 3 | 4 | import Mousetrap from 'mousetrap'; 5 | 6 | class Keyboard { 7 | constructor() { 8 | this.callbacks = {}; 9 | this.events = []; 10 | this.labels = []; 11 | } 12 | 13 | on(name, cb, event, label) { 14 | this.callbacks[name] = cb; 15 | this.events.push(event); 16 | this.labels.push(label); 17 | this.initCallbacks(); 18 | } 19 | 20 | clearCallbacks() { 21 | this.callbacks = {}; 22 | this.events = []; 23 | this.labels = []; 24 | } 25 | 26 | initCallbacks() { 27 | _.forEach(this.callbacks, this.initCallback.bind(this)); 28 | } 29 | 30 | initCallback(cb, name) { 31 | Mousetrap.bind(name, cb); 32 | } 33 | } 34 | 35 | module.exports = Keyboard; 36 | -------------------------------------------------------------------------------- /src/inputs/types/KinectTransport.js: -------------------------------------------------------------------------------- 1 | // KinectTransport Source: https://github.com/stimulant/MS-Cube-SDK/tree/research/KinectTransport 2 | 3 | 4 | 5 | import config from './../../config'; 6 | 7 | class KinectTransport { 8 | constructor() { 9 | this.callbacks = {}; 10 | this.events = []; 11 | this.labels = []; 12 | 13 | this.websocket = null; 14 | this.initializeWebSocket(); 15 | } 16 | 17 | initializeWebSocket() { 18 | this.websocket = new WebSocket(`ws://localhost:${config.kinecttransport.ports.outgoing}`); 19 | this.websocket.onopen = this.onOpen; 20 | this.websocket.onclose = this.oClose; 21 | this.websocket.onmessage = this.onMessage.bind(this); 22 | this.websocket.onerror = this.onError; 23 | 24 | // stop Chrome from ruining things and crashing the socket server 25 | window.addEventListener('beforeunload', () => { 26 | this.websocket.close(); 27 | }); 28 | } 29 | 30 | onOpen(evt) { 31 | console.log('KinectTransport connected:', evt); 32 | } 33 | 34 | onClose(evt) { 35 | console.log('KinectTransport disconnected:', evt); 36 | } 37 | 38 | onMessage(data) { 39 | const dataObj = JSON.parse(data.data); 40 | _.forEach(dataObj, (obj, key) => { 41 | switch (obj.type) { 42 | default: 43 | break; 44 | case 'bodies': 45 | let idx = 1; 46 | console.log(obj.bodies.bodies); 47 | _.forEach(obj.bodies.bodies, (body) => { 48 | if (typeof this.callbacks[obj.type] === 'function') { 49 | this.callbacks['bodies']('Kinect_User_' + idx, body, 'kinect'); 50 | } 51 | idx++; 52 | }); 53 | break; 54 | case 'depth': 55 | if (typeof this.callbacks[obj.type] === 'function') { 56 | this.callbacks['depth']('Kinect_User_' + idx, obj, 'kinect'); 57 | } 58 | break; 59 | } 60 | }); 61 | } 62 | 63 | onError(evt) { 64 | console.log('KinectTransport error:', evt); 65 | } 66 | 67 | on(name, cb, event, label) { 68 | this.callbacks[name] = cb; 69 | this.events.push(event); 70 | this.labels.push(label); 71 | this.initCallbacks(); 72 | } 73 | 74 | clearCallbacks() { 75 | this.callbacks = {}; 76 | this.events = []; 77 | this.labels = []; 78 | } 79 | 80 | initCallbacks() { 81 | // _.forEach(this.callbacks, this.initCallback.bind(this)); 82 | } 83 | } 84 | 85 | module.exports = KinectTransport; 86 | -------------------------------------------------------------------------------- /src/inputs/types/Mouse.js: -------------------------------------------------------------------------------- 1 | class Mouse { 2 | constructor(url) { 3 | this.callbacks = {}; 4 | this.events = []; 5 | this.labels = []; 6 | } 7 | 8 | on(name, cb, event, label) { 9 | this.callbacks[name] = cb; 10 | this.events.push(event); 11 | this.labels.push(label); 12 | this.initCallbacks(); 13 | } 14 | 15 | clearCallbacks() { 16 | this.callbacks = {}; 17 | this.events = []; 18 | this.labels = []; 19 | } 20 | 21 | initCallbacks() { 22 | _.forEach(this.callbacks, this.initCallback.bind(this)); 23 | } 24 | 25 | initCallback(cb, name) { 26 | } 27 | } 28 | 29 | module.exports = Mouse; 30 | -------------------------------------------------------------------------------- /src/inputs/types/Myo.js: -------------------------------------------------------------------------------- 1 | import Myo from 'myo'; 2 | 3 | 4 | // Myo devloper docs: https://github.com/thalmiclabs/myo.js/blob/master/docs.md 5 | 6 | class MyoInput { 7 | constructor() { 8 | this.callbacks = {}; 9 | this.events = []; 10 | this.labels = []; 11 | 12 | this.Myo = Myo; 13 | this.myos = []; 14 | 15 | this.Myo.connect('com.kineviz.myo'); 16 | this.Myo.on('connected', this.initMyos.bind(this)); 17 | } 18 | 19 | on(name, cb, event, label) { 20 | this.callbacks[name] = cb; 21 | this.events.push(event); 22 | this.labels.push(label); 23 | this.initCallbacks(); 24 | } 25 | 26 | clearCallbacks() { 27 | this.callbacks = {}; 28 | this.events = []; 29 | this.labels = []; 30 | } 31 | 32 | initCallbacks() { 33 | _.forEach(this.callbacks, this.initCallback.bind(this)); 34 | } 35 | 36 | initCallback(cb, name) { 37 | this.Myo.on(name, cb); 38 | } 39 | 40 | initMyos(myo) { 41 | _.forEach(this.Myo.myos, this.initMyo.bind(this)); 42 | this.saveMyos(); 43 | } 44 | 45 | initMyo(myo) { 46 | myo.streamEMG(true); 47 | } 48 | 49 | saveMyos() { 50 | this.myos = this.Myo.myos; 51 | } 52 | 53 | vibrate(myo) { 54 | console.log('Vibrating Myo:', myo.name); 55 | myo.vibrate(); // 'short', 'medium', 'long' 56 | } 57 | 58 | vibrateAll() { 59 | _.forEach(this.myos, this.vibrate); 60 | } 61 | } 62 | 63 | module.exports = MyoInput; 64 | -------------------------------------------------------------------------------- /src/inputs/types/NeuroSky.js: -------------------------------------------------------------------------------- 1 | const neurosky = require('node-neurosky'); 2 | 3 | 4 | 5 | // Myo devloper docs: https://github.com/thalmiclabs/myo.js/blob/master/docs.md 6 | 7 | class NeuroSky { 8 | constructor() { 9 | this.callbacks = {}; 10 | this.events = []; 11 | this.labels = []; 12 | 13 | this.ns = neurosky.createClient({ 14 | appName: 'KinevizMW', 15 | appKey: '1234567890abcdef...', 16 | }); 17 | this.ns.connect(); 18 | } 19 | 20 | on(name, cb, event, label) { 21 | this.callbacks[name] = cb; 22 | this.events.push(event); 23 | this.labels.push(label); 24 | this.initCallbacks(); 25 | } 26 | 27 | clearCallbacks() { 28 | this.callbacks = {}; 29 | this.events = []; 30 | this.labels = []; 31 | } 32 | 33 | initCallbacks() { 34 | _.forEach(this.callbacks, this.initCallback.bind(this)); 35 | } 36 | 37 | initCallback(cb, name) { 38 | this.ns.on(name, cb); 39 | } 40 | } 41 | 42 | module.exports = NeuroSky; 43 | -------------------------------------------------------------------------------- /src/inputs/types/OSCController.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | class OSCController { 4 | constructor(url) { 5 | this.callbacks = {}; 6 | this.events = []; 7 | this.labels = []; 8 | 9 | this.connected = false; 10 | this.websocket = null; 11 | 12 | this.keydown = {}; 13 | 14 | this.initializeWebSocket(url); 15 | } 16 | 17 | initializeWebSocket(url) { 18 | console.log('OSC Controller connecting to: ', url); 19 | 20 | this.websocket = new WebSocket(url); 21 | this.websocket.onopen = this.onOpen.bind(this); 22 | this.websocket.onclose = this.onClose.bind(this); 23 | this.websocket.onmessage = this.onMessage.bind(this); 24 | this.websocket.onerror = this.onError.bind(this); 25 | 26 | // stop Chrome from ruining things and crashing the socket server 27 | window.addEventListener('beforeunload', () => { 28 | this.websocket.close(); 29 | }); 30 | } 31 | 32 | 33 | onOpen(evt) { 34 | console.log('OSC Controller connected:', evt); 35 | this.connected = true; 36 | } 37 | 38 | onClose(evt) { 39 | console.log('OSC Controller disconnected:', evt); 40 | this.connected = false; 41 | } 42 | 43 | onMessage(msg) { 44 | this.callbacks.message(JSON.parse(msg.data)); 45 | } 46 | 47 | onError(evt) { 48 | console.log('OSC Controller error:', evt); 49 | } 50 | 51 | on(name, cb, event, label) { 52 | this.callbacks[name] = cb; 53 | this.events.push(event); 54 | this.labels.push(label); 55 | this.initCallbacks(); 56 | } 57 | 58 | clearCallbacks() { 59 | this.callbacks = {}; 60 | this.events = []; 61 | this.labels = []; 62 | } 63 | 64 | initCallbacks() { 65 | // _.forEach(this.callbacks, this.initCallback.bind(this)); 66 | } 67 | } 68 | 69 | module.exports = OSCController; 70 | -------------------------------------------------------------------------------- /src/inputs/types/PoseNet.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-27 11:07:07 5 | * @modify date 2018-08-27 11:07:07 6 | * @desc [Receive for posenet data.] 7 | */ 8 | 9 | 10 | 11 | class PoseNet { 12 | constructor(url) { 13 | this.callbacks = {}; 14 | this.events = []; 15 | this.labels = []; 16 | 17 | this.connected = false; 18 | this.websocket = null; 19 | 20 | this.keydown = {}; 21 | 22 | this.initializeWebSocket(url); 23 | } 24 | 25 | initializeWebSocket(url) { 26 | console.log('PoseNet connecting to: ', url); 27 | 28 | this.websocket = new WebSocket(url); 29 | this.websocket.onopen = this.onOpen.bind(this); 30 | this.websocket.onclose = this.onClose.bind(this); 31 | this.websocket.onmessage = this.onMessage.bind(this); 32 | this.websocket.onerror = this.onError.bind(this); 33 | 34 | // stop Chrome from ruining things and crashing the socket server 35 | window.addEventListener('beforeunload', () => { 36 | this.websocket.close(); 37 | }); 38 | } 39 | 40 | onOpen(evt) { 41 | console.log('PoseNet connected:', evt); 42 | this.connected = true; 43 | } 44 | 45 | onClose(evt) { 46 | console.log('PoseNet disconnected:', evt); 47 | this.connected = false; 48 | } 49 | 50 | onMessage(msg) { 51 | this.callbacks.message(JSON.parse(msg.data)); 52 | this.callbacks.message('PoseNet_User_0', JSON.parse(msg.data), 'poseNet'); 53 | } 54 | 55 | onError(evt) { 56 | console.log('PoseNet error:', evt); 57 | } 58 | 59 | on(name, cb, event, label) { 60 | this.callbacks[name] = cb; 61 | this.events.push(event); 62 | this.labels.push(label); 63 | this.initCallbacks(); 64 | } 65 | 66 | clearCallbacks() { 67 | this.callbacks = {}; 68 | this.events = []; 69 | this.labels = []; 70 | } 71 | 72 | initCallbacks() { 73 | // _.forEach(this.callbacks, this.initCallback.bind(this)); 74 | } 75 | } 76 | 77 | module.exports = PoseNet; 78 | -------------------------------------------------------------------------------- /src/inputs/types/iPhoneX.js: -------------------------------------------------------------------------------- 1 | import Logger from '../../util/Logger'; 2 | 3 | class IPhoneX { 4 | constructor(url) { 5 | this.callbacks = {}; 6 | this.events = []; 7 | this.labels = []; 8 | 9 | this.logger = new Logger(); 10 | 11 | this.connected = false; 12 | this.websocket = null; 13 | 14 | this.keydown = {}; 15 | 16 | this.initializeWebSocket(url); 17 | } 18 | 19 | initializeWebSocket(url) { 20 | console.log('iPhone X connecting to: ', url); 21 | 22 | this.websocket = new WebSocket(url); 23 | this.websocket.onopen = this.logger.onOpen.bind(this, this.constructor.name); 24 | this.websocket.onclose = this.logger.onClose.bind(this, this.constructor.name); 25 | this.websocket.onmessage = this.onMessage.bind(this); 26 | this.websocket.onerror = this.logger.onError.bind(this, this.constructor.name); 27 | } 28 | 29 | onMessage(msg) { 30 | const data = _.map(JSON.parse(msg.data).split('~'), (m) => { 31 | return m.split(':'); 32 | }); 33 | this.callbacks.message({ 34 | not: data.slice(0, data.length-208), 35 | 3: data.slice(data.length-208, data.length-156), 36 | 2: data.slice(data.length-156, data.length-104), 37 | 1: data.slice(data.length-104, data.length-52), 38 | blendShapes: data.slice(data.length-52, data.length), 39 | raw: data 40 | }); 41 | } 42 | 43 | on(name, cb, event, label) { 44 | this.callbacks[name] = cb; 45 | this.events.push(event); 46 | this.labels.push(label); 47 | this.initCallbacks(); 48 | } 49 | 50 | clearCallbacks() { 51 | this.callbacks = {}; 52 | this.events = []; 53 | this.labels = []; 54 | } 55 | 56 | initCallbacks() { 57 | // _.forEach(this.callbacks, this.initCallback.bind(this)); 58 | } 59 | } 60 | 61 | module.exports = IPhoneX; 62 | -------------------------------------------------------------------------------- /src/libs/BufferGeometryMerge.js: -------------------------------------------------------------------------------- 1 | THREE.BufferGeometry.prototype.merge = function (geometry) { 2 | if (geometry instanceof THREE.BufferGeometry === false) { 3 | console.error('THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry); 4 | return; 5 | } 6 | 7 | const attributes = this.attributes; 8 | 9 | if (this.index) { 10 | const indices = geometry.index.array; 11 | 12 | const offset = attributes.position.count; 13 | 14 | for (let i = 0, il = indices.length; i < il; i++) { 15 | indices[i] = offset + indices[i]; 16 | } 17 | 18 | this.index.array = Uint32ArrayConcat(this.index.array, indices); 19 | } 20 | 21 | for (const key in attributes) { 22 | if (geometry.attributes[key] === undefined) continue; 23 | 24 | attributes[key].array = Float32ArrayConcat(attributes[key].array, geometry.attributes[key].array); 25 | } 26 | 27 | return this; 28 | 29 | /** * 30 | * @param {Float32Array} first 31 | * @param {Float32Array} second 32 | * @returns {Float32Array} 33 | * @constructor 34 | */ 35 | function Float32ArrayConcat(first, second) { 36 | let firstLength = first.length, 37 | result = new Float32Array(firstLength + second.length); 38 | 39 | result.set(first); 40 | result.set(second, firstLength); 41 | 42 | return result; 43 | } 44 | 45 | /** 46 | * @param {Uint32Array} first 47 | * @param {Uint32Array} second 48 | * @returns {Uint32Array} 49 | * @constructor 50 | */ 51 | function Uint32ArrayConcat(first, second) { 52 | let firstLength = first.length, 53 | result = new Uint32Array(firstLength + second.length); 54 | 55 | result.set(first); 56 | result.set(second, firstLength); 57 | 58 | return result; 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /src/materials/ShaderToyLoader.js: -------------------------------------------------------------------------------- 1 | import ShaderToyMaterial from 'three-shadertoy-material'; 2 | 3 | import Mtdyzf from './shaders/Mtdyzf.json'; 4 | import XsX3RB from './shaders/XsX3RB.json'; 5 | import XtlSD7 from './shaders/XtlSD7.json'; 6 | import MsBfzm from './shaders/MsBfzm.json'; 7 | import MdBfzm from './shaders/MdBfzm.json'; 8 | 9 | import { shaderToy } from './../../server/config'; 10 | 11 | class ShaderToyLoader { 12 | constructor() { 13 | this.shaders = { 14 | Mtdyzf: [new ShaderToyMaterial(Mtdyzf.Shader.renderpass[0].code)], 15 | XsX3RB: [new ShaderToyMaterial(XsX3RB.Shader.renderpass[0].code)], 16 | XtlSD7: [new ShaderToyMaterial(XtlSD7.Shader.renderpass[0].code)], 17 | MsBfzm: [new ShaderToyMaterial(MsBfzm.Shader.renderpass[0].code)], 18 | MdBfzm: [new ShaderToyMaterial(MdBfzm.Shader.renderpass[0].code)], 19 | }; 20 | } 21 | 22 | getShader(id) { 23 | return new Promise((resolve, reject) => { 24 | if (this.shaders[id] !== undefined) { 25 | resolve(this.shaders[id]); 26 | return false; 27 | } 28 | this.getShaderToy('https://www.shadertoy.com/api/v1/shaders/' + id + '?key=' + shaderToy.key) 29 | .then((result) => { 30 | if (this.shaders[id] == undefined) { 31 | console.log(result.Shader.renderpass.length); 32 | if (result.Shader.renderpass.length > 1) { 33 | console.log(result.Shader.renderpass[1]); 34 | } 35 | this.shaders[id] = [new ShaderToyMaterial(result.Shader.renderpass[0].code)]; 36 | } 37 | resolve(this.shaders[id]); 38 | return false; 39 | }); 40 | }); 41 | } 42 | 43 | getShaderToy(url) { 44 | return new Promise((resolve, reject) => { 45 | const xhr = new XMLHttpRequest(); 46 | xhr.open('GET', url); 47 | xhr.onload = () => resolve(JSON.parse(xhr.responseText)); 48 | xhr.onerror = () => reject(xhr.statusText); 49 | xhr.send(); 50 | }); 51 | } 52 | } 53 | 54 | module.exports = ShaderToyLoader; 55 | -------------------------------------------------------------------------------- /src/materials/shaders/MdBfzm.json: -------------------------------------------------------------------------------- 1 | {"Shader":{"ver":"0.1","info":{"id":"MdBfzm","date":"1499892927","viewed":259,"name":"Halftone Dots","username":"cacheflowe","description":"A configurable halftone pattern for compositing purposes","likes":5,"published":3,"flags":0,"tags":["halftone","dots","pattern"],"hasliked":0},"renderpass":[{"inputs":[],"outputs":[{"id":37,"channel":0}],"code":"#define dotsRows 5.0\n#define radius 0.25\n#define invert 1\n\nvec2 rotateCoord(vec2 uv, float rads) {\n uv *= mat2(cos(rads), sin(rads), -sin(rads), cos(rads));\n\treturn uv;\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n \/\/ update layout params\n float rows = dotsRows + 3. * sin(iTime);\n float curRadius = radius + 0.15 * cos(iTime);\n \tfloat curRotation = iTime;\n vec2 curCenter = vec2(cos(iTime), sin(iTime));\n \/\/ get original coordinate, translate & rotate\n\tvec2 uv = (2. * fragCoord - iResolution.xy) \/ iResolution.y;\n uv += curCenter;\n uv = rotateCoord(uv, curRotation);\n \/\/ calc row index to offset x of every other row\n float rowIndex = floor(uv.y * rows);\t\t\n float oddEven = mod(rowIndex, 2.);\n \/\/ create grid coords\n vec2 uvRepeat = fract(uv * rows) - 0.5;\t\t\n if(oddEven == 1.) {\t\t\t\t\t\t\t\/\/ offset x by half\n \tuvRepeat = fract(vec2(0.5, 0.) + uv * rows) - vec2(0.5, 0.5);\t\n }\n \/\/ adaptive antialiasing, draw, invert\n float aa = iResolution.y * dotsRows * 0.00001; \t\n float col = smoothstep(curRadius - aa, curRadius + aa, length(uvRepeat));\n if(invert == 1) col = 1. - col;\t\t\t\n\tfragColor = vec4(vec3(col),1.0);\n}","name":"Image","description":"","type":"image"}]}} -------------------------------------------------------------------------------- /src/materials/shaders/MsBfzm.json: -------------------------------------------------------------------------------- 1 | {"Shader":{"ver":"0.1","info":{"id":"MsBfzm","date":"1499894783","viewed":256,"name":"Halftone Lines","username":"cacheflowe","description":"Another halftone pattern for compositing purposes","likes":2,"published":3,"flags":0,"tags":["lines","halftone","stripes"],"hasliked":0},"renderpass":[{"inputs":[],"outputs":[{"id":37,"channel":0}],"code":"#define linesRows 5.0\n#define thickness 0.25\n#define invert 0\n\nvec2 rotateCoord(vec2 uv, float rads) {\n uv *= mat2(cos(rads), sin(rads), -sin(rads), cos(rads));\n\treturn uv;\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n \/\/ update layout params\n float rows = linesRows * 0.5;\/\/linesRows + 3. * sin(iTime);\n float curThickness = 0.25 + 0.22 * cos(iTime);\n \tfloat curRotation = 0.8 * sin(iTime);\n \/\/ get original coordinate, translate & rotate\n\tvec2 uv = (2. * fragCoord - iResolution.xy) \/ iResolution.y;\n \/\/uv += curCenter;\n uv = rotateCoord(uv, curRotation);\n \/\/ create grid coords\n vec2 uvRepeat = fract(uv * rows);\t\t\n \/\/ adaptive antialiasing, draw, invert\n float aa = iResolution.y * 0.00003; \t\n float col = smoothstep(curThickness - aa, curThickness + aa, length(uvRepeat.y - 0.5));\n if(invert == 1) col = 1. - col;\t\t\t\n\tfragColor = vec4(vec3(col),1.0);\n}","name":"Image","description":"","type":"image"}]}} -------------------------------------------------------------------------------- /src/materials/shaders/Mtdyzf.json: -------------------------------------------------------------------------------- 1 | {"Shader":{"ver":"0.1","info":{"id":"Mtdyzf","date":"1533548930","viewed":408,"name":"wikipedia shadertoy shader","username":"shakthi_gs87","description":"wikipedia shadertoy sample shader from https:\/\/en.wikipedia.org\/wiki\/Shadertoy\n\nUsed for test on threejs here https:\/\/shakthi.github.io\/threejs-shadertoy\/dist\/","likes":1,"published":3,"flags":0,"tags":["wikipediashadertoy"],"hasliked":0},"renderpass":[{"inputs":[],"outputs":[{"id":37,"channel":0}],"code":"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n \/\/ input: pixel coordinates\n vec2 p = (-iResolution.xy + 2.0*fragCoord)\/iResolution.y;\n\n \/\/ angle of each pixel to the center of the screen\n float a = atan(p.y,p.x);\n \n \/\/ modified distance metric\n float r = pow( pow(p.x*p.x,4.0) + pow(p.y*p.y,4.0), 1.0\/8.0 );\n \n \/\/ index texture by (animated inverse) radious and angle\n vec2 uv = vec2( 1.0\/r + 0.2*iTime, a );\n\n \/\/ pattern: cosines\n float f = cos(12.0*uv.x)*cos(6.0*uv.y);\n\n \/\/ color fetch: palette\n vec3 col = 0.5 + 0.5*sin( 3.1416*f + vec3(0.0,0.5,1.0) );\n \n \/\/ lighting: darken at the center \n col = col*r;\n \n \/\/ output: pixel color\n fragColor = vec4( col, 1.0 );\n}","name":"Image","description":"","type":"image"}]}} -------------------------------------------------------------------------------- /src/outputs/README.md: -------------------------------------------------------------------------------- 1 | Create a new Input 2 | 1. Copy inputs/ExampleInput.txt 3 | 2. Rename ExampleInput.txt to YourInputName.js 4 | 3. Open YourInputName.js in your favorite editor 5 | 4. Change 'class InputName' (first line) to 'class YourInputName' 6 | 5. Change 'module.exports = InputName' (last line) to 'module.exports = YourInputName' 7 | 6. Recompile OpenPerform 8 | 7. Select new preset from GUI 9 | 10 | Create a new Preset 11 | 1. Copy presets/ExamplePreset.txt 12 | 2. Rename ExamplePreset.txt to YourPresetName.js 13 | 3. Open YourPresetName.js in your favorite editor 14 | 4. Change 'class PresetName' (first line) to 'class YourPresetName' 15 | 5. Change 'module.exports = PresetName' (last line) to 'module.exports = YourPresetName' 16 | 6. Recompile OpenPerform 17 | 7. Select new preset from GUI 18 | -------------------------------------------------------------------------------- /src/outputs/index.js: -------------------------------------------------------------------------------- 1 | /* This class interfaces with various output 2 | methods and handles response data and 3 | callbacks to the threejs environment. 4 | The output list is defined in config/index.js */ 5 | 6 | import TWEEN from 'tween.js'; 7 | 8 | import config from './../config'; 9 | 10 | import Common from './../util/Common'; 11 | 12 | // import all interfaces 13 | const outputTypes = require.context('./types', false, /\.js$/); 14 | 15 | // import all presets 16 | const presets = require.context('./presets', false, /\.js$/); 17 | 18 | class OutputManager { 19 | constructor(allowedOutputs, threeScene, parent) { 20 | this.allowedOutputs = allowedOutputs; 21 | this.scene = threeScene; // bridge to threejs environment (/src/three/scene.js) 22 | this.parent = parent; // bridge to react environment (/src/react/pages/Main.jsx) 23 | 24 | this.outputs = {}; 25 | this.presets = {}; 26 | 27 | // initialize all presets 28 | this.initPresets(); 29 | } 30 | 31 | initInputTypes() { 32 | const types = _.uniq(_.map(outputTypes.keys(), t => t.split('.')[1].split('/')[1])); 33 | _.each(_.without(this.allowedOutputs, types), (t) => { 34 | const InterfaceClass = require('./types/' + t); 35 | let url = ''; 36 | if (config[t.toLowerCase()]) { 37 | url = 'ws://' + window.location.hostname + ':' + config[t.toLowerCase()].ports.incoming; 38 | } 39 | this.outputs[t.toLowerCase()] = new InterfaceClass(url); 40 | }); 41 | 42 | // connect current preset with inputs 43 | this.connectCallbacks((this.parent.state.currentOutputPreset === null) ? 44 | this.parent.state.defaults.outputPreset : 45 | this.parent.state.currentOutputPreset); 46 | } 47 | 48 | initPresets() { 49 | const pres = _.uniq(_.map(presets.keys(), p => p.split('.')[1].split('/')[1])); 50 | this.parent.state.inputPresets = pres.slice(0); 51 | _.each(pres, (p) => { 52 | const PresetClass = require('./presets/' + p); 53 | this.presets[p.toLowerCase()] = new PresetClass(this, this.parent, this.scene); 54 | }); 55 | 56 | // initialize all interfaces 57 | this.initInputTypes(); 58 | } 59 | 60 | connectCallbacks(preset) { 61 | this.clearAllCallbacks(); 62 | 63 | const types = _.uniq(_.map(outputTypes.keys(), t => t.split('.')[1].split('/')[1])); 64 | _.each(_.without(this.allowedOutputs, types), (t) => { 65 | this.presets[preset.toLowerCase()].initCallbacks(t); 66 | }); 67 | console.log('Loading ' + preset + ' output preset.'); 68 | } 69 | 70 | clearCallbacks(output) { 71 | if (this.outputs[output.toLowerCase()]) { 72 | this.outputs[output.toLowerCase()].clearCallbacks(); 73 | } 74 | } 75 | 76 | clearAllCallbacks() { 77 | _.each(this.outputs, (o) => { 78 | o.clearCallbacks(); 79 | }); 80 | } 81 | 82 | registerCallback(output, event, label, callback) { 83 | if (this.outputs[output.toLowerCase()]) { 84 | this.outputs[output.toLowerCase()].on(event, callback, event, label); 85 | } 86 | } 87 | } 88 | 89 | module.exports = OutputManager; 90 | -------------------------------------------------------------------------------- /src/outputs/presets/Default.js: -------------------------------------------------------------------------------- 1 | import Common from './../../util/Common'; 2 | import Config from './../../config'; 3 | 4 | class DefaultPreset { 5 | constructor(outputManager, main, scene) { 6 | this.outputManager = outputManager; 7 | this.main = main; 8 | this.scene = scene; 9 | } 10 | 11 | initCallbacks(type) { 12 | switch (type.toLowerCase()) { 13 | default: 14 | console.log(type.toLowerCase() + ' output not found for this preset'); 15 | break; 16 | case 'midicontroller': 17 | this.initMidiControllerCallbacks(); 18 | break; 19 | } 20 | } 21 | 22 | initMidiControllerCallbacks() { 23 | this.outputManager.registerCallback('midiController', 'devicesConnected', 'Midi Controller', this.main.updateMidiOutputs.bind(this.main)); 24 | } 25 | } 26 | 27 | module.exports = DefaultPreset; 28 | -------------------------------------------------------------------------------- /src/outputs/types/ExampleInput.txt: -------------------------------------------------------------------------------- 1 | class InputName { 2 | constructor() { 3 | this.callbacks = {}; 4 | this.events = []; 5 | this.labels = []; 6 | } 7 | 8 | on(name, cb, event, label) { 9 | this.callbacks[name] = cb; 10 | this.events.push(event); 11 | this.labels.push(label); 12 | this.initCallbacks(); 13 | } 14 | 15 | clearCallbacks() { 16 | this.callbacks = {}; 17 | this.events = []; 18 | this.labels = []; 19 | } 20 | 21 | initCallbacks() { 22 | _.forEach(this.callbacks, this.initCallback.bind(this)); 23 | } 24 | 25 | initCallback(cb, name) { 26 | } 27 | } 28 | 29 | module.exports = InputName; 30 | -------------------------------------------------------------------------------- /src/performers/Head.js: -------------------------------------------------------------------------------- 1 | import FileLoader from '../util/Loader.js'; 2 | 3 | class Head extends React.Component { 4 | constructor(props) { 5 | super(props); 6 | this.head = null; 7 | 8 | this.loader = new FileLoader(); 9 | } 10 | 11 | loadHead() { 12 | console.log('Loading fbx head....'); 13 | this.loader.loadFBX('/models/fbx/SlothCharacter/sloth_head_blendshapes5.fbx', {}, (object) => { 14 | this.head = object; 15 | // console.log(this.head); 16 | // this.state.scene.scene.add(this.head); 17 | }); 18 | } 19 | 20 | updateHead(data) { 21 | console.log(data); 22 | if (this.head !== null) { 23 | // console.log(this.head.children[0]); 24 | _.each(data.blendShapes, (shp, idx) => { 25 | if (this.head.children[0].morphTargetDictionary[shp[0]] !== undefined) { 26 | this.head.children[0].morphTargetInfluences[this.head.children[0].morphTargetDictionary[shp[0]]] = parseFloat(shp[1]); 27 | this.head.children[0].geometry.verticesNeedUpdate = true; 28 | } 29 | }); 30 | console.log(this.head.children[0].morphTargetInfluences); 31 | } 32 | } 33 | } 34 | 35 | module.exports = Head; 36 | -------------------------------------------------------------------------------- /src/react/effects/DataTagsMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 01:47:30 5 | * @modify date 2018-08-26 01:47:30 6 | * @desc [Menu to control The DataTags Effect.] 7 | */ 8 | 9 | 10 | 11 | import DatGui, { DatBoolean, DatFolder } from 'react-dat-gui'; 12 | require('react-dat-gui/build/react-dat-gui.css'); 13 | 14 | import PartsPickerMenu from './PartsPickerMenu'; 15 | 16 | // react gui returned to effects menu 17 | class DataTagsMenu extends React.Component { 18 | constructor(props) { 19 | super(props); 20 | this.props = props; 21 | this.state = { 22 | data: this.props.data, 23 | currentTargets: this.props.currentTargets, 24 | possibleTargets: this.props.possibleTargets, 25 | }; 26 | } 27 | updateOptions(d) { 28 | this.setState({ 29 | data: d, 30 | }); 31 | this.props.updateOptions(d); 32 | } 33 | updateParts(d) { 34 | this.setState({ 35 | currentTargets: d, 36 | }); 37 | this.props.updateParts(d); 38 | } 39 | render() { 40 | return ( 41 |
42 | 43 | 44 | {/* */} 45 | 46 | 47 | 48 | {/* */} 49 | 50 |
51 | ); 52 | } 53 | } 54 | 55 | module.exports = DataTagsMenu; 56 | -------------------------------------------------------------------------------- /src/react/effects/ParticlesMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 01:47:30 5 | * @modify date 2018-08-26 01:47:30 6 | * @desc [Menu to control The Particles Effect.] 7 | */ 8 | 9 | 10 | 11 | import DatGui, { DatNumber, DatFolder, DatColor } from 'react-dat-gui'; 12 | require('react-dat-gui/build/react-dat-gui.css'); 13 | 14 | import PartsPickerMenu from './PartsPickerMenu'; 15 | 16 | // react gui returned to effects menu 17 | class ParticlesMenu extends React.Component { 18 | constructor(props) { 19 | super(props); 20 | this.props = props; 21 | this.state = { 22 | data: this.props.data, 23 | currentTargets: this.props.currentTargets, 24 | possibleTargets: this.props.possibleTargets, 25 | }; 26 | } 27 | updateOptions(d) { 28 | this.setState({ 29 | data: d, 30 | }); 31 | this.props.updateOptions(d); 32 | } 33 | updateParts(d) { 34 | this.setState({ 35 | currentTargets: d, 36 | }); 37 | this.props.updateParts(d); 38 | } 39 | render() { 40 | return ( 41 |
42 | 43 | 44 | {/* */} 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | {/* */} 54 | 55 |
56 | ); 57 | } 58 | } 59 | 60 | module.exports = ParticlesMenu; 61 | -------------------------------------------------------------------------------- /src/react/effects/RibbonsMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 01:47:30 5 | * @modify date 2018-08-26 01:47:30 6 | * @desc [Menu to control The Ribbons Effect.] 7 | */ 8 | 9 | 10 | 11 | import DatGui, { DatNumber, DatColor, DatFolder } from 'react-dat-gui'; 12 | require('react-dat-gui/build/react-dat-gui.css'); 13 | 14 | import PartsPickerMenu from './PartsPickerMenu'; 15 | 16 | // react gui returned to effects menu 17 | class RibbonsMenu extends React.Component { 18 | constructor(props) { 19 | super(props); 20 | this.props = props; 21 | this.state = { 22 | data: this.props.data, 23 | currentTargets: this.props.currentTargets, 24 | possibleTargets: this.props.possibleTargets, 25 | }; 26 | } 27 | updateOptions(d) { 28 | this.setState({ 29 | data: d, 30 | }); 31 | this.props.updateOptions(d); 32 | } 33 | updateParts(d) { 34 | this.setState({ 35 | currentTargets: d, 36 | }); 37 | this.props.updateParts(d); 38 | } 39 | render() { 40 | return ( 41 |
42 | 43 | 44 | {/* */} 45 | 46 | 47 | 48 | 49 | 50 | 51 | {/* */} 52 | 53 |
54 | ); 55 | } 56 | } 57 | 58 | module.exports = RibbonsMenu; 59 | -------------------------------------------------------------------------------- /src/react/inputs/NumberInput.jsx: -------------------------------------------------------------------------------- 1 | import 'rc-input-number/assets/index.css'; 2 | import InputNumber from 'rc-input-number'; 3 | 4 | import ReactDOM from 'react-dom'; 5 | 6 | class NumberInput extends React.Component { 7 | constructor(props) { 8 | super(props); 9 | this.props = props; 10 | this.state = {}; 11 | } 12 | render() { 13 | return ( 14 | 21 | ); 22 | } 23 | } 24 | 25 | module.exports = NumberInput; 26 | -------------------------------------------------------------------------------- /src/react/menus/ARMenu.jsx: -------------------------------------------------------------------------------- 1 | 2 | import { Panel, MenuItem, DropdownButton } from 'react-bootstrap'; 3 | 4 | class ARMenu extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | forceUpdate: false, 9 | }; 10 | } 11 | 12 | shouldComponentUpdate(nextProps, nextState) { 13 | if (this.state.forceUpdate === true) { 14 | this.setState({ forceUpdate: false }); 15 | return true; 16 | } 17 | 18 | if (this.props && this.state) { 19 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 20 | this.props = nextProps; 21 | return true; 22 | } 23 | return false; 24 | } 25 | return false; 26 | } 27 | 28 | render() { 29 | return ( 30 | 31 | 32 |
AR
33 |
34 | 35 | 36 | 37 | 38 |
39 | ); 40 | } 41 | } 42 | 43 | module.exports = ARMenu; 44 | -------------------------------------------------------------------------------- /src/react/menus/DebugMenu.jsx: -------------------------------------------------------------------------------- 1 | 2 | import { Panel, FormGroup, FormControl } from 'react-bootstrap'; 3 | 4 | class DebugMenu extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | forceUpdate: false, 9 | }; 10 | } 11 | shouldComponentUpdate(nextProps, nextState) { 12 | if (this.state.forceUpdate === true) { 13 | this.setState({ forceUpdate: false }); 14 | return true; 15 | } 16 | 17 | if (this.props && this.state) { 18 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 19 | this.props = nextProps; 20 | return true; 21 | } 22 | return false; 23 | } 24 | return false; 25 | } 26 | render() { 27 | return ( 28 | 29 | 30 |
Debug
31 |
32 | 33 | 34 |
35 | {this.props.arGui} 36 |
37 |
38 |
39 | ); 40 | } 41 | } 42 | 43 | module.exports = DebugMenu; 44 | -------------------------------------------------------------------------------- /src/react/menus/EnvironmentMenu.jsx: -------------------------------------------------------------------------------- 1 | 2 | import Select from 'react-select'; 3 | 4 | import { Panel, DropdownButton, MenuItem } from 'react-bootstrap'; 5 | 6 | import 'react-select/dist/react-select.css'; 7 | 8 | import EnvironmentStylesMenu from './../menus/styles/EnvironmentStylesMenu'; 9 | 10 | import Common from '../../util/Common'; 11 | 12 | class EnvironmentMenu extends React.Component { 13 | constructor(props) { 14 | super(props); 15 | this.props = props; 16 | this.state = { 17 | playing: false, 18 | looping: true, 19 | forceUpdate: false, 20 | currentEnvironment: null, 21 | }; 22 | } 23 | 24 | shouldComponentUpdate(nextProps, nextState) { 25 | if (this.state.forceUpdate == true) { 26 | this.setState({ forceUpdate: false }); 27 | return true; 28 | } 29 | 30 | if (this.props && this.state) { 31 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 32 | this.props = nextProps; 33 | return true; 34 | } 35 | return false; 36 | } 37 | return false; 38 | } 39 | 40 | changeStyle(environment, val) { 41 | environment.updateStyle(val.value); 42 | this.setState({ forceUpdate: true }); 43 | } 44 | 45 | toggleVisible(environment) { 46 | environment.toggleVisible(); 47 | this.setState({ forceUpdate: true }); 48 | } 49 | 50 | updateEnvironment(val) { 51 | this.setState({ forceUpdate: true }); 52 | this.props.updateEnvironment(val); 53 | } 54 | 55 | render() { 56 | if (this.props.environments == null || this.props.environments.length == 0) { 57 | return false; 58 | } 59 | 60 | return ( 61 | 62 | 63 |
Environment
64 |
65 | 66 | 67 | 76 | {_.map(this.props.availEnvironments, (environment, idx) => { 77 | return ({environment}); 78 | })} 79 | 80 | { 81 | _.map(this.props.environments.getEnvironments(), (environment, idx) => ( 82 | 83 | 84 | 85 | 88 | )) 89 | }
{environment.name} 86 | 87 |
90 |
91 |
92 |
93 | ); 94 | } 95 | } 96 | 97 | module.exports = EnvironmentMenu; 98 | -------------------------------------------------------------------------------- /src/react/menus/HelpMenu.jsx: -------------------------------------------------------------------------------- 1 | import { Panel } from 'react-bootstrap'; 2 | import Icon from 'react-fa'; 3 | 4 | class HelpMenu extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | forceUpdate: false, 9 | }; 10 | } 11 | shouldComponentUpdate(nextProps, nextState) { 12 | if (this.state.forceUpdate === true) { 13 | this.setState({ forceUpdate: false }); 14 | return true; 15 | } 16 | 17 | if (this.props && this.state) { 18 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 19 | this.props = nextProps; 20 | return true; 21 | } 22 | return false; 23 | } 24 | return false; 25 | } 26 | 27 | render() { 28 | return ( 29 | 30 | 31 |
32 |
33 |
34 | ); 35 | } 36 | } 37 | 38 | module.exports = HelpMenu; 39 | -------------------------------------------------------------------------------- /src/react/menus/InfoMenu.jsx: -------------------------------------------------------------------------------- 1 | import { Panel, ListGroup, ListGroupItem } from 'react-bootstrap'; 2 | import Icon from 'react-fa'; 3 | 4 | class InfoMenu extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | forceUpdate: false, 9 | }; 10 | } 11 | shouldComponentUpdate(nextProps, nextState) { 12 | if (this.state.forceUpdate === true) { 13 | this.setState({ forceUpdate: false }); 14 | return true; 15 | } 16 | 17 | if (this.props && this.state) { 18 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 19 | this.props = nextProps; 20 | return true; 21 | } 22 | return false; 23 | } 24 | return false; 25 | } 26 | 27 | render() { 28 | return ( 29 | 30 | 31 |
OpenPerform
32 |
33 | 34 | 35 | 36 | Source Code 37 | OpenPerform.org 38 | KinetechArts.org 39 | 40 | 41 | 42 |
43 | ); 44 | } 45 | } 46 | 47 | module.exports = InfoMenu; 48 | -------------------------------------------------------------------------------- /src/react/menus/VRMenu.jsx: -------------------------------------------------------------------------------- 1 | 2 | import { Panel, MenuItem, DropdownButton } from 'react-bootstrap'; 3 | 4 | class VRMenu extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | forceUpdate: false, 9 | }; 10 | } 11 | 12 | shouldComponentUpdate(nextProps, nextState) { 13 | if (this.state.forceUpdate === true) { 14 | this.setState({ forceUpdate: false }); 15 | return true; 16 | } 17 | 18 | if (this.props && this.state) { 19 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 20 | this.props = nextProps; 21 | return true; 22 | } 23 | return false; 24 | } 25 | return false; 26 | } 27 | 28 | render() { 29 | return ( 30 | 31 | 32 |
Enter VR
33 |
34 | 35 | 36 | 37 | 38 |
39 | ); 40 | } 41 | } 42 | 43 | module.exports = VRMenu; 44 | -------------------------------------------------------------------------------- /src/react/menus/camera/PerformerCameraMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 06:55:09 5 | * @modify date 2018-09-02 06:55:09 6 | * @desc [description] 7 | */ 8 | 9 | import { Popover, ListGroup, ListGroupItem, OverlayTrigger, Table, DropdownButton, MenuItem } from 'react-bootstrap'; 10 | import DatGui, { DatColor, DatNumber } from 'react-dat-gui'; 11 | import Icon from 'react-fa'; 12 | 13 | class PerformerCameraMenu extends React.Component { 14 | constructor(props) { 15 | super(props); 16 | this.props = props; 17 | this.state = { 18 | data: this.props.data, 19 | }; 20 | } 21 | 22 | shouldComponentUpdate(nextProps, nextState) { 23 | if (this.state.forceUpdate === true) { 24 | this.setState({ forceUpdate: false }); 25 | return true; 26 | } 27 | 28 | if (this.props && this.state) { 29 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 30 | this.props = nextProps; 31 | return true; 32 | } 33 | return false; 34 | } 35 | return false; 36 | } 37 | 38 | updateOptions(d) { 39 | this.setState({ 40 | data: d, 41 | }); 42 | this.props.updateOptions(d); 43 | this.forceUpdate(); 44 | } 45 | 46 | render() { 47 | const popoverTop = ( 48 | 49 | 50 | 51 | 52 | 53 | 54 | 58 | 62 | 66 | 67 | 68 |
55 | {(this.props.following) ? : } 56 | Follow 57 | 59 | {(this.props.snorry) ? : } 60 | Snorry 61 | 63 | {(this.props.firstPerson) ? : } 64 | First 65 |
69 |
70 |
71 | {/* 72 | 73 | 74 | 75 | 76 | 77 | */} 78 |
79 | ); 80 | return ( 81 | 87 | 88 | 89 | ); 90 | } 91 | } 92 | 93 | module.exports = PerformerCameraMenu; 94 | -------------------------------------------------------------------------------- /src/react/menus/controls/PerformerControlsMenu.jsx: -------------------------------------------------------------------------------- 1 | 2 | import { Popover, ListGroup, ListGroupItem, OverlayTrigger, Table } from 'react-bootstrap'; 3 | 4 | import Icon from 'react-fa'; 5 | 6 | import NumberInput from '../../inputs/NumberInput'; 7 | 8 | class PerformerControlsMenu extends React.Component { 9 | constructor(props) { 10 | super(props); 11 | this.props = props; 12 | this.state = { 13 | playing: true, 14 | looping: true, 15 | }; 16 | } 17 | playPause() { 18 | if (this.state.playing) { 19 | this.props.actions.pause(); 20 | this.setState({ playing: false }); 21 | } else { 22 | this.props.actions.play(); 23 | this.setState({ playing: true }); 24 | } 25 | } 26 | loopNoLoop() { 27 | if (this.state.looping) { 28 | this.props.actions.noLoop(); 29 | this.setState({ looping: false }); 30 | } else { 31 | this.props.actions.loop(); 32 | this.setState({ looping: true }); 33 | } 34 | } 35 | stop() { 36 | this.props.actions.stop(); 37 | this.setState({ playing: false }); 38 | } 39 | render() { 40 | switch (this.props.type.toLowerCase()) { 41 | default: 42 | return ( 43 | 44 | 45 | 46 | 49 | 50 | 51 |
47 | Live 48 |
52 | ); 53 | break; 54 | case 'clone': 55 | return ( 56 | 57 | 58 | 59 | 62 | 63 | 64 |
60 | Clone 61 |
65 | ); 66 | break; 67 | case 'bvh': 68 | return ( 69 | 70 | 71 | 72 | 77 | 80 | 86 | 87 | 88 |
73 | {(this.state.playing === true) ? 74 | : 75 | } 76 | 78 | 79 | 81 | {(this.state.looping === true) ? 82 | : 83 | 84 | } 85 |
89 | ); 90 | break; 91 | } 92 | } 93 | } 94 | 95 | module.exports = PerformerControlsMenu; 96 | -------------------------------------------------------------------------------- /src/react/menus/effects/DataTagsMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 01:47:30 5 | * @modify date 2018-08-26 01:47:30 6 | * @desc [Menu to control The DataTags Effect.] 7 | */ 8 | 9 | 10 | 11 | import DatGui, { DatBoolean, DatFolder } from 'react-dat-gui'; 12 | require('react-dat-gui/build/react-dat-gui.css'); 13 | 14 | import PartsPickerMenu from './PartsPickerMenu'; 15 | 16 | // react gui returned to effects menu 17 | class DataTagsMenu extends React.Component { 18 | constructor(props) { 19 | super(props); 20 | this.props = props; 21 | this.state = { 22 | data: this.props.data, 23 | currentTargets: this.props.currentTargets, 24 | possibleTargets: this.props.possibleTargets, 25 | }; 26 | } 27 | updateOptions(d) { 28 | this.setState({ 29 | data: d, 30 | }); 31 | this.props.updateOptions(d); 32 | } 33 | updateParts(d) { 34 | this.setState({ 35 | currentTargets: d, 36 | }); 37 | this.props.updateParts(d); 38 | } 39 | render() { 40 | return ( 41 |
42 | 43 | 44 | {/* */} 45 | 46 | 47 | 48 | {/* */} 49 | 50 |
51 | ); 52 | } 53 | } 54 | 55 | module.exports = DataTagsMenu; 56 | -------------------------------------------------------------------------------- /src/react/menus/effects/GhostingMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 01:47:30 5 | * @modify date 2018-08-26 01:47:30 6 | * @desc [Menu to control The Ghosting Effect.] 7 | */ 8 | 9 | 10 | 11 | import DatGui, { DatNumber, DatBoolean, DatFolder } from 'react-dat-gui'; 12 | require('react-dat-gui/build/react-dat-gui.css'); 13 | 14 | class GhostingMenu extends React.Component { 15 | constructor(props) { 16 | super(props); 17 | this.props = props; 18 | this.state = { 19 | data: this.props.data, 20 | }; 21 | } 22 | updateOptions(d) { 23 | this.setState({ 24 | data: d, 25 | }); 26 | this.props.updateOptions(d); 27 | } 28 | render() { 29 | return ( 30 |
31 | 32 | {/* */} 33 | {/* */} 34 | 35 | 36 | 37 | {/* */} 38 | 39 |
40 | ); 41 | } 42 | } 43 | 44 | module.exports = GhostingMenu; -------------------------------------------------------------------------------- /src/react/menus/effects/MovementSculptureMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 01:47:30 5 | * @modify date 2018-08-26 01:47:30 6 | * @desc [Menu to control The Movement Sculpture Effect.] 7 | */ 8 | 9 | 10 | 11 | import DatGui, { DatNumber, DatButton, DatFolder, DatSelect } from 'react-dat-gui'; 12 | require('react-dat-gui/build/react-dat-gui.css'); 13 | 14 | // react gui returned to effects menu 15 | class MovementSculptureMenu extends React.Component { 16 | constructor(props) { 17 | super(props); 18 | this.props = props; 19 | this.state = { 20 | data: this.props.data, 21 | }; 22 | } 23 | updateOptions(d) { 24 | this.setState({ 25 | data: d, 26 | }); 27 | this.props.updateOptions(d); 28 | } 29 | updateParts(d) { 30 | this.props.updateParts(d); 31 | } 32 | render() { 33 | return ( 34 |
35 | 36 | {/* */} 37 | 38 | 39 | 40 | 41 | {/* */} 42 | 43 |
44 | ); 45 | } 46 | } 47 | 48 | module.exports = MovementSculptureMenu; 49 | -------------------------------------------------------------------------------- /src/react/menus/effects/ParticlesMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 01:47:30 5 | * @modify date 2018-08-26 01:47:30 6 | * @desc [Menu to control The Particles Effect.] 7 | */ 8 | 9 | 10 | 11 | import DatGui, { DatNumber, DatFolder, DatColor } from 'react-dat-gui'; 12 | require('react-dat-gui/build/react-dat-gui.css'); 13 | 14 | import PartsPickerMenu from './PartsPickerMenu'; 15 | 16 | // react gui returned to effects menu 17 | class ParticlesMenu extends React.Component { 18 | constructor(props) { 19 | super(props); 20 | this.props = props; 21 | this.state = { 22 | data: this.props.data, 23 | currentTargets: this.props.currentTargets, 24 | possibleTargets: this.props.possibleTargets, 25 | }; 26 | } 27 | updateOptions(d) { 28 | this.setState({ 29 | data: d, 30 | }); 31 | this.props.updateOptions(d); 32 | } 33 | updateParts(d) { 34 | this.setState({ 35 | currentTargets: d, 36 | }); 37 | this.props.updateParts(d); 38 | } 39 | render() { 40 | return ( 41 |
42 | 43 | 44 | {/* */} 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | {/* */} 54 | 55 |
56 | ); 57 | } 58 | } 59 | 60 | module.exports = ParticlesMenu; 61 | -------------------------------------------------------------------------------- /src/react/menus/effects/PartsPickerMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 01:47:30 5 | * @modify date 2018-08-26 01:47:30 6 | * @desc [Menu to select on which performer part effects are attached.] 7 | */ 8 | 9 | 10 | import { ToggleButtonGroup, ToggleButton } from 'react-bootstrap'; 11 | 12 | class PartsPickerMenu extends React.Component { 13 | constructor(props) { 14 | super(props); 15 | this.props = props; 16 | this.state = {}; 17 | } 18 | render() { 19 | return ( 20 | 21 | {_.map(this.props.possibleTargets, (t, idx) => { 22 | return (); 23 | })} 24 | 25 | ); 26 | } 27 | } 28 | 29 | module.exports = PartsPickerMenu; 30 | -------------------------------------------------------------------------------- /src/react/menus/effects/PerformerEffectsMenu.jsx: -------------------------------------------------------------------------------- 1 | 2 | import ReactDOM from 'react-dom'; 3 | import { Popover, ListGroup, ListGroupItem, OverlayTrigger, Table, DropdownButton, MenuItem } from 'react-bootstrap'; 4 | 5 | import Icon from 'react-fa'; 6 | 7 | class PerformerEffectsMenu extends React.Component { 8 | constructor(props) { 9 | super(props); 10 | this.props = props; 11 | this.state = {}; 12 | } 13 | shouldComponentUpdate(nextProps, nextState) { 14 | if (this.state.forceUpdate === true) { 15 | this.setState({ forceUpdate: false }); 16 | return true; 17 | } 18 | 19 | if (this.props && this.state) { 20 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 21 | this.props = nextProps; 22 | return true; 23 | } 24 | } 25 | 26 | if (!_.isEqual(this.props.gui, nextProps.gui)) { 27 | return true; 28 | } 29 | 30 | return false; 31 | } 32 | renderPopOver() { 33 | return ( 34 | 35 | 36 | 45 | No Effect 46 | {_.map(this.props.effects, (effect, idx) => { 47 | return ({effect}); 48 | })} 49 | 50 | 51 | 52 | {this.props.gui} 53 | 54 | 55 | ); 56 | } 57 | render() { 58 | return ( 59 | 66 | 67 | 68 | ); 69 | } 70 | } 71 | 72 | module.exports = PerformerEffectsMenu; 73 | -------------------------------------------------------------------------------- /src/react/menus/effects/RibbonsMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-26 01:47:30 5 | * @modify date 2018-08-26 01:47:30 6 | * @desc [Menu to control The Ribbons Effect.] 7 | */ 8 | 9 | import DatGui, { DatNumber, DatColor, DatFolder } from 'react-dat-gui'; 10 | require('react-dat-gui/build/react-dat-gui.css'); 11 | 12 | import PartsPickerMenu from './PartsPickerMenu'; 13 | 14 | // react gui returned to effects menu 15 | class RibbonsMenu extends React.Component { 16 | constructor(props) { 17 | super(props); 18 | this.props = props; 19 | this.state = { 20 | data: this.props.data, 21 | currentTargets: this.props.currentTargets, 22 | possibleTargets: this.props.possibleTargets, 23 | }; 24 | } 25 | updateOptions(d) { 26 | this.setState({ 27 | data: d, 28 | }); 29 | this.props.updateOptions(d); 30 | } 31 | updateParts(d) { 32 | this.setState({ 33 | currentTargets: d, 34 | }); 35 | this.props.updateParts(d); 36 | } 37 | render() { 38 | return ( 39 |
40 | 41 | 42 | {/* */} 43 | 44 | 45 | 46 | 47 | 48 | 49 | {/* */} 50 | 51 |
52 | ); 53 | } 54 | } 55 | 56 | module.exports = RibbonsMenu; 57 | -------------------------------------------------------------------------------- /src/react/menus/environment/EmptyMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 03:51:06 5 | * @modify date 2018-09-02 03:51:06 6 | * @desc [description] 7 | */ 8 | 9 | import { ListGroup, ListGroupItem } from 'react-bootstrap'; 10 | import DatGui, { DatNumber, DatColor, DatFolder } from 'react-dat-gui'; 11 | 12 | class EmptyMenu extends React.Component { 13 | constructor(props) { 14 | super(props); 15 | this.props = props; 16 | } 17 | 18 | updateOptions(d) { 19 | this.props.updateOptions(d); 20 | this.forceUpdate(); 21 | } 22 | 23 | render() { 24 | return ( 25 | 26 | 27 | 28 | 29 | ); 30 | } 31 | } 32 | 33 | module.exports = EmptyMenu; 34 | -------------------------------------------------------------------------------- /src/react/menus/environment/ForestMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 03:51:19 5 | * @modify date 2018-09-02 03:51:19 6 | * @desc [description] 7 | */ 8 | 9 | import { ListGroup, ListGroupItem } from 'react-bootstrap'; 10 | import DatGui, { DatNumber, DatColor, DatFolder } from 'react-dat-gui'; 11 | 12 | class ForestMenu extends React.Component { 13 | constructor(props) { 14 | super(props); 15 | this.props = props; 16 | } 17 | 18 | updateOptions(d) { 19 | this.props.updateOptions(d); 20 | this.forceUpdate(); 21 | } 22 | 23 | render() { 24 | return ( 25 | 26 | 27 | 28 | 29 | ); 30 | } 31 | } 32 | 33 | module.exports = ForestMenu; 34 | -------------------------------------------------------------------------------- /src/react/menus/environment/GridMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 03:51:28 5 | * @modify date 2018-09-02 03:51:28 6 | * @desc [description] 7 | */ 8 | 9 | import { ListGroup, ListGroupItem } from 'react-bootstrap'; 10 | import DatGui, { DatColor, DatFolder, DatNumber } from 'react-dat-gui'; 11 | 12 | class GridMenu extends React.Component { 13 | constructor(props) { 14 | super(props); 15 | this.props = props; 16 | this.state = { 17 | data: this.props.data, 18 | }; 19 | } 20 | 21 | updateOptions(d) { 22 | this.setState({ 23 | data: d, 24 | }); 25 | this.props.updateOptions(d); 26 | this.forceUpdate(); 27 | } 28 | 29 | render() { 30 | return ( 31 | 32 | 33 | 34 | {/* */} 35 | 36 | 37 | 38 | 39 | {/* */} 40 | 41 | 42 | 43 | ); 44 | } 45 | } 46 | 47 | module.exports = GridMenu; 48 | -------------------------------------------------------------------------------- /src/react/menus/environment/SpaceMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 03:51:40 5 | * @modify date 2018-09-02 03:51:40 6 | * @desc [description] 7 | */ 8 | 9 | import { ListGroup, ListGroupItem } from 'react-bootstrap'; 10 | import DatGui, { DatNumber, DatColor, DatFolder } from 'react-dat-gui'; 11 | 12 | class SpaceMenu extends React.Component { 13 | constructor(props) { 14 | super(props); 15 | this.props = props; 16 | } 17 | 18 | updateOptions(d) { 19 | this.props.updateOptions(d); 20 | this.forceUpdate(); 21 | } 22 | 23 | render() { 24 | return ( 25 | 26 | 27 | 28 | 29 | ); 30 | } 31 | } 32 | 33 | module.exports = SpaceMenu; 34 | -------------------------------------------------------------------------------- /src/react/menus/environment/WaterMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 03:51:54 5 | * @modify date 2018-09-02 03:51:54 6 | * @desc [description] 7 | */ 8 | 9 | import { ListGroup, ListGroupItem } from 'react-bootstrap'; 10 | import DatGui, { DatNumber, DatColor, DatFolder } from 'react-dat-gui'; 11 | 12 | class WaterMenu extends React.Component { 13 | constructor(props) { 14 | super(props); 15 | this.props = props; 16 | this.state = { 17 | data: this.props.data, 18 | }; 19 | } 20 | 21 | updateOptions(d) { 22 | this.setState({ 23 | data: d 24 | }); 25 | this.props.updateOptions(d); 26 | this.forceUpdate(); 27 | } 28 | 29 | render() { 30 | return ( 31 | 32 | 33 | 34 | {/* */} 35 | 36 | 37 | 38 | 39 | {/* */} 40 | 41 | 42 | 43 | ); 44 | } 45 | } 46 | 47 | module.exports = WaterMenu; 48 | -------------------------------------------------------------------------------- /src/react/menus/render/AfterImageSettingsMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 04:05:16 5 | * @modify date 2018-09-02 04:39:39 6 | * @desc [description] 7 | */ 8 | 9 | import { Popover, OverlayTrigger } from 'react-bootstrap'; 10 | import DatGui, { DatNumber } from 'react-dat-gui'; 11 | import Icon from 'react-fa'; 12 | 13 | class AfterImageSettingsMenu extends React.Component { 14 | constructor(props) { 15 | super(props); 16 | this.props = props; 17 | this.state = { 18 | data: this.props.data, 19 | }; 20 | } 21 | 22 | shouldComponentUpdate(nextProps, nextState) { 23 | if (this.state.forceUpdate === true) { 24 | this.setState({ forceUpdate: false }); 25 | return true; 26 | } 27 | 28 | if (this.props && this.state) { 29 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 30 | this.props = nextProps; 31 | return true; 32 | } 33 | return false; 34 | } 35 | return false; 36 | } 37 | 38 | updateOptions(d) { 39 | this.setState({ 40 | data: d, 41 | }); 42 | this.props.updateOptions(d); 43 | this.forceUpdate(); 44 | } 45 | 46 | render() { 47 | const popoverTop = ( 48 | 49 | 50 | {/* */} 51 | 52 | {/* */} 53 | 54 | 55 | ); 56 | return ( 57 | 63 | 64 | 65 | ); 66 | } 67 | } 68 | 69 | module.exports = AfterImageSettingsMenu; 70 | -------------------------------------------------------------------------------- /src/react/menus/render/BloomSettingsMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 04:50:54 5 | * @modify date 2018-09-02 04:50:54 6 | * @desc [description] 7 | */ 8 | 9 | import { Popover, ListGroup, ListGroupItem, OverlayTrigger, Table, DropdownButton, MenuItem } from 'react-bootstrap'; 10 | import DatGui, { DatNumber } from 'react-dat-gui'; 11 | import Icon from 'react-fa'; 12 | 13 | class BloomSettingsMenu extends React.Component { 14 | constructor(props) { 15 | super(props); 16 | this.props = props; 17 | this.state = { 18 | data: this.props.data, 19 | }; 20 | } 21 | 22 | shouldComponentUpdate(nextProps, nextState) { 23 | if (this.state.forceUpdate === true) { 24 | this.setState({ forceUpdate: false }); 25 | return true; 26 | } 27 | 28 | if (this.props && this.state) { 29 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 30 | this.props = nextProps; 31 | return true; 32 | } 33 | return false; 34 | } 35 | return false; 36 | } 37 | 38 | updateOptions(d) { 39 | this.setState({ 40 | data: d, 41 | }); 42 | this.props.updateOptions(d); 43 | this.forceUpdate(); 44 | } 45 | 46 | render() { 47 | const popoverTop = ( 48 | 49 | 50 | {/* */} 51 | 52 | 53 | 54 | {/* */} 55 | 56 | 57 | ); 58 | return ( 59 | 65 | 66 | 67 | ); 68 | } 69 | } 70 | 71 | module.exports = BloomSettingsMenu; 72 | -------------------------------------------------------------------------------- /src/react/menus/render/DotShiftSettingsMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 05:06:19 5 | * @modify date 2018-09-02 05:06:19 6 | * @desc [description] 7 | */ 8 | 9 | import { Popover, OverlayTrigger } from 'react-bootstrap'; 10 | import DatGui, { DatNumber } from 'react-dat-gui'; 11 | import Icon from 'react-fa'; 12 | 13 | class DotShiftSettingsMenu extends React.Component { 14 | constructor(props) { 15 | super(props); 16 | this.props = props; 17 | this.state = { 18 | data: this.props.data, 19 | }; 20 | } 21 | 22 | shouldComponentUpdate(nextProps, nextState) { 23 | if (this.state.forceUpdate === true) { 24 | this.setState({ forceUpdate: false }); 25 | return true; 26 | } 27 | 28 | if (this.props && this.state) { 29 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 30 | this.props = nextProps; 31 | return true; 32 | } 33 | return false; 34 | } 35 | return false; 36 | } 37 | 38 | updateOptions(d) { 39 | this.setState({ 40 | data: d, 41 | }); 42 | this.props.updateOptions(d); 43 | this.forceUpdate(); 44 | } 45 | 46 | render() { 47 | const popoverTop = ( 48 | 49 | 50 | {/* */} 51 | 52 | 53 | {/* */} 54 | 55 | 56 | ); 57 | return ( 58 | 64 | 65 | 66 | ); 67 | } 68 | } 69 | 70 | module.exports = DotShiftSettingsMenu; 71 | -------------------------------------------------------------------------------- /src/react/menus/render/EdgesSettingsMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 05:16:56 5 | * @modify date 2018-09-02 05:16:56 6 | * @desc [description] 7 | */ 8 | 9 | import { Popover, ListGroup, ListGroupItem, OverlayTrigger, Table, DropdownButton, MenuItem } from 'react-bootstrap'; 10 | import DatGui, { DatNumber } from 'react-dat-gui'; 11 | import Icon from 'react-fa'; 12 | 13 | class EdgesSettingsMenu extends React.Component { 14 | constructor(props) { 15 | super(props); 16 | this.props = props; 17 | this.state = { 18 | forceUpdate: false, 19 | }; 20 | } 21 | 22 | shouldComponentUpdate(nextProps, nextState) { 23 | if (this.state.forceUpdate === true) { 24 | this.setState({ forceUpdate: false }); 25 | return true; 26 | } 27 | 28 | if (this.props && this.state) { 29 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 30 | this.props = nextProps; 31 | return true; 32 | } 33 | return false; 34 | } 35 | return false; 36 | } 37 | 38 | updateOptions(d) { 39 | this.setState({ 40 | data: d, 41 | }); 42 | this.props.updateOptions(d); 43 | this.forceUpdate(); 44 | } 45 | 46 | render() { 47 | const popoverTop = ( 48 | 49 | 50 | ); 51 | return ( 52 | 58 | 59 | 60 | ); 61 | } 62 | } 63 | 64 | module.exports = EdgesSettingsMenu; 65 | -------------------------------------------------------------------------------- /src/react/menus/render/HalftoneSettingsMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 05:58:21 5 | * @modify date 2018-09-02 05:58:21 6 | * @desc [description] 7 | */ 8 | 9 | import { Popover, ListGroup, ListGroupItem, OverlayTrigger, Table, DropdownButton, MenuItem } from 'react-bootstrap'; 10 | import DatGui, { DatNumber, DatBoolean, DatSelect } from 'react-dat-gui'; 11 | import Icon from 'react-fa'; 12 | 13 | class HalftoneSettingsMenu extends React.Component { 14 | constructor(props) { 15 | super(props); 16 | this.props = props; 17 | this.state = { 18 | data: this.props.data, 19 | }; 20 | } 21 | 22 | shouldComponentUpdate(nextProps, nextState) { 23 | if (this.state.forceUpdate === true) { 24 | this.setState({ forceUpdate: false }); 25 | return true; 26 | } 27 | 28 | if (this.props && this.state) { 29 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 30 | this.props = nextProps; 31 | return true; 32 | } 33 | return false; 34 | } 35 | return false; 36 | } 37 | 38 | updateOptions(d) { 39 | this.setState({ 40 | data: d, 41 | }); 42 | this.props.updateOptions(d); 43 | this.forceUpdate(); 44 | } 45 | 46 | render() { 47 | const popoverTop = ( 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | ); 63 | return ( 64 | 70 | 71 | 72 | ); 73 | } 74 | } 75 | 76 | module.exports = HalftoneSettingsMenu; 77 | -------------------------------------------------------------------------------- /src/react/menus/render/PixelSettingsMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 06:15:38 5 | * @modify date 2018-09-02 06:15:38 6 | * @desc [description] 7 | */ 8 | 9 | import { Popover, ListGroup, ListGroupItem, OverlayTrigger, Table, DropdownButton, MenuItem } from 'react-bootstrap'; 10 | import DatGui, { DatNumber, DatBoolean, DatSelect } from 'react-dat-gui'; 11 | import Icon from 'react-fa'; 12 | 13 | class PixelSettingsMenu extends React.Component { 14 | constructor(props) { 15 | super(props); 16 | this.props = props; 17 | this.state = { 18 | data: this.props.data, 19 | }; 20 | } 21 | 22 | shouldComponentUpdate(nextProps, nextState) { 23 | if (this.state.forceUpdate === true) { 24 | this.setState({ forceUpdate: false }); 25 | return true; 26 | } 27 | 28 | if (this.props && this.state) { 29 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 30 | this.props = nextProps; 31 | return true; 32 | } 33 | return false; 34 | } 35 | return false; 36 | } 37 | 38 | updateOptions(d) { 39 | this.setState({ 40 | data: d, 41 | }); 42 | this.props.updateOptions(d); 43 | this.forceUpdate(); 44 | } 45 | 46 | render() { 47 | const popoverTop = ( 48 | 49 | 50 | 51 | 52 | 53 | ); 54 | return ( 55 | 61 | 62 | 63 | ); 64 | } 65 | } 66 | 67 | module.exports = PixelSettingsMenu; 68 | -------------------------------------------------------------------------------- /src/react/menus/render/SketchSettingsMenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-09-02 06:55:09 5 | * @modify date 2018-09-02 06:55:09 6 | * @desc [description] 7 | */ 8 | 9 | import { Popover, ListGroup, ListGroupItem, OverlayTrigger, Table, DropdownButton, MenuItem } from 'react-bootstrap'; 10 | import DatGui, { DatColor, DatNumber } from 'react-dat-gui'; 11 | import Icon from 'react-fa'; 12 | 13 | class SketchSettingsMenu extends React.Component { 14 | constructor(props) { 15 | super(props); 16 | this.props = props; 17 | this.state = { 18 | data: this.props.data, 19 | }; 20 | } 21 | 22 | shouldComponentUpdate(nextProps, nextState) { 23 | if (this.state.forceUpdate === true) { 24 | this.setState({ forceUpdate: false }); 25 | return true; 26 | } 27 | 28 | if (this.props && this.state) { 29 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 30 | this.props = nextProps; 31 | return true; 32 | } 33 | return false; 34 | } 35 | return false; 36 | } 37 | 38 | updateOptions(d) { 39 | this.setState({ 40 | data: d, 41 | }); 42 | this.props.updateOptions(d); 43 | this.forceUpdate(); 44 | } 45 | 46 | render() { 47 | const popoverTop = ( 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | ); 58 | return ( 59 | 65 | 66 | 67 | ); 68 | } 69 | } 70 | 71 | module.exports = SketchSettingsMenu; 72 | -------------------------------------------------------------------------------- /src/react/menus/styles/EnvironmentStylesMenu.jsx: -------------------------------------------------------------------------------- 1 | 2 | import { Popover, ListGroup, ListGroupItem, OverlayTrigger, Table, DropdownButton, MenuItem } from 'react-bootstrap'; 3 | 4 | import Icon from 'react-fa'; 5 | 6 | 7 | class EnvironmentStylesMenu extends React.Component { 8 | constructor(props) { 9 | super(props); 10 | this.props = props; 11 | this.state = { 12 | forceUpdate: false, 13 | }; 14 | } 15 | shouldComponentUpdate(nextProps, nextState) { 16 | if (this.state.forceUpdate === true) { 17 | this.setState({ forceUpdate: false }); 18 | return true; 19 | } 20 | 21 | if (this.props && this.state) { 22 | if (!_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState)) { 23 | this.props = nextProps; 24 | return true; 25 | } 26 | return false; 27 | } 28 | return false; 29 | } 30 | render() { 31 | const popoverTop = ( 32 | 33 | {this.props.stylesGUI} 34 | 35 | ); 36 | return ( 37 | 43 | 44 | 45 | ); 46 | } 47 | } 48 | 49 | module.exports = EnvironmentStylesMenu; 50 | -------------------------------------------------------------------------------- /src/react/modals/KeyboardHelpModal.jsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { Modal, OverlayTrigger, Button, Row, Col } from 'react-bootstrap'; 4 | 5 | class KeyboardHelpModal extends React.Component { 6 | constructor(props) { 7 | super(props); 8 | this.state = {}; 9 | } 10 | shouldComponentUpdate(nextProps, nextState) { 11 | return this.props.show !== nextProps.show; 12 | } 13 | render() { 14 | return ( 15 | 16 | 17 | Keyboard Shortcuts 18 | 19 | 20 | {_.map(this.props.keyboardList.labels, (key, idx) => ({this.props.keyboardList.events[idx]}{key}))} 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | } 28 | } 29 | 30 | module.exports = KeyboardHelpModal; 31 | -------------------------------------------------------------------------------- /src/renderStyles/AfterImageStyle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-31 04:57:33 5 | * @modify date 2018-09-02 04:39:49 6 | * @desc [description] 7 | */ 8 | 9 | require('imports-loader?THREE=three!three/examples/js/shaders/CopyShader.js'); 10 | require('imports-loader?THREE=three!three/examples/js/postprocessing/EffectComposer.js'); 11 | require('imports-loader?THREE=three!three/examples/js/postprocessing/RenderPass.js'); 12 | require('imports-loader?THREE=three!three/examples/js/postprocessing/MaskPass.js'); 13 | require('imports-loader?THREE=three!three/examples/js/postprocessing/ShaderPass.js'); 14 | 15 | require('imports-loader?THREE=three!three/examples/js/postprocessing/AfterimagePass.js'); 16 | require('imports-loader?THREE=three!three/examples/js/shaders/AfterimageShader.js'); 17 | require('imports-loader?THREE=three!three/examples/js/postprocessing/AfterimagePass.js'); 18 | 19 | import AfterImageSettingsMenu from '../react/menus/render/AfterImageSettingsMenu'; 20 | 21 | class AfterImageStyle { 22 | constructor(composer, defaults) { 23 | this.composer = composer; 24 | this.defaults = defaults; 25 | 26 | this.name = 'After Image'; 27 | 28 | this.options = { 29 | damn: 0.96, 30 | }; 31 | 32 | this.container = $('#scenes'); 33 | this.w = this.container.width(); 34 | this.h = this.container.height(); 35 | 36 | this.afterimagePass = new THREE.AfterimagePass(this.options.damp); 37 | this.afterimagePass.renderToScreen = true; 38 | this.composer.addPass(this.afterimagePass); 39 | 40 | this.updateOptions = this.updateOptions.bind(this); 41 | } 42 | 43 | update(timeDelta) { 44 | // put frame updates here. 45 | } 46 | 47 | updateOptions(data) { 48 | this.options = data; 49 | this.afterimagePass.uniforms['damp'].value = this.options.damp; 50 | } 51 | 52 | getGUI() { 53 | return (); 54 | } 55 | } 56 | 57 | module.exports = AfterImageStyle; 58 | -------------------------------------------------------------------------------- /src/renderStyles/BloomStyle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-31 04:57:41 5 | * @modify date 2018-09-02 04:51:07 6 | * @desc [description] 7 | */ 8 | 9 | require('imports-loader?THREE=three!three/examples/js/shaders/CopyShader.js'); 10 | require('imports-loader?THREE=three!three/examples/js/postprocessing/EffectComposer.js'); 11 | require('imports-loader?THREE=three!three/examples/js/postprocessing/RenderPass.js'); 12 | require('imports-loader?THREE=three!three/examples/js/postprocessing/MaskPass.js'); 13 | require('imports-loader?THREE=three!three/examples/js/postprocessing/ShaderPass.js'); 14 | 15 | require('imports-loader?THREE=three!three/examples/js/shaders/LuminosityHighPassShader.js'); 16 | require('imports-loader?THREE=three!three/examples/js/postprocessing/UnrealBloomPass.js'); 17 | 18 | import BloomSettingsMenu from '../react/menus/render/BloomSettingsMenu'; 19 | 20 | class BloomStyle { 21 | constructor(composer, defaults) { 22 | this.composer = composer; 23 | this.defaults = defaults; 24 | 25 | this.name = 'Bloom'; 26 | 27 | this.options = { 28 | threshold: 0, 29 | strength: 1.5, 30 | radius: 0, 31 | }; 32 | 33 | this.container = $('#scenes'); 34 | this.w = this.container.width(); 35 | this.h = this.container.height(); 36 | 37 | this.firstPass = new THREE.UnrealBloomPass( 38 | new THREE.Vector2(this.w, this.h), 39 | this.options.strength, 40 | this.options.radius, 41 | this.options.threshold, 42 | ); 43 | this.firstPass.renderToScreen = true; 44 | this.composer.addPass(this.firstPass); 45 | 46 | this.updateOptions = this.updateOptions.bind(this); 47 | } 48 | 49 | update(timeDelta) { 50 | // put frame updates here. 51 | } 52 | 53 | updateOptions(data) { 54 | this.options = data; 55 | this.firstPass.threshold = data.threshold; 56 | this.firstPass.strength = data.strength; 57 | this.firstPass.radius = data.radius; 58 | } 59 | 60 | getGUI() { 61 | return (); 62 | } 63 | } 64 | 65 | module.exports = BloomStyle; -------------------------------------------------------------------------------- /src/renderStyles/DotShiftStyle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-31 04:57:48 5 | * @modify date 2018-09-02 05:06:02 6 | * @desc [description] 7 | */ 8 | 9 | require('imports-loader?THREE=three!three/examples/js/shaders/CopyShader.js'); 10 | require('imports-loader?THREE=three!three/examples/js/postprocessing/EffectComposer.js'); 11 | require('imports-loader?THREE=three!three/examples/js/postprocessing/RenderPass.js'); 12 | require('imports-loader?THREE=three!three/examples/js/postprocessing/MaskPass.js'); 13 | require('imports-loader?THREE=three!three/examples/js/postprocessing/ShaderPass.js'); 14 | 15 | require('imports-loader?THREE=three!three/examples/js/shaders/DotScreenShader.js'); 16 | require('imports-loader?THREE=three!three/examples/js/shaders/RGBShiftShader.js'); 17 | 18 | import DotShiftSettingsMenu from '../react/menus/render/DotShiftSettingsMenu'; 19 | 20 | class DotShiftStyle { 21 | constructor(composer, defaults) { 22 | this.composer = composer; 23 | this.defaults = defaults; 24 | 25 | this.name = 'Dot Shift'; 26 | 27 | this.options = { 28 | dotScale: 4, 29 | shiftAmt: 0.0015, 30 | }; 31 | 32 | this.container = $('#scenes'); 33 | this.w = this.container.width(); 34 | this.h = this.container.height(); 35 | 36 | this.firstPass = new THREE.ShaderPass(THREE.DotScreenShader); 37 | this.firstPass.uniforms['scale'].value = this.options.dotScale; 38 | this.composer.addPass(this.firstPass); 39 | 40 | this.secondPass = new THREE.ShaderPass(THREE.RGBShiftShader); 41 | this.secondPass.uniforms['amount'].value = this.options.shiftAmt; 42 | this.secondPass.renderToScreen = true; 43 | this.composer.addPass(this.secondPass); 44 | 45 | this.updateOptions = this.updateOptions.bind(this); 46 | } 47 | 48 | update(timeDelta) { 49 | // put frame updates here. 50 | } 51 | 52 | updateOptions(data) { 53 | this.options = data; 54 | this.firstPass.uniforms['scale'].value = this.options.dotScale; 55 | this.secondPass.uniforms['amount'].value = this.options.shiftAmt; 56 | } 57 | 58 | getGUI() { 59 | return (); 60 | } 61 | } 62 | 63 | module.exports = DotShiftStyle; 64 | -------------------------------------------------------------------------------- /src/renderStyles/EdgesStyle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-31 04:57:54 5 | * @modify date 2018-09-02 05:16:26 6 | * @desc [description] 7 | */ 8 | 9 | require('imports-loader?THREE=three!three/examples/js/shaders/CopyShader.js'); 10 | require('imports-loader?THREE=three!three/examples/js/postprocessing/EffectComposer.js'); 11 | require('imports-loader?THREE=three!three/examples/js/postprocessing/RenderPass.js'); 12 | require('imports-loader?THREE=three!three/examples/js/postprocessing/MaskPass.js'); 13 | require('imports-loader?THREE=three!three/examples/js/postprocessing/ShaderPass.js'); 14 | 15 | require('imports-loader?THREE=three!three/examples/js/shaders/LuminosityShader.js'); 16 | require('imports-loader?THREE=three!three/examples/js/shaders/SobelOperatorShader.js'); 17 | 18 | import EdgesSettingsMenu from '../react/menus/render/EdgesSettingsMenu'; 19 | 20 | class EdgesStyle { 21 | constructor(composer, defaults) { 22 | this.composer = composer; 23 | this.defaults = defaults; 24 | 25 | this.name = 'Edges'; 26 | 27 | this.options = {}; 28 | 29 | this.container = $('#scenes'); 30 | this.w = this.container.width(); 31 | this.h = this.container.height(); 32 | 33 | // color to grayscale conversion 34 | this.firstPass = new THREE.ShaderPass(THREE.LuminosityShader); 35 | this.composer.addPass(this.firstPass); 36 | 37 | // you might want to use a gaussian blur filter before 38 | // the next pass to improve the result of the Sobel operator 39 | // Sobel operator 40 | this.secondPass = new THREE.ShaderPass(THREE.SobelOperatorShader); 41 | this.secondPass.renderToScreen = true; 42 | this.secondPass.uniforms.resolution.value.x = this.w; 43 | this.secondPass.uniforms.resolution.value.y = this.h; 44 | this.composer.addPass(this.secondPass); 45 | 46 | this.updateOptions = this.updateOptions.bind(this); 47 | } 48 | 49 | update(timeDelta) { 50 | // put frame updates here. 51 | } 52 | 53 | updateOptions(data) { 54 | this.options = data; 55 | } 56 | 57 | getGUI() { 58 | return (); 59 | } 60 | } 61 | 62 | module.exports = EdgesStyle; -------------------------------------------------------------------------------- /src/renderStyles/HalftoneStyle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-31 04:58:02 5 | * @modify date 2018-09-02 05:58:06 6 | * @desc [description] 7 | */ 8 | 9 | require('imports-loader?THREE=three!three/examples/js/shaders/CopyShader.js'); 10 | require('imports-loader?THREE=three!three/examples/js/postprocessing/EffectComposer.js'); 11 | require('imports-loader?THREE=three!three/examples/js/postprocessing/RenderPass.js'); 12 | require('imports-loader?THREE=three!three/examples/js/postprocessing/MaskPass.js'); 13 | require('imports-loader?THREE=three!three/examples/js/postprocessing/ShaderPass.js'); 14 | 15 | require('imports-loader?THREE=three!three/examples/js/postprocessing/HalftonePass.js'); 16 | require('imports-loader?THREE=three!three/examples/js/shaders/HalftoneShader.js'); 17 | require('imports-loader?THREE=three!three/examples/js/shaders/DepthLimitedBlurShader.js'); 18 | require('imports-loader?THREE=three!three/examples/js/shaders/UnpackDepthRGBAShader.js'); 19 | 20 | import HalftoneSettingsMenu from '../react/menus/render/HalftoneSettingsMenu'; 21 | 22 | class HalftoneStyle { 23 | constructor(composer, defaults) { 24 | this.composer = composer; 25 | this.defaults = defaults; 26 | 27 | this.name = 'Halftone'; 28 | 29 | this.options = { 30 | shapeName: 'Dot', 31 | shape: 1, 32 | shapes: ['Dot', 'Ellipse', 'Line', 'Square'], 33 | radius: 4, 34 | rotateR: Math.PI / 12, 35 | rotateB: (Math.PI / 12) * 2, 36 | rotateG: (Math.PI / 12) * 3, 37 | scatter: 0, 38 | blending: 1, 39 | blendingModeName: 'Linear', 40 | blendingMode: 1, 41 | blendingModes: ['Linear', 'Multiply', 'Add', 'Lighter', 'Darker'], 42 | greyscale: false, 43 | disable: false, 44 | }; 45 | 46 | this.container = $('#scenes'); 47 | this.w = this.container.width(); 48 | this.h = this.container.height(); 49 | 50 | this.firstPass = new THREE.HalftonePass(this.w, this.h, this.options); 51 | this.firstPass.renderToScreen = true; 52 | this.composer.addPass(this.firstPass); 53 | 54 | this.updateOptions = this.updateOptions.bind(this); 55 | } 56 | 57 | update(timeDelta) { 58 | // put frame updates here. 59 | } 60 | 61 | updateOptions(data) { 62 | this.firstPass.uniforms.radius.value = data.radius; 63 | this.firstPass.uniforms.rotateR.value = data.rotateR * (Math.PI / 180); 64 | this.firstPass.uniforms.rotateG.value = data.rotateG * (Math.PI / 180); 65 | this.firstPass.uniforms.rotateB.value = data.rotateB * (Math.PI / 180); 66 | this.firstPass.uniforms.scatter.value = data.scatter; 67 | this.firstPass.uniforms.shape.value = data.shapes.indexOf(data.shapeName) + 1; 68 | this.firstPass.uniforms.greyscale.value = data.greyscale; 69 | this.firstPass.uniforms.blending.value = data.blending; 70 | this.firstPass.uniforms.blendingMode.value = data.blendingModes.indexOf(data.blendingModeName) + 1; 71 | this.firstPass.uniforms.disable.value = data.disable; 72 | 73 | this.options = data; 74 | } 75 | 76 | getGUI() { 77 | return (); 78 | } 79 | } 80 | 81 | module.exports = HalftoneStyle; 82 | -------------------------------------------------------------------------------- /src/renderStyles/PixelStyle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Travis Bennett 3 | * @email 4 | * @create date 2018-08-31 04:58:09 5 | * @modify date 2018-09-02 06:15:46 6 | * @desc [description] 7 | */ 8 | 9 | require('imports-loader?THREE=three!three/examples/js/shaders/CopyShader.js'); 10 | require('imports-loader?THREE=three!three/examples/js/postprocessing/EffectComposer.js'); 11 | require('imports-loader?THREE=three!three/examples/js/postprocessing/RenderPass.js'); 12 | require('imports-loader?THREE=three!three/examples/js/postprocessing/MaskPass.js'); 13 | require('imports-loader?THREE=three!three/examples/js/postprocessing/ShaderPass.js'); 14 | 15 | require('imports-loader?THREE=three!three/examples/js/shaders/PixelShader.js'); 16 | 17 | import PixelSettingsMenu from '../react/menus/render/PixelSettingsMenu'; 18 | 19 | class PixelStyle { 20 | constructor(composer, defaults) { 21 | this.composer = composer; 22 | this.defaults = defaults; 23 | 24 | this.name = 'Pixel'; 25 | 26 | this.options = { 27 | pixelSize: 8 28 | }; 29 | 30 | this.container = $('#scenes'); 31 | this.w = this.container.width(); 32 | this.h = this.container.height(); 33 | 34 | this.firstPass = new THREE.ShaderPass(THREE.PixelShader); 35 | this.firstPass.uniforms.resolution.value = new THREE.Vector2(this.w, this.h); 36 | this.firstPass.uniforms.resolution.value.multiplyScalar(window.devicePixelRatio); 37 | this.firstPass.uniforms.pixelSize.value = this.options.pixelSize; 38 | this.firstPass.renderToScreen = true; 39 | this.composer.addPass(this.firstPass); 40 | 41 | this.updateOptions = this.updateOptions.bind(this); 42 | } 43 | 44 | update(timeDelta) { 45 | // put frame updates here. 46 | } 47 | 48 | updateOptions(data) { 49 | this.options = data; 50 | this.firstPass.uniforms.pixelSize.value = this.options.pixelSize; 51 | } 52 | 53 | getGUI() { 54 | return (); 55 | } 56 | } 57 | 58 | module.exports = PixelStyle; 59 | -------------------------------------------------------------------------------- /src/shaders/morphTargetFragment.glsl: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | void main() { 5 | 6 | gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); 7 | 8 | } -------------------------------------------------------------------------------- /src/shaders/morphTargetVertex.glsl: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | uniform mat4 modelMatrix; 5 | uniform mat4 modelViewMatrix; 6 | uniform mat4 projectionMatrix; 7 | uniform mat4 viewMatrix; 8 | uniform mat3 normalMatrix; 9 | attribute vec3 position; 10 | attribute vec3 normal; 11 | attribute vec2 uv; 12 | 13 | attribute vec3 morphTarget0; 14 | attribute vec3 morphTarget1; 15 | attribute vec3 morphTarget2; 16 | attribute vec3 morphTarget3; 17 | attribute vec3 morphTarget4; 18 | 19 | uniform float morphTargetInfluences[ 4 ]; 20 | 21 | void main() { 22 | vec3 transformed = vec3( position ); 23 | 24 | transformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ]; 25 | transformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ]; 26 | transformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ]; 27 | transformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ]; 28 | 29 | vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 ); 30 | gl_Position = projectionMatrix * mvPosition; 31 | } -------------------------------------------------------------------------------- /src/shaders/performerFragment.glsl: -------------------------------------------------------------------------------- 1 | uniform float iGlobalTime; 2 | uniform vec2 iResolution; 3 | uniform vec4 iMouse; 4 | uniform sampler2D iChannel0; 5 | varying vec2 fragCoord; 6 | varying vec2 vUv; 7 | vec2 cmul( vec2 a, vec2 b ) { return vec2( a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x ); } 8 | vec2 csqr( vec2 a ) { return vec2( a.x*a.x - a.y*a.y, 2.*a.x*a.y ); } 9 | vec3 dmul( vec3 a, vec3 b ) { 10 | float r = length(a); 11 | b.xy=cmul(normalize(a.xy), b.xy); 12 | b.yz=cmul(normalize(a.yz), b.yz); 13 | return r*b; 14 | } 15 | vec3 pow4( vec3 z){ 16 | z=dmul(z,z);return dmul(z,z); 17 | } 18 | vec3 pow3( vec3 z){ 19 | float r2 = dot(z,z); 20 | vec2 a = z.xy;a=csqr(a)/dot( a,a); 21 | vec2 b = z.yz;b=csqr(b)/dot( b,b); 22 | vec2 c = z.xz;c=csqr(c)/dot( c,c); 23 | z.xy = cmul(a,z.xy); 24 | z.yz = cmul(b,z.yz); 25 | z.xz = cmul(c,z.xz); 26 | return r2*z; 27 | } 28 | mat2 rot(float a) { 29 | return mat2(cos(a),sin(a),-sin(a),cos(a)); 30 | } 31 | float zoom=4.; 32 | float field(in vec3 p) { 33 | float res = 0.; 34 | vec3 c = p; 35 | for (int i = 0; i < 10; ++i) { 36 | p = abs(p) / dot(p,p) -1.; 37 | p = dmul(p,p)+.7; 38 | res += exp(-6. * abs(dot(p,c)-.15)); 39 | } 40 | return max(0., res/3.); 41 | } 42 | vec3 raycast( in vec3 ro, vec3 rd ) 43 | { 44 | float t = 6.0; 45 | float dt = .05; 46 | vec3 col= vec3(0.); 47 | for( int i=0; i<64; i++ ) 48 | { 49 | float c = field(ro+t*rd); 50 | t+=dt/(.35+c*c); 51 | c = max(5.0 * c - .9, 0.0); 52 | col = .97*col+ .08*vec3(0.5*c*c*c, .6*c*c, c); 53 | } 54 | return col; 55 | } 56 | void main() 57 | { 58 | float time = iGlobalTime; 59 | vec2 q = fragCoord.xy / iResolution.xy; 60 | vec2 p = -1.0 + 2.0 * q; 61 | p.x *= iResolution.x/iResolution.y; 62 | vec2 m = vec2(0.); 63 | if( iMouse.z>0.0 )m = iMouse.xy/iResolution.xy*3.14; 64 | m-=.5; 65 | vec3 ro = zoom*vec3(1.); 66 | ro.yz*=rot(m.y); 67 | ro.xz*=rot(m.x+ 0.1*time); 68 | vec3 ta = vec3( 0.0 , 0.0, 0.0 ); 69 | vec3 ww = normalize( ta - ro ); 70 | vec3 uu = normalize( cross(ww,vec3(0.0,1.0,0.0) ) ); 71 | vec3 vv = normalize( cross(uu,ww)); 72 | vec3 rd = normalize( p.x*uu + p.y*vv + 4.0*ww ); 73 | vec3 col = raycast(ro,rd); 74 | col = .5 *(log(1.+col)); 75 | col = clamp(col,0.,1.); 76 | gl_FragColor = vec4( sqrt(col), 1.0 ); 77 | } -------------------------------------------------------------------------------- /src/shaders/performerVertex.glsl: -------------------------------------------------------------------------------- 1 | float is_prime(int num) 2 | { 3 | if (num <= 1) return 0.0; 4 | if (num % 2 == 0 && num > 2) return 0.0; 5 | 6 | for(int i = 3; i < int(floor(sqrt(float(num)))); i+= 2) 7 | { 8 | if (num % i == 0) 9 | return 0.0; 10 | } 11 | return 1.0; 12 | } 13 | 14 | 15 | void main( out vec4 fragColor, in vec2 fragCoord ) 16 | { 17 | int temp = ( 18 | int(fragCoord.x + iTime * 80.0 + iMouse.x * 10.0) 19 | ^ // try & | 20 | int(fragCoord.y + iTime * 80.0 + iMouse.y * 10.0) 21 | ); 22 | 23 | float p = is_prime(temp); 24 | 25 | fragColor = vec4(p / 0.4, p / 1.5, p, 1.0); 26 | } -------------------------------------------------------------------------------- /src/shaders/sketch/drawFragment.glsl: -------------------------------------------------------------------------------- 1 | uniform sampler2D tDiffuse; 2 | uniform sampler2D tShadow; 3 | uniform vec2 iResolution; 4 | varying vec2 vUv; 5 | #define Sensitivity (vec2(0.3, 1.5) * iResolution.y / 400.0) 6 | float checkSame(vec4 center, vec4 samplef) 7 | { 8 | vec2 centerNormal = center.xy; 9 | float centerDepth = center.z; 10 | vec2 sampleNormal = samplef.xy; 11 | float sampleDepth = samplef.z; 12 | vec2 diffNormal = abs(centerNormal - sampleNormal) * Sensitivity.x; 13 | bool isSameNormal = (diffNormal.x + diffNormal.y) < 0.1; 14 | float diffDepth = abs(centerDepth - sampleDepth) * Sensitivity.y; 15 | bool isSameDepth = diffDepth < 0.1; 16 | return (isSameNormal && isSameDepth) ? 1.0 : 0.0; 17 | } 18 | void main( ) 19 | { 20 | vec4 sample0 = texture2D(tDiffuse, vUv); 21 | vec4 sample1 = texture2D(tDiffuse, vUv + (vec2(1.0, 1.0) / iResolution.xy)); 22 | vec4 sample2 = texture2D(tDiffuse, vUv + (vec2(-1.0, -1.0) / iResolution.xy)); 23 | vec4 sample3 = texture2D(tDiffuse, vUv + (vec2(-1.0, 1.0) / iResolution.xy)); 24 | vec4 sample4 = texture2D(tDiffuse, vUv + (vec2(1.0, -1.0) / iResolution.xy)); 25 | float edge = checkSame(sample1, sample2) * checkSame(sample3, sample4); 26 | // gl_FragColor = vec4(edge, sample0.w, 1.0, 1.0); 27 | float shadow = texture2D(tShadow, vUv).x; 28 | gl_FragColor = vec4(edge, shadow, 1.0, 1.0); 29 | } -------------------------------------------------------------------------------- /src/shaders/sketch/drawVertex.glsl: -------------------------------------------------------------------------------- 1 | varying vec2 vUv; 2 | void main() { 3 | vec4 mvPosition = modelViewMatrix * vec4(position, 1.); 4 | gl_Position = projectionMatrix * mvPosition; 5 | vUv = uv; 6 | } -------------------------------------------------------------------------------- /src/shaders/sketch/finalFragment.glsl: -------------------------------------------------------------------------------- 1 | uniform sampler2D tDiffuse; 2 | uniform sampler2D tNoise; 3 | uniform float iTime; 4 | varying vec2 vUv; 5 | uniform vec4 EdgeColor; 6 | uniform vec4 BackgroundColor; 7 | uniform float NoiseAmount; 8 | uniform float ErrorPeriod; 9 | uniform float ErrorRange; 10 | // Reference: https://www.shadertoy.com/view/MsSGD1 11 | float triangle(float x) 12 | { 13 | return abs(1.0 - mod(abs(x), 2.0)) * 2.0 - 1.0; 14 | } 15 | float rand(float x) 16 | { 17 | return fract(sin(x) * 43758.5453); 18 | } 19 | void main() 20 | { 21 | float time = floor(iTime * 16.0) / 16.0; 22 | vec2 uv = vUv; 23 | uv += vec2(triangle(uv.y * rand(time) * 1.0) * rand(time * 1.9) * 0.005, 24 | triangle(uv.x * rand(time * 3.4) * 1.0) * rand(time * 2.1) * 0.005); 25 | float noise = (texture2D(tNoise, uv * 0.5).r - 0.5) * NoiseAmount; 26 | vec2 uvs[3]; 27 | uvs[0] = uv + vec2(ErrorRange * sin(ErrorPeriod * uv.y + 0.0) + noise, ErrorRange * sin(ErrorPeriod * uv.x + 0.0) + noise); 28 | uvs[1] = uv + vec2(ErrorRange * sin(ErrorPeriod * uv.y + 1.047) + noise, ErrorRange * sin(ErrorPeriod * uv.x + 3.142) + noise); 29 | uvs[2] = uv + vec2(ErrorRange * sin(ErrorPeriod * uv.y + 2.094) + noise, ErrorRange * sin(ErrorPeriod * uv.x + 1.571) + noise); 30 | float edge = texture2D(tDiffuse, uvs[0]).r * texture2D(tDiffuse, uvs[1]).r * texture2D(tDiffuse, uvs[2]).r; 31 | float diffuse = texture2D(tDiffuse, uv).g; 32 | float w = fwidth(diffuse) * 2.0; 33 | vec4 mCol = mix(BackgroundColor * 0.5, BackgroundColor, mix(0.0, 1.0, smoothstep(-w, w, diffuse - 0.3))); 34 | gl_FragColor = mix(EdgeColor, mCol, edge); 35 | } -------------------------------------------------------------------------------- /src/static/bmFonts/lato-bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/bmFonts/lato-bold.png -------------------------------------------------------------------------------- /src/static/bmFonts/lato-regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/bmFonts/lato-regular.png -------------------------------------------------------------------------------- /src/static/fonts/lato-thin-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/fonts/lato-thin-webfont.eot -------------------------------------------------------------------------------- /src/static/fonts/lato-thin-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/fonts/lato-thin-webfont.ttf -------------------------------------------------------------------------------- /src/static/fonts/lato-thin-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/fonts/lato-thin-webfont.woff -------------------------------------------------------------------------------- /src/static/fonts/lato-thin-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/fonts/lato-thin-webfont.woff2 -------------------------------------------------------------------------------- /src/static/images/credits.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/images/credits.jpg -------------------------------------------------------------------------------- /src/static/images/op_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/images/op_logo.png -------------------------------------------------------------------------------- /src/static/images/op_logo_lockup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/images/op_logo_lockup.png -------------------------------------------------------------------------------- /src/static/images/performer_outline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/images/performer_outline.jpg -------------------------------------------------------------------------------- /src/static/images/preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/images/preview.gif -------------------------------------------------------------------------------- /src/static/images/title.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/images/title.jpg -------------------------------------------------------------------------------- /src/static/images/vr_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/images/vr_active.png -------------------------------------------------------------------------------- /src/static/images/vr_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/images/vr_inactive.png -------------------------------------------------------------------------------- /src/static/models/fbx/Characters/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9e9efecd428e54b9aabf3e5fc4fbc526 3 | folderAsset: yes 4 | timeCreated: 1501101803 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/static/models/fbx/Characters/Materials/GunMaterial.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: GunMaterial 10 | m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} 11 | m_ShaderKeywords: 12 | m_LightmapFlags: 4 13 | m_EnableInstancingVariants: 0 14 | m_DoubleSidedGI: 0 15 | m_CustomRenderQueue: -1 16 | stringTagMap: {} 17 | disabledShaderPasses: [] 18 | m_SavedProperties: 19 | serializedVersion: 3 20 | m_TexEnvs: 21 | - _BumpMap: 22 | m_Texture: {fileID: 0} 23 | m_Scale: {x: 1, y: 1} 24 | m_Offset: {x: 0, y: 0} 25 | - _DetailAlbedoMap: 26 | m_Texture: {fileID: 0} 27 | m_Scale: {x: 1, y: 1} 28 | m_Offset: {x: 0, y: 0} 29 | - _DetailMask: 30 | m_Texture: {fileID: 0} 31 | m_Scale: {x: 1, y: 1} 32 | m_Offset: {x: 0, y: 0} 33 | - _DetailNormalMap: 34 | m_Texture: {fileID: 0} 35 | m_Scale: {x: 1, y: 1} 36 | m_Offset: {x: 0, y: 0} 37 | - _EmissionMap: 38 | m_Texture: {fileID: 0} 39 | m_Scale: {x: 1, y: 1} 40 | m_Offset: {x: 0, y: 0} 41 | - _MainTex: 42 | m_Texture: {fileID: 0} 43 | m_Scale: {x: 1, y: 1} 44 | m_Offset: {x: 0, y: 0} 45 | - _MetallicGlossMap: 46 | m_Texture: {fileID: 0} 47 | m_Scale: {x: 1, y: 1} 48 | m_Offset: {x: 0, y: 0} 49 | - _OcclusionMap: 50 | m_Texture: {fileID: 0} 51 | m_Scale: {x: 1, y: 1} 52 | m_Offset: {x: 0, y: 0} 53 | - _ParallaxMap: 54 | m_Texture: {fileID: 0} 55 | m_Scale: {x: 1, y: 1} 56 | m_Offset: {x: 0, y: 0} 57 | m_Floats: 58 | - _BumpScale: 1 59 | - _Cutoff: 0.5 60 | - _DetailNormalMapScale: 1 61 | - _DstBlend: 0 62 | - _GlossMapScale: 1 63 | - _Glossiness: 0.5 64 | - _GlossyReflections: 1 65 | - _Metallic: 0 66 | - _Mode: 0 67 | - _OcclusionStrength: 1 68 | - _Parallax: 0.02 69 | - _SmoothnessTextureChannel: 0 70 | - _SpecularHighlights: 1 71 | - _SrcBlend: 1 72 | - _UVSec: 0 73 | - _ZWrite: 1 74 | m_Colors: 75 | - _Color: {r: 1, g: 1, b: 1, a: 1} 76 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 77 | -------------------------------------------------------------------------------- /src/static/models/fbx/Characters/Materials/GunMaterial.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fb5e14eb1d53543c2a0f0fb4f0bedcd8 3 | timeCreated: 1501101803 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 2100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/static/models/fbx/Characters/Player.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/fbx/Characters/Player.fbx -------------------------------------------------------------------------------- /src/static/models/fbx/JohnSmithHead.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/fbx/JohnSmithHead.fbx -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 82967c9358aa34ec6a0f6e29750c642a 3 | folderAsset: yes 4 | timeCreated: 1511933011 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/Materials/sloth_all_1001_AlbedoTransparency.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: sloth_all_1001_AlbedoTransparency 10 | m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} 11 | m_ShaderKeywords: _METALLICGLOSSMAP _NORMALMAP 12 | m_LightmapFlags: 4 13 | m_EnableInstancingVariants: 0 14 | m_DoubleSidedGI: 0 15 | m_CustomRenderQueue: -1 16 | stringTagMap: {} 17 | disabledShaderPasses: [] 18 | m_SavedProperties: 19 | serializedVersion: 3 20 | m_TexEnvs: 21 | - _BumpMap: 22 | m_Texture: {fileID: 2800000, guid: 27a1657365e7440158436bc8e151d931, type: 3} 23 | m_Scale: {x: 1, y: 1} 24 | m_Offset: {x: 0, y: 0} 25 | - _DetailAlbedoMap: 26 | m_Texture: {fileID: 0} 27 | m_Scale: {x: 1, y: 1} 28 | m_Offset: {x: 0, y: 0} 29 | - _DetailMask: 30 | m_Texture: {fileID: 0} 31 | m_Scale: {x: 1, y: 1} 32 | m_Offset: {x: 0, y: 0} 33 | - _DetailNormalMap: 34 | m_Texture: {fileID: 0} 35 | m_Scale: {x: 1, y: 1} 36 | m_Offset: {x: 0, y: 0} 37 | - _EmissionMap: 38 | m_Texture: {fileID: 0} 39 | m_Scale: {x: 1, y: 1} 40 | m_Offset: {x: 0, y: 0} 41 | - _MainTex: 42 | m_Texture: {fileID: 2800000, guid: b0a9b07b207264316bf3be95cdcf6a08, type: 3} 43 | m_Scale: {x: 1, y: 1} 44 | m_Offset: {x: 0, y: 0} 45 | - _MetallicGlossMap: 46 | m_Texture: {fileID: 2800000, guid: 433a9cacc6e034c25a6a14eb6af1b09c, type: 3} 47 | m_Scale: {x: 1, y: 1} 48 | m_Offset: {x: 0, y: 0} 49 | - _OcclusionMap: 50 | m_Texture: {fileID: 0} 51 | m_Scale: {x: 1, y: 1} 52 | m_Offset: {x: 0, y: 0} 53 | - _ParallaxMap: 54 | m_Texture: {fileID: 0} 55 | m_Scale: {x: 1, y: 1} 56 | m_Offset: {x: 0, y: 0} 57 | m_Floats: 58 | - _BumpScale: 1 59 | - _Cutoff: 0.5 60 | - _DetailNormalMapScale: 1 61 | - _DstBlend: 0 62 | - _GlossMapScale: 1 63 | - _Glossiness: 0.5 64 | - _GlossyReflections: 1 65 | - _Metallic: 0 66 | - _Mode: 0 67 | - _OcclusionStrength: 1 68 | - _Parallax: 0.02 69 | - _SmoothnessTextureChannel: 0 70 | - _SpecularHighlights: 1 71 | - _SrcBlend: 1 72 | - _UVSec: 0 73 | - _ZWrite: 1 74 | m_Colors: 75 | - _Color: {r: 1, g: 1, b: 1, a: 1} 76 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 77 | -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/Materials/sloth_all_1001_AlbedoTransparency.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0eafc0c8e166e4cd2b0f64b71fda0c45 3 | timeCreated: 1511933011 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 2100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/Textures.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a488c610893e64a3289258a99af35e31 3 | folderAsset: yes 4 | timeCreated: 1510204871 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/Textures/sloth_all_1001_AlbedoTransparency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/fbx/SlothCharacter/Textures/sloth_all_1001_AlbedoTransparency.png -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/Textures/sloth_all_1001_AlbedoTransparency.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b0a9b07b207264316bf3be95cdcf6a08 3 | timeCreated: 1510333546 4 | licenseType: Free 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 1 11 | sRGBTexture: 1 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapFadeDistanceStart: 1 16 | mipMapFadeDistanceEnd: 3 17 | bumpmap: 18 | convertToNormalMap: 0 19 | externalNormalMap: 0 20 | heightScale: 0.25 21 | normalMapFilter: 0 22 | isReadable: 0 23 | grayScaleToAlpha: 0 24 | generateCubemap: 6 25 | cubemapConvolution: 0 26 | seamlessCubemap: 0 27 | textureFormat: 1 28 | maxTextureSize: 2048 29 | textureSettings: 30 | filterMode: -1 31 | aniso: -1 32 | mipBias: -1 33 | wrapMode: -1 34 | nPOTScale: 1 35 | lightmap: 0 36 | compressionQuality: 50 37 | spriteMode: 0 38 | spriteExtrude: 1 39 | spriteMeshType: 1 40 | alignment: 0 41 | spritePivot: {x: 0.5, y: 0.5} 42 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 43 | spritePixelsToUnits: 100 44 | alphaUsage: 1 45 | alphaIsTransparency: 0 46 | spriteTessellationDetail: -1 47 | textureType: 0 48 | textureShape: 1 49 | maxTextureSizeSet: 0 50 | compressionQualitySet: 0 51 | textureFormatSet: 0 52 | platformSettings: 53 | - buildTarget: DefaultTexturePlatform 54 | maxTextureSize: 4096 55 | textureFormat: -1 56 | textureCompression: 1 57 | compressionQuality: 50 58 | crunchedCompression: 0 59 | allowsAlphaSplitting: 0 60 | overridden: 0 61 | - buildTarget: Standalone 62 | maxTextureSize: 4096 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | spriteSheet: 70 | serializedVersion: 2 71 | sprites: [] 72 | outline: [] 73 | spritePackingTag: 74 | userData: 75 | assetBundleName: 76 | assetBundleVariant: 77 | -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/Textures/sloth_all_1001_MetallicSmoothness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/fbx/SlothCharacter/Textures/sloth_all_1001_MetallicSmoothness.png -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/Textures/sloth_all_1001_MetallicSmoothness.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 433a9cacc6e034c25a6a14eb6af1b09c 3 | timeCreated: 1510333569 4 | licenseType: Free 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 1 11 | sRGBTexture: 1 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapFadeDistanceStart: 1 16 | mipMapFadeDistanceEnd: 3 17 | bumpmap: 18 | convertToNormalMap: 0 19 | externalNormalMap: 0 20 | heightScale: 0.25 21 | normalMapFilter: 0 22 | isReadable: 0 23 | grayScaleToAlpha: 0 24 | generateCubemap: 6 25 | cubemapConvolution: 0 26 | seamlessCubemap: 0 27 | textureFormat: 1 28 | maxTextureSize: 2048 29 | textureSettings: 30 | filterMode: -1 31 | aniso: -1 32 | mipBias: -1 33 | wrapMode: -1 34 | nPOTScale: 1 35 | lightmap: 0 36 | compressionQuality: 50 37 | spriteMode: 0 38 | spriteExtrude: 1 39 | spriteMeshType: 1 40 | alignment: 0 41 | spritePivot: {x: 0.5, y: 0.5} 42 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 43 | spritePixelsToUnits: 100 44 | alphaUsage: 1 45 | alphaIsTransparency: 0 46 | spriteTessellationDetail: -1 47 | textureType: 0 48 | textureShape: 1 49 | maxTextureSizeSet: 0 50 | compressionQualitySet: 0 51 | textureFormatSet: 0 52 | platformSettings: 53 | - buildTarget: DefaultTexturePlatform 54 | maxTextureSize: 4096 55 | textureFormat: -1 56 | textureCompression: 1 57 | compressionQuality: 50 58 | crunchedCompression: 0 59 | allowsAlphaSplitting: 0 60 | overridden: 0 61 | - buildTarget: Standalone 62 | maxTextureSize: 4096 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | spriteSheet: 70 | serializedVersion: 2 71 | sprites: [] 72 | outline: [] 73 | spritePackingTag: 74 | userData: 75 | assetBundleName: 76 | assetBundleVariant: 77 | -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/Textures/sloth_all_1001_Normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/fbx/SlothCharacter/Textures/sloth_all_1001_Normal.png -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/Textures/sloth_all_1001_Normal.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 27a1657365e7440158436bc8e151d931 3 | timeCreated: 1510333583 4 | licenseType: Free 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 1 11 | sRGBTexture: 0 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapFadeDistanceStart: 1 16 | mipMapFadeDistanceEnd: 3 17 | bumpmap: 18 | convertToNormalMap: 0 19 | externalNormalMap: 0 20 | heightScale: 0.25 21 | normalMapFilter: 0 22 | isReadable: 0 23 | grayScaleToAlpha: 0 24 | generateCubemap: 6 25 | cubemapConvolution: 0 26 | seamlessCubemap: 0 27 | textureFormat: 1 28 | maxTextureSize: 2048 29 | textureSettings: 30 | filterMode: -1 31 | aniso: -1 32 | mipBias: -1 33 | wrapMode: -1 34 | nPOTScale: 1 35 | lightmap: 0 36 | compressionQuality: 50 37 | spriteMode: 0 38 | spriteExtrude: 1 39 | spriteMeshType: 1 40 | alignment: 0 41 | spritePivot: {x: 0.5, y: 0.5} 42 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 43 | spritePixelsToUnits: 100 44 | alphaUsage: 1 45 | alphaIsTransparency: 0 46 | spriteTessellationDetail: -1 47 | textureType: 1 48 | textureShape: 1 49 | maxTextureSizeSet: 0 50 | compressionQualitySet: 0 51 | textureFormatSet: 0 52 | platformSettings: 53 | - buildTarget: DefaultTexturePlatform 54 | maxTextureSize: 4096 55 | textureFormat: -1 56 | textureCompression: 1 57 | compressionQuality: 50 58 | crunchedCompression: 0 59 | allowsAlphaSplitting: 0 60 | overridden: 0 61 | - buildTarget: Standalone 62 | maxTextureSize: 4096 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | spriteSheet: 70 | serializedVersion: 2 71 | sprites: [] 72 | outline: [] 73 | spritePackingTag: 74 | userData: 75 | assetBundleName: 76 | assetBundleVariant: 77 | -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/sloth_head_blendshapes5.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/fbx/SlothCharacter/sloth_head_blendshapes5.fbx -------------------------------------------------------------------------------- /src/static/models/fbx/SlothCharacter/sloth_head_blendshapes5.fbx.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 63ae12abc50414d5c882dbe18f6a820b 3 | timeCreated: 1511933011 4 | licenseType: Pro 5 | ModelImporter: 6 | serializedVersion: 19 7 | fileIDToRecycleName: 8 | 100000: blendshapes3 9 | 100002: Sloth_Head2 10 | 100004: //RootNode 11 | 400000: blendshapes3 12 | 400002: Sloth_Head2 13 | 400004: //RootNode 14 | 4300000: Sloth_Head2 15 | 9500000: //RootNode 16 | 13700000: Sloth_Head2 17 | materials: 18 | importMaterials: 1 19 | materialName: 0 20 | materialSearch: 1 21 | animations: 22 | legacyGenerateAnimations: 4 23 | bakeSimulation: 0 24 | resampleCurves: 1 25 | optimizeGameObjects: 0 26 | motionNodeName: 27 | rigImportErrors: 28 | rigImportWarnings: 29 | animationImportErrors: 30 | animationImportWarnings: 31 | animationRetargetingWarnings: 32 | animationDoRetargetingWarnings: 0 33 | animationCompression: 1 34 | animationRotationError: 0.5 35 | animationPositionError: 0.5 36 | animationScaleError: 0.5 37 | animationWrapMode: 0 38 | extraExposedTransformPaths: [] 39 | clipAnimations: [] 40 | isReadable: 1 41 | meshes: 42 | lODScreenPercentages: [] 43 | globalScale: 10 44 | meshCompression: 0 45 | addColliders: 0 46 | importBlendShapes: 1 47 | swapUVChannels: 0 48 | generateSecondaryUV: 0 49 | useFileUnits: 1 50 | optimizeMeshForGPU: 1 51 | keepQuads: 0 52 | weldVertices: 1 53 | secondaryUVAngleDistortion: 8 54 | secondaryUVAreaDistortion: 15.000001 55 | secondaryUVHardAngle: 88 56 | secondaryUVPackMargin: 4 57 | useFileScale: 1 58 | tangentSpace: 59 | normalSmoothAngle: 60 60 | normalImportMode: 0 61 | tangentImportMode: 3 62 | importAnimation: 1 63 | copyAvatar: 0 64 | humanDescription: 65 | serializedVersion: 2 66 | human: [] 67 | skeleton: [] 68 | armTwist: 0.5 69 | foreArmTwist: 0.5 70 | upperLegTwist: 0.5 71 | legTwist: 0.5 72 | armStretch: 0.05 73 | legStretch: 0.05 74 | feetSpacing: 0 75 | rootMotionBoneName: 76 | rootMotionBoneRotation: {x: 0, y: 0, z: 0, w: 1} 77 | hasTranslationDoF: 0 78 | hasExtraRoot: 0 79 | skeletonHasParents: 1 80 | lastHumanDescriptionAvatarSource: {instanceID: 0} 81 | animationType: 2 82 | humanoidOversampling: 1 83 | additionalBone: 0 84 | userData: 85 | assetBundleName: 86 | assetBundleVariant: 87 | -------------------------------------------------------------------------------- /src/static/models/gltf/basicFace.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/gltf/basicFace.bin -------------------------------------------------------------------------------- /src/static/models/gltf/mars/scene.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/gltf/mars/scene.bin -------------------------------------------------------------------------------- /src/static/models/gltf/mars/textures/01_-_Default_baseColor.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/gltf/mars/textures/01_-_Default_baseColor.jpeg -------------------------------------------------------------------------------- /src/static/models/gltf/mars/textures/01_-_Default_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/gltf/mars/textures/01_-_Default_normal.png -------------------------------------------------------------------------------- /src/static/models/gltf/mars/textures/02_-_Default_baseColor.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/gltf/mars/textures/02_-_Default_baseColor.jpeg -------------------------------------------------------------------------------- /src/static/models/gltf/mars/textures/02_-_Default_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/gltf/mars/textures/02_-_Default_normal.png -------------------------------------------------------------------------------- /src/static/models/gltf/mars/textures/03_-_Default_baseColor.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/gltf/mars/textures/03_-_Default_baseColor.jpeg -------------------------------------------------------------------------------- /src/static/models/gltf/mars/textures/03_-_Default_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/gltf/mars/textures/03_-_Default_normal.png -------------------------------------------------------------------------------- /src/static/models/mtl/forest.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'low poly forest assets 1 .blend' 2 | # Material Count: 14 3 | 4 | newmtl Material 5 | Ns 96.078431 6 | Ka 1.000000 1.000000 1.000000 7 | Kd 0.640000 0.640000 0.640000 8 | Ks 0.500000 0.500000 0.500000 9 | Ke 0.000000 0.000000 0.000000 10 | Ni 1.000000 11 | d 1.000000 12 | illum 2 13 | 14 | newmtl Material.002 15 | Ns 96.078431 16 | Ka 1.000000 1.000000 1.000000 17 | Kd 0.640000 0.640000 0.640000 18 | Ks 0.500000 0.500000 0.500000 19 | Ke 0.000000 0.000000 0.000000 20 | Ni 1.000000 21 | d 1.000000 22 | illum 2 23 | 24 | newmtl Material.005 25 | Ns 96.078431 26 | Ka 1.000000 1.000000 1.000000 27 | Kd 0.640000 0.640000 0.640000 28 | Ks 0.500000 0.500000 0.500000 29 | Ke 0.000000 0.000000 0.000000 30 | Ni 1.000000 31 | d 1.000000 32 | illum 2 33 | 34 | newmtl Material.008 35 | Ns 96.078431 36 | Ka 1.000000 1.000000 1.000000 37 | Kd 0.640000 0.640000 0.640000 38 | Ks 0.500000 0.500000 0.500000 39 | Ke 0.000000 0.000000 0.000000 40 | Ni 1.000000 41 | d 1.000000 42 | illum 2 43 | 44 | newmtl Material.009 45 | Ns 96.078431 46 | Ka 1.000000 1.000000 1.000000 47 | Kd 0.640000 0.640000 0.640000 48 | Ks 0.500000 0.500000 0.500000 49 | Ke 0.000000 0.000000 0.000000 50 | Ni 1.000000 51 | d 1.000000 52 | illum 2 53 | 54 | newmtl Material.010 55 | Ns 96.078431 56 | Ka 1.000000 1.000000 1.000000 57 | Kd 0.640000 0.640000 0.640000 58 | Ks 0.500000 0.500000 0.500000 59 | Ke 0.000000 0.000000 0.000000 60 | Ni 1.000000 61 | d 1.000000 62 | illum 2 63 | 64 | newmtl Material.011 65 | Ns 96.078431 66 | Ka 1.000000 1.000000 1.000000 67 | Kd 0.640000 0.640000 0.640000 68 | Ks 0.500000 0.500000 0.500000 69 | Ke 0.000000 0.000000 0.000000 70 | Ni 1.000000 71 | d 1.000000 72 | illum 2 73 | 74 | newmtl Material.014 75 | Ns 96.078431 76 | Ka 1.000000 1.000000 1.000000 77 | Kd 0.640000 0.640000 0.640000 78 | Ks 0.500000 0.500000 0.500000 79 | Ke 0.000000 0.000000 0.000000 80 | Ni 1.000000 81 | d 1.000000 82 | illum 2 83 | 84 | newmtl Material.015 85 | Ns 96.078431 86 | Ka 1.000000 1.000000 1.000000 87 | Kd 0.640000 0.640000 0.640000 88 | Ks 0.500000 0.500000 0.500000 89 | Ke 0.000000 0.000000 0.000000 90 | Ni 1.000000 91 | d 1.000000 92 | illum 2 93 | 94 | newmtl Material.016 95 | Ns 96.078431 96 | Ka 1.000000 1.000000 1.000000 97 | Kd 0.640000 0.640000 0.640000 98 | Ks 0.500000 0.500000 0.500000 99 | Ke 0.000000 0.000000 0.000000 100 | Ni 1.000000 101 | d 1.000000 102 | illum 2 103 | 104 | newmtl Material.017 105 | Ns 96.078431 106 | Ka 1.000000 1.000000 1.000000 107 | Kd 0.640000 0.640000 0.640000 108 | Ks 0.500000 0.500000 0.500000 109 | Ke 0.000000 0.000000 0.000000 110 | Ni 1.000000 111 | d 1.000000 112 | illum 2 113 | 114 | newmtl Material.020 115 | Ns 96.078431 116 | Ka 1.000000 1.000000 1.000000 117 | Kd 0.640000 0.640000 0.640000 118 | Ks 0.500000 0.500000 0.500000 119 | Ke 0.000000 0.000000 0.000000 120 | Ni 1.000000 121 | d 1.000000 122 | illum 2 123 | 124 | newmtl Material.021 125 | Ns 96.078431 126 | Ka 1.000000 1.000000 1.000000 127 | Kd 0.640000 0.640000 0.640000 128 | Ks 0.500000 0.500000 0.500000 129 | Ke 0.000000 0.000000 0.000000 130 | Ni 1.000000 131 | d 1.000000 132 | illum 2 133 | 134 | newmtl soil 135 | Ns 96.078431 136 | Ka 1.000000 1.000000 1.000000 137 | Kd 0.640000 0.640000 0.640000 138 | Ks 0.500000 0.500000 0.500000 139 | Ke 0.000000 0.000000 0.000000 140 | Ni 1.000000 141 | d 1.000000 142 | illum 2 143 | -------------------------------------------------------------------------------- /src/static/models/textures/sloth_all_1001_AlbedoTransparency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/textures/sloth_all_1001_AlbedoTransparency.png -------------------------------------------------------------------------------- /src/static/models/textures/sloth_all_1001_MetallicSmoothness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/textures/sloth_all_1001_MetallicSmoothness.png -------------------------------------------------------------------------------- /src/static/models/textures/sloth_all_1001_Normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/models/textures/sloth_all_1001_Normal.png -------------------------------------------------------------------------------- /src/static/textures/grasslight-big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/grasslight-big.jpg -------------------------------------------------------------------------------- /src/static/textures/newmoon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/newmoon.png -------------------------------------------------------------------------------- /src/static/textures/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/noise.png -------------------------------------------------------------------------------- /src/static/textures/particle2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/particle2.png -------------------------------------------------------------------------------- /src/static/textures/pebbledwall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/pebbledwall.png -------------------------------------------------------------------------------- /src/static/textures/perlin-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/perlin-512.png -------------------------------------------------------------------------------- /src/static/textures/skyb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/skyb.png -------------------------------------------------------------------------------- /src/static/textures/skybox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/skybox.png -------------------------------------------------------------------------------- /src/static/textures/skyboxsun25degtest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/skyboxsun25degtest.png -------------------------------------------------------------------------------- /src/static/textures/skyboxsun25degtest.txt: -------------------------------------------------------------------------------- 1 | http://reije081.home.xs4all.nl/skyboxes/ 2 | -------------------------------------------------------------------------------- /src/static/textures/skyboxsun25degtest2.png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/skyboxsun25degtest2.png.png -------------------------------------------------------------------------------- /src/static/textures/sleepyhollow/sleepyhollow_bk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/sleepyhollow/sleepyhollow_bk.jpg -------------------------------------------------------------------------------- /src/static/textures/sleepyhollow/sleepyhollow_dn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/sleepyhollow/sleepyhollow_dn.jpg -------------------------------------------------------------------------------- /src/static/textures/sleepyhollow/sleepyhollow_ft.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/sleepyhollow/sleepyhollow_ft.jpg -------------------------------------------------------------------------------- /src/static/textures/sleepyhollow/sleepyhollow_lf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/sleepyhollow/sleepyhollow_lf.jpg -------------------------------------------------------------------------------- /src/static/textures/sleepyhollow/sleepyhollow_rt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/sleepyhollow/sleepyhollow_rt.jpg -------------------------------------------------------------------------------- /src/static/textures/sleepyhollow/sleepyhollow_up.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/sleepyhollow/sleepyhollow_up.jpg -------------------------------------------------------------------------------- /src/static/textures/tears/tears_bk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/tears/tears_bk.jpg -------------------------------------------------------------------------------- /src/static/textures/tears/tears_dn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/tears/tears_dn.jpg -------------------------------------------------------------------------------- /src/static/textures/tears/tears_ft.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/tears/tears_ft.jpg -------------------------------------------------------------------------------- /src/static/textures/tears/tears_lf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/tears/tears_lf.jpg -------------------------------------------------------------------------------- /src/static/textures/tears/tears_rt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/tears/tears_rt.jpg -------------------------------------------------------------------------------- /src/static/textures/tears/tears_up.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/tears/tears_up.jpg -------------------------------------------------------------------------------- /src/static/textures/waternormals.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinetecharts/openPerform/63292588f3619cb50a569a578148465ad9eab0cd/src/static/textures/waternormals.jpg -------------------------------------------------------------------------------- /src/styles/colors.css: -------------------------------------------------------------------------------- 1 | @Orange: #FF8800; 2 | @LtOrange: #FBAE44; 3 | @DkGrey: #585858; 4 | @BlueGreen: #4FD4E9; 5 | @Blue: #0073ae; 6 | @LtBlue: #4FD4E9; 7 | @DkBlue: #23495E; 8 | 9 | @PanelOpac: 0.75; 10 | @BackgroundVideoOpac: 0.75; -------------------------------------------------------------------------------- /src/styles/fonts.css: -------------------------------------------------------------------------------- 1 | /* @font-face { 2 | font-family: 'lato-black-webfont'; 3 | src: url('./../static/fonts/lato-black-webfont.eot?#iefix') format('embedded-opentype'), 4 | url('./../static/fonts/lato-black-webfont.woff') format('woff'), url('./../static/fonts/lato-black-webfont.ttf') format('truetype'), url('./../static/fonts/lato-black-webfont.svg#lato-black-webfont') format('svg'); 5 | } 6 | 7 | @font-face { 8 | font-family: 'lato-bold-webfont'; 9 | src: url('./../static/fonts/lato-bold-webfont.eot?#iefix') format('embedded-opentype'), 10 | url('./../static/fonts/lato-bold-webfont.woff') format('woff'), url('./../static/fonts/lato-bold-webfont.ttf') format('truetype'), url('./../static/fonts/lato-bold-webfont.svg#lato-bold-webfont') format('svg'); 11 | } 12 | 13 | @font-face { 14 | font-family: 'lato-hairline-webfont'; 15 | src: url('./../static/fonts/lato-hairline-webfont.eot?#iefix') format('embedded-opentype'), 16 | url('./../static/fonts/lato-hairline-webfont.woff') format('woff'), url('./../static/fonts/lato-hairline-webfont.ttf') format('truetype'), url('./../static/fonts/lato-hairline-webfont.svg#lato-hairline-webfont') format('svg'); 17 | } 18 | 19 | @font-face { 20 | font-family: 'lato-heavy-webfont'; 21 | src: url('./../static/fonts/lato-heavy-webfont.eot?#iefix') format('embedded-opentype'), 22 | url('./../static/fonts/lato-heavy-webfont.woff') format('woff'), url('./../static/fonts/lato-heavy-webfont.ttf') format('truetype'), url('./../static/fonts/lato-heavy-webfont.svg#lato-heavy-webfont') format('svg'); 23 | } 24 | 25 | @font-face { 26 | font-family: 'lato-light-webfont'; 27 | src: url('./../static/fonts/lato-light-webfont.eot?#iefix') format('embedded-opentype'), 28 | url('./../static/fonts/lato-light-webfont.woff') format('woff'), url('./../static/fonts/lato-light-webfont.ttf') format('truetype'), url('./../static/fonts/lato-light-webfont.svg#lato-light-webfont') format('svg'); 29 | } 30 | 31 | @font-face { 32 | font-family: 'lato-medium-webfont'; 33 | src: url('./../static/fonts/lato-medium-webfont.eot?#iefix') format('embedded-opentype'), 34 | url('./../static/fonts/lato-medium-webfont.woff') format('woff'), url('./../static/fonts/lato-medium-webfont.ttf') format('truetype'), url('./../static/fonts/lato-medium-webfont.svg#lato-medium-webfont') format('svg'); 35 | } 36 | 37 | @font-face { 38 | font-family: 'lato-regular-webfont'; 39 | src: url('./../static/fonts/lato-regular-webfont.eot?#iefix') format('embedded-opentype'), 40 | url('./../static/fonts/lato-regular-webfont.woff') format('woff'), url('./../static/fonts/lato-regular-webfont.ttf') format('truetype'), url('./../static/fonts/lato-regular-webfont.svg#lato-regular-webfont') format('svg'); 41 | } 42 | 43 | @font-face { 44 | font-family: 'lato-semibold-webfont'; 45 | src: url('./../static/fonts/lato-semibold-webfont.eot?#iefix') format('embedded-opentype'), 46 | url('./../static/fonts/lato-semibold-webfont.woff') format('woff'), url('./../static/fonts/lato-semibold-webfont.ttf') format('truetype'), url('./../static/fonts/lato-semibold-webfont.svg#lato-semibold-webfont') format('svg'); 47 | } */ 48 | 49 | @font-face { 50 | font-family: 'lato-thin-webfont'; 51 | src: url('./../static/fonts/lato-thin-webfont.eot?#iefix') format('embedded-opentype'), 52 | url('./../static/fonts/lato-thin-webfont.woff') format('woff'), 53 | url('./../static/fonts/lato-thin-webfont.ttf') format('truetype'), 54 | url('./../static/fonts/lato-thin-webfont.svg#lato-thin-webfont') format('svg'); 55 | } -------------------------------------------------------------------------------- /src/styles/login.css: -------------------------------------------------------------------------------- 1 | #login { 2 | font-family: 'lato-regular-webfont' !important; 3 | width: 400px; 4 | overflow: hidden; 5 | margin-right: auto; 6 | margin-left: auto; 7 | background: white; 8 | border-radius: 25px; 9 | padding:15px; 10 | border: 1px solid black; 11 | } 12 | 13 | #login > #logo { 14 | width: 70%; 15 | margin-right: auto; 16 | margin-left: auto; 17 | display: block; 18 | } 19 | 20 | #login > div > .form-group > input , #login > div > .form-group > button { 21 | margin: 0 auto 10px auto; 22 | display: block; 23 | } 24 | 25 | #login > div > .form-group > input { 26 | padding: 10px 15px; 27 | } 28 | 29 | #login > div > .form-group > button { 30 | background: #fff; 31 | padding: 10px 15px; 32 | border-radius: 10px; 33 | font-weight: bold; 34 | } -------------------------------------------------------------------------------- /src/three/vr/VRControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author dmarcos / https://github.com/dmarcos 3 | * @author mrdoob / http://mrdoob.com 4 | */ 5 | 6 | THREE.VRControls = function (object, onError) { 7 | const scope = this; 8 | 9 | let vrDisplay, 10 | vrDisplays; 11 | 12 | const standingMatrix = new THREE.Matrix4(); 13 | 14 | let frameData = null; 15 | 16 | if ('VRFrameData' in window) { 17 | frameData = new VRFrameData(); 18 | } 19 | 20 | function gotVRDisplays(displays) { 21 | vrDisplays = displays; 22 | 23 | if (displays.length > 0) { 24 | vrDisplay = displays[0]; 25 | } else if (onError) onError('VR input not available.'); 26 | } 27 | 28 | if (navigator.getVRDisplays) { 29 | navigator.getVRDisplays().then(gotVRDisplays); 30 | } 31 | 32 | // the Rift SDK returns the position in meters 33 | // this scale factor allows the user to define how meters 34 | // are converted to scene units. 35 | 36 | this.scale = 1; 37 | 38 | // If true will use "standing space" coordinate system where y=0 is the 39 | // floor and x=0, z=0 is the center of the room. 40 | this.standing = false; 41 | 42 | // Distance from the users eyes to the floor in meters. Used when 43 | // standing=true but the VRDisplay doesn't provide stageParameters. 44 | this.userHeight = 1.6; 45 | 46 | this.getVRDisplay = function () { 47 | return vrDisplay; 48 | }; 49 | 50 | this.setVRDisplay = function (value) { 51 | vrDisplay = value; 52 | }; 53 | 54 | this.getVRDisplays = function () { 55 | console.warn('THREE.VRControls: getVRDisplays() is being deprecated.'); 56 | return vrDisplays; 57 | }; 58 | 59 | this.getStandingMatrix = function () { 60 | return standingMatrix; 61 | }; 62 | 63 | this.update = function () { 64 | if (vrDisplay) { 65 | let pose; 66 | 67 | if (vrDisplay.getFrameData) { 68 | vrDisplay.getFrameData(frameData); 69 | pose = frameData.pose; 70 | } else if (vrDisplay.getPose) { 71 | pose = vrDisplay.getPose(); 72 | } 73 | 74 | if (pose.orientation !== null) { 75 | object.quaternion.fromArray(pose.orientation); 76 | } 77 | 78 | if (pose.position !== null) { 79 | object.position.fromArray(pose.position); 80 | } else { 81 | object.position.set(0, 0, 0); 82 | } 83 | 84 | if (this.standing) { 85 | if (vrDisplay.stageParameters) { 86 | object.updateMatrix(); 87 | 88 | standingMatrix.fromArray(vrDisplay.stageParameters.sittingToStandingTransform); 89 | object.applyMatrix(standingMatrix); 90 | } else { 91 | object.position.setY(object.position.y + this.userHeight); 92 | } 93 | } 94 | 95 | object.position.multiplyScalar(scope.scale); 96 | } 97 | }; 98 | 99 | this.resetPose = function () { 100 | if (vrDisplay) { 101 | vrDisplay.resetPose(); 102 | } 103 | }; 104 | 105 | this.resetSensor = function () { 106 | console.warn('THREE.VRControls: .resetSensor() is now .resetPose().'); 107 | this.resetPose(); 108 | }; 109 | 110 | this.zeroSensor = function () { 111 | console.warn('THREE.VRControls: .zeroSensor() is now .resetPose().'); 112 | this.resetPose(); 113 | }; 114 | 115 | this.dispose = function () { 116 | vrDisplay = null; 117 | }; 118 | }; 119 | -------------------------------------------------------------------------------- /src/three/vr/WebVR.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com 3 | * Based on @tojiro's vr-samples-utils.js 4 | */ 5 | 6 | const WEBVR = { 7 | 8 | isLatestAvailable() { 9 | console.warn('WEBVR: isLatestAvailable() is being deprecated. Use .isAvailable() instead.'); 10 | return this.isAvailable(); 11 | }, 12 | 13 | isAvailable() { 14 | return navigator.getVRDisplays !== undefined; 15 | }, 16 | 17 | getMessage() { 18 | let message; 19 | 20 | if (navigator.getVRDisplays) { 21 | navigator.getVRDisplays().then((displays) => { 22 | if (displays.length === 0) message = 'WebVR supported, but no VRDisplays found.'; 23 | }); 24 | } else { 25 | message = 'Your browser does not support WebVR. See webvr.info for assistance.'; 26 | } 27 | 28 | if (message !== undefined) { 29 | const container = document.createElement('div'); 30 | container.style.position = 'absolute'; 31 | container.style.left = '0'; 32 | container.style.top = '0'; 33 | container.style.right = '0'; 34 | container.style.zIndex = '999'; 35 | container.align = 'center'; 36 | 37 | const error = document.createElement('div'); 38 | error.style.fontFamily = 'sans-serif'; 39 | error.style.fontSize = '16px'; 40 | error.style.fontStyle = 'normal'; 41 | error.style.lineHeight = '26px'; 42 | error.style.backgroundColor = '#fff'; 43 | error.style.color = '#000'; 44 | error.style.padding = '10px 20px'; 45 | error.style.margin = '50px'; 46 | error.style.display = 'inline-block'; 47 | error.innerHTML = message; 48 | container.appendChild(error); 49 | 50 | return container; 51 | } 52 | }, 53 | 54 | getButton(effect) { 55 | const button = document.createElement('button'); 56 | button.style.position = 'absolute'; 57 | button.style.left = 'calc(50% - 50px)'; 58 | button.style.bottom = '20px'; 59 | button.style.width = '100px'; 60 | button.style.border = '0'; 61 | button.style.padding = '8px'; 62 | button.style.cursor = 'pointer'; 63 | button.style.backgroundColor = '#000'; 64 | button.style.color = '#fff'; 65 | button.style.fontFamily = 'sans-serif'; 66 | button.style.fontSize = '13px'; 67 | button.style.fontStyle = 'normal'; 68 | button.style.textAlign = 'center'; 69 | button.style.zIndex = '999'; 70 | button.textContent = 'ENTER VR'; 71 | button.onclick = function () { 72 | effect.isPresenting ? effect.exitPresent() : effect.requestPresent(); 73 | }; 74 | 75 | window.addEventListener('vrdisplaypresentchange', (event) => { 76 | button.textContent = effect.isPresenting ? 'EXIT VR' : 'ENTER VR'; 77 | }, false); 78 | 79 | return button; 80 | }, 81 | 82 | }; 83 | 84 | export default WEBVR; 85 | -------------------------------------------------------------------------------- /src/three/vr/tools/sculpt.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Sculpt { 4 | constructor(parent) { 5 | this.parent = parent; 6 | 7 | this.blob = null; 8 | this.vector = null; 9 | 10 | this.points = []; 11 | 12 | this.color = new THREE.Color(0xFFFFFF); 13 | 14 | this.up = new THREE.Vector3(0, 1, 0); 15 | this.vector = new THREE.Vector3(); 16 | 17 | this.matrix = null; 18 | 19 | this.initBlob(); 20 | } 21 | 22 | updateStrength(id) { 23 | this.points[id].strength = (Math.sin(performance.now() / 1000) + 1.5) / 20.0; 24 | } 25 | 26 | erase() { 27 | if (this.points.length > 2) { 28 | this.points.shift(); 29 | this.points.shift(); 30 | 31 | this.update(); 32 | 33 | const geometry = this.blob.generateGeometry(); 34 | const mesh = new THREE.Mesh(geometry, this.blob.material.clone()); 35 | mesh.position.y = 1; 36 | mesh.castShadow = true; 37 | mesh.receiveShadow = true; 38 | this.parent.add(mesh); 39 | 40 | this.initPoints(); 41 | } 42 | } 43 | 44 | draw(id) { 45 | const strength = this.points[id].strength / 2; 46 | 47 | this.vector = new THREE.Vector3().setFromMatrixPosition(this.matrix); 48 | 49 | this.transformPoint(this.vector); 50 | 51 | this.points.push({ position: this.vector, strength, subtract: 10 }); 52 | } 53 | 54 | transformPoint(vector) { 55 | this.vector.x = (vector.x + 1.0) / 2.0; 56 | this.vector.y = (vector.y / 2.0); 57 | this.vector.z = (vector.z + 1.0) / 2.0; 58 | } 59 | 60 | updatePoints(pivot, controller, id) { 61 | this.matrix = pivot.matrixWorld; 62 | 63 | this.points[id].position.setFromMatrixPosition(this.matrix); 64 | this.transformPoint(this.points[id].position); 65 | } 66 | 67 | clonePoints() {} 68 | 69 | updateColor(color) { 70 | this.color = color; 71 | this.blob.material.color = this.color; 72 | } 73 | 74 | initBlob() { 75 | const material = new THREE.MeshStandardMaterial({ 76 | color: this.color, 77 | roughness: 0.9, 78 | metalness: 0.0, 79 | }); 80 | 81 | this.blob = new THREE.MarchingCubes(64, material, true); 82 | this.blob.position.y = 1; 83 | this.parent.add(this.blob); 84 | 85 | this.initPoints(); 86 | } 87 | 88 | initPoints() { 89 | this.points = [ 90 | { position: new THREE.Vector3(), strength: -0.08, subtract: 10 }, 91 | { position: new THREE.Vector3(), strength: 0.04, subtract: 10 }, 92 | ]; 93 | } 94 | 95 | update() { 96 | this.blob.reset(); 97 | 98 | for (let i = 0; i < this.points.length; i++) { 99 | const point = this.points[i]; 100 | const position = point.position; 101 | 102 | this.blob.addBall(position.x, position.y, position.z, point.strength, point.subtract); 103 | } 104 | } 105 | } 106 | 107 | export default Sculpt; 108 | -------------------------------------------------------------------------------- /src/util/Common.js: -------------------------------------------------------------------------------- 1 | // Common utility functions 2 | 3 | 4 | 5 | 6 | function Common() { 7 | const self = this; 8 | 9 | this.getKeys = function (obj, append) { 10 | const all = {}; 11 | const seen = []; 12 | checkValue(obj); 13 | return Object.keys(all); 14 | function checkValue(value) { 15 | if (Array.isArray(value)) return checkArray(value); 16 | if (value instanceof Object) return checkObject(value); 17 | } 18 | function checkArray(array) { 19 | if (seen.indexOf(array) >= 0) return; 20 | seen.push(array); 21 | // for (var i = array.length-1, l = 0; i >= l; i--) { 22 | for (let i = 0, l = array.length; i < l; i++) { 23 | checkValue(array[i]); 24 | } 25 | } 26 | function checkObject(obj) { 27 | if (seen.indexOf(obj) >= 0) return; 28 | seen.push(obj); 29 | const keys = Object.keys(obj); 30 | // for (var i = keys.length-1, l = 0; i >= l; i--) { 31 | for (let i = 0, l = keys.length; i < l; i++) { 32 | const key = keys[i]; 33 | all[append + key] = true; 34 | checkValue(obj[key]); 35 | } 36 | } 37 | }; 38 | 39 | this.mapRange = function (inVal, inMin, inMax, outMin, outMax) { 40 | var a = inMax - inMin; 41 | var b = outMax - outMin; 42 | let outVal = (inVal - inMin) / a * b + outMin; 43 | outVal = outVal > outMax ? outMax : outVal 44 | outVal = outVal < outMin ? outMin : outVal 45 | return outVal 46 | }; 47 | 48 | this.convertVec3ToLatLon = function (pos) { 49 | return [90 - (Math.acos(pos.y / 1835)) * 180 / Math.PI, 50 | ((270 + (Math.atan2(pos.x, pos.z)) * 180 / Math.PI) % 360)]; 51 | }; 52 | 53 | this.convertLatLonToVec3 = function (lat, lon) { 54 | lat = lat * Math.PI / 180.0; 55 | lon = -lon * Math.PI / 180.0; 56 | return new THREE.Vector3( 57 | Math.cos(lat) * Math.cos(lon), 58 | Math.sin(lat), 59 | Math.cos(lat) * Math.sin(lon), 60 | ); 61 | }; 62 | 63 | this.getTZ = function (lat, lon) { 64 | return CoordinateTZ.calculate(lat, lon).timezone; 65 | }; 66 | 67 | this.hexToRgb = function (hex) { 68 | let c; 69 | if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) { 70 | c = hex.substring(1).split(''); 71 | if (c.length == 3) { 72 | c = [c[0], c[0], c[1], c[1], c[2], c[2]]; 73 | } 74 | c = `0x${c.join('')}`; 75 | return [(c >> 16) & 255, (c >> 8) & 255, c & 255]; 76 | } 77 | throw new Error('Bad Hex'); 78 | }; 79 | 80 | this.capitalizeFirstLetter = function (string) { 81 | return string.charAt(0).toUpperCase() + string.slice(1); 82 | }; 83 | } 84 | 85 | const tempCommon = new Common(); 86 | module.exports = tempCommon; 87 | -------------------------------------------------------------------------------- /src/util/Loader.js: -------------------------------------------------------------------------------- 1 | require('three/examples/js/loaders/DDSLoader.js'); 2 | require('three/examples/js/loaders/MTLLoader.js'); 3 | require('three/examples/js/loaders/BVHLoader.js'); 4 | require('three/examples/js/loaders/FBXLoader.js'); 5 | require('three/examples/js/loaders/OBJLoader.js'); 6 | require('three/examples/js/loaders/ColladaLoader.js'); 7 | require('three/examples/js/loaders/GLTFLoader.js'); 8 | 9 | const sceneLoader = require('../libs/three/loaders/SceneLoader'); 10 | 11 | class Loader { 12 | constructor() { 13 | this.debug = false; 14 | } 15 | 16 | loadGLTF(url, props, cb) { 17 | new THREE.GLTFLoader().load(url, (result) => { cb(result, props); }, this.onError); 18 | } 19 | 20 | loadOBJ(url, props, cb) { 21 | let objLoader = new THREE.OBJLoader(new THREE.LoadingManager()); 22 | if (props.materials) { 23 | objLoader.setMaterials(props.materials); 24 | } 25 | objLoader.load(url, (result) => { cb(result, props); }, this.onProgress, this.onError); 26 | } 27 | 28 | loadBVH(url, cb) { 29 | new THREE.BVHLoader().load(url, cb, this.onProgress, this.onError); 30 | } 31 | 32 | loadFBX(url, props, callback) { 33 | new THREE.FBXLoader(new THREE.LoadingManager()).load(url, (result) => { cb(result, props); }, this.onProgress, this.onError); 34 | } 35 | 36 | loadCollada(url, props, cb) { 37 | new THREE.ColladaLoader().load(url, (result) => { cb(result, props); }, this.onProgress, this.onError); 38 | } 39 | 40 | loadScene(url, props, cb) { 41 | new THREE.SceneLoader().load(url, (result) => { cb(result, props); }, this.onProgress, this.onError); 42 | } 43 | 44 | loadImage(url, cb) { 45 | new THREE.ImageLoader().load(url, cb, this.onProgress, this.onError); 46 | } 47 | 48 | loadTexture(url, props, cb) { 49 | new THREE.TextureLoader().load(url, (result) => { cb(result, props); }, this.onProgress, this.onError); 50 | } 51 | 52 | loadMTL(url, cb) { 53 | THREE.Loader.Handlers.add(/\.dds$/i, new THREE.DDSLoader()); 54 | new THREE.MTLLoader().load(url, cb, this.onProgress, this.onError); 55 | } 56 | 57 | onProgress(xhr) { 58 | if (xhr.lengthComputable && this.debug) { 59 | const percentComplete = (xhr.loaded / xhr.total) * 100; 60 | console.log(Math.round(percentComplete, 2) + '% downloaded'); 61 | } 62 | } 63 | 64 | onError(err) { 65 | if (this.debug) { 66 | console.error('An error happened.'); 67 | } 68 | } 69 | } 70 | 71 | module.exports = Loader; -------------------------------------------------------------------------------- /src/util/Logger.js: -------------------------------------------------------------------------------- 1 | 2 | class Logger { 3 | constructor() { 4 | // stop Chrome from ruining things and crashing the socket server 5 | window.addEventListener('beforeunload', () => { 6 | this.websocket.close(); 7 | }); 8 | } 9 | 10 | onOpen(name, evt) { 11 | console.log(name + ' socket connected:', evt); 12 | } 13 | 14 | onClose(name, evt) { 15 | console.log(name + ' socket disconnected:', evt); 16 | } 17 | 18 | onError(name, evt) { 19 | console.log(name + ' socket error:', evt); 20 | } 21 | } 22 | 23 | module.exports = Logger; -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | describe('Array', function() { 3 | describe('#indexOf()', function() { 4 | it('should return -1 when the value is not present', function() { 5 | assert.equal([1,2,3].indexOf(4), -1); 6 | }); 7 | }); 8 | }); -------------------------------------------------------------------------------- /webpack-gh-pages.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const { resolve } = require('path'); 3 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | const WebappWebpackPlugin = require('webapp-webpack-plugin'); 5 | const HtmlWebpackPlugin = require('html-webpack-plugin') 6 | 7 | const config = require('./server/config'); 8 | 9 | module.exports = { 10 | mode: 'production', 11 | context: resolve(__dirname, 'src'), 12 | entry: [ 13 | './index.jsx', 14 | // the entry point of our app 15 | ], 16 | output: { 17 | // the output bundle 18 | filename: 'bundle.js', 19 | 20 | publicPath: './', 21 | 22 | path: resolve(__dirname, 'dist/'), 23 | }, 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.(js|jsx)$/, 28 | exclude: /(node_modules|bower_components)/, 29 | use: { 30 | loader: 'babel-loader', 31 | options: { 32 | presets: ['env'], 33 | }, 34 | }, 35 | }, 36 | { 37 | test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, 38 | loader: 'url-loader?name=/fonts/[name].[ext]', 39 | }, 40 | { 41 | test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, 42 | loader: 'file-loader?name=/fonts/[name].[ext]', 43 | }, 44 | { 45 | test: /\.css$/, 46 | loader: 'style-loader', 47 | }, { 48 | test: /\.css$/, 49 | loader: 'css-loader', 50 | }, 51 | { 52 | test: /\.(jpe?g|gif|svg)$/i, 53 | use: [ 54 | 'img-loader?name=images/[name].[ext]', 55 | 'url-loader?name=images/[name].[ext]&limit=10000', 56 | ], 57 | }, 58 | { 59 | test: /\.(png)$/i, 60 | use: [ 61 | 'base64-image-loader', 62 | ], 63 | }, 64 | { 65 | test: /\.glsl$/, 66 | loader: 'webpack-glsl-loader', 67 | }, 68 | ], 69 | }, 70 | resolve: { 71 | extensions: ['.js', '.jsx', '.css'], 72 | }, 73 | plugins: [ 74 | new CopyWebpackPlugin([ 75 | { 76 | from: resolve(__dirname, config.copy.all.src), 77 | to: resolve(__dirname, 'dist/'), 78 | }, 79 | ]), 80 | new WebappWebpackPlugin(resolve(__dirname, './src/static/images/op_logo.png')), 81 | new HtmlWebpackPlugin({ 82 | title: 'Open Perform by Kinetech Arts', 83 | template: resolve(__dirname, './src/html/index.html'), 84 | }), 85 | new webpack.ProvidePlugin({ 86 | $: 'jquery', 87 | jQuery: 'jquery', 88 | 'window.jQuery': 'jquery', 89 | THREE: 'three', 90 | 'window.THREE': 'three', 91 | TWEEN: 'tween.js', 92 | 'window.TWEEN': 'tween.js', 93 | React: 'react', 94 | _: 'lodash', 95 | }), 96 | ], 97 | }; 98 | -------------------------------------------------------------------------------- /webpack-production.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const { resolve } = require('path'); 3 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | const WebappWebpackPlugin = require('webapp-webpack-plugin'); 5 | const HtmlWebpackPlugin = require('html-webpack-plugin') 6 | 7 | const config = require('./server/config'); 8 | 9 | module.exports = { 10 | mode: 'production', 11 | context: resolve(__dirname, 'src'), 12 | entry: [ 13 | './index.jsx', 14 | // the entry point of our app 15 | ], 16 | output: { 17 | // the output bundle 18 | filename: 'bundle.js', 19 | 20 | publicPath: './', 21 | 22 | path: resolve(__dirname, 'dist/'), 23 | }, 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.(js|jsx)$/, 28 | exclude: /(node_modules|bower_components)/, 29 | use: { 30 | loader: 'babel-loader', 31 | options: { 32 | presets: ['env'], 33 | }, 34 | }, 35 | }, 36 | { 37 | test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, 38 | loader: 'url-loader?name=/fonts/[name].[ext]', 39 | }, 40 | { 41 | test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, 42 | loader: 'file-loader?name=/fonts/[name].[ext]', 43 | }, 44 | { 45 | test: /\.css$/, 46 | loader: 'style-loader', 47 | }, { 48 | test: /\.css$/, 49 | loader: 'css-loader', 50 | }, 51 | { 52 | test: /\.(jpe?g|gif|svg)$/i, 53 | use: [ 54 | 'img-loader?name=images/[name].[ext]', 55 | 'url-loader?name=images/[name].[ext]&limit=10000', 56 | ], 57 | }, 58 | { 59 | test: /\.(png)$/i, 60 | use: [ 61 | 'base64-image-loader', 62 | ], 63 | }, 64 | { 65 | test: /\.glsl$/, 66 | loader: 'webpack-glsl-loader', 67 | }, 68 | ], 69 | }, 70 | resolve: { 71 | extensions: ['.js', '.jsx', '.css'], 72 | }, 73 | plugins: [ 74 | new CopyWebpackPlugin([ 75 | { 76 | from: resolve(__dirname, config.copy.all.src), 77 | to: resolve(__dirname, 'dist/'), 78 | }, 79 | ]), 80 | new WebappWebpackPlugin(resolve(__dirname, './src/static/images/op_logo.png')), 81 | new HtmlWebpackPlugin({ 82 | title: 'Open Perform by Kinetech Arts', 83 | template: resolve(__dirname, './src/html/index.html'), 84 | }), 85 | new webpack.ProvidePlugin({ 86 | $: 'jquery', 87 | jQuery: 'jquery', 88 | 'window.jQuery': 'jquery', 89 | THREE: 'three', 90 | 'window.THREE': 'three', 91 | TWEEN: 'tween.js', 92 | 'window.TWEEN': 'tween.js', 93 | React: 'react', 94 | _: 'lodash', 95 | }), 96 | ], 97 | }; 98 | --------------------------------------------------------------------------------