 
 
   drawToBuffer: -> 
-    @buffer ?= document.createElement 'canvas'
-    @buff_ctx ?= @buffer.getContext '2d'          
-    @buffer.width = (@resizing_canvas?.width or @refs.canvas.width) * DEVICE_PIXEL_RATIO
-    @buffer.height = (@resizing_canvas?.height or @refs.canvas.height) * DEVICE_PIXEL_RATIO
 
     histocache = @getAvatarPositions()?.positions or {}
-    for key, __ of histocache
-      sprite = @sprites[key]
-      updating_opacity = sprite.target_opacity != sprite.from_opacity || sprite.opacity != 1
-      if updating_opacity
-        @buff_ctx.save()
-        @buff_ctx.globalAlpha = sprite.opacity
-      @buff_ctx.drawImage sprite.img, sprite.x * DEVICE_PIXEL_RATIO, sprite.y * DEVICE_PIXEL_RATIO, sprite.width * DEVICE_PIXEL_RATIO, sprite.height * DEVICE_PIXEL_RATIO
-      
-      if updating_opacity
-        @buff_ctx.restore()
+
+    @skip_frame = false 
+    if SKIP_FRAMES
+      skippable = 0 
+      tot = 0
+      opacity_updated = false 
+      for key, __ of histocache
+        sprite = @sprites[key]
+        updating_opacity = sprite.target_opacity != sprite.from_opacity || sprite.opacity != 1
+
+        if updating_opacity
+          opacity_updated = true
+          break
+
+        if (sprite.last_render_x && Math.abs(sprite.x - sprite.last_render_x) < SKIP_FRAMES) &&
+           (sprite.last_render_y && Math.abs(sprite.y - sprite.last_render_y) < SKIP_FRAMES) &&
+           (sprite.last_render_size && Math.abs(sprite.width - sprite.last_render_size) < SKIP_FRAMES)
+          skippable += 1
+        tot += 1
+
+      @skip_frame = !opacity_updated && skippable / tot > .5
+
+
+    if !@skip_frame
+
+      @buffer ?= document.createElement 'canvas'
+      @buff_ctx ?= @buffer.getContext '2d'          
+      @buffer.width = (@resizing_canvas?.width or @refs.canvas.width) * DEVICE_PIXEL_RATIO
+      @buffer.height = (@resizing_canvas?.height or @refs.canvas.height) * DEVICE_PIXEL_RATIO
+
+      for key, __ of histocache
+        sprite = @sprites[key]
+        updating_opacity = sprite.target_opacity != sprite.from_opacity || sprite.opacity != 1
+        if updating_opacity
+          @buff_ctx.save()
+          @buff_ctx.globalAlpha = sprite.opacity
+        @buff_ctx.drawImage sprite.img, sprite.x * DEVICE_PIXEL_RATIO, sprite.y * DEVICE_PIXEL_RATIO, sprite.width * DEVICE_PIXEL_RATIO, sprite.height * DEVICE_PIXEL_RATIO
+        
+        if updating_opacity 
+          @buff_ctx.restore()
+
+        sprite.last_render_x = sprite.x
+        sprite.last_render_y = sprite.y
+        sprite.last_render_size = sprite.width
 
     @tick()
 


    requestAnimationFrame =>

      if @buffer? 
        @dirty_canvas = false        
        @renderScene()


          return if ani != @current_ani
          for key, __ of @updates_needed
            sprite = @sprites[key]

            sprite.x = sprite.from_x + (sprite.target_x - sprite.from_x) * val
            sprite.y = sprite.from_y + (sprite.target_y - sprite.from_y) * val
            sprite.width = sprite.height = sprite.from_size + (sprite.target_size - sprite.from_size) * val
            sprite.opacity = sprite.from_opacity + (sprite.target_opacity - sprite.from_opacity) * val
        
        onComplete: do (ani) => =>
          return if ani != @current_ani
          for key, __ of @updates_needed
