However, I am still developing the project and concept and would be very interested in repurposing it for another country, or even on a global scale. Get in touch if you’d like to help make it happen! Huge thanks to the British Council for supporting me to build the proof of concept.

Thanks to the wonderful Tom Jennings, the project has some storyboards to help explain how to interact with project:

Deep receives a photo message from her friend Zen showing her posing in front of an amazing sculpture that appears to hang in the sky above.Intrigued, Deep accessed the website that Zen pointed her to.After the website loads, Deep finds she can pan her smart phone around like a window onto the world and even use her finger to drag and change the sculpture in real time.Deep finds an angle she likes and shares it with her father via a text message.Deep’s father receives the message from Deep, an image and an instruction how to interact with the project via a feature phone.After checking on Google Maps, Deep’s father sends his longitude and latitude to the special number that Deep shared with him.Deep’s father receives a text message in response, showing the sculpture in the sky above his local area. He likes it so much he shows it to Deep’s grandmother.In a nearby square, the British Council projects the sculpture on a large wall. Locals can see the sculpture change in real time as users touch it on their smart phones.

User testing in India begins next week via the British Council so this week is my last chance to tweak the two demonstration files I’ll be submitting, one designed for iPhones and PCs without cameras and one designed for Android phones and Laptops with cameras.

On a Google Pixel phone the Mountain component isn’t particularly speedy, so I started by duplicating the component and trying to edit it to reduce it’s resolution. I also created a new pug file for the faster component and added it to my mainForRelease.js file so that Browserify would bundle it properly.

After a chat with the author of the component, Kevin Ngo, on the A-Frame Slack, he advised me to submit a pull request with the changes I required, and he would fold them into the main branch. He also supplied me with a tutorial on how to submit a pull request. I removed all my previous work and started by forking Kevin’s K-Frame repository by clicking the fork button on it’s GitHub. A new fork now existed on my GitHub. I then cloned it to my local machine:

git clone https://github.com/JGL/kframe.git

Then I moved into the folder itself, and created a new branch called mountain-variable-size:

To make sure I was using the simple nano editor for any git editing that might happen. I then edited kframe/components/mountain/index.js to the changes that I wanted, which were all to do with reducing the number of width and height segment in it’s internal PlaneBuffer. I then added it to my branch, ignored the generated kframe.js and kframe.min.js files, committed my changes and pushed the changes to my fork on GitHub.

Following Kevin Ngo’s advice, I decided to make a new component to allow me to modify either the landscape, ocean or mountain component’s material’s side property to allow them to be viewed from below. I started by creating a new file, material-side-modifier.js in my /src/js folder:

Which suggested to me that neither of my loops to change the material properties are functioning as desired. Should I be using update instead of init? Or should I be waiting for a completely different event? Or do I need to specify custom dependencies? I’d really rather not do the latter as I want this component to be able to change the side property of any component that has a material.

Which means that the traverse() method of Object3D in three.js doesn’t iterate through the Materials and Geometries of Object3D’s. So I’m never going to get to my material by the above method. What method should I use?

After further discussions on the A-Frame Slack on the #Learning channel, I altered my new component to be as follows:

In order to allow interaction with the sculpture, users are going to have to be able to click on it in some way.

Luckily, A-Frame provides the Cursor component to allow this. In order to familiarise myself with the component, I decided to follow the example provided in the docs, which allows the user to click to change the colour of entities that they click on.

To begin with, I created a new pug file (collidingWithTerrainModelComponent.pug) to create my demo html page, using the example from the docs and my previously developed component pug file:

I also had to add the cursor-listener.js file to my main.js as a requirement:

require('cursor-listener.js');

I found that the demo was reporting a click, but it wasn’t changing the colour correctly, so I edited the cursor-listener.js file as follows, drawing upon the material-side-modifier.js component that I had developed previously. I renamed the file to cursor-listener-terrain.js as it was apparent that this component wasn’t going to work well with the way that the Terrain Model component was set up:

A-Frame also has the Raycaster Component, so I decided to follow it’s tutorial to create a collider-check component, with the mountain component as it was the only component that had proved to be compatible with the cursor-listener component.

I created a new pug file (mountainComponentWithColliderCheck.pug) to to demonstrate the the newly created collider-check component. I also added the collider-check component to my main.js to that Browserify could do it’s magic. The resulting collider-check with Mountain component functioned as expected, as it output to the Javascript Console successfully when the cursor was over the Mountain component.

As the collider-check component was attaching a new listener to the Mountain Component itself:

I wanted to see if it would be possible to trigger the update() method of the Mountain Component. I created a new pug file (mountainComponentWithColliderCheckAndUpdate.pug) and component (collider-check-and-update.js):

The interaction was rather clumsy, so I created a new .pug file (mountainComponentWithMouseAndTouchInteraction.pug) and added Touch and Mouse interaction to the entire page, so that clicking or touching anywhere would generate a new terrain – as well as adding a random colour generator for the color and shadowColor attributes of the Mountain component, and finally making the sunPosition attribute random too.

The frankly amazing Dietrich Ayala created my first ever pull request for the project and added his getUserMedia() work to the project, to make the background panorama live on compatible (i.e. Firefox on Android) devices.

Kevin Ngo, the author of the package helpfully got back to me, and bumped the version of his package. I edited my package.json to reflect his change:

"kframe": "^0.3.2",

But this resulted in the following error when I tried to run:

npm update

To update K-Frame, the package in question:

ForceMacbookProRetina:APieceOfArtAsBigAsIndia joel$ npm updatenpmERR! Darwin 16.1.0npmERR!argv "/usr/local/Cellar/node/6.7.0/bin/node" "/usr/local/bin/npm" "update"npmERR!node v6.7.0npmERR!npm v3.10.7npmERR!code ETARGETnpmERR!notarget No compatible version found: kframe@'>=0.3.2 <0.4.0'npmERR!notarget Valid install targets:npmERR!notarget 0.3.0npmERR!notargetnpmERR!notarget This is most likely not a problem with npm itself.npmERR!notarget In most cases you or one of your dependencies are requestingnpmERR!notarget a package version that doesn't exist.npmERR! Please include the following file with any support request:npmERR!/Users/joel/Documents/Projects/jgl/BritishCouncil/APieceOfArtAsBigAsIndia/npm-debug.log

Today I’ve been working on adding many different A-Frame components to the panoramic image I shot of my studio. First, I created a new .pug file combining the terrain-model component by Ben Pyrik with the studio panorama:

I knew that I wanted the landscape to float in the sky above user’s heads, so I used the A-Frame Inspector to reposition the terrain model in the sky. Unfortunately, this had the side-effect of adding some glitches to the drawing of the terrain:

I suspect this is because A-Frame is expecting the terrain 3D model to be viewed from the other side. I decided to keep going with adding the other components I had found that could be good candidates for the interactive demo that I want to test with users in India.

That didn’t display correctly, so I decided to build back up from the static demo’s that Don provided with the component, before re-adding them to the panoramic image. After downloading them, I managed to get them working on my local server by editing the following lines of his Water demo:

But while isn’t my inclusion of the same component into main.js via Browserify working? I soon found the error, after re-reading Don’s readme.md. I had to add the following lines to register the component within main.js:

To make sure that Browserify included the necessary JS files to make the webpage work. This resulted in the following demo and screenshot:

After discussing my bug(s) on the fantastic A-Frame Slack it became clear that I need to edit the properties of the A-Frame Material which makes each entity an appearance. Specifically, I need to make the side property equal to double to render both sides of the mesh.

By looking in the Javascript console I could see that I was successfully printing “Hello World”, and setting the Landscape component to the variable landscapeEl. I could even make the Landscape visible or not by typing:

landscapeEl.setAttribute('visible', false);

or

landscapeEl.setAttribute('visible', true);

Into the console. I could also see that I was successfully displaying the public attributes of the Landscape component:

– and side wasn’t one of them (I wasn’t using the branch of the Component that bryvik had made as I was trying to find a general method for changing the side property of any material in A-Frame. I realised that I needed to manipulate the three.js that underlies a-frame directly, which I could do by accessing Entity’s object3D property – which is a native three.js object. By adding the following

Via the console, I could then manipulate the THREE.MeshLambertMaterial side property (via THREE.mesh) directly, to get the mesh to draw correctly:

The next step is to do this programatically, but I’m running into a bug where I can type the command on the console to see the result, even trying different methods:

var landscapeEl = document.querySelector('#landscape');
// Gaining access to the internal three.js object that the landscape component contains
var landscapeObject3D = landscapeEl.object3D;
console.log(landscapeObject3D.parent);
console.log(landscapeObject3D.children);
for(var i in landscapeObject3D.children) {
//for all the children of the landscapeObject3D, change the material side property to THREE.DoubleSide aka 2
landscapeObject3D.children[i].material.side = THREE.DoubleSide;
}
//this works when typed into the console, but not here programmatically, found here: http://stackoverflow.com/questions/18613295/how-to-set-a-texture-on-a-object3d-child-mesh
landscapeObject3D.children[0].material.side = THREE.DoubleSide;
//this works when typed into console, but not here programmatically, found here: https://threejs.org/docs/#Reference/Materials/Material
landscapeObject3D.traverse( function( node ) {
if( node.material ) {
node.material.side = THREE.DoubleSide;
}
});
//this also works when typed into the console, but not programatically, found here: http://stackoverflow.com/questions/16027131/three-js-how-to-make-double-sided-object

The A-Frame Slack came to the rescue, with pookage pointing out that I needed to call the code above only after the rest of the page had loaded, via the global JavaScript event handler: onLoad(). He also recommended the following the FunFunFunction YouTube Channel for general JavaScript learning.

function changeMaterialSide(){
//testing that I can print to the console
console.log("A-Frame and the rest have loaded");
//Gaining access to the landscape element via it's ID
var landscapeEl = document.querySelector('#landscape');
// Gaining access to the internal three.js object that the landscape component contains
var landscapeObject3D = landscapeEl.object3D;
//console.log(landscapeObject3D.parent);
//console.log(landscapeObject3D.children);
for(var i in landscapeObject3D.children) {
//for all the children of the landscapeObject3D, change the material side property to THREE.DoubleSide aka 2
landscapeObject3D.children[i].material.side = THREE.DoubleSide;
}
//this works when typed into the console, but not here programmatically, found here: http://stackoverflow.com/questions/18613295/how-to-set-a-texture-on-a-object3d-child-mesh
landscapeObject3D.children[0].material.side = THREE.DoubleSide;
//this works when typed into console, but not here programmatically, found here: https://threejs.org/docs/#Reference/Materials/Material
landscapeObject3D.traverse( function( node ) {
if( node.material ) {
node.material.side = THREE.DoubleSide;
}
});
//this also works when typed into the console, but not programatically, found here: http://stackoverflow.com/questions/16027131/three-js-how-to-make-double-sided-object
}
//Thanks to @pookage (http://www.beardeddevelopment.co.uk/) on the A-Frame Slack for pointing me in the correct direction:https://developer.mozilla.org/en/docs/Web/API/GlobalEventHandlers/onload
window.onload = changeMaterialSide;

With this new knowledge, I added the material changing functionality to the other two component demo’s I had made before, making a total of new three pug files, which compiled to the following HTML/A-Frame pages:

While 3. worked fine, after uploading, I tested 1. and 2. and found that the meshes would not render properly – even though 2. was rendering properly via my local server. I tried adding a call to Material.needsUpdate() after finding a Stackoverflow page alluding to it, but to no avail, even after changing the Material properties to just BackSide sides.

Third, I created a new JavaScript file (main.js) in a newly created js folder inside my previously created src folder:

cd src
mkdir js
cd js
touch main.js

Fourth, I added the following content to my new main.js file:

require('aframe');
require('aframe-terrain-model-component');

Fifth, I created a new .pug file (aFrameTerrainModelComponentOlympicPeninsulaGeneratedViaLessAndPugAndBrowserify.pug) in my previously created pug folder inside my previously created src folder, with the following content: