diff --git a/src/engine/adapter.js b/src/engine/adapter.js
index 222273c5c..93bc901b3 100644
--- a/src/engine/adapter.js
+++ b/src/engine/adapter.js
@@ -9,10 +9,8 @@ var parseDOM = memoize(html.parseDOM, {
 /**
  * Adapter between block creation events and block representation which can be
  * used by the Scratch runtime.
- *
- * @param {Object} `Blockly.events.create`
- *
- * @return {Object}
+ * @param {Object} e `Blockly.events.create`
+ * @return {Array.<Object>} List of blocks from this CREATE event.
  */
 module.exports = function (e) {
     // Validate input
@@ -20,68 +18,112 @@ module.exports = function (e) {
     if (typeof e.blockId !== 'string') return;
     if (typeof e.xml !== 'object') return;
 
-    // Storage object
-    var obj = {
-        id: e.blockId,
-        opcode: null,
-        next: null,
-        fields: {}
-    };
-
-    // Set opcode
-    if (typeof e.xml.attributes === 'object') {
-        obj.opcode = e.xml.attributes.type.value;
-    }
-
-    // Extract fields from event's `innerHTML`
-    if (typeof e.xml.innerHTML !== 'string') return obj;
-    if (e.xml.innerHTML === '') return obj;
-    obj.fields = extract(parseDOM(e.xml.innerHTML));
-
-    return obj;
+    return domToBlocks(parseDOM(e.xml.outerHTML));
 };
 
 /**
- * Extracts fields from a block's innerHTML.
- * @todo Extend this to support vertical grammar / nested blocks.
- *
- * @param {Object} DOM representation of block's innerHTML
- *
- * @return {Object}
+ * Convert outer blocks DOM from a Blockly CREATE event
+ * to a usable form for the Scratch runtime.
+ * This structure is based on Blockly xml.js:`domToWorkspace` and `domToBlock`.
+ * @param {Element} blocksDOM DOM tree for this event.
+ * @return {Array.<Object>} Usable list of blocks from this CREATE event.
  */
-function extract (dom) {
-    // Storage object
-    var fields = {};
-
-    // Field
-    var field = dom[0];
-    var fieldName = field.attribs.name;
-    fields[fieldName] = {
-        name: fieldName,
-        value: null,
-        blocks: {}
-    };
-
-    // Shadow block
-    var shadow = field.children[0];
-    var shadowId = shadow.attribs.id;
-    var shadowOpcode = shadow.attribs.type;
-    fields[fieldName].blocks[shadowId] = {
-        id: shadowId,
-        opcode: shadowOpcode,
-        next: null,
-        fields: {}
-    };
-
-    // Primitive
-    var primitive = shadow.children[0];
-    var primitiveName = primitive.attribs.name;
-    var primitiveValue = primitive.children[0].data;
-    fields[fieldName].blocks[shadowId].fields[primitiveName] = {
-        name: primitiveName,
-        value: primitiveValue,
-        blocks: null
-    };
-
-    return fields;
+function domToBlocks (blocksDOM) {
+    // At this level, there could be multiple blocks adjacent in the DOM tree.
+    var blocks = {};
+    for (var i = 0; i < blocksDOM.length; i++) {
+        var block = blocksDOM[i];
+        var tagName = block.name.toLowerCase();
+        if (tagName === 'block') {
+            domToBlock(block, blocks, 0);
+        }
+    }
+    // Flatten blocks object into a list.
+    var blocksList = [];
+    for (var b in blocks) {
+        blocksList.push(blocks[b]);
+    }
+    return blocksList;
+}
+
+/**
+ * Convert and an individual block DOM to the representation tree.
+ * Based on Blockly's `domToBlockHeadless_`.
+ * @param {Element} blockDOM DOM tree for an individual block.
+ * @param {Number} treeDepth How far down the tree we have recursed.
+ * @param {Object} blocks Collection of blocks to add to.
+ */
+function domToBlock (blockDOM, blocks, treeDepth) {
+    // Block skeleton.
+    var block = {
+        id: null, // Block ID
+        opcode: null, // Execution opcode, e.g., "event_whengreenflag".
+        inputs: {}, // Inputs to this block and the blocks they point to.
+        fields: {}, // Fields on this block and their values.
+        next: null, // Next block in the stack, if one exists.
+        topLevel: treeDepth == 0 // If this block starts a stack.
+    };
+
+    // Basic properties of the block from XML.
+    block.id = blockDOM.attribs.id;
+    block.opcode = blockDOM.attribs.type;
+
+    // Add the block to the representation tree.
+    blocks[block.id] = block;
+
+    // Process XML children and find enclosed blocks, fields, etc.
+    for (var i = 0; i < blockDOM.children.length; i++) {
+        var xmlChild = blockDOM.children[i];
+        // Enclosed blocks and shadows
+        var childBlockNode = null;
+        var childShadowNode = null;
+        for (var j = 0; j < xmlChild.children.length; j++) {
+            var grandChildNode = xmlChild.children[j];
+            if (!grandChildNode.name) {
+                // Non-XML tag node.
+                continue;
+            }
+            var grandChildNodeName = grandChildNode.name.toLowerCase();
+            if (grandChildNodeName == 'block') {
+                childBlockNode = grandChildNode;
+            } else if (grandChildNodeName == 'shadow') {
+                childShadowNode = grandChildNode;
+            }
+        }
+
+        // Use shadow block only if there's no real block node.
+        if (!childBlockNode && childShadowNode) {
+            childBlockNode = childShadowNode;
+        }
+
+        // Not all Blockly-type blocks are handled here,
+        // as we won't be using all of them for Scratch.
+        switch (xmlChild.name.toLowerCase()) {
+        case 'field':
+            // Add the field to this block.
+            var fieldName = xmlChild.attribs.name;
+            block.fields[fieldName] = {
+                name: fieldName,
+                value: xmlChild.children[0].data
+            };
+            break;
+        case 'value':
+        case 'statement':
+            // Recursively generate block structure for input block.
+            domToBlock(childBlockNode, blocks, treeDepth + 1);
+            // Link this block's input to the child block.
+            var inputName = xmlChild.attribs.name;
+            block.inputs[inputName] = {
+                name: inputName,
+                block: childBlockNode.attribs.id
+            };
+            break;
+        case 'next':
+            // Recursively generate block structure for next block.
+            domToBlock(childBlockNode, blocks, treeDepth + 1);
+            // Link next block to this block.
+            block.next = childBlockNode.attribs.id;
+            break;
+        }
+    }
 }
diff --git a/src/index.js b/src/index.js
index d128aab90..5c433f899 100644
--- a/src/index.js
+++ b/src/index.js
@@ -31,7 +31,11 @@ function VirtualMachine () {
         // Blocks
         switch (e.type) {
         case 'create':
-            instance.runtime.createBlock(adapter(e), false);
+            var newBlocks = adapter(e);
+            // A create event can create many blocks. Add them all.
+            for (var i = 0; i < newBlocks.length; i++) {
+                instance.runtime.createBlock(newBlocks[i], false);
+            }
             break;
         case 'change':
             instance.runtime.changeBlock({
@@ -64,7 +68,11 @@ function VirtualMachine () {
     instance.flyoutBlockListener = function (e) {
         switch (e.type) {
         case 'create':
-            instance.runtime.createBlock(adapter(e), true);
+            var newBlocks = adapter(e);
+            // A create event can create many blocks. Add them all.
+            for (var i = 0; i < newBlocks.length; i++) {
+                instance.runtime.createBlock(newBlocks[i], true);
+            }
             break;
         case 'change':
             instance.runtime.changeBlock({