How to Generate Noise with Canvas
videos

How to Generate Noise with Canvas

Tutorial Details
  • Topic: Canvas
  • Difficulty: Intermediate
  • Video Length: 17 Minutes

Not too long ago, I noted on Twitter that it’d be fantastic if, one day, CSS3 provided support for adding noise to elements (not audio, but texture). After a bit of experimentation and Googling, I came across a solution that uses JavaScript and canvas to dynamically create noise.


The Screencast


Final Source

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Noise</title>
</head>
<body>

<script>

function generateNoise(opacity) {
   if ( !!!document.createElement('canvas').getContext ) {
      return false;
   }

   var canvas = document.createElement("canvas"),
   ctx = canvas.getContext('2d'),
   x, y,
   number,
   opacity = opacity || .2;

   canvas.width = 45;
   canvas.height = 45;

   for ( x = 0; x < canvas.width; x++ ) {
      for ( y = 0; y < canvas.height; y++ ) {
         number = Math.floor( Math.random() * 60 );

         ctx.fillStyle = "rgba(" + number + "," + number + "," + number + "," + opacity + ")";
         ctx.fillRect(x, y, 1, 1);
      }
   }

   document.body.style.backgroundImage = "url(" + canvas.toDataURL("image/png") + ")";
}
generateNoise(.1); // default opacity is .2

</script>
</body>
</html>     

Conclusion

The big question: is it practical to use a solution like this? Ehh — technically, sure. Browsers that don’t support canvas will simply display a solid background color. That being said, a tiny 24-bit PNG still works perfectly, and is what I’ll most likely continue to use until a more convenient solution becomes available.

What do you think? Or better yet, do you know of a better solution? Mostly, the purpose of this tutorial is mostly to work with canvas a bit, and toy around with things! Thanks for watching, and thank you to Dennis Hotson for the concept.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://kurkit.lt Tautvydas

    Interesting way. Usually I use PS-made background images for this simple effect.

    • Brock Nunn

      I usually find myself using Photoshop images as well, however, I would love to move more of my sites graphics over to code. I would love to stop battling the image quality vs. file size war!

    • http://nodecms.org/en Alexander Trefz

      And as soon as you want to add an (nice) animation, you will fail, cause all you can do is a transparency or an move effect to change the picture.

  • http://laroouse.com piyansitll

    harika bir yazi olmus tnx adamım

  • http://mitchj.info Mitch Johnson

    yay! i’m mentioned in a nettuts article :D

    • http://dhotson.tumblr.com Dennis Hotson

      Except that you failed to give credit where it’s due.

      The code on your site is a direct rip of my code. I’m ok with people using it, just don’t pretend that you wrote it. Not cool.

  • Edward Longman

    Wouldn’t it just be easier to create a function that makes a random then call it each time e.g.
    rand=function(){return Math.floor(Math.random()*255)};

    also to make it harder to tell where the repeat was you could make the size random but with limits like so
    canvas.width = Math.floor(Math.random()*+100)+50};
    canvas.height = Math.floor(Math.random()*100)+50;
    (the plus 50 is just to make sure that you could not get a 1px by 1px background which would be somewhat pointless)
    I hope this make sense to you.

  • http://benackles.com Ben Ackles

    We should be supporting modern browsers first and ignore older browsers who don’t support these enhancements. It’s not going to kill people to see a solid texture (or lack thereof). If there’s some solidarity on whether a feature is the proper use of css3, then do it. If we continue to support (including fall-backs) older browsers we will never progress & frankly no internet user is going to care whether they see the same thing as someone with a modern browser. I don’t even think we should have fall-backs, because in the end that encourages older browsers to persist.

    Nice effect Jeffrey!

    • http://alexmueller.me Alex

      Amen Ben!

    • PDMoe

      Yeah i think you’re right but if you use a modern browser the page will always be faster than in older browser because of the use of code for some effects and I hope that people will realise this.
      Sure it’s a lot of more work to do when you create fallbacks but there are always old people who doesn’t even know how to download a modern browser or how to do updates.
      I think it always depends on the audience for that you create a website..

      • http://benackles.com Ben Ackles

        I tend to think the people who can’t download a modern browser are the same people that don’t care about noise or gradients or rounded corners. In fact, a simpler user experience without the fancy presentation is probably a better experience for older people.

    • http://nodecms.org/en Alexander Trefz

      And now we only need to convince our customers that this is true AND good.

      • http://benackles.com Ben Ackles

        Andy Clarke recently spoke on the idea and can probably explain it better than myself.

        http://vimeo.com/17137962

        The industry needs to adapt to changing technologies and those clients who adopt the latest and greatest techniques will benefit long-term. Mobile technology is growing 8x the rate of traditional browsing. If we rest on our laurels and create for the lowest common denominator we may miss the largest potential market share. Is that enough for your clients?

    • http://ideasandpixels.com Allen Gingrich

      Unfortunately, as was the case with my last major client, there are companies out there that force their network and office to use old browsers. When I first walked into the office and tried to access a web app they had built a few years prior, I was told by the app, “You must have Internet Explorer 6 installed to access this page. Click here to download it.”

      Yes, there are companies out there still pushing the worst browser since Netscape.

      • http://benackles.com Ben Ackles

        Can you still use the application with a solid background? If not, don’t use noise or gradients or rounded corners. The reality is there are few cases when presentational enhancements are really going to hurt the user experience. I understand using fallbacks for serious layout issues, but anything that’s simply going to offer a minor presentational variation doesn’t seem worth the trouble. By adopting new technology you push browsers forward (i.e. your last major client starts to tangibly see the difference). Additionally, our page loads speed up because you’re not using images-replacement techniques that don’t belong. Google has made it clear that they are using speed as one of the many pagerank signals going forward.

  • http://oldmanroller.blogspot.com Patrick

    Very cool!!

    I modified it a bit and made a simple star field. Here’s the js:

    function generateStars(amount){
    if ( !!!document.createElement(‘canvas’).getContext ) {
    return false;
    }

    var canvas = document.createElement(‘canvas’),
    ctx = canvas.getContext(’2d’),
    x, y,
    size,
    r, g, b, a,
    amount = amount || 100;

    canvas.width = 1000;
    canvas.height = 1000;

    // fill with black
    ctx.fillStyle = ‘rgba(0,0,0,1)’;
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    for (var i = 0; i < amount; i++) {
    x = RandomRange(0, canvas.width);
    y = RandomRange(0, canvas.height);
    size = RandomRange(1, 3);
    r = RandomRange(235, 255);
    g = RandomRange(235, 255);
    b = RandomRange(235, 255);
    a = Math.random();

    ctx.fillStyle = ‘rgba(‘ + r + ‘,’ + g + ‘,’ + b + ‘,’ + a + ‘)’;
    ctx.fillRect(x, y, size, size);
    }

    document.body.style.backgroundImage = “url(” + canvas.toDataURL(“image/png”) + “)”;
    }
    function RandomRange(from, to) {
    return Math.floor( Math.random() * (to – from) ) + from;
    }
    generateStars();

  • http://www.pangomedia.se Christian

    Cool! Would be cool to see an implementation of making the canvas monochrome.

    Like passing in a variable in the function and if that variable is true, make the random rgb-colors to be r: 127 g: 127 and b: 127.

    …or not. That’ll just make it a solid grey color right? Well, I’m not sure how to do it but I’d be glad if you could show me.

    /C

    By the way, what’s the difference between the spelling grey/gray? :)

    • Fabian Trafoier

      If you want monochrome colors try something like this:

      r = Math.floor( Math.random() * 256 );
      g = Math.floor( Math.random() * 256 );
      b = Math.floor( Math.random() * 256 );

      average = (r + g + b) / 3;

      ctx.fillStyle = ‘rgba(‘ + average + ‘,’ + average + ‘,’ + average + ‘,’ + opacity + ‘)’;

      p.s: ‘gray’ is American English and ‘grey’ is British English

  • http://creditorwatch.com.au Dale Hurley

    Hi Jeff

    Good to see your face.

    Cool to see the canvas being used and document.body.style.backgroundImage = “url(” + canvas.toDataURL(“image/png”) + “)”;

    Would it not be better to use a var called square and use that for the width, height and for loops? This would save calculating the canvas.width on each loop.

    Also because of hoisting shouldn’t the vars be set first in the function?

    Dale

  • Martin

    Minor point, but you should be talking the Math.rand() * 256, not 255 since you’re using floor(). This will produce values from 0-255, which, I think is your intention.

    Money shot of the whole thing is this one line: document.body.style.backgroundImage = “url(” + canvas.toDataURL(“image/png”) + “)”;

    Thanks for that!

    • Martin

      Of course, that should be Math.random(), not .rand().

  • http://hultner.se Alexander Hultner

    As much I like this idea and I like playing with canvas I feel that in a real world situation it would be wise to generate the png once, save it and then use that image over and over again since youre basically creating an png image anyway.

    Also then youd get rid of browser not supporting canvas problems and having less load on the client at the same time. Only downside with a static png really is if you really want a random set of noise on every page load. But still nice tutorial.

  • Brad

    This gives a very nice almost 3d view to your background. I think I will try it with some browns and see the outcome, Well done Jeffery

  • http://Zettersten.com Erik

    Absolutely my favorite JavaScript/css3 tutorial of the year. Honest…
    The technique is sound (I’m not sure how the dom handles coverting canvas into an img though), the outcome is wonderful, and the tutorial itself is perfect… A little canvas, a little js short code / ternary stuff, and topped off with the ever so awesome css3 transitions…

    More of these canvas goodies (: please

  • vaff

    Coming from Flash and ActionScript 3.0 which also follows the ECMAScript standard, I’m wondering if it isn’t possible to use a JavaScript Perlin Noise library for something like this :)?

  • http://dhotson.tumblr.com Dennis Hotson

    Pretty neat huh? :-)

    Not meaning to be rude, but credit where credit is due. This is a technique I originally used on my personal homepage: http://dhotson.github.com/
    I posted a (slightly crappy) jQuery plugin version of it on Forrst: http://forr.st/~muq

    That said, It’s good to see you’ve tidied it up a little. Thanks! :-)

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      Hey Dennis –

      I learned this technique from a guy, named Mitch. I referenced him twice in the written portion, and at the beginning of the video.

      Are you the original creator of this technique? If so, I’ll modify the article today.

      • http://dhotson.tumblr.com Dennis Hotson

        Thanks Jeffrey, that is correct.

        I’m happy for anyone to steal the code and use it however they like. I’d add a disclaimer that it is very much a hack. I wouldn’t recommend using it on your client’s site. ;-)

  • http://dhotson.tumblr.com Dennis Hotson

    Also, I should mention that a kind fellow named ajcates made an improved version of my plugin. It’s definitely worth checking out:

    http://github.com/ajcates/jQuery-Noise
    http://forr.st/~7Nk

  • http://blog.delivi.com/ Livingston Samuel

    nice effect!

    !!!document.createElement(‘canvas’).getContext in line #11 can be simply written as !document.createElement(‘canvas’).getContext

    • vaff

      are you sure ?

    • http://nodecms.org/en Alexander Trefz

      This is wrong.

      If document.createElement(‘canvas’).getContext is undefined
      then document.createElement(‘canvas’).getContext would be true because undefined is a falsy value.
      thats why you need to convert it to boolean first:

      !!document.createElement(‘canvas’).getContext

      this will return false when undefined and true when not, and then, we want to negotiate that.

      • http://nodecms.org/en Alexander Trefz

        Sorry, i forgot to use pre. btw: a little preview function would be nice.

        If document.createElement(‘canvas’).getContext is undefined
        then
        !document.createElement(‘canvas’).getContext would be true because undefined is a falsy value.
        thats why you need to convert it to boolean first:
        !!document.createElement(‘canvas’).getContext
        this will return false when undefined and true when not, and then, we want to negotiate that:

        !!!document.createElement(‘canvas’).getContext

      • vaff

        I know that, but apparently he didn’t ;)

      • http://www.fatmedia.co.uk Mike

        A slighty nicer way IMO would be this:

        var mycanvas = document.createElement(‘canvas’);

        if(! ‘getContext’ in mycanvas ) return false;

        // continue with function

        Just a thought!

  • http://www.google.si Mike

    Eye-killing, why would anyone put that for the background.

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      You’ve never used a touch of texture in your designs before? It’s extremely common.

  • Le Marquis

    Is it me or what? Whenever I externalize the JS into it’s own file and embed it into the HTML externally it doesn’t work any more? Did it lose the link to the body tag?

  • http://alternates.org Ege Özcan

    This is perfect. Just for the sake of not repeating myself, I would write:

    c = function() { return Math.floor( Math.random() * 256 ); }

    //in the loop:
    ctx.fillStyle = ‘rgba(‘ + c() + ‘,’ + c() + ‘,’ + c() + ‘,’ + opacity + ‘)’;

  • Matt Sur

    Jesus Christ your stunning sir.

  • http://pangomedia.se Christian

    Does anyone know how to make it monochrome? (see my earlier comment, ctrl+f -> “monochrome”)

    /C

    • Le Marquis

      monochrome colours are pretty easy! All gray colours have one similar number for instance (RGB 128, 128, 128 = medium grey). So all you have to do is generate a random number from 0 to 255 and fill that in the RGB (css) string. It’s even faster because you don’t need to calculate those three separate colours but just one digit.

    • Le Marquis

      function generateNoise(opacity) {
      if ( !!!document.createElement(‘canvas’).getContext ) {
      return false;
      }
      var canvas = document.createElement(‘canvas’),
      ctx = canvas.getContext(’2d’),
      x, y,
      number
      opacity = opacity || .2;

      canvas.width = 55;
      canvas.height = 55;

      for ( x = 0; x < canvas.width; x++ ) {
      for ( y = 0; y < canvas.height; y++ ) {
      number = Math.floor( Math.random() * 255 );

      ctx.fillStyle = 'rgba(' + number + ',' + number + ',' + number + ',' + opacity + ')';
      ctx.fillRect(x, y, 1, 1);
      }
      }

      document.body.style.backgroundImage = "url(" + canvas.toDataURL("image/png") + ")";
      }

      generateNoise(.2);

      • Le Marquis

        If the grey-scale is a bit to hard you could always push down the numbers. Normally it generates a random number between 0 till 255. But you could make it a bit toned down… Like so!

        number = Math.floor( Math.random() * 255 ); becomes
        number = Math.floor( Math.random() * 128 );

        I had this problem myself, the generated tones were even to hard on 0.1 alpha instead of making it 0.05 (which wasn’t to my satisfaction) I desided to tone it down a bit…

        Have fun with canvas!

  • http://www.l4u.dk/ Kasper Lau

    Nice, thanks for the demonstration.

  • http://www.jauhari.net/ Jauhari

    Wonderful JavaScript tutorial… Noise is simple effect with multiple purpose

  • Sliya

    Hey,

    I was just wondering what vim color scheme you’re using ?

    And by the way, thanks for the great tuts !

  • Jon

    Sorry if I seem a bit stupid but can you suggest any ways that this is useful? Numerous comments have said it is great for all sorts of purposes, I just don’t know what they are.
    Thanks

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      Thousands of websites use a bit of texture in their backgrounds.

  • Le Marquis

    I have just one question?

    How can I insert a fallback image for the background. I noticed IE 6 till 8 doesn’t support Canvas yet! So if you use this an want to make it cross browser friendly? How do you create a fallback within the JavaScript?

    • http://lookitsatravis.com Travis Vignon

      You’re gonna laugh when you see this. The solution is very easy – only requires the addition of a single line…

      function generateNoise(opacity) {
      if ( !!!document.createElement(‘canvas’).getContext ) {

      //add the following line
      document.body.style.backgroundImage = “url(path/to/image.jpg)”;

      return false;
      }

      }

      • Le Marquis

        How could I not see that… How stuppid!

  • Ege Özcan

    I made a tool out of this tutorial and published it on my testing domain. You can have a look at http://www.keodameo.com

  • http://designconcept.webdev20.pl designconcept

    Thank you for the tutorial. Waiting for more about HTML5 Canvas.

  • Brian McSweeney

    I’ve been meaning to look into doing something like this; thanks for putting it up!

    One thing I would change about it, though, is to make the default background color appear darker if the browser does not support canvas. Creating a texture through this method makes the background significantly darker (depending on your opacity setting), which would then require setting your body background to a lighter shade than you really want it. Because of this, anyone using a browser that doesn’t support canvas won’t see the intended color.

    For example, if someone on an older browser tried to look at the demo page, they would see a page in blindingly bright #f00, but when the canvas is applied the end result is closer to #900, which would be much better as a background color.

    As an alternative to making the background darker in non-canvas browsers, you could also make the background on browsers that do support canvas lighter before applying the noise, to cancel out the darkening effect.

    … Unfortunately, I don’t know how to generate a lighter shade of a particular color in javascript, so you have to find both colors yourself. Does anyone else have any ideas on how to do this?

  • https://github.com/dannyglue/jQuery-Noiser Danny

    Hi. Using the same technique, a 0.5kb jQuery plugin is created on github with a few options:

    https://github.com/dannyglue/jQuery-Noiser

    Example:

    $(‘body’).noiser({
    opacity: 0.5, // opacity from 0-1, defaulted to 0.1
    contrast: 20, // noise strength from 0-255, defaulted to 120
    red: 111, // add red from 0-255, defaulted to 0
    green: 126, // add green from 0-255, defaulted to 0
    blue: 144, // add blue from 0-255, defaulted to 0
    size: 100 // dimensions of the generated background image, defaulted to 60
    });

  • http://www.wsiwebefectivo.com diseño web guadalajara

    I’ve thinking about how to do that.I was trying to follow the pixastic script with the histograms,but I just get confused with jQuery stuff and I had to give up.Thank you for the tutorial. Waiting for more about HTML5 Canvas.I would love to see how to do it.

  • http://bealitao.carbonmade.com Bea Litao

    Thank you SO much for putting this up! I’m trying to learn what HTML5 can offer, and this tutorial has been very helpful! It just gave me another reason to keep studying!

    But, is it possible to have the code embedded instead?

  • http://joshriser.com Josh

    Is there a way to add noise to a specified element? I.E. Add noise to a list item, a paragraph, ect.

  • nakulh

    HOW to do the same with a “div” element

  • Edoardo

    I have slightly modified your code in order to generate a css class to which apply the noise. Here’s the code:

    Instead of:

    document.body.style.backgroundImage = “url(” + canvas.toDataURL(“image/png”) + “)”;

    To:

    var style = document.createElement(‘style’);
    style.type = ‘text/css’;
    style.innerHTML = “.noise{ background-image: url(“+canvas.toDataURL(“image/png”)+”)}”;
    document.getElementsByTagName(‘head’)[0].appendChild(style);

    Hope will help

  • Francisco Gutiérrez

    thank you very much! I have implemented the size too. It is very clear and helpfull