planet atmospheres

HTML

<script src="https://raw.github.com/jo/JSColor/master/jscolor.min.js"></script>
<canvas width=200 height=200></canvas>

<div id='controls'>
    <label for='c1'>Main Color</label><br/>
    <input id='c1' type='color' value='C9FFCF'/><br/>
    <label for='c2'>Second Color</label><br/>
    <input id='c2' type='color' value='BC82FF'/><br/>
    
    <label for='offset'>Atmosphere Size</label><br/>
    <input id='offset' type='range' step='1' value='8' min='0' max='25' /><br/>
    
    <label for='density'>Atmosphere Density</label></br>
    <input id='density' type='range' value='20' min='0' max='100' /><br/>
</div>

CSS

body {
    background: black;
    color: white;
}
canvas {
    width: 400px;
    height: 400px;
    background: black;
}

* {
    font-family: sans-serif;
    font-size: 12px;
}

#controls {
    position: absolute;
    top:10px;
    left:410px;
}

input {
    border: 0;
    padding: 3px;
    margin: 2px;
}

CoffeeScript

RGBColor = (color) ->
    rgb = undefined
    colorObj = undefined
    color = color.replace("0x", "")
    color = color.replace("#", "")
    rgb = parseInt(color, 16)
    colorObj = {}
    colorObj.r = (rgb & (255 << 16)) >> 16
    colorObj.g = (rgb & (255 << 8)) >> 8
    colorObj.b = (rgb & 255)
    colorObj

lerp = (a, b, x) ->
    return Math.round( (a*(1-x)+b*(1+x))/2 )

ctx = $('canvas')[0].getContext '2d'

radius = 50
x = 100
y = 100
dirx = 30
diry = -10

renderPass = (radius, x, y, dirx, diry, c1, c2, s,w, a) ->
    ctx.beginPath()
    c1 = RGBColor c1
    c2 = RGBColor c2
    grd = ctx.createRadialGradient x+dirx,y+diry, 0, x+dirx,y+diry, radius*1.3
    grd.addColorStop 0, "rgba(#{c1.r},#{c1.g},#{c1.b},#{a})"
    grd.addColorStop s, "rgba(#{c1.r},#{c1.g},#{c1.b},#{(1-s)*a})"
    rn = lerp c1.r,c2.r, s+w
    gn = lerp c1.g,c2.g, s+w
    bn = lerp c1.b,c2.b, s+w
    grd.addColorStop s+w, "rgba(#{rn},#{gn},#{bn},#{(1-(s+w))*a})"
    grd.addColorStop s+w+w, "rgba(#{rn},#{gn},#{bn},0)"
    ctx.fillStyle = grd
    ctx.arc x,y, radius, 0, 2*Math.PI, false
    ctx.fill()
    ctx.closePath()


render = ->
    c1 = $('#c1').val()
    c2 = $('#c2').val()
    offset = parseInt $('#offset').val()
    density = parseInt $('#density').val()
    density /= 100
    ctx.clearRect 0,0, 320,320
    renderPass radius, x, y, dirx, diry, c1, c2, 0.75, 0.1, 1
    
    i=0
    while i<(offset+1)
        renderPass (radius)+i*1, x, y, dirx, diry, c1, c2, 0.75, 0.1, density
        ++i

$('input').change ->
    render()
    
mouseisdown=false
$('canvas').mousedown (e) ->
    dirx = (e.pageX - 160) / 2
    diry = (e.pageY - 160) / 2
    render()
    mouseisdown = true
    return true
$('body').mouseup ->
    mouseisdown = false
    return true

$('body').mousemove (e) ->
    return if not mouseisdown
    dirx = (e.pageX - 200) / 2
    diry = (e.pageY - 200) / 2
    render()
    return true

setTimeout render, 20