WEB画面に枯葉が舞う

それにしても短い休日だった。
母さん、三途の川を渡ったころだろうか。


https://oshiete.goo.ne.jp/qa/12665779.html
枯葉よ~

<!DOCTYPE html>
<meta charset="UTF-8">
<title>Test</title>

<body>
<img class="kareha" src="data:image/gif;base64,R0lGODlhLQAqAKIAAP7jRvTSMvfZO/veQuS8H+zFJ/DMLv///yH5BAEAAAcALAAAAAAtACoAAAP4eLrc/tCRGau1k97NTyZdWBWZaDaGQZ6sEqRFew7CK89CfYsAQO88HzDUEw43RYAEdGQkH59CbDioDqAkgrSQMtwCOQEks+0GzmBR6lzRltfosKB6cXvbbi4cnLMOng0fG3lmZ2F+SU8fTHVvBnF9VYlJgh2OkHOSk0lXIpeGkX+bgCGffJmioz0mpoeaqkqeUoWnqLCxpbO0rq+bJoR7coiTnSLAdwrCfsvFIW4PoLzLYkdotXLYR3uY2GxAXdvW4gFAjrTiXTt5uuDtXVMtZFvm4PM3E1nr8/tSjPGL8vZVAgKw4KImBhM2UZAQ4MIFDUs8DGSQRQIAOw==">
<img class="kareha" src="data:image/gif;base64,R0lGODlhMAAnAKIAAOlcNOM+E8cqB9RxW96dkfDUz8hPPP///yH5BAEAAAcALAAAAAAwACcAAAP/eLrc/qS8Sas9Q97NndFdeBGfaFbDcK5OYahsfBBCKZ/FEMC3qQeGnskVAOJixGLQRMisfkUBKJQiDA3F6DREinCzAOCWa3iNH8lAWGBlkcqGNoWwVgcEPNzgdR/IHQNrAGt/JySDa0sNBWF3dmwyOQYAgQI1W3RgSj0kRY19DJkCdkYhZzmNg1GKqqONUhUFsgRvhQpNqa1Lra15BbQpNcI1Xmgpqqp3Cq2PGr9YltGWcSOBuWsYmjUKOpaOd5Z5Fri5ygSOjTNR3+CQXIFgYX7fAgpq0VmjeIbMqt1hAM5lGRhNXAdUn/oxIxjtzMFf11wN9NTOBgtZED2lGkUQYJwtEb+OWaM4EdwLJxfJIUJU0pOfG88mrZwJMB8QlHoM1AAgc6UnOjQYGuTQxA+wPWV2KJEA4MArjtuGbJnlJwfKpgd0SrP0UciCAApCbnXn1QHWBVQHcC37AOwcRRUSAAA7">

<script>

const {sin, cos, random, PI} = Math, DEG = PI / 180;

//_________

class P2 {
  constructor (x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }
}

//_________

class Status {
  constructor (...args) {
    this.reset (...args);
  }

  reset (fall = 0, swing = 0, spin = 0) {
    this.fall = fall;
    this.swing = swing;
    this.spin = spin;
    return this;
  }

  randomReset (max, min) {
    for (let name of Object.keys (max))
      this[name] = rand (max[name], min[name]);
    return this;
  }
}

//_________

class Kareha {

  constructor (terms, target, position, character, spin, life) {
    this.terms = terms;
    this.target = target;
    this.position = position;
    this.character = character;
    this.life = life;
    this.spin = spin;
  }


  reset () {
  let t = this.terms;
    this.position = new P2 (rand (t.endArea.x, t.beginArea.x), 0);
    this.character.randomReset (t.maxStatus, t.minStatus);
    this.life = this.spin = 0;
   
    return this.disp ();
  }


  move () {
    if (null === this.life)
      this.reset ();

    let {x, y} = this.position;
    if (this.terms.endArea.y < y)
      return this.reset ();

    this.life++;
    this.spin += this.character.spin;
    y += this.character.fall + cos (this.spin * DEG);
    x += sin (this.spin * DEG) * this.character.swing;

    this.position.x = x;
    this.position.y = y;

    return this.disp ();
  }


  disp () {
    let
      style = this.target.style,
      {x, y} = this.position;
    
    if (null === this.life)
      style.opacity = 0 + '';
    else {
      let n = this.spin |0;
      style.opacity = 1 + '';
      style.left = (x |0)+ 'px';
      style.top = (y |0)+ 'px';
      style.transform = `rotate(${this.spin}deg)`;
    }
    return this;
  }


  static create (terms, target, position = new P2, character = new Status, spin = 0, life = null) {
    let obj = new this (terms, target, position, character, spin, life);
    target.style.position = 'absolute';
    return obj.reset ();
  }
 
}


function rand (max = 100, min = 0) {
  let sa = max - min;
  return random () * sa + min;
}


//_________


{
  let img = document.querySelectorAll ('img.kareha');
  
  for (let i = 0; i < 20; i++) {
    img[0].parentNode.appendChild (img[0].cloneNode (false));
    img[1].parentNode.appendChild (img[1].cloneNode (false));
    
  }
}


const
  TERMS = {
    minStatus: new Status (1, .5, .1),
    maxStatus: new Status (3, 3, 2),
    beginArea: new P2 (0, 0),
    endArea: new P2 (640, 800)
  },

  KAREHA = [...document.querySelectorAll ('img.kareha')].map (e=> Kareha.create (TERMS, e));


(function loop () {
  KAREHA.forEach (obj=> obj.move ());
  window.requestAnimationFrame (loop);
}) ();

</script>