diff --git a/README.md b/README.md
index e114acb5c80cb62555d3371c56b59562ab1231ee..91613cdcdc36a486a997cb8bf97889457f64d73e 100644
--- a/README.md
+++ b/README.md
@@ -47,32 +47,69 @@ Instead of `BUILD_MODE=dist npm run build` you can also use `BUILD_MODE=dist npm
 * Follow the recipe above step by step and don't change the order. It is especially important to run npm first because installing after the linking will reset the linking.
 * Make sure the repositories are siblings on your machine's file tree.
 * If you have multiple Terminal tabs or windows open for the different Scratch repositories, make sure to use the same node version in all of them.
-* In the worst case unlink the repositories with `npm unlink` and start over.
+* In the worst case unlink the repositories by running `npm unlink` in both, and start over.
 
 ## Testing
-NOTE: If you're a windows user, please run these scripts in Windows `cmd.exe`  instead of Git Bash/MINGW64.
 
-Run linter, unit tests, build, and integration tests.
+### Documentation
+
+You may want to review the documentation for [Jest](https://facebook.github.io/jest/docs/en/api.html) and [Enzyme](http://airbnb.io/enzyme/docs/api/) as you write your tests.
+
+See [jest cli docs](https://facebook.github.io/jest/docs/en/cli.html#content) for more options.
+
+### Running tests
+
+*NOTE: If you're a windows user, please run these scripts in Windows `cmd.exe`  instead of Git Bash/MINGW64.*
+
+Before running any test, make sure you have run `npm install` from this (scratch-gui) repository's top level.
+
+#### Main testing command
+
+To run linter, unit tests, build, and integration tests, all at once:
 ```bash
 npm test
 ```
 
-Run unit tests in isolation.
+#### Running unit tests
+
+To run unit tests in isolation:
+```bash
+npm run test:unit
+```
+
+To run unit tests in watch mode (watches for code changes and continuously runs tests):
 ```bash
-npm run unit-test
+npm run test:unit -- --watch
 ```
 
-Run unit tests in watch mode (watches for code changes and continuously runs tests). See [jest cli docs](https://facebook.github.io/jest/docs/en/cli.html#content) for more options.
+#### Running integration tests
+
+Integration tests use a headless browser to manipulate the actual html and javascript that the repo
+produces. You will not see this activity (though you can hear it when sounds are played!).
+
+Note that integration tests require you to first create a build that can be loaded in a browser:
+
 ```bash
-npm run unit-test -- --watch
+npm run build
 ```
 
-Run integration tests in isolation.
+Then, you can run all integration tests:
+
 ```bash
-npm run integration-test
+npm run test:integration
 ```
 
-You may want to review the documentation for [Jest](https://facebook.github.io/jest/docs/en/api.html) and [Enzyme](http://airbnb.io/enzyme/docs/api/) as you write your tests.
+Or, you can run a single file of integration tests (in this example, the `backpack` tests):
+
+```bash
+$(npm bin)/jest --runInBand test/integration/backpack.test.js
+```
+
+If you want to watch the browser as it runs the test, rather than running headless, use:
+
+```bash
+USE_HEADLESS=no $(npm bin)/jest --runInBand test/integration/backpack.test.js
+```
 
 ## Publishing to GitHub Pages
 You can publish the GUI to github.io so that others on the Internet can view it.
diff --git a/package.json b/package.json
index 52a455237e3cfebc1b5fcc02e55da8af29f5b401..7764fd51becddbe2098d8fc53adb2fbbef90a222 100644
--- a/package.json
+++ b/package.json
@@ -72,7 +72,7 @@
     "mkdirp": "^0.5.1",
     "postcss-import": "^12.0.0",
     "postcss-loader": "^3.0.0",
-    "postcss-simple-vars": "^4.0.0",
+    "postcss-simple-vars": "^5.0.1",
     "prop-types": "^15.5.10",
     "raf": "^3.4.0",
     "raw-loader": "^0.5.1",
@@ -86,7 +86,7 @@
     "react-popover": "0.5.7",
     "react-redux": "5.0.7",
     "react-responsive": "5.0.0",
-    "react-style-proptype": "3.2.1",
+    "react-style-proptype": "3.2.2",
     "react-tabs": "2.3.0",
     "react-test-renderer": "16.2.0",
     "react-tooltip": "3.8.0",
@@ -98,8 +98,8 @@
     "scratch-audio": "0.1.0-prerelease.20180625202813",
     "scratch-blocks": "0.1.0-prerelease.1535662135",
     "scratch-l10n": "3.0.20180830210150",
-    "scratch-paint": "0.2.0-prerelease.20180907144642",
-    "scratch-render": "0.1.0-prerelease.20180824141819",
+    "scratch-paint": "0.2.0-prerelease.20180912222409",
+    "scratch-render": "0.1.0-prerelease.20180907144714",
     "scratch-storage": "1.0.2",
     "scratch-svg-renderer": "0.2.0-prerelease.20180907141232",
     "scratch-vm": "0.2.0-prerelease.20180912222010",
diff --git a/src/components/connection-modal/auto-scanning-step.jsx b/src/components/connection-modal/auto-scanning-step.jsx
index 623bbdd02aa904ee4d0e60606a80ccd0aa1d2225..a73c0b58db974d065bc2d3372cee0c43595ad8ec 100644
--- a/src/components/connection-modal/auto-scanning-step.jsx
+++ b/src/components/connection-modal/auto-scanning-step.jsx
@@ -45,8 +45,8 @@ const AutoScanningStep = props => (
                                 src={radarIcon}
                             />
                             <img
-                                className={styles.deviceButtonImage}
-                                src={props.deviceButtonImage}
+                                className={styles.peripheralButtonImage}
+                                src={props.peripheralButtonImage}
                             />
                         </React.Fragment>
                     )}
@@ -55,7 +55,7 @@ const AutoScanningStep = props => (
                             <FormattedMessage
                                 defaultMessage="No devices found"
                                 description="Text shown when no devices could be found"
-                                id="gui.connection.auto-scanning.noDevicesFound"
+                                id="gui.connection.auto-scanning.noPeripheralsFound"
                             />
                         </Box>
                     )}
@@ -139,9 +139,9 @@ const AutoScanningStep = props => (
 );
 
 AutoScanningStep.propTypes = {
-    deviceButtonImage: PropTypes.string,
     onRefresh: PropTypes.func,
     onStartScan: PropTypes.func,
+    peripheralButtonImage: PropTypes.string,
     phase: PropTypes.oneOf(Object.keys(PHASES))
 };
 
diff --git a/src/components/connection-modal/connected-step.jsx b/src/components/connection-modal/connected-step.jsx
index c02f644bc4e55d807124bd8cc41004a98cdca24b..aa71c63c8a11730b8a30379de6112a2be98150d4 100644
--- a/src/components/connection-modal/connected-step.jsx
+++ b/src/components/connection-modal/connected-step.jsx
@@ -12,10 +12,10 @@ const ConnectedStep = props => (
     <Box className={styles.body}>
         <Box className={styles.activityArea}>
             <Box className={styles.centeredRow}>
-                <div className={styles.deviceActivity}>
+                <div className={styles.peripheralActivity}>
                     <img
-                        className={styles.deviceActivityIcon}
-                        src={props.deviceImage}
+                        className={styles.peripheralActivityIcon}
+                        src={props.peripheralImage}
                     />
                     <img
                         className={styles.bluetoothConnectedIcon}
@@ -63,9 +63,9 @@ const ConnectedStep = props => (
 );
 
 ConnectedStep.propTypes = {
-    deviceImage: PropTypes.string.isRequired,
     onCancel: PropTypes.func,
-    onDisconnect: PropTypes.func
+    onDisconnect: PropTypes.func,
+    peripheralImage: PropTypes.string.isRequired
 };
 
 export default ConnectedStep;
diff --git a/src/components/connection-modal/connecting-step.jsx b/src/components/connection-modal/connecting-step.jsx
index be378b3fdd54773f4a1bf9989364a930f9faf433..e4753628677d3f7532b72f9c498823ba38215ce2 100644
--- a/src/components/connection-modal/connecting-step.jsx
+++ b/src/components/connection-modal/connecting-step.jsx
@@ -14,10 +14,10 @@ const ConnectingStep = props => (
     <Box className={styles.body}>
         <Box className={styles.activityArea}>
             <Box className={styles.centeredRow}>
-                <div className={styles.deviceActivity}>
+                <div className={styles.peripheralActivity}>
                     <img
-                        className={styles.deviceActivityIcon}
-                        src={props.deviceImage}
+                        className={styles.peripheralActivityIcon}
+                        src={props.peripheralImage}
                     />
                     <img
                         className={styles.bluetoothConnectingIcon}
@@ -61,8 +61,8 @@ const ConnectingStep = props => (
 
 ConnectingStep.propTypes = {
     connectingMessage: PropTypes.node.isRequired,
-    deviceImage: PropTypes.string.isRequired,
-    onDisconnect: PropTypes.func
+    onDisconnect: PropTypes.func,
+    peripheralImage: PropTypes.string.isRequired
 };
 
 export default ConnectingStep;
diff --git a/src/components/connection-modal/connection-modal.css b/src/components/connection-modal/connection-modal.css
index 16f337ef460e7a88120f9b5fe49958bdec07ba91..f024489c591456d75b65e6170f1ace7c71748351 100644
--- a/src/components/connection-modal/connection-modal.css
+++ b/src/components/connection-modal/connection-modal.css
@@ -25,14 +25,14 @@
     align-items: center;
 }
 
-.device-tile-pane {
+.peripheral-tile-pane {
     overflow-y: auto;
     width: 100%;
     height: 100%;
     padding: 0.5rem;
 }
 
-.device-tile {
+.peripheral-tile {
     display: flex;
     flex-direction: row;
     justify-content: space-between;
@@ -46,36 +46,36 @@
     margin-bottom: 0.5rem;
 }
 
-.device-tile-name {
+.peripheral-tile-name {
     display: flex;
     align-items: center;
 }
 
-[dir="ltr"] .device-tile-image {
+[dir="ltr"] .peripheral-tile-image {
     margin-right: 0.5rem;
 }
 
-[dir="rtl"] .device-tile-image {
+[dir="rtl"] .peripheral-tile-image {
     margin-left: 0.5rem;
 }
 
-.device-tile-name-wrapper {
+.peripheral-tile-name-wrapper {
     display: flex;
     flex-direction: column;
     justify-content: center;
     align-items: flex-start;
 }
 
-.device-tile-name-label {
+.peripheral-tile-name-label {
     font-weight: bold;
     font-size: 0.625rem;
 }
 
-.device-tile-name-text {
+.peripheral-tile-name-text {
     font-size: 0.875rem;
 }
 
-.device-tile button {
+.peripheral-tile button {
     padding: 0.6rem 0.75rem;
     border: none;
     border-radius: 0.25rem;
@@ -154,16 +154,16 @@
     }
 }
 
-.device-activity {
+.peripheral-activity {
     position: relative;
 }
 
-.device-activity-icon {
+.peripheral-activity-icon {
     /* width: 80px;
     height: 80px; */
 }
 
-.device-button-image {
+.peripheral-button-image {
     position: absolute;
 }
 
@@ -214,7 +214,7 @@
     box-shadow: 0px 0px 0px 2px $motion-transparent;
 }
 
-.device-tile-widgets {
+.peripheral-tile-widgets {
     display: flex;
     align-items: center;
 }
diff --git a/src/components/connection-modal/connection-modal.jsx b/src/components/connection-modal/connection-modal.jsx
index 6fb9cd4ff98c924e05d0ea5f35ebbf3aa7f1f348..99c9a6a531f9f73344cf5395c49d4f5bb7edaf35 100644
--- a/src/components/connection-modal/connection-modal.jsx
+++ b/src/components/connection-modal/connection-modal.jsx
@@ -27,7 +27,7 @@ const ConnectionModalComponent = props => (
         className={styles.modalContent}
         contentLabel={props.name}
         headerClassName={styles.header}
-        headerImage={props.smallDeviceImage}
+        headerImage={props.smallPeripheralImage}
         onHelp={props.onHelp}
         onRequestClose={props.onCancel}
     >
@@ -44,12 +44,12 @@ const ConnectionModalComponent = props => (
 
 ConnectionModalComponent.propTypes = {
     connectingMessage: PropTypes.node,
-    deviceButtonImage: PropTypes.string,
     name: PropTypes.node,
     onCancel: PropTypes.func.isRequired,
     onHelp: PropTypes.func.isRequired,
+    peripheralButtonImage: PropTypes.string,
     phase: PropTypes.oneOf(Object.keys(PHASES)).isRequired,
-    smallDeviceImage: PropTypes.string,
+    smallPeripheralImage: PropTypes.string,
     title: PropTypes.string.isRequired,
     useAutoScan: PropTypes.bool.isRequired
 };
diff --git a/src/components/connection-modal/error-step.jsx b/src/components/connection-modal/error-step.jsx
index a5a5ce1b70085d66bfd351599673da58da171821..21dcd8d54c92c4138862a053fe19e849835e744c 100644
--- a/src/components/connection-modal/error-step.jsx
+++ b/src/components/connection-modal/error-step.jsx
@@ -14,10 +14,10 @@ const ErrorStep = props => (
     <Box className={styles.body}>
         <Box className={styles.activityArea}>
             <Box className={styles.centeredRow}>
-                <div className={styles.deviceActivity}>
+                <div className={styles.peripheralActivity}>
                     <img
-                        className={styles.deviceActivityIcon}
-                        src={props.deviceImage}
+                        className={styles.peripheralActivityIcon}
+                        src={props.peripheralImage}
                     />
                 </div>
             </Box>
@@ -69,9 +69,9 @@ const ErrorStep = props => (
 );
 
 ErrorStep.propTypes = {
-    deviceImage: PropTypes.string.isRequired,
     onHelp: PropTypes.func,
-    onScanning: PropTypes.func
+    onScanning: PropTypes.func,
+    peripheralImage: PropTypes.string.isRequired
 };
 
 export default ErrorStep;
diff --git a/src/components/connection-modal/device-tile.jsx b/src/components/connection-modal/peripheral-tile.jsx
similarity index 77%
rename from src/components/connection-modal/device-tile.jsx
rename to src/components/connection-modal/peripheral-tile.jsx
index c806453aa0ff60828462376bf9c01a3a38ae550f..6b7e0388d6216eb4dab3094bef76c6ab0b15e613 100644
--- a/src/components/connection-modal/device-tile.jsx
+++ b/src/components/connection-modal/peripheral-tile.jsx
@@ -7,7 +7,7 @@ import Box from '../box/box.jsx';
 
 import styles from './connection-modal.css';
 
-class DeviceTile extends React.Component {
+class PeripheralTile extends React.Component {
     constructor (props) {
         super(props);
         bindAll(this, [
@@ -19,26 +19,26 @@ class DeviceTile extends React.Component {
     }
     render () {
         return (
-            <Box className={styles.deviceTile}>
-                <Box className={styles.deviceTileName}>
+            <Box className={styles.peripheralTile}>
+                <Box className={styles.peripheralTileName}>
                     <img
-                        className={styles.deviceTileImage}
-                        src={this.props.smallDeviceImage}
+                        className={styles.peripheralTileImage}
+                        src={this.props.smallPeripheralImage}
                     />
-                    <Box className={styles.deviceTileNameWrapper}>
-                        <Box className={styles.deviceTileNameLabel}>
+                    <Box className={styles.peripheralTileNameWrapper}>
+                        <Box className={styles.peripheralTileNameLabel}>
                             <FormattedMessage
                                 defaultMessage="Device name"
                                 description="Label for field showing the device name"
-                                id="gui.connection.device-name-label"
+                                id="gui.connection.peripheral-name-label"
                             />
                         </Box>
-                        <Box className={styles.deviceTileNameText}>
+                        <Box className={styles.peripheralTileNameText}>
                             {this.props.name}
                         </Box>
                     </Box>
                 </Box>
-                <Box className={styles.deviceTileWidgets}>
+                <Box className={styles.peripheralTileWidgets}>
                     <Box className={styles.signalStrengthMeter}>
                         <div
                             className={classNames(styles.signalBar, {
@@ -76,12 +76,12 @@ class DeviceTile extends React.Component {
     }
 }
 
-DeviceTile.propTypes = {
+PeripheralTile.propTypes = {
     name: PropTypes.string,
     onConnecting: PropTypes.func,
     peripheralId: PropTypes.string,
     rssi: PropTypes.number,
-    smallDeviceImage: PropTypes.string
+    smallPeripheralImage: PropTypes.string
 };
 
-export default DeviceTile;
+export default PeripheralTile;
diff --git a/src/components/connection-modal/scanning-step.jsx b/src/components/connection-modal/scanning-step.jsx
index cadee33c3e1a6a5669c7a3232f7f3e11ef7e04b5..bb6276ac09bf575012e3e90039b852d5f6a76a97 100644
--- a/src/components/connection-modal/scanning-step.jsx
+++ b/src/components/connection-modal/scanning-step.jsx
@@ -4,7 +4,7 @@ import React from 'react';
 import classNames from 'classnames';
 
 import Box from '../box/box.jsx';
-import DeviceTile from './device-tile.jsx';
+import PeripheralTile from './peripheral-tile.jsx';
 import Dots from './dots.jsx';
 
 import radarIcon from './icons/searching.png';
@@ -16,7 +16,7 @@ const ScanningStep = props => (
     <Box className={styles.body}>
         <Box className={styles.activityArea}>
             {props.scanning ? (
-                props.deviceList.length === 0 ? (
+                props.peripheralList.length === 0 ? (
                     <div className={styles.activityAreaInfo}>
                         <div className={styles.centeredRow}>
                             <img
@@ -26,19 +26,19 @@ const ScanningStep = props => (
                             <FormattedMessage
                                 defaultMessage="Looking for devices"
                                 description="Text shown while scanning for devices"
-                                id="gui.connection.scanning.lookingfordevices"
+                                id="gui.connection.scanning.lookingforperipherals"
                             />
                         </div>
                     </div>
                 ) : (
-                    <div className={styles.deviceTilePane}>
-                        {props.deviceList.map(device =>
-                            (<DeviceTile
-                                key={device.peripheralId}
-                                name={device.name}
-                                peripheralId={device.peripheralId}
-                                rssi={device.rssi}
-                                smallDeviceImage={props.smallDeviceImage}
+                    <div className={styles.peripheralTilePane}>
+                        {props.peripheralList.map(peripheral =>
+                            (<PeripheralTile
+                                key={peripheral.peripheralId}
+                                name={peripheral.name}
+                                peripheralId={peripheral.peripheralId}
+                                rssi={peripheral.rssi}
+                                smallPeripheralImage={props.smallPeripheralImage}
                                 onConnecting={props.onConnecting}
                             />)
                         )}
@@ -49,7 +49,7 @@ const ScanningStep = props => (
                     <FormattedMessage
                         defaultMessage="No devices found"
                         description="Text shown when no devices could be found"
-                        id="gui.connection.scanning.noDevicesFound"
+                        id="gui.connection.scanning.noPeripheralsFound"
                     />
                 </Box>
             )}
@@ -85,19 +85,19 @@ const ScanningStep = props => (
 );
 
 ScanningStep.propTypes = {
-    deviceList: PropTypes.arrayOf(PropTypes.shape({
+    onConnecting: PropTypes.func,
+    onRefresh: PropTypes.func,
+    peripheralList: 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
+    smallPeripheralImage: PropTypes.string
 };
 
 ScanningStep.defaultProps = {
-    deviceList: [],
+    peripheralList: [],
     scanning: true
 };
 
diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx
index 71c623135093df1f503ff64c93a57183eb33e761..aa1dfc0393388111d80c4179e21b7a0d62fa95f1 100644
--- a/src/components/gui/gui.jsx
+++ b/src/components/gui/gui.jsx
@@ -74,6 +74,7 @@ const GUIComponent = props => {
         onRequestCloseBackdropLibrary,
         onRequestCloseCostumeLibrary,
         onSeeCommunity,
+        onUpdateProjectTitle,
         previewInfoVisible,
         targetIsStage,
         soundsTabVisible,
@@ -147,6 +148,7 @@ const GUIComponent = props => {
                 <MenuBar
                     enableCommunity={enableCommunity}
                     onSeeCommunity={onSeeCommunity}
+                    onUpdateProjectTitle={onUpdateProjectTitle}
                 />
                 <Box className={styles.bodyWrapper}>
                     <Box className={styles.flexWrapper}>
@@ -294,6 +296,7 @@ GUIComponent.propTypes = {
     onRequestCloseCostumeLibrary: PropTypes.func,
     onSeeCommunity: PropTypes.func,
     onTabSelect: PropTypes.func,
+    onUpdateProjectTitle: PropTypes.func,
     previewInfoVisible: PropTypes.bool,
     soundsTabVisible: PropTypes.bool,
     stageSizeMode: PropTypes.oneOf(Object.keys(STAGE_SIZE_MODES)),
diff --git a/src/components/menu-bar/menu-bar.css b/src/components/menu-bar/menu-bar.css
index 662c0e1ae6fe2e403367d2d68194b81b83a0f409..46fd7313c16c6a12c55799979d43a876f6e33eff 100644
--- a/src/components/menu-bar/menu-bar.css
+++ b/src/components/menu-bar/menu-bar.css
@@ -37,6 +37,7 @@
     justify-content: flex-start;
     flex-wrap: nowrap;
     align-items: center;
+    flex-grow: 1;
 }
 
 .scratch-logo {
@@ -84,6 +85,16 @@
     background-color: $ui-black-transparent;
 }
 
+.menu-bar-item.growable {
+    max-width: 12rem;
+    flex: 1;
+}
+
+.title-field-growable {
+    flex-grow: 1;
+    width: 2rem;
+}
+
 .file-group {
     display: flex;
     flex-direction: row;
@@ -109,22 +120,6 @@
     height: 34px;
 }
 
-.title-field {
-    border: 1px dashed $ui-black-transparent;
-    border-radius: .25rem;
-    width: 12rem;
-    height: 34px;
-    background-color: transparent;
-    padding: .5rem;
-}
-
-.title-field,
-.title-field::placeholder {
-    color: $ui-white;
-    font-weight: bold;
-    font-size: .8rem;
-}
-
 .share-button {
     background: $data-primary;
     height: 32px;
diff --git a/src/components/menu-bar/menu-bar.jsx b/src/components/menu-bar/menu-bar.jsx
index b1ccd29412e736cd5c39b6297e17ddaf3e190668..897fedc3f3166da91678c56be805566d0200b35d 100644
--- a/src/components/menu-bar/menu-bar.jsx
+++ b/src/components/menu-bar/menu-bar.jsx
@@ -13,6 +13,7 @@ import LanguageSelector from '../../containers/language-selector.jsx';
 import ProjectLoader from '../../containers/project-loader.jsx';
 import Menu from '../../containers/menu.jsx';
 import {MenuItem, MenuSection} from '../menu/menu.jsx';
+import ProjectTitleInput from './project-title-input.jsx';
 import ProjectSaver from '../../containers/project-saver.jsx';
 import DeletionRestorer from '../../containers/deletion-restorer.jsx';
 import TurboMode from '../../containers/turbo-mode.jsx';
@@ -392,12 +393,14 @@ class MenuBar extends React.Component {
                         <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"
+                    <div className={classNames(styles.menuBarItem, styles.growable)}>
+                        <MenuBarItemTooltip
+                            enable
+                            id="title-field"
+                        >
+                            <ProjectTitleInput
+                                className={classNames(styles.titleFieldGrowable)}
+                                onUpdateProjectTitle={this.props.onUpdateProjectTitle}
                             />
                         </MenuBarItemTooltip>
                     </div>
@@ -521,7 +524,8 @@ MenuBar.propTypes = {
     onRequestCloseEdit: PropTypes.func,
     onRequestCloseFile: PropTypes.func,
     onRequestCloseLanguage: PropTypes.func,
-    onSeeCommunity: PropTypes.func
+    onSeeCommunity: PropTypes.func,
+    onUpdateProjectTitle: PropTypes.func
 };
 
 const mapStateToProps = state => ({
diff --git a/src/components/menu-bar/project-title-input.css b/src/components/menu-bar/project-title-input.css
new file mode 100644
index 0000000000000000000000000000000000000000..0567ca76614924b6a09d57b1b0a2169ceac8d655
--- /dev/null
+++ b/src/components/menu-bar/project-title-input.css
@@ -0,0 +1,46 @@
+@import "../../css/colors.css";
+@import "../../css/units.css";
+@import "../../css/z-index.css";
+
+/*
+If project-title-input.jsx is part of a menu bar say menu-bar.jsx, it can have additional css classes that
+can set a width for example or what it should do in a flex box (eg. grow).
+*/
+
+.title-field {
+    border: 1px dashed $ui-black-transparent;
+    border-radius: $form-radius;
+    -webkit-border-radius: $form-radius;
+    -moz-border-radius: $form-radius;
+    background-color: $ui-white-transparent;
+    background-clip: padding-box;
+    -webkit-background-clip: padding-box;
+    height: auto;
+    padding: .5rem;
+}
+
+.title-field {
+    color: $ui-white;
+    font-weight: bold;
+    font-size: .8rem;
+}
+
+.title-field::placeholder {
+    color: $ui-white;
+    font-weight: normal;
+    font-size: .8rem;
+    font-style: italic;
+}
+
+.title-field:hover {
+    background-color: hsla(0, 100%, 100%, 0.5);
+}
+
+.title-field:focus {
+    outline:none;
+    border: 1px solid $ui-transparent;
+    -webkit-box-shadow: 0 0 0 calc($space * .5) $ui-white-transparent;
+    box-shadow: 0 0 0 calc($space * .5) $ui-white-transparent;
+    background-color: $ui-white;
+    color: $text-primary;
+}
diff --git a/src/components/menu-bar/project-title-input.jsx b/src/components/menu-bar/project-title-input.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..b9b5aa6d8382e55c8483a4dde3290ae1ed6ad44a
--- /dev/null
+++ b/src/components/menu-bar/project-title-input.jsx
@@ -0,0 +1,67 @@
+import classNames from 'classnames';
+import {connect} from 'react-redux';
+import PropTypes from 'prop-types';
+import bindAll from 'lodash.bindall';
+import React from 'react';
+import {defineMessages, intlShape, injectIntl} from 'react-intl';
+
+import BufferedInputHOC from '../forms/buffered-input-hoc.jsx';
+import Input from '../forms/input.jsx';
+const BufferedInput = BufferedInputHOC(Input);
+
+import styles from './project-title-input.css';
+
+const messages = defineMessages({
+    projectTitlePlaceholder: {
+        id: 'gui.gui.projectTitlePlaceholder',
+        description: 'Placeholder for project title when blank',
+        defaultMessage: 'Project title here'
+    }
+});
+
+class ProjectTitleInput extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, [
+            'handleUpdateProjectTitle'
+        ]);
+    }
+    // call onUpdateProjectTitle if it is defined (only defined when gui
+    // is used within scratch-www)
+    handleUpdateProjectTitle (newTitle) {
+        if (this.props.onUpdateProjectTitle) {
+            this.props.onUpdateProjectTitle(newTitle);
+        }
+    }
+    render () {
+        return (
+            <BufferedInput
+                className={classNames(styles.titleField, this.props.className)}
+                maxLength="100"
+                placeholder={this.props.intl.formatMessage(messages.projectTitlePlaceholder)}
+                tabIndex="0"
+                type="text"
+                value={this.props.projectTitle}
+                onSubmit={this.handleUpdateProjectTitle}
+            />
+        );
+    }
+}
+
+ProjectTitleInput.propTypes = {
+    className: PropTypes.string,
+    intl: intlShape.isRequired,
+    onUpdateProjectTitle: PropTypes.func,
+    projectTitle: PropTypes.string
+};
+
+const mapStateToProps = state => ({
+    projectTitle: state.scratchGui.projectTitle
+});
+
+const mapDispatchToProps = () => ({});
+
+export default injectIntl(connect(
+    mapStateToProps,
+    mapDispatchToProps
+)(ProjectTitleInput));
diff --git a/src/components/prompt/prompt.jsx b/src/components/prompt/prompt.jsx
index 42de1599939801b8896374f032525be7c77982a9..78192f3adaac829916243929db569003bab283c0 100644
--- a/src/components/prompt/prompt.jsx
+++ b/src/components/prompt/prompt.jsx
@@ -48,6 +48,7 @@ const PromptComponent = props => (
                 <input
                     autoFocus
                     className={styles.variableNameTextInput}
+                    name={props.label}
                     placeholder={props.placeholder}
                     onChange={props.onChange}
                     onKeyPress={props.onKeyPress}
diff --git a/src/components/question/icon--enter.svg b/src/components/question/icon--enter.svg
new file mode 100644
index 0000000000000000000000000000000000000000..03b7c08627d980f0e45ad989d39eae3e602f9e19
Binary files /dev/null and b/src/components/question/icon--enter.svg differ
diff --git a/src/components/question/question.css b/src/components/question/question.css
index ad5e748e67f711e63a36e038ccd882ff61bf80e1..fb8d7869bfbbfe90a7a021e93c01bf1fd0a40d39 100644
--- a/src/components/question/question.css
+++ b/src/components/question/question.css
@@ -55,3 +55,10 @@
 .question-input > input:focus {
     box-shadow: 0px 0px 0px 3px $motion-transparent;
 }
+
+.question-submit-button-icon {
+    width: calc(2rem - $space);
+    height: calc(2rem - $space);
+    position: relative;
+    left: -7px;
+}
diff --git a/src/components/question/question.jsx b/src/components/question/question.jsx
index 2e8b9c9a53159006eb6e92548b60fbb4910c760f..c57fb085d37de1f42a75f3a709c05d0f313f76ac 100644
--- a/src/components/question/question.jsx
+++ b/src/components/question/question.jsx
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
 import React from 'react';
 import styles from './question.css';
 import Input from '../forms/input.jsx';
+import enterIcon from './icon--enter.svg';
 
 const QuestionComponent = props => {
     const {
@@ -28,7 +29,11 @@ const QuestionComponent = props => {
                         className={styles.questionSubmitButton}
                         onClick={onClick}
                     >
-                        {'✔︎' /* @todo should this be an image? */}
+                        <img
+                            className={styles.questionSubmitButtonIcon}
+                            draggable={false}
+                            src={enterIcon}
+                        />
                     </button>
                 </div>
             </div>
diff --git a/src/containers/auto-scanning-step.jsx b/src/containers/auto-scanning-step.jsx
index f8c0360a331dd2e141bef116dc3376c67406796c..f674738419d52289403add07bb1b1c52a21a4900 100644
--- a/src/containers/auto-scanning-step.jsx
+++ b/src/containers/auto-scanning-step.jsx
@@ -18,7 +18,7 @@ class AutoScanningStep extends React.Component {
         };
     }
     componentWillUnmount () {
-        // @todo: stop the device scan here
+        // @todo: stop the peripheral scan here
         this.unbindPeripheralUpdates();
     }
     handlePeripheralScanTimeout () {
@@ -49,7 +49,7 @@ class AutoScanningStep extends React.Component {
             'PERIPHERAL_SCAN_TIMEOUT', this.handlePeripheralScanTimeout);
     }
     handleRefresh () {
-        // @todo: stop the device scan here, it is more important for auto scan
+        // @todo: stop the peripheral scan here, it is more important for auto scan
         // due to timeout and cancellation
         this.setState({
             phase: PHASES.prescan
@@ -58,7 +58,7 @@ class AutoScanningStep extends React.Component {
     }
     handleStartScan () {
         this.bindPeripheralUpdates();
-        this.props.vm.startDeviceScan(this.props.extensionId);
+        this.props.vm.scanForPeripheral(this.props.extensionId);
         this.setState({
             phase: PHASES.pressbutton
         });
@@ -67,7 +67,7 @@ class AutoScanningStep extends React.Component {
     render () {
         return (
             <ScanningStepComponent
-                deviceButtonImage={this.props.deviceButtonImage}
+                peripheralButtonImage={this.props.peripheralButtonImage}
                 phase={this.state.phase}
                 title={this.props.extensionId}
                 onRefresh={this.handleRefresh}
@@ -78,9 +78,9 @@ class AutoScanningStep extends React.Component {
 }
 
 AutoScanningStep.propTypes = {
-    deviceButtonImage: PropTypes.string,
     extensionId: PropTypes.string.isRequired,
     onConnecting: PropTypes.func.isRequired,
+    peripheralButtonImage: PropTypes.string,
     vm: PropTypes.instanceOf(VM).isRequired
 };
 
diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx
index 8a6bec5fd7578beff79912dea9b6dd5cc52595ed..499d77636116b287d0acb3de60c939a0d31f0bd3 100644
--- a/src/containers/blocks.jsx
+++ b/src/containers/blocks.jsx
@@ -336,7 +336,7 @@ class Blocks extends React.Component {
     }
     handleCategorySelected (categoryId) {
         const extension = extensionData.find(ext => ext.extensionId === categoryId);
-        if (extension && extension.launchDeviceConnectionFlow) {
+        if (extension && extension.launchPeripheralConnectionFlow) {
             this.handleConnectionModalStart(categoryId);
         }
 
@@ -365,9 +365,9 @@ class Blocks extends React.Component {
             this.setState({connectionModal: {
                 extensionId: extensionId,
                 useAutoScan: extension.useAutoScan,
-                deviceImage: extension.deviceImage,
-                smallDeviceImage: extension.smallDeviceImage,
-                deviceButtonImage: extension.deviceButtonImage,
+                peripheralImage: extension.peripheralImage,
+                smallPeripheralImage: extension.smallPeripheralImage,
+                peripheralButtonImage: extension.peripheralButtonImage,
                 name: extension.name,
                 connectingMessage: extension.connectingMessage,
                 helpLink: extension.helpLink
diff --git a/src/containers/connection-modal.jsx b/src/containers/connection-modal.jsx
index 276d4f72a886e6df3b5f150d1cdd443e5eee9956..164f2455bb6a22a065ce5e5ba3946170271b43e0 100644
--- a/src/containers/connection-modal.jsx
+++ b/src/containers/connection-modal.jsx
@@ -35,7 +35,7 @@ class ConnectionModal extends React.Component {
         });
     }
     handleConnecting (peripheralId) {
-        this.props.vm.connectToPeripheral(this.props.extensionId, peripheralId);
+        this.props.vm.connectPeripheral(this.props.extensionId, peripheralId);
         this.setState({
             phase: PHASES.connecting
         });
@@ -47,13 +47,13 @@ class ConnectionModal extends React.Component {
     }
     handleDisconnect () {
         this.props.onStatusButtonUpdate(this.props.extensionId, 'not ready');
-        this.props.vm.disconnectExtensionSession(this.props.extensionId);
+        this.props.vm.disconnectPeripheral(this.props.extensionId);
         this.props.onCancel();
     }
     handleCancel () {
-        // If we're not connected to a device, close the websocket so we stop scanning.
+        // If we're not connected to a peripheral, close the websocket so we stop scanning.
         if (!this.props.vm.getPeripheralIsConnected(this.props.extensionId)) {
-            this.props.vm.disconnectExtensionSession(this.props.extensionId);
+            this.props.vm.disconnectPeripheral(this.props.extensionId);
         }
         this.props.onCancel();
     }
@@ -99,12 +99,12 @@ class ConnectionModal extends React.Component {
         return (
             <ConnectionModalComponent
                 connectingMessage={this.props.connectingMessage}
-                deviceButtonImage={this.props.deviceButtonImage}
-                deviceImage={this.props.deviceImage}
                 extensionId={this.props.extensionId}
                 name={this.props.name}
+                peripheralButtonImage={this.props.peripheralButtonImage}
+                peripheralImage={this.props.peripheralImage}
                 phase={this.state.phase}
-                smallDeviceImage={this.props.smallDeviceImage}
+                smallPeripheralImage={this.props.smallPeripheralImage}
                 title={this.props.extensionId}
                 useAutoScan={this.props.useAutoScan}
                 vm={this.props.vm}
@@ -121,14 +121,14 @@ class ConnectionModal extends React.Component {
 
 ConnectionModal.propTypes = {
     connectingMessage: PropTypes.node.isRequired,
-    deviceButtonImage: PropTypes.string,
-    deviceImage: PropTypes.string.isRequired,
     extensionId: PropTypes.string.isRequired,
     helpLink: PropTypes.string.isRequired,
     name: PropTypes.node.isRequired,
     onCancel: PropTypes.func.isRequired,
     onStatusButtonUpdate: PropTypes.func.isRequired,
-    smallDeviceImage: PropTypes.string.isRequired,
+    peripheralButtonImage: PropTypes.string,
+    peripheralImage: PropTypes.string.isRequired,
+    smallPeripheralImage: PropTypes.string.isRequired,
     useAutoScan: PropTypes.bool.isRequired,
     vm: PropTypes.instanceOf(VM).isRequired
 };
diff --git a/src/containers/gui.jsx b/src/containers/gui.jsx
index f08e6bab746dd171f040e48e916663bbf438538b..04c6142dce25e073c4f0a0676cd2ab3e5c37590d 100644
--- a/src/containers/gui.jsx
+++ b/src/containers/gui.jsx
@@ -7,6 +7,7 @@ import ReactModal from 'react-modal';
 
 import ErrorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
 import {openExtensionLibrary} from '../reducers/modals';
+import {setProjectTitle} from '../reducers/project-title';
 import {
     activateTab,
     BLOCKS_TAB_INDEX,
@@ -34,6 +35,10 @@ class GUI extends React.Component {
         };
     }
     componentDidMount () {
+        if (this.props.projectTitle) {
+            this.props.onUpdateReduxProjectTitle(this.props.projectTitle);
+        }
+
         if (this.props.vm.initialized) return;
         this.audioEngine = new AudioEngine();
         this.props.vm.attachAudioEngine(this.audioEngine);
@@ -65,6 +70,9 @@ class GUI extends React.Component {
                     });
             });
         }
+        if (this.props.projectTitle !== nextProps.projectTitle) {
+            this.props.onUpdateReduxProjectTitle(nextProps.projectTitle);
+        }
     }
     render () {
         if (this.state.loadingError) {
@@ -75,8 +83,10 @@ class GUI extends React.Component {
             /* eslint-disable no-unused-vars */
             assetHost,
             hideIntro,
+            onUpdateReduxProjectTitle,
             projectData,
             projectHost,
+            projectTitle,
             /* eslint-enable no-unused-vars */
             children,
             fetchingProject,
@@ -97,14 +107,19 @@ class GUI extends React.Component {
 }
 
 GUI.propTypes = {
+    assetHost: PropTypes.string,
     children: PropTypes.node,
     fetchingProject: PropTypes.bool,
     hideIntro: PropTypes.bool,
     importInfoVisible: PropTypes.bool,
     loadingStateVisible: PropTypes.bool,
     onSeeCommunity: PropTypes.func,
+    onUpdateProjectTitle: PropTypes.func,
+    onUpdateReduxProjectTitle: PropTypes.func,
     previewInfoVisible: PropTypes.bool,
     projectData: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
+    projectHost: PropTypes.string,
+    projectTitle: PropTypes.string,
     vm: PropTypes.instanceOf(VM)
 };
 
@@ -134,7 +149,8 @@ const mapDispatchToProps = dispatch => ({
     onActivateCostumesTab: () => dispatch(activateTab(COSTUMES_TAB_INDEX)),
     onActivateSoundsTab: () => dispatch(activateTab(SOUNDS_TAB_INDEX)),
     onRequestCloseBackdropLibrary: () => dispatch(closeBackdropLibrary()),
-    onRequestCloseCostumeLibrary: () => dispatch(closeCostumeLibrary())
+    onRequestCloseCostumeLibrary: () => dispatch(closeCostumeLibrary()),
+    onUpdateReduxProjectTitle: title => dispatch(setProjectTitle(title))
 });
 
 const ConnectedGUI = connect(
diff --git a/src/containers/project-loader.jsx b/src/containers/project-loader.jsx
index 507b716523796e14fb9b73fbb93cca44df2785f8..66081b7a906871cef4a5230d9264cc434c2d3dcd 100644
--- a/src/containers/project-loader.jsx
+++ b/src/containers/project-loader.jsx
@@ -6,6 +6,7 @@ import {defineMessages, injectIntl, intlShape} from 'react-intl';
 
 import analytics from '../lib/analytics';
 import log from '../lib/log';
+import {setProjectTitle} from '../reducers/project-title';
 
 import {
     openLoadingProject,
@@ -75,6 +76,12 @@ class ProjectLoader extends React.Component {
         if (thisFileInput.files) { // Don't attempt to load if no file was selected
             this.props.openLoadingState();
             reader.readAsArrayBuffer(thisFileInput.files[0]);
+            if (thisFileInput.files[0].name) {
+                const matches = thisFileInput.files[0].name.match(/^(.*)\.sb3$/);
+                if (matches) {
+                    this.props.onSetProjectTitle(matches[1].substring(0, 100));
+                }
+            }
         }
     }
     handleClick () {
@@ -112,6 +119,7 @@ ProjectLoader.propTypes = {
     children: PropTypes.func,
     closeLoadingState: PropTypes.func,
     intl: intlShape.isRequired,
+    onSetProjectTitle: PropTypes.func,
     openLoadingState: PropTypes.func,
     vm: PropTypes.shape({
         loadProject: PropTypes.func
@@ -124,6 +132,7 @@ const mapStateToProps = state => ({
 
 const mapDispatchToProps = dispatch => ({
     closeLoadingState: () => dispatch(closeLoadingProject()),
+    onSetProjectTitle: title => dispatch(setProjectTitle(title)),
     openLoadingState: () => dispatch(openLoadingProject())
 });
 
diff --git a/src/containers/project-saver.jsx b/src/containers/project-saver.jsx
index 13be33da808b1fa2cf9e10c6d2db2644112ef2e0..c32d4b1bf0a045b6c20f9d9593cf5548aebf922b 100644
--- a/src/containers/project-saver.jsx
+++ b/src/containers/project-saver.jsx
@@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
 import React from 'react';
 import {connect} from 'react-redux';
 import storage from '../lib/storage';
+import {projectTitleInitialState} from '../reducers/project-title';
+
 
 /**
  * Project saver component passes a saveProject function to its child.
@@ -33,21 +35,15 @@ class ProjectSaver extends React.Component {
         document.body.appendChild(saveLink);
 
         this.props.saveProjectSb3().then(content => {
-            // TODO user-friendly project name
-            // File name: project-DATE-TIME
-            const date = new Date();
-            const timestamp = `${date.toLocaleDateString()}-${date.toLocaleTimeString()}`;
-            const filename = `untitled-project-${timestamp}.sb3`;
-
             // Use special ms version if available to get it working on Edge.
             if (navigator.msSaveOrOpenBlob) {
-                navigator.msSaveOrOpenBlob(content, filename);
+                navigator.msSaveOrOpenBlob(content, this.props.projectFilename);
                 return;
             }
 
             const url = window.URL.createObjectURL(content);
             saveLink.href = url;
-            saveLink.download = filename;
+            saveLink.download = this.props.projectFilename;
             saveLink.click();
             window.URL.revokeObjectURL(url);
             document.body.removeChild(saveLink);
@@ -86,14 +82,24 @@ class ProjectSaver extends React.Component {
     }
 }
 
+const getProjectFilename = (curTitle, defaultTitle) => {
+    let filenameTitle = curTitle;
+    if (!filenameTitle || filenameTitle.length === 0) {
+        filenameTitle = defaultTitle;
+    }
+    return `${filenameTitle.substring(0, 100)}.sb3`;
+};
+
 ProjectSaver.propTypes = {
     children: PropTypes.func,
+    projectFilename: PropTypes.string,
     projectId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
     saveProjectSb3: PropTypes.func
 };
 
 const mapStateToProps = state => ({
     saveProjectSb3: state.scratchGui.vm.saveProjectSb3.bind(state.scratchGui.vm),
+    projectFilename: getProjectFilename(state.scratchGui.projectTitle, projectTitleInitialState),
     projectId: state.scratchGui.projectId
 });
 
diff --git a/src/containers/scanning-step.jsx b/src/containers/scanning-step.jsx
index 07595d5266d937c577f2e44634995b7849e3e5fb..6e1daa8e6eb32ebdfbef49db1d4ca4b8b87ed03a 100644
--- a/src/containers/scanning-step.jsx
+++ b/src/containers/scanning-step.jsx
@@ -14,18 +14,18 @@ class ScanningStep extends React.Component {
         ]);
         this.state = {
             scanning: true,
-            deviceList: []
+            peripheralList: []
         };
     }
     componentDidMount () {
-        this.props.vm.startDeviceScan(this.props.extensionId);
+        this.props.vm.scanForPeripheral(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
+        // @todo: stop the peripheral scan here
         this.props.vm.removeListener(
             'PERIPHERAL_LIST_UPDATE', this.handlePeripheralListUpdate);
         this.props.vm.removeListener(
@@ -34,7 +34,7 @@ class ScanningStep extends React.Component {
     handlePeripheralScanTimeout () {
         this.setState({
             scanning: false,
-            deviceList: []
+            peripheralList: []
         });
     }
     handlePeripheralListUpdate (newList) {
@@ -42,22 +42,22 @@ class ScanningStep extends React.Component {
         const peripheralArray = Object.keys(newList).map(id =>
             newList[id]
         );
-        this.setState({deviceList: peripheralArray});
+        this.setState({peripheralList: peripheralArray});
     }
     handleRefresh () {
-        this.props.vm.startDeviceScan(this.props.extensionId);
+        this.props.vm.scanForPeripheral(this.props.extensionId);
         this.setState({
             scanning: true,
-            deviceList: []
+            peripheralList: []
         });
     }
     render () {
         return (
             <ScanningStepComponent
-                deviceList={this.state.deviceList}
+                peripheralList={this.state.peripheralList}
                 phase={this.state.phase}
                 scanning={this.state.scanning}
-                smallDeviceImage={this.props.smallDeviceImage}
+                smallPeripheralImage={this.props.smallPeripheralImage}
                 title={this.props.extensionId}
                 onConnected={this.props.onConnected}
                 onConnecting={this.props.onConnecting}
@@ -71,7 +71,7 @@ ScanningStep.propTypes = {
     extensionId: PropTypes.string.isRequired,
     onConnected: PropTypes.func.isRequired,
     onConnecting: PropTypes.func.isRequired,
-    smallDeviceImage: PropTypes.string,
+    smallPeripheralImage: PropTypes.string,
     vm: PropTypes.instanceOf(VM).isRequired
 };
 
diff --git a/src/css/colors.css b/src/css/colors.css
index 37ffa62227a6f6ccb42a6170d4652db037f4f769..2222608922a9df36770fb8330fb663b2ea1e43c7 100644
--- a/src/css/colors.css
+++ b/src/css/colors.css
@@ -6,6 +6,7 @@ $ui-modal-overlay: hsla(215, 100%, 65%, 0.9); /* 90% transparent version of moti
 
 $ui-white: hsla(0, 100%, 100%, 1); /* #FFFFFF */
 $ui-white-transparent: hsla(0, 100%, 100%, 0.25); /* 25% transparent version of ui-white */
+$ui-transparent: hsla(0, 100%, 100%, 0); /* 25% transparent version of ui-white */
 
 $ui-black-transparent: hsla(0, 0%, 0%, 0.15); /* 15% transparent version of black */
 
diff --git a/src/lib/libraries/extensions/index.jsx b/src/lib/libraries/extensions/index.jsx
index edd4fa512b6e2e414762aa6fccb9fdab5cf7dfdf..4b5a4db07c6c2779693bdd71549ed8cd60db3583 100644
--- a/src/lib/libraries/extensions/index.jsx
+++ b/src/lib/libraries/extensions/index.jsx
@@ -9,13 +9,13 @@ import microbitImage from './microbit.png';
 import ev3Image from './ev3.png';
 import wedoImage from './wedo.png';
 
-import microbitDeviceImage from './device-connection/microbit/microbit-illustration.svg';
-import microbitMenuImage from './device-connection/microbit/microbit-small.svg';
-import ev3DeviceImage from './device-connection/ev3/ev3-hub-illustration.svg';
-import ev3MenuImage from './device-connection/ev3/ev3-small.svg';
-import wedoDeviceImage from './device-connection/wedo/wedo-illustration.svg';
-import wedoMenuImage from './device-connection/wedo/wedo-small.svg';
-import wedoButtonImage from './device-connection/wedo/wedo-button-illustration.svg';
+import microbitPeripheralImage from './peripheral-connection/microbit/microbit-illustration.svg';
+import microbitMenuImage from './peripheral-connection/microbit/microbit-small.svg';
+import ev3PeripheralImage from './peripheral-connection/ev3/ev3-hub-illustration.svg';
+import ev3MenuImage from './peripheral-connection/ev3/ev3-small.svg';
+import wedoPeripheralImage from './peripheral-connection/wedo/wedo-illustration.svg';
+import wedoMenuImage from './peripheral-connection/wedo/wedo-small.svg';
+import wedoButtonImage from './peripheral-connection/wedo/wedo-button-illustration.svg';
 
 export default [
     {
@@ -78,9 +78,9 @@ export default [
     {
         name: (
             <FormattedMessage
-                defaultMessage="Google Translate"
-                description="Name for the 'Google Translate' extension. Do not translate 'Google'."
-                id="gui.extension.googletranslate.name"
+                defaultMessage="Translate"
+                description="Name for the Translate extension"
+                id="gui.extension.translate.name"
             />
         ),
         extensionId: 'translate',
@@ -88,8 +88,8 @@ export default [
         description: (
             <FormattedMessage
                 defaultMessage="Translate text into many languages."
-                description="Description for the 'Google Translate' extension"
-                id="gui.extension.googletranslate.description"
+                description="Description for the Translate extension"
+                id="gui.extension.translate.description"
             />
         ),
         featured: true
@@ -107,10 +107,10 @@ export default [
         ),
         featured: true,
         disabled: false,
-        launchDeviceConnectionFlow: true,
+        launchPeripheralConnectionFlow: true,
         useAutoScan: false,
-        deviceImage: microbitDeviceImage,
-        smallDeviceImage: microbitMenuImage,
+        peripheralImage: microbitPeripheralImage,
+        smallPeripheralImage: microbitMenuImage,
         connectingMessage: (
             <FormattedMessage
                 defaultMessage="Connecting"
@@ -133,10 +133,10 @@ export default [
         ),
         featured: true,
         disabled: false,
-        launchDeviceConnectionFlow: true,
+        launchPeripheralConnectionFlow: true,
         useAutoScan: false,
-        deviceImage: ev3DeviceImage,
-        smallDeviceImage: ev3MenuImage,
+        peripheralImage: ev3PeripheralImage,
+        smallPeripheralImage: ev3MenuImage,
         connectingMessage: (
             <FormattedMessage
                 defaultMessage="Connecting. Make sure the pin on your EV3 is set to 1234."
@@ -159,11 +159,11 @@ export default [
         ),
         featured: true,
         disabled: false,
-        launchDeviceConnectionFlow: true,
+        launchPeripheralConnectionFlow: true,
         useAutoScan: true,
-        deviceImage: wedoDeviceImage,
-        smallDeviceImage: wedoMenuImage,
-        deviceButtonImage: wedoButtonImage,
+        peripheralImage: wedoPeripheralImage,
+        smallPeripheralImage: wedoMenuImage,
+        peripheralButtonImage: wedoButtonImage,
         connectingMessage: (
             <FormattedMessage
                 defaultMessage="Connecting"
diff --git a/src/lib/libraries/extensions/device-connection/ev3/ev3-hub-illustration.svg b/src/lib/libraries/extensions/peripheral-connection/ev3/ev3-hub-illustration.svg
similarity index 100%
rename from src/lib/libraries/extensions/device-connection/ev3/ev3-hub-illustration.svg
rename to src/lib/libraries/extensions/peripheral-connection/ev3/ev3-hub-illustration.svg
diff --git a/src/lib/libraries/extensions/device-connection/ev3/ev3-small.svg b/src/lib/libraries/extensions/peripheral-connection/ev3/ev3-small.svg
similarity index 100%
rename from src/lib/libraries/extensions/device-connection/ev3/ev3-small.svg
rename to src/lib/libraries/extensions/peripheral-connection/ev3/ev3-small.svg
diff --git a/src/lib/libraries/extensions/device-connection/microbit/microbit-illustration.svg b/src/lib/libraries/extensions/peripheral-connection/microbit/microbit-illustration.svg
similarity index 100%
rename from src/lib/libraries/extensions/device-connection/microbit/microbit-illustration.svg
rename to src/lib/libraries/extensions/peripheral-connection/microbit/microbit-illustration.svg
diff --git a/src/lib/libraries/extensions/device-connection/microbit/microbit-small.svg b/src/lib/libraries/extensions/peripheral-connection/microbit/microbit-small.svg
similarity index 100%
rename from src/lib/libraries/extensions/device-connection/microbit/microbit-small.svg
rename to src/lib/libraries/extensions/peripheral-connection/microbit/microbit-small.svg
diff --git a/src/lib/libraries/extensions/device-connection/wedo/wedo-button-illustration.svg b/src/lib/libraries/extensions/peripheral-connection/wedo/wedo-button-illustration.svg
similarity index 100%
rename from src/lib/libraries/extensions/device-connection/wedo/wedo-button-illustration.svg
rename to src/lib/libraries/extensions/peripheral-connection/wedo/wedo-button-illustration.svg
diff --git a/src/lib/libraries/extensions/device-connection/wedo/wedo-illustration.svg b/src/lib/libraries/extensions/peripheral-connection/wedo/wedo-illustration.svg
similarity index 100%
rename from src/lib/libraries/extensions/device-connection/wedo/wedo-illustration.svg
rename to src/lib/libraries/extensions/peripheral-connection/wedo/wedo-illustration.svg
diff --git a/src/lib/libraries/extensions/device-connection/wedo/wedo-small.svg b/src/lib/libraries/extensions/peripheral-connection/wedo/wedo-small.svg
similarity index 100%
rename from src/lib/libraries/extensions/device-connection/wedo/wedo-small.svg
rename to src/lib/libraries/extensions/peripheral-connection/wedo/wedo-small.svg
diff --git a/src/lib/libraries/extensions/translate.png b/src/lib/libraries/extensions/translate.png
index 95961ae52fee6e27c5f7946c41a7e4fd1d22fe7a..8f63ade37587318aa72e0ccf8eb822ee273dd130 100644
Binary files a/src/lib/libraries/extensions/translate.png and b/src/lib/libraries/extensions/translate.png differ
diff --git a/src/lib/project-loader-hoc.jsx b/src/lib/project-loader-hoc.jsx
index eafd49cb32606437837a1e3837ae1812d9507f51..571f220fdea8786a24f8d557ae6c72fde38b37de 100644
--- a/src/lib/project-loader-hoc.jsx
+++ b/src/lib/project-loader-hoc.jsx
@@ -72,7 +72,6 @@ const ProjectLoaderHOC = function (WrappedComponent) {
                 assetHost,
                 projectHost,
                 projectId,
-                reduxProjectId,
                 setProjectId: setProjectIdProp,
                 /* eslint-enable no-unused-vars */
                 ...componentProps
diff --git a/src/lib/titled-hoc.jsx b/src/lib/titled-hoc.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..2534d96bd61ba9f4cb4db89a51e33c031f1be6c4
--- /dev/null
+++ b/src/lib/titled-hoc.jsx
@@ -0,0 +1,54 @@
+import React from 'react';
+import bindAll from 'lodash.bindall';
+import {defineMessages, intlShape, injectIntl} from 'react-intl';
+
+const messages = defineMessages({
+    defaultProjectTitle: {
+        id: 'gui.gui.defaultProjectTitle',
+        description: 'Default title for project',
+        defaultMessage: 'Scratch Project'
+    }
+});
+
+/* Higher Order Component to get and set the project title
+ * @param {React.Component} WrappedComponent component to receive project title related props
+ * @returns {React.Component} component with project loading behavior
+ */
+const TitledHOC = function (WrappedComponent) {
+    class TitledComponent extends React.Component {
+        constructor (props) {
+            super(props);
+            bindAll(this, [
+                'handleUpdateProjectTitle'
+            ]);
+            this.state = {
+                projectTitle: this.props.intl.formatMessage(messages.defaultProjectTitle)
+            };
+        }
+        handleUpdateProjectTitle (newTitle) {
+            this.setState({projectTitle: newTitle});
+        }
+        render () {
+            return (
+                <WrappedComponent
+                    projectTitle={this.state.projectTitle}
+                    onUpdateProjectTitle={this.handleUpdateProjectTitle}
+                    {...this.props}
+                />
+            );
+        }
+    }
+
+    TitledComponent.propTypes = {
+        intl: intlShape.isRequired
+    };
+
+    // return TitledComponent;
+    const IntlTitledComponent = injectIntl(TitledComponent);
+    return IntlTitledComponent;
+
+};
+
+export {
+    TitledHOC as default
+};
diff --git a/src/playground/player.jsx b/src/playground/player.jsx
index 6c2833f1b8108d08022e9d6c85bac9357f1f497f..e236de667eb4b12919548908daad377dfa827fe9 100644
--- a/src/playground/player.jsx
+++ b/src/playground/player.jsx
@@ -8,6 +8,7 @@ import Box from '../components/box/box.jsx';
 import GUI from '../containers/gui.jsx';
 import HashParserHOC from '../lib/hash-parser-hoc.jsx';
 import AppStateHOC from '../lib/app-state-hoc.jsx';
+import TitledHOC from '../lib/titled-hoc.jsx';
 
 import {setPlayer} from '../reducers/mode';
 
@@ -48,7 +49,7 @@ const mapDispatchToProps = dispatch => ({
 });
 
 const ConnectedPlayer = connect(mapStateToProps, mapDispatchToProps)(Player);
-const WrappedPlayer = HashParserHOC(AppStateHOC(ConnectedPlayer));
+const WrappedPlayer = HashParserHOC(AppStateHOC(TitledHOC(ConnectedPlayer)));
 
 const appTarget = document.createElement('div');
 document.body.appendChild(appTarget);
diff --git a/src/playground/render-gui.jsx b/src/playground/render-gui.jsx
index adec922b8c206c9211888da34a8c426362b9a10b..562e57eac9c4c60ad4aea322adeec8b907067761 100644
--- a/src/playground/render-gui.jsx
+++ b/src/playground/render-gui.jsx
@@ -4,6 +4,7 @@ import ReactDOM from 'react-dom';
 import AppStateHOC from '../lib/app-state-hoc.jsx';
 import GUI from '../containers/gui.jsx';
 import HashParserHOC from '../lib/hash-parser-hoc.jsx';
+import TitledHOC from '../lib/titled-hoc.jsx';
 
 /*
  * Render the GUI playground. This is a separate function because importing anything
@@ -12,7 +13,7 @@ import HashParserHOC from '../lib/hash-parser-hoc.jsx';
  */
 export default appTarget => {
     GUI.setAppElement(appTarget);
-    const WrappedGui = HashParserHOC(AppStateHOC(GUI));
+    const WrappedGui = HashParserHOC(AppStateHOC(TitledHOC(GUI)));
 
     // TODO a hack for testing the backpack, allow backpack host to be set by url param
     const backpackHostMatches = window.location.href.match(/[?&]backpack_host=([^&]*)&?/);
diff --git a/src/reducers/gui.js b/src/reducers/gui.js
index 9340af56e1177485aa02c361c404070b6b4c6bf3..cfad8f6825ddad3a07a56b4c62757ffbc3a97909 100644
--- a/src/reducers/gui.js
+++ b/src/reducers/gui.js
@@ -12,6 +12,7 @@ import modeReducer, {modeInitialState} from './mode';
 import monitorReducer, {monitorsInitialState} from './monitors';
 import monitorLayoutReducer, {monitorLayoutInitialState} from './monitor-layout';
 import projectIdReducer, {projectIdInitialState} from './project-id';
+import projectTitleReducer, {projectTitleInitialState} from './project-title';
 import restoreDeletionReducer, {restoreDeletionInitialState} from './restore-deletion';
 import stageSizeReducer, {stageSizeInitialState} from './stage-size';
 import targetReducer, {targetsInitialState} from './targets';
@@ -37,6 +38,7 @@ const guiInitialState = {
     monitors: monitorsInitialState,
     monitorLayout: monitorLayoutInitialState,
     projectId: projectIdInitialState,
+    projectTitle: projectTitleInitialState,
     restoreDeletion: restoreDeletionInitialState,
     targets: targetsInitialState,
     toolbox: toolboxInitialState,
@@ -80,6 +82,7 @@ const guiReducer = combineReducers({
     monitors: monitorReducer,
     monitorLayout: monitorLayoutReducer,
     projectId: projectIdReducer,
+    projectTitle: projectTitleReducer,
     restoreDeletion: restoreDeletionReducer,
     targets: targetReducer,
     toolbox: toolboxReducer,
diff --git a/src/reducers/project-title.js b/src/reducers/project-title.js
new file mode 100644
index 0000000000000000000000000000000000000000..09bf6c4eab417e626b8a719326ac685c25d46cdd
--- /dev/null
+++ b/src/reducers/project-title.js
@@ -0,0 +1,25 @@
+const SET_PROJECT_TITLE = 'projectTitle/SET_PROJECT_TITLE';
+
+// we are initializing to a blank string instead of an actual title,
+// because it would be hard to localize here
+const initialState = '';
+
+const reducer = function (state, action) {
+    if (typeof state === 'undefined') state = initialState;
+    switch (action.type) {
+    case SET_PROJECT_TITLE:
+        return action.title;
+    default:
+        return state;
+    }
+};
+const setProjectTitle = title => ({
+    type: SET_PROJECT_TITLE,
+    title: title
+});
+
+export {
+    reducer as default,
+    initialState as projectTitleInitialState,
+    setProjectTitle
+};
diff --git a/test/integration/blocks.test.js b/test/integration/blocks.test.js
index 83b72620bcc04dad457f157071a54016f74381aa..b3ec62e2f6042c69ccb5f7ea985d8267e73da93e 100644
--- a/test/integration/blocks.test.js
+++ b/test/integration/blocks.test.js
@@ -68,11 +68,11 @@ describe('Working with the blocks', () => {
         await findByText('0', scope.reportedValue);
 
         await clickText('Make a Variable');
-        let el = await findByXpath("//input[@placeholder='']");
+        let el = await findByXpath("//input[@name='New variable name:']");
         await el.sendKeys('score');
         await clickButton('OK');
         await clickText('Make a Variable');
-        el = await findByXpath("//input[@placeholder='']");
+        el = await findByXpath("//input[@name='New variable name:']");
         await el.sendKeys('second variable');
         await clickButton('OK');
 
@@ -98,7 +98,7 @@ describe('Working with the blocks', () => {
         await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation
 
         await clickText('Make a List');
-        let el = await findByXpath("//input[@placeholder='']");
+        let el = await findByXpath("//input[@name='New list name:']");
         await el.sendKeys('list1');
         await clickButton('OK');
 
diff --git a/test/integration/examples.test.js b/test/integration/examples.test.js
index ecaeb56f2fa36f9bd83095563395f72a7759426f..8408c88f39bc949ef360095c1997252acf35428f 100644
--- a/test/integration/examples.test.js
+++ b/test/integration/examples.test.js
@@ -87,11 +87,11 @@ describe('blocks example', () => {
         await clickText('Variables');
         await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation
         await clickText('Make a Variable');
-        let el = await findByXpath("//input[@placeholder='']");
+        let el = await findByXpath("//input[@name='New variable name:']");
         await el.sendKeys('score');
         await clickButton('OK');
         await clickText('Make a Variable');
-        el = await findByXpath("//input[@placeholder='']");
+        el = await findByXpath("//input[@name='New variable name:']");
         await el.sendKeys('second variable');
         await clickButton('OK');
         const logs = await getLogs();