3DML Tutorial

1. Introduction

3DML is a simple markup language similar to HTML, the language used to build pages on the Web. 3DML creates, or "describes", Internet-ready, three-dimensional environments called spots. Much of the syntax will be familiar to you, if you already know basic HTML.

3DML is unique because it allows you to build a 3D space on the Web without doing any 3D modeling. And you can integrate many kinds of media right into a spot, including sound, animation, 2D graphics, and text. Building a spot for the Web is actually very similar to building in the real world using familiar pieces such as simple wooden blocks or even two-by-fours from the local lumberyard. In 3DML, there are sets of predefined blocks that you can put together to build a house, or a waterfall, or anything you desire. These sets of blocks are aptly named blocksets. In the Basic block set, there are blocks which are the shape ramps, columns, signs and more. The Village block set has blocks shaped like trees, houses, and sidewalks. Each of these blocks is represented by a character on your keyboard.

Like an HTML file, a 3DML file has 2 major sections: the head and the body.

The head is the section where you set attributes for the entire spot, such as the map dimensions, ambient light and sound, the sky texture, etc.

The body is the section where you can customize your blocks, and where you create your actual map. The map is the heart of a 3DML file, where you use different kinds of blocks (represented by ASCII characters) to build a 3D space. Each block typically occupies a space of 256 x 256 x 256 (pixels). Blocks are arranged into a grid pattern to create each horizontal level of a spot. Levels are stacked on top of each other to create multi-story spots.

This tutorial will take you step-by-step through the process of creating a spot. After you have completed your first spot, you may wish to use more advanced 3DML features. Check the 3DML Tag Guide for a complete list of 3DML tags. The Block Reference Guide has a complete list of the blocks in each blockset, with their default symbols and part names. The RoverScript Reference Guide describes the advanced topic of scripting your spots. Finally, the Blockset Builder Guide details the construction of your own blocksets.

Before you begin the tutorial, there are two things you will need to do:

1. Download and install the Flatland Rover software, and
2. Download and install the tutorial files.

If you haven't downloaded Flatland Rover yet, you can download it from http://www.flatland.com/download.

There are also a few files you will need in order to follow along with the tutorial. You can get the tutorial files at http://download.flatland.com/builders/tutorial.exe. This file will unzip to a folder called Flatland Tutorial on your desktop. Save your 3DML files that you create during the tutorial in this folder.

2. Getting Started

Open a new file in your text editor. You'll want to use software that displays all ASCII characters in the same amount of space. This is also called monospacing, meaning that an "i" takes up just as much space on the screen as a "M". Monospacing is very important for creating spots, because your maps will appear as easily readable grids. The Windows accessory program Notepad works well. Do not use a fancier word processor, such as Microsoft Word, which does not display characters with monospacing; your maps will not appear as easily readable grids.

Everything in a 3DML file must be bounded by the <spot> and </spot> tags. The <spot> tag has one parameter: version. The version parameter specifies what version of Rover the spot was designed for. If someone visits your spot with a version of Rover that is older than the version specified in the version tag, then they will be prompted to upgrade Rover before visiting your spot (the current version of Rover is 3.3).

Start a 3DML file

Go ahead and type the following lines of code to get started:

     <spot version="3.3">
     <head>
     </head>
     <body>
     </body>
     </spot>

When you have finished typing this, save your 3DML file with .3dml as the file extension (i.e., firstspot.3dml).

3. The <head> tag

The <head> tag contains several tags that apply to the entire spot.

The <debug> tag

<debug> is an optional tag you can use to get more information about errors in your spot. Rover is designed to ignore these errors as much as possible, and will display a spot as best it can when errors are present in the file. But if you include the <debug> tag, Rover will display error messages that will help you to locate and correct those errors. You will want to put the <debug> tag at the very beginning of the head section of your 3DML file, so that it will catch any errors in the head section as well. The best use of the <debug> tag is to include it while you are working on your 3DML files, and then to erase it before publishing your spot to the Web.

Add the following line of code just after your <head> tag:

     <debug warnings="yes" />

The <title> tag

The <title> tag holds the title of the spot. The title text will be displayed at the bottom of the browser window in Rover's GUI.

     <title name="title text" />

Put the following code between the <head> tags in your 3DML file:

     <title name="First Spot" />

The <blockset> tag

     <blockset href="url" />

The <blockset> tag lets Rover know what set of blocks and default textures to use to display the spot. The blockset is expressed as a URL. The first time a user encounters a new blockset, the blockset is downloaded and placed in the Flatland cache on the user's hard drive, where it will remain indefinitely. The next time the user encounters the same blockset, Rover will check the cache first before attempting to download the new set.

Everything in a spot is made out of blocks. The <blockset> tag tells the browser what set of blocks to use to display the spot. Currently, Flatland hosts five blocksets: the basic set (contaning mostly simple block-like shapes), the basic 2 set (more simple shapes), the island set, the interior set (containing tables, chairs, etc.), and the village set (containing houses, sidewalks, trees, etc.). You can find details about the blocks in each block set on the Blocksets page.

Put the following code between the <head> tags in your 3DML file:

     <blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />

The <map> tag

     <map style="single|double" 
      dimensions="(columns,rows,levels)" />

The <map> tag has two attributes: dimensions and style. Dimensions tells Rover what size your spot is going to be. Spots are measured in blocks, (columns, rows, levels). When you are building spots, remember that whenever you change the dimensions of your spot by adding new levels, columns,or rows, you will have to change the dimensions in the <map> tag as well. We will discuss the style attribute later on in the More Blocks! section of the tutorial. For now, just use style="single".

We are going to make a spot that is 9 blocks wide, 9 blocks long, and 1 block high. Put the following code between the <head> tags in your 3DML file.

     <map style="single" dimensions="(9,9,1)" />

The <sky> tag

     <sky texture="image-file-path-or-URL" 
      color="(red,green,blue)" 
      brightness="brightness%" />

The <sky> tag sets an image to be used as the background for your spot. This texture will appear anywhere there aren't any blocks visible. If you don't put a ceiling on your spot, the texture defined in the <sky> tag will appear in the sky. If you leave any holes in your walls or floors, then the sky texture will be seen there. Also, if a user sets the maximum viewing distance of Rover to a number lower than the dimensions of your spot, the resulting holes in your spot will reveal the sky texture.

If you prefer, you can set a color for the sky rather than a texture. The color is expressed by red, green, and blue values between 0 to 255. For example, pure red would be expressed as color="(255,0,0)", pure blue is color="(0,0,255)", and pure green would be color="(0,255,0)". All other colors can be expressed as combinations of red, green, and blue.

You can also set the brightness of the sky in the <sky> tag. Brightness is expressed as a whole number percentage. If you don't specify brightness, the default level is 100%. If you leave out the <sky> tag altogether, the background will default to the sky texture specified in the blockset. For the Basic blockset, that texture is a partly cloudy blue sky.

Remember, if your image file isn't in the same folder as your 3DML file, then you also need to specify the path to your image: <sky texture= "folder/image.gif" />

Put the following code between the <head> tags in your 3DML file. The image "clouds.gif" should be in a folder called "images", which is in the same folder as your 3DML file.

     <sky texture="images/clouds.gif" brightness="90%" />

The <ground> tag

     <ground texture="image-file-path-or-URL"
      color="(red,green,blue)" />

The <ground> tag specifies a texture (or color) to be used on the ground plane of your spot. If you use the <ground> tag, then you won't have to supply a solid floor of blocks in your map. The ground will be the same dimensions as your map. If your map is 5 blocks by 8 blocks, then your ground will be that same size as well.

You can specify either a texture or a color with which to fill the ground plane. If you leave the <ground> tag out, there will be no ground plane displayed in your spot, and you will have to supply a solid floor made of blocks in order to keep your visitors from falling endlessly through virtual space. If you want to use the default ground texture specified by the Basic blockset, then simply include an empty <ground> tag in your 3DML file: <ground />. This will generally give you a dirt-colored floor.

Put the following line of code between the <head> tags in your 3DML file:

     <ground texture="images/dirt.gif" />

The <ambient_light> tag

     <ambient_light brightness="brightness%" 
      color="(red,green,blue)" />

The <ambient_light> tag has two attributes: brightness and color. Brightness defines how bright your spot will appear to be in areas where you haven't placed any other lights. Brightness is expressed as a whole number percentage. If you set your ambient light relatively low, say around 50%, then you will have more room to play with lighting effects later. If you don't need that kind of flexibility, go ahead and set brightness at or close to 100%. The color attribute allows you to specify what color the light is in your spot, although colored light will only appear when Rover is being run on 3D acceleration hardware.

Brightness defaults to 100%, if not otherwise specified. Color defaults to white, or (255,255,255). Lighting will be covered in more detail in the Lighting section of the tutorial. For now, leave your ambient light at the default levels.

Put the following code between the <head> tags in your 3DML file:

     <ambient_light brightness="100%" />

The <ambient_sound> tag

     <ambient_sound file="wave-file-path-or-URL" VOLUME="volume%" 
      playback="looped|random" delay="minimum..maximum" />

The <ambient_sound> tag specifies a sound file that will play throughout your spot. The ambient sound will be heard at the same volume throughout the entire spot. The sound can either be looped continuously or played at random intervals with the playback attribute. If playback="random", you can also specify a range of delay times between playbacks. Delay times are measured in seconds, and are measured from the time that the sound begins, rather than when it ends. For example, if your sound is 5 seconds long, playback="random", and delay="5..10", then sometimes the sound will play back to back, (as the length of the sound file is the same as the minimum delay time), and no more than 5 seconds will ever elapse between when the sound ends and when it begins again. (The maximum delay time, 10 seconds, minus the length of the sound itself, 5 seconds, leaves a maximum silence of 5 seconds.) The default values for these attributes are as follows: volume="100%", playback="looped", delay="5..10".

We'll talk about other ways to use sound later in the Sound section of the tutorial.

Put the following code between the <head> tags in your 3DML file:

     <ambient_sound file="sounds/waves.wav" volume="65%"
      playback="looped" />

After you've heard how this works, you may want to remove the <ambient_sound> tag from your 3DML file, or you are likely to get very tired of hearing it throughout this tutorial!

Other <head> tags

There are three other tags that can go in the head section of the 3DML file: <placeholder>, <orb>, and <fog>. We'll discuss these tags later on in the tutorial.

The complete code for this tutorial should look like this:

     <spot version="3.3">
     <head>
     <debug warnings="yes" />
     <title name="First Spot" />
     <blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
     <map style="single" dimensions="(9,9,1)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="100%" />
     <ambient_sound file="sounds/waves.wav" volume="65%" playback="looped" />
     </head>
     <body>
     </body>
     </spot>

4. The <body> tag

The Body

The body of a 3DML file is where you finally get to make the map itself. There are five main activities that are handled in the <body> tags are: customizing blocks, creating the map, creating popups, assigning image maps, and assigning entrances and exits. First we will create a simple map and an entrance. We'll talk about all those other aspects shortly.

The Map

The map is made up of individual levels that act just like stories of a building. Each level in a spot must have the same number of rows and columns. If you need to add extra rows or columns to a spot you have already been working on, you will need to add those rows or columns to every level in the spot.

Each level in a spot is bounded by the <level>...</level> tags. The <level> tag has just one attribute: number. Number="1" refers to the bottom level of a spot, just like floors of a building. Any character between the <level> tags will be interpreted as a block. All blocks occupy the space of a cube with 256 pixels in every dimension (256 x 256 x 256).

For this first map we will use just two kinds of blocks. You can find a complete list of blocks in the Block Reference Guides.

The full block "#"

The full block is a solid cube, filling up the entire 256 x 256 x 256 block space.

The empty block "."

Nothing but virtual thin air. The empty block is just a place holder that keeps your maps looking like easy-to-read grids.

Put the following code between the <body> tags in your 3DML file:

     <level number="1">
     ###...###
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #########
     </level>

The <entrance> tag

You must always specify at least one entrance for your spot. The entrance doesn't look like anything, it is just the place in the spot where your visitors will first land. The <entrance> tag has three attributes: location, name, and angle. An <entrance> tag can be placed anywhere within the <body> tag. Some builders prefer to put their <entrance> tags immediately following the level in which they occur. Other builders prefer to keep all of their <entrance> tags together just before the closing </body> tag, after all of the levels have been defined. In this tutorial, we will ask you to keep them together at the end of the <body>. Our first spot will only have one level and one entrance.

The location is specified as an (x,y,z) coordinate, measured in blocks (with 1,1,1 being in the top left (or northwest) corner of the bottom level.)

The name attribute allows you to name each entrance, so that you can refer to them later. They act sort of like targets in HTML. Every spot must have one entrance named "default".

The angle attribute defines what direction your visitors will be facing when they enter the spot. The angle parameter has 2 values, turn and tilt, specified in whole number degrees. The first value specifies what direction (north, south, east, west, or somewhere in between) your visitors will face. Possible values range from 0 to 359. The second value specifies whether they will be looking up or down, with possible values of -90 to 90. The default value is "0,0" which will leave your visitors facing north, and parallel to the horizon. A value of "90,0" will set your visitors facing directly east, "180,45" will leave them facing south, and 45 degrees up into the "air", etc.

Put the following code after the </level> tag in your 3DML file:

     <entrance location="(5,8,1)" name="default" angle="0,0" />

Congratulations!

You now have a fully functioning spot! Save the file as "firstspot.3dml" in the Flatland Tutorial folder, and open it in your Web browser or the Flatland Rover stand-alone browser (simply drag the file firstspot.3dml onto your browser window). You will find yourself in a room with 4 walls and no ceiling. You should see your sky texture overhead, and the ground texture underfoot. You will also see the sky texture in the open space in the wall in front of you. Go to the edge and look over.

     <spot version="3.3">
     <head>
     <debug warnings="yes" />
     <title name="First Spot" />
     <blockset 
      href="http://blocksets.flatland.com/flatsets/basic.bset" />
     <map style="single" dimensions="(9,9,1)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="100%" />
     <ambient_sound file="sounds/waves.wav" volume="65%" 
      playback="looped"/>
     </head>
     <body>
     <level number="1">
     ###...###
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #########
     </level>
     <entrance location="(5,8,1)" name="default" angle="0,0" />
     </body>
     </spot> 

5. Multiple Levels

So lets make this simple room we've created a little taller and give it a ceiling.

The ceiling block "-" (that's a hyphen, not an underline)

The ceiling block is 32 pixels thick and fills the top of the block space. Ceiling Blocks also happen to make great floors for the level above them!

To Number or Not To Number

Levels in a spot don't actually have to be numbered. Numbering is an easy way to keep track of what level of a spot you are working on, but it also means that if you add any new levels to anywhere other than the top of a spot, you have to go through and change all of your level numbers. The browser will read the spot just fine whether or not you include the number attribute, so this option is entirely up to you. In this tutorial, we'll go ahead and number them.

Make a taller spot

Add the following code to your 3DML file, after the level that you've already made.

     <level number="2">
     ###---###
     #-------#
     #-------#
     #-------#
     #-------#
     #-------#
     #-------#
     #-------#
     #########
     </level>

Now we have changed the dimensions of our spot, so we will have to change the <map> tag as well. Change your <map> tag to read:

     <map dimension="(9,9,2)" />

Let's also change the title of this spot to Tall Spot. But don't throw away your firstspot.3dml file. We will use it again later in the tutorial. Change the <title> tag to read like this:

     <title name="Tall Spot" />

Now save your spot as "tallspot.3dml" and open it in your browser. You should have a tall room with a ceiling and an opening in front of you.

     <spot version="3.3">
     <head>
     <debug warnings="yes" />
     <title name="Tall Spot" />
     <blockset 
      href="http://blocksets.flatland.com/flatsets/basic.bset"/>
     <map style="single" dimensions="(9,9,2)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="100%" />
     <ambient_sound file="sounds/waves.wav" volume="65%" 
      playback="looped"/>
     </head>
     <body>
     <level number="1">
     ###...###
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #########
     </level>
     <level number="2">
     ###---###
     #-------#
     #-------#
     #-------#
     #-------#
     #-------#
     #-------#
     #-------#
     #########
     </level>
     <entrance location="(5,8,1)" name="default" angle="0,0" />
     </body>
     </spot>

6. Navigation in Multi-level Spots

Visitors to your spots can't fly through them. Spots have gravity, so if you want your visitors to be able climb to the upper levels of your spot, then you will have to provide a path for them to do so.

The half block "h"

The half block is just the bottom half of a full block.

The nramp block "N"

The nramp block is a ramp that rises to the height of a full Block, going up towards the north.

The nbottomramp block "k"

The nbottomramp block is a ramp that rises to the height of a half block, going up towards the north.

The ntopramp block "K"

The ntopramp block is a ramp that rises from the height of a half block to the height of a full block, going up towards the north.

Provide a path onto the roof of your spot.

Change level 1 of your Tall Spot to look like this:

     <level number="1">
     ###...###
     #.......#
     ##......#
     ##......#
     #K......#
     #h......#
     #k......#
     #.......#
     #########
     </level>

Change level 2 of your Tall spot to look like this:

     <level number="2">
     ###---###
     #-------#
     #N------#
     #.------#
     #-------#
     #-------#
     #-------#
     #-------#
     #########
     </level>

Save your Tall Spot and open it in your browser. You should now be able to climb the ramps up to the roof!

     <spot version="3.3">
     <head>
     <debug warnings="yes" />
     <title name="Tall Spot" />
     <blockset 
      href="http://blocksets.flatland.com/flatsets/basic.bset"/>
     <map style="single" dimensions="(9,9,2)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="100%" />
     <ambient_sound file="sounds/waves.wav" volume="65%" 
      playback="looped"/>
     </head>
     <body>
     <level number="1">
     ###...###
     #.......#
     ##......#
     ##......#
     #K......#
     #h......#
     #k......#
     #.......#
     #########
     </level>
     <level number="2">
     ###---###
     #-------#
     #N------#
     #.------#
     #-------#
     #-------#
     #-------#
     #-------#
     #########
     </level>
     <entrance location="(5,8,1)" name="default" angle="0,0" />
     </body>
     </spot>

7. The <create> tag: creating and changing textures

All of the 3DML blocks are assigned particular textures, and sometimes sounds or other attributes. With the <create> tag, you can customize many of these features. The <create> tag works by telling the browser to take a block it already knows, change a few things about it, and give it a new ASCII symbol to represent the new block in the map.

Each kind of Block that is used in a 3DML file has a number of "parts" that make up its shape. You can change the texture of each of these parts with the <create> tag. For example, the full block has 6 parts corresponding to the six sides of the cube. They are refered to as "n, s, e, w, top, and bottom", with n,s,e, and w, corresponding to north, south, east, and west. To find out the parts that make up each block, check the Blockset Reference Guides.

Lets take a look at a sample <create> tag:

     <create symbol="a" block="full">
     <part name="n,s,e,w" texture="images/brick.gif" />
     </create>

This tag tells the browser that we are going to make a new block, which will be referred to in the map as the ASCII character "a", and which will be shaped like a full block. Then we tell the browser to change the texture on the 4 sides of the cube to be the file "brick.gif", located in the "images" folder. Note that the "top" and "bottom" parts of the block haven't been changed, and will appear with the default texture.

Image File Formats.

Rover supports GIF files, including animated or transparent GIFs, and JPEG files.

Syntax Rules

There are some syntax details you'll need to keep in mind:

<create> tags are placed in the <body>, before your first level.

If you want to change all of the parts of a block to be a single texture, you can use "*" to refer to all parts at once: <part name="*" texture="images/brick.gif" /> would change all parts of a block to the brick texture.

In the block attribute, you can refer to the block type either by its name "full", or by its default ASCII symbol "#". You can also reuse the ASCII characters that are assigned as defaults. For example, if you aren't going to use any unaltered full blocks in your spot, then you can assign the "#" character to one of your changed blocks:

     <create symbol="#" block="full">
     <part name="*" texture="images/brick.gif" />
     </create>

Now everytime you use the "#" character in your map, you will get full blocks that are textured with brick.gif, rather than the default texture.

All blocks have default textures that are included in the blockset. If you want to use one of these textures on a different part or different block, you can do so by preceeding the texture name with a "@".

     <create symbol="#" block="#">
     <part name="top" texture="@clouds.gif" />
     </create>

This would put the texture clouds.gif, which usually appears as the default sky texture, on the top of the full block.

Texture styles

By default, textures will be "stretched" to fill the part in question when you change a texture. If your texture is 64 x 64 pixels, and the part you are placing it on is 256 x 256, then the texture will be stretched to the appropriate size to fit the part. In this case, you would be making the texture four times its original size, which would probably cause the texture to pixelate (or lose resolution.) You also have a couple of other options if you use the style attribute in the <part> tag. With style, you can set the texture to scale up to fill the part, or you can set it to tile to fill the part. Style="scaled" will simply grow the texture to the size of a full block (256 x 256), and apply that texture to the part in question. Style="tiled" will lay the texture out side by side of itself like tiles to fit the part in question. Here are some examples of all three styles.

Texture projection

On some blocks, textures may not always appear exactly as you expected. This happens on curved blocks, like spheres, domes, and the curvein and curveout blocks. To make a long story short, the way Rover usually projects textures onto blocks just doesn't work well for these curved blocks. For these blocks, it works best for the texture to be projected from just one side, and you can specify which side with the projection attribute. Possible values are "top|bottom|north|south|east|west". Projection is only necessary with textures that are "tiled" or "scaled" onto curved blocks. "Stretched" textures do not need the projection attribute.

Texture orientation

Occasionally you may want to change the orientation of a texture on a part. For instance, you may want it to display upside-down. You can achieve this by adding an angle attribute to the <create> tag. Possible values for the angle attribute range from 0-359. The texture will be rotated in a clockwise direction. Angle="180" would turn the texture 180 degrees clockwise, in effect turning it upside down.

Color and translucency

You can also use the <create> tag to assign a color to a part of a block, rather than a texture:

     <part name="name" color="(red,green,blue)" />

You can also set a part to be translucent:

     <part name="top" texture="painting.gif" translucency="50%" />

The translucency feature will only show up to users who have 3D acceleration hardware installed. Users who don't will see all opaque textures.

The faces attribute

Faces specifies whether a texture is displayed on one, both, or none of the sides of a polygon. The default value is faces="1" which means that textures are applied to just one side of a polygon. So with a full block in its default state, you can see the textures from the outside of the block. But if you were to step inside the block itself, you would not see anything, because the textures are not displayed on the "inside" sides of the polygons. But if you specify faces="2", then the textures will be displayed on both sides of each polygon. This is particularly useful if you use a translucent or transparent texture on one part of a block. For instance, if you use a translucent texture on the south side of a full block, and you use faces="2" for all the other parts, then you will be able to see the inside of the block when you look through the south side.

The faces attribute can also be used to make polygons invisible, by using faces="0". This will prevent textures from being displayed on both sides of the polygon, making it invisible. You still won't be able to walk through it though.

The faces attribute goes in the <part> tag.

Solidity

The solid attribute determines whether or not your visitors will collide with that particular part of a block. If solid="no", then they will be able to walk right through that part. The default value is solid="yes".

So the syntax for the entire <part> tag is as follows:

     <part name="name" texture="folder/image.gif" 
      color="(r,g,b)" style="tiled|stretched|scaled" 
      projection="top|bottom|north|south|east|west" 
      faces="0|1|2" solid="yes|no" translucency="number%" 
      angle="0-359" />

The placeholder texture

When a visitor first comes to view your spot over the Internet, it may take a few seconds (or even minutes depending the size of your texture files and the speed of the visitor's Internet connection) to download the custom textures that you have assigned to your blocks. The shape of your spot will be displayed much more quickly however. If Rover is ready to display a block, but the texture has not finished downloading from the Internet, then a placeholder texture will be displayed until the custom texture arrives. Every blockset has a placeholder texture associated with it that will be used by default, but you can also assign a different texture to act as the placeholder. The <placeholder> tag goes in the head of the 3DML file and has just one attribute: texture.

     <placeholder texture="image-file-path -or- URL" />

You can also use different colors as placeholders on specific blocks by using the color attribute in the <create> tag. If a <create> tag has both a texture and color attribute, then the color will be displayed as a placeholder until the image file arrives. This feature is useful if you want to try to approximate your final textures before they download. For instance, if one of your textures looks like water, then you could take a blue color from that texture and use it instead of the placeholder texture while the full texture downloads.

About downloading textures

Textures will be downloaded in the order in which they appear in the 3DML file, so it is a good idea to put the <create> tags for the blocks that appear near the entrance to your spot first in your 3DML file. This way your visitors can begin to see your spot the way you intended without having to wait for the entire download to finish.

Or you can use the <load> tag to force Rover to load textures in a different order. When Rover encounters a <load> tag in a 3DML file, it will load that image at that time, before moving on to the next <create> tag. The syntax for load looks like this:

     <load texture="folder/image.gif" />

Change a texture in your spot

Put the following code in your Tall Spot 3DML file, just after the <body> tag:

     <create symbol="#" block="full">
     <part name="n,s,e,w" texture="images/pinkmarble.gif" />
     </create>

     <create symbol="-" block="ceiling">
     <part name="bottom" texture="@edgetop.gif" />
     </create>

Save your file and open it in your browser. The walls of your spot should now appear to be pink marble, and the ceiling should be a sort of metal screen-like texture. If you go up onto the roof, however, you will see that the top of the ceiling blocks haven't changed.

     <spot version="3.3">
     <head>
     <debug warnings="yes" />
     <title name="Tall Spot" />
     <blockset href="http://blocksets.flatland.com/flatsets/basic.bset"/>
     <map style="single" dimensions="(9,9,2)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="100%" />
     <ambient_sound file="sounds/waves.wav" volume="65%" playback="looped"/>
     </head>
     <body>
     <create symbol="#" block="full">
     <part name="n,s,e,w" texture="images/pinkmarble.gif"/>
     </create>
     <create symbol="-" block="ceiling">
     <part name="bottom" texture="@edgetop.gif" />
     </create>
     <level number="1">
     ###...###
     #.......#
     ##......#
     ##......#
     #K......#
     #h......#
     #k......#
     #.......#
     #########
     </level>
     <level number="2">
     ###---###
     #-------#
     #N------#
     #.------#
     #-------#
     #-------#
     #-------#
     #-------#
     #########
     </level>
     <entrance location="(5,8,1)" name="default" angle="0,0" />
     </body>
     </spot>

8. The <create> tag: Orientation

In addition to changing textures, the <create> tag can also be used to change the orientation of a block, or turn it to face another direction.

Orientation is accomplished by specifying two different values. First, you specify what direction you want the top of the block to face (up,down,north,south,east, or west). Then you specify an angle of rotation around that axis.

Lets look at a new block called the curvein block, and turn it around to see how orientation works.

The curvein block ":"

The curvein block looks like a full block that has been "scooped out" to be concave on the top and south sides.

Now if you want to turn the curvein block around so that the scooped out side faces the top and north, you would use the following tag:

     <create symbol="A" block="curvein">
     <param orient="up,180" />
     </create>

Now every time the browser encounters an "A" in the map, it will take a curvein block, leave its top pointing "up", and turn it 180 degrees clockwise, (around the Y axis) making the curved side of the block face up and north.

Now, if you were standing to the south of a curvein block, and you wanted to tip it over to the right, so its top faced east, you would use this code:

     <create symbol="A" block="curvein">
     <param orient="east,0" />
     </create>

So Rover will make the top of the block face "east", and will rotate it "0" degrees around that axis.

Now imagine that you want the "scooped out" part to face down and east. You'll need to point the top of the block towards the "east", and then rotate "270" degrees. That is a 270 degree clockwise rotation, if you were looking at the original top of the block, which is now pointing east.

Rotation is limited to values of 0, 90, 180, or 270. Rotation is always clockwise around what was originally the y axis. Imagine that you are standing on the top of the block, and you remain there as the block is tilted to the "east". You are now standing on the east side of the block, looking at what used to be the top of the block. The rotation will take place in a clockwise direction from where you are standing. Having a physical block to play with on your desk may be of some help. Here are some examples to help you visualize all this topsy-turvy-ness.

Without any rotation, blocks are designed to look "right" to a visitor who is facing north. This is just a general rule that hopefully will make building a littleeasier. For instance, the curvein and curveout blocks both have their curves on the south side, so that you can see them when you are facing north. The front door of the house blocks (in the Village Blockset) all face south, so that they look correct to a visitor who is facing north.

A Note about Ramps

In the Basic Blockset, we have gone ahead and provided north, south, east and west orientations of the ramp blocks, just to make life a little easier. So to get a ramp that goes up to the south, you can just use the sramp block, rather than having to use an orient attribute on an nramp block.

Change the orientation of a block

First, lets just put a few different curvein blocks in your spot just to see how they work.

Add the following code just after the <body> tag in tallspot.3dml:

     <create symbol="A" block="curvein">
     </create>

     <create symbol="B" block="curvein">
     <param orient="up,90" />
     </create>

     <create symbol="C" block="curvein">
     <param orient="down,0" />
     </create>

     <create symbol="D" block="curvein">
     <param orient="west,90" />
     </create>

And change level 1 of tallspot.3dml to look like this:

     <level number="1">
     ###..D###
     #.......#
     ##...C..#
     ##......#
     #K...B..#
     #h......#
     #k...A..#
     #.......#
     #########
     </level>

Save the file and open it in your browser. Take a look at how each orientation attribute changed the different curvein blocks.

Making orientation useful

Go back to the four <create> tags for blocks A, B, C, and D, and change them to look like this:

     <create symbol="A" block="curvein">
     <param orient="east,0" />
     </create>

     <create symbol="B" block="curvein">
     <param orient="west,0" />
     </create>

     <create symbol="C" block="curvein">
     <param orient="north,90" />
     </create>

     <create symbol="D" block="curvein">
     <param orient="north,270" />
     </create>

Change level 1 of tallspot.3dml to look like this:

     <level number="1">
     ###...###
     #A.....B#
     ##......#
     ##......#
     #K......#
     #h......#
     #k......#
     #D.....C#
     #########
     </level>

Save the file and open it in your browser. The room should now have nice curved corners.

     <spot version="3.3">
     <head>
     <debug warnings="yes" />
     <title name="Tall Spot" />
     <blockset href="http://blocksets.flatland.com/flatsets/basic.bset"/>
     <map style="single" dimensions="(9,9,2)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="100%" />
     <ambient_sound file="sounds/waves.wav" volume="65%" playback="looped"/>
     </head>
     <body>
     <create symbol="A" block="curvein">
     <param orient="east,0" />
     </create>

     <create symbol="B" block="curvein">
     <param orient="west,0" />
     </create>

     <create symbol="C" block="curvein">
     <param orient="north,90" />
     </create>

     <create symbol="D" block="curvein">
     <param orient="270,90" />
     </create>

     <create symbol="#" block="full">
     <part name="n,s,e,w" texture="images/pinkmarble.gif" />
     </create>

     <create symbol="-" block="ceiling">
     <part name="bottom" texture="@edgetop.gif" />
     </create>

     <level number="1">
     ###...###
     #A.....B#
     ##......#
     ##......#
     #K......#
     #h......#
     #k......#
     #D.....C#
     #########
     </level>
     <level number="2">
     ###---###
     #-------#
     #N------#
     #.------#
     #-------#
     #-------#
     #-------#
     #-------#
     #########
     </level>

     <entrance location="(5,8,1)" name="default" angle="0,0" />
     </body>
     </spot>

9. Linking

The ability to make hyperlinks between information sources is arguably the most important feature of the Internet. Spots are no different in this respect than HTML Web pages. Links are accomplished in 3DML by naming entrances and exits in your file, and pointing them at each other, or at outside spots or Web pages.

Links can occur anywhere in a spot. You can place an exit on any block, including an empty block. Traditionally, however, exits are used in conjuction with the portal block. When a visitor to your spot rolls their mouse over an exit, the destination title or URL will appear just below the cursor, to let them know where the link will take them.

The portal block "@"

The portal block is used to indicate a hyperlink. It looks something like a doorway, only a little twistier. You can place an image over the doorway to give your visitors some clue as to where the link leads. By default, a portal block is linked to http://www.flatland.com. You can link the portal to any URL by using an <exit> tag.

When you are making your own spots, you'll want to use the <create> tag to put an image that indicates where the link leads in the doorway of your portal. But for now, we'll just use the default Flatland logo image.

The <exit> tag

     <exit location="(column,row,level)" 
      href="file_name#entrance_name" 
      trigger="click on,step on" text="text" 
      target="destination name" />

Like the <entrance> tag, the <exit> tag can be placed anywhere within the <body> tags. Some builders like to put them directly after the level in which they occur, others like to keep them all together at the bottom.

The <exit> tag has five attributes: location, href, trigger, target, and text. Location is the (x,y,z) coordinate at which the exit occurs, with (1,1,1) being in the top left or northwest corner of the bottom level. Href is where the link leads to, expressed as the destination's file name or URL, followed by the entrance name, separated by a "#". Trigger defines how the exit may be activated, either by clicking on it, stepping on it, or both. To make an exit both "click on" and "step on" activated, just include both options in the trigger attribute: trigger="click on, step on". By default, exits placed in the body of the 3DML file will be "click on". Exits placed on portal blocks will be both "click on" and "step on". If you want to open the link in a new window or frame of an html page, you can use the target attribute to name where the link will open, just as you would in HTML. Text specifies the text that will appear by the user's cursor, indicating that the link is active. Usually this text is the title of the page or spot that the link leads to. But you can of course put any text here that you wish. If no text attribute is specified, then no text will appear.

Entrances and exits in the <create> tag

Entrances and exits can also be attached to specific blocks by including them in the <create> tag. The tag syntax is the same, except that you don't need a location parameter. Remember, when you

attach an exit directly to a block, then every instance of that block in your map will link to the same URL. When you attach an entrance to a block, and then use that block more than once in a map, then you will effectively have more than one entrance with the same name. Lets say you have an entrance named "doorway" attached to a block that appears three times in your map. When a visitor travels through a link to the "doorway" entrance, Rover will chose one of the 3 doorway entrances to use at random.

A note about entrances

Entrances can only be placed on empty spaces or on certain kinds of blocks. If an entrance is placed on a location that is occupied by a block with a solid shape, then Rover will remove the model for that block, and it won't appear in your spot. This includes the portal Block. If you want a portal to act as an entrance as well as an exit, you should place the entrance on the location just in front of the portal block. The blocks in the Basic Blockset that are allowed as entrances are these: floor, ceiling, ground, halfceiling, halffloor, all light blocks, and sound. Check the Blockset Guides to be sure whether or not a particular block can act as an entrance.

We are going to make a link between firstspot.3dml and tallspot.3dml, and a link between two different locations within tallspot.3dml.

Link my spots!

First, lets put in a portal. Change Level 1 of firstspot.3dml to look like this:

     <level number="1">
     ###.@.###
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #.......#
     #########
     </level>

Then, add this exit tag just before the </body> tag:

     <exit location="(5,1,1)" href="tallspot.3dml#default" 
      trigger="click on, step on" text="tallspot"/>

This has established a one-way link from the portal in firstspot.3dml, located at (5,1,1), to the default entrance in tallspot.3dml. A visitor can travel from firstspot.3dml to tallspot.3dml, but not back again, because there is no <exit> tag in the tallspot.3dml file.

Create a two-way link

In order to make this a two-way link, add this tag before the </body> tag in tallspot.3dml:

     <exit location="(5,1,1)" href="firstspot.3dml#default" 
      trigger="click on, step on" text="firstspot" />

And put a portal in that location to mark the link:

     <level number="1">
     ###.@.###
     #A.....B#
     ##......#
     ##......#
     #K......#
     #h......#
     #k......#
     #D.....C#
     #########
     </level>

Save both of your files, and open firstspot.3dml in your browser. Go back and forth between the links!

You probably noticed that when you linked back into firstspot.3dml, you didn't enter in the same location from which you left. This is because there is only one <entrance> tag in firstspot.3dml, the default entrance at (5,8,1). In order to create an exact two-way link between two locations, each location must have both an <entrance> tag and an <exit> tag that point to each other. Also remember that the links would work just fine with or without the portal blocks. The portal is just a convention (like highlighted text in HTML) to indicate that a link is present.

Create a direct two-way link

In order to create a direct two-way link, add this <entrance> tag to firstspot.3dml:

     <entrance location="(5,2,1)" name="second" angle="180,0" />

And go back to the <exit> tag in tallspot.3dml and change it to read:

     <exit location="(5,1,1)" href="firstspot.3dml#second" 
      trigger="click on, step on" text="firstspot" />

Now you have a direct link between two locations in two different spots. Next, we'll add an internal link between two different locations within tallspot.3dml.

Create a direct link

In your tallspot.3dml file, add these tags to the body:

     <entrance location="(7,6,1)" name="floor" />
     <entrance location="(7,6,3)" name="roof" />
     <exit location="(7,7,1)" href="#roof"
      trigger="click on, step on" text="Up to the Roof" />
     <exit location="(7,7,3)" href="#floor"
      trigger="click on, step on" text="Down to the Floor" />

And mark your links with portals.

Change Level 1 to the following:

     <level number="1">
     ###.@.###
     #A.....B#
     ##......#
     ##......#
     #K......#
     #h......#
     #k....@.#
     #D.....C#
     #########
     </level>

And then add a Level 3 that looks like this:

     <level number="3">
     .........
     .........
     .........
     .........
     .........
     .........
     ......@..
     .........
     .........
     </level>

And now you will need to change your <map> tag accordingly:

     <map dimensions="(9,9,3)" />

Save both of your files and open tallspot.3dml in your browser. Experiment jumping around between all of the links you have created.

     <spot version="3.3">
     <head>
     <debug warnings="yes" />
     <title name="Tall Spot" />
     <blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
     <map style="single" dimensions="(9,9,3)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="100%" />
     <ambient_sound file="sounds/waves.wav" volume="65%" playback="looped" />
     </head>
     <body>
     <create symbol="A" block="curvein">
     <param orient="east,0" />
     </create>
     <create symbol="B" block="curvein">
     <param orient="west,0" />
     </create>
     <create symbol="C" block="curvein">
     <param orient="north,90" />
     </create>
     <create symbol="D" block="curvein">
     <param orient="north,270" />
     </create>
     <create symbol="#" block="full">
     <part name="n,s,e,w" texture="images/pinkmarble.gif" />
     </create>
     <create symbol="-" block="ceiling">
     <part name="bottom" texture="@edgetop.gif" />
     </create>
     <level number="1">
     ###.@.###
     #A.....B#
     ##......#
     ##......#
     #K......#
     #h......#
     #k....@.#
     #D.....C#
     #########
     </level>
     <level number="2">
     ###---###
     #-------#
     #N------#
     #.------#
     #-------#
     #-------#
     #-------#
     #-------#
     #########
     </level>
     <level number="3">
     .........
     .........
     .........
     .........
     .........
     .........
     ......@..
     .........
     .........
     </level>
     <entrance location="(5,8,1)" name="default" angle="0,0" />
     <exit location="(5,1,1)" href="firstspot.3dml#second"
      trigger="click on,step on" text="firstspot" />
     <entrance location="(7,6,1)" name="floor" />
     <entrance location="(7,6,3)" name="roof" />
     <exit location="(7,7,1)" href="#roof"
      trigger="click on, step on" text="Up to the Roof" />
     <exit location="(7,7,3)" href="#floor"
      trigger="click on, step on" text="Down to the Floor" />
     </body>
     </spot>

10. Invisible Audibles: Adding Sound

There are four different ways that sounds can be used in spots: ambient sounds, the sound block, sounds attached to blocks in the <create> tag, and sounds assigned to particular locations in the map. We've already discussed the <ambient_sound> tag that goes in the head of your spot file. Your visitors will hear the ambient sound at the same volume throughout the entire spot. The other two methods of using sound are attached to blocks or locations, and therefore the sound will get louder as your visitors aproach the block or location that holds the sound. Currently, all sounds used in spots must be in WAV format. Most sound processing software will save files in WAV format.

The sound block "~"

The sound block has no 3D model. You can't see it at all; you can only hear it.

If you want to have a sound that appears to come from an object, then you want to use the <create> tag to add a sound to whatever block you want. If you just want a sound to emanate from a general area in a spot, then you want to use a sound block or assign it to a particular location in your map. Even when you are using the sound block, you still need to use the <create> tag to assign the correct sound to your block, so lets look at how that works.

Using sound in the <create> tag

The tag for sound has eight attributes: file, volume, playback, delay, flood, radius, rolloff, and name. The syntax is as follows:

     <create symbol="x" block="sound">
     <sound file="sounds/noise.wav" volume="number%" 
      playback="looped|random|once|single" 
      delay="minimum..maximum" flood="yes|no" 
      radius="number of blocks" rolloff="1.0" 
      name="sound name" />
     </create>

Be sure to include the path when you name the file, if your sounds aren't in the same folder as your 3DML file.

Volume is expressed as a whole number percentage.

Playback determines how a sound will be played. There are 4 different playback options: looped, random, once, and single. Playback="looped" will cause the sound to play continuously. If playback="once", the sound will play only once. If playback="single", then the sound will play once every time the player enters the specified radius. If playback=random", the sound will play at random intervals. If playback="random", you can also specify a range of delay times between playbacks. Delay times are measured in seconds, and are measured from the time that the sound begins, rather than when it ends. For example, if your sound is five seconds long, playback="random", and delay="5..10", then sometimes the sound will play back to back, as the length of the sound file is the same as the minimum delay time, and no more than 5 seconds will ever elapse between when the sound ends and when it begins again. The maximum delay time, 10 seconds, minus the length of the sound itself, 5 seconds, leaves a maximum silence of 5 seconds.

The volume of a sound will drop off gradually as you get farther away from the source. But if flood="yes", then the sound will play at the specified volume throughout the specified radius, rather than dropping off gradually.

Radius is measured in blocks, and has two different roles. On a sound with flood="yes", the radius defines how large an area will be filled with that sound. If volume="100%", flood="yes", and radius="5", then the sound will be heard at full volume right up to the edge of the 5 block border, at which point it will turn off completely. On a sound with playback="once" or playback="single", the radius acts as a trigger. The sound will be played when the user enters the specified radius.

Rolloff determines how quickly the sound volume will taper off as you move away from the sound source. In most cases, the default value (rolloff="1.0") is the most natural setting for this parameter. But if you need more control over how the sound drops off, you can change the rolloff value. If rolloff="2.0", then the sound will drop off twice as fast (meaning it will be audible only half as far away from the source.) If rolloff="0.5", then the sound will drop off half as fast (meaning it will be audible twice as far away.)

The default values for these attributes are as follows: volume="100%", playback="looped" delay="5..10" radius="1" rolloff="1.0".

Note that a block can only have one sound attached to it, unless you give each sound a name attribute.

Using Sounds in the <body>

You can also assign sounds to a specific location in the map by simply adding a location parameter to the <sound> tag and placing it in the body of the 3DML file (usually at the end) rather than in the <create> tag:

     <sound file="sounds/noise.wav" volume="number%" 
      playback="looped|random" delay="minimum..maximum" 
      flood="yes|no" radius="number of blocks" 
      location="(column,row,level)" />

Improving performance

Having lots of sound sources in a spot can tax the performance of Rover on slower machines. If you attach a sound to your floor block for instance, and that block appears 25 times in your spot, Rover has to keep track of 25 different sound sources. Visitors to your spot will get much better performance out of Rover if you place that sound on one location, or scatter a few sounds sources around the spot. If you set flood="yes", and your radii overlap, the sound will play at a consistent volume throughout the area.

Just like custom textures, sound files will be downloaded in the order in which they appear in the 3DML file. Because sound files are often quite large, it is a good idea to list any <create> tags that include sounds last. On the other hand, if you want your visitors to hear a sound immediately upon entering a spot (or at least as soon as possible) then put the tag for that sound first before the other <create> tags.

Add a sound to your spot

In tallspot.3dml, add the following code after the <body> tag:

     <create symbol="~" block="sound">
     <sound file="sounds/giggle.wav" volume="75%" 
      radius="5" flood="yes" playback="looped" />
     </create>
     <create symbol="c" block="ceiling">
     <part name="top" texture="images/smiley.gif" />
     <part name="bottom" texture="@edgetop.gif" />
     <sound file="sounds/guffaw.wav" volume="100%" 
      playback="random" delay="3..6" />
     </create>

Change Level 2 to look like this:

     <level number="2">
     ###---###
     #c-----c#
     #N------#
     #.------#
     #-------#
     #-------#
     #-------#
     #c-----c#
     #########
     </level>

And change Level 3 to look like this:

     <level number="3">
     .........
     .........
     .........
     .........
     ....~....
     .........
     ......@..
     .........
     .........
     </level>

Save your file and open it in your browser. Go up to the roof of the spot, move around and listen to the different ways the sounds work. You should be able to hear 3 different sounds: the constant ambient sound (unless you took this tag out), the guffaws that you hear intermittently and are louder if you are close to a smiley, and the giggle that plays at a constant volume throughout the area.

     <spot version="3.3">
     <head>
     <debug warnings="yes" />
     <title name="Tall Spot" />
     <blockset href="http://blocksets.flatland.com/flatsets/basic.bset"/>
     <map style="single" dimensions="(9,9,3)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="100%" />
     <ambient_sound file="sounds/waves.wav" volume="65%" 
      playback="looped" />
     </head>
     <body>

     <create symbol="~" block="sound">
     <sound file="sounds/giggle.wav" volume="75%" 
      radius="5" flood="yes" playback="looped" />
     </create>

     <create symbol="c" block="ceiling">
     <part name="top" texture="images/smiley.gif" />
     <part name="bottom" texture="@edgetop.gif" />
     <sound file="sounds/guffaw.wav" volume="100%" 
      playback="random" delay="3..6" />
     </create>

     <create symbol="A" block="curvein">
     <param orient="east,0" />
     </create>

     <create symbol="B" block="curvein">
     <param orient="west,0" />
     </create>

     <create symbol="C" block="curvein">
     <param orient="north,90" />
     </create>

     <create symbol="D" block="curvein">
     <param orient="270,90" />
     </create>

     <create symbol="#" block="full">
     <part name="n,s,e,w" texture="images/pinkmarble.gif" />
     </create>

     <create symbol="-" block="ceiling">
     <part name="bottom" texture="@edgetop.gif" />
     </create>

     <level number="1">
     ###.@.###
     #A.....B#
     ##......#
     ##......#
     #K......#
     #h......#
     #k....@.#
     #D.....C#
     #########
     </level>
     <level number="2">
     ###---###
     #c-----c#
     #N------#
     #.------#
     #-------#
     #-------#
     #-------#
     #c-----c#
     #########
     </level>
     <level number="3">
     .........
     .........
     .........
     .........
     ....~....
     .........
     ......@..
     .........
     .........
     </level>

     <entrance location="(5,8,1)" name="default" angle="0,0" />
     <exit location="(5,1,1)" href="firstspot.3dml#second" 
      trigger="click on,step on" text="firstspot" />
     <entrance location="(7,6,1)" name="floor" />
     <entrance location="(7,6,3)" name="roof" />
     <exit location="(7,7,1)" href="#roof" 
      trigger="click on, step on" text="Up to the Roof" />
     <exit location="(7,7,3)" href="#floor" 
      trigger="click on, step on" text="Down to the Floor" />
     
     </body>
     </spot>

11. Lighting

We have already discussed the <ambient_light> tag, which goes in the head section of the 3DML file. Ambient_light lights everything in your spot evenly, without creating any shadows. If you are going to be using lighting effects in your spot, then you should set your ambient_light relatively low (around 50% or less), so that your other lights will show up more dramatically.

Aside from ambient_light, there are three different categories of light: orb light, point_light, and spot_light. Orb light is light that shines from a specific direction in the sky, illuminating the entire spot. Point_light is light that shines in all directions from a specified location. Spot_light is light that shines in a specified direction from a specified location.

The <orb> tag

     <orb texture="folder/image.gif"
      position="(turn,tilt)"
      brightness="percentage%"
      color="(red,green,blue)" />

The <orb> tag allows you to place a light source in the sky that affects your entire spot, much like the sun or moon would in the real world. When you use the <orb> tag, you also have the ability to "hang" a sun or moon texture in the sky. There is at least one default orb texture that is included in each blockset. In the Basic Blockset, that texture is a bright sun. There is a full moon texture included in the Village Blockset. And of course, you can specify a texture of your own. The <orb> tag is always placed in the head section of the 3DML file.

No matter what texture you use in the sky, light will shine from the location of the texture illuminating the entire spot. Unlike ambient_light, light from the orb will create shadowed areas. Ambient light will illuminate all areas of a spot, regardless of whether or not they are exposed to the sky. But orb light will only illuminate surfaces that face the light source.

Position refers to where the orb will sit in the sky. Position is expressed as a pair of angles called "turn" and "tilt". The turn angle specifies what direction the orb will be in. Possible values are from 0-359, with 0 refering to north, 90 to east, 180 to south, etc. The tilt angle defines how high in the sky the orb will appear. Possible values range from -90 to 90, with 0 being at the ground, or "horizon", 90 being directly overhead, etc.

Brightness defines how bright the orb light will be. And texture defines what image will be displayed. Brightness will be 100% by default, and the default orb texture will be displayed in the sky if no other texture is specified.

Color allows you to define the color of the light, but colored light will only appear to users who have 3D acceleration hardware. Other users will see the normal white light.

You can also turn your orb into a hyperlink by adding an href parameter:

     <orb texture="folder/image.gif" position="(turn,tilt)"
      brightness="percentage%" color="(red,green,blue)"
      href="url" text="text" target="target_frame" />

Add orb light to your spot

First, you'll want to lower the ambient_light in your spot so that your lighting effects will show up. In tallspot.3dml, change the <ambient_light> tag in the head to read:

     <ambient_light brightness="30%" />

Then place the following tag in the head section of tallspot.3dml:

     <orb position="(45,45)" brightness="60%" />

The <point_light> tag

There are two different styles of point_light: static and pulsate. Static point_lights are good for lighting a general area of a spot. Pulsating point_lights are good for alien abduction scenes. (OK, and a few other more mundane things as well. But alien abductions are the preferred way to use them!)

Static point_light

The static point_light tag looks like this:

     <point_light style="static" position="(x,y,z)" 
      brightness="brightness%" radius="#_of_blocks" 
      flood="yes|no" color="(red,green,blue)" />

Here, position refers to the placement of the light within the block space. Position="(0,0,0)" would place the light at the bottom southwest corner of the block. Position="(128,256,128)" would place the light in the middle of the top of the block. Lights will be placed in the center of the block (128,128,128) by default if no position is defined.

Brightness defines how bright the light will be at the position of the source.

Radius defines how far from the source the light will be visible. If radius="4" and brightness="90%", then the light will be 90% brightness at the location of the light source, and will fade gradually to whatever the ambient_light level is 4 blocks away.

That is, unless flood is set to "yes". Flood="yes" will cause the light to flood the entire radius at the specified brightness level. In the above example, if flood were turned on, then light would appear at 90% brightness for the entire 4 block radius, and the light would drop sharply to the ambient level at the edge of the 4 block radius. The flood parameter defaults to "no".

Color allows you to define the color of the light, but colored light will only appear to users who have 3D acceleration hardware. Other users will see the normal white light.

Note that every polygon inside of a light's radius will not necessarily be illuminated. Only those polygons that face the light will be lit. A polygon that is within the radius of a light, but is not facing it, will not be affected by the light.

Pulsating point_light

The tag for a pulsating point_light is slightly different:

     <point_light style="pulsate" position="(x,y,z)" 
      brightness="min%..max%" radius="#_of_blocks" 
      flood="yes|no" color="(red,green,blue)" 
      speed="cycles_per_second" />

Notice that the brightness parameter describes a range between two values. And there is an added speed attribute. If brightness="20%..80%" and speed="2", then the light level will pulse from 20% to 80% and back again twice every second. You can slow the pulse down by assigning a value less than 1 to the speed parameter. Speed=".25" would create a light that takes four seconds to raise to its brightest level and back again.

Turn Smileys into Alien Abductors

Go back to the <create> tag for your smileys in tallspot.3dml (the "c" symbol you created), and add the following point_light:

     <point_light style="pulsate" position="(128,0,128)" 
      brightness="20%..90%" radius="1" flood="yes" 
      color="(0,0,255)" speed="1" />

So the entire <create> tag for the "c" block will look like this:

     <create symbol="c" block="ceiling">
     <part name="top" texture="images/smiley.gif" />
     <part name="bottom" texture="images/pinkmarble.gif" />
     <sound file="sounds/guffaw.wav" volume="100%" 
      radius="2" playback="random" />
     <point_light style="pulsate" position="(128,0,128)" 
      brightness="20%..90%" radius="2" flood="yes" 
      color="(0,0,255)" speed="1" />
     </create>

This will make a pulsating light under all of your smileys. Remember, your smileys are ceiling blocks with smiley faces on the top of the block space. This point_light is assigned to the bottom of the block space. Your smiley textures will not be lit by it because they face away from it. In order to light the smiley textures themselves, you would want to place a light above the smiley blocks, in level 3 of your map.

The <spot_light> tag

There are 3 different kinds of spot_lights: static, search, and revolve. A static spot_light shines a still cone of light. A searching spot_light moves back and forth between 2 specified points. A revolving spot_light rotates in a defined circle.

The tag for a static spot_light looks like this:

     <spot_light style="static" position="(x,y,z)" 
      brightness="brightness%" radius="#_of_blocks" 
      flood="yes|no" color="(red,green,blue)" 
      direction="(turn,tilt)" cone="angle" />

Position, brightness, radius, flood, and color all work the same here as they do for point_lights.

Direction describes where the spot_light is focused, and is expressed as a pair of angles. If no direction parameter is present, the light will face exactly north and horizontal to the ground plane by default, or direction="(0,0)". The first angle is called the "turn". The turn angle describes rotation in the horizontal plane. Possible values range from 0 to 359, where 0 is north, 180 is south, etc. The second angle is called the "tilt" and describes how far above or below the horizontal plane the light points. Possible values range from -90 to 90, where 0 is horizontal to the ground, 90 points straight up, and -90 points straight down. With the turn and tilt angles, you can describe any possible direction for your light to point.

Cone describes how wide the spot_light is. Cone is the diameter of the influence of the light, expressed as a degree, (0 to 359). The default value for cone is 45.

So a spot_light with direction="(45,0)" and cone="90" would illuminate the northeastern corner of a scene (assuming that the spot_light is in the center of the scene.) The turn angle is 45 pointing directly northeast, the tilt angle is 0 pointing parallel to the ground plane, and the cone is 90 which spreads the light out over a 90 degree area from the north axis to the east axis.

Direction="(0,-90)" would create a light that points straight down.

Searching spot_light

The tag for a searching spot_light would look like this:

     <spot_light style="search" position="(x,y,z)" 
      brightness="brightness%" radius="#_of_blocks" 
      flood="yes|no" color="(red,green,blue)" 
      direction="(turn1,tilt1)..(turn2,tilt2)" 
      cone="angle" speed="cycles_per_second" />

In a search style spot_light, you can define two different directions and the search light will move smoothly back and forth between the two directions. The path that the search light takes between the two defined directions is determined by which direction has a higher value for its turn angle. The light will always travel from the lowest turn angle value to the highest. Values for the turn angles can range from -359 to 359. To make a search light that moves between a point directly north to a point directly east, you would designate direction="(0,0)..(90,0)", and the light would travel clockwise from the north horizon to the east horizon. But what if you wanted a light to travel between the same 2 points, but to go the long way around, passing by the south and west horizons on the way? Then you would change the value of the eastern direction to read (-270,0). Direction="(0,0)..(-270,0)" would create a light that travels clockwise from the eastern horizon to the northern horizon and back again, passing through the south and west on the way.

Speed determines how fast the search light will move between the two directions. Speed is expressed as cycles per second. Speed="2" would make a light that moves from direction 1 to direction 2 and back again twice per second.

Revolving spot_lights

To create a revolving spot_light use the following code:

     <spot_light style="revolve" position="(x,y,z)" 
      brightness="brightness%" radius="#_of_blocks" 
      flood="yes|no" color="(red,green,blue)" 
      direction="(turn1,tilt1)..(turn2,tilt2)" 
      cone="angle" speed="revolutions_per_second" />

This tag is very similar to the syntax for the search light, but the light will continue in a full circle through the 2 specified directions. If the turn angle of the first direction is smaller than the second one, then the light will rotate in a clockwise direction. If the second turn angle is smaller, then the motion will be counterclockwise.

Placing lights in your spot

There are three different ways to describe light in a 3DML file:

  1. Adding lights to blocks using the <create> tag.
  2. Assigning lights to particular locations in the map.
  3. Using light blocks.

The tags that describe point_lights and spot_lights can be placed in the <create> tag of any block. Remember that a light included in a <create> tag will appear in every instance of that block in the map. Note that a block can only have one light assigned to it, unless you assign a name attribute to each <point_light> or <spot_light> tag after the first.

Alternately, a light can be assigned to a specific location in your map, regardless of what block might be there. To do this, simply put your light tag in the body of your 3DML file (usually near the end with your entrances and exits). You will also need to add a location parameter to the light tag to place the light at a specific location in the map. The location parameter works just the way it did for sounds: location="(column, row, level)"

Add a search light

In tallspot.3dml, add the following tag to the end of the body, just before your entrances and exits:

     <spot_light style="search" position="(1,1,128)" 
      brightness="100%" radius="7" location="(4,4,1)" 
      direction="(17,3)..(132,3)" cone="30" speed=".5" />

This should give you a spot_light that searches back and forth between the two portals on level 1 of tallspot.3dml

The pointlight block "'" (that's a single quote)

The pointlight block has no 3D model. A visitor won't see any object where the pointlight block sits, but light will emanate from it, lighting the surrounding blocks. By default, the pointlight block is a static point_light at 100% brightness and a radius of 4.

Add a light block

Now change the code for level 2 to look like this:

     <level number="2"> 
     ###---###
     #c-----c#
     #N------#
     #'------#
     #-------#
     #-------# 
     #-------#
     #c-----c#
     #########
     </level>

This should give you a bright light over the ramp area.

Save your file and open it in your browser to see the light. (Don't you wish illumination was always this easy?) You should see pulsing lights in the four corners of the first level of tallspot.3dml (and they will be blue if you have 3D acceleration hardware), a search light that roves between the two portals, and a constant bright light over the ramp area. You will also notice that the orb light is visible even when you are "inside". Lights in 3DML do not cast hard shadows. The orb light shines right through the "roof" and illuminates the walls that face it inside as well.

     <spot version="3.3">
     <head>
     <debug warnings="yes" />
     <title name="tall spot" />
     <blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
     <map style="single" dimensions="(9,9,3)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="30%" />
     <ambient_sound file="sounds/waves.wav" volume="65%"
      playback="looped" />
     <orb position="(45,45)" brightness="60%" />
     </head>
     <body>
     <create symbol="~" block="sound">
     <sound file="sounds/giggle.wav" volume="75%" radius="5"
      flood="yes" playback="looped" />
     </create>

     <create symbol="c" block="ceiling">
     <part name="top" texture="images/smiley.gif" />
     <part name="bottom" texture="@edgetop.gif" />
     <sound file="sounds/guffaw.wav" volume="100%"
      playback="random" delay="3..6" />
     <point_light style="pulsate" position="(128,0,128)"
      brightness="20%..90%" radius="1" flood="yes"
      color="(0,0,255)" speed="1" />
     </create>

     <create symbol="a" block="curvein">
     <param orient="east,0" />
     </create>

     <create symbol="b" block="curvein"> 
     <param orient="west,0" />
     </create>

     <create symbol="c" block="curvein">
     <param orient="north,90" />
     </create>

     <create symbol="d" block="curvein">
     <param orient="270,90" />
     </create>

     <create symbol="#" block="full">
     <part name="n,s,e,w" texture="images/pinkmarble.gif" />
     </create>

     <create symbol="-" block="ceiling">
     <part name="bottom" texture="@edgetop.gif" />
     </create>

     <level number="1">
     ###.@.###
     #a.....b#
     ##......#
     ##......#
     #k......#
     #h......#
     #k....@.#
     #d.....c#
     #########
     </level>
     <level number="2">
     ###---###
     #c-----c#
     #n------#
     #'------#
     #-------#
     #-------#
     #-------#
     #c-----c#
     #########
     </level>
     <level number="3">
     .........
     .........
     .........
     .........
     ....~....
     .........
     ......@..
     .........
     .........
     </level>

     <spot_light style="search" position="(1,1,128)"
      brightness="100%" radius="7" location="(4,4,1)"
      direction="(17,3)..(132,3)" cone="30" speed=".5" />

     <entrance location="(5,8,1)" name="default" angle="0.0" /%gt;

     <exit location="(5,1,1)" href="firstspot.3dml#second"
      trigger="click on,step on" text="firstspot" />

     <entrance location="(7,6,1)" name="floor" />

     <entrance location="(7,6,3)" name="roof" />

     <exit location="(7,7,1)" href="#roof"
      trigger="click on, step on" text="up to the roof"/>

     <exit location="(7,7,3)" href="#floor"
      trigger="click on, step on" text="down to the floor" />

     </body>
     </spot>

12. Popups

Popups are 2D images or text that you can assign to specific locations in your map. They are not visible to the visitor at first, but "pop up" on the screen when the visitor gets within a defined radius of the location that holds the popup, or when she rolls her mouse over a block that holds the popup. Popups are very useful for including extra information that you want a visitor to be able to see, without cluttering up your spot. They are great for providing detailed info about many objects in the spot. They also can be used to provide a simple navigational map of your spot that is visible right at the entrance.

The <popup> tag, like the <entrance> and <exit> tags, can go anywhere in the body. We usually place them at the end of the body, after all of the levels have been defined. But you can put them after the level in which they occur if you prefer. Popups can also be attached to blocks by putting the <popup> tag inside a <create> tag. Popups can contain either textures, text, or imagemaps.

Popup Textures

Lets start by just looking at a simple <popup> tag:

     <popup location="(column,row,level)" 
      trigger="rollover,proximity|everywhere" radius="blocks" 
      texture="folder/image.gif" placement="mouse|top-left|top|
      top-right|left|center|right|bottom-left|bottom|bottom-right" 
      brightness="number%" />

Location describes where in the map the popup is anchored. If the popup is attached to a block in a <create> tag, then the location parameter is not needed. If the popup is not attached to a block, and the location parameter is left out, then the popup will be displayed throughout the entire spot.

Trigger is how the popup gets activated, either by rolling over it with the mouse, or by coming within the specified radius, or both. Or, if trigger="everywhere", then the popup will appear throughout the entire spot.

Radius is how close the user has to be to the location to trigger the popup (when trigger is set to "proximity"). Radius is described as a whole number of blocks. Unlike lights and sounds, the radius for popups only functions on one level, i.e. a popup on level 4 with a radius of 2 will not be visible on levels 3 or 5.

Texture defines the file that will pop up.

Placement describes where on the user's screen the image will appear. When placement="mouse", the popup will appear in the same location as the user's cursor.

Brightness defines how bright the popup will appear.

Popup Text

You can also put text in popups by adding the following attributes to the <popup> tag:

     text="message" 
     textalign="top-left|top|top-right|left|center|right|
     bottom-left|bottom|bottom-right"
     textcolor="(r,g,b)"

Textalign defines how your text will appear in relationship to the popup texture.

Textcolor is the color of the text.

You can also assign a color to the popup itself, rather than a texture. To do so, you will need these two additional tags:

     color="(r,g,b)" 
     size="(width,height)" 

Size defines the size of the rectangle of color on which your text will appear, measured in pixels. If you place text over an image, then the color attribute will be used to define a color for a drop shadow on the text, making it easier to read against the background image. If no color is defined, then the background of the popup will be transparent by default.

Popup Imagemaps

Popups can also contain clickable imagemaps. The syntax for creating an imagemap is almost exactly the same as it is in HTML, except that the tag is called imagemap rather than map, and 3DML supports rectangle and circle shapes in the imagemap, but not polygons. To create an imagemap, put the following code somewhere in the body section of your 3DML file:

     <imagemap name="imagemap name">
     <area shape="rect|circle" coords="(x1,y1,x2,y2)|(x,y,radius)"
      href="destination URL" target="destination target" 
      text="display text" />
      ...
     </imagemap> 

When creating a rectangular area of an imagemap, the coordinates x1,y1 refer to the top left corner of the rectangle, and x2,y2 refer to the bottom right corner. When creating a circular area of an imagemap, x,y refers to the center of the circle.

In order to use an imagemap in your popup, add the following parameter to the <popup> tag:

     imagemap="imagemap name"

Note: If you are using an imagemap with your popup, and you have trigger set to rollover, then your placement will have to be mouse. Otherwise, the popup will disappear before your visitor can select anything!

So the entire <popup> tag, with all the possible attributes looks like this:

     <popup location="(column,row,level)"
      trigger="rollover,proximity|everywhere"
      radius="number-of-blocks"
      texture="image-file-path-or-URL"
      color="(r,g,b)"
      placement="mouse|top-left|top|top-right|left|center|
      right|bottom-left|bottom|bottom-right"
      size="(width,height)"
      text="message"
      textalign="top-left|top|top-right|left|center|right|
      bottom-left|bottom|bottom-right"
      textcolor="(r,g,b)"
      imagemap="map name"
      brightness="brightness%" />

Default values are as follows: trigger="proximity", placement="center", color="transparent", textcolor="(255,255,255)", size="(320,240)", textalign="center", brightness="100%".

Add some popups to your tall spot.

Add these <popup> tags after your <entrance> and <exit> tags:

     <popup location="(3,3,3)" radius="2" text="What's so funny?"
      color="(0,255,0)" size="(100,60)" textcolor="(255,0,0)"
     placement="top" />
     <popup location="(3,7,3)" radius="2" text="Beats me man!"
     color="(0,0,255)" size="(100,60)" textcolor="(255,0,0)"
     placement="bottom" /> 

Save your file and open it in your browser. Move around on the roof and take a look at how the popups work.

     <spot version="3.3">
     <head>
     <debug />
     <title name="Tall Spot" />
     <blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
     <map style="single" dimensions="(9,9,3)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="30%" />
     <ambient_sound file="sounds/waves.wav" volume="65%"
      playback="looped" />
     <orb position="(45,45)" brightness="60%" />
     </head>
     <body>
     <create symbol="~" block="sound">
     <sound file="sounds/giggle.wav" volume="75%" radius="5" 
      flood="yes" playback="looped" />
     </create>
     <create symbol="c" block="ceiling">
     <part name="top" texture="images/smiley.gif" />
     <part name="bottom" texture="@edgetop.gif" />
     <sound file="sounds/guffaw.wav" volume="100%" 
      playback="random" delay="3..6" />
     <point_light style="pulsate" position="(128,0,128)"
      brightness="20%..90%" radius="1" flood="yes" 
      color="(0,0,255)" speed="1" />
     </create> 

     <create symbol="A" block="curvein">
     <param orient="east,0" />
     </create> 
     
     <create symbol="B" block="curvein">
     <param orient="west,0" />
     </create> 

     <create symbol="C" block="curvein">
     <param orient="north,90" />
     </create> 

     <create symbol="D" block="curvein">
     <param orient="270,90" /> 
     </create> 
     
     <create symbol="#" block="full">
     <part name="n,s,e,w" texture="images/pinkmarble.gif" />
     </create> 
     
     <create symbol="-" block="ceiling">
     <part name="bottom" texture="@edgetop.gif" /> 
     </create> 
     
     <level number="1"> 
     ###.@.### 
     #A.....B# 
     ##......# 
     ##......# 
     #K......# 
     #h......# 
     #k....@.# 
     #D.....C# 
     ######### 
     </level> 
     <level number="2"> 
     ###---### 
     #c-----c# 
     #N------# 
     #'------# 
     #-------# 
     #-------# 
     #-------# 
     #c-----c# 
     ######### 
     </level> 
     <level number="3"> 
     ......... 
     ......... 
     ......... 
     ......... 
     ....~.... 
     ......... 
     ......@.. 
     ......... 
     .........      
     </level> 
     
     <spot_light style="search" position="(1,1,128)"
      brightness="100%" radius="7" location="(4,4,1)"
      direction="(17,3)..(132,3)" cone="30" speed=".5" /> 
     
     <entrance location="(5,8,1)" name="default" angle="0.0" />
     
     <exit location="(5,1,1)" href="firstspot.3dml#second" 
      trigger="click on,step on" text="firstspot" /> 
     
     <entrance location="(7,6,1)" name="floor" /> 
     
     <entrance location="(7,6,3)" name="roof" /> 

     <exit location="(7,7,1)" href="#roof"
      trigger="click on,step on" text="Up to the Roof" /> 
     
     <exit location="(7,7,3)" href="#floor"
      trigger="click on,step on" text="Down to the Floor" /> 
     
     <popup location="(3,3,3)" radius="2" text="What's so funny?" 
      color="(0,255,0)" size="(100,60)" textcolor="(255,0,0)" 
      placement="top" /> 

     <popup location="(3,7,3)" radius="2" text="Beats me man!" 
      color="(0,0,255)" size="(100,60)" textcolor="(255,0,0)" 
      placement="bottom" /> 

     </body> 
     </spot>

13. Sprites

Sprites are special types of blocks that don't really have a 3D model, but that offer particular behaviors to 2D images in 3D space. There are 4 types of sprites:

The sprite block "1"

The simplest sprite block is simply a single plane on which you can place a texture and which doesn't really have any behavior at all.

The spriterevolve block "2"

The spriterevolve block is a single plane that spins around on its central axis.

The spriteface block "3"

The spriteface block is a single plane that always faces the viewer. No matter what direction you approach the spriteface block from, the image that is assigned to it will appear to be facing you.

The spritefacet block "4"

The spritefacet block will unwrap a gif animation and present each frame to be viewed from a different angle in the spot. For example, if you took photographs of your favorite comfy chair from 8 different vantage points, all in the same horizontal plane, then put those images together in a gif animation, the spritefacet block would unwrap that animation, making it appear as if the chair were in your spot, and you could walk all the way around it.

Sprite Parameters

There are 5 parameters that are associated with sprites. All sprites can take the align, solid, and size parameters. Align specifies at what height in the blockspace the sprite will appear. Sprites will appear at the bottom of the block space by default. They can also be assigned to the top or the center. solid determines whether or not you can walk through the sprite. If solid="no", then a visitor can walk right through the sprite. If solid="yes", then the sprite will be solid. Solid="yes" by default. Size of course determines how large the sprite will be. Size is measured in pixels and cannot exceed "(256,256)". If no size is specified, the sprite will be the same size as the image that is placed on it.

The sprite block can also take an angle parameter, specifying what angle the sprite is facing. The angle is expressed as whole number degrees from 0 to 359. The default value is "0". The spriterevolve block can take a speed parameter, expressed as revolutions per second. The default value is ".5".

Experiment with Sprites.

Put the following <create> tags in your firstspot.3dml:

     <create symbol="1" block="sprite"> 
     <part name="*" texture="images/animate.gif" />
     <param angle="45" solid="no" />
     </create> 

     <create symbol="2" block="spriterevolve"> 
     <part name="*" texture="images/animate.gif" /> 
     <param speed="1" solid="no" /> 
     </create>

     <create symbol="3" block="spriteface"> 
     <part name="*" texture="images/animate.gif" /> 
     <param align="top" /> 
     </create> 
     
     <create symbol="4" block="spritefacet"> 
     <part name="*" texture="images/animate.gif" /> 
     <param align="center" /> 
     </create> 

And change the map to look like this:

     <level number="1">
     ###.@.### 
     #.......# 
     #.1.....# 
     #.....2.# 
     #.......# 
     #.3.....# 
     #....4..# 
     #.......# 
     ######### 
     </level> 

Save the file and open it in your browser. Walk around each of the different sprites to see how they behave. Try walking right through them.

     <spot version="3.3">
     <head> 
     <debug /> 
     <title name="First Spot" /> 
     <blockset href="http://blocksets.flatland.com/flatsets/basic.bset" /> 
     <map style="single" dimensions="(9,9,1)" /> 
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="100%" />
     <ambient_sound file="sounds/waves.wav" volume="65%" 
      playback="looped" />
     </head>
     <body>
     <create symbol="1" block="sprite">
     <part name="*" texture="images/animate.gif" />
     <param angle="45" />
     </create> 

     <create symbol="2" block="spriterevolve">
     <part name="*" texture="images/animate.gif" />
     <param speed="1" />
     </create>
     
     <create symbol="3" block="spriteface">
     <part name="*" texture="images/animate.gif" />
     <param align="top" />
     </create>

     <create symbol="4" block="spritefacet">
     <part name="*" texture="images/animate.gif" />
     <param align="center" />
     </create>

     <level number="1"> 
     ###.@.### 
     #.......# 
     #.1.....# 
     #.....2.# 
     #.......# 
     #.3.....# 
     #....4..# 
     #.......# 
     ######### 
     </level> 
     
     <entrance location="(5,2,1)" name="second" angle="180,0" />

     <entrance location="(5,8,1)" name="default" angle="0,0" />

     <exit location="(5,1,1)" href="tallspot.3dml#default" 
      trigger="click on,step on" text="tallspot" /> 

     </body> 
     </spot> 

14. Actions

<Action> tags are used to make your spots more dynamic and interactive. Currently, there are two types of actions: replace and exit. The <replace> tag allows you to switch out one block for another when the action is triggered. This very simple functionality opens an incredibly wide range of options to you. The <replace> tag can be used to make doors that open and close, locks that require keys to open, blocks that move around in your spot, sounds that are triggered on user actions, etc. The possibilities are endless. And of course, an <exit> tag within an <action> tag will trigger a link to occur.

Let's take a look at some sample code, then we'll go into the details:

     <create symbol="1" block="full">
          <part name="*" texture="images/sad.gif" />
          <action trigger="roll on" >
               <replace source="2" />
          </action>
     </create>

     <create symbol="2" block="full">
          <part name="*" texture="images/happy.gif" />
     </create>

Here we have created a full block, which has the image "sad.gif" on all its parts, and assigned it the symbol "1". Whenever a user rolls her mouse over this block, the block will be replaced with the "2" block, which is also a full block but which has the image "happy.gif" on all its parts.

Note that there is no other action on the "2" block, so once this action has been triggered once, there is no more functionality. When the player rolls off the block, it will still appear to be happy. But we can also add an <action> tag to block "2" which will switch back to block "1":

     <create symbol="2" block="full">
          <part name="*" texture="images/happy.gif" />
          <action trigger="roll off" />
               <replace source="1" />
          </action>
     </create>

Now there is another <replace> tag on block "2", with trigger="roll off". So when the user rolls over block one, it will replace itself with block "2". Then when they roll off of block "2", it will replace itself with block "1" again. So in effect, when a user rolls the mouse onto the block, they will see happy.gif, and when they roll off, they will see sad.gif again.

Let's look at the complete syntax for action and replace:

     <action location="(column,row,level)" trigger="roll on|
      roll off|click on|step in|step out|proximity|timer|location" 
      radius="number-of-blocks" delay="min..max" />
     <replace source="symbol|(column,row,level)"
      target="(column,row,level)" />
     </action> 

Radius is measured in blocks and is only used when the trigger is "step in", "step out", or "proximity". When trigger="proximity", the action will remain active as long as the user is within the specified radius. Once they leave the radius, then the action will reverse itself.

Delay is measured in seconds and is only used when the trigger is "timer". If only one value is included for delay, then the delay will always be the same number of seconds. If a minimum and maximum delay are specified, then the delay will be a random length in between those 2 values.

If the action is not attached to a block through a <create> tag, then location specifies where the action is located in the map.

Target (in the <action> tag) is only used when trigger="location". If trigger="location" then the action will be triggered when a block is placed on the specified target.

Target (in the <replace> tag) specifies the location in the map where the replace will take place. If no target is specified, then the block that holds the <action> tag will be replaced.

Source specifies the block that will be used to replace whatever block sits at the target.

Action and exit

<Action> tags can also hold <exit> tags. For a cheery example, lets say you wanted to create an area of your spot that was a fiery pit of death. You might put an <action> tag in the middle of this area with trigger="step in" that contains an exit that leads to another spot or HTML page that says something like "HAHA! Yer dead." The <action> tag would look like this:

     <action trigger="step in" radius="3" location="(5,5,1)">
          <exit href="hell.3dml#yerdead" />
     </action> 

So any time a user wanders within 3 blocks of the location (5,5,1), they will be sent to the entrance named "yerdead" in the spot "hell.3dml".
Each action can have only one trigger, but a single <action> tag can have one <exit> tag, and/or as many <replace> tags in it as you want. And a single <create> tag can have multiple <action> tags as well. So in the above example, we might add a second <action> tag to block "2" with trigger="click on", so that if a user clicks on the block, some other action will take place, but if they roll off without clicking, then the block will just revert back to block "1".

Actions in imagemaps

Actions can also work inside of imagemaps. The code is the same as for a regular imagemap, except that the <area> tag becomes an <action> tag, like so:

     <imagemap name="pop1train">
          <action shape="rect" coords="0,0,100,100"
           trigger="click on">
               <replace source="+2" target="(10,6,2)" />
          </action>
     </imagemap> 

Relative replace

The source and target for a <replace> tag can also be specified in terms relative to the current block. For example, you could tell Rover to replace a block with the block that is 2 blocks east and 3 blocks south:

     <create symbol="#" block="full">
          <action>
               <replace source="(-2,+3,0) target="(0,0,+1)" />
          </action>
     </create> 

Lets say that this block is sitting at the location (4,4,4) in your map. This action tells Rover to take the block that is at (2,7,4) [That's -2 columns, +3 rows, +0 levels] and place a copy of it at (4,4,5) [+0 columns, +0 rows, and +1 level].

Let's have some action!

Still working in your firstspot.3dml file, add the following <create> tags:

     <create symbol="#" block="full">
          <action trigger="click on">
               <replace source="A" />
          </action>
     </create>

     <create symbol="A" block="full">
          <part name="*" texture="images/pinkmarble.gif" />
     </create> 

The "#" blocks that make up the walls of this spot will now replace themselveswith the "A" block when they are clicked on. Save the file and open it in your browser. Click on the walls to see them change.
Now lets try a different kind of action. Change the <create> tag for the "2" block to look like this:

     <create symbol="2" block="spriterevolve">
          <part name="*" texture="images/animate.gif" />
          <param speed="1" />
          <action trigger="timer" delay=".85">
               <replace source="5" />
          </action>
     </create>

And add a new <create> tag that looks like this:

     <create symbol="5" block="sprite">
          <part name="*" texture="images/animate.gif" />
          <action trigger="timer" delay="2">
               <replace source="2" />
          </action>
     </create> 

Save the file and open it in your browser. You'll see that the spriterevolve block will now revolve for a little less than a second, and then replace itself with a regular sprite block that doesn't move for 2 seconds. Then this sprite block will replace itself with the original spriterevolve block again.

And now lets use the target parameter, and do several replaces in one <action> tag. First, we'll need to add another level to our map. Add this code, right after Level 1:

     <level number="2">
     .........
     .........
     .........
     .........
     .........
     .........
     .........
     .........
     .........
     </level>

And don't forget to change the dimensions in your <map> tag:

     <map style="single" dimensions="(9,9,2)" />

Then add the following <create> tags to your file:

     <create symbol="B" block="pyramid">
          <part name="*" texture="images/pinkmarble.gif" />
          <action trigger="click on">
               <replace source="." />
               <replace source="P" target="(1,1,2)" />
               <replace source="P" target="(1,9,2)" />
               <replace source="P" target="(9,1,2)" />
               <replace source="P" target="(9,9,2)" />
               <replace source="P" target="(3,1,2)" />
               <replace source="P" target="(7,1,2)" />
          </action>
     </create>
     
     <create symbol="P" block="pyramid">
          <part name="*" texture="images/pinkmarble.gif" />
     </create>

And now add the "B" block to your map. Change Level 1 to look like this:

     <level number="1">
     ###.@.###
     #.......#
     #.1.....#
     #.....2.#
     #...B...#
     #.3.....#
     #....4..#
     #.......#
     #########
     </level>

Save the file and open it in your browser. You'll see a pink pyramid in the center of the spot. When you click on this pyramid, it will disappear and 6 other pyramids will appear along the top of the wall. The original block disappears throught the first <replace> tag, where it replaces itself with a ".", or empty block.

     <spot version="3.3">
     <head>
     <debug />
     <title name="First Spot" />
     <blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
     <map style="single" dimensions="(9,9,2)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="100%" />
     <ambient_sound file="sounds/waves.wav"
      volume="65%" playback="looped" />
     </head>
     <body>
     <create symbol="1" block="sprite">
     <part name="*" texture="images/animate.gif" />
     <param angle="45" />
     </create>
     <create symbol="2" block="spriterevolve">
     <part name="*" texture="images/animate.gif" />
     <param speed="1" />
     <action trigger="timer" delay=".85">
     <replace source="5" />
     </action>
     </create>
     <create symbol="3" block="spriteface">
     <part name="*" texture="images/animate.gif" />
     <param align="top" />
     </create>
     <create symbol="4" block="spritefacet">
     <part name="*" texture="images/animate.gif" />
     <param align="center" />
     </create>
     <create symbol="5" block="sprite">
     <part name="*" texture="images/animate.gif" />
     <action trigger="timer" delay="2">
     <replace source="2" />
     </action>
     </create> 
     <create symbol="#" block="full">
     <action trigger="click on">
     <replace source="A" />
     </action>
     </create>
     <create symbol="A" block="full">
     <part name="*" texture="images/pinkmarble.gif" />
     </create>
     <create symbol="B" block="pyramid">
     <part name="*" texture="images/pinkmarble.gif" />
     <action trigger="click on">
     <replace source="." />
     <replace source="P" target="(1,1,2)" />
     <replace source="P" target="(1,9,2)" />
     <replace source="P" target="(9,1,2)" />
     <replace source="P" target="(9,9,2)" />
     <replace source="P" target="(3,1,2)" />
     <replace source="P" target="(7,1,2)" />
     </action>
     </create>
     <create symbol="P" block="pyramid">
     <part name="*" texture="images/pinkmarble.gif" />
     </create>
     <level number="1">
     ###.@.###
     #.......#
     #.1.....#
     #.....2.#
     #...B...#
     #.3.....#
     #....4..#
     #.......#
     #########
     </level>
     <level number="2">
     .........
     .........
     .........
     .........
     .........
     .........
     .........
     .........
     .........
     </level>
     <entrance location="(5,2,1)" name="second" angle="180,0" />
     <entrance location="(5,8,1)" name="default" angle="0,0" /> 
     <exit location="(5,1,1)" href="tallspot.3dml#default"
      trigger="click on,step on" text="tallspot" />
     </body>
     </spot> 

15. More Blocks!

Multiple Blocksets

It is possible to use blocks from more than one blockset in a single spot. Simply include more than one <blockset> tag in your head. Whichever blockset is specified first will be the primary blockset for the spot. All other blocksets become secondary. Here are a few things to remember: The default textures for the sky, ground, placeholder, etc. will come from the primary blockset.

Within each blockset, each block has a default symbol. When using more than one blockset, however, you may encounter situations where the same default symbol is used to represent 2 different blocks from 2 different blocksets. In this situation, the default symbols from the primary blockset (the one that appears first in your 3DML file) take precedence. You can still use the default symbol for a block in a secondary blockset if that symbol isn't used in the primary blockset. If you want to refer to a block that comes from a secondary blockset, thenjust preceed the name of the block with the name of the blockset, separated by a colon:

     <create symbol="A" block="village:housebase1"> 

Textures refered to with the @ symbol will come from the primary blockset. Again, to refer to a texture from a secondary blockset, preceed the name of the texture with a colon and the name of the blockset:

     <part name="n" texture="@village:bluedoor.gif" /> 

Use Elements from the Village Blockset

Lets put a lamp block from the Village blockset into our spot. First, add this extra <blockset> tag after the one you already have in your Tall spot:

     <blockset href="http://blocksets.flatland.com/flatsets/village.bset" /> 

The Basic and Village blocksets are designed so that the default block symbols don't overlap, so we can use the lamp block without doing anything special in the <create> tag. But lets make a <create> tag anyway, just to illustrate how it works.

Add the following code to the beginning of the body section of tallspot.3dml:

     <create symbol="v" block="village:lamp">
     </create>

And change level 3 of your map to look like this:

     <level number="3">
     .........
     .........
     .........
     .........
     ....~....
     .........
     ..v...@..
     .........
     .........
     </level> 

Now go back to the create tag that you made way back in the beginning of the tutorial for the full block (#) and change it to read:

     <create symbol="#" block="full">
     <part name="n,s,e,w" texture="@village:sqcel.gif" />
     </create> 

Now save your file and open it in your browser. You should see a streetlamp from the village set up on the roof, and the walls on the bottom level should be covered in square bumpy things.

Double-Characer Symbols

Back at the very beginning of the tutorial, we talked about the <map> tag. The <map> tag has an attribute called style that lets Rover know what kind of symbols you will use to represent your blocks. By default, the value of style is "single", meaning that you will use single ASCII characters to represent your blocks. This limits you to 92 different kinds of blocks, however, because that is how many ASCII symbols there are on your keyboard, (minus a couple that are reserved by 3DML). But if you are making a somewhat extensive spot, with several custom textures and many rotations of blocks, then you could easily run out of characters. That's where style="double" comes in. With style set to double characters, you can use any combination of 2 ASCII characters to represent each block, raising the number of possible blocks from 92 to over 8000!

When you use a double-character map, you must also use double-characters in your <create> tags, or anywhere else that you might be referring to blocks.

Each block has a single character symbol by default. The default double-character symbol for each block is the same as the default single character, preceeded by a "." So the default symbol for the full block, "#", becomes simply ".#". An nramp block is normally "N", and its double-character default is ".N", etc.

When you make a map with double characters, you can leave a space in between the symbols for each block, so that you can read your map more easily. Here's a very simple single character map, and the same map made again with double characters:

     <level number="1">
     #####
     #.N.#
     #...#
     #W.E#
     #...#
     #.S.#
     #####
     </level>
     
     <level number="1">
     .# .# .# .# .#
     .# .. .N .. .#
     .# .. .. .. .#
     .# .W .. .E .# 
     .# .. .. .. .#
     .# .. .S .. .#
     .# .# .# .# .#
     </level>

Its not necessary for you to convert your tallspot.3dml spot to double characters, but here's what it would look like if you did, with all changed tags in bold.

     <spot version="3.3">
     <hread>
     <debug />
     <title name="Tall Spot" />
     <blockset href="http://blocksets.flatland.com/flatsets/basic.bset" />
     <blockset href="http://blocksets.flatland.com/flatsets/village.bset" />
     <map style="double" dimensions="(9,9,3)" />
     <sky texture="images/clouds.gif" brightness="90%" />
     <ground texture="images/dirt.gif" />
     <ambient_light brightness="30%" />
     <ambient_sound file="sounds/waves.wav" volume="65%"
      playback="looped" />
     <orb position="(45,45)" brightness="60%"
      href="http://www.flatland.com"
      text="Check out Flatland Online!" />
     </head>
     <body>
     <create symbol=".v" block="village:lamp">
     </create>
     <create symbol=".~" block="sound">
     <sound file="sounds/giggle.wav" volume="75%" radius="5"
      flood="yes" p