├── .gitignore ├── docs ├── img │ ├── Fork.png │ ├── Get.png │ ├── Hole.png │ ├── Logo.png │ ├── Fork@2x.png │ ├── Get@2x.png │ ├── Hole@2x.png │ ├── Background.jpg │ ├── DonkeyKong.png │ └── Background@2x.jpg ├── reset.css ├── prism.css ├── prism.min.js ├── style.css └── index.html ├── README.md ├── fatpixels.min.js └── fatpixels.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /docs/img/Fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matmartinez/fatpixels/HEAD/docs/img/Fork.png -------------------------------------------------------------------------------- /docs/img/Get.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matmartinez/fatpixels/HEAD/docs/img/Get.png -------------------------------------------------------------------------------- /docs/img/Hole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matmartinez/fatpixels/HEAD/docs/img/Hole.png -------------------------------------------------------------------------------- /docs/img/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matmartinez/fatpixels/HEAD/docs/img/Logo.png -------------------------------------------------------------------------------- /docs/img/Fork@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matmartinez/fatpixels/HEAD/docs/img/Fork@2x.png -------------------------------------------------------------------------------- /docs/img/Get@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matmartinez/fatpixels/HEAD/docs/img/Get@2x.png -------------------------------------------------------------------------------- /docs/img/Hole@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matmartinez/fatpixels/HEAD/docs/img/Hole@2x.png -------------------------------------------------------------------------------- /docs/img/Background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matmartinez/fatpixels/HEAD/docs/img/Background.jpg -------------------------------------------------------------------------------- /docs/img/DonkeyKong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matmartinez/fatpixels/HEAD/docs/img/DonkeyKong.png -------------------------------------------------------------------------------- /docs/img/Background@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matmartinez/fatpixels/HEAD/docs/img/Background@2x.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FatPixels 2 | ========= 3 | 4 | State-of-the-art pixel art animation and drawing. See [reference, examples and more](http://www.matmartinez.net/fatpixels/). -------------------------------------------------------------------------------- /docs/reset.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/) 3 | * http://cssreset.com 4 | */ 5 | html, body, div, span, applet, object, iframe, 6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 7 | a, abbr, acronym, address, big, cite, code, 8 | del, dfn, em, img, ins, kbd, q, s, samp, 9 | small, strike, strong, sub, sup, tt, var, 10 | b, u, i, center, 11 | dl, dt, dd, ol, ul, li, 12 | fieldset, form, label, legend, 13 | table, caption, tbody, tfoot, thead, tr, th, td, 14 | article, aside, canvas, details, embed, 15 | figure, figcaption, footer, header, hgroup, 16 | menu, nav, output, ruby, section, summary, 17 | time, mark, audio, video { 18 | margin: 0; 19 | padding: 0; 20 | border: 0; 21 | font-size: 100%; 22 | font: inherit; 23 | vertical-align: baseline; 24 | } 25 | /* HTML5 display-role reset for older browsers */ 26 | article, aside, details, figcaption, figure, 27 | footer, header, hgroup, menu, nav, section { 28 | display: block; 29 | } 30 | body { 31 | line-height: 1; 32 | } 33 | ol, ul { 34 | list-style: none; 35 | } 36 | blockquote, q { 37 | quotes: none; 38 | } 39 | blockquote:before, blockquote:after, 40 | q:before, q:after { 41 | content: ''; 42 | content: none; 43 | } 44 | table { 45 | border-collapse: collapse; 46 | border-spacing: 0; 47 | } -------------------------------------------------------------------------------- /docs/prism.css: -------------------------------------------------------------------------------- 1 | /** 2 | * prism.js default theme for JavaScript, CSS and HTML 3 | * Based on dabblet (http://dabblet.com) 4 | * @author Lea Verou 5 | */ 6 | 7 | code[class*="language-"], 8 | pre[class*="language-"] { 9 | color: black; 10 | text-shadow: 0 1px white; 11 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 12 | direction: ltr; 13 | text-align: left; 14 | white-space: pre; 15 | word-spacing: normal; 16 | 17 | -moz-tab-size: 4; 18 | -o-tab-size: 4; 19 | tab-size: 4; 20 | 21 | -webkit-hyphens: none; 22 | -moz-hyphens: none; 23 | -ms-hyphens: none; 24 | hyphens: none; 25 | } 26 | 27 | /* Code blocks */ 28 | pre[class*="language-"] { 29 | overflow: auto; 30 | } 31 | 32 | .token.comment, 33 | .token.prolog, 34 | .token.doctype, 35 | .token.cdata { 36 | color: slategray; 37 | } 38 | 39 | .token.punctuation { 40 | color: #999; 41 | } 42 | 43 | .namespace { 44 | opacity: .7; 45 | } 46 | 47 | .token.property, 48 | .token.tag, 49 | .token.boolean, 50 | .token.number { 51 | color: #905; 52 | } 53 | 54 | .token.selector, 55 | .token.attr-name, 56 | .token.string { 57 | color: #690; 58 | } 59 | 60 | .token.operator, 61 | .token.entity, 62 | .token.url, 63 | .language-css .token.string, 64 | .style .token.string { 65 | color: #a67f59; 66 | } 67 | 68 | .token.atrule, 69 | .token.attr-value, 70 | .token.keyword { 71 | color: #07a; 72 | } 73 | 74 | 75 | .token.regex, 76 | .token.important { 77 | color: #e90; 78 | } 79 | 80 | .token.important { 81 | font-weight: bold; 82 | } 83 | 84 | .token.entity { 85 | cursor: help; 86 | } 87 | 88 | /** 89 | * prism.js Dark theme for JavaScript, CSS and HTML 90 | * Based on the slides of the talk “/Reg(exp){2}lained/” 91 | * @author Lea Verou 92 | */ 93 | 94 | .dark code[class*="language-"], 95 | .dark pre[class*="language-"] { 96 | color: white; 97 | text-shadow: 0 -.1em .2em black; 98 | } 99 | 100 | .dark .token.comment, 101 | .dark .token.prolog, 102 | .dark .token.doctype, 103 | .dark .token.cdata { 104 | color: hsl(30,20%,50%); 105 | } 106 | 107 | .dark .token.punctuation { 108 | opacity: .7; 109 | } 110 | 111 | .dark .namespace { 112 | opacity: .7; 113 | } 114 | 115 | .dark .token.property, 116 | .dark .token.tag, 117 | .dark .token.boolean, 118 | .dark .token.number { 119 | color: hsl(350, 40%, 70%); 120 | } 121 | 122 | .dark .token.selector, 123 | .dark .token.attr-name, 124 | .dark .token.string { 125 | color: hsl(30,20%,50%); 126 | } 127 | 128 | .token.operator, 129 | .token.entity, 130 | .token.url, 131 | .language-css .token.string, 132 | .style .token.string { 133 | color: hsl(40, 90%, 60%); 134 | } 135 | 136 | .dark .token.atrule, 137 | .dark .token.attr-value, 138 | .dark .token.keyword { 139 | color: hsl(350, 40%, 70%); 140 | } 141 | 142 | 143 | .dark .token.regex, 144 | .dark .token.important { 145 | color: #e90; 146 | } -------------------------------------------------------------------------------- /docs/prism.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Prism: Lightweight, robust, elegant syntax highlighting 3 | * MIT license http://www.opensource.org/licenses/mit-license.php/ 4 | * @author Lea Verou http://lea.verou.me 5 | */(function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var r={};for(var i in e)e.hasOwnProperty(i)&&(r[i]=t.util.clone(e[i]));return r;case"Array":return e.slice()}return e}},languages:{extend:function(e,n){var r=t.util.clone(t.languages[e]);for(var i in n)r[i]=n[i];return r},insertBefore:function(e,n,r,i){i=i||t.languages;var s=i[e],o={};for(var u in s)if(s.hasOwnProperty(u)){if(u==n)for(var a in r)r.hasOwnProperty(a)&&(o[a]=r[a]);o[u]=s[u]}return i[e]=o},DFS:function(e,n){for(var r in e){n.call(e,r,e[r]);t.util.type(e)==="Object"&&t.languages.DFS(e[r],n)}}},highlightAll:function(e,n){var r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');for(var i=0,s;s=r[i++];)t.highlightElement(s,e===!0,n)},highlightElement:function(r,i,s){var o,u,a=r;while(a&&!e.test(a.className))a=a.parentNode;if(a){o=(a.className.match(e)||[,""])[1];u=t.languages[o]}if(!u)return;r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o;a=r.parentNode;/pre/i.test(a.nodeName)&&(a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var f=r.textContent;if(!f)return;f=f.replace(/&/g,"&").replace(//g,">").replace(/\u00a0/g," ");var l={element:r,language:o,grammar:u,code:f};t.hooks.run("before-highlight",l);if(i&&self.Worker){var c=new Worker(t.filename);c.onmessage=function(e){l.highlightedCode=n.stringify(JSON.parse(e.data));l.element.innerHTML=l.highlightedCode;s&&s.call(l.element);t.hooks.run("after-highlight",l)};c.postMessage(JSON.stringify({language:l.language,code:l.code}))}else{l.highlightedCode=t.highlight(l.code,l.grammar);l.element.innerHTML=l.highlightedCode;s&&s.call(r);t.hooks.run("after-highlight",l)}},highlight:function(e,r){return n.stringify(t.tokenize(e,r))},tokenize:function(e,n){var r=t.Token,i=[e],s=n.rest;if(s){for(var o in s)n[o]=s[o];delete n.rest}e:for(var o in n){if(!n.hasOwnProperty(o)||!n[o])continue;var u=n[o],a=u.inside,f=!!u.lookbehind||0;u=u.pattern||u;for(var l=0;le.length)break e;if(c instanceof r)continue;u.lastIndex=0;var h=u.exec(c);if(h){f&&(f=h[1].length);var p=h.index-1+f,h=h[0].slice(f),d=h.length,v=p+d,m=c.slice(0,p+1),g=c.slice(v+1),y=[l,1];m&&y.push(m);var b=new r(o,a?t.tokenize(h,a):h);y.push(b);g&&y.push(g);Array.prototype.splice.apply(i,y)}}}return i},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]"){for(var r=0;r"+i.content+""};if(!self.document){self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}})();; 6 | Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,number:/\b-?(0x)?\d*\.?[\da-f]+\b/g,operator:/[-+]{1,2}|!|=?<|=?>|={1,2}|(&){1,2}|\|?\||\?|\*|\//g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};; 7 | Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(var|let|if|else|while|do|for|return|in|instanceof|function|new|with|typeof|try|catch|finally|null|break|continue)\b/g,number:/\b(-?(0x)?\d*\.?[\da-f]+|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(<|<)script[\w\W]*?(>|>)[\w\W]*?(<|<)\/script(>|>)/ig,inside:{tag:{pattern:/(<|<)script[\w\W]*?(>|>)|(<|<)\/script(>|>)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});; -------------------------------------------------------------------------------- /docs/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #161616;/*#1d1d1d;*/ 3 | background-repeat: repeat-x; 4 | background-position: center top; 5 | background-image: url(img/Background.jpg); 6 | 7 | font-family: "Helvetica Neue", sans-serif; 8 | font-weight: lighter; 9 | 10 | padding-right: 5px; 11 | padding-left: 5px; 12 | } 13 | 14 | .amp { 15 | font-family: Baskerville,'Goudy Old Style',Palatino,'Book Antiqua',serif; 16 | font-style: italic; 17 | font-weight: normal; 18 | } 19 | 20 | em { 21 | font-style: italic; 22 | } 23 | 24 | code { 25 | font-size: 14px; 26 | font-family: "Panic Sans", "Menlo", monospace; 27 | } 28 | 29 | /* 30 | * 31 | * Header. 32 | * 33 | */ 34 | header { 35 | max-width: 700px; 36 | margin: 0 auto; 37 | 38 | overflow: hidden; 39 | } 40 | 41 | 42 | header .hero { 43 | margin-top: 20px; 44 | } 45 | 46 | header .hero > * { 47 | display: block; 48 | margin: 0 auto; 49 | } 50 | 51 | header hgroup { 52 | display: block; 53 | 54 | padding-top: 40px; 55 | padding-bottom: 40px; 56 | 57 | text-align: center; 58 | } 59 | 60 | header a.logo, 61 | header a.logo > * { 62 | display: block; 63 | } 64 | 65 | header a.logo > * { 66 | display: inline-block; 67 | } 68 | 69 | header h2 { 70 | margin-top: 10px; 71 | 72 | color: #888; 73 | text-shadow: 0px 1px 0px #000; 74 | 75 | color: #fff; 76 | text-shadow: 0px 1px 4px #000; 77 | 78 | font-size: 18px; 79 | } 80 | 81 | header ol.buttons { 82 | margin-top: 60px; 83 | } 84 | 85 | header ol.buttons li { 86 | display: inline-block; 87 | margin-right: 10px; 88 | margin-left: 10px; 89 | } 90 | 91 | header ol.buttons li a { 92 | display: block; 93 | width: 190px; 94 | height: 60px; 95 | 96 | margin-bottom: 2px; 97 | 98 | background-size: 190px 60px; 99 | } 100 | 101 | header ol.buttons li a:active { 102 | margin-top: 2px; 103 | margin-bottom: 0px; 104 | } 105 | 106 | header ol.buttons a.js { 107 | background-image: url(img/Get.png); 108 | } 109 | 110 | header ol.buttons a.fork { 111 | background-image: url(img/Fork.png); 112 | } 113 | 114 | @media 115 | only screen and (-webkit-min-device-pixel-ratio: 2), 116 | only screen and ( min--moz-device-pixel-ratio: 2), 117 | only screen and ( -o-min-device-pixel-ratio: 2/1) { 118 | 119 | header ol.buttons a.js { 120 | background-image: url(img/Get@2x.png); 121 | } 122 | 123 | header ol.buttons a.fork { 124 | background-image: url(img/Fork@2x.png); 125 | } 126 | } 127 | 128 | 129 | /* 130 | * 131 | * Snippet. 132 | * 133 | */ 134 | 135 | section.snippet { 136 | max-width: 680px; 137 | margin: 0 auto; 138 | 139 | border-top: 2px dotted #1d1d1d; 140 | border-bottom: 2px dotted #1d1d1d; 141 | 142 | background: repeat-y url(img/Hole.png) left top, 143 | repeat-y url(img/Hole.png) right top, 144 | #dbdbdb; 145 | } 146 | 147 | @media 148 | only screen and (-webkit-min-device-pixel-ratio: 2), 149 | only screen and ( min--moz-device-pixel-ratio: 2), 150 | only screen and ( -o-min-device-pixel-ratio: 2/1) { 151 | 152 | section.snippet { 153 | background-size: 40px 24px; 154 | background: repeat-y url(img/Hole@2x.png) left top, 155 | repeat-y url(img/Hole@2x.png) right top, 156 | #dbdbdb; 157 | } 158 | 159 | } 160 | 161 | 162 | section.snippet pre { 163 | display: block; 164 | 165 | padding: 15px; 166 | padding-top: 20px; 167 | padding-bottom: 20px; 168 | 169 | margin: 0px; 170 | margin-right: 40px; 171 | margin-left: 40px; 172 | 173 | border-left: 2px dotted #bbbabc; 174 | border-right: 2px dotted #bbbabc; 175 | 176 | text-shadow: 0px 1px 0px #fff; 177 | } 178 | 179 | /* 180 | * 181 | * Reference. 182 | * 183 | */ 184 | 185 | section.reference { 186 | max-width: 680px; 187 | margin: 0 auto; 188 | 189 | margin-top: 40px; 190 | margin-bottom: 40px; 191 | 192 | color: #a5a5a5; 193 | line-height: 24px; 194 | } 195 | 196 | section.reference h1 { 197 | font-size: 24px; 198 | color: #fff; 199 | 200 | margin-bottom: 20px; 201 | } 202 | 203 | section.reference h1 span { 204 | color: #888; 205 | } 206 | 207 | section.reference h2 { 208 | color: #fff; 209 | } 210 | 211 | section.reference ol { 212 | padding-left: 40px; 213 | padding-right: 20px; 214 | } 215 | 216 | section.reference ol li { 217 | margin-bottom: 10px; 218 | } 219 | 220 | section.reference b { 221 | color: #fff; 222 | } 223 | 224 | section.reference em { 225 | color: #666; 226 | } 227 | 228 | section.reference p { 229 | margin-left: 20px; 230 | } 231 | 232 | section.reference pre { 233 | margin: 0px; 234 | margin-right: 20px; 235 | margin-left: 20px; 236 | } 237 | 238 | section.reference a { 239 | color: #fff; 240 | } 241 | 242 | /* 243 | * 244 | * Footer. 245 | * 246 | */ 247 | 248 | footer { 249 | font-size: 14px; 250 | text-align: center; 251 | color: #666; 252 | 253 | padding-top: 40px; 254 | padding-bottom: 40px; 255 | } 256 | 257 | footer p { 258 | margin-top: 5px; 259 | } 260 | 261 | footer .susumi { 262 | font-size: 12px; 263 | } 264 | 265 | footer a { 266 | color: #999; 267 | text-decoration: none; 268 | } -------------------------------------------------------------------------------- /fatpixels.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FatPixels: State-of-the-art pixel art animation and drawing. For the rest of us. 3 | * @author Matías Martínez http://matmartinez.net/ 4 | */(function(g,i,c){function j(q){for(var o=1;o=o){p.call();r=new Date().getTime()}q.value=k(n)}q.value=k(n);return q}function f(n){g.cancelAnimationFrame?g.cancelAnimationFrame(n.value):g.webkitCancelAnimationFrame?g.webkitCancelAnimationFrame(n.value):g.webkitCancelRequestAnimationFrame?g.webkitCancelRequestAnimationFrame(n.value):g.mozCancelRequestAnimationFrame?g.mozCancelRequestAnimationFrame(n.value):g.oCancelRequestAnimationFrame?g.oCancelRequestAnimationFrame(n.value):g.msCancelRequestAnimationFrame?g.msCancelRequestAnimationFrame(n.value):clearInterval(n)}var d={scale:1,autoplay:true,loop:true,speed:"15fps",};var a=function(n){if(!this.drawWithTarget){return new a(n)}this.options=j(n||{},{},d);this.bitmaps=null;this.bitmapSize={width:0,height:0};this.frames=null;this.frame=0;this.useSprite=this.options.sprite!=c;this.useArrayOfImages=this.options.images!=c};var e=function(n,o){this.buffer=i.createElement("canvas");this.buffer.width=n;this.buffer.height=o};e.prototype.drawInBuffer=function(n){this.buffer.getContext("2d").drawImage(n,0,0)};e.prototype.drawBufferInContext=function(n){n.drawImage(this.buffer,0,0)};a.prototype.renderFrames=function(M,L){var B=this.bitmaps;var D=this.bitmapSize;if(!B||L){var C=this;return C.getBitmaps(function(w,r){C.bitmaps=w;C.bitmapSize=r;C.renderFrames(M,false)})}var u=[];var K=this.options.scale,t=D.width*K,F=D.height*K;var n=i.createElement("canvas");n.width=t;n.height=F;var A=n.getContext("2d");for(var E=0;E1)}o.needsDisplay()})};a.prototype.drawingHandler=function(o,n){console.warn("FatPixels: Empty implementation for -drawingHandler.")};a.prototype.needsDisplay=function(){var s=this;var r=s.isAnimating,p=s.frames,o=s.frame;var n=s.options.onAnimation;var q=s.options.speed;if(typeof q=="string"||q instanceof String){if(l(q,"fps")){q=1000/parseFloat(q)}else{if(l(q,"ms")){q=parseFloat(q)}else{if(l(q,"s")){q=parseFloat(q)*1000}}}}if(!s.drawingInterval){s.drawingInterval=m(function(){o++;if(o==p.length){o=0;if(s.options.loop==false){setTimeout(function(){s.setAnimating(false)},1)}}s.drawingHandler(p[o],o);if(n){n(o)}},q)}if(!r){f(s.drawingInterval);delete s.drawingInterval}s.drawingHandler(p[o],o)};a.prototype.setAnimating=function(n){if(n!=this.isAnimating){this.isAnimating=n;this.needsDisplay()}};a.prototype.setFrame=function(n){if(n!=this.frame&&n 2 | 3 | 4 | FATPIXELS — JavaScript State-of-the-art pixel art animation and drawing. For the rest of us. 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 38 | 39 | 40 |
41 |
42 | 43 |
44 | 45 |
46 |

47 |

State-of-the-art pixel art animation & drawing.

48 | 49 |
    50 |
  1. 51 |
  2. 52 |
53 |
54 |
55 | 56 |
57 |
// Draw your art at any scale. The animation is for free.
 58 | var donkeyKong = new FatPixels({
 59 | 	scale  : 4.0,
 60 | 	speed  : "16fps",
 61 | 	sprite : {
 62 | 		url : 'DonkeyKong.png',
 63 | 		direction: 'y',
 64 | 		count : 187,
 65 | 	}
 66 | });
 67 | 
 68 | // jQuery is also supported, see below.
 69 | donkeyKong.drawWithTarget(document.getElementById("donkey"));
70 |
71 | 72 |
73 |

Options for creating a FatPixels object.

74 | 75 |
    76 |
  1. 77 |

    scale (Float)

    78 |

    Scaling factor for the rendered bitmaps. Default is 1.0. 79 |

  2. 80 | 81 |
  3. 82 |

    autoplay (Boolean)

    83 |

    If true, the animation will start immediately after all frames are ready. Default is true.

    84 |
  4. 85 | 86 |
  5. 87 |

    loop (Boolean)

    88 |

    If true, the animation will start again over and over and over. Default is true.

    89 |
  6. 90 | 91 |
  7. 92 |

    speed (String or Number)

    93 |

    The animation speed. Strings like "69fps", "200ms" or "1s" are totally cool. Numbers will be interpreted as milliseconds. Default is "15fps".

    94 |
  8. 95 | 96 |
  9. 97 |

    sprite (Dictionary)

    98 |

    Include a value for url with the location of your sprite image, the direction of the sprite as "x" or "y", and the count of frames. See the code for Donkey Kong above and the sprite image here.

    99 |
  10. 100 | 101 |
  11. 102 |

    images (Array)

    103 |

    Instead of sprite you can specify an URL for each frame.

    104 |
  12. 105 | 106 |
  13. 107 |

    onAnimation (Function)

    108 |

    A callback run every time a frame is animated. Handy, for example, when is needed to pause at a certain frame on the middle of the animation. The frame index is also passed to the function.

    109 |
  14. 110 |
111 |
112 | 113 |
114 |

Methods

115 |
    116 |
  1. 117 |

    drawWithTarget (DOMElement target)

    118 |

    Draws inside any element. A <canvas> element will be put inside the target.

    119 |
  2. 120 | 121 |
  3. 122 |

    drawWithCanvas (DOMElement canvas)

    123 |

    Draws directly to a <canvas> element on the DOM.

    124 |
  4. 125 | 126 |
  5. 127 |

    drawWithHandler (Function handler)

    128 |

    Advanced! Use this in the very special case you need to do custom drawing. For example, drawing multiple sprites on a single canvas. The animation is handled for you.

    129 | 130 |
    
    131 | myFatPixelsObject.drawWithHandler(function(fatFrame, idx){
    132 | 	// Do your custom drawing.
    133 | });
    134 | 					
    135 |

    See the source code for reference on the FatFrame object.

    136 |
  6. 137 |
138 |
139 | 140 |
141 |

Playback and frames

142 |
    143 |
  1. 144 |

    setAnimating (Boolean animating)

    145 |

    Resumes or pauses the animation. Access the property with .isAnimating.

    146 |
  2. 147 | 148 |
  3. 149 |

    setFrame (Integer index)

    150 |

    Sets the current frame. Access the property with .frame.

    151 |
  4. 152 | 153 |
  5. 154 |

    play (), pause () and stop ()

    155 |

    To quickly use instead of setAnimating.

    156 |
  6. 157 |
158 |
159 | 160 |
161 |

jQuery support

162 |
    163 |
  1. 164 |

    jQuery is supported but not required. A FatPixels object is returned (breaking the chain, sorry) and the drawing method is called on the matched elements for you.

    165 |
    
    166 | $('figure.huge').FatPixels({
    167 | 	scale  : 5,
    168 | 	images : [
    169 | 		'Marco-1.png',
    170 | 		'Marco-2.png',
    171 | 		'Marco-3.png'
    172 | 	]
    173 | });
    174 |
  2. 175 |
176 |
177 | 178 |
179 |

With love by Matías Martínez.

180 |

Donkey Kong Country by © Nintendo.

181 |
182 | 183 | 184 | -------------------------------------------------------------------------------- /fatpixels.js: -------------------------------------------------------------------------------- 1 | (function(window, document, undefined){ 2 | 3 | /* 4 | * Fills in default values. 5 | */ 6 | 7 | function merge(obj) { 8 | for (var i=1; i < arguments.length; i++) { 9 | var def = arguments[i] 10 | for (var n in def) 11 | if (obj[n] === undefined) obj[n] = def[n] 12 | } 13 | return obj 14 | } 15 | 16 | /* 17 | * Checks if a string has a suffix. 18 | */ 19 | function suffix(str, suffix) { 20 | return str.indexOf(suffix, str.length - suffix.length) !== -1; 21 | } 22 | 23 | /* 24 | * Gets an image from an URL. 25 | */ 26 | 27 | function get(URL, onCompletion) { 28 | var img = new Image(); 29 | if (onCompletion) 30 | { 31 | img.onload = function() { 32 | onCompletion(img, URL); 33 | }; 34 | img.onerror = function() { 35 | onCompletion(false); 36 | }; 37 | img.onabort = function() { 38 | onCompletion(false); 39 | }; 40 | } 41 | img.src = URL; 42 | } 43 | 44 | /* 45 | * requestAnimationFrame() by Paul Irish. 46 | */ 47 | var requestAnimFrame = (function() { 48 | return window.requestAnimationFrame || 49 | window.webkitRequestAnimationFrame || 50 | window.mozRequestAnimationFrame || 51 | window.oRequestAnimationFrame || 52 | window.msRequestAnimationFrame || 53 | function(/* function */ callback, /* DOMElement */ element){ 54 | window.setTimeout(callback, 1000 / 60); 55 | }; 56 | })(); 57 | 58 | /* 59 | * Freaking setInterval having a baby with requestAnimationFrame(). 60 | */ 61 | function requestInterval(fn, delay) { 62 | if( !window.requestAnimationFrame && 63 | !window.webkitRequestAnimationFrame && 64 | !(window.mozRequestAnimationFrame && window.mozCancelRequestAnimationFrame) && 65 | !window.oRequestAnimationFrame && 66 | !window.msRequestAnimationFrame) 67 | return window.setInterval(fn, delay); 68 | 69 | var start = new Date().getTime(), 70 | handle = new Object(); 71 | 72 | function loop() { 73 | var current = new Date().getTime(), 74 | delta = current - start; 75 | 76 | if(delta >= delay) { 77 | fn.call(); 78 | start = new Date().getTime(); 79 | } 80 | 81 | handle.value = requestAnimFrame(loop); 82 | }; 83 | 84 | handle.value = requestAnimFrame(loop); 85 | return handle; 86 | } 87 | 88 | /* 89 | * clearInterval() for a requestInterval(). 90 | */ 91 | function clearRequestInterval(handle) { 92 | window.cancelAnimationFrame ? window.cancelAnimationFrame(handle.value) : 93 | window.webkitCancelAnimationFrame ? window.webkitCancelAnimationFrame(handle.value) : 94 | window.webkitCancelRequestAnimationFrame ? window.webkitCancelRequestAnimationFrame(handle.value) : 95 | window.mozCancelRequestAnimationFrame ? window.mozCancelRequestAnimationFrame(handle.value) : 96 | window.oCancelRequestAnimationFrame ? window.oCancelRequestAnimationFrame(handle.value) : 97 | window.msCancelRequestAnimationFrame ? window.msCancelRequestAnimationFrame(handle.value) : 98 | clearInterval(handle); 99 | }; 100 | 101 | /* 102 | * 103 | * The default options. 104 | * 105 | */ 106 | 107 | var defaults = { 108 | scale : 1.0, // (Float) Scaling factor for rendering a pixel. 109 | autoplay : true, // (BOOL) Should start playing immediately. 110 | loop : true, // (BOOL) Repeats over and over or just once after -play. 111 | speed : "15fps", // (String or Float) - Strings like "69fps", "200ms" or "1s". 112 | // - Floats will work as milliseconds. 113 | }; 114 | 115 | /* 116 | * 117 | * FatPixels Constructor. 118 | * 119 | */ 120 | var FatPixels = function(o) { 121 | if (!this.drawWithTarget) return new FatPixels(o) 122 | this.options = merge(o || {}, {}, defaults); 123 | 124 | // 125 | // Kind of private properties: 126 | // 127 | 128 | // (Array) User-provided bitmaps. 129 | this.bitmaps = null; 130 | 131 | // (Size) The size of the bitmaps. 132 | this.bitmapSize = {width : 0, height : 0}; 133 | 134 | // (Array) An array of FatFrame objects for each frame. 135 | this.frames = null; 136 | 137 | // (Integer) The initial frame to start animating. 138 | this.frame = 0; 139 | 140 | // (BOOL) Uses the sprite mode. 141 | this.useSprite = this.options.sprite != undefined; 142 | 143 | // (BOOL) Uses the old image array mode. 144 | this.useArrayOfImages = this.options.images != undefined; 145 | }; 146 | 147 | /* 148 | * 149 | * Frame Constructor. For the super weird case of drawing and caching 150 | * custom frames. Used internally, ignore it. 151 | * Parameters: 152 | - w, h. (Floats) Width and height for the frame buffer. 153 | * 154 | */ 155 | var FatFrame = function(w, h) { 156 | // Why have a stored canvas for each frame? Because it's super fast 157 | // to draw from canvas to canvas. Waaaay faster than drawing images. 158 | this.buffer = document.createElement("canvas"); 159 | this.buffer.width = w; 160 | this.buffer.height = h; 161 | }; 162 | 163 | FatFrame.prototype.drawInBuffer = function(canvas){ 164 | this.buffer.getContext("2d").drawImage(canvas, 0, 0); // Canvas to buffer. 165 | }; 166 | 167 | FatFrame.prototype.drawBufferInContext = function(context){ 168 | context.drawImage(this.buffer, 0, 0); // Buffer to canvas 2D context. 169 | }; 170 | 171 | /* 172 | * 173 | * - renderFrames. Renders each frame. 174 | * Parameters: 175 | - onCompletion. (Function) A function called after frames are ready. 176 | - ignoreCache. (BOOL) Pass true to force bitmap downloading. 177 | * 178 | */ 179 | 180 | FatPixels.prototype.renderFrames = function(onCompletion, ignoreCache) { 181 | 182 | // Bitmaps are the user provided images at original scale (1x). 183 | // If not present, they get downloaded. 184 | var bitmaps = this.bitmaps; 185 | var bitmapSize = this.bitmapSize; 186 | 187 | if (!bitmaps || ignoreCache) 188 | { 189 | var _this = this; 190 | 191 | return _this.getBitmaps(function(_bitmaps, _bitmapSize){ 192 | _this.bitmaps = _bitmaps; 193 | _this.bitmapSize = _bitmapSize; 194 | _this.renderFrames(onCompletion, false); // If cache already ignored, keep going. 195 | }); 196 | } 197 | 198 | // Frames are FatPixels scaled versions of the user bitmaps. 199 | // They're drawn once (or when the scale changes), and used 200 | // directly by the animation functions. 201 | var frames = []; 202 | 203 | var scale = this.options.scale, 204 | w = bitmapSize.width * scale, 205 | h = bitmapSize.height * scale; 206 | 207 | var canvas = document.createElement("canvas"); 208 | canvas.width = w; 209 | canvas.height = h; 210 | 211 | var ctx = canvas.getContext("2d"); 212 | 213 | for (var i=0; i will be put inside. 350 | * Parameters: 351 | - target. (DOMElement) Easy as any DOM element. 352 | * 353 | */ 354 | 355 | FatPixels.prototype.drawWithTarget = function(target) { 356 | var canvas = document.createElement("canvas"); 357 | 358 | target.appendChild(canvas); 359 | 360 | this.drawWithCanvas(canvas); 361 | }; 362 | 363 | /* 364 | * 365 | * - drawWithCanvas: Draws directly to a element. 366 | * Parameters: 367 | - canvas. (DOMElement) A DOM element. 368 | * 369 | */ 370 | 371 | FatPixels.prototype.drawWithCanvas = function(canvas) { 372 | var ctx = canvas.getContext("2d"); 373 | var w, h, needsSizing = true; 374 | 375 | this.drawWithHandler(function(frame, idx){ 376 | if (needsSizing) 377 | { 378 | w = frame.buffer.width; 379 | h = frame.buffer.height; 380 | 381 | canvas.width = w; 382 | canvas.height = h; 383 | 384 | needsSizing = false; 385 | } 386 | 387 | ctx.clearRect(0, 0, w, h); 388 | 389 | frame.drawBufferInContext(ctx); 390 | }); 391 | }; 392 | 393 | /* 394 | * 395 | * - drawWithHandler: Use this to do custom drawing. 396 | Useful when drawing multiple sprites to the same 397 | canvas. 398 | * Parameters: 399 | - handler. A callback function called every time a frame needs to 400 | be displayed. See -drawWithCanvas implementation for an 401 | example. 402 | 403 | - frame: (FatFrame) The frame. 404 | - idx: (Integer) Index of the frame. 405 | 406 | The handler is stored as .drawingHandler. 407 | * 408 | */ 409 | 410 | FatPixels.prototype.drawWithHandler = function(handler) { 411 | var _this = this; 412 | 413 | _this.drawingHandler = handler; 414 | 415 | _this.renderFrames(function(){ 416 | 417 | if (_this.options.autoplay) 418 | _this.isAnimating = (_this.frames.length > 1); 419 | 420 | _this.needsDisplay(); 421 | }); 422 | }; 423 | 424 | FatPixels.prototype.drawingHandler = function(frame, idx){ 425 | // 426 | // Set using -drawWithHandler. 427 | // 428 | console.warn("FatPixels: Empty implementation for -drawingHandler."); 429 | }; 430 | 431 | /* 432 | * 433 | * - needsDisplay: Manages animation and the drawing of frames. 434 | * 435 | */ 436 | FatPixels.prototype.needsDisplay = function() { 437 | var _this = this; 438 | 439 | var _isAnimating = _this.isAnimating, 440 | _frames = _this.frames, 441 | _idx = _this.frame; 442 | 443 | var _onAnimation = _this.options.onAnimation; 444 | 445 | var i = _this.options.speed; 446 | 447 | if (typeof i == "string" || i instanceof String) 448 | { 449 | if (suffix(i, "fps")) 450 | { 451 | i = 1000 / parseFloat(i); 452 | } 453 | else if (suffix(i, "ms")) 454 | { 455 | i = parseFloat(i); 456 | } 457 | else if (suffix(i, "s")) 458 | { 459 | i = parseFloat(i) * 1000; 460 | } 461 | } 462 | 463 | if (!_this.drawingInterval) 464 | { 465 | _this.drawingInterval = requestInterval(function(){ 466 | _idx++; 467 | 468 | if (_idx == _frames.length) 469 | { 470 | _idx = 0; 471 | 472 | if (_this.options.loop == false) 473 | setTimeout(function(){ 474 | _this.setAnimating(false); 475 | }, 1); 476 | } 477 | 478 | _this.drawingHandler(_frames[_idx], _idx); 479 | 480 | if (_onAnimation) 481 | _onAnimation(_idx); 482 | 483 | }, i); 484 | } 485 | 486 | if (!_isAnimating) 487 | { 488 | clearRequestInterval(_this.drawingInterval); 489 | 490 | delete _this.drawingInterval; 491 | } 492 | 493 | _this.drawingHandler(_frames[_idx], _idx); 494 | }; 495 | 496 | /* 497 | * 498 | * - setAnimating: Pauses or resumes the animation. 499 | * Parameters: 500 | - animating. True or false for play/pause. 501 | 502 | * - (BOOL)isAnimating : Returns true or false if animating. 503 | * 504 | */ 505 | 506 | FatPixels.prototype.setAnimating = function(animating) { 507 | if (animating != this.isAnimating) 508 | { 509 | this.isAnimating = animating; 510 | this.needsDisplay(); 511 | } 512 | }; 513 | 514 | /* 515 | * 516 | * - setFrame: Sets the current frame. 517 | * Parameters: 518 | - idx. An index for the desired frame. 519 | 520 | * - (Integer)frame: Returns the current displayed frame index. 521 | * 522 | */ 523 | 524 | FatPixels.prototype.setFrame = function(idx) { 525 | if (idx != this.frame && idx < this.frames.length) 526 | { 527 | this.frame = idx; 528 | this.needsDisplay(); 529 | } 530 | }; 531 | 532 | /* 533 | * 534 | * Quickies for animation. 535 | * 536 | */ 537 | 538 | FatPixels.prototype.pause = function() { 539 | this.setAnimating(false); 540 | }; 541 | 542 | FatPixels.prototype.play = function() { 543 | this.setAnimating(true); 544 | }; 545 | 546 | FatPixels.prototype.stop = function() { 547 | this.setAnimating(false); 548 | this.setFrame(0); 549 | }; 550 | 551 | /* 552 | * 553 | * jQuery Plugin. 554 | * 555 | * Works when jQuery is available. The FatPixels object 556 | * can be found using data() on a jQuery object. 557 | * 558 | var myFatPixelsObject = $("figure.example").FatPixels({...}); 559 | 560 | myFatPixelsObject.pause(); 561 | myFatPixelsObject.setFrame(4); 562 | myFatPixelsObject.play(); 563 | * 564 | */ 565 | 566 | if (typeof jQuery == 'function') 567 | { 568 | (function($){ 569 | 570 | $.fn.FatPixels = function(opts) { 571 | this.each(function() { 572 | var $this = $(this), 573 | data = $this.data(); 574 | 575 | if (data.pixels) 576 | { 577 | data.pixels.remove(); 578 | delete data.pixels; 579 | } 580 | 581 | if (opts !== false) 582 | { 583 | data.pixels = new FatPixels(opts); 584 | 585 | if (this.tagName.toLowerCase() === "canvas") 586 | data.pixels.drawWithCanvas(this); 587 | else 588 | data.pixels.drawWithTarget(this); 589 | 590 | } 591 | 592 | return data.pixels; 593 | }); 594 | 595 | return this; 596 | }; 597 | 598 | })(jQuery); 599 | } 600 | 601 | /* 602 | * 603 | * Define the FatPixels public constructors on the global scope. 604 | * 605 | */ 606 | 607 | if (typeof define == 'function' && define.amd) 608 | { 609 | define(function() { return FatPixels }); 610 | define(function() { return FatFrame }); 611 | } 612 | else 613 | { 614 | window.FatPixels = FatPixels; 615 | window.FatFrame = FatFrame; 616 | } 617 | 618 | })(window, document); --------------------------------------------------------------------------------