├── README.md ├── art_neon.css ├── art_neon.js ├── clock.js ├── common.js ├── index.html ├── input.js ├── jquery.js ├── loader.js ├── noise.js └── teaser.jpg /README.md: -------------------------------------------------------------------------------- 1 | # Neonflames 2 | Neon flames is a crazy online HTML5 drawing tool. 3 | 4 | Try the most recent version online at: https://29a.ch/sandbox/2011/neonflames/ 5 | 6 | This is copyright (c) by Jonas Wagner. 7 | -------------------------------------------------------------------------------- /art_neon.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: black; 3 | height: 100%; 4 | overflow: hidden; 5 | font-family: sans-serif; 6 | font-size: 12px; 7 | } 8 | 9 | #colors { 10 | position: absolute; 11 | top: 54px; 12 | left: 8px; 13 | padding: 0; 14 | margin: 0; 15 | width: 200px; 16 | } 17 | 18 | #colors li { 19 | display: inline-block; 20 | opacity: 0.3; 21 | width: 64px; 22 | height: 64px; 23 | margin: 8px; 24 | border-radius: 64px; 25 | border-radius: 50%; 26 | border: 2px solid white; 27 | cursor: pointer; 28 | -webkit-transition: opacity ease-in-out 0.5s; 29 | -moz-transition: opacity ease-in-out 0.5s; 30 | transition: opacity ease-in-out 0.5s; 31 | } 32 | ul#colors li:hover, #colors li.active { 33 | opacity: 1.0; 34 | width: 80px; 35 | height: 80px; 36 | margin: 0; 37 | -webkit-transition: all ease-in-out 0.5s; 38 | -moz-transition: all ease-in-out 0.5s; 39 | transition: all ease-in-out 0.5s; 40 | } 41 | #colors li.active { 42 | opacity: 0.3; 43 | } 44 | 45 | canvas { 46 | clear: left; 47 | } 48 | 49 | #clear { 50 | right: 300px; 51 | } 52 | 53 | #clear:hover { 54 | background: rgb(170,14,0); /* Old browsers */ 55 | background: -moz-linear-gradient(top, rgba(170,14,0,1) 0%, rgba(190,13,0,1) 50%, rgba(148,7,0,1) 51%, rgba(150,8,0,1) 71%, rgba(154,3,0,1) 100%); /* FF3.6+ */ 56 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(170,14,0,1)), color-stop(50%,rgba(190,13,0,1)), color-stop(51%,rgba(148,7,0,1)), color-stop(71%,rgba(150,8,0,1)), color-stop(100%,rgba(154,3,0,1))); /* Chrome,Safari4+ */ 57 | background: -webkit-linear-gradient(top, rgba(170,14,0,1) 0%,rgba(190,13,0,1) 50%,rgba(148,7,0,1) 51%,rgba(150,8,0,1) 71%,rgba(154,3,0,1) 100%); /* Chrome10+,Safari5.1+ */ 58 | background: -o-linear-gradient(top, rgba(170,14,0,1) 0%,rgba(190,13,0,1) 50%,rgba(148,7,0,1) 51%,rgba(150,8,0,1) 71%,rgba(154,3,0,1) 100%); /* Opera11.10+ */ 59 | background: -ms-linear-gradient(top, rgba(170,14,0,1) 0%,rgba(190,13,0,1) 50%,rgba(148,7,0,1) 51%,rgba(150,8,0,1) 71%,rgba(154,3,0,1) 100%); /* IE10+ */ 60 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#aa0e00', endColorstr='#9a0300',GradientType=0 ); /* IE6-9 */ 61 | background: linear-gradient(top, rgba(170,14,0,1) 0%,rgba(190,13,0,1) 50%,rgba(148,7,0,1) 51%,rgba(150,8,0,1) 71%,rgba(154,3,0,1) 100%); /* W3C */ 62 | border: 2px solid #ddd; 63 | } 64 | 65 | #share { 66 | right: 135px; 67 | 68 | } 69 | 70 | #download { 71 | right: 8px; 72 | } 73 | .button { 74 | 75 | -webkit-transition: all ease-in-out 0.5s; 76 | -moz-transition: all ease-in-out 0.5s; 77 | transition: all ease-in-out 0.5s; 78 | box-shadow: 0 0 10px black inset; 79 | position: absolute; 80 | margin: 8px; 81 | top: 4px; 82 | right: 8px; 83 | color: #ddd; 84 | font-weight: bold; 85 | display: block; 86 | text-align: center; 87 | width: 100px; 88 | border-radius: 10px; 89 | padding: 8px; 90 | border: 2px solid #666; 91 | text-decoration: none; 92 | 93 | background: #4c4c4c; /* Old browsers */ 94 | background: -moz-linear-gradient(top, #4c4c4c 0%, #595959 12%, #666666 25%, #474747 39%, #2c2c2c 50%, #000000 51%, #111111 60%, #2b2b2b 76%, #1c1c1c 91%, #131313 100%); /* FF3.6+ */ 95 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#4c4c4c), color-stop(12%,#595959), color-stop(25%,#666666), color-stop(39%,#474747), color-stop(50%,#2c2c2c), color-stop(51%,#000000), color-stop(60%,#111111), color-stop(76%,#2b2b2b), color-stop(91%,#1c1c1c), color-stop(100%,#131313)); /* Chrome,Safari4+ */ 96 | background: -webkit-linear-gradient(top, #4c4c4c 0%,#595959 12%,#666666 25%,#474747 39%,#2c2c2c 50%,#000000 51%,#111111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%); /* Chrome10+,Safari5.1+ */ 97 | background: -o-linear-gradient(top, #4c4c4c 0%,#595959 12%,#666666 25%,#474747 39%,#2c2c2c 50%,#000000 51%,#111111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%); /* Opera11.10+ */ 98 | background: -ms-linear-gradient(top, #4c4c4c 0%,#595959 12%,#666666 25%,#474747 39%,#2c2c2c 50%,#000000 51%,#111111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%); /* IE10+ */ 99 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#4c4c4c', endColorstr='#131313',GradientType=0 ); /* IE6-9 */ 100 | background: linear-gradient(top, #4c4c4c 0%,#595959 12%,#666666 25%,#474747 39%,#2c2c2c 50%,#000000 51%,#111111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%); /* W3C */ 101 | } 102 | .button:hover { 103 | color: #fff; 104 | border-color: #fff; 105 | } 106 | 107 | #social { 108 | position: absolute; 109 | left: 380px; 110 | top: 15px; 111 | height: 10px; 112 | width: 300px; 113 | } 114 | #social > * { 115 | float: left; 116 | opacity: 0.5; 117 | } 118 | #social > *:hover { 119 | opacity: 1.0; 120 | } 121 | 122 | h1, p { 123 | color: #fff; 124 | opacity: 0.5; 125 | position: absolute; 126 | top: -10px; 127 | left: 15px; 128 | font-family: Michroma, sans-serif; 129 | } 130 | 131 | p { 132 | top: 8px; 133 | left: 150px; 134 | } 135 | 136 | h1:hover, p:hover { 137 | opacity: 1.0; 138 | } 139 | h1 a, p a { 140 | color: #fff; 141 | text-decoration: none; 142 | } 143 | noscript { 144 | color: white; 145 | } 146 | -------------------------------------------------------------------------------- /art_neon.js: -------------------------------------------------------------------------------- 1 | var particles = [], 2 | color = 'rgb(12, 2, 2)', 3 | composite = 'lighter', 4 | max_age = 100, 5 | initial_radius = 5, 6 | lineWidth = 1.0, 7 | noiseCanvas = makeOctaveNoise(canvas.width, canvas.height, 8), 8 | noise = noiseCanvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height).data; 9 | 10 | function clear(){ 11 | _gaq.push(['_trackEvent', 'neonfuzz', 'clear']); 12 | ctx.globalCompositeOperation = 'source-over'; 13 | ctx.fillStyle = 'black'; 14 | ctx.fillRect(0, 0, canvas.width, canvas.height); 15 | } 16 | 17 | function download(){ 18 | _gaq.push(['_trackEvent', 'neonfuzz', 'download']); 19 | window.open(canvas.toDataURL('image/jpeg', 0.9)) 20 | } 21 | 22 | function share(){ 23 | _gaq.push(['_trackEvent', 'neonfuzz', 'share']); 24 | 25 | 26 | try { 27 | var img = canvas.toDataURL('image/jpeg', 0.9).split(',')[1]; 28 | } catch(e) { 29 | var img = canvas.toDataURL().split(',')[1]; 30 | } 31 | var w = window.open(); 32 | w.document.write('Uploading...'); 33 | $.ajax({ 34 | url: 'http://api.imgur.com/2/upload.json', 35 | type: 'POST', 36 | data: { 37 | type: 'base64', 38 | key: '48c16073663cb7d3befd1c2c064dfa0d', 39 | name: 'neon.jpg', 40 | title: 'test title', 41 | caption: 'test caption', 42 | image: img 43 | }, 44 | dataType: 'json' 45 | }).success(function(data) { 46 | w.location.href = data['upload']['links']['imgur_page']; 47 | }).error(function() { 48 | alert('Could not reach api.imgur.com. Sorry :('); 49 | w.close(); 50 | }); 51 | } 52 | 53 | function getNoise(x, y, channel) { 54 | //return fuzzy(0.4); 55 | return noise[(~~x+~~y*canvas.width)*4+channel]/127-1.0; 56 | } 57 | 58 | // base +/- range 59 | function fuzzy(range, base){ 60 | return (base||0) + (Math.random()-0.5)*range*2 61 | } 62 | 63 | timer.ontick = function(td){ 64 | if(input.mouse.down){ 65 | for(var i = 0; i < 10; i++){ 66 | particles.push({ 67 | vx: fuzzy(10.0), 68 | vy: fuzzy(10.0), 69 | x: input.mouse.x, 70 | y: input.mouse.y, 71 | age: 0 72 | }); 73 | } 74 | } 75 | 76 | ctx.lineWidth = lineWidth; 77 | ctx.strokeStyle = color; 78 | ctx.fillStyle = color; 79 | ctx.globalAlpha = 1.0; 80 | ctx.globalCompositeOperation = composite; 81 | var alive = []; 82 | 83 | for(var i = 0; i < particles.length; i++){ 84 | var p = particles[i]; 85 | p.vx = p.vx*0.8 + getNoise(p.x, p.y, 0)*4;//+fuzzy(1.0); 86 | p.vy = p.vy*0.8 + getNoise(p.x, p.y, 1)*4;//+fuzzy(1.0); 87 | p.x += p.vx; 88 | p.y += p.vy; 89 | p.age ++; 90 | 91 | ctx.beginPath(); 92 | ctx.arc(p.x, p.y, 0.5, 0, Math.PI*2, true); 93 | ctx.closePath(); 94 | ctx.fill(); 95 | //ctx.stroke(); 96 | 97 | if(p.age < max_age){ 98 | alive.push(p); 99 | } 100 | } 101 | 102 | particles = alive; 103 | } 104 | 105 | ctx.fillStyle = 'black'; 106 | ctx.fillRect(0, 0, canvas.width, canvas.height); 107 | 108 | $('#colors li').click(function() { 109 | $('#colors li').removeClass('active'); 110 | $(this).addClass('active'); 111 | }); 112 | -------------------------------------------------------------------------------- /clock.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | window.clock = {}; 3 | window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame; 4 | clock.Clock = function () { 5 | this.running = false; 6 | this.interval = null; 7 | this.t0 = new Date(); 8 | } 9 | clock.Clock.prototype = { 10 | tick: function () { 11 | var t1 = new Date(), 12 | td = (t1-this.t0)/1000; 13 | this.t0 = t1; 14 | this.ontick(td); 15 | }, 16 | start: function (element) { 17 | this.running = true; 18 | var self = this, f; 19 | if(window.requestAnimationFrame){ 20 | window.requestAnimationFrame(f = function () { 21 | self.tick(); 22 | if(self.running){ 23 | window.requestAnimationFrame(f, element); 24 | } 25 | }, element); 26 | } 27 | else { 28 | this.interval = window.setInterval(function() { 29 | self.tick(); 30 | }, 1); 31 | } 32 | this.t0 = new Date(); 33 | }, 34 | stop: function() { 35 | if(this.interval){ 36 | window.clearInterval(this.interval); 37 | this.interval = null; 38 | } 39 | this.running = false; 40 | }, 41 | ontick: function() {} 42 | }; 43 | 44 | })(); 45 | -------------------------------------------------------------------------------- /common.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var canvas = document.getElementById('c'), 3 | ctx = canvas.getContext('2d'), 4 | input = new inputhandler.InputHandler(canvas), 5 | timer = new clock.Clock(); 6 | 7 | canvas.height = window.innerHeight; 8 | canvas.width = window.innerWidth; 9 | document.body.style.margin = 0; 10 | document.body.style.overflow = 'hidden'; 11 | 12 | timer.start(); 13 | 14 | window.timer = timer; 15 | window.input = input; 16 | window.ctx = ctx; 17 | window.canvas = canvas; 18 | 19 | })(); 20 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |