3DML Tag Guide

This reference guide provides the details of the syntax for each of the 3DML tags. A thorough description of the blocks available can be found in the Blockset Guides. These guides are designed to be used in conjunction with the 3DML Tutorial, which gives step-by-step instructions on how to build a spot. It is advisable to complete the tutorial first.

3DML is a markup language that describes three-dimensional spaces (called spots) that are viewable with the Flatland Rover. Wherever possible, 3DML syntax is identical to or as similar to HTML syntax as possible. In some cases, however, we chose to make things a little different from HTML in order to retain XML compliance.

This guide is current for Rover version 3.4.

The code samples provided here are given in an extended form with line breaks between tag properties to make them easy to read. Please note, however, that in 3DML you can write tags either way, as long, one line tags, or with line breaks as used in this reference.

General Rules About 3DML Tags

One line tags follow this basic syntax:

     <tag attribute="value" />

Tags that bound other groups of tags follow this basic syntax:

     <tag1 attribute="value">
          <tag2 attribute="value" />
     </tag1>

The tags that can bound other tags are:

<spot>, <head>, <body>, <create>, <action>, <imagemap>, <define>

All tags must be bounded by <>. Tags and attributes are not case sensitive, but opening and closing tags must be in the same case. This reference uses lowercase tags and attributes for consistancy.

All values, meaning anything immediately following an equals sign(=) must be surrounded by quotes("). Any value that describes an x,y or x,y,z coordinate must be bounded by parentheses ( ). R,G,B color values also must be bounded by parentheses ( ).

To include comments in a 3DML file, use the following syntax:

<!-- your comments here -->

Any information bounded in this way will be ignored by Rover. Avoid using multiple, consecutive dashes (--) in comments for XML compliance.

Basic structure of a 3DML file

The <spot> tag

     <spot version="current_version_number"> ... </spot>

The first and last tags in a 3DML file. Everything between these tags is considered to be a spot described in the 3DML format. The version parameter specifies the oldest version of Rover the spot was designed for. As of the writing of this reference, the current version number is 3.4.

The <head> tag

     <head> ... </head>

These tags define a block of information which appears before the body section. The header acts as it does in HTML, containing information that applies to the entire spot.

The <body> tag

     <body> ... </body>

These tags surround the body content of the spot description, including the map itself.

Tags that can appear in the head of a 3DML file

The <debug> tag

     <debug warnings="yes|no" />

Used when building a 3DML file. If the <debug> tag is present, Rover will display error messages that will help the author find and correct errors in their 3DML file. It is recommended that the <debug> tag be removed before publishing your 3DML file to the Web.

The warnings attribute controls whether or not warnings (non-fatal errors) will be reported. Rover 3.4 is designed to be much more verbose in it's warnings, so it's helpful to be able to turn them off at times. The default is "yes".

The <title> tag

     <title name="name text" />

The text in the <title> tag is the name of the spot, and will be displayed in at the bottom of the browser window.

The <blockset> tag

     <blockset href="url" />

Specifies which set of blocks (i.e., textures, sounds, models and behaviors) to use to display this spot in the browser.

The <map> tag

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

Dimensions specifies the size of the map described in the 3DML file in units of blocks (every block is the same size; imagine them as wooden cubes placed side-by-side and also stacked to create levels). Style determines whether single or double character symbols will be used to represent blocks in the map and in create tags.

The <sky> tag

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

Uses the given image file (GIF or JPEG) as the tiled texture for the sky above the spot. Alternately, a color can be specified to appear in the sky, instead of a texture. The brightness parameter sets the light on the sky image between 0 and 100 percent (default is 100%).

The <fog> tag

     <fog color="(red,green,blue)" start="value" end="value"
      density="density%" />

Applies fog to entire spot. Fog color, density, distance in blocks where the fog starts, and distance in blocks where the fog ends can all be specified. Default fog values are color="(255,255,255)", start="1", end="10", and density="50%". By default, fog is disabled. Fog may or may not be rendered in a spot, depending on the 3D graphics card of the computer.

The <ground> tag

     <ground texture="folder/image.gif -or- URL"
      color="(red,green,blue)" />

If supplied, Rover uses the given image (or color) as the ground plane directly beneath the first level of the map. An author can then build a map without having to supply a solid floor. To use the default ground texture, include an "empty" ground tag:

     <ground />

If not supplied, there will be no ground. Movement through the lowest, groundless level is hindered, unless blocks are placed on this level to move over.

The <ambient_light> tag

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

Sets the ambient light level and color for the entire spot. Default is 100% brightness, and white light. Colored light will only be visible when Rover is running on 3D acceleration hardware.

The <orb> tag

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

Sets an image to be displayed in the sky such as a sun or moon. Also defines a source position for a directional light that shines from the orb over the entire spot, and the brightness and color of that light. Color will only be seen on 3D acceleration hardware. Href defines a link to a URL and text defines what text will be displayed on mouse roll-over.

The <ambient_sound> tag

     <ambient_sound file="folder/sound.wav -or- URL"
      volume="volume%" playback="looped|random|once"
      delay="minimum..maximum" />

Uses the given WAV file as the ambient sound of the entire spot. The volume of the sound can be between 0 and 100 percent (default is 100%). The sound can either be played once, looped, or played at random intervals. If playback="random", you can specify a range of times in between playbacks. Delay times are measured in seconds, and from the beginning of the sound, rather than the end.

The <placeholder> tag

     <placeholder texture="folder/image.gif -or- URL" />

Uses the specified texture in place of any custom textures while the custom textures download.

The <onload> tag

     <onload href="url" target="target_name" />

Launches the specified URL as soon as the spot is loaded. This is useful for displaying information in another frame or window along with your spot.

Tags that can appear in the body of a 3DML file

The <create> tag

     <create symbol="symbol" block="symbol-or-block-name">
          ...
     </create>

Every 3D block object is assigned a single ASCII character as a symbol. For instance, let's say a full block is assigned to the "#" character. So when you make a wall on the map you might type ##### which is a wall that is five blocks wide. Double-character symbols may also be used, if style="double" in the <map> tag. When using double-character symbols, each default single-character symbol is preceeded by a ".". So the default double-character symbol for a full block is ".#". The <create> tag allows you to change the textures applied to a block object and change some other features of the block, such as the orientation, the lighting (brightness, radius, and color) or the sound (WAV file, volume, radius and playback mode).

Below is an example of a <create> tag with all of the possible attributes:

     <create symbol="symbol" block="symbol-or-block-name">
          <param
           orient="up|down|north|south|east|west,angle
             -or - (angle_x,angle_y,angle_z)"
           solid="yes|no" movable="yes|no" origin="(x,y,z)"
           scale="(scale_x,scale_y,scale_z)" />
          <part name="name" texture="folder/image.gif-or-URL"
           angle="0-359" color="(red,green,blue)"
           translucency="translucency%"
           style="tiled|scaled|stretched"
           projection="top|bottom|north|south|east|west"
           faces="0|1|2" solid="yes|no"
           rect="x1,y1,x2,y2" />
     </create>

The <create> tag can also include any or all of the the following tags: <entrance>, <exit>, <param>, <popup>, <point_light>, <spot_light>, <sound>, <action>, <define>, and <script>. When used inside the <create> tag, these tags use the same syntax that they use on their own, except that they don't take a location attribute.

Avoid using < or & in your block symbols for XML compliance.

The <define> tag

     <define>
          ... variables and functions ...
     </define>

The <define> tag is used to define RoverScript variables and functions in your spot. See RoverScript Reference for more details.

The <import> tag

     <import href="folder/file.3dml" />

The <import> tag makes Rover insert the contents of the specified file into the 3DML file. This can be useful for sharing common elements between spots. The <import> tag can be used anywhere in the body of a spot, except inside of <level>, <define>, <action>, or <script> tags. The imported 3DML file must start with <import> and end with </import>.

The <load> tag

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

The <load> tag forces Rover to load the specified file. Normally, Rover will load textures and sounds in the order in which they appear in the 3DML file. Using the <load> tag, you can force Rover to load images or sounds in a different order.

The <level> tag

     <level number="number">
          ...rows of block symbols...
     </level>

Defines the two dimensional map for one floor level of a spot. Between the tags, all letters are interpreted as building blocks for rendering the spot. The map must be written as a rectangle of characters with all rows equal in length. There is a one-to-one correspondence between the symbol positions in the map and the placement of the 3D blocks in the resulting spot. The number attribute is optional. It is expected in general that each consecutive level defines a higher floor level of the spot.

The <entrance> tag

     <entrance location="(column,row,level)"
      name="name" angle="0-359,-90-90" />

Defines a location where players can hyperlink into this spot from another spot or Web page. More than one may be defined in a single spot. There must be at least one entrance named "default" in every 3DML file. Angle defines what direction the viewer will be facing when she enters through this entrance (0 to 359 degrees with 0 equal to north, and -90 to 90 degrees to determine whether she is looking up or down.) The <entrance> tag can be placed anywhere within the body. It is usually placed at the end of the body, after all of the levels have been defined. Some authors prefer to put them immediatley following the level in which they occur. An entrance can also be assigned to a block by placing it inside the <create> tag. It does not take a location attribute if it is placed in the <create> tag.

The <exit> tag

     <exit location="(column,row,level)"
      href="folder/spot.3dml#entrance-name"
      trigger="click on|step on" text="text"
      target="destination name" />

A hyperlink to another 3DML file. Location defines where in the spot the link will be placed. The href gives the filename or URL of the destination spot or HTML page, with an optional entrance name (if omitted the "default" entrance will be used). The trigger attribute defines how the link can be activated, either by clicking on it, stepping on it, or both. The text attribute defines the text that will be displayed when the mouse rolls over the link. Target names the frame or window in which the link will open, just as it does in HTML. The default target of a 3DML file is "_self"; the default target of any other file is "_blank". Like the <entrance> tag, the <exit> tag can also be assigned to a block by including it in the <create> tag, or it can be placed in the body on its own, usually at the end of the body or immediately following the level in which it occurs.

The <action> tag

     <action location="(column,row,level)"
      trigger="roll on|roll off|click on|step in|
      step out|proximity|timer|location|key down|
      key up|key hold|start" key="keyvalue" partname="name-of-part"
      radius="number-of-blocks" delay="min..max" />
          <replace source="symbol|(column,row,level)"
           target="(column,row,level)" />
          <spin angles="(angle_x,angle_y,angle_z)" active="yes|no />
          <nospin />
          <orbit source="(column,row,level)|symbol"
           distance="(x,y,z)" speed="" active="yes|no" />
          <move pattern="pattern_code" active="yes|no" />
          <ripple style="waves|raindrops" force="value"
           droprate="droprate%" damp="damp%" />
     </action>

Defines an action which takes place as a response to a particular trigger. Radius used only for trigger="step in" or "step out". Delay is only used for trigger="timer". Delay is measured in seconds. If only one delay value is specified, the delay time will remain consistent. If delay is expressed as a range from minimum to maximum times, the delay will be random within those parameters. Action tags can stand alone in the body of the 3DML file, or they can be attached to blocks inside the <create> tag. Action can also be used in an imagemap with the additional attributes of shape="rect|circle" and coords="x1,y1,x2,y2|x,y,radius".

Key values for the key parameter include:

a b c d e f g h i j k l m n o p q r s t u v w x y z
1 2 3 4 5 6 7 8 9 0
- = ~ ! @ # $ % ^ * ( ) _ + : " ? ; ' , . /
[shift]  [ctrl]  [alt]   [space]   [backspace] [enter] [insert]
[delete] [home]  [end]   [page up] [page down] [up]    [down]
[left]   [right] [pad 0] [pad 1]   [pad 2]     [pad 3] [pad 4]
[pad 6]  [pad 7] [pad 8] [pad 9]   [pad +]     [pad -] [pad *]
[pad /]  [pad .] [none]

Replace defines a block to be replaced by another. Target defines the location of the block that will be replaced. Source specifies the block that will take the place of the specified target. If no target is specified, then the source will replace the block which holds the <action> tag.

Spin rotates a block x,y,z degrees per second. Use <nospin /> to stop this action on a block.

Orbit makes one block spin around another block, like the moon orbits the earth. The source is the symbol of the block that this block should orbit. The distance is the number of pixels away the block should orbit in the x, y and z directions. The speed is the how many radians to travel per second.

Move gives a block a set of instructions to follow over time. These instructions are made up of mini commands:

  • sp = speed of motion per second (sp, x, y, z)
  • mv = number of pixels to travel (mv, x, y, z)
  • lp = loop, do the whole set of actions again when done (lp)

Example: <move pattern="(sp,100,100,100), (mv,80,0,0), (mv,0,80,0), (mv,-80,0,0),(mv,0,-80,0)(lp)" />

This moves a block in a repeating square pattern.

Ripple makes water effects on the surface of a block. Style is the type of water effect, either rain or waves. Force is the number of pixels to change the surface (randomized by both rain and water). Droprate is how often to cause a raindrop or a wave. Damp is how much to soften the effect over time, the less this amount the longer the ripples travel. Default values are style="raindrops", force="15.0", droprate="25%", and damp="85%".

The <popup> tag

     <popup location="(column,row,level)"
      trigger="rollover|proximity|everywhere"
      radius="number-of-blocks"
      texture="folder/image.gif -or- URL"
      color="(red,green,blue)"
      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="(red,green,blue)" imagemap="map name"
      brightness="brightness%" />

Popups are 2D images that get displayed on the screen when the user travels within the radius of the location defined this 2D image can be a texture (animated or still) or a color. The position and size of the popup image on the screen can be specified. Text can also appear on a popup, with a given alignment and color. When text is placed over a texture, the color attribute will define the color of a drop-shadow to make the text more legible. Finally, the brightness of the entire popup can be specified. Popups can be assigned to a location in the map in the body section, or they can be assigned to a specific block in the <create> tag. If used in the <create> tag, the location attribute is not needed. If used in the body, and no location attribute is defined, then the popup will display throughout the entire spot.

The <imagemap> tag

     <imagemap name="imagemap name">
          <area shape="rect|circle"
           coords="x1,y1,x2,y2|x,y,radius"
           href="destination URL"
           target="destination target"/>
          <area ... />
          <action shape="rect|circle"
           coords="x1,y1,x2,y2|x,y,radius"
           trigger="roll on|roll off|click on|
           step in|step out|timer">
          </action>
     </imagemap>

Defines an imagemap. Imagemaps are images that have areas that contain links to other 3DML spots or HTML pages. Imagemaps can be used in popups only. 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.

The <sound> tag

     <sound file="folder/sound.wav-or-url" name="sound name"
      location="(column,row,level)"
      volume="volume%" playback="looped|random|once|single"
      delay="minimum..maximum" radius="#_of_blocks"
      flood="yes|no" rolloff="rolloffvalue" />

Specifies a sound file that will play in the spot. Location refers to the placement of the sound in the map. The sound can either be played once, once every time the player enters the specified radius (single), 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. Flood="yes" will cause the sound to fill the specified radius at the specified volume. Radius should only be used if flood="yes" or playback="single" or "once". Rolloff determines how quickly the sound will taper off as you move away from the source. Sounds can also be assigned to specific blocks within the <create> tag. If used in the <create> tag, the location attribute is not necessary. Default values are as follows: volume="100%", playback="looped", delay="5..10", radius="1", flood="no", and rolloff="1.0".

The <point_light> tag

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

Defines a static light at a specific location in the map that shines in all directions. Location refers to the placement of the light in the map. Position refers to the position of the light within the 256-pixel blockspace. Flood="yes" will cause the light to fill the radius at the specified brightness. Flood="no" will create a light that is the specified brightness at the center, and gradually drops off to the ambient_light level at the far end of the radius. The default value is flood="no". Colored light will only be visible on 3D acceleration hardware. Lights can also be assigned to specific blocks within the <create> tag. If used in the <create> tag, the location attribute is not necessary.

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

Defines a point_light that constantly pulses from the minimum brightness to the maximum brightness. If speed="2", the light will go from the minimum brightness to the maximum and back again 2 times per second.

The <spot_light> tag

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

Defines a static spot_light at a specified location that shines in a specified direction. Direction is expressed as a pair of angles. The turn angle describes a direction in the horizontal plane, from 0 to 359 degrees, with 0 being north. The tilt angle describes a direction in the vertical plane, from -90 to 90 degrees, with 90 pointing straight up, 0 pointing at the horizon, and -90 pointing straight down. The cone describes how wide the light is in degrees.

     <spot_light style="search" location="(column,row,level)"
      position="(x,y,z)" brightness="n%" radius="blocks"
      flood="yes|no" color="(red,green,blue)"
      direction="(turn1,tilt1)..(turn2,tilt2)"
      cone="angle" speed="cycles_per_second" name="light name" />

Defines a searching spot_light that moves from direction 1 to direction 2 and back again at the specified speed.

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

Defines a rotating spot_light that passes through directions 1 and 2 at the specified number of revolutions per second.

The <script> tag

Call functions and perform other scripting operations. See RoverScript Reference for more information.

     <script trigger="delay|proximity|roll on|roll off|
      click on|step in|step out|proximity|timer|location|
      key down|key hold|key up" delay="seconds"
      radius="#_of_blocks" key="keyvalue">
          ... script ...
     </script>

The <player> tag

     <player size="(x,y,z)" camera="(x,y,z)" block="block name"
      move_forward="key" move_back="key"
      move_left="key" move_right="key"
      look_up="key" look_down="key"
      sidle_mode="key" fast_mode="key"
      go_faster="key" go_slower="key" />

The default values for the <player> tag are: move_back="[up]",
move_back="[down]", move_left="[left]", move_right="[right]", look_up="a",
look_down="z", sidle_mode="[shift]", fast_mode="[ctrl]", go_faster="[pad +]",
and go_slower="[pad -]".

last updated Wednesday January 15 2003


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" 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="@village:sqcel.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">
     .. .. .. .. .. .. .. .. ..
     .. .. .. .. .. .. .. .. ..
     .. .. .. .. .. .. .. .. ..
     .. .. .. .. .. .. .. .. ..
     .. .. .. .. .~ .. .. .. ..
     .. .. .. .. .. .. .. .. ..
     .. .. .v .. .. .. .@ .. ..
     .. .. .. .. .. .. .. .. ..
     .. .. .. .. .. .. .. .. ..
     </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>

16. Tips and Tricks

Posting spots to the Web

Be sure and read the section on Putting it on the Web. You may need to do a little bit of configuring for people to be able to see your spots.

Using TextPad

The best text editor that we have found for editing 3DML files is a shareware application called TextPad. TextPad has several features that make it ideal for 3DML, including line numbers and a Block Select mode that allows you to select blocks of text regardless of line breaks. You can download TextPad at http://www.textpad.com.

Once you have installed TextPad, you can turn on the line numbering feature under the View menu. This is very useful when correcting errors, as error messages usually tell you the line number where the error occured. You will find the Block Select Mode under the Configure menu. With this feature turned on, you can select and move or edit columns of your 3DML map. TextPad also has very good search and replace tools. You'll find these under the Search menu.

We have also created 3DML Clip Libraries for TextPad. These will provide the tag syntax of each tag in 3DML, which you can then edit in your 3DML file. You don't have to remember all the syntax! You can download the clip libraries for TextPad 3.x hereor for TextPad 4.x hereAfter the download is complete, double click on the file cliplib.exe. This is a self-extracting archive that will install the libraries in TextPad's User folder. Check the accompanying readme file for instructions on how to use the clip libraries.

Embedding in HTML

Often, there are good reasons to provide 2D information along with your 3D spots. In addition to popups, spots can be easily incorporated into HTML pages with the <embed> tag:

     <html>
     <head>
     <title>My First Spot!</title>
     </head>
     <body bgcolor="#000000" leftmargin="0"
      topmargin="0" scroll="no">
     <embed type="model/vnd.flatland.3dml"
      src="firstspot.3dml"
      pluginspace="http://www.flatland.com/download_direct.html"
      height="100%" width="100%">
     </body>
     </html>

This code would display firstspot.3dml in an HTML document. If a user doesn't have Rover, they will be prompted to go to the download page. The <embed> tag can be used to put spots inside html frames or tables as well.

File Size

Just as with regular HTML pages, the file size of 3DML files themselves are very small, and easily downloadable. It's the images and sounds that are much larger and can make for lengthy download times. Rover ships with all of the default textures already installed, so if you use all default textures in your spot, then the entire thing is just a very small text file. Ultimately, you will always just have to weigh the need for speedy download with the need for custom textures. To shorten download times, make sure your image files are properly prepared for Web delivery. When possible, use smaller textures that can be tiled, rather than large images. 3DML currently only supports .wav files for sounds, which are generally rather large. So sound should be used rather sparingly. Short looped sounds are much preferred to longer sounds.

Interesting Shapes

Don't pass up the flexibility that the orient parameter affords in creating interesting shapes! All of the blocks have up to 16 different orientation possiblities. Experiment with flipping blocks upside down and putting them together in different combinations to make unexpected structures.

Transparency

3DML fully supports gif89 images, meaning transparency and animation are available to you as design tools. Transparency can be used very effectively in spots, but you should be aware that using too much transparency can adversely affect the performance of Rover. The best places to use transparency are on sprites and popups, because they are only 1 polygon. When you put transparent textures on 3D blocks, Rover has to keep track of transparency on many polygons at once, which can tax performance. If it seems that your spot is running slowly, try cutting down on the amount of transparency used in the spot, and see if that helps performance.

Variations in Performance

We are all used to dealing with the wide disparity between different bandwidth conections to the Internet. A highly graphic site with several sounds may not be a big deal on a T1 line, but it can be tedious on a 56.6kbps modem. Like all other web media, this is true for 3DML as well. With 3DML spots, processor speed is also a consideration. Just because you built your spot on a top-of-the-line Pentium 400 doesn't mean that everyone who looks at it is going to get the same blinding performance out of it. As a general rule, users who don't have at least a Pentium 166 may have some trouble navigating 3DML spots.

HELP TELL THE WORLD ABOUT FLATLAND!

As independent newcomers to the Web, Flatland relies on the grassroots enthusiasm of every Builder on the web exploring with 3DML and the Rover. If you've enjoyed exploring 3D on the Web with Rover, or built your own 3D spot using 3DML, help spread the word! One way to help other folks know about how easy 3D on the Web can be is to put a "Download Rover" or "Powered by 3DML" button on your site. To do so, you can simply cut and paste the following html text, or click on either (or both!) of these buttons below, and your browser will let you save the image. You can then add it to your web site any way you prefer.

To add a Powered by 3DML button to your site, you can cut and paste the following HTML into your web page:

     <a href="http://www.flatland.com"><img
      src="http://www.flatland.com/imgz/buttons/powered_by_3DML.gif"
      border="0" alt="Powered by 3DML!" height="30" width="90"></a>

To add a Download Flatland Rover button to your site, you can cut and paste the following HTML into your web page:

     <a href="http://www.flatland.com/download/"><img
      src="http://www.flatland.com/imgz/buttons/download_button.gif"
      border="0" alt="Download Flatland Rover Now!" height="30"
      width="90"></a>

Congratulations! You've now completed the 3DML tutorial. If you have any questions, please, ask away! Now that you've built your first two spots, the "first spot" and the "tallspot", it's time to build your own unique 3D spot. And once you have, let us know, and we'll add it to the growing directory of 3DML spots on the web!

last updated Friday February 28 2003


Block Building Guide

What is a blockset?

Blocksets contain the building blocks of 3DML spots. A blockset file (*.bset) can contain blocks (*.block), textures (*.gif, *.jpg), sounds (*.wav), and a style file (*.style).

You can examine the contents of the blocksets on your machine. First, browse to the folder where your blocksets are kept; this is usually C:\\Program Files\Flatland\Flatland. Then browse a folder like \blocksets.flatland.com\flatsets. In this folder there should be at least one blockset, like basic.bset. Copy this file to a convenient place. Change the extension of the copied file from .bset to .zip, and unzip the folder using whatever archive extraction utility you use (i.e., WinZip, Stuffit, etc.). You can now look at the blocks, textures, and sounds that were in the blockset.

What tools are recommended for building blocks?

Currently, there is no modelling program that natively creates blocks. Blocks can be created by exporting from a 3D modelling program to a RayDream Studio mesh format (.rds) and converting them, or by hand-coding them. This tutorial assumes the use of the following tools.

Metasequoia by Mizno Lab. Easy-to-use 3D modeling tool that can export to RayDream mesh format (*.rds). Unless you live in Japan, download MetasequoiaLE, the freeware version.
[download MetasequoiaLE]

Block-IT! by Simon Bailey (AKA Morpheus) at Inside Track. RayDream mesh format (*.rds) to block format (*.block) conversion utility. Essential, if you plan on the Metasequoia -> Block-IT! -> EditBset or RayDream Studio -> Block-IT! -> EditBset method of block building.
[form to download]

Block2MetaS by Mike Jost (AKA MJ). Block format to MetaS format conversion utility.
[download Block2MetaS]

EditBset by Flatland. The blockset editor, a must-have for any blockset editing.
[download EditBset]

DXF2Block by Flatland. A DXF format (*.dxf) to block format (*.block) conversion utility. If you've have models in the right proprietary DXF format, it could be useful. No instructions provided here for its use.
[download DXF2Block]

Photoshop by Adobe. Great for creating and editing textures, but expensive.

GoldWave by GoldWave, Inc. An excellent shareware sound-editing utility.

WinZip or another archiving and extracting utility, for opening blocksets and batch file insertions.

Notepad, or any other non-formatting text-editor. For hand-coding and examining blocks.

Building Blocks Methods

The Hand-Coded Method

It is possible to hand-code your own blocks, since blocks are simply XML files describing the vertices and polygons that make up your block. To hand-code blocks, you must understand the block syntax. See 3DML Tag Guide: General Rules About 3DML Tags.

The <block> tag

Like the <spot> tag, the <block> tag begins and ends the block.

Like in 3DML, the code is organized in some basic container tags. The whole block is enclosed by the <block> ... </block> tag. The <block> tag has (at least) two parameters: name and type. Name defines the name for the block and should be equal to the blockfile name. Type should be set to "structural", this is the setting for common building blocks.

The <vertices> and <vertex> tags

In the <vertices> tag, you will have to define the 'edges' of your block, those points in the block space that define the ends of your polygon's sides.

The <parts> and <part> tags

In the <parts> tag, you define the parts of your block with the polygons that form them.

Tip: If you plan to edit your own block basing on one of Flatland's blocks, be sure to delete all <front> and <rear> tags as well as the line saying <bsp_tree root="1"/>. These are information for the binary tree, which you can hardly code by hand. They will be generated automatically, as soon as you load your block into EditBset and click on the "Add BSP tree" button.

The <polygon> tag

COMING SOON

The other tags

If you open up a blockset and look at block file, you might notice a few tags and parameters that you didn't put in your hand-coded block: the <bsp_tree> tag, the texcoords parameter, the front and rear parameters.

Also, if you wish to document your block code, you can add comments just like in your spots:

    <!-- your comments here -->

Defining the vertices

The first thing to do, is to define all the vertices of your block. You should draw your block on a piece of paper and calculate x, y, and z values for each point. Rover uses a left-handed coordinate system, with (0,0,0) in the bottom south-west corner of the block. Positive x is eastward, positive y is upward, positive z is northward.

Now for each point, add a <vertex ref="n" coords="(x,y,z)" /> tag to the vertices container, where "n" is a counting number starting with 1 and x,y,z are the above calculated coordinates. For efficiency's sake, vertices that are shared by polygons should only be defined once. You should also note the vertex's number (n) on your paper drawing. This will make things easier later.

Note: there's no rule, what vertex has to be defined first or last. Just make sure, that you have no double ref numbers and you don't define the same vertex twice.

Defining the polygons and parts

Next you'll have to define the polygons (surfaces) of your block. However, since polygons have to be nested in parts, add a <part> ... </part> container tag inside the <parts> tag.

The <part> tag here has the same attributes as the <part> tag in 3DML, so you can add everything from texture, color, faces to solid to the tag as default values for the part. One thing you have to add is the name attribute of course!

Now, inside the <part> tag, add a <polygon ref="n" vertices="v,v,v..." texcoords="..." /> tag. The ref attribute "n" is again a counting number for all polygons in the block. Don't use the same number twice! In the vertices attribute, list the associated vertices that form the polygon in clockwise order around the front face.

Note: there's no rule, what polygon has to be defined first or last. Just make sure, that you have no double ref numbers and you don't define the same polygon twice.

The texcoords define which corner of a texture will be attached to a given vertex. You just have to define a list of special parenthesis values corresponding to the vertices listed before. Set (0,0) for the top-left corner, (1,0) for the top-right corner, (1,1) for the bottom-right corner and (0,1) for the bottom-left corner. If your polygon has only 3 vertices, you'll have to decide, which of the four corners can be left out.

But wait, there's help! You don't necessarily have to define the texcoords at all. EditBset will generate all the texcoords automatically when loading the block. However EditBset isn't perfect, so it makes its best guess as to which vertex should get (0,0) so that the top edge of the texture is pointing up (or in the case of polygons that face up or down, so that the top edge of the texture is pointing north).

I would recommend that for triangles you put in the texture coordinates yourself, since EditBset may not make the correct choice. But it should figure out quads (squares, rectangles etc.) okay. Polygons with 5+ sides don't support the "stretched" texture style; EditBset will generate texture coordinates for a "scaled" texture style in that case.

Example: The Full Block

<block name="full" type="structural">
    <vertices>
        <vertex ref="1" coords="(   0.00000, 256.00000,   0.00000)"/>
        <vertex ref="2" coords="(   0.00000, 256.00000, 256.00000)"/>
        <vertex ref="3" coords="( 256.00000, 256.00000, 256.00000)"/>
        <vertex ref="4" coords="( 256.00000, 256.00000,   0.00000)"/>
        <vertex ref="5" coords="(   0.00000,   0.00000,   0.00000)"/>
        <vertex ref="6" coords="( 256.00000,   0.00000,   0.00000)"/>
        <vertex ref="7" coords="( 256.00000,   0.00000, 256.00000)"/>
        <vertex ref="8" coords="(   0.00000,   0.00000, 256.00000)"/>
    </vertices>
    <parts>
        <part name="top" texture="cement.gif">
            <polygon ref="1" vertices="1,2,3,4"/>
        </part>
        <part name="bottom" texture="cement.gif">
            <polygon ref="2" vertices="5,6,7,8"/>
        </part>
        <part name="s" texture="cement.gif">
            <polygon ref="3" vertices="1,4,6,5"/>
        </part>
        <part name="w" texture="cement.gif">
            <polygon ref="4" vertices="5,8,2,1"/>
        </part>
        <part name="n" texture="cement.gif">
            <polygon ref="5" vertices="8,7,3,2"/>
        </part>
        <part name="e" texture="cement.gif">
            <polygon ref="6" vertices="4,3,7,6"/>
        </part>
    </parts>
</block>

When you have finished coding your block, you will need to import it into EditBset.

The MetaSequoia to Block-Ed to EditBset Method

MetaSequoia

For modeling, I use MetaSequoia. It's easy to use, and lacks the frills of most modeling programs that would just get in the way of simple block-building.

I find that setting the View > Grid > Interval to 32 or 64 and the Mesh size to 256 makes it easy to judge the size of your model relative to the 256 x 256 x 256 block size.

Converting the Model

Convert MetaSequoia models to blocks using the following procedure:

  1. Open your MetaS. model (*.mqo) file in MetaSLE.
  2. Select Edit > select all.
  3. Select Selected > Invert.
  4. Select File > Save As....
  5. Select Save as type: RayDream Studio (*.rds) and give your file a name.
  6. Set Size : Multiply to 1.
  7. Click Axis : Swap XY.
  8. Click Axis : Swap YZ.
  9. Click OK.
  10. Open the Block-IT! program.
  11. Find and select your .rds file in the Source -RDS(.rds) folder tree.
  12. Give your block a name, and a default texture.
  13. Select a destination folder from the Desination - Flatland Rover (.block) folder tree.
  14. Click Convert.

From there, use EditBset to add the .block file to your blockset.

Using EditBset

With EditBset, you can open any blocksets, edit all blockset parameters like version, placeholder, sky, ground and orb settings. You can also create new blocksets, load textures and sounds into it. And last but not least, you can even load your very own block definition files (*.block) into the blockset and let EditBset calculate those nasty BSP trees!

Hosting your Blocksets

If you want others to be able to download your blockset, you need to upload your blockset to your server.

Your blockset will be cached by Rover in the same way as the Flatland blocksets. Once downloaded, you will find it in the Flatland folder on your hard drive in a folder named after your server's domain name. So, if your blockset is hosted on:

    http://www.yourserver.com/yourdirectory/blocksets

then the blockset will be downloaded to:

    C:\\Program Files\Flatland\Flatland\www.yourserver.com\yourdirectory\blocksets

Managing Blocksets

Rover has a built-in blockset manager. When you load a spot, click the Controls icon and select Manage blocksets on my hard drive. You can view and delete blocksets, force a blockset to reload, and set the interval that Rover waits before checking for blockset updates.

last updated Friday January 03 2003


RoverScript Reference

RoverScript: 3DML Scripting Reference

RoverScript is a scripting language interpreted by the Flatland Rover. The open source scripting engine, called SimKin, was developed by Simon Whiteside. For more information on SimKin, visit http://www.simkin.co.uk/.

Just as JavaScript extends the functionality of HTML web pages from static content to dynamic content, RoverScript extends the functionality of 3DML spots.

This guide is current for Rover version 3.4.

The <define> tag

Defines script variables and functions. The <define> tag can be contained by <body> and <create> tags. Variable name, attributes, and values follows this format:

     <define>
          <variablename>variablevalue</variablename>
          <!-- or -->
          <variablename attribute="value" />
     </define>

The <function> tag

Defines a named script function. Contained by <define> tags.

     <function name="functionname">
     ... function definition ...
     </function>

Note: A function with name="start" will run automatically before the spot is rendered.

The <script> tag

Call functions and perform other scripting operations.

     <script trigger="(delay|proximity|roll on|roll off|
      click on|step in|step out|proximity|timer|location|
      key down|key hold|key up)" delay="seconds"
      radius="#_of_blocks" key="keyvalue">
     ... script ...
     </script>

Comments

     // text following double slashes is ignored to end of line
     /* text between slash-asterix is ignored,
     even on multiple lines */

Syntax

A single statement may be spread over multiple lines. All statements must end in a semi-colon.

Operators

Mathematical

Addition

     x + y

Subtraction

     x - y

Multiplication

     x * y

Division

     x / y

Modulus

     x % y

Assignment

x = y

Comparison

Equality

     x = y

Inequality

     x != y

Greater Than

     x gt y

Greater Than or Equal To

     x ge y

Less Than

     x lt y

Less Than or Equal To

     x le y

Logical

AND

     x and y

OR

     x or y

NOT (negation)

     not x

String Concatenation

     myString = "My" # "String"

Statements

Compound

     {
          do this;
          do that;
     }

If-Else

     if ( expression )
     { do this }
     else
     { do that }

Switch-Case

     switch (x)
     {
          case y { do this }
          case z { do that }
          default { do default }
     }

While-Do loop

     while ( expression ) { do this }

Do-While loop

     do { do this } while ( expression )

For loop

     for loopvar = startval to endval { do this }
          <!-- or -->
     for loopvar = startval to endval step stepval { do this }

For-Each loop

     for each item in collection { do this with item }

Pre-defined objects

spot

The spot object holds miscellaneous information about the spot and the PC it is running on. It also holds all of the global variables and functions defined in the stand-alone <define> tag in a spot.

Variable | Type | Access | Description | Example
spot.title | string | read/write | A string that holds the title of the spot. | spot_title_time.3dml
spot.time:hour | integer | read only | The current hour (0-23). | spot_title_time.3dml
spot.time:minute | integer | read only | The current minute (0-59). | spot_title_time.3dml
spot.time:second | integer | read only | The current second (0-59). | spot_title_time.3dml
spot.time:millisecond | integer | read only | The current millisecond (usually measured since the PC was booted, but the start point should be considered undefined). | spot_title_time.3dml
spot.user_can_move | boolean | read/write | Flag indicating whether the user is permitted to move around via the mouse or keyboard. | spot_user_can_move.3dml
spot.user_can_look | boolean | read/write | Flag indicating whether the user is permitted to look around via the mouse or keyboard. | spot_user_can_look.3dml

Function | Return Type | Description
spot.new_array() | array object | Creates a new array object with no elements.
spot.free_array(array) |  | Destroys the array object passed in the argument.
spot.log(string) |  | Writes a string to the log file.
spot.start() |  | Supplied by the builder of the spot: will be called when the spot starts, before anything else happens. This function is optional.
spot.stop() |  | Supplied by the builder of the spot: will be called when the spot stops. This function is optional.

array

An array object holds zero or more elements of any type. Note that in the following table, "array" is a placeholder for the name of the variable holding an array object.

Variable | Type | Access | Description
array.elements | integer | read only | The number of elements in the array.
array[index] | any type | read/write | The array element at the given index.

Function | Return Type | Description
array.insert(index, value) |  | Inserts a new element before the given index.
array.prepend(value) |  | Inserts a new element at the start of the array.
array.append(value) |  | Inserts a new element at the end of the array.
array.delete(index) |  | Deletes the element at the given index.

math

The math object provides mathematical functions and constants.

Variable | Type | Access | Description
math.pi | real | read only | Holds the constant p.

Function | Return Type | Description
math.random(min,max) | integer | Returns a random integer between min and max.
math.sqrt(x) | real | Returns the square root of x.
math.sin(x) | real | Returns the sine of x; x is in radians.
math.cos(x) | real | Returns the cosine of x; x is in radians.
math.tan(x) | real | Returns the tangent of x; x is in radians.
math.asin(x) | real | Returns the arc sine of x in radians.
math.acos(x) | real | Returns the arc cosine of x in radians.
math.atan(x) | real | Returns the arc tangent of x in radians.
math.rad(x) | real | Converts x from degrees to radians.
math.deg(x) | real | Converts x from radians to degrees.
math.abs(x) | real | Returns the absolute (positive) value of x.

fog

The fog object controls the appearance of the fog in a spot.

Variable | Type | Access | Description | Example
fog.color:red | real | read/write | The red component of the fog color (0-255). |
fog.color:green | real | read/write | The green component of the fog color (0-255). |
fog.color:blue | real | read/write | The blue component of the fog color (0-255). |
fog.density | real | read/write | The density of the fog, as a percentage (0-100). |
fog.startradius | integer | read/write | The starting distance of the fog, in blocks. |
fog.endradius | integer | read/write | The ending distance of the fog, in blocks. |

sky

The sky object controls the look of the sky in a spot.

Variable | Type | Access | Description | Example
sky.brightness | real | read/write | The brightness of the sky, as a percentage (0-100). | sky_brightness_color.3dml
sky.color:red | real | read/write | The red component of the sky color (0-255). | sky_brightness_color.3dml
sky.color:green | real | read/write | The green component of the sky color (0-255). | sky_brightness_color.3dml
sky.color:blue | real | read/write | The blue component of the sky color (0-255). | sky_brightness_color.3dml
sky.texture | string | read/write | The URL of the sky texture. | sky_texture.3dml

ambient_light

The ambient_light object controls the behaviour of the ambient light in a spot.

Function | Type | Access | Description | Example
ambient_light.brightness | real | read/write | The brightness of the ambient light, as a percentage (0-100). | ambient_light.3dml
ambient_light.color:red | real | read/write | The red compoent of the ambient light color (0-255). | ambient_light.3dml
ambient_light.color:green | real | read/write | The green component of the ambient light color (0-255). | ambient_light.3dml
ambient_light.color:blue | real | read/write | The blue component of the ambient light color (0-255). | ambient_light.3dml

ambient_sound

The ambient_sound object controls the behaviour of the ambient sound in a spot.

Variable | Type | Access | Description | Example
ambient_sound.file | string | read/write | The URL of the wave file. | ambient_sound.3dml
ambient_sound.volume | real | read/write | The volume of the sound, as a percentage (0-100). | ambient_sound.3dml
ambient_sound.playback | string | read/write | The playback mode of the sound, which is one of the following: "looped", "random", "single", "once". | ambient_sound.3dml
ambient_sound.delay:minimum | real | read/write | The minimum delay between playbacks, in seconds. | ambient_sound.3dml
ambient_sound.delay:range | real | read/write | The maximum additional delay between playbacks, in seconds. | ambient_sound.3dml

orb

The orb object controls the appearance of the orb and its light source in a spot.

Function | Type | Access | Description | Example
orb.brightness | real | read/write | The brightness of the orb light, as a percentage (0-100). | orb_all.3dml
orb.color:red | real | read/write | The red component of the orb light color (0-255). | orb_all.3dml
orb.color:green | real | read/write | The green component of the orb light color (0-255). | orb_all.3dml
orb.color:blue | real | read/write | The blue component of the orb light color (0-255). | orb_all.3dml
orb.position:angle_x | real | read/write | The angle of the orb above or below the horizon (90 is directly above, -90 is directly below). | orb_all.3dml
orb.position:angle_y | real | read/write | The direction of the orb (0 is north, 180 is south). | orb_all.3dml
orb.texture | string | read/write | The URL of the orb texture. | orb_all.3dml
orb.href | string | read/write | The URL of the orb hyperlink. | orb_all.3dml
orb.target | string | read/write | The target window of the orb hyperlink. | orb_all.3dml
orb.text | string | read/write | The popup text of the orb hyperlink. | orb_all.3dml

player

The player object represents the user's position and viewpoint in the spot.

Variable | Type | Access | Description
player.location:column | integer | read only | The column the player is nearest to.
player.location:row | integer | read only | The row the player is nearest to.
player.location:level | integer | read only | The level the player is nearest to.
player.location:x | real | read/write | The x coordinate of the player.
player.location:y | real | read/write | The y coordinate of the player.
player.location:z | real | read/write | The z coordinate of the player.
player.orientation:look_angle | real | read/write | The look angle of the player (-90 is up, 90 is down).
player.orientation:turn_angle | real | read/write | The turn angle of the player (0 is north, 180 is south).
player.size:x | real | read/write | The player size along the X axis.
player.size:y | real | read/write | The player size along the Y axis.
player.size:z | real | read/write | The player size along the Z axis.
player.camera:x | real | read/write | The camera offset along the X axis.
player.camera:y | real | read/write | The camera offset along the Y axis.
player.camera:z | real | read/write | The camera offset along the Z axis.
player.move_forward | string | read/write | The key(s) for moving forward. 1
player.move_back | string | read/write | The key(s) for moving back. 1
player.move_left | string | read/write | The key(s) for turning/sidling left. 1
player.move_right | string | read/write | The key(s) for turning/sidling right. 1
player.look_up | string | read/write | The key(s) for looking up. 1
player.look_down | string | read/write | The key(s) for looking down. 1
player.sidle_mode | string | read/write | The key(s) that when held down change turning to sidling. 1
player.fast_mode | string | read/write | The key(s) that when held down causes the player to move at maximum speed. 1
player.go_faster | string | read/write | The key(s) for increasing speed. 1
player.go_slower | string | read/write | The key(s) for decreasing speed. 1
Notes: 1The syntax of the string is the same for the equivilant attributes of the <player> tag, i.e. a key is either an alphanumeric character, or a special key name in square brackets (such as "[page up]"). At most two keys can be assigned to one player function, the key names must be seperated by a comma.

map

The map object provides variables and functions associated with the map.

Variable | Type | Access | Description
map.dimensions:columns | integer | read only | The number of columns in the map.
map.dimensions:rows | integer | read only | The number of rows in the map.
map.dimensions:levels | integer | read only | The number of levels in the map.

Function | Return Type | Description
map.get_block(column, row, level) | block object | Returns the fixed or movable block at the given map location, or null if there is none. A fixed block takes precedence.
map.get_block(symbol) | block object | Returns the fixed or movable block with the given symbol.
map.get_blocks(column, row, level) | array object | Returns an array of fixed and movable blocks at the given map location. Array is automatically deallocated.
map.get_blocks(symbol) | array object | Returns an array of fixed or movable blocks with the given symbol. Array is automatically deallocated.
map.set_block(column, row, level, symbol) |  | Places a block with the given symbol on the given map location, replacing whatever block may have been there.
map.move_block(column1, row1, level1, column2, row2, level2) |  | Moves a block from one map location to another. The original map location becomes empty, and the block that was at the new map location, if any, is replaced.

block

A block object represents one block on the map, and provides ways to manipulate it. Note that in the following tables, "block" is a placeholder for a variable that is holding the block object. Also note that the variables below are only writable if the block is movable. Finally, any variables or functions defined in a <define> tag inside of a <create> tag will be associated with the block of that symbol.

Variable | Type | Access | Description
block.location:column | integer | read/write | The column the block is in (or near if movable).
block.location:row | integer | read/write | The row the block is in (or near if movable).
block.location:level | integer | read/write | The level the block is in (or near if movable).
block.location:x | real | read/write | The x coordinate of the block, in "pixels".
block.location:y | real | read/write | The y coordinate of the block, in "pixels".
block.location:z | real | read/write | The z coordinate of the block, in "pixels".
block.origin:x | real | read/write | The X coordinate of the origin around which the block rotates, in "pixels".
block.origin:y | real | read/write | The Y coordinate of the origin around which the block rotates, in "pixels".
block.origin:z | real | read/write | The Z coordinate of the origin around which the block rotates, in "pixels".
block.bbox:min_x | real | read only | The minimum x coordinate of the block's bounding box.
block.bbox:min_y | real | read only | The minimum y coordinate of the block's bounding box.
block.bbox:min_z | real | read only | The minimum z coordinate of the block's bounding box.
block.bbox:max_x | real | read only | The maximum x coordinate of the block's bounding box.
block.bbox:max_y | real | read only | The maximum y coordinate of the block's bounding box.
block.bbox:max_z | real | read only | The maximum z coordinate of the block's bounding box.
block.vertices | integer | read only | The number of vertices the block has.
block.vertex[index]:x | real | read/write | The x coordinate of vertex[index].
block.vertex[index]:y | real | read/write | The y coordinate of vertex[index].
block.vertex[index]:z | real | read/write | The z coordinate of vertex[index].
block.orig_vertex[index]:x | real | read only | The original x coordinate of vertex[index], before it was modified. 1
block.orig_vertex[index]:y | real | read only | The original y coordinate of vertex[index], before it was modified. 1
block.orig_vertex[index]:z | real | read only | The original z coordinate of vertex[index], before it was modified. 1
block.movable | boolean | read only | Flag indicating if the block is movable.
block.symbol | string | read only | The symbol of the block.
block.name | string | read only | The name of the block.

Function | Return Type | Description
block.get_vertices(); | Returns an array of vertices. Array is automatically deallocated.
vertex_array.set(i,x,y,z); | Sets coordinates of vertex x,y,z at index i of vertex array when set_vertices() is called.
block.set_vertices(); | Sets the vertices of the block.
block.reset_vertices(); | Resets the coordinates of all vertices to their original values.
block.orient(compass_direction, angle); | Sets the orientation of the block, by first tipping the block over so that the top of the block faces in the compass direction (which can be one of the following values: "north", "east", "south", "west", "up" or "down"), then rotating the block around the axis pointing in that compass direction. 2
block.orient(y_angle, x_angle, z_angle); | Sets the orientation of the block, by first rotating the block around the y axis, then the x axis, then the z axis. 2
block.rotate_x(angle); | Rotates the block around the x axis by the given angle.
block.rotate_y(angle); | Rotates the block around the y axis by the given angle.
block.rotate_z(angle); | Rotates the block around the z axis by the given angle.

Notes:
1 The orig_vertex array holds the original coordinates of all vertices in a block, as defined in the blockset. Any changes made to the vertices of a block, either via the vertex array, the orient or rotate functions, or the orient attribute of the <param> tag in the 3DML file, are not reflected in the orig_vertex array. The reset_vertices function can be used to reset all coordinates in the vertex array to the coordinates in the orig_vertex array.

2 The orient functions start with the original coordinates of all vertices, and then orient the block to a new position. This means that any other changes you've made to the vertices will be lost. If you want to make culmulative changes to the vertices, you should use the rotate functions instead, which are more flexible since you can control the order in which you rotate the block around the x, y and z axes. The orient functions are intended to mimic the behaviour of the orient attribute of the param tag, and hence are rather limited in scope.

last updated Friday January 17 2003