Garden of Joy webGL Social Experiment

What is this? It is a simple webGL social experiment. It allows you to share ideas and passions with your friends on facebook by doing so you help build the garden. You can also view other flowers by using your arrow keys to move with the mouse and clicking on other flowers to view what other people enjoy. This experiment was built with threeJS, toxiclibs, and content from Katalabs. This is an alpha as in I am still testing it. So you should expect improvements. I have also thought of several other ideas along the way. I will continue to roll out social applications, desktop, and mobile. The idea of a virtual garden appealed to me because I love gardens and nature in general. I get 99% of my inspiration from nature so the subject matter makes sense to me. A garden grows because of love, care and tending to it. This idea was one of the more complicated implementations of a social experiment I could think of and that is why I choose it. While I do not have a green thumb this is something I can appreciate due to my upbringing and family. If I had more time I would certainly take it up. I like to be challenged and it is important to never stop challenging your thinking and changing your environment. If you do Java try C#, If you do JavaScript do some ActionScript get it change it up and be fearless. I knew that it would challenge me. Making image sliders, rss feeds, accordions, custom scroll bars, etc is trivial simple basic math.

I was originally thinking about creating a twitter virtual garden but became restless with the idea of doing another search driven twitter app. I have actually invested in several books that are dedicated to data visualization and I would like to create more engaging applications that utilize data in a unique way. Data doesn’t have to be boring! I also wanted to make another social application but also use oAuth to do so. oAuth is really shaping up to be the login choice of the masses which is cool to see it is after all about 7 years in the making. oAuth is now being utilized by Twitter and Facebook. I am also anxious to get my hands on the google+ api (hint hint let me have at it google) although it is not available. So I decided to create another Facebook application. They have considerably improved their api since I last utilized it! It was a pleasant surprise. The garden of joy was built utilizing several javascript libraries:

View the Garden Click Here

Front End Code to view all of it just go to the application and view source

    // resets the camera after it has been viewing a single flower for a bit
	function newCamera(position){
		camera = new THREE.FirstPersonCameraModified( {
					fov: 60, aspect: window.innerWidth / window.innerHeight, near: 1, far: 100000,
					movementSpeed: 200, lookSpeed: 0.03, noFly: false, lookVertical: false
				} );
			if(position != undefined){
				camera.position = position;
	// initiates the garden after the user has accepted the application
	function init() {
				loader = new THREE.JSONLoader();
				container = document.getElementById( 'container' );
				camera.position.y = 60;
				curentTarget =;
				scene = new THREE.Scene();
				toxiToThreeSupport = new toxi.THREE.ToxiclibsSupport(scene);
				threeMesh = undefined; 
				threeLight = new THREE.Light(0xe40d4f);
				material = new THREE.MeshNormalMaterial({color: 0xe40d4f, opacity: 0.7, blending: THREE.AdditiveBlending, doubleSided: true });
				material2 = new THREE.MeshBasicMaterial( { color: 0xe40d4f,opacity: 0.5, blending: THREE.AdditiveBlending, doubleSided: true  } );
				// uses a service I built to retun the user data in JSON for the garden
				$.get('', function(data){
				gardenData = data;
                // Right now I am using SphericalHarmonics from Toxiclibs to build the flower although this will change
					//var m = new Array(0.0,3.0,6.0,0.0,1.0,5.0,5.0,5.0);
				var m = new Array(4.0,2.0,5.0,3.0,1.0,8.0,3.0,3.0);
						//var m = new Array(2.0,1.0,6.0,1.0,2.0,7.0,0.0,7.0);
				var sh = new toxi.SphericalHarmonics(m)
						// Loops through the data and randomly places the flowers in the garden
						SurfaceMeshBuilder = new toxi.SurfaceMeshBuilder(sh);
						for(var i=0; i< data.length; i++){
							var toxiMesh = SurfaceMeshBuilder.createMesh(new toxi.TriangleMesh(),50,1,true);
							threeMesh = toxiToThreeSupport.addMesh(toxiMesh,[material, material2,  new THREE.MeshBasicMaterial( { color: 0x3ff507,opacity: 0.2, blending: THREE.AdditiveBlending } )]);
							threeMesh.scale = new THREE.Vector3(5,5,5); = i;
							threeMesh.doubleSided = true;
							threeMesh.position.x = i*Math.floor(Math.random()*400);
							threeMesh.position.z = i*Math.floor(Math.random()*400);
							threeMesh.position.y = 20;
							threeMesh.doubleSided = true;
				// Loads the Katalabs model for the garden
				loader.load( { model: "/models/garden.js", callback: function(geo){ 
						var mesh2 =  new THREE.Mesh( geo, new THREE.MeshFaceMaterial({blending: THREE.AdditiveBlending, doubleSided: true, transparent:true, depthTest: false}) );
						mesh2.scale.x = mesh2.scale.y = mesh2.scale.z = 800;
						mesh2.doubleSided = true;
						var mc = THREE.CollisionUtils.MeshColliderWBox(mesh2);
						THREE.Collisions.colliders.push( mc );
						console.log('fail' + e);
				 } });
				renderer = new THREE.WebGLRenderer( { antialias: false } );
				renderer.setSize( window.innerWidth, window.innerHeight );
				container.innerHTML = "";
				container.appendChild( renderer.domElement );
				stats = new Stats(); = 'absolute'; = '0px';
				container.appendChild( stats.domElement );
                // looks at the url to determine if it is a user story if so it loads that flower in the garden first
					if(window.location.hash != undefined && window.location.hash != ''){
						var hashStr = window.location.hash;
						hashStr = hashStr.replace(/#/i, '');
						var getUrl = '' + hashStr;
						$.get(getUrl, function (data) {
							  position: 'absolute',
							  right: '20px',
							  top: '10px'
						  $('#whatYoulove').css('z-index', '20');
						  var m = new Array(4.0, 2.0, 5.0, 3.0, 1.0, 8.0, 3.0, 3.0);
						  var sh = new toxi.SphericalHarmonics(m)
						  SurfaceMeshBuilder = new toxi.SurfaceMeshBuilder(sh);
						  var toxiMesh = SurfaceMeshBuilder.createMesh(new toxi.TriangleMesh(), 50, 1, true);
						  threeMesh = toxiToThreeSupport.addMesh(toxiMesh, [material, material2, new THREE.MeshBasicMaterial({
							  color: 0x3ff507,
							  opacity: 0.2,
							  blending: THREE.AdditiveBlending
						  threeMesh.scale = new THREE.Vector3(5, 5, 5); = data.length + 1;
						  threeMesh.doubleSided = true;
						  threeMesh.position.x = Math.floor(Math.random() * 400);
						  threeMesh.position.z = Math.floor(Math.random() * 400);
						  threeMesh.position.y = 20;
						  var currentPosition = threeMesh.position;
						  threeMesh.doubleSided = true;
						  cameraTween = new TWEEN.Tween(camera.position).to({
							  x: currentPosition.x - 300,
							  y: currentPosition.y,
							  z: currentPosition.z
						  }, 2000).easing(TWEEN.Easing.Elastic.EaseOut).start();
						  cameraTween.onComplete(function () { = currentPosition;
							  setTimeout('removeTarget()', 5000);
		// prevents normal mouse down event and allows for the user to click and zoom in on a flower
		function onDocumentMouseDown( event ) {
				var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
				projector.unprojectVector( vector, camera );
				var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
				var intersects = ray.intersectObjects( objects );
				if ( intersects.length > 0 ) {
					console.log(intersects[ 0 ].object.position.x);
                    // tween camera with the intersecting object
					cameraTween = new TWEEN.Tween( camera.position ).to( {
						x: intersects[ 0 ].object.position.x - 300,
						y: intersects[ 0 ].object.position.y,
						z: intersects[ 0 ].object.position.z}, 2000 )
					.easing( TWEEN.Easing.Elastic.EaseOut).start();
					obj = intersects[ 0 ].object;
					try{ = obj.position;
					flID = parseInt(;
					var userData = '
'+ gardenData[flID].username +'
'+ gardenData[flID].love +'
'; }catch(e){ console.log(e); } $('.formContent').html(''); $('.formContent').html(userData); $('#whatYoulove').css({position:'absolute', right:'20px', top:'10px'}); $('#whatYoulove').css('z-index','20'); $('#whatYoulove').fadeIn('fast'); // removes the target and resets the camera setTimeout('removeTarget()', 5000); }); } } function removeTarget(){ newCamera(camera.position); } function animate() { requestAnimationFrame( animate ); render(); stats.update(); } function render() { TWEEN.update(); var time = new Date().getTime() * 0.01; renderer.render(scene, camera); }

It was a tremendous amount of fun to play around with all of the libraries they all work well together and I am anxious to use them in future projects. TweenJS makes it ridiculously easy to create your animated motion tweens even in 3-D. The tweens give the applications that organic fluid feel. Tweens are great for creating motion. If you have used tweener for actionscript then you know exactly what I am talking about. The tweener engine utilizes many of Robert Penner’s easing equations. Robert Penner wrote a wonderful book about animation “Programming Flash MX” it came out several years ago but still holds its weight in gold. This book is a gem it is useful for anyone wanting to do animation efficiently I highly recommend this book and it has helped me out for a number of years now. ThreeJS is always a pleasure to use when creating 3d environments it is easy to import models into it. I also wanted to use toxiclibs because I have only played with it a little within Processing. Now that it is JavaScript I believe this opens up a number of opportunities it works concurrently with other libraries with ease. I created the original flowers that populate the virtual garden with toxiclibs. I would also like to devote a little time to create an algorithm that uses an L-System possibly in combination with a golden spiral to build random flowers. I have been using processing more and more and it is easy to utilize and algorithm in it and then export the model out as an obj file. Processing is a really handy tool it allows you to easily export content out in a number of useful formats. This of course is a daunting task and I don’t know if I can devote that much time to it. I can make static models but 3d models are time consuming to make especially with open source products.

To create the models I utilized blender specifically the Katalabs OurBricks model library. They have developed a plugin for Blender that makes importing a model a one click operation. It was a cinch. I was able to easily import the models into Blender and then prepare them for threeJS. The Blender user interface has been improved greatly and is finally proving itself as a really useful tool todo 3d modeling. I actually donated money to the Blender foundation about 10 years ago to open source it. It is really great to see it making so many advancements. I have had to recently invest more money in books on Blender to keep up with all the new cool features it offers. It has always been a really cool tool although the learning curve has traditionally been exceptionally brutal it appears to be lowering and becoming the default choice for open source 3d development. I would like become more efficient when creating 3d models. I believe using blender3d will make using every other tool easy. I just need to become more clever in the way I go about creating content.

I really enjoy doing webGL work and I can’t wait until it is fully embraced by mobile which I believe will happen in the not so distant future. Web design and development have been sped up it is funny to me hearing people talk about html5 taking 10 years to implement. These predictions were most likely made when browsers were being released on a two year release cycle that is clearly not the case anymore. Google has set the bar with 3 month release cycles and is forcing all other browsers to play catch up.

Firefox has also sped up considerably and has many features that are not found in their competition right now like the web audio api! Firefox wants to enable web developers to compete with native applications head on. With technologies like webGL and the Audio api this goal is not a far stretch. I have also noticed that the overall quality of Firefox and webGL is really high I have noticed recently that it handles transparency better than Chrome currently does. It will also be interesting to see what Microsofts Windows 8 has to offer developers.

Take some time and vote for webGL to be demoed at SXSX!

← Previous post

Next post →


  1. “doesn’t work under xp” – to be honest it’s no wonder html5 isn’t getting anywhere.

  2. Aleksandar Rodic

    Any chance of seeing this without Facebook?

  3. Yes, Your right I should modify it so it is opt in for Facebook. Good idea thanks for the positive feedback. Would also like to make it work for Google+ can’t wait to see that api I bet it beats the hell out of Facebooks api….

  4. Brendonsmith

    That’s because windowsXP is DEAD.  Adapt over come and conquer everything.  Sorry you lack forward thinking and are stuck in the past must suck to be you.  

Leave a Reply