(function(global){


    // ###CanvasHolder 
    // **constructor** receives as arguments 
    //
    // * `elementId` id of the dom element
    // * `contextId` default `2d`, or `webgl`
    function CanvasHolder(elementId,contextId){
        this.dom = document.getElementById(elementId);
        this.context =  this.dom.getContext(contextId || '2d');
        this.setSize();
    }


    // 
    // **Set size** of canvas element depending on window dimensions
    CanvasHolder.prototype.setSize = function() {
        this.width  = this.dom.width  = window.innerWidth;
        this.height = this.dom.height = window.innerHeight;    
    };


    // **recalculate** canvas element size if window dimensions is changed after last call
    CanvasHolder.prototype.recalculate = function() {
        if (this.width  != window.innerWidth || this.height != window.innerHeight) {
            this.setSize();
        }
    };


    // ##FrAnim
    // **constructor** resives as arguments 
    //
    // * `elementId` id of the dom element
    // * `contextId` default `2d`, or `webgl`
    function FrAnim(canvaseId,contextId){
        this.canvas = new CanvasHolder(canvaseId,contextId);
        this.requestId = 0;
        this.func = {
            init:function () {
                throw "init function isn't set";
            },
            draw:function () {
                throw "draw function isn't set";
            },
            animate:function () {
                throw "animate function isn't set";
            }
        };
    }


    //###set
    //**set** functions needed for animation
    FrAnim.prototype.set = function(functions) {
        this.func.setup = functions.setup;
        this.func.update = functions.update;
        this.func.draw = functions.draw;
        return this;
    };
 

    //###start
    //**start** animation loop 
    FrAnim.prototype.start = function(opt) {
        this.isRunning = true;
        var updateThis;
        var drawThis;
        var self = this;
        var ctx = this.canvas.context;
        //**run** `setup` once and save its returned `object` in `updateThis` variable
        updateThis = this.func.setup(ctx);
        updateThis = (typeof updateThis != 'object') ? {} :updateThis;

        //**save** `requestId` for stopping animation loop if needed
        this.requestId = window.requestAnimationFrame(function callback(time) {

            // **call** `recalculate` in case window size has changed
            if(opt.autoResize) self.canvas.recalculate();

            //**call** `update` function on `updateThis` and pass `time` as argument.
            //if it returns `object` it will be used for `draw` function otherwise 
            //`draw` well be called on `updateThis`
            var temp = self.func.update.call(updateThis,time);
            drawThis = (typeof temp != 'object') ? updateThis :temp;
            
            //**call** draw function `drawThis` and pass **Canvas Context** as argument.
            //it it returns `object` call `update` on in in next frame
            temp = self.func.draw.call(drawThis,ctx);
            updateThis = (typeof temp != 'object') ? updateThis : temp;

            //**if** `isRunning` is `false` it means that `stop` is called so we should  call `cancelAnimationFrame` and reset requestId
            if (self.isRunning === false) {
                window.cancelAnimationFrame(self.requestId);
                self.requestId = 0;
            }else{
                window.requestAnimationFrame(callback);
            }
        });
        
        return this;
    }; 


    //###Stop
    //**Stop** animation loop
    FrAnim.prototype.stop = function() {        
        this.isRunning = false;
        return this;
    };


    //###Save to global
    //**Get** script element from which it is loaded.
    var scripts = document.getElementsByTagName("script");
    var currentScript = scripts[ scripts.length - 1 ];
    
    //**Make** `FrAnim` axsasible from global scope with name which is written in `data-var` attribute
    var name = currentScript.dataset.var || 'FrAnim';
    global[name] = FrAnim;
    
    //**Get** name of file which is written in `data-var` attribute and load it
    var file = currentScript.dataset.file;
    if (file) {
        var script = document.createElement("script");
        script.src = file+'.js';
        var head = document.getElementsByTagName("head")[0] || document.documentElement;
        head.appendChild(script);
    }

})(this);
@@ -1332,20 +1332,22 @@
         
-draw
+update
 :functio
@@ -1376,20 +1376,22 @@
  throw %22
-draw
+update
  functio
@@ -1431,23 +1431,20 @@
         
-animate
+draw
 :functio
@@ -1477,15 +1477,12 @@
 ow %22
-animate
+draw
  fun
@@ -1884,19 +1884,26 @@
 unction(
-opt
+userConfig
 ) %7B%0A    
@@ -1910,30 +1910,81 @@
     
-this.isRunning = true;
+var config = %7B%0A            autoResize : true,%0A            setupThis  : %7B%7D
 %0A   
@@ -1988,19 +1988,19 @@
         
-var
+%7D, 
  updateT
@@ -1998,25 +1998,26 @@
   updateThis
-;
+, 
 %0A        var
@@ -2013,19 +2013,19 @@
         
-var
+   
  drawThi
@@ -2025,17 +2025,18 @@
 drawThis
-;
+, 
 %0A       
@@ -2036,19 +2036,19 @@
         
-var
+   
  self = 
@@ -2047,25 +2047,26 @@
  self = this
-;
+, 
 %0A        var
@@ -2062,19 +2062,19 @@
         
-var
+   
  ctx = t
@@ -2110,25 +2110,324 @@
 /**r
-un** %60setup%60 once
+ewrite** user configuration to default config if type matches%0A        if (userConfig)%0A            for(var key in config)%0A                if(typeof userConfig%5Bkey%5D == typeof config%5Bkey%5D)%0A                    config%5Bkey%5D = userConfig%5Bkey%5D;%0A%0A%0A        this.isRunning = true;%0A        //**call** %60setup%60 once on %60setupThis%60
  and
@@ -2515,17 +2515,39 @@
 nc.setup
-(
+.call(config.setupThis,
 ctx);%0A  
@@ -2603,12 +2603,27 @@
 ) ? 
-%7B%7D
+config.setupThis
  :
+ 
 upda
@@ -2824,38 +2824,28 @@
 e%60 i
-n case window size has changed
+f %60autoResize%60 is on
 %0A   
@@ -2860,11 +2860,14 @@
  if(
-opt
+config
 .aut
@@ -3307,16 +3307,19 @@
 unction 
+on 
 %60drawThi

use defolt config and extend it with users one