├── tests └── unit │ ├── .eslintrc.js │ └── Object3D.spec.js ├── examples ├── water.jpg ├── Cube.vue ├── main.js ├── gui.js ├── Ocean.vue ├── App.vue └── SF03.vue ├── public ├── favicon.ico ├── static │ ├── Project_Utopia.ogg │ ├── textures │ │ ├── diamond.png │ │ ├── redwool.png │ │ └── cobblestone.png │ └── threex │ │ └── spaceships │ │ ├── F03_512.jpg │ │ ├── lensflare0_alpha.png │ │ ├── SpaceFighter03.mtl │ │ ├── LICENSE │ │ └── SpaceFighter03.obj └── index.html ├── babel.config.js ├── .editorconfig ├── src ├── mesh │ ├── Mesh.vue │ ├── Geometry.vue │ ├── Material.vue │ ├── MObjMtl.vue │ └── Texture.vue ├── components │ ├── Light.vue │ ├── AudioListener.vue │ ├── Camera.vue │ ├── Base.vue │ ├── Scene.vue │ ├── OrbitControls.vue │ ├── Animation.vue │ ├── PositionalAudio.vue │ ├── Renderer.vue │ └── Object3D.vue ├── oimo │ ├── SpaceObject.vue │ ├── OimoWorld.vue │ ├── OimoBody.vue │ └── SpaceSystem.vue ├── util.js ├── dat │ └── DatGui.vue ├── index.js ├── physics │ ├── MovementObject.vue │ ├── MassObject.vue │ └── MovementSystem.vue └── threex │ ├── loaders │ ├── MTLLoader.js │ └── OBJLoader.js │ └── controls │ └── OrbitControls.js ├── .gitignore ├── .npmignore ├── jest.config.js ├── LICENSE ├── vue.config.js ├── package.json └── README.md /tests/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true 4 | } 5 | } -------------------------------------------------------------------------------- /examples/water.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fritx/vue-threejs/HEAD/examples/water.jpg -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fritx/vue-threejs/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/static/Project_Utopia.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fritx/vue-threejs/HEAD/public/static/Project_Utopia.ogg -------------------------------------------------------------------------------- /public/static/textures/diamond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fritx/vue-threejs/HEAD/public/static/textures/diamond.png -------------------------------------------------------------------------------- /public/static/textures/redwool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fritx/vue-threejs/HEAD/public/static/textures/redwool.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@vue/app', { 4 | modules: 'commonjs' 5 | }] 6 | ] 7 | } -------------------------------------------------------------------------------- /public/static/textures/cobblestone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fritx/vue-threejs/HEAD/public/static/textures/cobblestone.png -------------------------------------------------------------------------------- /public/static/threex/spaceships/F03_512.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fritx/vue-threejs/HEAD/public/static/threex/spaceships/F03_512.jpg -------------------------------------------------------------------------------- /public/static/threex/spaceships/lensflare0_alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fritx/vue-threejs/HEAD/public/static/threex/spaceships/lensflare0_alpha.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /src/mesh/Mesh.vue: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | 23 | package-lock.json 24 | /lib 25 | /package 26 | /package * 27 | *.tgz 28 | -------------------------------------------------------------------------------- /public/static/threex/spaceships/SpaceFighter03.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | newmtl VMtl01.002_F03_512.JPG 4 | Ns 96.078431 5 | Ka 0.000000 0.000000 0.000000 6 | Kd 0.398431 0.398431 0.398431 7 | Ks 0.000000 0.000000 0.000000 8 | Ni 1.000000 9 | d 1.000000 10 | illum 2 11 | #map_Kd Free-game-models-collection/spaceships/SpaceFighter03/F03_512.JPG 12 | map_Kd F03_512.jpg 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/Cube.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 19 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | 23 | package-lock.json 24 | # /lib 25 | /package 26 | /package * 27 | *.tgz 28 | 29 | /examples 30 | /src 31 | /test 32 | /public 33 | /.editorconfig 34 | /*.config.js 35 | -------------------------------------------------------------------------------- /src/components/Light.vue: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /src/components/AudioListener.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 22 | -------------------------------------------------------------------------------- /examples/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | 6 | // import * as VueThreejs from '@/../package/lib/VueThreejs.common' // testing pack 7 | // import * as VueThreejs from '@/../lib/VueThreejs.common' // testing build 8 | import * as VueThreejs from '@' 9 | // import VueThreejs from '@' 10 | Vue.use(VueThreejs) 11 | 12 | Vue.config.productionTip = false 13 | 14 | new Vue({ 15 | render: h => h(App), 16 | }).$mount('#app') 17 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: [ 3 | 'js', 4 | 'jsx', 5 | 'json', 6 | 'vue' 7 | ], 8 | transform: { 9 | '^.+\\.vue$': 'vue-jest', 10 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub', 11 | '^.+\\.jsx?$': 'babel-jest' 12 | }, 13 | moduleNameMapper: { 14 | '^@/(.*)$': '/src/$1' 15 | }, 16 | snapshotSerializers: [ 17 | 'jest-serializer-vue' 18 | ], 19 | testMatch: [ 20 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' 21 | ], 22 | testURL: 'http://localhost/' 23 | } 24 | -------------------------------------------------------------------------------- /src/oimo/SpaceObject.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 32 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | vue-threejs 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/mesh/Geometry.vue: -------------------------------------------------------------------------------- 1 | 29 | -------------------------------------------------------------------------------- /src/components/Camera.vue: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | import { Vector3 } from 'three' 2 | 3 | // for simplicity 4 | // using plain object `{ x, y, z }` to describe vector 5 | // instead of class Vector3 6 | let $vec = { 7 | multiplyScalar (v, s) { 8 | v = this.toVector3(v) 9 | v.multiplyScalar(s) 10 | return this.toPlainObj(v) 11 | }, 12 | 13 | add (v1, v2) { 14 | v1 = this.toVector3(v1) 15 | v2 = this.toVector3(v2) 16 | let v = v1.add(v2) 17 | return this.toPlainObj(v) 18 | }, 19 | 20 | toVector3 (v) { 21 | v = v || {} 22 | return new Vector3(v.x, v.y, v.z) 23 | }, 24 | 25 | toPlainObj (v) { 26 | let { x, y, z } = v 27 | return { x, y, z } 28 | } 29 | } 30 | 31 | export { $vec } 32 | -------------------------------------------------------------------------------- /src/oimo/OimoWorld.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 39 | -------------------------------------------------------------------------------- /src/dat/DatGui.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 29 | 30 | 33 | 34 | 37 | -------------------------------------------------------------------------------- /examples/gui.js: -------------------------------------------------------------------------------- 1 | export function getModel () { 2 | let ui = { 3 | camera: { 4 | x: 9, y: 21, z: 20 5 | }, 6 | ocean: { 7 | y: -200 8 | }, 9 | sf03: { 10 | scale: 1 11 | }, 12 | sysKey: 0, 13 | replay: () => { 14 | ui.sysKey += 1 15 | } 16 | } 17 | return ui 18 | } 19 | 20 | export function setupPanel (gui, ui) { 21 | let fc = gui.addFolder('Camera') 22 | fc.add(ui.camera, 'x', -50, 50).step(0.01) 23 | fc.add(ui.camera, 'y', -50, 50).step(0.01) 24 | fc.add(ui.camera, 'z', -50, 50).step(0.01) 25 | fc.open() 26 | 27 | let fo = gui.addFolder('Ocean') 28 | fo.add(ui.ocean, 'y', -250, 10).step(0.01) 29 | fo.open() 30 | 31 | let fs = gui.addFolder('SF03') 32 | fs.add(ui.sf03, 'scale', 0.1, 7).step(0.01) 33 | fs.open() 34 | gui.add(ui, 'replay') 35 | } 36 | -------------------------------------------------------------------------------- /src/oimo/OimoBody.vue: -------------------------------------------------------------------------------- 1 | 35 | -------------------------------------------------------------------------------- /src/mesh/Material.vue: -------------------------------------------------------------------------------- 1 | 34 | -------------------------------------------------------------------------------- /src/components/Base.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 38 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | let vueComs = {} 2 | 3 | let vueContext = require.context('./', true, /\.vue$/) 4 | vueContext.keys().forEach(path => { 5 | let com = vueContext(path).default 6 | vueComs[com.name] = com 7 | exports[com.name] = com 8 | }) 9 | 10 | let loaderContext = require.context('./threex/loaders', false, /\.js$/) 11 | loaderContext.keys().forEach(path => { 12 | let com = loaderContext(path).default 13 | // fix: uglify would kill the function name 14 | let name = path.match(/([^/]+)\.js$/)[1] 15 | exports[name] = com 16 | }) 17 | 18 | exports.install = Vue => { 19 | Object.keys(vueComs).forEach(k => { 20 | // fix: name 'object3d' is required, 21 | // or it would be parsed to 'object-3-d' somewhere else 22 | let rk 23 | if (k === 'Object3D') rk = 'object3d' 24 | if (rk) Vue.component(rk, vueComs[k]) 25 | Vue.component(k, vueComs[k]) 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /src/physics/MovementObject.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 42 | -------------------------------------------------------------------------------- /src/components/Scene.vue: -------------------------------------------------------------------------------- 1 | 37 | -------------------------------------------------------------------------------- /src/physics/MassObject.vue: -------------------------------------------------------------------------------- 1 | 43 | -------------------------------------------------------------------------------- /tests/unit/Object3D.spec.js: -------------------------------------------------------------------------------- 1 | import { shallowMount } from '@vue/test-utils' 2 | import Object3D from '@/components/Object3D' 3 | 4 | describe('Object3D.vue', () => { 5 | ['position', 'rotation'].forEach(k => { 6 | describe(`#${k}`, () => { 7 | it('should init by default', () => { 8 | const wrapper = shallowMount(Object3D) 9 | expect(wrapper.vm.curObj[k]) 10 | .toMatchObject({ x: 0, y: 0, z: 0 }) 11 | }) 12 | 13 | it('should init via props', () => { 14 | const wrapper = shallowMount(Object3D, { 15 | propsData: { [k]: { y: 3, z: -5 } } 16 | }) 17 | expect(wrapper.vm.curObj[k]) 18 | .toMatchObject({ x: 0, y: 3, z: -5 }) 19 | }) 20 | 21 | it('should watch props', () => { 22 | const wrapper = shallowMount(Object3D) 23 | wrapper.setProps({ [k]: { x: -7 } }) 24 | setTimeout(() => { 25 | expect(wrapper.vm.curObj[k]) 26 | .toMatchObject({ x: -7, y: 0, z: 0 }) 27 | }) 28 | }) 29 | }) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /src/mesh/MObjMtl.vue: -------------------------------------------------------------------------------- 1 | 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Fritz Lin 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /src/physics/MovementSystem.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 46 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | let isLib = process.env.TARGET === 'lib' 2 | 3 | module.exports = { 4 | css: { 5 | extract: !isLib 6 | }, 7 | chainWebpack: config => { 8 | if (isLib) { 9 | // https://github.com/vuejs/vue-cli/issues/2646 10 | config.merge({ 11 | externals: { 12 | vue: { 13 | commonjs: 'vue', 14 | commonjs2: 'vue', 15 | root: 'Vue', 16 | }, 17 | three: { 18 | commonjs: 'three', 19 | commonjs2: 'three', 20 | root: 'THREE', 21 | }, 22 | 'dat.gui': { 23 | commonjs: 'dat.gui', 24 | commonjs2: 'dat.gui', 25 | // https://github.com/dataarts/dat.gui/blob/1b18f7227e56c8b5071337732342101501b9fa95/rollup.config.js#L30 26 | root: 'dat', 27 | }, 28 | oimo: { 29 | commonjs: 'oimo', 30 | commonjs2: 'oimo', 31 | // https://github.com/lo-th/Oimo.js/blob/0ce1c3d8ff3f857d9180035076a70d8d6976a3e6/rollup.config.js#L7 32 | root: 'OIMO', 33 | }, 34 | } 35 | }) 36 | } 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /public/static/threex/spaceships/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jerome Etienne 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/components/OrbitControls.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 51 | -------------------------------------------------------------------------------- /src/components/Animation.vue: -------------------------------------------------------------------------------- 1 | 65 | -------------------------------------------------------------------------------- /src/mesh/Texture.vue: -------------------------------------------------------------------------------- 1 | 57 | -------------------------------------------------------------------------------- /src/components/PositionalAudio.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 59 | -------------------------------------------------------------------------------- /src/components/Renderer.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 62 | -------------------------------------------------------------------------------- /examples/Ocean.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 55 | -------------------------------------------------------------------------------- /src/oimo/SpaceSystem.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-threejs", 3 | "version": "0.2.0-alpha.1", 4 | "description": "Three.js bindings for Vue", 5 | "author": "Fritz Lin ", 6 | "repository": "https://github.com/fritx/vue-threejs", 7 | "license": "MIT", 8 | "main": "./lib/VueThreejs.common.js", 9 | "unpkg": "./lib/VueThreejs.umd.min.js", 10 | "scripts": { 11 | "demo:deploy": "gh-pages -d dist", 12 | "demo:dev": "vue-cli-service serve ./examples/main.js", 13 | "demo:build": "vue-cli-service build ./examples/main.js", 14 | "build": "cross-env TARGET=lib vue-cli-service build ./src/index.js --target=lib --dest=lib --name=VueThreejs", 15 | "test:unit": "vue-cli-service test:unit", 16 | "test": "npm run test:unit", 17 | "lint": "vue-cli-service lint" 18 | }, 19 | "peerDependencies": { 20 | "three": ">=0.81.2", 21 | "vue": ">=2.0.3" 22 | }, 23 | "devDependencies": { 24 | "@vue/cli-plugin-babel": "^3.3.0", 25 | "@vue/cli-plugin-eslint": "^3.3.0", 26 | "@vue/cli-plugin-unit-jest": "^3.4.0", 27 | "@vue/cli-service": "^3.3.0", 28 | "@vue/test-utils": "^1.0.0-beta.20", 29 | "babel-core": "7.0.0-bridge.0", 30 | "babel-eslint": "^10.0.1", 31 | "babel-jest": "^23.6.0", 32 | "cross-env": "^4.0.0", 33 | "dat.gui": "^0.7.5", 34 | "eslint": "^5.8.0", 35 | "eslint-plugin-vue": "^5.0.0", 36 | "gh-pages": "^3.1.0", 37 | "oimo": "^1.0.9", 38 | "three": "^0.86.0", 39 | "vue": "^2.4.4", 40 | "vue-template-compiler": "^2.4.4" 41 | }, 42 | "eslintConfig": { 43 | "root": true, 44 | "env": { 45 | "node": true 46 | }, 47 | "extends": [ 48 | "plugin:vue/essential", 49 | "eslint:recommended" 50 | ], 51 | "rules": {}, 52 | "parserOptions": { 53 | "parser": "babel-eslint" 54 | } 55 | }, 56 | "postcss": { 57 | "plugins": { 58 | "autoprefixer": {} 59 | } 60 | }, 61 | "browserslist": [ 62 | "> 1%", 63 | "last 2 versions", 64 | "not ie <= 8" 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /examples/App.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 85 | 86 | 89 | -------------------------------------------------------------------------------- /src/components/Object3D.vue: -------------------------------------------------------------------------------- 1 | 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-threejs 2 | 3 | 4 | 5 | > \[WIP\] [Three.js][threejs] bindings for [Vue][vue] 6 | 7 | Migrated from [react-threejs][react-threejs] 8 | 9 | Demos: [react-world][react-world], [vue-world][vue-world] 10 | 11 | 12 | 13 | ```js 14 | // import VueThreejs from 'vue-threejs' // below 0.2.0 15 | import * as VueThreejs from 'vue-threejs' // >= 0.2.0 16 | 17 | Vue.use(VueThreejs) 18 | ``` 19 | 20 | ```vue 21 | 30 | ``` 31 | 32 | **Physics** 33 | 34 | ```vue 35 | 36 | 38 | 39 | 40 | 42 | 43 | 44 | 45 | ``` 46 | 47 | ```vue 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | ``` 58 | 59 | **Roadmap** 60 | 61 | - [x] Basic components 62 | - [x] renderer/scene/camera/listener 63 | - [x] object3d/light/audio/controls/animation 64 | - [x] mesh/geometry/material/texture/obj-mtl 65 | - [ ] Watch for props change 66 | - [x] position/rotation/obj 67 | - [ ] more 68 | - [ ] Animation 69 | - [x] component/animate/speed/paused/blocked 70 | - [ ] global-control 71 | - [ ] Physical engine 72 | - [x] movement(a/v/pos/ra/rv/rot)/mass(m/F) 73 | - [x] gravity(G/r)/collision/oimo 74 | - [ ] circular-motion/centripetal-force 75 | - [ ] Unit test 76 | - [x] karma/mocha/phantom 77 | - [ ] avoriaz/ava 78 | 79 | **Study Notes** 80 | 81 | - [VueJS extend component: remove parent's property](https://stackoverflow.com/questions/45680047/vuejs-extend-component-remove-parents-property) 82 | - [Vue2 migration commits of vue-threejs](https://github.com/fritx/vue-threejs/commits/vue2) 83 | - `cannot use as root element` 84 | - `lifecycle ready => mounted` 85 | - `template or render function not defined` 86 | - `avoid mutating a prop directly` 87 | - `this.$dispatch is not a function` 88 | - [v-ref is not working with