<file_sep># js1k 2016

[Fireworks!](http://js1k.com/2016-elemental/demo/2584)

![](https://cloud.githubusercontent.com/assets/777712/13724369/03f95e88-e838-11e5-8453-2765615d7400.gif)
<file_sep>#!/usr/bin/env node
'use strict'

const uglify = require('uglify-js')
const fs = require('fs')
const mkdirp = require('mkdirp')
const packer = require('regpack').packer
const path = require('path')

const srcPath = path.resolve(__dirname, '..', 'the.js')
const distDirPath = path.resolve(__dirname, '..', 'dist')
const distJsPath = path.resolve(distDirPath, 'submit.js')
const distShimPath = path.resolve(distDirPath, 'demo.html')
const shimTopPath = path.resolve(__dirname, 'shim-top.html')
const shimBottomPath = path.resolve(__dirname, 'shim-bottom.html')

function buildJs () {
  const src = uglify.minify(srcPath).code

  const packerResults = packer.runPacker(src, {
    withMath: false,
    hash2DContext: true,
    varsNotReassigned: []
  })

  const allOutputs = [src].concat(packerResults.reduce((result, data) => {
    return result.concat(data.result.map(r => r[1]))
  }, []))

  const shortestResult = allOutputs.reduce((result, output) => {
    if (output.length < result.length) {
      return output
    } else {
      return result
    }
  }, allOutputs[0])

  return shortestResult
}

function buildHtml (js) {
  return [
    fs.readFileSync(shimTopPath, { encoding: 'utf8' }),
    js,
    fs.readFileSync(shimBottomPath, { encoding: 'utf8' })
  ].join('')
}

mkdirp.sync(distDirPath)

const js = buildJs()
fs.writeFileSync(distJsPath, js)

fs.writeFileSync(distShimPath, buildHtml(js))

console.log(`output is ${js.length} characters`)
<file_sep>/* eslint-disable no-undef */

// style the <body>
b.style.cssText = 'margin:0;padding:0;background:#262747;overflow:hidden;font-family:sans-serif;font-size:26pt;font-weight:100'

// add a div that tells you to click
k = b.appendChild(document.createElement('div'))
k.style.cssText = 'position:fixed;top:0;left:0;width:100%;padding:26px;color:#fff;text-align:center;opacity:1;transition:opacity 3s'
k.innerHTML = 'click for fireworks!'

// keep track of canvas size
w = innerWidth
h = innerHeight

// an array of all of the rockets and the particles
r = []
p = []

// shoots a rocket on click
b.onclick = function (clickEvent) {
  k.style.opacity = 0

  r.push({
    a: clickEvent.clientX,
    b: clickEvent.clientY,
    y: h
  })
};

// tick
(function T () {
  // iterate through all the rockets, clearing the list if there aren't any active
  U = 1
  c.fillStyle = '#ffffff'
  r.map(function (rocket) {
    // skip if this rocket is already destroyed
    if (rocket.d) { return }

    // we've updated at least 1 rocket
    U = 0

    // shoot the rocket upward, destroying it if needed
    if ((rocket.y -= 20) < rocket.b) {
      // destroy the rocket
      rocket.d = 1

      // generate particles
      for (R = (((Math.random() * 10) + 5) | 0); R; R--) {
        // choose this ring's color, velocity
        C = '#' + [
          'ff0000',
          'ff9900',
          'ffff00',
          '00ff00',
          '00ffff',
          'ff00ff'
        ][(Math.random() * 6) | 0]
        V = (Math.random() * 7) + 5

        // how many particles?
        I = ((Math.random() * 20) + 5) | 10

        // generate each particle
        for (P = I; P; P--) {
          p.push({
            c: C,
            x: rocket.a,
            y: rocket.y,
            v: V,
            s: 10,
            f: Math.cos(2 * Math.PI * P / I),
            g: Math.sin(2 * Math.PI * P / I)
          })
        }
      }
    } else {
      // draw the rocket
      c.beginPath()
      c.arc(rocket.a, rocket.y, 2, 0, 2 * Math.PI)
      c.fill()
    }
  })
  if (U) {
    r = []
  }

  // iterate through all the particles, clearing them if you updated none
  U = 1
  p.map(function (particle) {
    // stop if it's too slow
    if ((particle.v -= 0.2) < 0) { return }

    // we've updated at least one particle
    U = 0

    // slowly accelerate downward
    particle.g += 0.03

    // move the particle
    particle.x += particle.f * particle.v
    particle.y += particle.g * particle.v

    // shrink
    particle.s = Math.max(particle.s -= 0.5, 1)

    // draw the particle
    c.fillStyle = particle.c
    c.beginPath()
    c.arc(particle.x, particle.y, particle.s, 0, 2 * Math.PI)
    c.fill()
  })
  if (U) {
    p = []
  }

  // go again
  requestAnimationFrame(T)
})()
