diff --git a/README.md b/README.md new file mode 100644 index 0000000..1730dce --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +

Exokit Studio

+

An interface for the Exokit Engine.

+ +

+ + + + + + +

+ +
+ Site + — + Docs + — + Discord + — + Twitter + — + Email List +
+ +## Examples + +Hands Reality Tab +Live Reload Magic Leap +Tutorial Reality Tab + +Reality Projection with HTC Vive and Magic Leap +Emukit +Various Exokit Apps + +*Find more examples on [YouTube](https://www.youtube.com/channel/UC87Q7_5ooY8FSLwOec52ZPQ).* + + +## Overview + +Exokit Studio **enables developers to build XR experiences with ease** by having a seamless interface to the Exokit Engine. Studio prefers using GUIs instead of command lines with difficult to remember arguments to use the functionality you want. + +Studio uses the [Exokit Engine](https://github.com/exokitxr/exokit), which is written on top of Node and emulates a web browser, providing native hooks for WebGL, WebGL2, WebVR, WebXR, WebAudio, and other APIs used in immersive experiences. + +:eyeglasses: **Exokit Engine currently targets the following platforms**: +* OpenVR Desktop VR (Steam compatible) +* HTC Vive +* Valve Index * +* Oculus Desktop (Oculus Rift, Oculus Rift S) +* Oculus Mobile (Oculus Quest, Oculus Go, GearVR) +* Magic Leap +* iOS ARKit * +* Android ARCore * +* Google VR (Daydream / Cardboard / Mirage Solo) * +* Hololens / Hololens 2 * +* any XR device, start a [pull request](https://github.com/exokitxr/exokit/compare) to the Exokit Engine with a native binding if it isn't listed here! * + +\* not supported yet + +:electric_plug: **Exokit Engine powers experiences built with**: +* Three.js +* Unity +* Pixi.js +* Babylon.js +* A-Frame +* Custom WebGL frameworks +* WebAssembly, TypeScript, and any language that transpiles to JavaScript +* Unity WebVR export * +* SteamVR * +* any 3d web framework, start a [pull request](https://github.com/exokitxr/exokit/compare) to the Exokit Engine if a 3d web framework isn't currently supported! * + +\* not supported yet + +## Quickstart + +### Desktop +

Download and install Studio for current OS

+ +### Local Development + +```sh +git clone https://github.com/exokitxr/studio.git +cd studio +npm install +npm build +``` + +## Stay in Touch + +- [Join our Discord](https://discord.gg/Apk6cZN) for discussions. +- [Follow @exokitxr on Twitter](https://twitter.com/exokitxr) for updates. diff --git a/exobot.html b/exobot.html new file mode 100644 index 0000000..1930185 --- /dev/null +++ b/exobot.html @@ -0,0 +1,149 @@ + + + + + + + exobot + + + + + +

exobot

+ + + + + diff --git a/graffiti_ml.html b/graffiti_ml.html index f18989e..c59404f 100644 --- a/graffiti_ml.html +++ b/graffiti_ml.html @@ -331,7 +331,7 @@

graffiti_ml

scene.add(controllerMesh); }); - const cubeGeometry = new THREE.BoxBufferGeometry(0.02, 0.02, 0.001); + const cubeGeometry = new THREE.BoxBufferGeometry(0.05, 0.05, 0.05); const hitMeshMaterial = new THREE.MeshPhongMaterial({ color: 0x673ab7, }); diff --git a/index.html b/index.html index 9011030..3683e6a 100644 --- a/index.html +++ b/index.html @@ -11,9 +11,14 @@ - - - - \ No newline at end of file diff --git a/ui/public/index.html b/ui/public/index.html index cbaaddb..0defbd8 100644 --- a/ui/public/index.html +++ b/ui/public/index.html @@ -12,7 +12,7 @@ - Exokit Launcher + Exokit Studio diff --git a/ui/public/manifest.json b/ui/public/manifest.json index fddfd1d..bc4df82 100644 --- a/ui/public/manifest.json +++ b/ui/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "Exokit Launcher", - "name": "Exokit Launcher", + "short_name": "Exokit Studio", + "name": "Exokit Studio", "icons": [ { "src": "favicon.ico", diff --git a/ui/src/components/Engine.jsx b/ui/src/components/Engine.jsx index 57b3cf1..2590b10 100644 --- a/ui/src/components/Engine.jsx +++ b/ui/src/components/Engine.jsx @@ -25,6 +25,7 @@ class Engine extends React.Component { flags: [], item: null, settings: null, + joinPartySettings: null, urlFocus: false, addTab: 'template', url: 'https://aframe.io/a-painter/', @@ -34,16 +35,6 @@ class Engine extends React.Component { componentDidMount() { _postViewportMessage(); window.addEventListener('resize', _postViewportMessage); - - /* window.addEventListener('keydown', e => { - console.log('iframe keydown ' + e.keyCode); - }); - window.addEventListener('keyup', e => { - console.log('iframe keyup ' + e.keyCode); - }); - window.addEventListener('keypress', e => { - console.log('iframe keypress ' + e.keyCode); - }); */ } postMessage(action){ @@ -129,6 +120,15 @@ class Engine extends React.Component { }); } + openJoinPartySettings(joinPartySettings) { + this.setState({ + item: null, + joinPartySettings, + }, () => { + this.postMenuStatus(); + }); + } + openAddTab(e, addTab) { this.setState({ addTab, @@ -137,7 +137,7 @@ class Engine extends React.Component { e.stopPropagation(); } - onEngineRenderClick() { + onEngineRenderFocus() { this.blur(); } @@ -223,6 +223,7 @@ class Engine extends React.Component { this.setState({ item: null, settings: null, + joinPartySettings: null, urlFocus: false, }, () => { this.postMenuStatus(); @@ -232,7 +233,7 @@ class Engine extends React.Component { postMenuStatus() { window.postMessage({ method: 'menu', - open: this.state.item !== null || this.state.settings !== null || this.state.urlFocus, + open: this.state.item !== null || this.state.settings !== null || this.state.joinPartySettings !== null ||this.state.urlFocus, }); } @@ -252,6 +253,7 @@ class Engine extends React.Component {
this.openSettings('settings')}>Settings...
this.openSettings('sdkPaths')}>SDK Paths...
+
this.openJoinPartySettings('joinPartySettings')}>Party...
{/*
Settings
*/} @@ -284,9 +286,9 @@ class Engine extends React.Component {
-
this.addTemplate('kitchenSink')}> - -
Kitchen sink
+
this.addTemplate('webXrSample')}> + +
WebXR Sample
this.addTemplate('exobot')}> @@ -335,14 +337,12 @@ class Engine extends React.Component {
- this.openSettings(null)}/>
-
this.onEngineRenderClick()} /> + this.onEngineRenderFocus()}/> { _postViewportMessage(); }}> @@ -360,11 +360,73 @@ class Engine extends React.Component {
+ this.openSettings(null)}/> + this.openJoinPartySettings(null)}/>
); } } +class EngineRender extends React.Component { + /* onMouseDown(e) { + const engineRender = document.getElementById('engine-render'); + const bcr = engineRender.getBoundingClientRect(); + window.postMessage({ + method: 'viewportMouseDown', + x: e.clientX - bcr.x, + y: e.clientY - bcr.y, + button: e.button, + }); + } + onMouseUp(e) { + const engineRender = document.getElementById('engine-render'); + const bcr = engineRender.getBoundingClientRect(); + window.postMessage({ + method: 'viewportMouseUp', + x: e.clientX - bcr.x, + y: e.clientY - bcr.y, + button: e.button, + }); + } + onClick(e) { + const engineRender = document.getElementById('engine-render'); + const bcr = engineRender.getBoundingClientRect(); + window.postMessage({ + method: 'viewportClick', + x: e.clientX - bcr.x, + y: e.clientY - bcr.y, + button: e.button, + }); + } + onMouseMove(e) { + const engineRender = document.getElementById('engine-render'); + const bcr = engineRender.getBoundingClientRect(); + window.postMessage({ + method: 'viewportMouseMove', + x: e.clientX - bcr.x, + y: e.clientY - bcr.y, + }); + } + onMouseWheel(e) { + const engineRender = document.getElementById('engine-render'); + const bcr = engineRender.getBoundingClientRect(); + window.postMessage({ + method: 'viewportMouseWheel', + x: e.clientX - bcr.x, + y: e.clientY - bcr.y, + deltaX: e.deltaX, + deltaY: e.deltaY, + }); + } */ + + render() { + /*
this.onClick(e)} onMouseDown={e => this.onMouseDown(e)} onMouseUp={e => this.onMouseUp(e)} onMouseMove={e => this.onMouseMove(e)} onMouseWheel={e => this.onMouseWheel(e)} />*/ + return ( +
+ ); + } +} + class Settings extends React.Component { constructor(props) { super(props); @@ -454,4 +516,86 @@ class Settings extends React.Component { } } +class JoinPartySettings extends React.Component { + + constructor(props) { + super(props); + + this.state = { + }; + } + + componentDidMount() { + } + + classNames() { + const classNames = ['joinPartySettings']; + if (this.props.open) { + classNames.push('open'); + } + return classNames.join(' '); + } + + onMetricsBlur() { + } + + joinParty() { + const registryUrl = document.getElementById('registryUrl'); + const serverList = document.getElementById('serverList'); + + window.postMessage({ + method: 'joinParty', + registryUrl: registryUrl.value, + name: serverList.value + }); + } + + listPartyServers() { + const registryUrl = document.getElementById('registryUrl'); + window.postMessage({ + method: 'listPartyServers', + registryUrl: registryUrl.value + }); + + const serverList = document.getElementById('serverList'); + window.addEventListener('message',function(e) { + serverList.focus(); + for (let i = 0; i < e.data.servers.length; i++) { + const {name} = e.data.servers[i]; + + var option = document.createElement("option"); + option.value = name; + option.text = name; + serverList.appendChild(option); + } + },false); + } + + render() { + return ( +
+
this.props.close()}>
+
+
Party
+
+ +
+ this.listPartyServers()} /> +
+ +
+