  /* <![CDATA[ */
  
  // Das Feuerwerk
  //   canvasID:  ID der Canvas (fuer Context und Groesse)
  //   anzahl:    Anzahl der Bomben im Array (maximal angezeigte Bomben)
  // Die Objekthierarchie enthält bomb und star, Kapselung
  function fireworks(canvasID, anzahl)
  {
    // Canvas und Context zum Malen
    var canvas    = document.getElementById(canvasID);
    var context2d = canvas.getContext('2d');

    // Array mit bomb-Objekten
    this.chain = [];

    // fireworks::bomb - Eine "Bombe" (bestehend aus Sternchen)
    //   width, height: ...der Canvas (wichtig fuer Zufallsposition der Bomben)
    //
    //   x,y:   Startposition der Bombe
    //   diam:  Faktor fuer den Durchmesser der Bombe
    //   color: Farbe der Bombe/Sternchen (String 'rgb(r,g,b)')
    //   n:     Anzahl der Sternchen der Bombe (Leuchtpunkte)
    //   ttl:   time to live, Lebensdauer der Bombe;
    //          bei ttl 0 kann die Bombe durch eine neue ersetzt werden
    this.bomb = function(width, height)
    {
      var x     = width*(0.25+0.50*Math.random());
      var y     = height*(0.25+0.25*Math.random());
      var diam  = 1+2*Math.random();
      var color = getRandomColor();
      var n     = 100+150*Math.random();
      var ttl   = 50+50*Math.random();

      // Array von star-Objekten ("Sternchen", Leuchtpunkte)
      this.stars = [];

      // fireworks::bomb::star - Ein Sternchen der Bombe
      //   x,y:    Position
      //   dx,dy:  Schrittweiten für nächsten Schritt
      //   r, phi: Radius und Winkel für den Vektor (dx,dy)
      //   ttl:    star-Lebensdauer; wird auf 0 heruntergezählt (dann erlischt das Sternchen)
      this.star = function()
      {
        this.x   = x;
        this.y   = y;
        this.ttl = Math.ceil(ttl*(1-0.3*Math.random()));  // 70 bis 100 % der bomb-ttl

        var r    = diam*Math.pow(Math.random(),0.4);  // pow: Sternchen nach aussen schieben
        var phi  = Math.random()*2*Math.PI;
        var dx   = r*Math.cos(phi);
        var dy   = r*Math.sin(phi)-2;                 // -2: Impuls nach oben

        // star.move - Bewege ein Sternchen einen Schritt (dx,dy) weiter
        this.move = function()
        {
          this.x += dx;
          this.y += dy;
          dy += 0.06;   // ===== Gravitation ^^ ======

          this.ttl--;
        };
      }; // end of star

      // bomb.move: Die Bombe geht in den nächsten Zustand über, d.h.
      //            alle Sternchen bewegen sich 1 Schritt (dx,dy)
      this.move = function()
      {
        for(var i=0; i<n; i++)
          this.stars[i].move();

        ttl--;
      };

      // bomb.draw: Male alle Sternchen der Bombe auf die Canvas
      this.draw = function(context)
      {
        context.fillStyle = color;

        for(var i=0; i<n; i++)
          if(this.stars[i].ttl>0 &&  !((this.stars[i].ttl+i)%5 && ttl<50)  )       //+++++
            context.fillRect( this.stars[i].x, this.stars[i].y, 2, 2 );
      };

      // bomb.isDone: Bombe ist "erloschen" (kann ersetzt werden durch eine neue)
      this.isDone = function()   {  return ttl<=0;  };

      // bomb-constructor-code - Fülle das stars-Array mit n Sternchen
      for (var i=0; i<n; i++)
        this.stars.push(new this.star());

    }; // end of bomb

    // fw.doFrame - Alle Bomben bewegen (und malen), typischerweise zeitgesteuert
    //              Erloschene Bombe (ttl=0, isDone) entfernen und durch neue ersetzen
    this.doFrame = function()
    {
      // Canvas loeschen
      context2d.fillStyle = 'black';
      context2d.fillRect( 0, 0, canvas.width, canvas.height );

      // Jede Bombe 1 Schritt bewegen und zeichnen
      for(var i in this.chain)
      {
        this.chain[i].move();
        this.chain[i].draw(context2d);
      }
      
      // Falls Bombe 0 "erloschen" ist, diese entfernen und eine neue nachschieben
      if(this.chain.length && this.chain[0].isDone())
      {
        this.chain.shift();
        this.chain.push(new this.bomb(canvas.width, canvas.height));
      }
    }

    // fw-constructor-code - Erzeuge 'anzahl' Bomben
    for(var i=0; i<anzahl; i++)
      this.chain.push(new this.bomb(canvas.width, canvas.height));

  };

  // === utils ===
  function getRandomColor()
  {
    var r = Math.ceil(150+100*Math.random());
    var g = Math.ceil(150+100*Math.random());
    var b = Math.ceil(150+100*Math.random());
    return 'rgb('+r+','+g+','+b+')';
  };

  // === globaler Start ===
  window.onload = function()
  {
    myFireworks = new fireworks('mycanvas', 3);    // ID der canvas, 3 Bomben

    window.setInterval('myFireworks.doFrame()', 40);
  }
  
  /*
    Globale Symbole:  fireworks, getRandomColor, myFireworks
    Einbau: Benötigt ein canvas-Element mit gesetzten width-/height-Attributen und ID
  */
  /* ]]> */
