# Pause and Resume an Animation

**URL:** <https://forums.sketchup.com/t/pause-and-resume-an-animation/232335>\
**Category:** Ruby API\
**Created:** [June 10, 2023, 4:59pm UTC](https://forums.sketchup.com/t/pause-and-resume-an-animation/232335 "2023-06-10T16:59:10Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![sguthery](https://avatars.discourse-cdn.com/v4/letter/s/77aa72/32.png) [@sguthery](https://forums.sketchup.com/u/sguthery)\
**Post date:** [June 10, 2023, 4:59pm UTC](https://forums.sketchup.com/t/pause-and-resume-an-animation/232335/1 "2023-06-10T16:59:10Z")

</div>

If I pause an animation by simply returning true from nextFrame but then later resuming the animation from where it was when it was paused. I seem to have to click the view to get the animation to in fact resume. When I click the view window, the blue select box around the model flashes and the animation picks up again. Why the necessity to click the view window? Code below.

[RotateGear.rb](https://forums.sketchup.com/uploads/short-url/uVOSD5y03dy745OqocW2mNLd8sP.rb) (1.1 KB)

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [June 10, 2023, 8:13pm UTC](https://forums.sketchup.com/t/pause-and-resume-an-animation/232335/2 "2023-06-10T20:13:13Z")

</div>

Your profile states you are on SketchUp 2022. Is this still true?  
I ask be cause the 2023 release uses a different GUI framework that may have issues.

I cannot test you code, because you did not provide a test model with the definition and instances.  
I suspect the weirdness is a result of your misuse of the selection object.

* * *

A quick look at your example code …

**(1)** Ruby uses 2 space indentation.

**(2)** All the `@@vars` in your class should be `@vars` (ie, instance variables, as that is how you are using them.) In addition their initialization should be moved into an `initialize` instance method which is called automatically by a class’ `new` constructor method after the object has been created. Any variables passed to `new` are passed on to `initialize`.

**(3)** You have the statement `mod = Sketchup.active_model`, but then repeatedly call `Sketchup.active_model`.  
Likely, you should assign it to `@model` in `initialize` and use that instance variable throughout.

**(4)**  **Is a biggie**. There is **no need whatsoever** to stuff objects into the selection set in order to iterate them. The [`Sketchup::ComponentDefinition#instances`](https://ruby.sketchup.com/Sketchup/ComponentDefinition.html) method returns an [`Array`](https://ruby-doc.org/core-2.7.2/Array.html) that has an `#each` iterator (among others defined, as well as all those mixed in from module [`Enumerable`](https://ruby-doc.org/core-2.7.2/Enumerable.html).)

**(5)** I would suggest you calculate what you can **before** the animation loop starts. Probably this means within the `initialize` method. It is **very inefficient** to be getting the gear definition’s instances collection anew and reiterating it and recreating each instance’s rotational transformation again and again in every frame.  
Ie, gears are pressed onto shafts and normally do not move. Their rotational transform will not change, … they will rotate by the same amount, about the same axis point, each frame.

**(6)** In the `rp = Geom::Point3d.new(ent.bounds.center)` statement, it is frivolous to construct a point obejct. [`BoundingBox#center`](https://ruby.sketchup.com/Geom/BoundingBox.html#center-instance_method) already returns a `Geom::Point3d` object.

**(7)** A toggle command usually reverses a Boolean variable:

```ruby
def toggle_something
  @something = !@something
end

```

Meaning, in Ruby it is kind of weird to use `0` and `1` for Boolean state.

* * *

I know this is a little test code, but we encourage proper coding here for a shared environment. (It seems like the various AI bots search the web for examples and think bad code are gospel because it posted on the web and parrot it as answers.)

**(a)**  **All** code for SketchUp should be within a unique namespace module. It also is best to separate each of your extensions from others within the namespace using submodules.

**(b)** Local variables should not be created at the top level within the ObjectSpace.

**(c)** Only Ruby classes and select API classes should ever be defined in the top level ObjectSpace (because they become global.)

**(d)** Code that creates UI objects (commands, menu items, toolbars, buttons) should be wrapped within a load guard so that they are only created **once**.

**See next post for an example …**

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [June 10, 2023, 8:15pm UTC](https://forums.sketchup.com/t/pause-and-resume-an-animation/232335/3 "2023-06-10T20:15:29Z")

</div>

[GearSpinner.rb](https://forums.sketchup.com/uploads/short-url/7Ai0wWesZNLLiGifFnqQqKHV47h.rb) (2.9 KB)

(Untested, except to be sure it loaded without syntax errors.)

For those that want to just look without downloading …

> **( CLICK HERE TO EXPAND )**
>
> ```ruby
> # encoding: UTF-8
> 
> module Sguthery
> module GearSpinner
> 
> class RotateGear
> 
> VERSION ||= '0.2.3'
> 
> @@animation = nil unless defined?(@@animation)
> 
> ### CLASS METHODS
> #
> 
> def self.instance
> @@animation
> end
> 
> def self.pause
> @@animation.interrupt if @@animation
> end
> 
> def self.resume
> @@animation.interrupt(false) if @@animation
> end
> 
> def self.start
> model = Sketchup.active_model
> model.active_view.animation = nil if @@animation
> @@animation = self.new(model) # initialize called with model
> model.active_view.animation = @@animation
> end
> 
> def self.stop
> if @@animation
> id = UI.start_timer(1.0, false) {
> UI.stop_timer(id)
> @@animation = nil
> }
> @@animation.cease
> end
> false
> end
> 
> ### PRIVATE INSTANCE METHODS
> #
> private
> 
> def initialize(model)
> @model = Sketchup.active_model
> @rd = 0
> @rv = Geom::Vector3d.new(0,0,1)
> @pause = false
> instances = @model.definitions['Gear1'].instances
> # Create a Hash with instance keys and their transform values using the
> # Hash::[] class constructor method that takes: [[key1, value1], ... ]
> @transforms = Hash[
> # Map instances array to a new array of [instance, transform] subarrays:
> instances.map do |inst|
> [inst, Geom::Transformation.rotation(inst.bounds.center, @rv, 0.0175)]
> end
> ]
> end
> 
> ### PUBLIC INSTANCE METHODS
> #
> public
> 
> def cease
> @model.active_view.animation = nil
> puts("Stopped #{@pause} at #{@rd}")
> false
> end
> 
> def interrupt(parameter = true)
> if parameter
> @pause = true
> puts("Paused #{@pause} at #{@rd}")
> else
> @pause = false
> puts("Resumed #{@pause} at #{@rd}")
> end
> end
> 
> def nextFrame(view)
> if @pause
> sleep 1.0
> return true
> end
> puts("frame")
> 
> @transforms.each do |inst, trans|
> inst.transform!(trans)
> end
> view.show_frame
> 
> sleep 0.2
> if @rd < 100
> @rd = @rd + 0.5
> return true
> else
> @rd = 0
> self.class.stop # returns false
> end
> end # nextFrame()
> 
> end # class
> 
> if !defined?(@loaded)
> 
> submenu = UI.menu("Plugins").add_submenu("Gear")
> 
> submenu.add_item("Start") { RotateGear.start }
> 
> submenu.add_item("Pause") { RotateGear.pause }
> 
> submenu.add_item("Resume") { RotateGear.resume }
> 
> submenu.add_item("Stop") { RotateGear.stop }
> 
> @loaded = true
> end
> 
> end # submodule
> end # module Sguthery
> 
> ```

---

<div class="post-metadata">

**Author:** ![sguthery](https://avatars.discourse-cdn.com/v4/letter/s/77aa72/32.png) [@sguthery](https://forums.sketchup.com/u/sguthery)\
**Post date:** [June 10, 2023, 11:00pm UTC](https://forums.sketchup.com/t/pause-and-resume-an-animation/232335/4 "2023-06-10T23:00:19Z")

</div>

Thanks much for your comments, Dan. Greatly appreciated. Yes, I’m on 2022, which is what Trimble sold me about a week ago (just before the price increase!).

I swizzled your GearSpinner code a little differently …  
gears = RotateGear.new  
@@animation = gears  
submenu.add\_item(“Start”) { Sketchup.active\_model.active\_view.animation = gears }  
but the gear goes round and round just fine.

You used a couple of methods on @@animation that I don’t find in the API docs at [Module: Sketchup — SketchUp Ruby API Documentation](https://ruby.sketchup.com/Sketchup), namely, cease and interrupt. Maybe these are in 2023 or perhaps there are updated docs somewhere?

Does a year’s worth of Pro entitle one to a free update from 2022 to 2023?

Cheers, Scott

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [June 11, 2023, 12:36am UTC](https://forums.sketchup.com/t/pause-and-resume-an-animation/232335/5 "2023-06-11T00:36:41Z")

</div>

> [@sguthery](#):
>
> You used a couple of methods on @@animation that I don’t find in the API docs at [Module: Sketchup — SketchUp Ruby API Documentation](https://ruby.sketchup.com/Sketchup), namely, cease and interrupt. Maybe these are in 2023 or perhaps there are updated docs somewhere?

If you look again at the documentation for [`Animation`](https://ruby.sketchup.com/Sketchup/Animation.html), in the class **Overview** section, take notice of the box note with emboldened: “ **This class is abstract.** ” It continues and informs you that “…You can not sub-class this class because it is not defined by the API.”

So, it means that there is no actual `Sketchup::Animation` superclass. It is only shown within the [`Sketchup`](https://ruby.sketchup.com/Sketchup.html) module so the YARD documentation generator will document it, and because if it was shown as a global class, coders might think it was a core Ruby class.

Abstract classes do not have a superclass other than [`Object`](https://ruby-doc.org/core-2.7.2/Object.html) because they do not need to inherit special functionality, other than what basic functionality all classes in Ruby inherit. For the API, abstract classes need to define publicly accessible methods (some of which are optional) the SketchUp engine will poll for and call if defined.

From now on, take notice of API classes that are marked as **abstract**. All the SketchUp API observer classes are abstract since v2016.

* * *

Okay, so since an abstract class is **not** an API class (that you should **never** modify,) you are free to define extra methods within so as to make a well written and working class.

In the example, I had to choose instance method names other than `pause` and `stop` because those are the names of the optional callback methods the API would poll for. (They really should have been named like the API’s other callback methods … ie, `onPause` and `onStop`, but this was decided like 20 years ago.) So, this is why I named them `interrupt` and `cease`.

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [June 11, 2023, 12:50am UTC](https://forums.sketchup.com/t/pause-and-resume-an-animation/232335/6 "2023-06-11T00:50:42Z")

</div>

> **Off-Topic Re: Version and licensing ... ( click to expand ) ...**
>
> > [@sguthery](#):
> >
> > Yes, I’m on 2022, which is what Trimble sold me about a week ago (just before the price increase!).
> 
> ~~I haven’t heard of a price increase recently.~~ EDIT: Okay I see discuss that it’s going up in July.
> 
> Perhaps, they would prefer new users stay on 2022 until the next update to 2023.1 because of some current issues with 2023.0.2. One of them is that model files are going corrupt. Another is issues with the inspector dialogs being black out or not updating.
> 
> > [@sguthery](#):
> >
> > Does a year’s worth of Pro entitle one to a free update from 2022 to 2023?
> 
> It’s a subscription license, not a classic license for a single version. You can install 2023 at the same time, They install into separate program directories. You use the same subscription license.
> 
> However, the last one installed will be the default that double-clicking a SKP file will open into. If after installing 2023, you still want to open SKP files in 2022 when double-clicked, then you will need to rerun the 2022 installer and choose the Repair option.

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [June 11, 2023, 12:55am UTC](https://forums.sketchup.com/t/pause-and-resume-an-animation/232335/7 "2023-06-11T00:55:25Z")

</div>

> [@sguthery](#):
>
> I swizzled your GearSpinner code a little differently …
> 
> ```ruby
> gears = RotateGear.new
> @@animation = gears
> submenu.add_item(“Start”) { Sketchup.active_model.active_view.animation = gears }
> 
> ```
> 
> but the gear goes round and round just fine.

Why would you do this? It is all handled in the `RotateGear::start` class method.  
All the menu item block need do is call this class method.

---

<div class="post-metadata">

**Author:** ![sguthery](https://avatars.discourse-cdn.com/v4/letter/s/77aa72/32.png) [@sguthery](https://forums.sketchup.com/u/sguthery)\
**Post date:** [June 11, 2023, 9:58am UTC](https://forums.sketchup.com/t/pause-and-resume-an-animation/232335/8 "2023-06-11T09:58:46Z")

</div>

Dan:

Thanks again for your comments. They’re all informative and very useful.

But even with the code you kindly provided, I have to click the window or tap a key to get the animation running again after I pause it. In fact, just returning ‘true’ to nextFrame and doing nothing else stops the nextFrame loop altogether. A click or key tap will trigger one more call to nextFrame and then crickets.

However, if I call view.show\_frame before just returning true (even though there has been no change to the model) the regular calls to nextFrame continue. Having to refresh a display that hasn’t changed to get functionality that doesn’t depend on the display is a little counter-intuitive, but it does work around the problem.

Thanks again for your guidance.

Cheers, Scott

P.S. There might be a single-step debugging utility of this SketchUp property but running an animation to single-step a script is probably ill-advised.

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [June 11, 2023, 3:10pm UTC](https://forums.sketchup.com/t/pause-and-resume-an-animation/232335/9 "2023-06-11T15:10:08Z")

</div>

> [@sguthery](#):
>
> I have to click the window or tap a key to get the animation running again after I pause it. In fact, just returning `true` to `nextFrame` and doing nothing else stops the `nextFrame` loop altogether. A click or key tap will trigger one more call to `nextFrame` and then crickets.
> 
> However, if I call `view.show_frame` before just returning true (even though there has been no change to the model) the regular calls to `nextFrame` continue. Having to refresh a display that hasn’t changed to get functionality that doesn’t depend on the display is a little counter-intuitive, but it does work around the problem.

Okay. It might be an actual issue that should be reported in the official tracker at GitHub.

- [Issues · SketchUp/api-issue-tracker (github.com)](https://github.com/SketchUp/api-issue-tracker/issues)

But again, nobody else can reproduce without a test model that had the gears and the component definition named “Gear1”.
