sink-1
2013. 01. 10.

My attempt to simulate a hyperbolic funnel (gone a bit crazy). Drag on the screen and see the marbles spinning. Press enter key to invert the colors.

» launch sink-1

p5    = processing
balls = []
g     = 1
cx    = null
cy    = null
bg    = 255
fg    = 0
rtn   = if typeof(window.devicePixelRatio) != 'undefined'
          window.devicePixelRatio
        else
          1

setup = ->
  size      $(window).width() * rtn, $(window).height() * rtn
  frameRate 60
  stroke    fg
  cx = p5.width / 2
  cy = p5.height / 2

angle = (x, y) ->
  atan2 cy - y, cx - x

dying = (x, y, vx, vy) ->
  dist(cx, cy, x, y) < 10 and mag(vx, vy) < 10

class Ball
  constructor: (@x, @y, @vx, @vy) ->
    @sw = 1 + random() * 30
    @life = 20

  tick: ->
    ang = angle(@x, @y)
    @vx += g * cos(ang)
    @vy += g * sin(ang)

    @vx *= 0.99
    @vy *= 0.99

    @x += @vx
    @y += @vy

    strokeWeight @sw
    point @x, @y

    @life -= 1 if dying(@x, @y, @vx, @vy)
    @life > 0

keyPressed = ->
  if keyCode() == ENTER || keyCode() == RETURN
    [fg, bg] = [bg, fg]
    stroke fg

draw = ->
  if __mousePressed()
    mx = p5.mouseX * rtn
    my = p5.mouseY * rtn
    ang = angle(mx, my)
    for i in [0...3]
      a = ang + 0.4 * PI + 0.2 * random() * PI
      f = random() * 50
      balls.push new Ball(mx, my, f * cos(a), f * sin(a))

  background bg
  balls = (b for b in balls when b.tick())
» capture | close