├── .env ├── .gitignore ├── .idea ├── dictionaries │ ├── jmarinacci.xml │ └── josh.xml ├── encodings.xml ├── general-editor.iml ├── inspectionProfiles │ └── Project_Default.xml ├── markdown-exported-files.xml ├── markdown-navigator.xml ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── .travis.yml ├── README.md ├── build ├── .env ├── Cesium.js ├── asset-manifest.json ├── draco │ ├── draco_decoder.js │ ├── draco_decoder.wasm │ └── draco_wasm_wrapper.js ├── favicon.ico ├── icon.png ├── index.html ├── manifest.json ├── precache-manifest.5fbd345512572e93f9d3988bcd79790a.js ├── scripts │ └── hit.js ├── service-worker.js ├── static │ ├── css │ │ ├── 1.4e907ffd.chunk.css │ │ ├── 1.4e907ffd.chunk.css.map │ │ ├── main.00c346a3.chunk.css │ │ └── main.00c346a3.chunk.css.map │ ├── js │ │ ├── 1.d63e4f82.chunk.js │ │ ├── 1.d63e4f82.chunk.js.map │ │ ├── main.3fa218bd.chunk.js │ │ ├── main.3fa218bd.chunk.js.map │ │ ├── runtime~main.4a686d48.js │ │ └── runtime~main.4a686d48.js.map │ └── media │ │ ├── fa-brands-400.03783c51.eot │ │ ├── fa-brands-400.073c2f3c.svg │ │ ├── fa-brands-400.7559b377.woff2 │ │ ├── fa-brands-400.ed2b8bf1.ttf │ │ ├── fa-brands-400.fe9d62e0.woff │ │ ├── fa-regular-400.59215032.ttf │ │ ├── fa-regular-400.8fdea4e8.svg │ │ ├── fa-regular-400.e07d9e40.woff2 │ │ ├── fa-regular-400.e5770f98.woff │ │ ├── fa-regular-400.fc9c63c8.eot │ │ ├── fa-solid-900.4bced7c4.woff │ │ ├── fa-solid-900.acf50f59.ttf │ │ ├── fa-solid-900.b557f56e.svg │ │ ├── fa-solid-900.b5cf8ae2.woff2 │ │ ├── fa-solid-900.ef3df984.eot │ │ └── startup-sound.8786b4e1.m4a ├── webxr-geospatial-min.js ├── webxr-geospatial.js ├── webxr-min.js └── webxr.js ├── embedtest.html ├── package-lock.json ├── package.json ├── public ├── .env ├── Cesium.js ├── draco │ ├── draco_decoder.js │ ├── draco_decoder.wasm │ └── draco_wasm_wrapper.js ├── favicon.ico ├── icon.png ├── index.html ├── manifest.json ├── scripts │ └── hit.js ├── webxr-geospatial-min.js ├── webxr-geospatial.js ├── webxr-min.js └── webxr.js └── src ├── App.css ├── App.js ├── App.test.js ├── api.md ├── docserver.js ├── exports.js ├── index.css ├── index.js ├── metadoc ├── AssetView.js ├── CircleDef.js ├── Common.js ├── Dimension.js ├── Editor1.js ├── EventCoalescer.js ├── ImageDef.js ├── MetadocCanvas.js ├── PageCanvasView.js ├── PresentationApp.js ├── RectDef.js └── TextDef.js ├── syncgraph ├── GraphAccessor.js ├── MissingDocDialog.js ├── PubnubSyncWrapper.js ├── SyncGraphProvider.js ├── UndoQueue.js └── utils.js └── vr ├── 3dof.js ├── Actions.js ├── AssetActions.js ├── AssetsManager.js ├── AuthModule.js ├── Common.js ├── Common.test.js ├── ConsoleView.js ├── DRACOLoader.js ├── EditorCameraControls.js ├── ErrorCatcher.js ├── GLTFAssetView.js ├── GLTFLoader.js ├── GeoAssetView.js ├── GifSupport.js ├── ImmersivePlayer.js ├── ImmersiveVREditor.js ├── OrbitControls.js ├── ScriptEditor.js ├── ScriptManager.js ├── SkeletonUtils.js ├── Templates.js ├── ToasterManager.js ├── ToasterNotification.js ├── TransformControls.js ├── TranslateControl.js ├── TranslationArrow.js ├── VRCanvas.js ├── VREditor.css ├── VREditor.js ├── VREmbedViewApp.js ├── XRSupport.js ├── XRWorldInfo.js ├── console.css ├── cycle.js ├── defs ├── BG360Def.js ├── CloneDef.js ├── CubeDef.js ├── GPUParticles.js ├── GeoAnchorDef.js ├── GroupDef.js ├── HudAnchorDef.js ├── Image2DDef.js ├── ImageAnchorDef.js ├── LocalAnchorDef.js ├── ModelDef.js ├── ObjectDef.js ├── ParticlesDef.js ├── PlaneDef.js ├── PortalDef.js ├── SceneDef.js ├── SphereDef.js └── TextDef.js ├── dialogs ├── AddAudioAssetDialog.js ├── AddGLBAssetDialog.js ├── AddGLTFAssetDialog.js ├── AddImageAssetDialog.js ├── BadAssetsDialog.js ├── GithubAuthDialog.js ├── MakeEmbedDialog.js ├── OpenAssetDialog.js ├── OpenFileDialog.js ├── OpenScriptDialog.js ├── PasswordDialog.js ├── QRDialog.js ├── SaveDocumentAsDialog.js ├── SimpleMessageDialog.js └── UnsavedDocumentDialog.js ├── panel2d ├── button2d.js ├── component2d.js ├── group2d.js ├── label2d.js ├── panel2d.js ├── togglebutton2d.js └── togglegroup2d.js ├── setupTests.js ├── startup-sound.m4a └── tween.js /.env: -------------------------------------------------------------------------------- 1 | PASSWORD=password 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /es 6 | /lib 7 | 8 | # testing 9 | /coverage 10 | 11 | # want the production to live in the repo so it's accessible from there 12 | # /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | docs/ 25 | -------------------------------------------------------------------------------- /.idea/dictionaries/jmarinacci.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | realworld 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/dictionaries/josh.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | clss 5 | gltf 6 | hypercard 7 | immersive 8 | unmount 9 | wireframe 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/general-editor.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /.idea/markdown-exported-files.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | "11" 4 | script: 5 | npm run build 6 | npm test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MrEd : the Mixed Reality Editor 2 | 3 | This is the source to a visual editor for mixed reality. It is built in react 4 | and should be compiled and put on a webserver before using. 5 | 6 | You may want to start by trying a [live demo on Glitch here](https://mred-demo.glitch.me/). To go further you'll want to remix the [glitch itself](https://glitch.com/~mred-demo) and edit the ".env" file and set a password. Then make sure you login with that password inside of MrEd (when running your remix of the glitch). 7 | -------------------------------------------------------------------------------- /build/.env: -------------------------------------------------------------------------------- 1 | password=secret 2 | -------------------------------------------------------------------------------- /build/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "main.css": "./static/css/main.00c346a3.chunk.css", 3 | "main.js": "./static/js/main.3fa218bd.chunk.js", 4 | "main.js.map": "./static/js/main.3fa218bd.chunk.js.map", 5 | "static/css/1.4e907ffd.chunk.css": "./static/css/1.4e907ffd.chunk.css", 6 | "static/js/1.d63e4f82.chunk.js": "./static/js/1.d63e4f82.chunk.js", 7 | "static/js/1.d63e4f82.chunk.js.map": "./static/js/1.d63e4f82.chunk.js.map", 8 | "runtime~main.js": "./static/js/runtime~main.4a686d48.js", 9 | "runtime~main.js.map": "./static/js/runtime~main.4a686d48.js.map", 10 | "static/media/startup-sound.m4a": "./static/media/startup-sound.8786b4e1.m4a", 11 | "static/media/all.css": "./static/media/fa-solid-900.b557f56e.svg", 12 | "static/css/main.00c346a3.chunk.css.map": "./static/css/main.00c346a3.chunk.css.map", 13 | "static/css/1.4e907ffd.chunk.css.map": "./static/css/1.4e907ffd.chunk.css.map", 14 | "index.html": "./index.html", 15 | "precache-manifest.5fbd345512572e93f9d3988bcd79790a.js": "./precache-manifest.5fbd345512572e93f9d3988bcd79790a.js", 16 | "service-worker.js": "./service-worker.js" 17 | } -------------------------------------------------------------------------------- /build/draco/draco_decoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MozillaReality/mred/a91654c26c4c418ea7ef4f441609c51578124d66/build/draco/draco_decoder.wasm -------------------------------------------------------------------------------- /build/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MozillaReality/mred/a91654c26c4c418ea7ef4f441609c51578124d66/build/favicon.ico -------------------------------------------------------------------------------- /build/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MozillaReality/mred/a91654c26c4c418ea7ef4f441609c51578124d66/build/icon.png -------------------------------------------------------------------------------- /build/index.html: -------------------------------------------------------------------------------- 1 | The Mixed Reality Editor
-------------------------------------------------------------------------------- /build/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Mr. Ed", 3 | "name": "The Mixed Reality Editor", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /build/precache-manifest.5fbd345512572e93f9d3988bcd79790a.js: -------------------------------------------------------------------------------- 1 | self.__precacheManifest = [ 2 | { 3 | "revision": "3fa218bd21bf5be85a76", 4 | "url": "./static/css/main.00c346a3.chunk.css" 5 | }, 6 | { 7 | "revision": "3fa218bd21bf5be85a76", 8 | "url": "./static/js/main.3fa218bd.chunk.js" 9 | }, 10 | { 11 | "revision": "d63e4f828b6a0568df7a", 12 | "url": "./static/css/1.4e907ffd.chunk.css" 13 | }, 14 | { 15 | "revision": "d63e4f828b6a0568df7a", 16 | "url": "./static/js/1.d63e4f82.chunk.js" 17 | }, 18 | { 19 | "revision": "4a686d48d5a089750c49", 20 | "url": "./static/js/runtime~main.4a686d48.js" 21 | }, 22 | { 23 | "revision": "8786b4e19fb0a0782a336f445cc6584f", 24 | "url": "./static/media/startup-sound.8786b4e1.m4a" 25 | }, 26 | { 27 | "revision": "7559b3774a0625e8ca6c0160f8f6cfd8", 28 | "url": "./static/media/fa-brands-400.7559b377.woff2" 29 | }, 30 | { 31 | "revision": "03783c5172ee1ad128c576bf88fac168", 32 | "url": "./static/media/fa-brands-400.03783c51.eot" 33 | }, 34 | { 35 | "revision": "fe9d62e0d16a333a20e63c3e7595f82e", 36 | "url": "./static/media/fa-brands-400.fe9d62e0.woff" 37 | }, 38 | { 39 | "revision": "ed2b8bf117160466ba6220a8f1da54a4", 40 | "url": "./static/media/fa-brands-400.ed2b8bf1.ttf" 41 | }, 42 | { 43 | "revision": "fc9c63c8224fb341fc933641cbdd12ef", 44 | "url": "./static/media/fa-regular-400.fc9c63c8.eot" 45 | }, 46 | { 47 | "revision": "e07d9e40b26048d9abe2ef966cd6e263", 48 | "url": "./static/media/fa-regular-400.e07d9e40.woff2" 49 | }, 50 | { 51 | "revision": "e5770f9863963fb576942e25214a226d", 52 | "url": "./static/media/fa-regular-400.e5770f98.woff" 53 | }, 54 | { 55 | "revision": "59215032a4397507b80e5625dc323de3", 56 | "url": "./static/media/fa-regular-400.59215032.ttf" 57 | }, 58 | { 59 | "revision": "8fdea4e89ac405d9f8db327adb331d8d", 60 | "url": "./static/media/fa-regular-400.8fdea4e8.svg" 61 | }, 62 | { 63 | "revision": "ef3df98419d143d9617fe163bf4edc0b", 64 | "url": "./static/media/fa-solid-900.ef3df984.eot" 65 | }, 66 | { 67 | "revision": "b5cf8ae26748570d8fb95a47f46b69e1", 68 | "url": "./static/media/fa-solid-900.b5cf8ae2.woff2" 69 | }, 70 | { 71 | "revision": "4bced7c4c0d61d4f988629bb8ae80b8b", 72 | "url": "./static/media/fa-solid-900.4bced7c4.woff" 73 | }, 74 | { 75 | "revision": "acf50f59802f20d8b45220eaae532a1c", 76 | "url": "./static/media/fa-solid-900.acf50f59.ttf" 77 | }, 78 | { 79 | "revision": "073c2f3ce60eaf69cc2767ef3d989078", 80 | "url": "./static/media/fa-brands-400.073c2f3c.svg" 81 | }, 82 | { 83 | "revision": "b557f56e367e59344ca95f9d1fb44352", 84 | "url": "./static/media/fa-solid-900.b557f56e.svg" 85 | }, 86 | { 87 | "revision": "25fb2036dd1d67f2371be8061fac1e87", 88 | "url": "./index.html" 89 | } 90 | ]; -------------------------------------------------------------------------------- /build/scripts/hit.js: -------------------------------------------------------------------------------- 1 | /* 2 | #title hittest 3 | #description xr hit test and place anchor 4 | */ 5 | ({ 6 | properties: { 7 | speed: { 8 | type:'number', 9 | value: 1, 10 | } 11 | }, 12 | click: function(e) { 13 | alert(1) 14 | console.log(e) 15 | console.log(this) 16 | console.log(this.globals) 17 | // this.globals.getHitAnchorFromNormalizedScreenCoordinates(x,y).then( (anchor) => { 18 | }, 19 | }) 20 | 21 | 22 | -------------------------------------------------------------------------------- /build/service-worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your Workbox-powered service worker! 3 | * 4 | * You'll need to register this file in your web app and you should 5 | * disable HTTP caching for this file too. 6 | * See https://goo.gl/nhQhGp 7 | * 8 | * The rest of the code is auto-generated. Please don't update this file 9 | * directly; instead, make changes to your Workbox build configuration 10 | * and re-run your build process. 11 | * See https://goo.gl/2aRDsh 12 | */ 13 | 14 | importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js"); 15 | 16 | importScripts( 17 | "./precache-manifest.5fbd345512572e93f9d3988bcd79790a.js" 18 | ); 19 | 20 | workbox.clientsClaim(); 21 | 22 | /** 23 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to 24 | * requests for URLs in the manifest. 25 | * See https://goo.gl/S9QRab 26 | */ 27 | self.__precacheManifest = [].concat(self.__precacheManifest || []); 28 | workbox.precaching.suppressWarnings(); 29 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); 30 | 31 | workbox.routing.registerNavigationRoute("./index.html", { 32 | 33 | blacklist: [/^\/_/,/\/[^\/]+\.[^\/]+$/], 34 | }); 35 | -------------------------------------------------------------------------------- /build/static/css/main.00c346a3.chunk.css: -------------------------------------------------------------------------------- 1 | .console{display:flex;flex-direction:column}.console .message-log{overflow:scroll;flex:1.0 1;margin:0;list-style:none;padding-left:0}.console .message-log li{padding:.5rem}.console .message-log li b{border-radius:.5rem;padding:.25rem .5rem;margin:.25rem;font-size:90%}.console .message-log li b.log{background-color:#fafad2}.console .message-log li b.error{border:1px solid #ffb6c1;background-color:#ffb6c1}.console .message-log li b.location.local{background-color:#0ff}.console .message-log li b.location.remote{background-color:pink}.map-icon{border:5px solid red}#mapid{z-index:0} 2 | /*# sourceMappingURL=main.00c346a3.chunk.css.map */ -------------------------------------------------------------------------------- /build/static/css/main.00c346a3.chunk.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["/Users/jmarinacci/projects/general-editor/src/vr/console.css"],"names":[],"mappings":"AACA,SACI,aAAc,AACd,qBAAuB,CAC1B,AAED,sBACI,gBAAiB,AACjB,WAAU,AACV,SAAU,AACV,gBAAiB,AACjB,cAAgB,CACnB,AAED,yBACI,aAAuB,CAC1B,AAED,2BACI,oBAAsB,AACtB,qBAAwB,AACxB,cAAgB,AAChB,aAAe,CAClB,AAED,+BACI,wBAAuC,CAC1C,AACD,iCACI,yBAA4B,AAC5B,wBAA4B,CAC/B,AAED,0CACI,qBAAuB,CAC1B,AACD,2CACI,qBAAuB,CAC1B,AAMD,UACI,oBAAsB,CACzB,AACD,OACI,SAAW,CACd","file":"main.00c346a3.chunk.css","sourcesContent":["\n.console {\n display: flex;\n flex-direction: column;\n}\n\n.console .message-log {\n overflow: scroll;\n flex: 1.0;\n margin: 0;\n list-style: none;\n padding-left: 0;\n}\n\n.console .message-log li {\n padding: 0.5rem 0.5rem;\n}\n\n.console .message-log li b {\n border-radius: 0.5rem;\n padding: 0.25rem 0.5rem;\n margin: 0.25rem;\n font-size: 90%;\n}\n\n.console .message-log li b.log {\n background-color: lightgoldenrodyellow;\n}\n.console .message-log li b.error {\n border: 1px solid lightpink;\n background-color: lightpink;\n}\n\n.console .message-log li b.location.local {\n background-color: aqua;\n}\n.console .message-log li b.location.remote {\n background-color: pink;\n}\n\n\n\n\n\n.map-icon {\n border: 5px solid red;\n}\n#mapid {\n z-index: 0;\n}\n\n\n\n"]} -------------------------------------------------------------------------------- /build/static/js/runtime~main.4a686d48.js: -------------------------------------------------------------------------------- 1 | !function(e){function r(r){for(var n,f,i=r[0],l=r[1],a=r[2],c=0,s=[];c 2 | 3 | 4 | 5 | Title 6 | 12 | 13 | 14 | 15 |

Embedded VR scene

16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "general-editor", 3 | "version": "0.1.4", 4 | "private": false, 5 | "main": "lib/exports.js", 6 | "dependencies": { 7 | "appy-comps": "^0.1.18", 8 | "appy-style": "0.0.7", 9 | "caniuse-lite": "^1.0.30000976", 10 | "cors": "^2.8.4", 11 | "dagre": "^0.8.2", 12 | "gl-matrix": "^2.5.1", 13 | "hsluv": "0.0.1", 14 | "json-prune": "^1.1.0", 15 | "leaflet": "^1.5.1", 16 | "preval.macro": "^3.0.0", 17 | "pubnub": "^4.20.1", 18 | "qrcode": "^1.2.0", 19 | "react": "^16.8.6", 20 | "react-ace": "^6.5.0", 21 | "react-dom": "^16.8.6", 22 | "react-scripts": "2.0.3", 23 | "react-visual-editor-framework": "^1.0.9", 24 | "syncing_protocol": "0.0.11", 25 | "three": "^0.104.0", 26 | "three-gltf2-loader": "^1.2.0", 27 | "three-web-layer": "0.0.21", 28 | "util-inspect": "^0.1.8", 29 | "webxr-boilerplate": "^0.1.9" 30 | }, 31 | "scripts": { 32 | "start": "react-scripts start", 33 | "build": "react-scripts build", 34 | "test": "react-scripts test --env=jsdom", 35 | "eject": "react-scripts eject", 36 | "build-components": "nwb build-react-component" 37 | }, 38 | "browserslist": [ 39 | ">0.2%", 40 | "not dead", 41 | "not ie <= 11", 42 | "not op_mini all" 43 | ], 44 | "devDependencies": { 45 | "@fortawesome/fontawesome-free": "^5.9.0", 46 | "nwb": "^0.23.0" 47 | }, 48 | "homepage": "./", 49 | "jest": {} 50 | } 51 | -------------------------------------------------------------------------------- /public/.env: -------------------------------------------------------------------------------- 1 | password=secret 2 | -------------------------------------------------------------------------------- /public/draco/draco_decoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MozillaReality/mred/a91654c26c4c418ea7ef4f441609c51578124d66/public/draco/draco_decoder.wasm -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MozillaReality/mred/a91654c26c4c418ea7ef4f441609c51578124d66/public/favicon.ico -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MozillaReality/mred/a91654c26c4c418ea7ef4f441609c51578124d66/public/icon.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 27 | The Mixed Reality Editor 28 | 29 | 30 | 31 | 34 |
35 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Mr. Ed", 3 | "name": "The Mixed Reality Editor", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /public/scripts/hit.js: -------------------------------------------------------------------------------- 1 | /* 2 | #title hittest 3 | #description xr hit test and place anchor 4 | */ 5 | ({ 6 | properties: { 7 | speed: { 8 | type:'number', 9 | value: 1, 10 | } 11 | }, 12 | click: function(e) { 13 | alert(1) 14 | console.log(e) 15 | console.log(this) 16 | console.log(this.globals) 17 | // this.globals.getHitAnchorFromNormalizedScreenCoordinates(x,y).then( (anchor) => { 18 | }, 19 | }) 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | // import './App.css' 3 | import VREditor from './vr/VREditor' 4 | import {ImmersivePlayer} from './vr/ImmersivePlayer' 5 | import {PopupManagerContext} from 'appy-comps' 6 | import {AuthModule} from './vr/AuthModule' 7 | 8 | export default class App extends Component { 9 | getApp() { 10 | this.props.options.AuthModule = AuthModule 11 | if(this.props.options.mode === 'play') { 12 | return 13 | } 14 | this.provider = new VREditor(this.props.options) 15 | this.provider.popupManager = this.context 16 | return this.provider.getApp() 17 | } 18 | 19 | render() { 20 | return this.getApp() 21 | } 22 | } 23 | App.contextType = PopupManagerContext 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | const opts = {} 8 | ReactDOM.render(, div); 9 | }); 10 | -------------------------------------------------------------------------------- /src/api.md: -------------------------------------------------------------------------------- 1 | the lifecycle of a document: 2 | 3 | 4 | * connect to the doc server using AuthModule.init() 5 | * load the document 6 | * parse and cache all of the behaviors in the behaviors list 7 | * load all images in the assets 8 | * rebuild three-js objects in the tree. pass in cache obj with provider methods -------------------------------------------------------------------------------- /src/docserver.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const fs = require('fs'); 3 | const paths = require('path'); 4 | const cors = require('cors'); 5 | const bodyParser = require('body-parser'); 6 | const PubNub = require("pubnub") 7 | 8 | let pubnub = null; 9 | let dir = null; 10 | let assets_dir = null; 11 | let port = null; 12 | 13 | startup(); 14 | 15 | function startup() { 16 | //handle env vars first 17 | if(process.env.DIR) dir = process.env.DIR 18 | if(process.env.PORT) port = parseInt(process.env.PORT) 19 | if(dir && port) { 20 | startPubNub(); 21 | startServer(); 22 | return 23 | } 24 | 25 | //handle args next 26 | const args = process.argv.slice(2) 27 | if (args.length < 2) throw new Error("missing docs dir and port"); 28 | dir = args[0]; 29 | if(!fs.existsSync(dir)) throw new Error(`doc dir doesn't exist: "${dir}"`) 30 | const portS = args[1] 31 | if(!parseInt(portS)) throw new Error(`invalid port number "${portS}"`) 32 | port = parseInt(portS) 33 | 34 | console.log(`starting server with docs dir ${dir} and port ${port}`) 35 | startPubNub(); 36 | startServer(); 37 | } 38 | 39 | function startPubNub() { 40 | pubnub = new PubNub({ 41 | publishKey:"pub-c-1cba58da-c59a-4b8b-b756-09e9b33b1edd", 42 | subscribeKey:"sub-c-39263f3a-f6fb-11e7-847e-5ef6eb1f4733" 43 | }) 44 | } 45 | 46 | function parseId(req) { 47 | //strip out non-alphanumeric characters for safety 48 | return req.params.id.replace(/\W/g, '_') 49 | } 50 | function parseAssetId(req) { 51 | console.log("start = ", req.params.id) 52 | const parts = req.params.id.split('.').map((part)=>part.replace(/\W/g,'_')) 53 | console.log("parts",parts.length,parts) 54 | if(parts.length === 1) return parts[0] 55 | const end = parts.pop() 56 | return parts.join("")+'.'+end 57 | } 58 | function docPath(id) { 59 | return paths.join(process.cwd(), dir, id + '.json') 60 | } 61 | function assetPath(id) { 62 | return paths.join(process.cwd(), assets_dir,id) 63 | } 64 | function startServer() { 65 | assets_dir = paths.join(dir,'assets') 66 | if(!fs.existsSync(assets_dir)) fs.mkdir(assets_dir) 67 | console.log("using assets dir",assets_dir); 68 | 69 | const app = express(); 70 | app.use(cors()); 71 | app.use(bodyParser.json({limit: '50mb'})); 72 | app.get("/doc/:id", (req, res) => { 73 | const id = parseId(req) 74 | res.sendFile(docPath(id)) 75 | }) 76 | app.post("/doc/:id", (req, res) => { 77 | const id = parseId(req) 78 | const data = JSON.stringify(req.body, null, ' '); 79 | fs.writeFile(docPath(id),data,(err)=>{ 80 | if(err) { 81 | console.log("failed",err) 82 | res.json({success:false,message:"could not save"}) 83 | } 84 | console.log("wrote it") 85 | console.log("sending message to channel",id) 86 | pubnub.publish({channel:id, message:{message:'updated'}}).then((t)=>console.log(t)).catch((e)=>console.log(e)) 87 | res.json({success:true,message:"saved it!"}) 88 | }) 89 | }) 90 | app.get('/asset/:id', (req,res) => { 91 | const id = parseAssetId(req) 92 | console.log("id = ",id) 93 | console.log('sending the file',assetPath(id)) 94 | res.sendFile(assetPath(id)) 95 | }) 96 | app.post('/asset/:id', (req,res) => { 97 | const id = parseAssetId(req) 98 | console.log("got request to upload a file with id",req.params.id, '=>',id) 99 | const path = paths.join(process.cwd(),dir,'assets',id) 100 | console.log('writing to',path) 101 | const file = fs.createWriteStream(path,{encoding:'binary'}) 102 | //stream it directly to disk 103 | req.on('data',(chunk) => file.write(chunk)) 104 | req.on('end', () => { 105 | file.end() 106 | res.json({success:true,message:'uploaded it', id:id}) 107 | }) 108 | }) 109 | 110 | const server = app.listen(port, function () { 111 | console.log(`docserver listening at http://${server.address().address}:${server.address().port}`); 112 | }); 113 | 114 | } 115 | 116 | -------------------------------------------------------------------------------- /src/exports.js: -------------------------------------------------------------------------------- 1 | import PropSheet from "./common/PropSheet" 2 | import SyncGraphProvider from './syncgraph/SyncGraphProvider' 3 | const {DocGraph, CommandGenerator} = require("syncing_protocol"); 4 | import {toQueryString} from './utils' 5 | 6 | 7 | export {PropSheet, SyncGraphProvider, DocGraph, CommandGenerator, toQueryString} -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MozillaReality/mred/a91654c26c4c418ea7ef4f441609c51578124d66/src/index.css -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import '@fortawesome/fontawesome-free/css/all.css' 5 | import App from './App'; 6 | import {parseOptions} from 'react-visual-editor-framework' 7 | import {PopupManager, PopupManagerContext} from 'appy-comps' 8 | 9 | const default_options = { 10 | mode: 'edit', 11 | } 12 | const options = parseOptions(default_options) 13 | console.log("options is",options); 14 | 15 | function init() { 16 | return 17 | 18 | 19 | } 20 | 21 | ReactDOM.render(init(), document.getElementById("root")); 22 | 23 | -------------------------------------------------------------------------------- /src/metadoc/AssetView.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from "react" 2 | import {fetchGraphObject} from '../syncgraph/utils' 3 | import {ASSET_TYPES} from '../vr/Common' 4 | import GLTFAssetView from '../vr/GLTFAssetView' 5 | import GeoAssetView from '../vr/GeoAssetView' 6 | 7 | export default class AssetView extends Component { 8 | render() { 9 | const prov = this.props.provider 10 | const asset = fetchGraphObject(prov.getDataGraph(),this.props.asset) 11 | return
12 |

{asset.subtype} : {asset.title}

13 | {this.renderAsset(asset)} 14 |
15 | } 16 | 17 | renderAsset(asset) { 18 | const url = this.props.provider.assetsManager.getAssetURL(asset) 19 | if(asset.subtype === ASSET_TYPES.IMAGE) return {asset.title}/ 20 | if(asset.subtype === ASSET_TYPES.AUDIO) return