diff --git a/src/engine/execute.js b/src/engine/execute.js
index 0d1dbc3cc..6c58cd156 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -1,5 +1,3 @@
-var YieldTimers = require('../util/yieldtimers.js');
-
 /**
  * If set, block calls, args, and return values will be logged to the console.
  * @const {boolean}
@@ -13,11 +11,6 @@ var execute = function (sequencer, thread) {
     var currentBlockId = thread.peekStack();
     var currentStackFrame = thread.peekStackFrame();
 
-    // Save the yield timer ID, in case a primitive makes a new one
-    // @todo hack - perhaps patch this to allow more than one timer per
-    // primitive, for example...
-    var oldYieldTimerId = YieldTimers.timerId;
-
     var opcode = runtime.blocks.getOpcode(currentBlockId);
 
     // Generate values for arguments (inputs).
@@ -64,17 +57,12 @@ var execute = function (sequencer, thread) {
         done: function() {
             sequencer.proceedThread(thread);
         },
-        timeout: YieldTimers.timeout,
+        timeout: thread.addTimeout.bind(thread),
         stackFrame: currentStackFrame,
         startSubstack: function (substackNum) {
             sequencer.stepToSubstack(thread, substackNum);
         }
     });
-    // Update if the thread has set a yield timer ID
-    // @todo hack
-    if (YieldTimers.timerId > oldYieldTimerId) {
-        thread.yieldTimerId = YieldTimers.timerId;
-    }
     if (DEBUG_BLOCK_CALLS) {
         console.log('ending stack frame: ', currentStackFrame);
         console.log('returned: ', primitiveReturnValue);
diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js
index deaa15266..1541d1c6f 100644
--- a/src/engine/sequencer.js
+++ b/src/engine/sequencer.js
@@ -53,10 +53,10 @@ Sequencer.prototype.stepThreads = function (threads) {
                 // Normal-mode thread: step.
                 this.startThread(activeThread);
             } else if (activeThread.status === Thread.STATUS_YIELD) {
-                // Yield-mode thread: check if the time has passed.
-                if (!YieldTimers.resolve(activeThread.yieldTimerId)) {
-                    // Thread is still yielding
-                    // if YieldTimers.resolve returns false.
+                // Yield-mode thread: resolve timers.
+                activeThread.resolveTimeouts();
+                if (activeThread.status === Thread.STATUS_YIELD) {
+                    // Still yielding.
                     numYieldingThreads++;
                 }
             } else if (activeThread.status === Thread.STATUS_DONE) {
diff --git a/src/engine/thread.js b/src/engine/thread.js
index c98efab48..bd991db27 100644
--- a/src/engine/thread.js
+++ b/src/engine/thread.js
@@ -1,3 +1,5 @@
+var YieldTimers = require('../util/yieldtimers.js');
+
 /**
  * A thread is a running stack context and all the metadata needed.
  * @param {?string} firstBlock First block to execute in the thread.
@@ -30,10 +32,10 @@ function Thread (firstBlock) {
     this.status = 0; /* Thread.STATUS_RUNNING */
 
     /**
-     * Yield timer ID (for checking when the thread should unyield).
+     * Execution-synced timeouts.
      * @type {number}
      */
-    this.yieldTimerId = -1;
+    this.timeoutIds = [];
 }
 
 /**
@@ -104,4 +106,29 @@ Thread.prototype.yield = function () {
     this.status = Thread.STATUS_YIELD;
 };
 
+/**
+ * Add an execution-synced timeouts for this thread.
+ * See also: util/yieldtimers.js:timeout
+ * @param {!Function} callback To be called when the timer is done.
+ * @param {number} timeDelta Time to wait, in ms.
+ */
+Thread.prototype.addTimeout = function (callback, timeDelta) {
+    var timeoutId = YieldTimers.timeout(callback, timeDelta);
+    this.timeoutIds.push(timeoutId);
+};
+
+/**
+ * Attempt to resolve all execution-synced timeouts on this thread.
+ */
+Thread.prototype.resolveTimeouts = function () {
+    var newTimeouts = [];
+    for (var i = 0; i < this.timeoutIds.length; i++) {
+        var resolved = YieldTimers.resolve(this.timeoutIds[i]);
+        if (!resolved) {
+            newTimeouts.push(this.timeoutIds[i]);
+        }
+    }
+    this.timeoutIds = newTimeouts;
+};
+
 module.exports = Thread;
diff --git a/src/util/yieldtimers.js b/src/util/yieldtimers.js
index 45e244eaf..84c6d3259 100644
--- a/src/util/yieldtimers.js
+++ b/src/util/yieldtimers.js
@@ -68,23 +68,4 @@ YieldTimers.resolve = function (id) {
     return true;
 };
 
-/**
- * Reject a timer so the callback never executes.
- * @param {number} id Timer ID to reject.
- */
-YieldTimers.reject = function (id) {
-    if (YieldTimers.timers[id]) {
-        delete YieldTimers.timers[id];
-    }
-};
-
-/**
- * Reject all timers currently stored.
- * Especially useful for a Scratch "stop."
- */
-YieldTimers.rejectAll = function () {
-    YieldTimers.timers = {};
-    YieldTimers.timerId = 0;
-};
-
 module.exports = YieldTimers;