CSS 3D Clouds Retake

This post is going to cover my experience following through the tutorial on making CSS 3D clouds posted here: http://www.clicktorelease.com/tutorials/css3dclouds/. I didn’t make the original code, but I did run into several issues while I went through and I wanted to share my experience, work-arounds, and pieces of code that were missing from the original tutorial.

All the questions that came up and fixes changes here were done on the Chrome Beta (v20.0.1132.41 beta-m to be exact)

1. Creating the world and a camera

CSS 3D Clouds Step 1

In this step, you create two div’s in the body of your HTML 5 page, the outer <div> gets an id of viewport and the inner <div> gets an id of world. From there you setup some structural styling (viewport spans entire screen via absolute positioning, world is centered in the middle)

Initial Page Setup

Some initial styling needs to be done to make it look like the demo, here’s what I have:

  1. * {
  2. box-sizing: border-box;
  3. margin: 0;
  4. padding: 0;
  5. }
  6.  
  7. body {
  8. overflow: hidden;
  9. }
  10.  
  11. #viewport {
  12. background-image: linear-gradient(bottom, rgb(69, 132, 180) 28%, rgb( 31, 71, 120 ) 64%);
  13. background-image: -o-linear-gradient(bottom, rgb(69, 132, 180) 28%, rgb( 31, 71, 120 ) 64%);
  14. background-image: -moz-linear-gradient(bottom, rgb(69, 132, 180) 28%, rgb( 31, 71, 120 ) 64%);
  15. background-image: -webkit-linear-gradient(bottom, rgb(69, 132, 180) 28%, rgb( 31, 71, 120 ) 64%);
  16. background-image: -ms-linear-gradient(bottom, rgb(69, 132, 180) 28%, rgb( 31, 71, 120 ) 64%);
  17. }
  18.  
  19. #world {
  20. background-color: rgba(255, 0, 0, .2);
  21. }

Vendor prefixes

I’m so used to Chrome being the “latest and greatest” that I honestly expected to be able to use non-prefixed CSS properties and have the code “just work”. That’s NOT the case. As of this writing you will need to use prefixed properties, so add the following prefixes into the appropriate rules:

  1. #viewport {
  2. perspective: 400;
  3. -webkit-perspective: 400;
  4. -moz-perspective: 400;
  5. -o-perspective: 400;
  6. }
  7.  
  8. #world {
  9. transform-style: preserve-3d;
  10. -webkit-transform-style: preserve-3d;
  11. -moz-transform-style: preserve-3d;
  12. -o-transform-style: preserve-3d;
  13. }

Help, my javascript code doesn’t work!

You probably put your javascript in the <head> tag, which means that

  1. document.getElementById( 'world' )

will not work because the elements don’t exist yet. Put the script at the end right before the </body> tag and it should work if everything else is correct.

Besides, it’s just good practice to put your javascript last.

Help, my javascript code doesn’t work! (pt 2)

This just shows my ignorance of javascript, but if something still isn’t working, you might have this problem:

Javascript uses the \ character in your strings to tell the parser to treat the next line as if the string continued:

  1. 'translateZ( ' + d + 'px ) \
  2. rotateX( ' + worldXAngle + 'deg) \
  3. rotateY( ' + worldYAngle + 'deg)';

Is the same as:

  1. 'translateZ( ' + d + 'px ) rotateX( ' + worldXAngle + 'deg) rotateY( ' + worldYAngle + 'deg)';

Zooming javascript

The code samples in the original tutorial omit the code to zoom in and out with the mouse wheel. Here it is in all it’s javascripty wonderfulness:

  1. window.addEventListener( 'mousewheel', onContainerMouseWheel );
  2. window.addEventListener( 'DOMMouseScroll', onContainerMouseWheel );
  3.  
  4. function onContainerMouseWheel( event ) {
  5. event = event ? event : window.event;
  6. d = d - (event.detail ? event.detail * -5 : event.wheelDelta / 8);
  7. updateView();
  8. }

2. Adding objects to our world

CSS 3D Clouds Step 2
E.g. .cloudBase.

Create cloud base code is incorrect

Instead of:

  1. for( var j = 0; j <<; 5; j++ ) {

the correct line is:

  1. for( var j = 0; j < 5; j++ ) {

Actual random numbers and prefixed transforms

The random numbers for createCloud():

  1. var random_x = 256 - ( Math.random() * 512 );
  2. var random_y = 256 - ( Math.random() * 512 );
  3. var random_z = 256 - ( Math.random() * 512 );

The transform styles for createCloud()

  1. div.style.transform = t;
  2. div.style.webkitTransform = t;
  3. div.style.MozTransform = t;
  4. div.style.oTransform = t;

3. Adding layers to our objects

CSS 3D Clouds Step 3
There were a couple of things in this section that cause me to scratch my head and go whyyyyy?

Code for random generation and transforms.

Random variables:

  1. var random_x = 256 - ( Math.random() * 512 );
  2. var random_y = 256 - ( Math.random() * 512 );
  3. var random_z = 100 - ( Math.random() * 200 );
  4. var random_a = Math.random() * 360;
  5. var random_s = .25 + Math.random();
  6. random_x *= .2; random_y *= .2;

Vendor transforms:

  1. cloud.style.transform = t;
  2. cloud.style.webkitTransform = t;
  3. cloud.style.MozTransform = t;
  4. cloud.style.oTransform = t;

Why don’t I see the new squares?

You have to add in the style for .cloudLayer into your CSS:

  1. .cloudLayer {
  2. position: absolute;
  3. left: 50%;
  4. top: 50%;
  5. width: 256px;
  6. height: 256px;
  7. margin-left: -128px;
  8. margin-top: -128px;
  9. background-color: rgba( 0, 255, 255, .1 );
  10. -webkit-transition: opacity .5s ease-out;
  11. -moz-transition: opacity .5s ease-out;
  12. -o-transition: opacity .5s ease-out;
  13. }

I see the cloud layers, but why are they are all flat?

Yeah, this got me too, the parent div’s need to have preserve-3d, so add this into your CSS:

  1. #world div {
  2. transform-style: preserve-3d;
  3. -webkit-transform-style: preserve-3d;
  4. -moz-transform-style: preserve-3d;
  5. -o-transform-style: preserve-3d;
  6. }

4. Making the 3D effect work

CSS 3D Clouds Step 4

This section is essentially “make the layers point at the camera”. You still want them projected into the same locations, but you want them to always face the camera, giving you that sense of “volume” effect.

Vendor Transforms and Update()

First, here’s all the vendor transforms:

  1. layer.style.transform = t;
  2. layer.style.webkitTransform = t;
  3. layer.style.MozTransform = t;
  4. layer.style.oTransform = t;

Now, you also need to call this update manually once right before the end of your script. So right before the closing script tag, make sure you call this:

  1. update();

Render Loop

Finally, even if you do this, you’ll notice that your layers still don’t point at the camera. You need to add in a function that loops and updates the layers in the #viewport at regular intervals. You could add a call to the update function inside your mouse move event, but we’ll need the loop to get the rotation to work in the next step, so it’s better if you just do this now.

  1. (function() {
  2. var lastTime = 0;
  3. var vendors = ['ms', 'moz', 'webkit', 'o'];
  4. for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
  5. window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
  6. window.cancelRequestAnimationFrame = window[vendors[x]+
  7. 'CancelRequestAnimationFrame'];
  8. }
  9.  
  10. if (!window.requestAnimationFrame)
  11. window.requestAnimationFrame = function(callback, element) {
  12. var currTime = new Date().getTime();
  13. var timeToCall = Math.max(0, 16 - (currTime - lastTime));
  14. var id = window.setTimeout(function() { callback(currTime + timeToCall); },
  15. timeToCall);
  16. lastTime = currTime + timeToCall;
  17. return id;
  18. };
  19.  
  20. if (!window.cancelAnimationFrame)
  21. window.cancelAnimationFrame = function(id) {
  22. clearTimeout(id);
  23. };
  24. }())

Lets break this down. I discovered that this function is a polyfill for the browser animation spec here one Paul Irish’s awesome blog http://paulirish.com/2011/requestanimationframe-for-smart-animating/. Previously, when you would animate something, you would set a timer, and every few milliseconds go and update move something from point A to point B on the screen with a small increment. In order to get smoother animations, the browsers are starting to support this requestAnimationFrame function that allows several changes to be made, and update everything with a single reflow / redraw of the screen. This becomes especially handy when you are updating multiple elements on the screen and you want a clean responsive display. It also means that the browser can stop animating when you switch tabs, which means that you don’t eat up battery when someone isn’t looking at your page :)

All you really need to know is that this creates a function on the javascript window object that tells the browser to “please render an animation frame, and call back to this function when you are done and ready to render the next frame”.

5. Final words

CSS 3D Clouds Step 5

Subtle Rotating

Not mentioned, but if you want the clouds to slowly rotate like the demo, you need to add in the rotate z component into the transform update of your layers like so:

  1. 'rotateZ( ' + layer.data.a + 'deg ) /

And, you need to add in a speed property into your cloud layers when you create them:

  1. speed: .2 * Math.random() - .1

Adding Cloud Images

Instead of this:

  1. var cloud = document.createElement( 'div' );

Use this (or find your own cloud .png, it should be transparent to work properly)

  1. var cloud = document.createElement( 'img' );
  2. cloud.style.opacity = 0;
  3. var src = 'http://www.clicktorelease.com/tutorials/css3dclouds/cloud.png';
  4. ( function( img ) {
  5. img.addEventListener( 'load', function() {
  6. img.style.opacity = .8;
  7. } )
  8. } )( cloud );
  9. cloud.setAttribute( 'src', src );

And finally to remove all the debug styles remove the following lines out of your CSS:

From #world remove:

  1. background-color: rgba(255, 0, 0, .2);

From .cloudBase remove:

  1. background-color: rgba( 255, 0, 255, .5 );

From .cloudLayer remove:

  1. background-color: rgba( 0, 255, 255, .1 );

That should cover it! Now go make some happy clouds.

Credits

Everything here was completely taken from the Click To Release CSS 3D Clouds tutorial and expanded to include the missing parts.

Building a REALLY simple WCF P2P application

Often times when I’m looking at playing with a new technology that it becomes extremely difficult to find a simple stripped down easy-to-use chunk of code that also walks through, in-depth, the concepts and reasoning behind the code. This particular code chunk began as I started exploring the Microsoft WCF’s P2P networking services and found a rather distinct lack of code that explained the hows and whys of building a Peer to Peer network.

P2P Basics

Ok. Low level building blocks.

First, everybody (who’s interested in P2P) should already understand the client server paradigm, if not, there are many wonderfully detailed articles to explain the details. In short we have N clients all connected to 1 server. Client A sends a message to the server, the server decides what to do, and then may or may not send a response to Client A and / or Client B, Client C… etc… In a peer to peer network on the other hand, everyone is the client, everyone is a server. Because of this, the client / server naming scheme goes away by popular vote and everyone is called a node or a peer. When a node is connected to other nodes that whole group is called a mesh (or graph, or cloud).

Now, in a pure P2P network there is no central authority to help or govern how nodes find each other to form a mesh or how meshes are initially created.  Every node is connected to some number of other nodes, which are then connected to more nodes and so on. When one node wishes to communicate with another node (or nodes) the message is first passed on to the nodes that the first node knows about. These nodes in turn pass along the message on to other nodes that they know about and so on until finally everybody has seen the message.

One of the best, and probably most used, examples of a peer to peer network is the chat room. Until someone creates it, the chat room does not exist, but once it’s created people can be invited, join, and send messages that appear on everybody else’s screen. Even if the original person leaves the chat room, the room still exists as long as there are participants logged in. Once the last person leaves the chat room no longer exists.

Ping – The P2P Application

Note: I really dislike configuration files in demos or tutorials unless it’s a large application or showing how a particular aspect of a configuration file works. The fact that I can tell a static factory to build me something with a string name that corresponds to another file that somehow gets found, loaded, and happens to reference compiled type that then has a hidden class generated that implements that interface and is passed, bugs me when I’m trying to learn something.

If your going to follow along with this, your going to need .NET 3.5 installed and be running XP SP3, Vista, Win7 or Server 08. Visual Studio doesn’t hurt either.

To set up your project crack open Visual Studio and spin up a new Console Application, call it SimpleP2PExample. Once you have that open go over to the project, right click and Add Service Reference to System.ServiceModel, this allows you to use .NET’s WCF stuff in your app. You can choose to split up each class or interface into its own file or not: Up to you.

IPing
  1. //Contract for our network. It says we can 'ping'
  2. [ServiceContract(CallbackContract = typeof(IPing))]
  3. public interface IPing
  4. {
  5. [OperationContract(IsOneWay = true)]
  6. void Ping(string sender, string message);
  7. }

Alright, first of all, attributes. If you don’t know what they are, then here’s the low down mouthful one line explanation:

Attributes are essentially binary metadata associated with a class, method, property or whatever that provides additional information about whatever it’s “Decorating”.

The first attribute is the service contract. Wait a second. Contracts.

In our node-talking-to-other-nodes scenario, somehow they have to know how to talk to each other, if I asked what the size of the door was and you handed me a window, I have NO idea what that means or what that represents. A contract defines exactly what I’m telling you, what I’m expecting back, how, and when.

In this case we’re defining a contract that has one operation, a method called Ping. We know that when node A talks to node B that if node A says “Hey, Ping(“MyName”, “Hello.”) to Node B that node B will know what to do with that and how to pass it along to other nodes. It’s also specifies that I don’t expect Node B to give me anything back.

Now, the implementation.

PingImplementation
  1. //implementation of our ping class
  2. public class PingImplementation : IPing
  3. {
  4. public void Ping(string sender, string message)
  5. {
  6. Console.WriteLine("{0} says: {1}", sender, message);
  7. }
  8. }

Fairly simple, whenever we receive a ping from another node, this method will be executed.

The Peer Class

Alright, now the fun, magic, and games begin. We’re going to create a class called peer, which will contain all our service start / stop code and also hold our implementation of PingImplementation.

Peer
  1. public class Peer
  2. {
  3. public string Id { get; private set; }
  4.  
  5. public IPing Channel;
  6. public IPing Host;
  7.  
  8. public Peer(string id)
  9. {
  10. Id = id;
  11. }
  12. }

In order to identify an individual node in the network, so that we know who’s who and don’t get everything mixed up, it’s customary to have a unique Id that’s assigned to the peer. Now, we have two IPing variables, the best way to describe them would be incoming and outgoing. An instance of the PingImplementation class will go in Host since it will be receiving any incoming communication from other nodes; The Channel is used to communicate out to other nodes and is built up via a factory.

Peer
  1. public void StartService()
  2. {
  3. var binding = new NetPeerTcpBinding();
  4. binding.Security.Mode = SecurityMode.None;
  5.  
  6. var endpoint = new ServiceEndpoint(
  7. ContractDescription.GetContract(typeof(IPing)),
  8. binding,
  9. new EndpointAddress("net.p2p://SimpleP2P"));
  10.  
  11. Host = new PingImplementation();
  12.  
  13. _factory = new DuplexChannelFactory(
  14. new InstanceContext(Host),
  15. endpoint);
  16.  
  17. var channel = _factory.CreateChannel();
  18.  
  19. ((ICommunicationObject)channel).Open();
  20.  
  21. // wait until after the channel is open to allow access.
  22. Channel = channel;
  23. }
  24. private DuplexChannelFactory<IPing>; _factory;

This is what we will use to start the peer.  This is the part where I’ve built up what could have been done in the configuration file with code instead.

Lets take it from the top.  First off, we have our binding; this defines what communication protocol we are going to be using, and as this is a PeerToPeer app… we use NetPeerTcpBinding().  You’ll also notice that in the next line I set the security mode to none; this is done for simplicities sake. There’s three types of security modes, including None, Message, Transport and TransportWithMessageCredential. Its a bit beyond the scope of this post, but Message security ensures that the message was not tampered with as it was passed from peer to peer, Transport security ensures that the connection between nodes is secure, and TransportWithMessageCredential does both.

Now, our application needs an endpoint, essentially, an service endpoint is a set of information that is exposed outside of the application (in this case on the network as well) so that others can access it. The endpoint defines the address it can be reached at, the contract, and the method that should be used to communicate. In this case, we build up our endpoint by using ContractDescription.GetContract to generate a contract class off of our IPing interface, our network type binding, and an endpoint address where this endpoint can be reached.

Finally, we create a new instance of our PingImplementation class as the Host, and we create our channel factory. A DuplexChannelFactory allows for two way communication, the first parameter is the object that you want to receive incoming calls, and the endpoint is where those calls are coming from. The factory then creates the channel and a whole bunch of magical things happen.

If you’ll remember, our channel is of type IPing, the Duplex Factory performs some magic and generates a concrete implementation of your interface (it also implements ICommunicationObject, which is why you’ll sometimes see people create another interface called something like “IPingChannel : IPing, ICommunicationObject”, it does make it so that you don’t have to cast it, but for the purpose of this post it’s not necessary). Imagine that it takes your interface, implements all the methods and properties with all the cool DuplexChannel code needed to talk back and fourth, creates an instance, and returns it to you.

Finally, I call open on my channel to let the world see that my brand new channel and endpoint are ready for business.

Peer
  1. public void StopService()
  2. {
  3. ((ICommunicationObject)Channel).Close();
  4. if (_factory != null)
  5. _factory.Close();
  6. }

Now, it’s all well and good, until your done. Then you need to close you channel and factory, this should be pretty self explanatory at this point.  Remember our channel is an ICommunicationObject in addition to being a IPing object, so we cast and close, then check to see if our factory is null, and if not, close that as well.

Threading The Peer Class

Something I chose to do was make the peer threaded. This allows me to drop it into an application, in a thread, and receive and push stuff into it at my leisure. To do this I add in a:

Peer
  1. private readonly AutoResetEvent _stopFlag = new AutoResetEvent(false);

This will allow me to block a method of the thread until I decide fire it (When I stop the peer).

Peer
  1. public void Run()
  2. {
  3. Console.WriteLine("[ Starting Service ]");
  4. StartService();
  5.  
  6. Console.WriteLine("[ Service Started ]");
  7. _stopFlag.WaitOne();
  8.  
  9. Console.WriteLine("[ Stopping Service ]");
  10. StopService();
  11.  
  12. Console.WriteLine("[ Service Stopped ]");
  13. }
  14.  
  15. public void Stop()
  16. {
  17. _stopFlag.Set();
  18. }

The run method embodies the lifecycle of this peer. When the peer thread starts into the run method it will start the service, wait until the stop flag is fired (when the Stop() method is called), and then stop and dispose the service.

Putting It All Together
Program
  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Count() <= 1)
  6. {
  7. for (int i = 0; i < 4; i++)
  8. {
  9. Process.Start("SimpleP2PExample.exe");
  10. }
  11. }
  12.  
  13. new Program().Run();
  14. }
  15.  
  16. public void Run()
  17. {
  18. Console.WriteLine("Starting the simple P2P demo.");
  19.  
  20. var peer = new Peer("Peer(" + Guid.NewGuid() + ")");
  21. var peerThread = new Thread(peer.Run) {IsBackground = true};
  22. peerThread.Start();
  23.  
  24. //wait for the server to start up.
  25. Thread.Sleep(1000);
  26.  
  27. while (true)
  28. {
  29. Console.Write("Enter Something: ");
  30. string tmp = Console.ReadLine();
  31.  
  32. if (tmp == "") break;
  33.  
  34. peer.Channel.Ping(peer.Id, tmp);
  35. }
  36.  
  37. peer.Stop();
  38. peerThread.Join();
  39. }
  40. }

From top to bottom, the Main method of the application checks to see if it’s the first one of this application to have started up, if it its, then it starts four additional processes (Note that if you called your project something other than SimpleP2PExample, you will need to replace the the string in Process.Start to be the name as the executable file your project generates).

The run method is also fairly simple, it creates a new instance of the Peer class, assigns it a GUID, creates a thread for the peer’s run method, starts up the thread and pauses to wait for the peer’s thread to start.  We then enter a loop until the user presses enter without inputting any text. Any text that is put in is transmitted over the peer channel using the peer’s id and the message. Once we’ve finished, we stop the session and wait for the peerThread to exit and join back up with the main thread. We then exit.

Wrap Up

I hope this helps someone out there get a better understanding of the basic concepts of a simple Peer to Peer application. Feel free to leave feedback!

Paul Rohde

WCF Manual Service Hosing on Windows Vista and Windows 7

With the new security features introduced in Windows Vista and now in Windows 7 there are some, not so obvious, problems that have crept in and cause weird errors in even simple code. I was building a simple web service for the first time a simple HelloWorld in a console application to make it easy to debug and output trace information. Nothing complicated, a little different because I was configuring everything manually in code as opposed to using configuration file. Here’s the code for my simple, stripped down HelloWorld service:

ConsoleServer.cs
  1.  
  2. using System;
  3. using System.ServiceModel;
  4.  
  5. namespace ConsoleServer
  6. {
  7. class Program
  8. {
  9. static void Main(string[] args)
  10. {
  11. Console.Write("Server...");
  12.  
  13. ServiceHost serviceHost = new ServiceHost(typeof(HelloWorldService),
  14. new Uri("http://localhost:9000/TestService"));
  15.  
  16. serviceHost.AddServiceEndpoint(
  17. typeof(IHelloWorldService),
  18. new WSHttpBinding(),
  19. "");
  20.  
  21. serviceHost.Open();
  22.  
  23. Console.WriteLine("Started");
  24.  
  25. Console.ReadLine();
  26. }
  27. }
  28.  
  29. //operation contract
  30. [ServiceContract]
  31. public interface IHelloWorldService
  32. {
  33. [OperationContract]
  34. string HelloWorld();
  35. }
  36.  
  37. public class HelloWorldService : IHelloWorldService
  38. {
  39. public void HelloWorld()
  40. {
  41. System.Threading.Thread.Sleep(1000); //sleep for one second
  42. return "Hello World Service";
  43. }
  44. }
  45. }
  46.  

And the client:

ConsoleClient.cs
  1.  
  2. using System;
  3. using System.ServiceModel;
  4. using ConsoleServer;
  5.  
  6. namespace Client
  7. {
  8. class Program
  9. {
  10. static void Main(string[] args)
  11. {
  12. Console.WriteLine("Client");
  13.  
  14. ChannelFactory<IHelloWorldService> myChannelFactory =
  15. new ChannelFactory<IHelloWorldService>(
  16. new WSHttpBinding(),
  17. new EndpointAddress
  18. ("http://localhost:9000/TestService"));
  19. IHelloWorldService wcfClient = myChannelFactory.CreateChannel();
  20.  
  21.  
  22. System.Threading.Thread.Sleep(3000);
  23. Console.WriteLine("Calling Hello World");
  24. for (int i = 0; i < 5; i++)
  25. {
  26. Console.WriteLine(wcfClient.HelloWorld());
  27. Console.WriteLine("- Called HelloWorld");
  28. }
  29.  
  30. Console.WriteLine("Done");
  31.  
  32. Console.ReadLine();
  33.  
  34.  
  35. }
  36. }
  37. }
  38.  

The code is fairly straight forward as far as services go, running it however I began getting the following error:

HTTP could not register URL http://localhost:9000/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details).

Extremely unhelpful, and the link provided by Microsoft offers no solutions (insert eye roll here) so I went off to consult Google… After a bit of research I discovered that it was the security features in Window 7 and Windows Vista that had been causing the problem, mostly because I’m trying to do everything manually in code some of the permission requests or other behind the scenes magic that normally occurs when Visual Studio 2008 creates and hosts a service from an application configuration file don’t happen. (My guess is that when visual studio installs it sets up permissions for Cassini, it’s inbuilt web server, and that when you run your service the ‘normal’ way that it automatically wraps your service in Cassini, effectively bypassing the normal application security measures, but that’s another story). Long and the short of it is that if you want to do this yourself you need to add some permissions to your user (by default even administrator accounts in Windows 7 and I *think* Windows Vista run in a restricted mode) to allow you to register your service with windows. (The original article is here)

Run a Command Prompt with Administrator privileges (Actually right click and select it), type and run the following command (replace the port number with whatever port you are using, 9000 for the code above, and your domain(or computername if your not on a domain) and username).

netsh http add urlacl url=http://+:8000/ user=DOMAIN\UserName

And *BAM* everything magically works. Cool huh?

– Paul Rohde