class IsoBoxer
  
  constructor: (id) ->
    @rot = random() * TWO_PI
    @dr = @rot;
    @rx = random() * 0.1 + 0.01
    @ry = @rx / 2
    @x = random()
    @y = random()
    @dx = @x
    @dy = @y
    @height = random() * 0.1 + 0.1
    @verts = []
    @damp = 40
    @chance = 0.2
    @randStep = 0.15
    @halfRandStep = @randStep / 2
    @rotStep =  @randStep * 10
    @halfRotStep = @rotStep / 2
    @col = ['#de9268', '#7ba8d4', '#3e8ad6', '#248a81']
    @col = id == 0 && @col[1] || @col[floor random() * @col.length]
    
  run: (@id) =>
    alpha = 1;
    repeat boxNum, (id) =>
      if @id != id
        repeat @verts.length, (i) =>
          if pointInPoly @verts[i][0], @verts[i][1], boxers[id].verts
            @dx = random() * 2 - 1
            @dy = random() * 2 - 1
            alpha = random()
            false

    if random() < @chance
      @dx += random() * @randStep - @halfRandStep
      @dr += random() * @rotStep - @halfRotStep

    if random() < @chance
      @dy += random() * @randStep - @halfRandStep
      @dr += random() * @rotStep - @halfRotStep

    if @dx > 1 || @dx < 0 then @dx = random()
    if @dy > 1 || @dy < 0 then @dy = random()

    @rot += (@dr - @rot) / @damp
    @x += (@dx - @x) / @damp
    @y += (@dy - @y) / @damp

    para @x, @y,
      range: [ 0, TWO_PI ]
      step: HALF_PI

      f: (t) =>
        x: @rx * cos t + @rot
        y: @ry * sin t + @rot

      render: (verts, x, y) =>
        yOff = verts.map (val) =>
          coord = val.slice()
          coord[1] += @height
          coord
            
        shadow color: '#fff', alpha: 0.04, blur: 1, x: 0, y: @height
          
        fill @col, alpha - 0.7
        stroke '#fff', 0.02
        repeat 4, (i) =>
          i1 = i + 1
          poly x, y, [verts[i], yOff[i], yOff[i1], verts[i1]]
       
        noStroke()
        fill '#fff', alpha 
        
        @verts = poly x, y, verts
        noShadow()

boxNum = 9
boxers = []
repeat boxNum, (id) -> boxers.push new IsoBoxer(id)

Z animate, ->

  grd = context.createLinearGradient 0, 0, width, height
  grd.addColorStop 0, '#1f2a36' 
  grd.addColorStop 1, '#456b91' 

  background grd
  noStroke()
  fill '#59697a'
  

  boxers.sort (a, b) -> a.y > b.y
    .forEach (boxer, i) ->
      boxer.run(i)
View Compiled

External CSS

  1. https://codepen.io/ZevanRosser/pen/Xgaveb.css

External JavaScript

  1. https://codepen.io/ZevanRosser/pen/Xgaveb.js