docs: def tick(self, events):
          """Execute one frame of the interpreter.
  
          Don't call more than 40 times per second.
  
          """
          self.add_new_threads()
  
          if self.drag_sprite:
              (mx, my) = self.screen.get_mouse_pos()
              (ox, oy) = self.drag_offset
              new_position = (mx + ox, my + oy)
              if self.drag_sprite.position != new_position:
                  self.has_dragged = True
                  self.drag_sprite.position = new_position
  
          for event in events:
              if event.kind == "key_pressed":
                  assert event.value in kurt.Insert(None, "key").options()
                  self.trigger_hats("whenKeyPressed", event.value)
  
              elif event.kind == "mouse_down":
                  mouse_pos = self.screen.get_mouse_pos()
                  for sprite in reversed(self.project.sprites):
                      rect = bounds(sprite)
                      if rect.collide_point(mouse_pos):
                          if self.screen.touching_mouse(sprite):
                              scriptable = sprite
                              break
                  else:
                      scriptable = self.project.stage
  
                  if scriptable.is_draggable:
                      (mx, my) = self.screen.get_mouse_pos()
                      (x, y) = scriptable.position
                      self.drag_offset = (x - mx, y - my)
                      self.drag_sprite = scriptable
                      self.has_dragged = False
                      go_to_front(scriptable)
                  else:
                      self.trigger_scriptable_hats(scriptable, "whenClicked")
  
              elif event.kind == "mouse_up":
                  if self.drag_sprite:
                      if not self.has_dragged:
                          self.trigger_scriptable_hats(self.drag_sprite,
                                                       "whenClicked")
                      self.drag_sprite = None
  
          remove_threads = []
          while 1:
              for (script, thread) in self.threads.items():
                  modified = False
                  for event in thread.tick():
                      if event.kind == "stop":
                          if event.value == "all":
                              self.stop()
                              return
                          elif event.value == "other scripts in sprite":
                              for (script, other) in self.threads.items():
                                  if other.scriptable == thread.scriptable:
                                      other.finish()
                                      del self.threads[script]
                              modified = True
                              break
                          else:
                              thread.finish()
                              del self.threads[script]
                              modified = True
                              break
                      else: # Pass to Screen
                          yield event
                  if modified:
                      break
              else:
                  break
  
          self.add_new_threads()