                     return
         @render_scene(true)
 
+    animate: (opts={}) =>
+        opts = defaults opts,
+            fps  : undefined
+            stop : false
+            mouseover : true
+        #console.log('anim', @opts.element.length, @opts.element.is(":visible"))
+
+        if not @opts.element.is(":visible")
+            # check again after a delay
+            setTimeout((() => @animate(opts)), 1500)
+            return
+
+        if opts.stop
+            @_stop_animating = true
+            # so next time around will start
+            return
+        if @_stop_animating
+            @_stop_animating = false
+            return
+        f = () =>
+            requestAnimationFrame((()=>@animate(opts)))
+        if opts.fps? and opts.fps
+            setTimeout(f , 1000/opts.fps)
+        else
+            f()
+        if opts.mouseover and (not document.hasFocus() or not @opts.element.is(":hover"))
+            return
+        @render_scene()
+
+    render_scene: (force=false) =>
+        #console.log('render', @opts.element.length)
+        if @controls?
+            @controls?.update()
+        else
+            if @opts.trackball
+                @set_trackball_controls()
+
+        pos = @camera.position
+        if not @_last_pos?
+            new_pos = true
+            @_last_pos = pos.clone()
+        else if @_last_pos.distanceToSquared(pos) > .05
+            new_pos = true
+            @_last_pos.copy(pos)
+        else
+            new_pos = false
+
+        if not new_pos and not force
+            return
+
+        # rescale all text in scene
+        if (new_pos or force) and @_center?
+            s = @camera.position.distanceTo(@_center) / 3
+            if @_text?
+                for sprite in @_text
+                    sprite.scale.set(s,s,s)
+            if @_frame_labels?
+                for sprite in @_frame_labels
+                    sprite.scale.set(s,s,s)
+
+        @renderer.render(@scene, @camera)
+
 $.fn.salvus_threejs = (opts={}) ->
     @each () ->
         elt = $(this)


        @scene.add(particle)

    # always call this after adding things to the scene to make sure track
    # controls are sorted out, etc.   Set draw:false, if you don't want to
    # actually *see* a frame.

            @controls.target = @_center
        @render_scene(true)

    add_3dgraphics_obj: (opts) =>
        opts = defaults opts,
            obj       : required
            wireframe : false

        for o in opts.obj
            switch o.type
