diff --git a/app/helloworld.js b/app/helloworld.js
index cbb2fd8..9f7ad6b 100644
--- a/app/helloworld.js
+++ b/app/helloworld.js
@@ -1,42 +1,36 @@
AFRAME.registerComponent('helloworld', {
schema: {
-
+ foo: { type:"string"}
},
+
dependencies:{
- "iso": "https://rawgit.com/Utopiah/reponame/master/dist/file.min.js", // fallback URL for xrsh in case component
- "xterm": "https://rawgit.com/Utopiah/reponame/master/dist/file.min.js", // was not loaded (in AFRAME.components)
- "content-menu": "https://rawgit.com/Utopiah/reponame/master/dist/file.min.js", // TIP: include branch/commit in URL to lock specify version
+ "html": "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME
+ "stylis": "https://unpkg.com/stylis@4.3.1/dist/umd/stylis.js" // modern CSS (https://stylis.js.org)
},
+
+ dom: {
+ scale: 3.5,
+ events: ['click'],
+ html: `
`,
+ css: `div{ #hello {position:relative;top:0;width:300px} }`
+ },
+
events:{
-
- "iso": function(tty){// act when component gets mounted
- // 'term' is basically AFRAME.components.ISOterminal
- tty.write('hello to tty ISO-os from AFRAME')
- tty.on('stdout', (data) => {
- // react to data being spoken/typed into the terminal
- // (spatial prompting like 'open foo.gltf', 'component helloworld' e.g.)
- })
- },
-
- "xterm": function(xterm){// act when component gets mounted
- // 'term' is basically AFRAME.components.ISOterminal
- },
-
- "content-menu": function(menu){
- menu.add({
- name: 'edit', // "everything must have an edit-button" ~ Fabien Benetou
- icon: 'gear', // see https://jsonforms.io to see json-2-html forms
- type: 'object', // json-2-webxr has nothing like it (yet) but offers uniform interfaces across components
- properties:{
- enabled: { type: 'boolean', default: true, format: 'checkbox' },
- edit_terminal: { type: 'function', cb: () => AFRAME.components.ISOterminal.exec('pico /com/helloworld.js') },
- edit_spatial: { type: 'function', cb: () => this.require({"spatial-edit":{required:true}}) }
- }
- })
- }
+ "html": function( ){ console.log("htmlmesh component mounted!") }, // html-component was added to this AFRAME entity
+ "title": function(e){ this.dom.el.querySelector("button").innerHTML = e.detail.v }, // this.data.title was changed
+ "click": function(e){ // a click was detected on this.dom.el or AFRAME entity
+ this.data.title = 'hello world '+(new Date().getTime())
+ console.dir(e.detail.target || e.target)
+ },
},
- init: function () { },
+ init: function () {
+ this.require( this.dependencies )
+ .then( () => {
+ document.body.appendChild(this.dom.el)
+ this.el.setAttribute("html",'html:#hello; cursor:#cursor')
+ })
+ },
manifest: { // HTML5 manifest to identify app to xrsh
"short_name": "Hello world",
@@ -56,18 +50,18 @@ AFRAME.registerComponent('helloworld', {
"theme_color": "#3367D6",
"shortcuts": [
{
- "name": "How are you today?",
+ "name": "What is the latest news?",
+ "cli":{
+ "usage": "helloworld [options]",
+ "example": "helloworld news",
+ "args":{
+ "--latest": {type:"string"}
+ }
+ },
"short_name": "Today",
"description": "View weather information for today",
"url": "/today?source=pwa",
"icons": [{ "src": "/images/today.png", "sizes": "192x192" }]
- },
- {
- "name": "How's weather tomorrow?",
- "short_name": "Tomorrow",
- "description": "View weather information for tomorrow",
- "url": "/tomorrow?source=pwa",
- "icons": [{ "src": "/images/tomorrow.png", "sizes": "192x192" }]
}
],
"description": "Hello world information",
diff --git a/app/iso.js b/app/iso.js
new file mode 100644
index 0000000..59f869b
--- /dev/null
+++ b/app/iso.js
@@ -0,0 +1,113 @@
+AFRAME.registerComponent('helloworld', {
+ schema: {
+ foo: { type:"string"}
+ },
+ dependencies:{
+ "html": "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME
+ "stylis": "https://unpkg.com/stylis@4.3.1/dist/umd/stylis.js" // modern CSS (https://stylis.js.org)
+ },
+ dom: {
+ scale: 3.5,
+ events: ['click'],
+ html: ``,
+ css: `div{ #hello {position:absolute;top:0;width:300px} }`
+ },
+ events:{
+ "html": function( ){ console.log("htmlmesh component mounted!") }, // html-component was added to this AFRAME entity
+ "title": function(e){ this.dom.el.querySelector("button").innerHTML = e.detail.v }, // this.data.title was changed
+ "click": function(e){ alert("clicked "+ (e.detail.target || e.target).tagName ) }, // a click was detected on this.dom.el or AFRAME entity
+// "aframe-html": function(){
+// this.el.setAttribute()
+// alert("aframe loaded")
+// }
+
+// "iso": function(tty){// act when component gets mounted
+// // 'term' is basically AFRAME.components.ISOterminal
+// tty.write('hello to tty ISO-os from AFRAME')
+// tty.on('stdout', (data) => {
+// // react to data being spoken/typed into the terminal
+// // (spatial prompting like 'open foo.gltf', 'component helloworld' e.g.)
+// })
+// },
+//
+// "xterm": function(xterm){// act when component gets mounted
+// // 'term' is basically AFRAME.components.ISOterminal
+// },
+//
+// "content-menu": function(menu){
+// menu.add({
+// name: 'edit', // "everything must have an edit-button" ~ Fabien Benetou
+// icon: 'gear', // see https://jsonforms.io to see json-2-html forms
+// type: 'object', // json-2-webxr has nothing like it (yet) but offers uniform interfaces across components
+// properties:{
+// enabled: { type: 'boolean', default: true, format: 'checkbox' },
+// edit_terminal: { type: 'function', cb: () => AFRAME.components.ISOterminal.exec('pico /com/helloworld.js') },
+// edit_spatial: { type: 'function', cb: () => this.require({"spatial-edit":{required:true}}) }
+// }
+// })
+// }
+ },
+
+ init: function () {
+ this.require( this.dependencies )
+ .then( () => {
+ document.body.appendChild(this.dom.el)
+
+ setInterval( () => this.data.title = String(Math.random()), 500 )
+ this.el.setAttribute("html",'html:#hello; cursor:#cursor')
+ })
+ },
+
+ manifest: { // HTML5 manifest to identify app to xrsh
+ "short_name": "Hello world",
+ "name": "Hello world",
+ "icons": [
+ {
+ "src": "/images/icons-vector.svg",
+ "type": "image/svg+xml",
+ "sizes": "512x512"
+ }
+ ],
+ "id": "/?source=pwa",
+ "start_url": "/?source=pwa",
+ "background_color": "#3367D6",
+ "display": "standalone",
+ "scope": "/",
+ "theme_color": "#3367D6",
+ "shortcuts": [
+ {
+ "name": "How are you today?",
+ "short_name": "Today",
+ "description": "View weather information for today",
+ "url": "/today?source=pwa",
+ "icons": [{ "src": "/images/today.png", "sizes": "192x192" }]
+ },
+ {
+ "name": "How's weather tomorrow?",
+ "short_name": "Tomorrow",
+ "description": "View weather information for tomorrow",
+ "url": "/tomorrow?source=pwa",
+ "icons": [{ "src": "/images/tomorrow.png", "sizes": "192x192" }]
+ }
+ ],
+ "description": "Hello world information",
+ "screenshots": [
+ {
+ "src": "/images/screenshot1.png",
+ "type": "image/png",
+ "sizes": "540x720",
+ "form_factor": "narrow"
+ }
+ ],
+ "help":`
+Helloworld application
+
+This is a help file which describes the application.
+It will be rendered thru troika text, and will contain
+headers based on non-punctualized lines separated by linebreaks,
+in above's case "\nHelloworld application\n" will qualify as header.
+ `
+ }
+
+});
+
diff --git a/com/app.js b/com/app.js
new file mode 100644
index 0000000..7efc2d7
--- /dev/null
+++ b/com/app.js
@@ -0,0 +1,158 @@
+// this is a highlevel way of loading buildless 'apps' (a collection of js components)
+
+AFRAME.registerComponent('app', {
+ schema:{
+ "uri":{ type:"string"}
+ },
+ init: function() {
+ this.require([ this.data.uri ])
+ .then( () => {
+ let id = this.data.uri.split("/").pop() // 'a/b/c/mycom.js' => 'mycom.js'
+ let component = id.split(".js").shift() // 'mycom.js' => 'mycom'
+ let entity = document.createElement("a-entity")
+ this.el.setAttribute(component,this.data)
+ })
+ },
+
+
+ // usage: require(["./app/foo.js"])
+ // require({foo: "https://foo.com/foo.js"})
+ require: AFRAME.AComponent.prototype.require = function(packages){
+ let deps = []
+ if( !packages.map ) packages = Object.values(packages)
+ packages.map( (package) => {
+ let id = package.split("/").pop()
+ if( !document.head.querySelector(`script#${id}`) ){
+ let p = new Promise( (resolve,reject) => {
+ let script = document.createElement("script")
+ script.id = id
+ script.src = package
+ script.onload = () => resolve()
+ script.onerror = (e) => reject(e)
+ document.head.appendChild(script)
+ })
+ deps.push(p)
+ }
+ })
+ return Promise.all(deps)
+ }
+
+})
+
+// monkeypatching initComponent will trigger events when components
+// are initialized (that way apps can react to attached components)
+// basically, in both situations:
+//
+//
+//
+// event 'foo' will be triggered as both entities (in)directly require component 'foo'
+
+AFRAME.AComponent.prototype.initComponent = function(initComponent){
+ return function(){
+ this.el.emit( this.attrName, this)
+ return initComponent.apply(this,arguments)
+ }
+}( AFRAME.AComponent.prototype.initComponent)
+
+
+// monkeypatching updateProperties will detect a component config like:
+// dom: {
+// html: `hello
`,
+// css: `#hello {color:red}`,
+// events: ['click']
+// }
+// and use it to create a reactive DOM-component (using native javascript Proxy)
+// which delegates all related DOM-events AND data-changes back to the AFRAME component
+
+AFRAME.AComponent.prototype.updateProperties = function(updateProperties){
+ return function(){
+ updateProperties.apply(this,arguments)
+ if( this.dom && this.data){
+ let reactify = (el,aframe) => new Proxy(this.data,{
+ get(me,k,v) { return me[k] },
+ set(me,k,v){
+ me[k] = v
+ aframe.emit(k,{el,k,v})
+ }
+ })
+ let el = document.createElement('div')
+ el.innerHTML = this.dom.html
+ this.data = reactify( el, this.el )
+ this.dom.events.map( (e) => el.addEventListener(e, (ev) => this.el.emit(e,ev) ) )
+ this.dom.el = el
+ // add css if any
+ if( this.dom.css && !document.head.querySelector(`style#${this.attrName}`) ){
+ document.head.innerHTML += ``
+ }
+ if( this.dom.scale ) this.el.setAttribute('scale',`${this.dom.scale} ${this.dom.scale} ${this.dom.scale}`)
+ //('[helloworld]').object3D.children[0].material.map.magFilter = THREE.NearestFilter
+ }
+ }
+}( AFRAME.AComponent.prototype.updateProperties)
+
+//
+// base CSS for XRSH apps
+//
+document.head.innerHTML += `
+
+`
diff --git a/com/require.js b/com/require.js
deleted file mode 100644
index 6a01ad1..0000000
--- a/com/require.js
+++ /dev/null
@@ -1,14 +0,0 @@
-AFRAME.registerComponent('require', {
- init: function() {
- },
-
-})
-// work in progress
-//
-// //
-//const updateComponents = AFRAME.AEntity.prototype.updateComponents
-//AFRAME.AEntity.prototype.updateComponents = function(updateComponents){
-// return function(){
-// return updateComponents.apply(this,args)
-// }
-//}(updateComponents)