diff --git a/package.json b/package.json
index a3ff0b80b12f0ff763551c8bd08a572f0b2f286a..136a6bc41fdb41da7f6b59c69479d9cabc2031fc 100644
--- a/package.json
+++ b/package.json
@@ -59,6 +59,7 @@
     "gh-pages": "github:rschamp/gh-pages#publish-branch-to-subfolder",
     "html-webpack-plugin": "^3.2.0",
     "immutable": "3.8.2",
+    "intl": "1.2.5",
     "jest": "^21.0.0",
     "keymirror": "0.1.1",
     "lodash.bindall": "4.4.0",
@@ -95,13 +96,13 @@
     "redux-throttle": "0.1.1",
     "rimraf": "^2.6.1",
     "scratch-audio": "0.1.0-prerelease.20180625202813",
-    "scratch-blocks": "0.1.0-prerelease.1531144787",
+    "scratch-blocks": "0.1.0-prerelease.1531409796",
     "scratch-l10n": "3.0.20180703181510",
-    "scratch-paint": "0.2.0-prerelease.20180709132225",
+    "scratch-paint": "0.2.0-prerelease.20180712144339",
     "scratch-render": "0.1.0-prerelease.20180618173030",
     "scratch-storage": "0.5.1",
     "scratch-svg-renderer": "0.2.0-prerelease.20180618172917",
-    "scratch-vm": "0.1.0-prerelease.1530902855",
+    "scratch-vm": "0.1.0-prerelease.1531340421",
     "selenium-webdriver": "3.6.0",
     "startaudiocontext": "1.2.1",
     "style-loader": "^0.21.0",
diff --git a/src/components/action-menu/action-menu.css b/src/components/action-menu/action-menu.css
index 6771a6851d50d5aefd856d94700811d6be15bf3d..8f39946c128d445c5dbd98acbade5ac10553f1c2 100644
--- a/src/components/action-menu/action-menu.css
+++ b/src/components/action-menu/action-menu.css
@@ -28,7 +28,7 @@ button::-moz-focus-inner {
 }
 
 .button:hover {
-    background: $pen-primary;
+    background: $extensions-primary;
 }
 
 .button:active {
@@ -126,7 +126,7 @@ button::-moz-focus-inner {
     is not very easy to style.
 */
 .tooltip {
-    background-color: $pen-primary !important;
+    background-color: $extensions-primary !important;
     opacity: 1 !important;
     border: 1px solid hsla(0, 0%, 0%, .1) !important;
     box-shadow: 0 0 .5rem hsla(0, 0%, 0%, .25) !important;
@@ -134,7 +134,7 @@ button::-moz-focus-inner {
 }
 
 .tooltip:after {
-    background-color: $pen-primary;
+    background-color: $extensions-primary;
 }
 
 .coming-soon-tooltip {
diff --git a/src/components/blocks/blocks.css b/src/components/blocks/blocks.css
index 5f738b196ff18175e11a547f48e6fec3adece552..e02486ce0fe376d091090b4355d2a0febc3c8331 100644
--- a/src/components/blocks/blocks.css
+++ b/src/components/blocks/blocks.css
@@ -40,6 +40,14 @@
     box-sizing: content-box;
 }
 
+.blocks :global(.blocklyBlockDragSurface) {
+    /*
+        Fix an issue where the drag surface was preventing hover events for sharing blocks.
+        This does not prevent user interaction on the blocks themselves.
+    */
+    pointer-events: none;
+}
+
 /*
     Shrink category font to fit "My Blocks" for now.
     Probably will need different solutions for language support later, so
diff --git a/src/components/camera-modal/camera-modal.css b/src/components/camera-modal/camera-modal.css
index 5f631e41bf5ad9b22675065153f683534c896a7b..4ea962fbafd68bc7ecdf3736d96930070a46f0de 100644
--- a/src/components/camera-modal/camera-modal.css
+++ b/src/components/camera-modal/camera-modal.css
@@ -93,7 +93,7 @@ $main-button-size: 2.75rem;
 }
 
 .main-button:hover {
-    background: $pen-primary;
+    background: $extensions-primary;
     box-shadow: 0 0 0 6px $motion-transparent;
 }
 
diff --git a/src/components/cards/card.css b/src/components/cards/card.css
index 99ab8a66c01f10aa99f68fdbd1153bf1e2a72538..9e14a1fb2a6b1152e0b099479febe77507c68ea9 100644
--- a/src/components/cards/card.css
+++ b/src/components/cards/card.css
@@ -14,21 +14,21 @@
     top: 5%;
     background: $ui-white;
     border: 1px solid $ui-tertiary;
-    width: 10px;
+    width: .75rem;
     z-index: 10;
     opacity: 0.9;
     overflow: hidden;
 }
 
 .left-card {
-    left: -10px;
+    left: -.75rem;
     border-right: 0;
     border-top-left-radius: 0.75rem;
     border-bottom-left-radius: 0.75rem;
 }
 
 .right-card {
-    right: -10px;
+    right: -.75rem;
     border-left: 0;
     border-top-right-radius: 0.75rem;
     border-bottom-right-radius: 0.75rem;
@@ -39,9 +39,9 @@
     position: absolute;
     top: 0;
     left: 0;
-    height: 1.8rem;
+    height: 2.5rem;
     width: 100%;
-    background: $motion-primary;
+    background: $extensions-primary;
 }
 
 .left-button, .right-button {
@@ -51,14 +51,24 @@
     z-index: 20;
     user-select: none;
     cursor: pointer;
-    background: $motion-primary;
-    box-shadow: 0 0 0 4px $motion-transparent;
-    height: 40px;
-    width: 40px;
+    background: $extensions-primary;
+    box-shadow: 0 0 0 4px $extensions-transparent;
+    height: 44px;
+    width: 44px;
     border-radius: 100%;
     display: flex;
     justify-content: center;
     align-items: center;
+    transition: all 0.25s ease;
+}
+
+.left-button:hover, .right-button:hover {
+    box-shadow: 0 0 0 6px $extensions-transparent;
+    transform: scale(1.125);
+}
+
+.left-button img, .right-button img{
+    width: 1.75rem;
 }
 
 .left-button {
@@ -88,10 +98,10 @@
     flex-direction: row;
     justify-content: space-between;
     align-items: center;
-    background: $motion-primary;
-    border-bottom: 1px solid $motion-tertiary;
-    padding: 0.5rem;
+    background: $extensions-primary;
+    border-bottom: 1px solid $extensions-tertiary;
     font-size: 0.625rem;
+    font-weight: bold;
 }
 
 .remove-button, .all-button {
@@ -101,6 +111,11 @@
     flex-direction: row;
     justify-content: center;
     align-items: center;
+    padding: 0.75rem;
+}
+
+.remove-button:hover, .all-button:hover {
+    background-color: $ui-black-transparent;
 }
 
 .step-title {
@@ -161,14 +176,14 @@
     color: $motion-primary;
     font-weight: bold;
     font-size: 0.85rem;
-    margin: 14px 0px;
+    margin: .625rem 0px;
     text-align: center;
     font-weight: bold;
     text-align: center;
 }
 
 .help-icon, .close-icon {
-    height: 0.75rem;
+    height: 1rem;
 }
 
 .help-icon {
@@ -198,9 +213,9 @@
     display: flex;
     align-items: center;
     color: $ui-white;
-    font-size: 12px;
+    font-size: .75rem;
     font-weight: bold;
-    line-height: 15px;
+    line-height: 1rem;
     text-align: center;
 }
 
@@ -228,10 +243,10 @@
     height: 0.5rem;
     margin: 0 0.25rem;
     border-radius: 100%;
-    background: transparent;
-    border: 2px solid $ui-white-transparent;
+    background: $ui-white-transparent;
 }
 
 .active-step-pip {
-    background: white;
+    background: $ui-white;
+    box-shadow: 0px 0px 0px 2px $ui-black-transparent;
 }
diff --git a/src/components/cards/cards.jsx b/src/components/cards/cards.jsx
index ab01f8ecdf1f54a193abb692a38c0f00061e80b3..dc081ae0b64548c429a9c3f4da0e6ae4c03e1500 100644
--- a/src/components/cards/cards.jsx
+++ b/src/components/cards/cards.jsx
@@ -8,7 +8,7 @@ import styles from './card.css';
 import nextIcon from './icon--next.svg';
 import prevIcon from './icon--prev.svg';
 
-import helpIcon from './icon--help.svg';
+import helpIcon from '../../lib/assets/icon--tutorials.svg';
 import closeIcon from '../close-button/icon--close.svg';
 
 const CardHeader = ({onCloseCards, onShowAll, totalSteps, step}) => (
@@ -22,9 +22,9 @@ const CardHeader = ({onCloseCards, onShowAll, totalSteps, step}) => (
                 src={helpIcon}
             />
             <FormattedMessage
-                defaultMessage="All How-Tos"
-                description="Title for button to return to how-to library"
-                id="gui.cards.all-how-tos"
+                defaultMessage="Tutorials"
+                description="Title for button to return to tutorials library"
+                id="gui.cards.all-tutorials"
             />
         </div>
         {totalSteps > 1 ? (
diff --git a/src/components/cards/icon--help.svg b/src/components/cards/icon--help.svg
deleted file mode 100644
index 436d052874bd47c11a55909be61d0fb83777c000..0000000000000000000000000000000000000000
Binary files a/src/components/cards/icon--help.svg and /dev/null differ
diff --git a/src/components/connection-modal/connected-step.jsx b/src/components/connection-modal/connected-step.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..c02f644bc4e55d807124bd8cc41004a98cdca24b
--- /dev/null
+++ b/src/components/connection-modal/connected-step.jsx
@@ -0,0 +1,71 @@
+import {FormattedMessage} from 'react-intl';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Box from '../box/box.jsx';
+import Dots from './dots.jsx';
+import bluetoothIcon from './icons/bluetooth-white.svg';
+import styles from './connection-modal.css';
+import classNames from 'classnames';
+
+const ConnectedStep = props => (
+    <Box className={styles.body}>
+        <Box className={styles.activityArea}>
+            <Box className={styles.centeredRow}>
+                <div className={styles.deviceActivity}>
+                    <img
+                        className={styles.deviceActivityIcon}
+                        src={props.deviceImage}
+                    />
+                    <img
+                        className={styles.bluetoothConnectedIcon}
+                        src={bluetoothIcon}
+                    />
+                </div>
+            </Box>
+        </Box>
+        <Box className={styles.bottomArea}>
+            <Box className={styles.instructions}>
+                <FormattedMessage
+                    defaultMessage="Connected"
+                    description="Message indicating that a device was connected"
+                    id="gui.connection.connected"
+                />
+            </Box>
+            <Dots
+                success
+                total={3}
+            />
+            <div className={styles.cornerButtons}>
+                <button
+                    className={classNames(styles.redButton, styles.connectionButton)}
+                    onClick={props.onDisconnect}
+                >
+                    <FormattedMessage
+                        defaultMessage="Disconnect"
+                        description="Button to disconnect the device"
+                        id="gui.connection.disconnect"
+                    />
+                </button>
+                <button
+                    className={styles.connectionButton}
+                    onClick={props.onCancel}
+                >
+                    <FormattedMessage
+                        defaultMessage="Go to Editor"
+                        description="Button to return to the editor"
+                        id="gui.connection.go-to-editor"
+                    />
+                </button>
+            </div>
+        </Box>
+    </Box>
+);
+
+ConnectedStep.propTypes = {
+    deviceImage: PropTypes.string.isRequired,
+    onCancel: PropTypes.func,
+    onDisconnect: PropTypes.func
+};
+
+export default ConnectedStep;
diff --git a/src/components/connection-modal/connecting-step.jsx b/src/components/connection-modal/connecting-step.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..063e67a826c79f4c9f55548e321d499d8c86d6a3
--- /dev/null
+++ b/src/components/connection-modal/connecting-step.jsx
@@ -0,0 +1,71 @@
+import {FormattedMessage} from 'react-intl';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Box from '../box/box.jsx';
+import Dots from './dots.jsx';
+
+import bluetoothIcon from './icons/bluetooth-white.svg';
+import closeIcon from '../close-button/icon--close.svg';
+
+import styles from './connection-modal.css';
+
+const ConnectingStep = props => (
+    <Box className={styles.body}>
+        <Box className={styles.activityArea}>
+            <Box className={styles.centeredRow}>
+                <div className={styles.deviceActivity}>
+                    <img
+                        className={styles.deviceActivityIcon}
+                        src={props.deviceImage}
+                    />
+                    <img
+                        className={styles.bluetoothConnectingIcon}
+                        src={bluetoothIcon}
+                    />
+                </div>
+            </Box>
+        </Box>
+        <Box className={styles.bottomArea}>
+            <Box className={styles.instructions}>
+                <FormattedMessage
+                    defaultMessage="Connecting"
+                    description=""
+                    id="gui.connection.connecting"
+                />
+            </Box>
+            <Dots
+                counter={1}
+                total={3}
+            />
+            <div className={styles.segmentedButton}>
+                <button
+                    disabled
+                    className={styles.connectionButton}
+                >
+                    <FormattedMessage
+                        defaultMessage="Connecting..."
+                        description="Label indicating that connection is in progress"
+                        id="gui.connection.connecting-cancelbutton"
+                    />
+                </button>
+                <button
+                    className={styles.connectionButton}
+                    onClick={props.onDisconnect}
+                >
+                    <img
+                        className={styles.abortConnectingIcon}
+                        src={closeIcon}
+                    />
+                </button>
+            </div>
+        </Box>
+    </Box>
+);
+
+ConnectingStep.propTypes = {
+    deviceImage: PropTypes.string.isRequired,
+    onDisconnect: PropTypes.func
+};
+
+export default ConnectingStep;
diff --git a/src/components/connection-modal/connection-modal.css b/src/components/connection-modal/connection-modal.css
new file mode 100644
index 0000000000000000000000000000000000000000..ee0a0aae1e6ee354f7c3a2decd302f65b000644d
--- /dev/null
+++ b/src/components/connection-modal/connection-modal.css
@@ -0,0 +1,308 @@
+@import "../../css/colors.css";
+@import "../../css/units.css";
+
+.modal-content {
+    width: 480px;
+}
+
+.header {
+    background-color: $pen-primary;
+}
+
+.body {
+    background: $ui-white;
+}
+
+.label {
+    font-weight: 500;
+    margin: 0 0 0.75rem;
+}
+
+.centered-row {
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+}
+
+.device-tile-pane {
+    overflow-y: auto;
+    width: 100%;
+    height: 100%;
+    padding: 0.5rem;
+}
+
+.device-tile {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+
+    background-color: $ui-white;
+    border-radius: 0.25rem;
+    padding: 10px;
+    width: 100%;
+    height: 55px;
+    margin-bottom: 0.5rem;
+}
+
+.device-tile-name {
+    display: flex;
+    align-items: center;
+}
+
+.device-tile-image {
+    margin-right: 0.5rem;
+}
+
+.device-tile-name-wrapper {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: flex-start;
+}
+
+.device-tile-name-label {
+    font-weight: bold;
+    font-size: 0.625rem;
+}
+
+.device-tile-name-text {
+    font-size: 0.875rem;
+}
+
+.device-tile button {
+    padding: 0.6rem 0.75rem;
+    border: none;
+    border-radius: 0.25rem;
+    font-weight: 600;
+    font-size: 0.85rem;
+    background: $motion-primary;
+    border: $motion-primary;
+    color: white;
+    cursor: pointer;
+}
+
+.signal-strength-meter {
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-end;
+    width: 22px;
+    height: 16px;
+    margin-right: 1rem;
+}
+
+.signal-bar {
+    width: 4px;
+    border-radius: 4px;
+    background-color: #DBDBDB;
+}
+
+.signal-bar:nth-of-type(1) { height: 25%; }
+.signal-bar:nth-of-type(2) { height: 50%; }
+.signal-bar:nth-of-type(3) { height: 75%; }
+.signal-bar:nth-of-type(4) { height: 100%; }
+
+.green-bar {
+    background-color: $pen-primary;
+}
+
+.radar {
+    width: 40px;
+    height: 40px;
+    margin-right: 0.5rem;
+    animation: spin 4s linear infinite;
+}
+
+@keyframes spin {
+    100% {
+        transform: rotate(360deg);
+    }
+}
+
+
+.device-activity {
+    position: relative;
+}
+
+.device-activity-icon {
+    /* width: 80px;
+    height: 80px; */
+}
+
+.bluetooth-connecting-icon {
+    position: absolute;
+    top: -5px;
+    right: -15px;
+    padding: 5px 5px;
+    background-color: $motion-primary;
+    border-radius: 100%;
+    box-shadow: 0px 0px 0px 4px $motion-transparent;
+    /* animation: pulse-blue-ring 1s infinite ease-in-out alternate; */
+    animation: wiggle 0.5s infinite ease-in-out alternate;
+
+}
+
+@keyframes pulse-blue-ring {
+    100% {
+        box-shadow: 0px 0px 0px 8px $motion-light-transparent;
+    }
+}
+
+
+.bluetooth-connected-icon {
+    position: absolute;
+    top: -5px;
+    right: -15px;
+    padding: 5px 5px;
+    background-color: $pen-primary;
+    border-radius: 100%;
+    box-shadow: 0px 0px 0px 4px $pen-transparent;
+}
+
+
+
+@keyframes wiggle {
+    0% {transform: rotate(3deg) scale(1.05);}
+    25% {transform: rotate(-3deg) scale(1.05);}
+    50% {transform: rotate(5deg) scale(1.05);}
+    75% {transform: rotate(-2deg) scale(1.05);}
+    100% {transform: rotate(0deg) scale(1.05);}
+}
+
+.device-tile-widgets {
+    display: flex;
+    align-items: center;
+}
+
+.activityArea {
+    height: 165px;
+    background-color: $motion-light-transparent;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}
+
+.button-row {
+    font-weight: bolder;
+    text-align: center;
+    display: flex;
+}
+
+.abort-connecting-icon {
+    width: 10px;
+    transform: rotate(45deg);
+}
+
+.connection-button {
+    padding: 0.6rem 0.75rem;
+    border-radius: 0.5rem;
+    background: $motion-primary;
+    color: white;
+    font-weight: 600;
+    font-size: 0.85rem;
+    margin: 0.25rem;
+    border: none;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+}
+
+.connection-button:disabled {
+    background: $motion-transparent;
+}
+
+.segmented-button {
+    display: flex;
+}
+
+.segmented-button .connection-button:first-of-type {
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+    margin-right: 0;
+}
+
+.segmented-button .connection-button:last-of-type {
+    margin-left: 1px;
+    border-top-left-radius: 0;
+    border-bottom-left-radius: 0;
+}
+
+.button-icon-right {
+    margin-left: 0.5rem;
+}
+
+.button-icon-left {
+    margin-right: 0.5rem;
+}
+
+.red-button {
+    background: $red-primary;
+}
+
+.corner-buttons {
+    display: flex;
+    justify-content: space-between;
+    width: 100%;
+    padding: 0 1rem;
+}
+
+.bottom-area {
+    background-color: $ui-white;
+    text-align: center;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding-bottom: 12px;
+}
+
+.instructions {
+    text-align: center;
+    padding: 1rem;
+}
+
+.dots-row {
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+    padding-bottom: 1rem;
+}
+
+.dots-holder {
+    display: flex;
+    padding: 0.25rem 0.1rem;
+    border-radius: 1rem;
+    background: $motion-light-transparent;
+}
+
+.dots-holder-success {
+    background: $pen-transparent;
+}
+
+.dots-holder-error {
+    background: $error-transparent;
+}
+
+.dot {
+    width: 0.5rem;
+    height: 0.5rem;
+    margin: 0 0.3rem;
+    border-radius: 100%;
+}
+
+.inactive-step-dot {
+    background: $motion-transparent;
+}
+
+.active-step-dot {
+    background: $motion-primary;
+}
+
+.success-dot {
+    background: $pen-primary;
+}
+
+.error-dot {
+    background: $error-primary;
+}
diff --git a/src/components/connection-modal/connection-modal.jsx b/src/components/connection-modal/connection-modal.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..5ddcb33e3b891aa5641cbf63d884688cc83c0183
--- /dev/null
+++ b/src/components/connection-modal/connection-modal.jsx
@@ -0,0 +1,50 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import keyMirror from 'keymirror';
+
+import Box from '../box/box.jsx';
+import Modal from '../modal/modal.jsx';
+
+import ScanningStep from '../../containers/scanning-step.jsx';
+import ConnectingStep from './connecting-step.jsx';
+import ConnectedStep from './connected-step.jsx';
+import ErrorStep from './error-step.jsx';
+
+import styles from './connection-modal.css';
+
+const PHASES = keyMirror({
+    scanning: null,
+    connecting: null,
+    connected: null,
+    error: null
+});
+
+const ConnectionModalComponent = props => (
+    <Modal
+        className={styles.modalContent}
+        contentLabel={props.name}
+        headerClassName={styles.header}
+        headerImage={props.smallDeviceImage}
+        onRequestClose={props.onCancel}
+    >
+        <Box className={styles.body}>
+            {props.phase === PHASES.scanning && <ScanningStep {...props} />}
+            {props.phase === PHASES.connecting && <ConnectingStep {...props} />}
+            {props.phase === PHASES.connected && <ConnectedStep {...props} />}
+            {props.phase === PHASES.error && <ErrorStep {...props} />}
+        </Box>
+    </Modal>
+);
+
+ConnectionModalComponent.propTypes = {
+    name: PropTypes.node,
+    onCancel: PropTypes.func.isRequired,
+    phase: PropTypes.oneOf(Object.keys(PHASES)).isRequired,
+    smallDeviceImage: PropTypes.string,
+    title: PropTypes.string.isRequired
+};
+
+export {
+    ConnectionModalComponent as default,
+    PHASES
+};
diff --git a/src/components/connection-modal/device-tile.jsx b/src/components/connection-modal/device-tile.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..c806453aa0ff60828462376bf9c01a3a38ae550f
--- /dev/null
+++ b/src/components/connection-modal/device-tile.jsx
@@ -0,0 +1,87 @@
+import {FormattedMessage} from 'react-intl';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+import React from 'react';
+import bindAll from 'lodash.bindall';
+import Box from '../box/box.jsx';
+
+import styles from './connection-modal.css';
+
+class DeviceTile extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, [
+            'handleConnecting'
+        ]);
+    }
+    handleConnecting () {
+        this.props.onConnecting(this.props.peripheralId);
+    }
+    render () {
+        return (
+            <Box className={styles.deviceTile}>
+                <Box className={styles.deviceTileName}>
+                    <img
+                        className={styles.deviceTileImage}
+                        src={this.props.smallDeviceImage}
+                    />
+                    <Box className={styles.deviceTileNameWrapper}>
+                        <Box className={styles.deviceTileNameLabel}>
+                            <FormattedMessage
+                                defaultMessage="Device name"
+                                description="Label for field showing the device name"
+                                id="gui.connection.device-name-label"
+                            />
+                        </Box>
+                        <Box className={styles.deviceTileNameText}>
+                            {this.props.name}
+                        </Box>
+                    </Box>
+                </Box>
+                <Box className={styles.deviceTileWidgets}>
+                    <Box className={styles.signalStrengthMeter}>
+                        <div
+                            className={classNames(styles.signalBar, {
+                                [styles.greenBar]: this.props.rssi > -80
+                            })}
+                        />
+                        <div
+                            className={classNames(styles.signalBar, {
+                                [styles.greenBar]: this.props.rssi > -60
+                            })}
+                        />
+                        <div
+                            className={classNames(styles.signalBar, {
+                                [styles.greenBar]: this.props.rssi > -40
+                            })}
+                        />
+                        <div
+                            className={classNames(styles.signalBar, {
+                                [styles.greenBar]: this.props.rssi > -20
+                            })}
+                        />
+                    </Box>
+                    <button
+                        onClick={this.handleConnecting}
+                    >
+                        <FormattedMessage
+                            defaultMessage="Connect"
+                            description="Button to start connecting to a specific device"
+                            id="gui.connection.connect"
+                        />
+                    </button>
+                </Box>
+            </Box>
+        );
+    }
+}
+
+DeviceTile.propTypes = {
+    name: PropTypes.string,
+    onConnecting: PropTypes.func,
+    peripheralId: PropTypes.string,
+    rssi: PropTypes.number,
+    smallDeviceImage: PropTypes.string
+};
+
+export default DeviceTile;
diff --git a/src/components/connection-modal/dots.jsx b/src/components/connection-modal/dots.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..23814eaf75ecffed01d5f964da940e8c22277448
--- /dev/null
+++ b/src/components/connection-modal/dots.jsx
@@ -0,0 +1,59 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import classNames from 'classnames';
+
+import Box from '../box/box.jsx';
+import styles from './connection-modal.css';
+
+const Dots = props => (
+    <Box className={styles.dotsRow}>
+        <div
+            className={classNames(
+                styles.dotsHolder,
+                {
+                    [styles.dotsHolderError]: props.error,
+                    [styles.dotsHolderSuccess]: props.success
+                }
+            )}
+        >
+            {Array(props.total).fill(0)
+                .map((_, i) => {
+                    let type = 'inactive';
+                    if (props.counter === i) type = 'active';
+                    if (props.success) type = 'success';
+                    if (props.error) type = 'error';
+                    return (<Dot
+                        key={`dot-${i}`}
+                        type={type}
+                    />);
+                })}
+        </div>
+    </Box>
+);
+
+Dots.propTypes = {
+    counter: PropTypes.number,
+    error: PropTypes.bool,
+    success: PropTypes.bool,
+    total: PropTypes.number
+};
+
+const Dot = props => (
+    <div
+        className={classNames(
+            styles.dot,
+            {
+                [styles.inactiveStepDot]: props.type === 'inactive',
+                [styles.activeStepDot]: props.type === 'active',
+                [styles.successDot]: props.type === 'success',
+                [styles.errorDot]: props.type === 'error'
+            }
+        )}
+    />
+);
+
+Dot.propTypes = {
+    type: PropTypes.string
+};
+
+export default Dots;
diff --git a/src/components/connection-modal/error-step.jsx b/src/components/connection-modal/error-step.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..681d74b72a2b278b13ae23d39d853becf5b4116d
--- /dev/null
+++ b/src/components/connection-modal/error-step.jsx
@@ -0,0 +1,76 @@
+import {FormattedMessage} from 'react-intl';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Box from '../box/box.jsx';
+import Dots from './dots.jsx';
+import helpIcon from './icons/help.svg';
+import backIcon from './icons/back.svg';
+
+import styles from './connection-modal.css';
+
+const ErrorStep = props => (
+    <Box className={styles.body}>
+        <Box className={styles.activityArea}>
+            <Box className={styles.centeredRow}>
+                <div className={styles.deviceActivity}>
+                    <img
+                        className={styles.deviceActivityIcon}
+                        src={props.deviceImage}
+                    />
+                </div>
+            </Box>
+        </Box>
+        <Box className={styles.bottomArea}>
+            <div className={styles.instructions}>
+                <FormattedMessage
+                    defaultMessage="Oops, looks like something went wrong."
+                    description="The device connection process has encountered an error."
+                    id="gui.connection.errorMessage"
+                />
+            </div>
+            <Dots
+                error
+                total={3}
+            />
+            <Box className={styles.buttonRow}>
+                <button
+                    className={styles.connectionButton}
+                    onClick={props.onScanning}
+                >
+                    <img
+                        className={styles.buttonIconLeft}
+                        src={backIcon}
+                    />
+                    <FormattedMessage
+                        defaultMessage="Try again"
+                        description="Button to initiate trying the device connection again after an error"
+                        id="gui.connection.tryagainbutton"
+                    />
+                </button>
+                <button
+                    className={styles.connectionButton}
+                    onClick={props.onHelp}
+                >
+                    <img
+                        className={styles.buttonIconLeft}
+                        src={helpIcon}
+                    />
+                    <FormattedMessage
+                        defaultMessage="Help"
+                        description="Button to view help content"
+                        id="gui.connection.helpbutton"
+                    />
+                </button>
+            </Box>
+        </Box>
+    </Box>
+);
+
+ErrorStep.propTypes = {
+    deviceImage: PropTypes.string.isRequired,
+    onHelp: PropTypes.func,
+    onScanning: PropTypes.func
+};
+
+export default ErrorStep;
diff --git a/src/components/connection-modal/icons/back.svg b/src/components/connection-modal/icons/back.svg
new file mode 100644
index 0000000000000000000000000000000000000000..42f7508f279eaeee36aac930e3f343d2bfc7c518
Binary files /dev/null and b/src/components/connection-modal/icons/back.svg differ
diff --git a/src/components/connection-modal/icons/bluetooth-white.svg b/src/components/connection-modal/icons/bluetooth-white.svg
new file mode 100644
index 0000000000000000000000000000000000000000..df2ae141ebce92e1af1ad8f3f6e90b57c8248225
Binary files /dev/null and b/src/components/connection-modal/icons/bluetooth-white.svg differ
diff --git a/src/components/connection-modal/icons/cancel.svg b/src/components/connection-modal/icons/cancel.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b30decdb65a22a832208426f4258a5fa1dea00b7
Binary files /dev/null and b/src/components/connection-modal/icons/cancel.svg differ
diff --git a/src/components/connection-modal/icons/close.svg b/src/components/connection-modal/icons/close.svg
new file mode 100644
index 0000000000000000000000000000000000000000..a537fc800d01115552a00073103be09cf5ce9fcf
Binary files /dev/null and b/src/components/connection-modal/icons/close.svg differ
diff --git a/src/components/connection-modal/icons/help.svg b/src/components/connection-modal/icons/help.svg
new file mode 100644
index 0000000000000000000000000000000000000000..2938e8340ebb54dd699f80eaf48794bd383a96a4
Binary files /dev/null and b/src/components/connection-modal/icons/help.svg differ
diff --git a/src/components/connection-modal/icons/refresh.svg b/src/components/connection-modal/icons/refresh.svg
new file mode 100644
index 0000000000000000000000000000000000000000..3d4aebb47071a08f9214c5e4c5eafb035e2b86ea
Binary files /dev/null and b/src/components/connection-modal/icons/refresh.svg differ
diff --git a/src/components/connection-modal/icons/searching.png b/src/components/connection-modal/icons/searching.png
new file mode 100644
index 0000000000000000000000000000000000000000..260f3227f2ef09cc1aa6fbca0fc928e2b5be0e28
Binary files /dev/null and b/src/components/connection-modal/icons/searching.png differ
diff --git a/src/components/connection-modal/scanning-step.jsx b/src/components/connection-modal/scanning-step.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..1728e1fd5d55df75790f0301ef00386783d95b15
--- /dev/null
+++ b/src/components/connection-modal/scanning-step.jsx
@@ -0,0 +1,103 @@
+import {FormattedMessage} from 'react-intl';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Box from '../box/box.jsx';
+import DeviceTile from './device-tile.jsx';
+import Dots from './dots.jsx';
+
+import radarIcon from './icons/searching.png';
+import refreshIcon from './icons/refresh.svg';
+
+import styles from './connection-modal.css';
+
+const ScanningStep = props => (
+    <Box className={styles.body}>
+        <Box className={styles.activityArea}>
+            {props.scanning ? (
+                props.deviceList.length === 0 ? (
+                    <div className={styles.activityAreaInfo}>
+                        <div className={styles.centeredRow}>
+                            <img
+                                className={styles.radar}
+                                src={radarIcon}
+                            />
+                            <FormattedMessage
+                                defaultMessage="Looking for devices"
+                                description="Text shown while scanning for devices"
+                                id="gui.connection.scanning.lookingfordevices"
+                            />
+                        </div>
+                    </div>
+                ) : (
+                    <Box className={styles.deviceTilePane}>
+                        {props.deviceList.map(device =>
+                            (<DeviceTile
+                                key={device.peripheralId}
+                                name={device.name}
+                                peripheralId={device.peripheralId}
+                                rssi={device.rssi}
+                                smallDeviceImage={props.smallDeviceImage}
+                                onConnecting={props.onConnecting}
+                            />)
+                        )}
+                    </Box>
+                )
+            ) : (
+                <Box className={styles.instructions}>
+                    <FormattedMessage
+                        defaultMessage="No devices found"
+                        description="Text shown when no devices could be found"
+                        id="gui.connection.scanning.noDevicesFound"
+                    />
+                </Box>
+            )}
+        </Box>
+        <Box className={styles.bottomArea}>
+            <Box className={styles.instructions}>
+                <FormattedMessage
+                    defaultMessage="Select your device in the list above."
+                    description="Prompt for choosing a device to connect to"
+                    id="gui.connection.scanning.instructions"
+                />
+            </Box>
+            <Dots
+                counter={0}
+                total={3}
+            />
+            <button
+                className={styles.connectionButton}
+                onClick={props.onRefresh}
+            >
+                <FormattedMessage
+                    defaultMessage="Refresh"
+                    description="Button in prompt for starting a search"
+                    id="gui.connection.search"
+                />
+                <img
+                    className={styles.buttonIconRight}
+                    src={refreshIcon}
+                />
+            </button>
+        </Box>
+    </Box>
+);
+
+ScanningStep.propTypes = {
+    deviceList: PropTypes.arrayOf(PropTypes.shape({
+        name: PropTypes.string,
+        rssi: PropTypes.number,
+        peripheralId: PropTypes.string
+    })),
+    onConnecting: PropTypes.func,
+    onRefresh: PropTypes.func,
+    scanning: PropTypes.bool.isRequired,
+    smallDeviceImage: PropTypes.string
+};
+
+ScanningStep.defaultProps = {
+    deviceList: [],
+    scanning: true
+};
+
+export default ScanningStep;
diff --git a/src/components/import-modal/import-modal.css b/src/components/import-modal/import-modal.css
index b41c02b1baaa92923fc92af9ecbe3d22667cef1f..b265efae02fc5ed6c7348a4422d9b84e9e474fa0 100644
--- a/src/components/import-modal/import-modal.css
+++ b/src/components/import-modal/import-modal.css
@@ -45,7 +45,7 @@ $sides: 20rem;
 
     box-sizing: border-box;
     width: 100%;
-    background-color: $pen-primary;
+    background-color: $extensions-primary;
 }
 
 .header-item {
@@ -129,12 +129,12 @@ $sides: 20rem;
     font-weight: bold;
     font-size: .875rem;
     cursor: pointer;
-    border: 0px solid $pen-primary;
+    border: 0px solid $extensions-primary;
     outline: none;
 }
 
 .input-row button.ok-button {
-    background: $pen-primary;
+    background: $extensions-primary;
     color: white;
 }
 
diff --git a/src/components/library-item/library-item.jsx b/src/components/library-item/library-item.jsx
index 8977d3f931d2069b805a8347ef887f69d78953e5..19e88bc6ae5fbca3ce3892f67b812c74d108492b 100644
--- a/src/components/library-item/library-item.jsx
+++ b/src/components/library-item/library-item.jsx
@@ -106,7 +106,10 @@ class LibraryItem extends React.PureComponent {
 }
 
 LibraryItem.propTypes = {
-    description: PropTypes.string,
+    description: PropTypes.oneOfType([
+        PropTypes.string,
+        PropTypes.node
+    ]),
     disabled: PropTypes.bool,
     featured: PropTypes.bool,
     iconURL: PropTypes.string.isRequired,
diff --git a/src/components/menu-bar/icon--help.svg b/src/components/menu-bar/icon--help.svg
deleted file mode 100644
index 6974a7f45f8c740074060a3414eadc02cefd0084..0000000000000000000000000000000000000000
Binary files a/src/components/menu-bar/icon--help.svg and /dev/null differ
diff --git a/src/components/menu-bar/menu-bar.css b/src/components/menu-bar/menu-bar.css
index eba5f885eff82eae922578bdb57acaa75efbecd0..45669f8d6ed979207c8d2774b55504df885118c0 100644
--- a/src/components/menu-bar/menu-bar.css
+++ b/src/components/menu-bar/menu-bar.css
@@ -151,9 +151,7 @@
 }
 
 .help-icon {
-    height: 2rem;
-    width: 3rem;
-    margin-top: 0.5rem;
+    margin-right: 0.35rem;
 }
 
 .account-nav-menu, .mystuff-button {
diff --git a/src/components/menu-bar/menu-bar.jsx b/src/components/menu-bar/menu-bar.jsx
index 164e9c78e7160686b988084d6fddfabf003e0ffc..b843e05b45aafbbd4b817b7c097d7d4586315ee2 100644
--- a/src/components/menu-bar/menu-bar.jsx
+++ b/src/components/menu-bar/menu-bar.jsx
@@ -2,6 +2,7 @@ import classNames from 'classnames';
 import {connect} from 'react-redux';
 import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-intl';
 import PropTypes from 'prop-types';
+import bindAll from 'lodash.bindall';
 import React from 'react';
 
 import Box from '../box/box.jsx';
@@ -30,6 +31,7 @@ import {
 
 import styles from './menu-bar.css';
 
+import helpIcon from '../../lib/assets/icon--tutorials.svg';
 import mystuffIcon from './icon--mystuff.png';
 import feedbackIcon from './icon--feedback.svg';
 import profileIcon from './icon--profile.png';
@@ -39,18 +41,16 @@ import languageIcon from '../language-selector/language-icon.svg';
 
 import scratchLogo from './scratch-logo.svg';
 
-import helpIcon from './icon--help.svg';
-
 const ariaMessages = defineMessages({
     language: {
         id: 'gui.menuBar.LanguageSelector',
         defaultMessage: 'language selector',
         description: 'accessibility text for the language selection menu'
     },
-    howTo: {
-        id: 'gui.menuBar.howToLibrary',
-        defaultMessage: 'How-to Library',
-        description: 'accessibility text for the how-to library button'
+    tutorials: {
+        id: 'gui.menuBar.tutorialsLibrary',
+        defaultMessage: 'Tutorials',
+        description: 'accessibility text for the tutorials button'
     }
 });
 
@@ -128,297 +128,313 @@ MenuBarMenu.propTypes = {
     open: PropTypes.bool,
     place: PropTypes.oneOf(['left', 'right'])
 };
-
-const MenuBar = props => (
-    <Box className={styles.menuBar}>
-        <div className={styles.mainMenu}>
-            <div className={styles.fileGroup}>
-                <div className={classNames(styles.menuBarItem)}>
-                    <img
-                        alt="Scratch"
-                        className={styles.scratchLogo}
-                        draggable={false}
-                        src={scratchLogo}
-                    />
-                </div>
-                <div
-                    className={classNames(styles.menuBarItem, styles.hoverable, {
-                        [styles.active]: props.languageMenuOpen
-                    })}
-                    onMouseUp={props.onClickLanguage}
-                >
-                    <MenuBarItemTooltip
-                        enable={window.location.search.indexOf('enable=language') !== -1}
-                        id="menubar-selector"
-                        place="right"
-                    >
-                        <div
-                            aria-label={props.intl.formatMessage(ariaMessages.language)}
-                            className={classNames(styles.languageMenu)}
-                        >
-                            <img
-                                className={styles.languageIcon}
-                                src={languageIcon}
-                            />
+class MenuBar extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, [
+            'handleLanguageMouseUp'
+        ]);
+    }
+    handleLanguageMouseUp (e) {
+        if (!this.props.languageMenuOpen) {
+            this.props.onClickLanguage(e);
+        }
+    }
+    render () {
+        return (
+            <Box className={styles.menuBar}>
+                <div className={styles.mainMenu}>
+                    <div className={styles.fileGroup}>
+                        <div className={classNames(styles.menuBarItem)}>
                             <img
-                                className={styles.dropdownCaret}
-                                src={dropdownCaret}
+                                alt="Scratch"
+                                className={styles.scratchLogo}
+                                draggable={false}
+                                src={scratchLogo}
                             />
                         </div>
-                        <MenuBarMenu
-                            open={props.languageMenuOpen}
-                            onRequestClose={props.onRequestCloseLanguage}
+                        <div
+                            className={classNames(styles.menuBarItem, styles.hoverable, {
+                                [styles.active]: this.props.languageMenuOpen
+                            })}
+                            onMouseUp={this.handleLanguageMouseUp}
                         >
-                            <LanguageSelector />
-                        </MenuBarMenu>
-
-                    </MenuBarItemTooltip>
-                </div>
-                <div
-                    className={classNames(styles.menuBarItem, styles.hoverable, {
-                        [styles.active]: props.fileMenuOpen
-                    })}
-                    onMouseUp={props.onClickFile}
-                >
-                    <div className={classNames(styles.fileMenu)}>
-                        <FormattedMessage
-                            defaultMessage="File"
-                            description="Text for file dropdown menu"
-                            id="gui.menuBar.file"
-                        />
-                    </div>
-                    <MenuBarMenu
-                        open={props.fileMenuOpen}
-                        onRequestClose={props.onRequestCloseFile}
-                    >
-                        <MenuItemTooltip id="new">
-                            <MenuItem>
-                                <FormattedMessage
-                                    defaultMessage="New"
-                                    description="Menu bar item for creating a new project"
-                                    id="gui.menuBar.new"
-                                />
-                            </MenuItem>
-                        </MenuItemTooltip>
-                        <MenuSection>
-                            <MenuItemTooltip id="save">
-                                <MenuItem>
-                                    <FormattedMessage
-                                        defaultMessage="Save now"
-                                        description="Menu bar item for saving now"
-                                        id="gui.menuBar.saveNow"
-                                    />
-                                </MenuItem>
-                            </MenuItemTooltip>
-                            <MenuItemTooltip id="copy">
-                                <MenuItem>
-                                    <FormattedMessage
-                                        defaultMessage="Save as a copy"
-                                        description="Menu bar item for saving as a copy"
-                                        id="gui.menuBar.saveAsCopy"
-                                    /></MenuItem>
-                            </MenuItemTooltip>
-                        </MenuSection>
-                        <MenuSection>
-                            <ProjectLoader>{(renderFileInput, loadProject, loadProps) => (
-                                <MenuItem
-                                    onClick={loadProject}
-                                    {...loadProps}
+                            <MenuBarItemTooltip
+                                enable={window.location.search.indexOf('enable=language') !== -1}
+                                id="menubar-selector"
+                                place="right"
+                            >
+                                <div
+                                    aria-label={this.props.intl.formatMessage(ariaMessages.language)}
+                                    className={classNames(styles.languageMenu)}
                                 >
-                                    <FormattedMessage
-                                        defaultMessage="Load from your computer"
-                                        description="Menu bar item for uploading a project from your computer"
-                                        id="gui.menuBar.uploadFromComputer"
+                                    <img
+                                        className={styles.languageIcon}
+                                        src={languageIcon}
                                     />
-                                    {renderFileInput()}
-                                </MenuItem>
-                            )}</ProjectLoader>
-                            <ProjectSaver>{(saveProject, saveProps) => (
-                                <MenuItem
-                                    onClick={saveProject}
-                                    {...saveProps}
-                                >
-                                    <FormattedMessage
-                                        defaultMessage="Save to your computer"
-                                        description="Menu bar item for downloading a project to your computer"
-                                        id="gui.menuBar.downloadToComputer"
+                                    <img
+                                        className={styles.dropdownCaret}
+                                        src={dropdownCaret}
                                     />
-                                </MenuItem>
-                            )}</ProjectSaver>
-                        </MenuSection>
-                    </MenuBarMenu>
-                </div>
-                <div
-                    className={classNames(styles.menuBarItem, styles.hoverable, {
-                        [styles.active]: props.editMenuOpen
-                    })}
-                    onMouseUp={props.onClickEdit}
-                >
-                    <div className={classNames(styles.editMenu)}>
-                        <FormattedMessage
-                            defaultMessage="Edit"
-                            description="Text for edit dropdown menu"
-                            id="gui.menuBar.edit"
-                        />
+                                </div>
+                                <MenuBarMenu
+                                    open={this.props.languageMenuOpen}
+                                    onRequestClose={this.props.onRequestCloseLanguage}
+                                >
+                                    <LanguageSelector />
+                                </MenuBarMenu>
+
+                            </MenuBarItemTooltip>
+                        </div>
+                        <div
+                            className={classNames(styles.menuBarItem, styles.hoverable, {
+                                [styles.active]: this.props.fileMenuOpen
+                            })}
+                            onMouseUp={this.props.onClickFile}
+                        >
+                            <div className={classNames(styles.fileMenu)}>
+                                <FormattedMessage
+                                    defaultMessage="File"
+                                    description="Text for file dropdown menu"
+                                    id="gui.menuBar.file"
+                                />
+                            </div>
+                            <MenuBarMenu
+                                open={this.props.fileMenuOpen}
+                                onRequestClose={this.props.onRequestCloseFile}
+                            >
+                                <MenuItemTooltip id="new">
+                                    <MenuItem>
+                                        <FormattedMessage
+                                            defaultMessage="New"
+                                            description="Menu bar item for creating a new project"
+                                            id="gui.menuBar.new"
+                                        />
+                                    </MenuItem>
+                                </MenuItemTooltip>
+                                <MenuSection>
+                                    <MenuItemTooltip id="save">
+                                        <MenuItem>
+                                            <FormattedMessage
+                                                defaultMessage="Save now"
+                                                description="Menu bar item for saving now"
+                                                id="gui.menuBar.saveNow"
+                                            />
+                                        </MenuItem>
+                                    </MenuItemTooltip>
+                                    <MenuItemTooltip id="copy">
+                                        <MenuItem>
+                                            <FormattedMessage
+                                                defaultMessage="Save as a copy"
+                                                description="Menu bar item for saving as a copy"
+                                                id="gui.menuBar.saveAsCopy"
+                                            /></MenuItem>
+                                    </MenuItemTooltip>
+                                </MenuSection>
+                                <MenuSection>
+                                    <ProjectLoader>{(renderFileInput, loadProject, loadProps) => (
+                                        <MenuItem
+                                            onClick={loadProject}
+                                            {...loadProps}
+                                        >
+                                            <FormattedMessage
+                                                defaultMessage="Load from your computer"
+                                                description="Menu bar item for uploading a project from your computer"
+                                                id="gui.menuBar.uploadFromComputer"
+                                            />
+                                            {renderFileInput()}
+                                        </MenuItem>
+                                    )}</ProjectLoader>
+                                    <ProjectSaver>{(saveProject, saveProps) => (
+                                        <MenuItem
+                                            onClick={saveProject}
+                                            {...saveProps}
+                                        >
+                                            <FormattedMessage
+                                                defaultMessage="Save to your computer"
+                                                description="Menu bar item for downloading a project to your computer"
+                                                id="gui.menuBar.downloadToComputer"
+                                            />
+                                        </MenuItem>
+                                    )}</ProjectSaver>
+                                </MenuSection>
+                            </MenuBarMenu>
+                        </div>
+                        <div
+                            className={classNames(styles.menuBarItem, styles.hoverable, {
+                                [styles.active]: this.props.editMenuOpen
+                            })}
+                            onMouseUp={this.props.onClickEdit}
+                        >
+                            <div className={classNames(styles.editMenu)}>
+                                <FormattedMessage
+                                    defaultMessage="Edit"
+                                    description="Text for edit dropdown menu"
+                                    id="gui.menuBar.edit"
+                                />
+                            </div>
+                            <MenuBarMenu
+                                open={this.props.editMenuOpen}
+                                onRequestClose={this.props.onRequestCloseEdit}
+                            >
+                                <MenuItemTooltip id="undo">
+                                    <MenuItem>
+                                        <FormattedMessage
+                                            defaultMessage="Undo"
+                                            description="Menu bar item for undoing"
+                                            id="gui.menuBar.undo"
+                                        />
+                                    </MenuItem>
+                                </MenuItemTooltip>
+                                <MenuItemTooltip id="redo">
+                                    <MenuItem>
+                                        <FormattedMessage
+                                            defaultMessage="Redo"
+                                            description="Menu bar item for redoing"
+                                            id="gui.menuBar.redo"
+                                        />
+                                    </MenuItem>
+                                </MenuItemTooltip>
+                                <MenuSection>
+                                    <MenuItemTooltip id="turbo">
+                                        <MenuItem>
+                                            <FormattedMessage
+                                                defaultMessage="Turbo mode"
+                                                description="Menu bar item for toggling turbo mode"
+                                                id="gui.menuBar.turboMode"
+                                            />
+                                        </MenuItem>
+                                    </MenuItemTooltip>
+                                </MenuSection>
+                            </MenuBarMenu>
+                        </div>
                     </div>
-                    <MenuBarMenu
-                        open={props.editMenuOpen}
-                        onRequestClose={props.onRequestCloseEdit}
+                    <Divider className={classNames(styles.divider)} />
+                    <div
+                        aria-label={this.props.intl.formatMessage(ariaMessages.tutorials)}
+                        className={classNames(styles.menuBarItem, styles.hoverable)}
+                        onClick={this.props.onOpenTipLibrary}
                     >
-                        <MenuItemTooltip id="undo">
-                            <MenuItem>
+                        <img
+                            className={styles.helpIcon}
+                            src={helpIcon}
+                        />
+                        <FormattedMessage {...ariaMessages.tutorials} />
+                    </div>
+                    <Divider className={classNames(styles.divider)} />
+                    <div className={classNames(styles.menuBarItem)}>
+                        <MenuBarItemTooltip id="title-field">
+                            <input
+                                disabled
+                                className={classNames(styles.titleField)}
+                                placeholder="Untitled-1"
+                            />
+                        </MenuBarItemTooltip>
+                    </div>
+                    <div className={classNames(styles.menuBarItem)}>
+                        <MenuBarItemTooltip id="share-button">
+                            <Button className={classNames(styles.shareButton)}>
                                 <FormattedMessage
-                                    defaultMessage="Undo"
-                                    description="Menu bar item for undoing"
-                                    id="gui.menuBar.undo"
+                                    defaultMessage="Share"
+                                    description="Label for project share button"
+                                    id="gui.menuBar.share"
                                 />
-                            </MenuItem>
-                        </MenuItemTooltip>
-                        <MenuItemTooltip id="redo">
-                            <MenuItem>
+                            </Button>
+                        </MenuBarItemTooltip>
+                    </div>
+                    <div className={classNames(styles.menuBarItem, styles.communityButtonWrapper)}>
+                        {this.props.enableCommunity ?
+                            <Button
+                                className={classNames(styles.communityButton)}
+                                iconClassName={styles.communityButtonIcon}
+                                iconSrc={communityIcon}
+                                onClick={this.props.onSeeCommunity}
+                            >
                                 <FormattedMessage
-                                    defaultMessage="Redo"
-                                    description="Menu bar item for redoing"
-                                    id="gui.menuBar.redo"
+                                    defaultMessage="See Community"
+                                    description="Label for see community button"
+                                    id="gui.menuBar.seeCommunity"
                                 />
-                            </MenuItem>
-                        </MenuItemTooltip>
-                        <MenuSection>
-                            <MenuItemTooltip id="turbo">
-                                <MenuItem>
+                            </Button> :
+                            <MenuBarItemTooltip id="community-button">
+                                <Button
+                                    className={classNames(styles.communityButton)}
+                                    iconClassName={styles.communityButtonIcon}
+                                    iconSrc={communityIcon}
+                                >
                                     <FormattedMessage
-                                        defaultMessage="Turbo mode"
-                                        description="Menu bar item for toggling turbo mode"
-                                        id="gui.menuBar.turboMode"
+                                        defaultMessage="See Community"
+                                        description="Label for see community button"
+                                        id="gui.menuBar.seeCommunity"
                                     />
-                                </MenuItem>
-                            </MenuItemTooltip>
-                        </MenuSection>
-                    </MenuBarMenu>
+                                </Button>
+                            </MenuBarItemTooltip>
+                        }
+                    </div>
                 </div>
-            </div>
-            <Divider className={classNames(styles.divider)} />
-            <div className={classNames(styles.menuBarItem)}>
-                <MenuBarItemTooltip id="title-field">
-                    <input
-                        disabled
-                        className={classNames(styles.titleField)}
-                        placeholder="Untitled-1"
-                    />
-                </MenuBarItemTooltip>
-            </div>
-            <div className={classNames(styles.menuBarItem)}>
-                <MenuBarItemTooltip id="share-button">
-                    <Button className={classNames(styles.shareButton)}>
-                        <FormattedMessage
-                            defaultMessage="Share"
-                            description="Label for project share button"
-                            id="gui.menuBar.share"
-                        />
-                    </Button>
-                </MenuBarItemTooltip>
-            </div>
-            <div className={classNames(styles.menuBarItem, styles.communityButtonWrapper)}>
-                {props.enableCommunity ?
-                    <Button
-                        className={classNames(styles.communityButton)}
-                        iconClassName={styles.communityButtonIcon}
-                        iconSrc={communityIcon}
-                        onClick={props.onSeeCommunity}
+                <div className={classNames(styles.menuBarItem, styles.feedbackButtonWrapper)}>
+                    <a
+                        className={styles.feedbackLink}
+                        href="https://scratch.mit.edu/discuss/topic/299791/"
+                        rel="noopener noreferrer"
+                        target="_blank"
                     >
-                        <FormattedMessage
-                            defaultMessage="See Community"
-                            description="Label for see community button"
-                            id="gui.menuBar.seeCommunity"
-                        />
-                    </Button> :
-                    <MenuBarItemTooltip id="community-button">
                         <Button
-                            className={classNames(styles.communityButton)}
-                            iconClassName={styles.communityButtonIcon}
-                            iconSrc={communityIcon}
+                            className={styles.feedbackButton}
+                            iconSrc={feedbackIcon}
                         >
                             <FormattedMessage
-                                defaultMessage="See Community"
-                                description="Label for see community button"
-                                id="gui.menuBar.seeCommunity"
+                                defaultMessage="Give Feedback"
+                                description="Label for feedback form modal button"
+                                id="gui.menuBar.giveFeedback"
                             />
                         </Button>
-                    </MenuBarItemTooltip>
-                }
-            </div>
-        </div>
-        <div className={classNames(styles.menuBarItem, styles.feedbackButtonWrapper)}>
-            <a
-                className={styles.feedbackLink}
-                href="https://scratch.mit.edu/discuss/topic/299791/"
-                rel="noopener noreferrer"
-                target="_blank"
-            >
-                <Button
-                    className={styles.feedbackButton}
-                    iconSrc={feedbackIcon}
-                >
-                    <FormattedMessage
-                        defaultMessage="Give Feedback"
-                        description="Label for feedback form modal button"
-                        id="gui.menuBar.giveFeedback"
-                    />
-                </Button>
-            </a>
-        </div>
-        <div className={styles.accountInfoWrapper}>
-            <div
-                aria-label={props.intl.formatMessage(ariaMessages.howTo)}
-                className={classNames(styles.menuBarItem, styles.hoverable)}
-                onClick={props.onOpenTipLibrary}
-            >
-                <img
-                    className={styles.helpIcon}
-                    src={helpIcon}
-                />
-            </div>
-            <MenuBarItemTooltip id="mystuff">
-                <div
-                    className={classNames(
-                        styles.menuBarItem,
-                        styles.hoverable,
-                        styles.mystuffButton
-                    )}
-                >
-                    <img
-                        className={styles.mystuffIcon}
-                        src={mystuffIcon}
-                    />
+                    </a>
                 </div>
-            </MenuBarItemTooltip>
-            <MenuBarItemTooltip
-                id="account-nav"
-                place="left"
-            >
-                <div
-                    className={classNames(
-                        styles.menuBarItem,
-                        styles.hoverable,
-                        styles.accountNavMenu
-                    )}
-                >
-                    <img
-                        className={styles.profileIcon}
-                        src={profileIcon}
-                    />
-                    <span>
-                        {'scratch-cat' /* @todo username */}
-                    </span>
-                    <img
-                        className={styles.dropdownCaretIcon}
-                        src={dropdownCaret}
-                    />
+                <div className={styles.accountInfoWrapper}>
+                    <MenuBarItemTooltip id="mystuff">
+                        <div
+                            className={classNames(
+                                styles.menuBarItem,
+                                styles.hoverable,
+                                styles.mystuffButton
+                            )}
+                        >
+                            <img
+                                className={styles.mystuffIcon}
+                                src={mystuffIcon}
+                            />
+                        </div>
+                    </MenuBarItemTooltip>
+                    <MenuBarItemTooltip
+                        id="account-nav"
+                        place="left"
+                    >
+                        <div
+                            className={classNames(
+                                styles.menuBarItem,
+                                styles.hoverable,
+                                styles.accountNavMenu
+                            )}
+                        >
+                            <img
+                                className={styles.profileIcon}
+                                src={profileIcon}
+                            />
+                            <span>
+                                {'scratch-cat' /* @todo username */}
+                            </span>
+                            <img
+                                className={styles.dropdownCaretIcon}
+                                src={dropdownCaret}
+                            />
+                        </div>
+                    </MenuBarItemTooltip>
                 </div>
-            </MenuBarItemTooltip>
-        </div>
-    </Box>
-);
+            </Box>
+        );
+    }
+}
 
 MenuBar.propTypes = {
     editMenuOpen: PropTypes.bool,
diff --git a/src/components/modal/modal.css b/src/components/modal/modal.css
index 3aa21280beba80b61181349e5ae8a1bc38b52459..9a5a035a7de18edba2d6d5343fdc4fa97f213878 100644
--- a/src/components/modal/modal.css
+++ b/src/components/modal/modal.css
@@ -83,6 +83,10 @@ $sides: 20rem;
     user-select: none;
 }
 
+.header-image {
+    margin-right: 0.5rem;
+}
+
 .header-item-filter {
     display: flex;
     flex-basis: $sides;
diff --git a/src/components/modal/modal.jsx b/src/components/modal/modal.jsx
index dff3ce8537b748e0c5c554d25652b8f30615efdc..940af75586f59e05291f9970b5bf972f353ccdb3 100644
--- a/src/components/modal/modal.jsx
+++ b/src/components/modal/modal.jsx
@@ -26,13 +26,19 @@ const ModalComponent = props => (
             direction="column"
             grow={1}
         >
-            <div className={styles.header}>
+            <div className={classNames(styles.header, props.headerClassName)}>
                 <div
                     className={classNames(
                         styles.headerItem,
                         styles.headerItemTitle
                     )}
                 >
+                    {props.headerImage ? (
+                        <img
+                            className={styles.headerImage}
+                            src={props.headerImage}
+                        />
+                    ) : null}
                     {props.contentLabel}
                 </div>
                 <div
@@ -74,6 +80,8 @@ ModalComponent.propTypes = {
         PropTypes.object
     ]).isRequired,
     fullScreen: PropTypes.bool,
+    headerClassName: PropTypes.string,
+    headerImage: PropTypes.string,
     onRequestClose: PropTypes.func
 };
 
diff --git a/src/components/preview-modal/preview-modal.css b/src/components/preview-modal/preview-modal.css
index 2c35acf63e0f78fbca407f74b063e691e105f2ec..d6cf6dc4568fd5178ea0849bbd92551838d14bf9 100644
--- a/src/components/preview-modal/preview-modal.css
+++ b/src/components/preview-modal/preview-modal.css
@@ -69,8 +69,8 @@
 }
 
 .button-row button.view-project-button {
-    background: $pen-primary;
-    border-color: $pen-primary;
+    background: $extensions-primary;
+    border-color: $extensions-primary;
     color: white;
 }
 
diff --git a/src/components/stage-selector/stage-selector.css b/src/components/stage-selector/stage-selector.css
index e845160faee34e2c5768d08883f121079ad06275..4e35dd4b68fbbbfa2b4794510beaa2cd22b83b50 100644
--- a/src/components/stage-selector/stage-selector.css
+++ b/src/components/stage-selector/stage-selector.css
@@ -20,10 +20,12 @@ $header-height: calc($stage-menu-height - 2px);
     border-style: solid;
     border-bottom: 0;
     cursor: pointer;
-    transition: border-color 0.25s ease-out, box-shadow 0.25s ease-out;
+    transition: all 0.25s ease;
 }
 
 .stage-selector.is-selected {
+    border-top-left-radius: .625rem;
+    border-top-right-radius: .625rem;
     border-color: $motion-primary;
     box-shadow: 0px 0px 0px 4px $motion-transparent;
 }
@@ -44,6 +46,7 @@ $header-height: calc($stage-menu-height - 2px);
     border-top-right-radius: $space;
     border-bottom: 1px solid $ui-black-transparent;
     width: 100%;
+    transition: background-color 0.25s ease;
 }
 
 .header-title {
@@ -53,6 +56,15 @@ $header-height: calc($stage-menu-height - 2px);
 
     /* @todo: make this a mixin for all UI text labels */
     user-select: none;
+    transition: color 0.25s ease;
+}
+
+.stage-selector.is-selected .header {
+    background-color: $motion-primary;
+}
+
+.stage-selector.is-selected .header-title {
+    color: $ui-white;
 }
 
 .count {
@@ -71,9 +83,11 @@ $header-height: calc($stage-menu-height - 2px);
 
 .costume-canvas {
     display: block;
+    margin-top: .25rem;
     width: 100%;
     user-select: none;
-    border-bottom: 1px solid $ui-black-transparent;
+    border: 1px solid $ui-black-transparent;
+    border-radius: .25rem;
     box-shadow: inset 0 0 4px $ui-black-transparent;
 }
 
diff --git a/src/components/stage-selector/stage-selector.jsx b/src/components/stage-selector/stage-selector.jsx
index 9d40d3c249e9d413a89bbfdc9d8f15e82b6ebf98..50161bf8cbbfbc389ddcbd196201badfea408687 100644
--- a/src/components/stage-selector/stage-selector.jsx
+++ b/src/components/stage-selector/stage-selector.jsx
@@ -80,9 +80,9 @@ const StageSelector = props => {
             {url ? (
                 <CostumeCanvas
                     className={styles.costumeCanvas}
-                    height={54}
+                    height={48}
                     url={url}
-                    width={72}
+                    width={64}
                 />
             ) : null}
             <div className={styles.label}>
diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx
index 40ad9234ed774d4bdbe0b3e0cc8ee78a14de89e7..c81c5d21ad6bc843712795eec0c8d37655db91a0 100644
--- a/src/containers/blocks.jsx
+++ b/src/containers/blocks.jsx
@@ -9,8 +9,10 @@ import VM from 'scratch-vm';
 
 import analytics from '../lib/analytics';
 import Prompt from './prompt.jsx';
+import ConnectionModal from './connection-modal.jsx';
 import BlocksComponent from '../components/blocks/blocks.jsx';
 import ExtensionLibrary from './extension-library.jsx';
+import extensionData from '../lib/libraries/extensions/index.jsx';
 import CustomProcedures from './custom-procedures.jsx';
 import errorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
 import {STAGE_DISPLAY_SIZES} from '../lib/layout-constants';
@@ -38,6 +40,9 @@ class Blocks extends React.Component {
             'attachVM',
             'detachVM',
             'handleCategorySelected',
+            'handleConnectionModalStart',
+            'handleConnectionModalClose',
+            'handleStatusButtonUpdate',
             'handlePromptStart',
             'handlePromptCallback',
             'handlePromptClose',
@@ -56,9 +61,11 @@ class Blocks extends React.Component {
             'setLocale'
         ]);
         this.ScratchBlocks.prompt = this.handlePromptStart;
+        this.ScratchBlocks.statusButtonCallback = this.handleConnectionModalStart;
         this.state = {
             workspaceMetrics: {},
-            prompt: null
+            prompt: null,
+            connectionModal: null
         };
         this.onTargetsUpdate = debounce(this.onTargetsUpdate, 100);
         this.toolboxUpdateQueue = [];
@@ -94,6 +101,7 @@ class Blocks extends React.Component {
     shouldComponentUpdate (nextProps, nextState) {
         return (
             this.state.prompt !== nextState.prompt ||
+            this.state.connectionModal !== nextState.connectionModal ||
             this.props.isVisible !== nextProps.isVisible ||
             this.props.toolboxXML !== nextProps.toolboxXML ||
             this.props.extensionLibraryVisible !== nextProps.extensionLibraryVisible ||
@@ -148,11 +156,12 @@ class Blocks extends React.Component {
     setLocale () {
         this.workspace.getFlyout().setRecyclingEnabled(false);
         this.ScratchBlocks.ScratchMsgs.setLocale(this.props.locale);
-        this.props.vm.setLocale(this.props.locale, this.props.messages);
-
-        this.workspace.updateToolbox(this.props.toolboxXML);
-        this.props.vm.refreshWorkspace();
-        this.workspace.getFlyout().setRecyclingEnabled(true);
+        this.props.vm.setLocale(this.props.locale, this.props.messages)
+            .then(() => {
+                this.workspace.updateToolbox(this.props.toolboxXML);
+                this.props.vm.refreshWorkspace();
+                this.workspace.getFlyout().setRecyclingEnabled(true);
+            });
     }
 
     updateToolbox () {
@@ -204,6 +213,8 @@ class Blocks extends React.Component {
         this.props.vm.addListener('targetsUpdate', this.onTargetsUpdate);
         this.props.vm.addListener('EXTENSION_ADDED', this.handleExtensionAdded);
         this.props.vm.addListener('BLOCKSINFO_UPDATE', this.handleBlocksInfoUpdate);
+        this.props.vm.addListener('PERIPHERAL_CONNECTED', this.handleStatusButtonUpdate);
+        this.props.vm.addListener('PERIPHERAL_ERROR', this.handleStatusButtonUpdate);
     }
     detachVM () {
         this.props.vm.removeListener('SCRIPT_GLOW_ON', this.onScriptGlowOn);
@@ -215,6 +226,8 @@ class Blocks extends React.Component {
         this.props.vm.removeListener('targetsUpdate', this.onTargetsUpdate);
         this.props.vm.removeListener('EXTENSION_ADDED', this.handleExtensionAdded);
         this.props.vm.removeListener('BLOCKSINFO_UPDATE', this.handleBlocksInfoUpdate);
+        this.props.vm.removeListener('PERIPHERAL_CONNECTED', this.handleStatusButtonUpdate);
+        this.props.vm.removeListener('PERIPHERAL_ERROR', this.handleStatusButtonUpdate);
     }
 
     updateToolboxBlockValue (id, value) {
@@ -311,6 +324,11 @@ class Blocks extends React.Component {
         this.handleExtensionAdded(blocksInfo);
     }
     handleCategorySelected (categoryId) {
+        const extension = extensionData.find(ext => ext.extensionId === categoryId);
+        if (extension && extension.launchDeviceConnectionFlow) {
+            this.handleConnectionModalStart(categoryId);
+        }
+
         this.withToolboxUpdates(() => {
             this.workspace.toolbox_.setSelectedCategoryById(categoryId);
         });
@@ -330,6 +348,23 @@ class Blocks extends React.Component {
             p.prompt.title !== this.ScratchBlocks.Msg.RENAME_LIST_MODAL_TITLE;
         this.setState(p);
     }
+    handleConnectionModalStart (extensionId) {
+        const extension = extensionData.find(ext => ext.extensionId === extensionId);
+        if (extension) {
+            this.setState({connectionModal: {
+                extensionId: extensionId,
+                deviceImage: extension.deviceImage,
+                smallDeviceImage: extension.smallDeviceImage,
+                name: extension.name
+            }});
+        }
+    }
+    handleConnectionModalClose () {
+        this.setState({connectionModal: null});
+    }
+    handleStatusButtonUpdate () {
+        this.ScratchBlocks.refreshStatusButtons(this.workspace);
+    }
     handlePromptCallback (input, optionSelection) {
         this.state.prompt.callback(input, optionSelection,
             (optionSelection === 'local') ? [] :
@@ -381,6 +416,17 @@ class Blocks extends React.Component {
                         onOk={this.handlePromptCallback}
                     />
                 ) : null}
+                {this.state.connectionModal ? (
+                    <ConnectionModal
+                        deviceImage={this.state.connectionModal.deviceImage}
+                        extensionId={this.state.connectionModal.extensionId}
+                        name={this.state.connectionModal.name}
+                        smallDeviceImage={this.state.connectionModal.smallDeviceImage}
+                        vm={vm}
+                        onCancel={this.handleConnectionModalClose}
+                        onStatusButtonUpdate={this.handleStatusButtonUpdate}
+                    />
+                ) : null}
                 {extensionLibraryVisible ? (
                     <ExtensionLibrary
                         vm={vm}
diff --git a/src/containers/connection-modal.jsx b/src/containers/connection-modal.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..ffb5c6ddf5c3b4ec05d61d1cbca8b7c05ac13d3d
--- /dev/null
+++ b/src/containers/connection-modal.jsx
@@ -0,0 +1,104 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import bindAll from 'lodash.bindall';
+import ConnectionModalComponent, {PHASES} from '../components/connection-modal/connection-modal.jsx';
+import VM from 'scratch-vm';
+
+class ConnectionModal extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, [
+            'handleScanning',
+            'handleConnected',
+            'handleConnecting',
+            'handleDisconnect',
+            'handleError'
+        ]);
+        this.state = {
+            phase: PHASES.scanning
+        };
+    }
+    componentDidMount () {
+        this.props.vm.on('PERIPHERAL_CONNECTED', this.handleConnected);
+        this.props.vm.on('PERIPHERAL_ERROR', this.handleError);
+
+        // Check if we're already connected
+        if (this.props.vm.getPeripheralIsConnected(this.props.extensionId)) {
+            this.handleConnected();
+        }
+
+    }
+    componentWillUnmount () {
+        this.props.vm.removeListener('PERIPHERAL_CONNECTED', this.handleConnected);
+        this.props.vm.removeListener('PERIPHERAL_ERROR', this.handleError);
+    }
+    handleScanning () {
+        this.setState({
+            phase: PHASES.scanning
+        });
+    }
+    handleConnecting (peripheralId) {
+        this.props.vm.connectToPeripheral(this.props.extensionId, peripheralId);
+        this.setState({
+            phase: PHASES.connecting
+        });
+    }
+    handleDisconnect () {
+        this.props.onStatusButtonUpdate(this.props.extensionId, 'not ready');
+        this.props.vm.disconnectExtensionSession(this.props.extensionId);
+        this.props.onCancel();
+    }
+    handleCancel () {
+        // If we're not connected to a device, close the websocket so we stop scanning.
+        if (!this.props.vm.getPeripheralIsConnected(this.props.extensionId)) {
+            this.props.vm.disconnectExtensionSession(this.props.extensionId);
+        }
+        this.props.onCancel();
+    }
+    handleError () {
+        this.props.onStatusButtonUpdate();
+        this.setState({
+            phase: PHASES.error
+        });
+    }
+    handleConnected () {
+        this.props.onStatusButtonUpdate();
+        this.setState({
+            phase: PHASES.connected
+        });
+    }
+    handleHelp () {
+        // @todo: implement the help button
+    }
+    render () {
+        return (
+            <ConnectionModalComponent
+                deviceImage={this.props.deviceImage}
+                extensionId={this.props.extensionId}
+                name={this.props.name}
+                phase={this.state.phase}
+                smallDeviceImage={this.props.smallDeviceImage}
+                title={this.props.extensionId}
+                vm={this.props.vm}
+                onCancel={this.props.onCancel}
+                onConnected={this.handleConnected}
+                onConnecting={this.handleConnecting}
+                onDisconnect={this.handleDisconnect}
+                onHelp={this.handleHelp}
+                onScanning={this.handleScanning}
+            />
+        );
+    }
+}
+
+ConnectionModal.propTypes = {
+    deviceImage: PropTypes.string.isRequired,
+    extensionId: PropTypes.string.isRequired,
+    name: PropTypes.node.isRequired,
+    onCancel: PropTypes.func.isRequired,
+    onStatusButtonUpdate: PropTypes.func.isRequired,
+    smallDeviceImage: PropTypes.string.isRequired,
+    vm: PropTypes.instanceOf(VM).isRequired
+};
+
+export default ConnectionModal;
diff --git a/src/containers/extension-library.jsx b/src/containers/extension-library.jsx
index a1af3bac41fcd71221b6414785ebbe6fcb53a1e1..a23f1e6c8c74dada999b93aae070ebaebfe025e0 100644
--- a/src/containers/extension-library.jsx
+++ b/src/containers/extension-library.jsx
@@ -46,10 +46,17 @@ class ExtensionLibrary extends React.PureComponent {
                 });
             }
         }
+        let gaLabel = '';
+        if (typeof (item.name) === 'string') {
+            gaLabel = item.name;
+        } else {
+            // Name is localized, get the default message for the gaLabel
+            gaLabel = item.name.props.defaultMessage;
+        }
         analytics.event({
             category: 'library',
             action: 'Select Extension',
-            label: item.name
+            label: gaLabel
         });
     }
     render () {
diff --git a/src/containers/scanning-step.jsx b/src/containers/scanning-step.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..ecc19318913845154c248f716dfad6d440147c2e
--- /dev/null
+++ b/src/containers/scanning-step.jsx
@@ -0,0 +1,74 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import bindAll from 'lodash.bindall';
+import ScanningStepComponent from '../components/connection-modal/scanning-step.jsx';
+import VM from 'scratch-vm';
+
+class ScanningStep extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, [
+            'handlePeripheralListUpdate',
+            'handlePeripheralScanTimeout',
+            'handleRefresh'
+        ]);
+        this.state = {
+            scanning: true,
+            deviceList: []
+        };
+    }
+    componentDidMount () {
+        this.props.vm.startDeviceScan(this.props.extensionId);
+        this.props.vm.on(
+            'PERIPHERAL_LIST_UPDATE', this.handlePeripheralListUpdate);
+        this.props.vm.on(
+            'PERIPHERAL_SCAN_TIMEOUT', this.handlePeripheralScanTimeout);
+    }
+    componentWillUnmount () {
+        // @todo: stop the device scan here
+        this.props.vm.removeListener(
+            'PERIPHERAL_LIST_UPDATE', this.handlePeripheralListUpdate);
+        this.props.vm.removeListener(
+            'PERIPHERAL_SCAN_TIMEOUT', this.handlePeripheralScanTimeout);
+    }
+    handlePeripheralScanTimeout () {
+        this.setState({scanning: false});
+    }
+    handlePeripheralListUpdate (newList) {
+        // TODO: sort peripherals by signal strength? so they don't jump around
+        const peripheralArray = Object.keys(newList).map(id =>
+            newList[id]
+        );
+        this.setState({deviceList: peripheralArray});
+    }
+    handleRefresh () {
+        this.props.vm.startDeviceScan(this.props.extensionId);
+        this.setState({
+            scanning: true,
+            deviceList: []
+        });
+    }
+    render () {
+        return (
+            <ScanningStepComponent
+                deviceList={this.state.deviceList}
+                phase={this.state.phase}
+                smallDeviceImage={this.props.smallDeviceImage}
+                title={this.props.extensionId}
+                onConnected={this.props.onConnected}
+                onConnecting={this.props.onConnecting}
+                onRefresh={this.handleRefresh}
+            />
+        );
+    }
+}
+
+ScanningStep.propTypes = {
+    extensionId: PropTypes.string.isRequired,
+    onConnected: PropTypes.func.isRequired,
+    onConnecting: PropTypes.func.isRequired,
+    smallDeviceImage: PropTypes.string,
+    vm: PropTypes.instanceOf(VM).isRequired
+};
+
+export default ScanningStep;
diff --git a/src/containers/tips-library.jsx b/src/containers/tips-library.jsx
index 4db0d06659874b4f0f9d38246297ac7824125503..ebbee3f3022175f797e021e1e0253a0821f5258c 100644
--- a/src/containers/tips-library.jsx
+++ b/src/containers/tips-library.jsx
@@ -20,9 +20,9 @@ import {
 
 const messages = defineMessages({
     tipsLibraryTitle: {
-        defaultMessage: 'How-Tos',
-        description: 'Heading for the help/how-tos library',
-        id: 'gui.tipsLibrary.howtos'
+        defaultMessage: 'Choose a Tutorial',
+        description: 'Heading for the help/tutorials library',
+        id: 'gui.tipsLibrary.tutorials'
     }
 });
 
diff --git a/src/css/colors.css b/src/css/colors.css
index 8dbc51ecdbeb9157cb0425cdcba22a941ea5bef6..37ffa62227a6f6ccb42a6170d4652db037f4f769 100644
--- a/src/css/colors.css
+++ b/src/css/colors.css
@@ -15,6 +15,7 @@ $text-primary-transparent: hsla(225, 15%, 40%, 0.75);
 $motion-primary: hsla(215, 100%, 65%, 1); /* #4C97FF */
 $motion-tertiary: hsla(215, 60%, 50%, 1); /* #3373CC */
 $motion-transparent: hsla(215, 100%, 65%, 0.35); /* 35% transparent version of motion-primary */
+$motion-light-transparent: hsla(215, 100%, 65%, 0.1); /* 10% transparent version of motion-primary */
 
 $red-primary: hsla(20, 100%, 55%, 1); /* #FF661A */
 $red-tertiary: hsla(20, 100%, 45%, 1); /* #E64D00 */
@@ -27,3 +28,11 @@ $control-primary: hsla(38, 100%, 55%, 1); /* #FFAB19 */
 $data-primary: hsla(30, 100%, 55%, 1); /* #FF8C1A */
 
 $pen-primary: hsla(163, 85%, 40%, 1); /* #0FBD8C */
+$pen-transparent: hsla(163, 85%, 40%, 0.25); /* #0FBD8C */
+
+$error-primary: hsla(30, 100%, 55%, 1); /* #FF8C1A */
+$error-transparent: hsla(30, 100%, 55%, 0.25); /* #FF8C1A */
+
+$extensions-primary: hsla(163, 85%, 40%, 1); /* #0FBD8C */
+$extensions-tertiary: hsla(163, 85%, 30%, 1); /* #0B8E69 */
+$extensions-transparent: hsla(163, 85%, 40%, 0.35); /* 35% transparent version of extensions-primary */
diff --git a/src/lib/assets/icon--tutorials.svg b/src/lib/assets/icon--tutorials.svg
new file mode 100644
index 0000000000000000000000000000000000000000..fea09e781b3f88a43750b69f25e6e522846a4466
Binary files /dev/null and b/src/lib/assets/icon--tutorials.svg differ
diff --git a/src/lib/audio/audio-effects.js b/src/lib/audio/audio-effects.js
index 067dcc6209397782d248a3a04ce8ad11f0f668d9..ab170f9c677924e2be4f4995287e9699e1271ffc 100644
--- a/src/lib/audio/audio-effects.js
+++ b/src/lib/audio/audio-effects.js
@@ -34,9 +34,6 @@ class AudioEffects {
             playbackRate = 1 / pitchRatio;
             sampleCount = Math.floor(buffer.length / playbackRate);
             break;
-        case effectTypes.REVERSE:
-            buffer.getChannelData(0).reverse();
-            break;
         }
         if (window.OfflineAudioContext) {
             this.audioContext = new window.OfflineAudioContext(1, sampleCount, buffer.sampleRate);
@@ -46,7 +43,24 @@ class AudioEffects {
             const sampleScale = 44100 / buffer.sampleRate;
             this.audioContext = new window.webkitOfflineAudioContext(1, sampleScale * sampleCount, 44100);
         }
-        this.buffer = buffer;
+
+        // For the reverse effect we need to manually reverse the data into a new audio buffer
+        // to prevent overwriting the original, so that the undo stack works correctly.
+        // Doing buffer.reverse() would mutate the original data.
+        if (name === effectTypes.REVERSE) {
+            const originalBufferData = buffer.getChannelData(0);
+            const newBuffer = this.audioContext.createBuffer(1, buffer.length, buffer.sampleRate);
+            const newBufferData = newBuffer.getChannelData(0);
+            const bufferLength = buffer.length;
+            for (let i = 0; i < bufferLength; i++) {
+                newBufferData[i] = originalBufferData[bufferLength - i - 1];
+            }
+            this.buffer = newBuffer;
+        } else {
+            // All other effects use the original buffer because it is not modified.
+            this.buffer = buffer;
+        }
+
         this.source = this.audioContext.createBufferSource();
         this.source.buffer = this.buffer;
         this.source.playbackRate.value = playbackRate;
diff --git a/src/lib/blocks.js b/src/lib/blocks.js
index c1bde0ff2e69c310977c84308cd73c802655d28f..f6b78b68ee4a325c5d03701e8d484466ba856f0c 100644
--- a/src/lib/blocks.js
+++ b/src/lib/blocks.js
@@ -208,5 +208,12 @@ export default function (vm) {
         return monitoredBlock ? monitoredBlock.isMonitored : false;
     };
 
+    ScratchBlocks.FlyoutExtensionCategoryHeader.getExtensionState = function (extensionId) {
+        if (vm.getPeripheralIsConnected(extensionId)) {
+            return ScratchBlocks.StatusButtonState.READY;
+        }
+        return ScratchBlocks.StatusButtonState.NOT_READY;
+    };
+
     return ScratchBlocks;
 }
diff --git a/src/lib/libraries/extensions/device-connection/ev3/ev3-hub-illustration.svg b/src/lib/libraries/extensions/device-connection/ev3/ev3-hub-illustration.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7f8c8c395969e202e01d4e18c0225b5ab98c49b0
Binary files /dev/null and b/src/lib/libraries/extensions/device-connection/ev3/ev3-hub-illustration.svg differ
diff --git a/src/lib/libraries/extensions/device-connection/ev3/ev3-small.svg b/src/lib/libraries/extensions/device-connection/ev3/ev3-small.svg
new file mode 100644
index 0000000000000000000000000000000000000000..260e2fd26c1197626e40e69c9d60acb691f7f264
Binary files /dev/null and b/src/lib/libraries/extensions/device-connection/ev3/ev3-small.svg differ
diff --git a/src/lib/libraries/extensions/device-connection/microbit/microbit-illustration.svg b/src/lib/libraries/extensions/device-connection/microbit/microbit-illustration.svg
new file mode 100644
index 0000000000000000000000000000000000000000..3ef892bcc456fd9196e72356742391fd74b67a93
Binary files /dev/null and b/src/lib/libraries/extensions/device-connection/microbit/microbit-illustration.svg differ
diff --git a/src/lib/libraries/extensions/device-connection/microbit/microbit-small.svg b/src/lib/libraries/extensions/device-connection/microbit/microbit-small.svg
new file mode 100644
index 0000000000000000000000000000000000000000..ead401aba1045eba027ae09168f845a7811c9cec
Binary files /dev/null and b/src/lib/libraries/extensions/device-connection/microbit/microbit-small.svg differ
diff --git a/src/lib/libraries/extensions/index.jsx b/src/lib/libraries/extensions/index.jsx
index 71404f8fb0e2abd8a47018569487c350ad581074..62da95ea5b04e991841878659f14af4b460e3571 100644
--- a/src/lib/libraries/extensions/index.jsx
+++ b/src/lib/libraries/extensions/index.jsx
@@ -11,6 +11,12 @@ import ev3Image from './ev3.png';
 import boostImage from './boost.png';
 import translateImage from './translate.png';
 
+import ev3DeviceImage from './device-connection/ev3/ev3-hub-illustration.svg';
+import ev3MenuImage from './device-connection/ev3/ev3-small.svg';
+
+import microbitDeviceImage from './device-connection/microbit/microbit-illustration.svg';
+import microbitMenuImage from './device-connection/microbit/microbit-small.svg';
+
 export default [
     {
         name: (
@@ -120,7 +126,10 @@ export default [
             />
         ),
         featured: true,
-        disabled: true
+        disabled: true,
+        launchDeviceConnectionFlow: true,
+        deviceImage: microbitDeviceImage,
+        smallDeviceImage: microbitMenuImage
     },
     {
         name: 'LEGO WeDo 2.0',
@@ -148,7 +157,10 @@ export default [
             />
         ),
         featured: true,
-        disabled: true
+        disabled: true,
+        launchDeviceConnectionFlow: true,
+        deviceImage: ev3DeviceImage,
+        smallDeviceImage: ev3MenuImage
     },
     {
         name: 'LEGO Boost',
diff --git a/src/lib/libraries/extensions/translate.png b/src/lib/libraries/extensions/translate.png
index 3e25993021b71beb390b2f6b9865b566e88839a6..95961ae52fee6e27c5f7946c41a7e4fd1d22fe7a 100644
Binary files a/src/lib/libraries/extensions/translate.png and b/src/lib/libraries/extensions/translate.png differ
diff --git a/src/lib/make-toolbox-xml.js b/src/lib/make-toolbox-xml.js
index 1c2a0ae1936d2ef2d373ba87437bc696e80d3467..245c918e51e99de0991e05868741c24263d912e0 100644
--- a/src/lib/make-toolbox-xml.js
+++ b/src/lib/make-toolbox-xml.js
@@ -270,12 +270,12 @@ const looks = function (isStage, targetId) {
 const sound = function (isStage, targetId) {
     return `
     <category name="%{BKY_CATEGORY_SOUND}" id="sound" colour="#D65CD6" secondaryColour="#BD42BD">
-        <block id="${targetId}_sound_play" type="sound_play">
+        <block id="${targetId}_sound_playuntildone" type="sound_playuntildone">
             <value name="SOUND_MENU">
                 <shadow type="sound_sounds_menu"/>
             </value>
         </block>
-        <block id="${targetId}_sound_playuntildone" type="sound_playuntildone">
+        <block id="${targetId}_sound_play" type="sound_play">
             <value name="SOUND_MENU">
                 <shadow type="sound_sounds_menu"/>
             </value>
diff --git a/src/playground/index.jsx b/src/playground/index.jsx
index d35785698dfa2048e32ba5d22f5d2b131abfe994..da2be7a27831b6179acb436d6b441f66e86c9dcf 100644
--- a/src/playground/index.jsx
+++ b/src/playground/index.jsx
@@ -1,5 +1,8 @@
+// Polyfills
 import 'es6-object-assign/auto';
 import 'core-js/fn/array/includes';
+import 'intl'; // For Safari 9
+
 import React from 'react';
 import ReactDOM from 'react-dom';
 
diff --git a/test/integration/how-tos.test.js b/test/integration/how-tos.test.js
index 7a08385e814b2bfb971a6df3ad36535e9f5c8af8..5b9b76e4b74cb0163066010a3bd91da03a8992b3 100644
--- a/test/integration/how-tos.test.js
+++ b/test/integration/how-tos.test.js
@@ -27,7 +27,7 @@ describe('Working with the how-to library', () => {
         await loadUri(uri);
         await clickXpath('//button[@title="tryit"]');
         await clickText('Costumes');
-        await clickXpath('//*[@aria-label="How-to Library"]');
+        await clickXpath('//*[@aria-label="Tutorials"]');
         await clickText('Getting Started'); // Modal should close
         // Make sure YouTube video on first card appears
         await findByXpath('//div[contains(@class, "step-video")]');