Image Transitions Manual

1. Using the Script

This is the basic user guide, which will show you how to use the transition methods, how to use the script to pre-load images, and edit its global configuration. There's also information to help you understand the script's debugging messages.

  1. Transition methods
  2. Utility methods
  3. Public properties
  4. Debugging messages

Transition methods

There are seven transition methods currently available:

fade An opacity-fade effect
wipe A clip-based revealing effect
slide A position-based sliding or pushing effect
grow A transform-based scaling effect
twist A transform-based rotation effect
skew A transform-based geometric-distortion effect
bars Multiple clip-based bars, squares and checkerboard effects

You can run transitions on any number of images simultaneously, but each single image can only have one transition running on it at any one time. The script doesn't create the images, it adds effects to existing images defined in HTML, for example:

<img id="flag" src="images/blue.png" alt="Blue Flag" />

All the transition methods use identical syntax — except for fade, which is slightly different because it has fewer arguments; here's an example of the fade method's syntax:

Transitions.fade(
    "#flag",                // image reference     [REQUIRED String|Object]
    "images/red.png",       // new SRC             [REQUIRED String]
    "Red Flag",             // new ALT text        [REQUIRED String]
    "2"                     // duration            [REQUIRED String|Number] 
    );

And here's an example of the syntax used by all the other methods — it's basically the same except for three additional arguments at the end:

Transitions.wipe(
    "#flag",                // image reference        [REQUIRED String|Object]
    "images/red.png",       // new SRC                [REQUIRED String]
    "Red Flag",             // new ALT text           [REQUIRED String]
    "2",                    // duration               [REQUIRED String|Number] 
    "RND",                  // animation type         [REQUIRED String]
    "75%",                  // fade depth             [OPTIONAL String|Number]
    "Yes"                   // reverse transition     [OPTIONAL String|Boolean]  
    );

Please note: The arguments passed to transition methods are only validated when using the development version of the script ("transitions.debug.js", which is included in the download archive, and produces debugging messages to alert you to the error). It's best to use the development version while you're still experimenting with the script, then switch to the production version when you're ready to go live.

Arguments

Image reference [REQUIRED String|Object]

A reference to the image you're using — which can either be an Object reference to the <img> element itself, or a String of the image's ID with a leading "#" (like an ID-selector in CSS).

New SRC [REQUIRED String]

A String that specifies the SRC of the new image, that will be swapped as part of the transition.

New ALT text [REQUIRED String]

A String that specifies ALT text for the new image, that will be updated at the same time as the SRC is swapped.

You can set this to any string value, including an empty string, but you cannot omit it entirely. If you want the ALT text to remain unchanged, you can always pass a property reference from the original image:

var image = document.getElementById('flag');

Transitions.fade(image, "red.png", image.alt, "2");
Duration [REQUIRED String|Number]

A numeric-String or Number that specifies the total length of the transition, in seconds.

The duration doesn't have to be a whole number of seconds, a floating-point value is fine. If you define it as a string it will be converted to a float, therefore you can use any value that would be valid for such a conversion.

The minimum duration for a transition depends on the "step-resolution" value (which is one of the configuration options you can edit). If you've never changed that value then the default minimum duration is "0.25" seconds.

Animation type [REQUIRED String]

A String that specifies the particular animation effect to use for this transition.

All the transitions, apart from fade, can create a whole range of different effects, and each of these is defined by an animation type. The type itself is a short letter-code that represents a description of the type, such as "LR" for Left to Right (for a wipe or grow transition).

You can select a random type for any of these transitions, by setting the value "RND". Otherwise, the range of possible values is different for different transitions: wipe/grow, slide, twist, skew and bars.

For details of all the animation types, see :: Animation types.

Fade depth [OPTIONAL String|Number]

A String or Number that specifies the depth of an additional opacity-fade, to apply to the transition at the same time as its main effect.

You can set this with a string percentage from "0%" to "100%", or with a floating-point number between 0 and 1.

For example, if you set this to "75%" as part of a left-to-right wipe transition, then the new image that's appearing from the left will also fade-in, from 25% to full opacity over the duration of the transition. At the same time, the original image underneath will fade-out, from full opacity down to 25%.

If undefined this argument defaults to 0 (no added fade).

Reverse transition [OPTIONAL String|Boolean]

A String or Boolean that specifies whether to reverse the effect of the transition. For example, instead of wiping left-to-right to cover the original image with the new one, it would wipe right-to-left to reveal the new image underneath.

To enable reverse you can set this to true, or to "yes", "y", "1" or "-" (all of those values are case-insensitively recognised as true-ish, therefore any other String value will be treated as false). If you prefer, you can think of this as a transition direction flag, and set it to "+" or "-" to specify forward or reverse.

If undefined this argument defaults to false (don't reverse).

Note: callback oncomplete

The transition methods also accept an asynchronous callback function, which if present, will be fired when the transition is complete. This is documented separately; For more about transition callbacks, see :: Defining the transition callback.

Return value [Boolean|Object]

Return value

All the transition methods return true, false or null, to indicate the result of the operation:

  1. If the browser doesn't support this (if it doesn't support the specific transition, or it doesn't support the script at all; or it does support the transition but images are disabled in the browser), then the method will return null (to indicate exclusion).
  2. If the browser is fine but a transition is already in progress on the specified image, then the method will return false (to indicate that it's busy).
  3. Otherwise, if all is well, then the method will return true (to indicate success).

Since transitions are asynchronous, the method will return long before the transition itself is complete; in fact in practice, it will return before the transition has even begun. If the transition method throws an error, then obviously it won't return at all.

Also see :: Fallback behavior for partially-supported browsers.

Animation types

Animation types for the “wipe” and “grow” methods

The wipe and grow transitions have an identical range of animation types — each supports 15 different types, specified by the following letter-codes:

Code Description
"LR" Left to Right
"RL" Right to Left
"TB" Top to Bottom
"BT" Bottom to Top
"TLBR" Top-Left to Bottom-Right
"TRBL" Top-Right to Bottom-Left
"BLTR" Bottom-Left to Top-Right
"BRTL" Bottom-Right to Top-Left
"MLRC" Middle-Left to Right-Corners
"MRLC" Middle-Right to Left-Corners
"TCBC" Top-Center to Bottom-Corners
"BCTC" Bottom-Center to Top-Corners
"CVE" Center to Vertical Edges
"CHE" Center to Horizontal Edges
"CC" Center to Corners
Animation types for the “slide” method

The slide transition supports 13 different animation types, specified by the following letter-codes:

Code Description
"SLR" Single Left to Right
"SRL" Single Right to Left
"STB" Single Top to Bottom
"SBT" Single Bottom to Top
"STLBR" Single Top-Left to Bottom-Right
"STRBL" Single Top-Right to Bottom-Left
"SBLTR" Single Bottom-Left to Top-Right
"SBRTL" Single Bottom-Right to Top-Left
"DLR" Double Left to Right
"DRL" Double Right to Left
"DTB" Double Top to Bottom
"DBT" Double Bottom to Top
"QCC" Quadruple Corners to Corners
Animation types for the “twist” method

The twist transition supports 16 different animation types, specified by the following letter-codes:

Code Description
"TLC" Top-Left and Clockwise
"TLA" Top-Left and Anti-Clockwise
"TRC" Top-Right and Clockwise
"TRA" Top-Right and Anti-Clockwise
"BLC" Bottom-Left and Clockwise
"BLA" Bottom-Left and Anti-Clockwise
"BRC" Bottom-Right and Clockwise
"BRA" Bottom-Right and Anti-Clockwise
"MLC" Middle-Left and Clockwise
"MLA" Middle-Left and Anti-Clockwise
"MRC" Middle-Right and Clockwise
"MRA" Middle-Right and Anti-Clockwise
"TCC" Top-Center and Clockwise
"TCA" Top-Center and Anti-Clockwise
"BCC" Bottom-Center and Clockwise
"BCA" Bottom-Center and Anti-Clockwise
Animation types for the “skew” method

The skew transition supports 30 different animation types, specified by the following letter-codes:

Code Description
"TLC" Top-Left and Clockwise
"TLA" Top-Left and Anti-Clockwise
"TRC" Top-Right and Clockwise
"TRA" Top-Right and Anti-Clockwise
"BLC" Bottom-Left and Clockwise
"BLA" Bottom-Left and Anti-Clockwise
"BRC" Bottom-Right and Clockwise
"BRA" Bottom-Right and Anti-Clockwise
"TLB" Top-Left and Bend
"TRB" Top-Right and Bend
"BLB" Bottom-Left and Bend
"BRB" Bottom-Right and Bend
"TLF" Top-Left and Flip
"TLDF" Top-Left and Double-Flip
"TRF" Top-Right and Flip
"TRDF" Top-Right and Double-Flip
"BLF" Bottom-Left and Flip
"BLDF" Bottom-Left and Double-Flip
"BRF" Bottom-Right and Flip
"BRDF" Bottom-Right and Double-Flip
"MDC" Middle and Double-Clockwise
"MDA" Middle and Double-Anti-Clockwise
"CDC" Center and Double-Clockwise
"CDA" Center and Double-Anti-Clockwise
"TCCF" Top-Center and Clockwise Flip
"TCAF" Top-Center and Anti-Clockwise Flip
"TCFF" Top-Center and Flying Flip!
"BCCF" Bottom-Center and Clockwise Flip
"BCAF" Bottom-Center and Anti-Clockwise Flip
"BCFF" Bottom-Center and Flying Flip!
Animation types for the “bars” method

The bars transition supports 21 different core animation types, and for each of these you also specify the numeric-range of the effect, by adding a number before the letter-code — for example "8LR" means 8 × Left to Right.

The first group of animation types creates vertical or horizontal bars (sometimes called a ‘blinds’ effect), and supports 2–64 numeric permutations. Each numeric permutation creates another bar, therefore this effect can create up to 64 bars at once (though you will start to notice a performance hit with larger numbers):

Code Description
"nLR" n × Left to Right
"nRL" n × Right to Left
"nTB" n × Top to Bottom
"nBT" n × Bottom to Top
"nCVE" n × Centers to Vertical Edges
"nCHE" n × Centers to Horizontal Edges

The next group of animation types creates parallel groups of squares, and supports 2–8 numeric permutations. Each numeric permutation extends the range in two dimensions, therefore this effect can create up to 64 squares at once (8×8) (though you will start to notice a performance hit with larger numbers):

Code Description
"nTLBR" (n × n) × Top-Left to Bottom-Right
"nTRBL" (n × n) × Top-Right to Bottom-Left
"nBLTR" (n × n) × Bottom-Left to Top-Right
"nBRTL" (n × n) × Bottom-Right to Top-Left
"nMLRC" (n × n) × Middle-Left to Right-Corners
"nMRLC" (n × n) × Middle-Right to Left-Corners
"nTCBC" (n × n) × Top-Center to Bottom-Corners
"nBCTC" (n × n) × Bottom-Center to Top-Corners
"nCC" (n × n) × Centers to Corners

The final group of animation types creates staggered groups of squares (sometimes called a ‘checkerboard’ effect), and supports 2–8 numeric permutations. Each numeric permutation extends the range in two dimensions, therefore this effect can create up to 64 squares at once (8×8) (though you will start to notice a performance hit with larger numbers):

Code Description
"nSLR" (n × n) × Staggered Left to Right
"nSRL" (n × n) × Staggered Right to Left
"nSTB" (n × n) × Staggered Top to Bottom
"nSBT" (n × n) × Staggered Bottom to Top
"nSCVE" (n × n) × Staggered Centers to Vertical Edges
"nSCHE" (n × n) × Staggered Centers to Horizontal Edges

Fallback behavior for partially-supported browsers

Some of the transition methods use CSS Transforms (or their vendor equivalents) — grow uses "scale", twist uses "rotate", and skew uses, er, "skew". Implementations of these 2D transforms are very new in most browsers, and consequently the methods that use them are only supported in the latest builds. Firefox 3.0, for example, doesn't support these transitions, though it does support all the others and the script in general.

So the fallback behavior for this group of browsers is that they still do a basic image-swap, so at least they achieve the same end result, even if the journey is not so impressive.

This fallback behavior is also used by browsers when images are disabled.

Most of the time you won't need to consider this especially, however if you're synchronising multiple transitions to create a slideshow or other automation, you'll find that the timing of the fallback behavior becomes important — because the fallback image-swap happens instantly, rather than over time like an animated transition effect.

So you also have the option of delaying the fallback behavior, so that it has the same duration as the transition effect; this behavior is configurable via the "long-fallback" option.

For more about synchronisation and fallback behavior, see: Sequencer fallback timing for partially-supported browsers.

Layout quirks that affect transition clones

Most of the transitions use one or more cloned images — copies of the original, that are appended to the end of the <body> and positioned to superimpose, and which are often the only element(s) that actually carry the transition style. For example, a left-to-right wipe transition uses a clone to create the wiping effect, gradually revealing it to cover the original until it's completely obscured; at which point the actual image-swap happens on the original, and the clone is removed.

The size and position of the clones are calculated from properties of the original image, however, the values these calculations return will include any borders or padding on the image. Their positions are also returned with respect to the top-left corner of the border, not the top-left corner of the image content itself, as might be intuitive. So for example, if the image has a 5px border and 15px padding on all sides, then the clones will be 40px too wide and too tall — and at full-size, the re-scaled clones will ultimately cover the borders, padding and content of the original image.

Most likely, this will not be what you want, so the practical way to avoid it is simply don't apply border or padding to any images you use for transitions. The thing to do, if you need that styling, is to wrap the image in a <span> and apply the styles to that instead.

This is the only known layout quirk. There are no other CSS properties that are known to be an issue for transition images, and no other known situation in which properties on any intermediate elements could cause a problem.

The stacking-order of transition clones is also configurable, via the "base-zindex" option.

Utility methods

The script provides three utility methods to accompany the transition methods, which perform ancillary tasks to help with the general effort:

  • The cache method can be used to pre-load any number of images, returning data that can tell you whether any (or indeed all) of them failed to load.
  • The define method is used for configuring global options, allowing you to control certain key aspects of the script's behavior, such as the resolution of transition animations.
  • The pictures method will tell you whether images are enabled in the browser. It's used internally as part of the transition and caching logic, and is made available as a public method so you can get that information on-demand.

Transitions.cache(srcs [, oncomplete]);

If the new SRC you specify for a transition refers to an image that hasn't been cached ... well, you'll see the effect on a placeholder (or whatever the browser creates) for as long as it takes the image to load! The best thing to do then is pre-load all images which are going to be used for transitions, and do so as soon as possible during the page's initial loading. You can do this using the script's built-in cache method.

The cache method can be used to pre-load any number of images. Its process is naturally asynchronous, but it can also fire an optional callback when complete, sending back data you can use to test for caching failures.

Transitions.cache(
    ["red.png","gold.png","green.png"],     // image SRCs            [REQUIRED Object (array)]
    function(data) { ... }                  // callback oncomplete   [OPTIONAL Function]
    );

Please note: The arguments passed to cache are only validated when using the development version of the script ("transitions.debug.js", which is included in the download archive, and produces debugging messages to alert you to the error).

Arguments

Image SRCs [REQUIRED Object (array)]

An array of String values, each of which specifies the SRC of an image to cache. This array can contain as many values as you wish, and each will be loaded in turn using a created IMG Object. The path of each image will naturally be relative to the page the script is running on.

You may find it helpful, when working with a long and repetitive list of SRCs, to use some JavaScript shortcuts to compile the final cache array; like this:

var flags = ["red", "gold", "green"],
    path = "/images/flags/",
    suffix = ".png";
    
Transitions.cache((path + flags.join(suffix + "," + path) + suffix).split(","));
Callback oncomplete [OPTIONAL Function]

A Function that will be called when the caching process is complete.

For each SRC in the input array, an IMG Object will be created, and as it loads it will either fire onload for success or onerror for failure. When one or the other has fired for every image in the array, then your callback function will be fired.

The callback will be passed a single argument — an array that corresponds exactly with the input SRCs; each member of the array will be either be an Object reference to the loaded image, or it will be null if the image failed to load. So you can use this data to test for caching failures, by comparing the original SRCs with the members which are null.

But please remember: the callback will only fire at all if the cache method is successful (if it returns true). If it returns false or null to indicate an exception or exclusion, then the process won't complete and the callback won't fire either.

Return value [Boolean|Object]

Return value

The cache method returns true, false or null, to indicate the result of the operation:

  1. If the browser is unsupported (if it doesn't support the script at all), then the method will return null (to indicate exclusion).
  2. If the browser is fine but images are disabled, then the method will return false (to indicate this exception).
  3. Otherwise, if all is well, then the method will return true (to indicate success).

If the cache method throws an error, then obviously it won't return at all.

Transitions.define(name, value);

The script has a small number of global configuration options, which affect key aspects of the transitions' behavior and appearance. The options are all privileged variables and cannot be modified directly — only using the script's built-in define method.

You can use define to change the value of any option at any time, and the change will take effect on the next transition you run.

Transitions.define(
    "step-resolution",      // option name      [REQUIRED String]
    20                      // option value     [REQUIRED Number/Boolean]
    );

Please note: The arguments passed to define are only validated when using the development version of the script ("transitions.debug.js", which is included in the download archive, and produces debugging messages to alert you to the error).

Arguments

Option name [REQUIRED String]

A String that specifies which option you're defining.

For details of all the available options, see :: Available options.

Option value [OPTIONAL Number/Boolean]

The new value you're defining for this option, which is either a Boolean or a Number, depending on which option it is.

Return value [Boolean|Object]

Return value

The define method returns true or null, to indicate the result of the operation:

  1. If the browser is unsupported (if it doesn't support the script at all), then the method will return null (to indicate exclusion).
  2. Otherwise, if all is well, then the method will return true (to indicate success).

There's no specific failure condition associated with this method, therefore no situation in which it will return false. If the define method throws an error, then obviously it won't return at all.

Available options

"step-resolution" [REQUIRED Number]

Specify a Number — which must be an integer greater than 1 — that defines the number of timer iterations per second for a transition animation.

Transitions.define("step-resolution", 16);

For example, a two-second transition with the default resolution of 16, will create 32 frames of animation over the total length of the transition.

Higher values create smoother animation, but are much more expensive to run (placing a higher load on the user's CPU). Lower values are cheaper but create a coarser effect, that may begin to look jerky at very low values.

The resolution also determines the minimum speed of a transition, by the following formula:

Speed formula:
speed = (1 / resolution) * 4

So for example, with a resolution of 16, the minimum speed for any transition is 0.25 seconds; or if the resolution were increased to 20 then the minimum speed would drop to 0.2 seconds.

(The * 4 multiplier in that formula relates to the fact that all transitions have a minimum of four frames of animation. The animator also limits the speed of a single frame to 10ms, never faster. Ultimately, what this implies is that the absolute minimum speed for any transition is 0.04 seconds.)

The default value for this option is 16, which is playing it very safe for the sake of broad cross-platform support.

"long-fallback" [REQUIRED Boolean]

Specify true or false for whether the fallback behavior for partially-supported browsers (or those in which images are disabled) should still wait for the specified duration before doing the image-swap.

Transitions.define("long-fallback", false);

The purpose of having this switch is so that, when you're using the script for a slideshow — or anything that runs a sequence of synchronised transitions over time — then this group of browsers will still run-through the images in a timely fashion, rather than just ripping through them all in an instant. For more about this issue, see :: Sequencer fallback timing for partially-supported browsers.

But if you're only using the script for single image changes, then there's little point having this feature enabled — it would just amount to a useless pause!

The default value for this option is false.

"base-zindex" [REQUIRED Number]

Specify a Number — which must be an integer greater than 1 — that defines the stacking order of transition clones, to make sure they're on top.

Transitions.define("base-zindex", 2);

Most transitions use cloned images, appended to the end of the <body> and positioned to superimpose the original, and used to carry the actual the transition style. For example, a left-to-right wipe transition uses a clone to create the wiping effect, gradually revealing it to cover the original until it's completely obscured; at which point the actual image-swap happens on the original, and the clone is removed.

So, the purpose of this option is to allow you to control the "z-index" of the created clones. You may need to increase the value to make sure the clones are on top of the original (depending on what other CSS positioning affects the image and its context). You'll soon know if there's a problem, because the transition effect will be obscured, and all you'll see is the snap-change of SRC and ALT text from the underlying image swap.

The default value for this option is 2 (and this is also its minimum value; there's no actual maximum defined by CSS, but in practice, browsers support values up to at least 30000).

For other potential CSS issues with transition clones, see :: Layout quirks that affect transition clones.

Transitions.pictures();

The ability to display images is clearly important to an image script! Whether or not they're enabled in the browser is detected automatically, and affects the logic of the caching process as well as the transition methods themselves (ie. if images are disabled, the cache method will not complete, and transitions will do their fallback behavior).

This information is also available on-demand, if you need it, via the script's public pictures method. You can call it at any time and get the current browser state, to use as part of your own scripting logic.

The pictures method has no arguments, it only returns a value.

var enabled = Transitions.pictures();

Return value [Boolean|Object]

Return value

The pictures method returns true, false or null, to indicate the result of the operation:

  1. If the browser is unsupported (if it doesn't support the script at all), then the method will return null (to indicate exclusion).
  2. Else if the browser is supported but images are currently disabled, then the method will return false (to indicate this state).
  3. Or if the browser is supported and images are currently enabled, then the method will return true (to indicate that state).

Public properties

In addition to the configuration options, the script makes two public properties available, that you can use as scripting conditions — a "supported" flag, and a script-version string.

Transitions.supported [Boolean]

This property is true or false according to whether the script is supported. You can use it as a condition to shield those browsers which don't support it from having to parse any other scripting that makes use of it.

if(Transitions.supported)
{
    //the browser is supported
}

You don't actually have to do this, because all the public methods already handle unsupported browsers (by returning null to indicate exclusion). But you might prefer to use it around your own scripting anyway, just to save those older, unsupported browsers from processing code they won't actually be using. For an overview of the script's browser support, see :: Browser support.

If you wish to, you can also change the value of this property, for purposes of your own. You may, for example, wish to mark specific older browsers as unsupported, to bring them into line with your own support expectations. You can set the value to false at any time, and then subsequent calls to any of the script's methods will fail, cleanly, returning null for exclusion like any other unsupported browser.

//why make life any harder :-D
if(/MSIE 6/.test(navigator.userAgent)) 
{ 
    Transitions.supported = false; 
}

Setting this to true for browsers that were never supported in the first place ... is not recommended!

Transitions.version [String]

This property is a String that records the current script version number, such as "2.0".

Not really sure what use this is, it's made available just in case. But you might think of something, and if you do, there you go!

Debugging messages

When you're using the development version of the script ("transitions.debug.js", which is included in the download archive), all the public methods will provide debugging information, to alert you to any errors in your arguments.

Only the development version provides debugging information, the production version doesn't, and consequently may give rise to unpredictable errors, if the input is wrong. It's best to use the development version while you're still experimenting with the script, then switch to the production version when you're ready to go live.

Debugging messages will be thrown to your browser's JavaScript console, providing information about the nature and location of the error. For example, this is the error produced if the image reference passed to the wipe method is null or doesn't exist:

The image-reference required by Transitions.wipe() is missing or null. 

file: http://localhost/calling-script.js
line: 123

Here's a list of all the different errors you may encounter. Transition errors / Caching errors / Configuration errors

Transition errors

The [argument] passed to Transitions.[method] is not valid.

Thrown by a transition method when the value of any argument is incorrect; the message will tell you specifically which argument is wrong. For example, setting the ALT text to a Number instead of a String.

The [argument] required by Transitions.[method] is missing or null.

Thrown by a transition method when a required argument is missing entirely, or evaluates to null; the message will tell you specifically which argument is missing. For example, if the image reference points to an element that doesn't actually exist.

Caching errors

The [argument] passed to Transitions.cache() is not valid.

Thrown by the cache method when the value of any argument is incorrect; the message will tell you specifically which argument is wrong. For example, setting the image paths array to an object-literal instead of an array.

The [argument] required by Transitions.cache() is missing or null.

Thrown by the cache method when a required argument is missing entirely, or evaluates to null; the message will tell you specifically which argument is missing. For example, if the image paths array is not defined at all.

Configuration errors

The "[argument]" value passed to Transitions.define() is not valid.

Thrown by the define method when an option value is incorrect; the message will tell you specifically which option it's referring to. For example, setting the "step-resolution" to a floating-point number.

The [argument] required by Transitions.define() is missing or null.

Thrown by the define method when an option value is missing entirely, or evaluates to null. For example, defining an option name but neglecting to define any option value.

The [argument] specified in Transitions.define() does not exist.

Thrown by the define method when the name refers to an option that doesn't exist. For example, setting the option name to "lol-kthxbye".

main page | Further Development

top

Image Transitions Manual

  1. Using the Script [this page]
  2. Further Development

main page

Categories...

Website gadgets

Bits of site functionality:

Usability widgets

Local network apps

Web-applications for your home or office network:

Game and novelties

Our internal search engine is currently offline, undergoing some configuration changes in preparation for a major site overhaul. In the meantime, you can still search this site using Google Custom Search.


In this area

Main areas


[brothercake] a round peg in a square hole, that still fits