<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <title>Evil Dynamic Layout: Text animation</title>
  <style type="text/css">
    #canvas { position: relative; margin: 0em; }
    div { -moz-opacity: 0; position: absolute; }
    /* * { border: solid 1px fuchsia; margin: 4px; padding: 4px; -moz-opacity: 0.9 ! important; } */
  </style>
  <script type="text/javascript">
  <![CDATA[

    function Animator(aElement, aSteps, aDelay) { 
      this.element = aElement;
      this.delay = aDelay;
      this.steps = aSteps;
      this.transitions = [];

      this.addTransition = function(aTransition) {
        this.transitions.push(aTransition);
      }

      this.animate = function() {
        if (this.delay > 0) {
          this.delay--;
        } else {
          if (this.steps) {
            for (var index = 0; index < this.transitions.length; index++) {
              this.transitions[index].animate(this.element, this.steps);
            }
            this.steps--;
          }
        }
        return this.steps;
      }
      this.length = function() {
        return this.delay + this.steps;
      }
    }

    function DimensionTransition(aProperty, aValue, aEnd, aSuffix) { 
      this.property = aProperty;
      this.value = aValue;
      this.end = aEnd;
      this.suffix = aSuffix;

      this.animate = function(element, steps) {
        this.value += (this.end - this.value) / steps;
        element.style.setProperty(this.property, this.value+this.suffix, '');
      }
    }

    function KeywordTransition(aProperty, aValue) { 
      this.property = aProperty;
      this.value = aValue;

      this.animate = function(element, steps) {
        element.style.setProperty(this.property, this.value, '');
      }
    }

    function ClipTransition(aValue, aEnd, aSuffix) { 
      this.value = aValue;
      this.end = aEnd;
      this.suffix = aSuffix;

      this.animate = function(element, steps) {
        this.value += (this.end - this.value) / steps;
        // the following is incorrect XXX
        element.style.setProperty('clip', 'rect('+this.value+this.suffix+','+this.value+this.suffix+','+this.value+this.suffix+','+this.value+this.suffix+')', '');
      }
    }

    var delay = location.search;
    if (delay) {
      delay = delay.substring(1, delay.length);
    } else {
      delay = 50;
    } 
    var animations = [];

    function setup() {
      animations = [];
      var body = document.getElementById('canvas');
      for (var index = body.childNodes.length-1; index >= 0; index--) {
        body.removeChild(body.childNodes[index]);
      }

      /* Animation Constants */
      var steps1 = 25;
      var steps2 = 15;
      var steps3 = 15;
      var lineStart = 50;
      var fontSize = 60;

      /* Element: Welcome */
      var Welcome = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
      Welcome.appendChild(document.createTextNode('Welcome To...'));
      Welcome.className = 'Welcome';
      Welcome.style.top = '30px';
      Welcome.style.left = (-fontSize*2*10+50)+'px';
      Welcome.style.width = fontSize*4*10+'px';
      Welcome.style.lineHeight = fontSize*2+'px';
      Welcome.style.textAlign = 'center';
      body.appendChild(Welcome);

      /* Element: C */
      var C = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
      C.appendChild(document.createTextNode('C'));
      C.className = 'C';
      C.style.width = fontSize*3+'px';
      C.style.lineHeight = fontSize*3+'px';
      C.style.textAlign = 'center';
      body.appendChild(C);

      /* Element: S */
      var S1 = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
      S1.appendChild(document.createTextNode('S'));
      S1.className = 'S';
      S1.style.width = fontSize*3+'px';
      S1.style.lineHeight = fontSize*3+'px';
      S1.style.textAlign = 'center';
      body.appendChild(S1);

      /* Element: S */
      var S2 = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
      S2.appendChild(document.createTextNode('S'));
      S2.className = 'S';
      S2.style.width = fontSize*3+'px';
      S2.style.lineHeight = fontSize*3+'px';
      S2.style.textAlign = 'center';
      body.appendChild(S2);

      /* Element: D */
      var D = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
      D.appendChild(document.createTextNode('D'));
      D.className = 'D';
      D.style.width = fontSize*3+'px';
      D.style.lineHeight = fontSize*3+'px';
      D.style.textAlign = 'center';
      body.appendChild(D);

      /* Element: O */
      var O = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
      O.appendChild(document.createTextNode('O'));
      O.className = 'O';
      O.style.width = fontSize*3+'px';
      O.style.lineHeight = fontSize*3+'px';
      O.style.textAlign = 'center';
      body.appendChild(O);

      /* Element: M */
      var M = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
      M.appendChild(document.createTextNode('M'));
      M.className = 'M';
      M.style.width = fontSize*3+'px';
      M.style.lineHeight = fontSize*3+'px';
      M.style.textAlign = 'center';
      body.appendChild(M);

      /* Element: footer */
      var Footer = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
      Footer.appendChild(document.createTextNode('\u00A9 2001-2003 Ian Hickson. Distributed under the terms of the GPL.'));
      Footer.className = 'Footer';
      Footer.style.top = 50+fontSize*3+'px';
      Footer.style.left = lineStart/2+'px';
      Footer.style.fontSize = fontSize/5+'px';
      body.appendChild(Footer);

      /* Animation */
      var WelcomeAnimation1 = new Animator(Welcome, steps1*6/5, 0);
      WelcomeAnimation1.addTransition(new DimensionTransition('font-size', fontSize/4, fontSize/3, 'px'));
      WelcomeAnimation1.addTransition(new DimensionTransition('-moz-opacity', 0.0, 1.0, ''));
      WelcomeAnimation1.addTransition(new DimensionTransition('margin-left', 0, lineStart+fontSize, 'px'));
      animations.push(WelcomeAnimation1);
      var CAnimation1 = new Animator(C, steps1, 0);
      CAnimation1.addTransition(new DimensionTransition('font-size', fontSize*5, fontSize, 'px'));
      CAnimation1.addTransition(new DimensionTransition('-moz-opacity', 0.0, 1.0, ''));
      CAnimation1.addTransition(new DimensionTransition('left', -150, lineStart+fontSize*0.1, 'px'));
      CAnimation1.addTransition(new DimensionTransition('top', -150, 50, 'px'));
      animations.push(CAnimation1);
      var S1Animation1 = new Animator(S1, steps1, steps1/5);
      S1Animation1.addTransition(new DimensionTransition('font-size', fontSize*3, fontSize, 'px'));
      S1Animation1.addTransition(new DimensionTransition('-moz-opacity', 0.0, 1.0, ''));
      S1Animation1.addTransition(new DimensionTransition('left', -50, lineStart+fontSize*0.8, 'px'));
      S1Animation1.addTransition(new DimensionTransition('top', 200, 50, 'px'));
      animations.push(S1Animation1);
      var S2Animation1 = new Animator(S2, steps1, steps1/4);
      S2Animation1.addTransition(new DimensionTransition('font-size', fontSize*4, fontSize, 'px'));
      S2Animation1.addTransition(new DimensionTransition('-moz-opacity', 0.0, 1.0, ''));
      S2Animation1.addTransition(new DimensionTransition('left', 250, lineStart+fontSize*1.4, 'px'));
      S2Animation1.addTransition(new DimensionTransition('top', 300, 50, 'px'));
      animations.push(S2Animation1);
      var DAnimation1 = new Animator(D, steps2, steps1*2/3);
      DAnimation1.addTransition(new DimensionTransition('font-size', fontSize*5, fontSize, 'px'));
      DAnimation1.addTransition(new DimensionTransition('-moz-opacity', 0.0, 1.0, ''));
      DAnimation1.addTransition(new DimensionTransition('left', 150, lineStart+fontSize*0.0, 'px'));
      DAnimation1.addTransition(new DimensionTransition('top', -75, 50+fontSize, 'px'));
      animations.push(DAnimation1);
      var OAnimation1 = new Animator(O, steps2, steps1*3/3);
      OAnimation1.addTransition(new DimensionTransition('font-size', fontSize*5, fontSize, 'px'));
      OAnimation1.addTransition(new DimensionTransition('-moz-opacity', 0.0, 1.0, ''));
      OAnimation1.addTransition(new DimensionTransition('left', 275, lineStart+fontSize*0.75, 'px'));
      OAnimation1.addTransition(new DimensionTransition('top', 50, 50+fontSize, 'px'));
      animations.push(OAnimation1);
      var MAnimation1 = new Animator(M, steps2, steps1*4/3);
      MAnimation1.addTransition(new DimensionTransition('font-size', fontSize*5, fontSize, 'px'));
      MAnimation1.addTransition(new DimensionTransition('-moz-opacity', 0.0, 1.0, ''));
      MAnimation1.addTransition(new DimensionTransition('left', -150, lineStart+fontSize*1.5, 'px'));
      MAnimation1.addTransition(new DimensionTransition('top', 250, 50+fontSize, 'px'));
      animations.push(MAnimation1);
      var WelcomeAnimation2 = new Animator(Welcome, steps2*2, MAnimation1.length());
      WelcomeAnimation2.addTransition(new DimensionTransition('font-size', fontSize/3, fontSize*3, 'px'));
      WelcomeAnimation2.addTransition(new DimensionTransition('-moz-opacity', 1.0, 0.0, ''));
      animations.push(WelcomeAnimation2);
      var CAnimation2 = new Animator(C, steps2*2, MAnimation1.length());
      CAnimation2.addTransition(new DimensionTransition('font-size', fontSize, fontSize*3, 'px'));
      CAnimation2.addTransition(new DimensionTransition('-moz-opacity', 1.0, 0.0, ''));
      animations.push(CAnimation2);
      var S1Animation2 = new Animator(S1, steps2*2, MAnimation1.length());
      S1Animation2.addTransition(new DimensionTransition('font-size', fontSize, fontSize*3, 'px'));
      S1Animation2.addTransition(new DimensionTransition('-moz-opacity', 1.0, 0.0, ''));
      animations.push(S1Animation2);
      var S2Animation2 = new Animator(S2, steps2*2, MAnimation1.length());
      S2Animation2.addTransition(new DimensionTransition('font-size', fontSize, fontSize*3, 'px'));
      S2Animation2.addTransition(new DimensionTransition('-moz-opacity', 1.0, 0.0, ''));
      animations.push(S2Animation2);
      var DAnimation2 = new Animator(D, steps2*2, MAnimation1.length());
      DAnimation2.addTransition(new DimensionTransition('font-size', fontSize, fontSize*3, 'px'));
      DAnimation2.addTransition(new DimensionTransition('-moz-opacity', 1.0, 0.0, ''));
      animations.push(DAnimation2);
      var OAnimation2 = new Animator(O, steps2*2, MAnimation1.length());
      OAnimation2.addTransition(new DimensionTransition('font-size', fontSize, fontSize*3, 'px'));
      OAnimation2.addTransition(new DimensionTransition('-moz-opacity', 1.0, 0.0, ''));
      animations.push(OAnimation2);
      var MAnimation2 = new Animator(M, steps2*2, MAnimation1.length());
      MAnimation2.addTransition(new DimensionTransition('font-size', fontSize, fontSize*3, 'px'));
      MAnimation2.addTransition(new DimensionTransition('-moz-opacity', 1.0, 0.0, ''));
      animations.push(MAnimation2);
      var FooterAnimation1 = new Animator(Footer, steps3, MAnimation2.length()-steps2*0.5);
      FooterAnimation1.addTransition(new DimensionTransition('-moz-opacity', 0.0, 1.0, ''));
      animations.push(FooterAnimation1);
      var FooterAnimation2 = new Animator(Footer, steps3, FooterAnimation1.length());
      FooterAnimation2.addTransition(new DimensionTransition('-moz-opacity', 1.0, 0.5, ''));
      animations.push(FooterAnimation2);

    }    

    function idle() {
      var more = 0;
      for (var index = 0; index < animations.length; index++) {
        more |= animations[index].animate();
      }
      if (more) {
        window.setTimeout(idle, delay);
      }
    }

  ]]>
  </script>
 </head>
 <body onload="setup(); idle()">
   <div id="canvas"/>
 </body>
</html>
