Pages

Banner 468

Wednesday 22 June 2011

HTML 5 & CSS 3

0 comments
 
This weeks topics are the much anticipated HTML5 and CSS3 specifications, the next generation in web page markup and styling.

Introduction

HTML5 is the successor to HTML4 which came out way back in 1999. Back then the internet was a very different place where notions such as web applications, e-commerce and social networking were yet unheard of. The web has changed a lot since then but the fundamental technology used to build it hasn't, and over the years its limitations were becoming ever more apparent where web designers were stretching HTML to its absolute limits, hacking it into submission.  Thankfully, in 2006, the Web Hypertext Application Technology Working Group (WHATWG) and the World Wide Web Consortium (W3C) - both of which were working on separate specifications - decided to cooperate to create HTML5. The principles behind HTML5 (as stated on w3schools.com) are:
  • New features should be based on HTML, CSS, DOM and Javascript
  • Reduce the need for external plugins such as flash
  • Better error handling
  • More markup to replace scripting
  • HTML5 should be device independent
  • The development process should be visible to the public 

Implementing HTML5

HTML5 is still a work in progress but W3C have announced that it will be complete by 2014. Since HTML5 is not yet an official standard, no browser has full HTML5 support, however, most major browsers continue to add support for HTML5 with every release. This means that we can (and are encouraged to) start using HTML5 features today.  HTML5 builds on the previous specification so drastic changes to existing markup is not required to start using some of the new features. HTML5 markup also makes websites more search engine friendly, can help improve accessibility and given that all the major browsers largely support the syntax, the business cost for adopting HTML5 is almost negligible.

So, What's new in HTML5?

HTML5 is loaded with new features aimed at improving user experience over the web.  It's a collection of various small improvements that collectively help web designers create something special.  Here are some the most noticeable features in HTML5:
  • A <canvas> element that allows for dynamic rendering of 2D shapes and images on web pages
  • Content specific elements (such as header and article) to improve web page semantics
  • Support for audio and video playback
  • New form controls for better input validation
  • Improved support for local storage (based on databases rather than cookies)
One of my favorite has to be the set of new form controls.  In contrast to HTML4 where we had the generic textbox, HTML5 gives us input controls for: email, URLs, numbers, ranges, dates, search boxes, even colour!    These controls will drastically improve the way user input is currently validated.  Client-side input validation in HTML4 was always a headache and in most cases only cosmetic since it was largely based on javascript which could be disabled at any time by the end user.  With these new controls however, these basic validations will be carried out by the browser itself, which means less javascript and more robustness.  This is not to say that we can do without server-side validation, far from it, but at least we are spared the cumbersome client-side equivalents.  Browser support for these new input types varies, however they can still be used since they will behave as normal text-boxes if they are not supported, which is brilliant.  That's the main thing about HTML5.  We do not need to wait for an official release date to start using HTML5 features, indeed there won't be such a date.  HTML5 is with us today, browser support is growing steadily so failing to embrace the new specification today, simply means being left behind.

What about Visuals? - Enter CSS 3

Cascading Style Sheets (CSS) are an integral part of web development adding layout and style to our HTML pages.  Way back in my very first post(s) I discussed CSS at length, highlighting how it can help us de-couple our web page content from its layout.  The current specification of CSS (2.1) is powerful but CSS 3 takes that power to a completely new level.  Just like HTML5, CSS 3 builds on its predecessor and is still under development by the W3C, however modern browsers already support most of the new properties introduced in CSS 3.  This means that we can start using CSS 3 today, just as we can HTML5.  There is one catch though.  Until CSS 3 specification is finalised, browsers are allowed to interpret a property any way they see fit.  These kind of properties are usually prefixed with a namespace (such as -moz- or -webkit-) to indicate that they are not yet standard.  To explain this better, let's take the new "border-radius" property as an example.

CSS 3 supports adding rounded corners to objects, something which was previously only (painstakingly) possible using images.  Suppose we wanted to add a border with rounded corners to every "<div>" element on our website.  Here's what the CSS 3 style rule would look like:

   div {
      border: 1px solid black;
      -moz-border-radius: 5px;
      -webkit-border-radius: 5px;
      border-radius: 5px;
   }

The first line in the rule simply sets a solid black border around our "<div>" element.  The next 3 lines all state that the border should have rounded corners, each 5 pixels in radius.  Why do we have 3 lines that seemingly state the same thing?  "border-radius" is the proper name of this new CSS 3 property and this is the name that will stick once the CSS 3 specification is finalised.  "-moz-border-radius" is the Mozilla (Firefox) team's interpretation of how the property should be implemented, while the "-webkit-border-radius-" property is the Webkit (Safari, Chrome) team's interpretation. It is important to note that the proper name of the property should always be defined after it's 'non-standard' counterparts such that it is the one that takes precedence.  This will ensure that your stylesheet is forward-compatible i.e. newer browsers that support the standard property will in fact apply the standard one as it always takes precedence, without you having to constantly update your stylesheet.  Furthermore, older browsers can still apply the non-standard version of the property as they have no knowledge of the standard name!  As a matter of fact, at the time of writing, all the latest versions of the major browsers including Internet Explorer, Chrome, Safari and Opera, now support the standard version of "border-radius".  However,  if you want to test this behavior out, try the "border-image" property.

Here's a list of the most common prefixes for CSS 3 properties which are not yet standard:

PrefixBrowser
-ms-Internet Explorer 9
-moz-Firefox
-webkit-Safari, Chrome
-o-Opera

Other Features

There's lots more to CSS 3 than fancy borders, much more in fact. Here are some of the more exciting features of CSS 3:

  • Fonts - you can now use any font you like on your webpage rather than sticking to web-safe fonts;
  • 2D and 3D Transformations;
  • Transitions; and
  • Animations

Fonts

How many times have you resorted to images just so that you could use a particular font for your website logo or headings, sacrificing flexibility for looks.  With CSS 3 this is no longer an issue, simply upload your chosen font to your website and it will be automatically downloaded as required.  Now you can have the looks, the flexibility and better accessibility on your website, neat.


Transformations

In CSS 3 we can apply 2D and 3D transformations to any element on our web page including:

  • Translation (move)
  • Rotation
  • Scaling (re-sizing)
  • Skewing
  • Matrix (any combination of the above)
At the moment, 2D transformations enjoy more browser support than 3D transformations.  In fact, at the time of writing, all major browsers support 2D transformations while only Safari and Chrome have support for 3D transformations.  Here are some examples followed by the CSS 3 styles used:

Examples of CSS 3 2D Transformations (as viewed in Google Chrome)

div{
   background-color:#F5F5F5;
   border:solid 1px black;   
   width:100px;
   height:100px;
   margin:30px;
   float:left;
   text-align:center;
   font-family:arial;
   line-height:30px;
   -webkit-border-radius:5px;
   -moz-border-radius:5px;
   border-radius:5px;
   -webkit-box-shadow: 5px 5px 12px cyan;
   -moz-box-shadow: 5px 5px 12px cyan;
    box-shadow: 5px 5px 12px cyan;
}
 
.rotate{
   -ms-transform:rotate(45deg);
   -moz-transform:rotate(45deg);
   -webkit-transform:rotate(45deg);
   -o-transform:rotate(45deg);
   transform:rotate(45deg);
}
 
.scale {
   -ms-transform:scale(1.5,1.5):
   -moz-transform:scale(1.5,1.5);
   -webkit-transform:scale(1.5,1.5);
   -0-transform-scale(1.5,1.5);
   transform:scale(1.5,1.5);
}
 
.skew {
   -ms-transform:skew(20deg, 15deg); 
   -moz-transform:skew(20deg, 15deg);
   -webkit-transform:skew(20deg, 15deg);
   -o-transform:skew(20deg, 15deg);
   transform:skew(20deg, 15deg);
}

All three <div> elements in this example have the same basic style: i00 pixels square, have a light grey background and a thin black border. I also added the new CSS 3 properties "border-radius" and "box-shadow". "Border-radius" we've already seen, "box-shadow" on the other hand is another border-related CSS 3 property that creates a drop-shadow around your elements by specifying X and Y offsets (how far you want the shadow to 'drop') and shadow distance - how soft/precise it is.

Each of the <div> elements however implements a different class according to the desired transformation. The rotate transformation rotates the element around its centre by the specified number of degrees. The scale transformation takes two parameters one for the width and another for the height. In this case the div is enlarged by a factor of 1.5 along both axis. Similarly the skew transformation takes two angles as parameters (for the x-axis and y-axis) and skews the object accordingly.

3D transformations work in a similar way, this time taking parameters across three dimensions, (X, Y and Z). You could also specify perspective properties and transformation origin in 3D transformations. However, I want to turn my attention to one of my personal favorites: Animation.

CSS 3 Animation

Until recently, the only way to add animations to your website was by using animated gifs or plugins such as Flash.  If you were really brave you could also animate using javascript - not for the feint hearted.  This led to all sorts of inconveniences such as lack of flexibility, accessibility and compatibility. Now we can add animations to our website "natively" using CSS 3. Let's take a simple example, try hovering over any of the columns below using Chrome or Safari:














Whenever the mouse hovers over any one of the columns, the column expands for a short period of time and goes back to its original size. This effect is created using CSS 3 keyframe animation which is currently only supported by webkit browsers. Here's how it's done:

a.anim{
    display:block;
    text-decoration:none;
    width:150px;
    height:120px;
    padding-top:80px;
    text-align:center;
    margin:1px;
    background:url(http://www.w3.org/html/logo/downloads/HTML5_Logo_64.png) no-repeat #F5F5F5 50% 10px;
    border:solid 1px black;
    float:left;
 }

 a:hover{
    /* Animate */
    -webkit-animation-name:grow;
    -webkit-animation-duration: .4s;
    -webkit-animation-iteration-count: 1;
    -webkit-animation-timing-function: ease-in-out;

    /* Forward Compatibility */
    animation-name:grow;
    animation-duration: .4s;
    animation-iteration-count: 1;
    animation-timing-function: ease-in-out;

 }
 
 /* Define the Animation */
 @-webkit-keyframes grow {
    0%   {-webkit-transform: scale(1,1);}
    50%  {-webkit-transform: scale(1.2, 1.2);}
    100% {-webkit-transform: scale(1, 1);}

 @keyframes grow { /* forward compatibility */
    0%   {transform: scale(1,1);}
    50%  {transform: scale(1.2, 1.2);}
    100% {transform: scale(1, 1);}

 }



Ok, so our three columns are in fact three anchor elements styled to look like columns, nothing new here. The animation is triggered by the "a:hover" selector where we specify:

  • The name of the animation to trigger: "grow" in this case;
  • How long the animation should take;
  • How many times the animation should run: once in this case
  • The timing/easing function which adds a more organic feel to the animation

Easing adds smoothness to our animation. In this case the easing function is set to "ease-in-out" which means that the animation start slowly, accelerate towards the middle and slow down again at the end. The final part is the animation definition itself which is based on three keyframes. Each keyframe applies a scale transformation to change the size of the object being animated over time. Animations must have at least two keyframes, one for the begining (0% or 'from') and one for the end (100% or 'to'), but you can have as many keyframes as you like between these two. In this case the animation is pretty simple so one additional keyframe set at the middle of the animation (50%) is enough to get the desired effect.  Of course you could add all sorts of effects to your animation such as changing colours, borders, shadows... you name it.  

Summing Up

Presenting all there is to know about HTML5 and CSS 3 in a single blog post is a ridiculous proposition, the subject is as vast as it is exciting - and it's still evolving. What strikes me the most is the fact that HTML5 and CSS 3 bring so much to web development and asks very little in return in terms of learning effort. If you know HTML you know HTML5, same goes for CSS 3. They are not new technologies but rather extensions to what we're already used to, and yet they bring so much more (power) to the table. I've never experienced anything like it with any other language I've used so far. The fact that all the major players in the software industry including Apple, Google and more recently Microsoft, have committed themselves to HTML5 is further testament to its significance to web development and beyond.
Readmore...
Saturday 18 June 2011

More LSL

0 comments
 
My last post was all about Second Life's Linden Scriptng Language (LSL) and how to add LSL scripts to our objects. We built a simple elevating platform that moved along the z-axis when touched by an avatar. This week I will continue building on this example, introducing new LSL concepts along the way.

Inter-Object Communication


Currently, our elevator starts moving after being touched by an avatar but this is not very realistic. Most elevators move when someone presses a call button and I want to replicate this behavior on my virtual counterpart. The first thing I need is a call button. Since the aim of this blog is to demonstrate LSL rather than creating beautifully crafted objects a simple prim will do as a call button. I need to add a script to my call button to notify my elevator that it should start moving. One way of doing this is to broadcast a message over a specific channel and set the elevator to listen to messages coming from that channel. Here's the button's script:

default
{
    state_entry()
    {
    }

    touch_start(integer total_number)
    {
        llSay (1360, "elev-mov");
    }
    
}

Pretty simple. All the script does is broadcast the "elev-mov" message over channel 1360 whenever the object is touched. We now need to configure our elevator to listen for this message:

default
{
    state_entry()
    {
        llListen(1360, "es1",NULL_KEY, "");
        ...
        ...
        ...
    }
    
     listen(integer channel, string name, key id, string message)
    {
        if (channel == 1360 && name="es1" && message == "elev-mov")
        {
            state moving;
        }
        
    }


The first line in the state_entry script for the default state sets the object to listen to any messages coming in on channel 1360 from an object named "es1" ("es1" is the name I gave the call button). I could also configure the object to listen for messages coming from another object that has a specific Universally Unique Identifier (UUID)but I must admit I haven't yet found a way to do this reliably. Our elevator is now set to listen for messages coming from the call button. We now need to take action on those messages. To do this we add a 'listen' event to our default state script and add the required code. In this case the elevator checks the channel (1360), source (call button) and message and starts moving. You might notice that using this technique, your object could be configured to listen for messaged from multiple objects over multiple channels and react accordingly. I'm not too sure about performance though.

Linking Objects

So now we have a platform that moves when the call button is 'pressed', but it's only a platform. What if we wanted to add 'walls' to this platform to make it look more like an actual elevator. Simply placing these walls on top of the platform will not make them move with it when the call button is pressed! Here's where linking objects comes in handy. To link the walls to the floor hold down the shift key and click on the walls and floor in succession to select all the objects. It is important to select the floor last and I will explain why in a minute. After selecting all the objects click the 'Link' button in the "Build Toolbox" to link the objects together. Now when the call button is pressed, the walls will move together with the platform for a more realistic looking elevator. This will not work unless the floor was selected last when linking the objects because the floor's script would not be set as the parent script of the group.

Final Thoughts

That's it for this week and for my coverage of Second Life. There's much more to Second Life and Linden Scripting Language than I have covered over the past couple of posts, in fact I've just barely scratched the surface. The fact that there's much to discover in Second Life is, for me, beside the point. The real issue for me is how willing am I to scratch below the surface and dig deeper into this virtual world. The answer I'm afraid is I'm not. Although I can appreciate the effort it took to create such a world and admire the vision behind it I was sincerely let down by the whole experience. Second life looks dated (most places I've been to anyway) and feels sluggish. I'm running this on a Core i5 processor and a GeForce GTS 250 graphics card over a 10 megabit connection but it still feels slow. I don't want to sound too negative here, as I said I do admire the vision behind it and what can be achieved within it but I'm afraid that I will not log-back into it any time soon.
Readmore...
Saturday 4 June 2011

LSL - Objects that Respond to Commands

0 comments
 
Welcome back. Today’s post is all about the Linden Scripting Language and how we can use LSL to make objects respond to simple commands. As with any form of programming, the best way to explain LSL concepts is through practical examples, so I've chosen to build a simple elevator. The elevator will respond to “Touch” events by move vertically between pre-defined minimum and maximum z-axis values.

In order to focus on the actual scripting, I will not spend too much time building and fiddling with the design of the elevator. A simple rectangular platform will do nicely for this example.

Adding a Script

The first thing to do is to add an actual script to our platform. To do this, go to the “Content” tab of the build toolbox and click the “New Script” button. Double-click the newly added script object to open the script editor which should contain the following default script:

default
{
   state_entry()
   {
      llSay(0, "Hello, Avatar!");
   }

   touch_start(integer total_number)
   {
      llSay(0, "Touched.");
   }
}  

States and Events

LSL is an event-driven language based on finite state machines. This means that every object in second life can have a pre-defined number of states and can transition from one state to another by reacting to events. All objects must have at least one state, the default state which is was we can see in the listing above – defined by the ‘default’ keyword. This script also contains two event handlers: ‘state_entry’ and ‘touch_start’. ‘State_entry’ is called whenever the object enters the current (in this case default) state, which in turn calls the LSL pre-defined ‘llSay’ function which basically broadcasts the “Hello Avatar!” message on channel 0, the public channel. On the other hand, ‘touch_start’ is triggered whenever the object is touched while in the default state, broadcasting “Touched” on the public channel.

Building our Elevator script


Going back to our example, our elevator can be in either one of two states: stationary (default) or moving. We want our elevator to start moving when it’s touched and we want it to stop moving when it gets to the target position. Here’s the basic skeleton for our script:

default
{
   state_entry()
   {
      //Determine the next Target position based on the current position
   }
   
   touch_start(integer total_number)
   {
      //Go to the moving state
   }
}

state moving
{
   state_entry()
   {
      //Start Moving and stop when target is reached
   }
}

We need four global variables to store values for the minimum and maximum Z-axis positions, the speed at which the elevator should move and the target position (up or down). These variables are placed at the very top of the script and given their default values. When entering the default state we want to set the target position according to the current position. In other words, if the elevator is currently at the bottom, the target will be the top and vice-versa. We also want the elevator to enter the ‘moving’ state when an avatar touches it:

integer MinZ = 23;  // Minimum Z position (bottom)
integer MaxZ = 27;  // Maximum Z position (top)
integer DeltaZ = 1; // Rate of change of Z (speed)
integer TargetZ;    // Target  Z position

default
{
   state_entry()
   {
      vector position = llGetPos();
      if (position.z >= MaxZ) 
      {
         TargetZ = MinZ;
      }
      else
      {
         TargetZ = MaxZ;
      }
   }
   
   touch_start(integer total_number)
   {
      //Go to the moving state
      state moving;
   }
}

state moving
{
   state_entry()
   {
      //Start Moving and stop when target is reached
   }
}

At line 10 the script calls the llGetPos() function that returns the current position of our object as a vector. A variable of type vector holds three floating point numbers for X, Y and Z values which in this case are our object’s position in 3D space (in metres). The current Z position is then used to determine the elevator’s next target position.

Animating Movement

In the moving state we could of course set the elevator’s position to the current target but that would not be very realistic. An elevator does not simply jump from one floor to another, it gradually moves between floors until the target is reached. To replicate this effect we need some sort of animation to smoothly transition the elevator from the current position to the target. There are multiple ways of doing this but I decided to use a timer event to control movement. Let’s have a look at the code for the moving state:

state moving
{
   state_entry()
   {
      llSetTimerEvent(0.1);
   }
    
   timer()
   {
      vector position = llGetPos();
        
      if (position.z < TargetZ) //Moving Up
      {
         if (position.z + DeltaZ > TargetZ)
         {
            position.z = TargetZ;
         }
         else
         {
            position.z = position.z + DeltaZ; 
         }
      }
      else // Moving down
      {
         if (position.z - DeltaZ < TargetZ)
         {
            position.z = TargetZ;
         }
         else
         {
            position.z = position.z - DeltaZ;
         }
      }        
    
      llSetPos (position);  //Set the new position        
                
      if (position.z == TargetZ) // Target reached
      {
         llSetTimerEvent(0);  //Cancel the timer
         state default;            // Goto the default state
      }
        
    }
}

This code might look slightly complex but in actual fact it’s fairly straight forward. When the object enters the moving state it calls the ‘llSetTimerEvent()’ function to trigger a timer event every tenth of a second. The timer event then does the actual movement. First it gets the object’s current position with the ‘llGetPos()’ function which is then compared to the target. If the current Z position is less than the target it means that the elevator is moving upwards and vice versa. Depending on the direction of movement, the value of ‘DeltaZ’ – the rate of change of vertical position (speed) – is added or subtracted from the current position. The script also makes sure that the maximum and minimum positions are not exceeded. After calculating the new position, the ‘llSetPos()’ function is called to ‘move’ the elevator to the new position. When the elevator reaches its target, the timer is cancelled and the object is moved back to the default state. And that’s it. Now, when the elevator is touched it will gradually move to its destination where it will stop until it is touched again to bring it back.

Further Improvements

Of course there are lots of ways to improve the script. For instance floating point numbers could be used for DeltaZ to make the animation smoother. The elevator itself could be designed much better rather than a simple platform by linking various prims together and use messaging to make them move as a single unit. I’ll be looking into messaging and linking in a future post where we’ll see how we can create a call button for our elevator.

Conclusion

Although building and scripting is one of the most enjoyable things in Second Life (for me at least) it can also be very, very frustrating at times. Given that scripts are compiled and run on the server, each time you modify a script it could take a while for the change to take effect depending on the amount of lag being experienced. When testing a script you usually need to continuously correct or tweak the code and having a bad response time can make this a rather frustrating experience. Also, the risk of being disconnected from second life without warning is also there (happened to me a couple of times) so I had to resort to writing code on a local text-editor and pasting it into Second Life to make sure I always had a backup I could fall back to. Although I have only begun to scratch the surface, it is already apparent that scripting in second life can be pretty powerful.
Readmore...
Wednesday 1 June 2011

Building & Scripting Objects in Second Life

0 comments
 
This week we shall have a look at how to build (very basic) objects in Second Life and how we can use scripts to add interactivity to these objects.

So let’s get straight down to business…

Building Basics


Second Life provides tools that enable you to create whatever your imagination conjures up. The only limits are practice and your own imagination! The building blocks for most everything in second life are known as Primitives or ‘Prims’ for short. Prims are basic shapes, such as cubes and spheres, provided by the building tools that can be combined together to create the larger more complex shapes in your creation. In total, there are around 15 prims of different shapes at your disposal.

To start building, you must be in an area in which you are allowed to build. This could be your own land, someone else’s land (if the owner gives you permission) or a sandbox, a public area where people can build stuff to their heart’s content. One thing to note about sandboxes is that the objects built in them are only temporary since sandboxes are periodically cleaned by their owners. To avoid losing your creation, make sure to save it in your inventory!

Editing Objects


So, we know where to build and with what to build but how do we actually build stuff? To start building, right-click anywhere on the ground and select “Build” from the context menu. This brings up the build toolbox shown below:

With the magic wand tool selected, choose the desired prim shape and click anywhere on the ground to create the object, a process known as “rezzing” a prim.  Now that we have created our basic object we can go ahead and change pretty much anything about it. An object can be moved, rotated, resized, hollowed out, twisted, tapered… the list goes on. You can also change the texture of the object (the default texture is wood).

To move an object, select “Move” from the toolbox and use the arrows provided to move the object in the desired direction. Similarly selecting “Rotate” and “Stretch” from the toolbox will allow you to rotate and resize an object in 3 dimensions. The X, Y and Z axis’ in Second Life are colour-coded Red, Green and Blue respectively and the control surfaces provided to manipulate the object follow this standard as illustrated below:

Moving an object

Rotating an object

Resizing an object

You can also manually set numerical values for moving/rotating/re-sizing objects rather than using the control surfaces for more precise control.

Building a Chair

A chair is a good candidate to demonstrate how to use the build tools to create something that is actually useful. My chair will have four wooden legs and fabric-covered seat and back, nothing too fancy. Here’s the finished product:

The finished product
The first step is to create all the basic components of the chair independently of one-another starting with the seat. The seat is made from a cube prim which I flattened into the correct shape. I then took a copy of the seat and rotated it around the x-axis to make the back. I also re-sized the back to make it slightly narrower than the width of the seat. Finally I used another cube prim to create the first of the legs which I copied 3 times to create the set. At this point I should mention some pretty handy shortcuts I found for copying and rotating objects which make the process much quicker than having to go back to the build toolbox each time. To copy an object make sure it is selected, then hold down the ‘shift’ key and click and drag away from the object. This will create an exact copy of the selected object. To rotate an object, simply hold the ‘Ctrl’ key and use the rotation control surfaces to rotate along the desired axis. Here’s what the chair looks like before assembly:
The chair components

Before assembling the chair however I wanted to assign different textures to the various components. I wanted my chair to have a fabric seat and wooden legs. To change the texture of the currently selected part(s), goto the “Textures” tab in the build toolbox and click on the wooden texture thumbnail. This will open up the “Pick Texture” dialog box from where you can browse through all the available textures. I chose to go with the standard “Fabric Linen” texture found under the “Fabrics” folder.
Applying a texture

Similarly, a wooden texture is applied to the chair's legs.

The final step is assembling the chair, starting from the legs. To make it easier to see what I was doing, I opted to position the legs while the seat was still on the floor. I also made use of the “Snap To Grid” option to help me better position the legs relative to the seat. Snapping to the grid also made it much easier to equally space the legs.

Snapping to grid makes it easier to align objects

When I was happy with the position of the legs, I simply slid the seat along the Z-axis to bring it above them and correctly positioned (and slightly tapered) the back. Finally I selected all the parts and linked them together to make them behave like one object. Job done.

Introduction to Scripting

All scripts in Second Life are written in Linden Scripting Language, LSL for short, which is syntactically similar to C and Java. LSL scripts are interpreted and executed on the Second Life servers which send the results back to the viewer. LSL is state and event driven, meaning that an object can be in one of many states and transitions from one state to another by reacting to events. For instance a door can be open or closed (states) and can transition from one state to the other after being touched (event).

In my next post we will have a closer look at LSL and how we can add scripts to our objects. We shall also see how we can add interactivity to our objects by making them respond to commands.
Readmore...