diff --git a/package.json b/package.json
index d5b05b928bf39b4fb98c1e958b535602211ff3b0..a094b12769ac3b837223a6f888767629e91660a0 100644
--- a/package.json
+++ b/package.json
@@ -30,15 +30,18 @@
     "react-dom": "15.x.x"
   },
   "devDependencies": {
+    "autoprefixer": "6.5.3",
     "babel-core": "6.14.0",
     "babel-eslint": "7.0.0",
     "babel-loader": "6.2.5",
     "babel-plugin-transform-object-rest-spread": "6.16.0",
     "babel-preset-es2015": "6.14.0",
     "babel-preset-react": "6.11.1",
+    "classnames": "2.2.5",
     "copy-webpack-plugin": "3.0.1",
+    "css-loader": "0.26.1",
     "eslint": "3.8.1",
-    "eslint-config-scratch": "^2.0.0",
+    "eslint-config-scratch": "^3.0.0",
     "eslint-plugin-react": "6.4.1",
     "gh-pages": "0.11.0",
     "html-webpack-plugin": "2.22.0",
@@ -48,17 +51,22 @@
     "lodash.defaultsdeep": "4.4.0",
     "minilog": "3.0.1",
     "opt-cli": "1.5.1",
+    "postcss-loader": "1.2.0",
     "react": "15.3.2",
     "react-dom": "15.3.2",
     "react-modal": "1.5.2",
+    "react-redux": "4.4.6",
     "react-style-proptype": "1.2.0",
+    "redux": "3.6.0",
     "scratch-blocks": "latest",
     "scratch-render": "latest",
     "scratch-vm": "latest",
+    "style-loader": "0.13.1",
     "svg-to-image": "1.1.3",
     "svg-url-loader": "1.1.0",
     "travis-after-all": "1.4.4",
     "webpack": "1.13.2",
+    "webpack-combine-loaders": "2.0.3",
     "webpack-dev-server": "1.15.2",
     "xhr": "2.2.2"
   }
diff --git a/src/.eslintrc.js b/src/.eslintrc.js
index 77bf09f3fe1d42f5d7249ec84af903ec8670c28a..0abd74d675fae217d8745dcba17a049e96cc5fa5 100644
--- a/src/.eslintrc.js
+++ b/src/.eslintrc.js
@@ -1,9 +1,9 @@
 module.exports = {
+    root: true,
+    extends: ['scratch', 'scratch/es6', 'scratch/react'],
     env: {
-        node: false,
         browser: true
     },
-    extends: ['scratch/es6', 'scratch/react'],
     globals: {
         process: true
     }
diff --git a/src/components/blocks/blocks.css b/src/components/blocks/blocks.css
new file mode 100644
index 0000000000000000000000000000000000000000..3d00662496134202e23248933958e7abf6481746
--- /dev/null
+++ b/src/components/blocks/blocks.css
@@ -0,0 +1,7 @@
+.blocks {
+    position: absolute;
+    top: 40px;
+    right: 500px;
+    bottom: 0;
+    left: 0;
+}
diff --git a/src/components/blocks.jsx b/src/components/blocks/blocks.jsx
similarity index 62%
rename from src/components/blocks.jsx
rename to src/components/blocks/blocks.jsx
index 8e1b9a19a916cdcec349b2fb7fa7d5abeb05fa4a..fa00102abe51ca1f8437caa83d5c9619e2789e85 100644
--- a/src/components/blocks.jsx
+++ b/src/components/blocks/blocks.jsx
@@ -1,5 +1,7 @@
 const React = require('react');
 
+const styles = require('./blocks.css');
+
 class BlocksComponent extends React.Component {
     render () {
         const {
@@ -8,15 +10,8 @@ class BlocksComponent extends React.Component {
         } = this.props;
         return (
             <div
-                className="scratch-blocks"
+                className={styles.blocks}
                 ref={componentRef}
-                style={{
-                    position: 'absolute',
-                    top: 0,
-                    right: 500,
-                    bottom: 0,
-                    left: 0
-                }}
                 {...props}
             />
         );
diff --git a/src/components/costume-canvas.jsx b/src/components/costume-canvas/costume-canvas.jsx
similarity index 100%
rename from src/components/costume-canvas.jsx
rename to src/components/costume-canvas/costume-canvas.jsx
diff --git a/src/components/green-flag/green-flag.css b/src/components/green-flag/green-flag.css
new file mode 100644
index 0000000000000000000000000000000000000000..b8000e48277db1b70c458db492e1ff21df36d1af
--- /dev/null
+++ b/src/components/green-flag/green-flag.css
@@ -0,0 +1,11 @@
+.green-flag {
+    position: absolute;
+    top: 8px;
+    right: calc(480px - 16px);
+    width: 16px;
+    height: 16px;
+}
+
+.active {
+    filter: saturate(200%) brightness(150%);
+}
diff --git a/src/components/green-flag/green-flag.jsx b/src/components/green-flag/green-flag.jsx
index 8e0c12d593cef9bf4113a2907f89931962a07ce1..f1b24b1516471c1cd650181c008df3a3b180c9d8 100644
--- a/src/components/green-flag/green-flag.jsx
+++ b/src/components/green-flag/green-flag.jsx
@@ -1,5 +1,8 @@
+const classNames = require('classnames');
 const React = require('react');
+
 const greenFlagIcon = require('./green-flag.svg');
+const styles = require('./green-flag.css');
 
 const GreenFlagComponent = function (props) {
     const {
@@ -10,16 +13,11 @@ const GreenFlagComponent = function (props) {
     } = props;
     return (
         <img
-            className="scratch-green-flag"
+            className={classNames({
+                [styles.greenFlag]: true,
+                [styles.active]: active
+            })}
             src={greenFlagIcon}
-            style={{
-                position: 'absolute',
-                top: 380,
-                right: 440,
-                width: 50,
-                // @todo Get real design here
-                filter: active ? 'saturate(200%) brightness(150%)' : 'none'
-            }}
             title={title}
             onClick={onClick}
             {...componentProps}
diff --git a/src/components/gui.jsx b/src/components/gui.jsx
deleted file mode 100644
index 568d2e169e870ef21f690265f97db58796dfd3b2..0000000000000000000000000000000000000000
--- a/src/components/gui.jsx
+++ /dev/null
@@ -1,29 +0,0 @@
-const React = require('react');
-
-const GUIComponent = function (props) {
-    const {
-        children,
-        ...componentProps
-    } = props;
-    return (
-        <div
-            className="scratch-gui"
-            style={{
-                position: 'absolute',
-                top: 0,
-                right: 0,
-                bottom: 0,
-                left: 0
-            }}
-            {...componentProps}
-        >
-            {children}
-        </div>
-    );
-};
-
-GUIComponent.propTypes = {
-    children: React.PropTypes.node
-};
-
-module.exports = GUIComponent;
diff --git a/src/components/gui/gui.css b/src/components/gui/gui.css
new file mode 100644
index 0000000000000000000000000000000000000000..78b6f009ac5791ea7b1e1ec0f40a635f68193d0d
--- /dev/null
+++ b/src/components/gui/gui.css
@@ -0,0 +1,7 @@
+.gui {
+    position: absolute;
+    top: 0;
+    right: 4px;
+    bottom: 0;
+    left: 4px;
+}
diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..31e5e6ae2d0e4d6a21c8bc9cf6d7ee985e647f8e
--- /dev/null
+++ b/src/components/gui/gui.jsx
@@ -0,0 +1,90 @@
+const defaultsDeep = require('lodash.defaultsdeep');
+const React = require('react');
+const VM = require('scratch-vm');
+
+const MediaLibrary = require('../../lib/media-library');
+const shapeFromPropTypes = require('../../lib/shape-from-prop-types');
+
+const Blocks = require('../../containers/blocks.jsx');
+const GreenFlag = require('../../containers/green-flag.jsx');
+const TargetPane = require('../../containers/target-pane.jsx');
+const Stage = require('../../containers/stage.jsx');
+const StopAll = require('../../containers/stop-all.jsx');
+
+const styles = require('./gui.css');
+
+const GUIComponent = props => {
+    let {
+        basePath,
+        blocksProps,
+        children,
+        greenFlagProps,
+        mediaLibrary,
+        targetPaneProps,
+        stageProps,
+        stopAllProps,
+        vm
+    } = props;
+    blocksProps = defaultsDeep({}, blocksProps, {
+        options: {
+            media: `${basePath}static/blocks-media/`
+        }
+    });
+    if (children) {
+        return (
+            <div className={styles.gui}>
+                {children}
+            </div>
+        );
+    }
+    return (
+        <div className={styles.gui}>
+            <GreenFlag
+                vm={vm}
+                {...greenFlagProps}
+            />
+            <StopAll
+                vm={vm}
+                {...stopAllProps}
+            />
+            <Stage
+                vm={vm}
+                {...stageProps}
+            />
+            <TargetPane
+                mediaLibrary={mediaLibrary}
+                vm={vm}
+                {...targetPaneProps}
+            />
+            <Blocks
+                vm={vm}
+                {...blocksProps}
+            />
+        </div>
+    );
+};
+
+GUIComponent.propTypes = {
+    basePath: React.PropTypes.string,
+    blocksProps: shapeFromPropTypes(Blocks.propTypes, {omit: ['vm']}),
+    children: React.PropTypes.node,
+    greenFlagProps: shapeFromPropTypes(GreenFlag.propTypes, {omit: ['vm']}),
+    mediaLibrary: React.PropTypes.instanceOf(MediaLibrary),
+    stageProps: shapeFromPropTypes(Stage.propTypes, {omit: ['vm']}),
+    stopAllProps: shapeFromPropTypes(StopAll.propTypes, {omit: ['vm']}),
+    targetPaneProps: shapeFromPropTypes(TargetPane.propTypes, {omit: ['vm']}),
+    vm: React.PropTypes.instanceOf(VM)
+};
+
+GUIComponent.defaultProps = {
+    basePath: '/',
+    blocksProps: {},
+    greenFlagProps: {},
+    mediaLibrary: new MediaLibrary(),
+    targetPaneProps: {},
+    stageProps: {},
+    stopAllProps: {},
+    vm: new VM()
+};
+
+module.exports = GUIComponent;
diff --git a/src/components/library-item.jsx b/src/components/library-item.jsx
deleted file mode 100644
index 307bd97866f82eb396904acabc2940d78a014f12..0000000000000000000000000000000000000000
--- a/src/components/library-item.jsx
+++ /dev/null
@@ -1,62 +0,0 @@
-const bindAll = require('lodash.bindall');
-const React = require('react');
-const stylePropType = require('react-style-proptype');
-
-const CostumeCanvas = require('./costume-canvas.jsx');
-
-class LibraryItem extends React.Component {
-    constructor (props) {
-        super(props);
-        bindAll(this, ['handleClick']);
-    }
-    handleClick (e) {
-        this.props.onSelect(this.props.id);
-        e.preventDefault();
-    }
-    render () {
-        const style = (this.props.selected) ?
-            this.props.selectedGridTileStyle : this.props.gridTileStyle;
-        return (
-            <div
-                style={style}
-                onClick={this.handleClick}
-            >
-                <CostumeCanvas url={this.props.iconURL} />
-                <p>{this.props.name}</p>
-            </div>
-        );
-    }
-}
-
-LibraryItem.defaultProps = {
-    gridTileStyle: {
-        float: 'left',
-        width: '140px',
-        marginLeft: '5px',
-        marginRight: '5px',
-        textAlign: 'center',
-        cursor: 'pointer'
-    },
-    selectedGridTileStyle: {
-        float: 'left',
-        width: '140px',
-        marginLeft: '5px',
-        marginRight: '5px',
-        textAlign: 'center',
-        cursor: 'pointer',
-        background: '#aaa',
-        borderRadius: '6px'
-    }
-};
-
-LibraryItem.propTypes = {
-    gridTileStyle: stylePropType,
-    iconURL: React.PropTypes.string,
-    id: React.PropTypes.number,
-    name: React.PropTypes.string,
-    onSelect: React.PropTypes.func,
-    selected: React.PropTypes.bool,
-    selectedGridTileStyle: stylePropType
-};
-
-module.exports = LibraryItem;
diff --git a/src/components/library-item/library-item.css b/src/components/library-item/library-item.css
new file mode 100644
index 0000000000000000000000000000000000000000..ab3342835774064b2e75168829829eea6f711dfd
--- /dev/null
+++ b/src/components/library-item/library-item.css
@@ -0,0 +1,12 @@
+.library-item {
+    float: left;
+    width: 140px;
+    margin-left: 5px;
+    margin-right: 5px;
+    text-align: center;
+    cursor: pointer;
+}
+.library-item.is-selected {
+    background: #aaa;
+    border-radius: 6px;
+}
diff --git a/src/components/library-item/library-item.jsx b/src/components/library-item/library-item.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..641f989da0ec694391014500cc99a30079ccb7d6
--- /dev/null
+++ b/src/components/library-item/library-item.jsx
@@ -0,0 +1,41 @@
+const classNames = require('classnames');
+const bindAll = require('lodash.bindall');
+const React = require('react');
+
+const CostumeCanvas = require('../costume-canvas/costume-canvas.jsx');
+const styles = require('./library-item.css');
+
+class LibraryItem extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, ['handleClick']);
+    }
+    handleClick (e) {
+        this.props.onSelect(this.props.id);
+        e.preventDefault();
+    }
+    render () {
+        return (
+            <div
+                className={classNames({
+                    [styles.libraryItem]: true,
+                    [styles.isSelected]: this.props.selected
+                })}
+                onClick={this.handleClick}
+            >
+                <CostumeCanvas url={this.props.iconURL} />
+                <p>{this.props.name}</p>
+            </div>
+        );
+    }
+}
+
+LibraryItem.propTypes = {
+    iconURL: React.PropTypes.string,
+    id: React.PropTypes.number,
+    name: React.PropTypes.string,
+    onSelect: React.PropTypes.func,
+    selected: React.PropTypes.bool
+};
+
+module.exports = LibraryItem;
diff --git a/src/components/library/library.css b/src/components/library/library.css
new file mode 100644
index 0000000000000000000000000000000000000000..02101f223974d00a9054bf5a83cd342ab08010ad
--- /dev/null
+++ b/src/components/library/library.css
@@ -0,0 +1,8 @@
+.library-scroll-grid {
+    overflow: scroll;
+    position: absolute;
+    top: 70px;
+    bottom: 20px;
+    left: 30px;
+    right: 30px;
+}
diff --git a/src/components/library.jsx b/src/components/library/library.jsx
similarity index 86%
rename from src/components/library.jsx
rename to src/components/library/library.jsx
index 66faaa32306630b7b781acf39968d7714d3a1ba8..043ece729151d4d6529fe74f468f2ac4b67efaf1 100644
--- a/src/components/library.jsx
+++ b/src/components/library/library.jsx
@@ -1,8 +1,10 @@
 const bindAll = require('lodash.bindall');
 const React = require('react');
 
-const LibraryItem = require('./library-item.jsx');
-const ModalComponent = require('./modal.jsx');
+const LibraryItem = require('../library-item/library-item.jsx');
+const ModalComponent = require('../modal/modal.jsx');
+
+const styles = require('./library.css');
 
 class LibraryComponent extends React.Component {
     constructor (props) {
@@ -19,21 +21,13 @@ class LibraryComponent extends React.Component {
         this.setState({selectedItem: id});
     }
     render () {
-        const scrollGridStyle = {
-            overflow: 'scroll',
-            position: 'absolute',
-            top: '70px',
-            bottom: '20px',
-            left: '30px',
-            right: '30px'
-        };
         return (
             <ModalComponent
                 visible={this.props.visible}
                 onRequestClose={this.props.onRequestClose}
             >
                 <h1>{this.props.title}</h1>
-                <div style={scrollGridStyle}>
+                <div className={styles.libraryScrollGrid}>
                     {this.props.data.map((dataItem, itemId) => {
                         const scratchURL = dataItem.md5 ?
                             `https://cdn.assets.scratch.mit.edu/internalapi/asset/${dataItem.md5}/get/` :
diff --git a/src/components/modal.jsx b/src/components/modal.jsx
deleted file mode 100644
index 65a7275e6d28bf1c27cba409e27753a083edb8b8..0000000000000000000000000000000000000000
--- a/src/components/modal.jsx
+++ /dev/null
@@ -1,74 +0,0 @@
-const React = require('react');
-const ReactModal = require('react-modal');
-const stylePropType = require('react-style-proptype');
-
-class ModalComponent extends React.Component {
-    render () {
-        return (
-            <ReactModal
-                isOpen={this.props.visible}
-                ref={m => (this.modal = m)}
-                style={this.props.modalStyle}
-                onRequestClose={this.props.onRequestClose}
-            >
-                <div
-                    style={this.props.closeButtonStyle}
-                    onClick={this.props.onRequestClose}
-                >
-                    {'x'}
-                </div>
-                {this.props.children}
-            </ReactModal>
-        );
-    }
-}
-
-const modalStyle = {
-    overlay: {
-        zIndex: 1000,
-        backgroundColor: 'rgba(0, 0, 0, .75)'
-    },
-    content: {
-        position: 'absolute',
-        overflow: 'visible',
-        borderRadius: '6px',
-        padding: 0,
-        top: '5%',
-        bottom: '5%',
-        left: '5%',
-        right: '5%',
-        background: '#fcfcfc'
-    }
-};
-
-const closeButtonStyle = {
-    color: 'rgb(255, 255, 255)',
-    background: 'rgb(50, 50, 50)',
-    borderRadius: '15px',
-    width: '30px',
-    height: '25px',
-    textAlign: 'center',
-    paddingTop: '5px',
-    position: 'absolute',
-    right: '3px',
-    top: '3px',
-    cursor: 'pointer'
-};
-
-ModalComponent.defaultProps = {
-    modalStyle: modalStyle,
-    closeButtonStyle: closeButtonStyle
-};
-
-ModalComponent.propTypes = {
-    children: React.PropTypes.node,
-    closeButtonStyle: stylePropType,
-    modalStyle: React.PropTypes.shape({
-        overlay: stylePropType, // eslint-disable-line react/no-unused-prop-types
-        content: stylePropType // eslint-disable-line react/no-unused-prop-types
-    }),
-    onRequestClose: React.PropTypes.func,
-    visible: React.PropTypes.bool
-};
-
-module.exports = ModalComponent;
diff --git a/src/components/modal/modal.css b/src/components/modal/modal.css
new file mode 100644
index 0000000000000000000000000000000000000000..b9cb8527b1d31d627de55b0d8bec120c42b61095
--- /dev/null
+++ b/src/components/modal/modal.css
@@ -0,0 +1,36 @@
+.modal-overlay {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    z-index: 1000;
+    background-color: rgba(0, 0, 0, .75);
+}
+.modal-content {
+    outline: none;
+    position: absolute;
+    overflow: visible;
+    -webkit-overflow-scrolling: 'touch';
+    border: 1px solid #ccc;
+    border-radius: 6px;
+    padding: 0;
+    top: 5%;
+    right: 5%;
+    bottom: 5%;
+    left: 5%;
+    background: #fcfcfc;
+}
+.modal-close-button {
+    color: rgb(255, 255, 255);
+    background: rgb(50, 50, 50);
+    border-radius: 15px;
+    width: 30px;
+    height: 25px;
+    text-align: center;
+    padding-top: 5px;
+    position: absolute;
+    right: 3px;
+    top: 3px;
+    cursor: pointer
+}
diff --git a/src/components/modal/modal.jsx b/src/components/modal/modal.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..3c36ba50921e50e8386f8be8e6ff56e53bc7793c
--- /dev/null
+++ b/src/components/modal/modal.jsx
@@ -0,0 +1,34 @@
+const React = require('react');
+const ReactModal = require('react-modal');
+
+const styles = require('./modal.css');
+
+class ModalComponent extends React.Component {
+    render () {
+        return (
+            <ReactModal
+                className={styles.modalContent}
+                isOpen={this.props.visible}
+                overlayClassName={styles.modalOverlay}
+                ref={m => (this.modal = m)}
+                onRequestClose={this.props.onRequestClose}
+            >
+                <div
+                    className={styles.modalCloseButton}
+                    onClick={this.props.onRequestClose}
+                >
+                    {'x'}
+                </div>
+                {this.props.children}
+            </ReactModal>
+        );
+    }
+}
+
+ModalComponent.propTypes = {
+    children: React.PropTypes.node,
+    onRequestClose: React.PropTypes.func,
+    visible: React.PropTypes.bool
+};
+
+module.exports = ModalComponent;
diff --git a/src/components/sprite-selector-item/sprite-selector-item.css b/src/components/sprite-selector-item/sprite-selector-item.css
new file mode 100644
index 0000000000000000000000000000000000000000..29941a9f9c98b91510366016e1f73acd09de3639
--- /dev/null
+++ b/src/components/sprite-selector-item/sprite-selector-item.css
@@ -0,0 +1,10 @@
+.sprite-selector-item {
+    border: 1px solid;
+    border-color: transparent;
+    display: inline-block;
+    height: 72px;
+    width: 72px;
+}
+.sprite-selector-item.is-selected {
+    border-color: black;
+}
diff --git a/src/components/sprite-selector-item/sprite-selector-item.jsx b/src/components/sprite-selector-item/sprite-selector-item.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..a7de0d93c864cde916db9cfbb91f4da8c6e17f79
--- /dev/null
+++ b/src/components/sprite-selector-item/sprite-selector-item.jsx
@@ -0,0 +1,33 @@
+const classNames = require('classnames');
+const React = require('react');
+
+const CostumeCanvas = require('../costume-canvas/costume-canvas.jsx');
+const styles = require('./sprite-selector-item.css');
+
+const SpriteSelectorItem = props => (
+    <div
+        className={classNames({
+            [styles.spriteSelectorItem]: true,
+            [styles.isSelected]: props.selected
+        })}
+        onClick={props.onClick}
+    >
+        {props.costumeURL ? (
+            <CostumeCanvas
+                height={50}
+                url={props.costumeURL}
+                width={50}
+            />
+        ) : null}
+        <div>{props.name}</div>
+    </div>
+);
+
+SpriteSelectorItem.propTypes = {
+    costumeURL: React.PropTypes.string,
+    name: React.PropTypes.string,
+    onClick: React.PropTypes.func,
+    selected: React.PropTypes.bool
+};
+
+module.exports = SpriteSelectorItem;
diff --git a/src/components/sprite-selector.jsx b/src/components/sprite-selector.jsx
deleted file mode 100644
index 069829b7347f50a90dce6ee2ec0595c4b1a86c25..0000000000000000000000000000000000000000
--- a/src/components/sprite-selector.jsx
+++ /dev/null
@@ -1,59 +0,0 @@
-const React = require('react');
-
-const SpriteSelectorComponent = function (props) {
-    const {
-        onChange,
-        sprites,
-        value,
-        openNewSprite,
-        openNewCostume,
-        openNewBackdrop,
-        ...componentProps
-    } = props;
-    return (
-        <div
-            style={{
-                position: 'absolute',
-                top: 380,
-                right: 10
-            }}
-            {...componentProps}
-        >
-            <select
-                multiple
-                value={value}
-                onChange={onChange}
-            >
-                {sprites.map(sprite => (
-                    <option
-                        key={sprite.id}
-                        value={sprite.id}
-                    >
-                        {sprite.name}
-                    </option>
-                ))}
-            </select>
-            <p>
-                <button onClick={openNewSprite}>New sprite</button>
-                <button onClick={openNewCostume}>New costume</button>
-                <button onClick={openNewBackdrop}>New backdrop</button>
-            </p>
-        </div>
-    );
-};
-
-SpriteSelectorComponent.propTypes = {
-    onChange: React.PropTypes.func,
-    openNewBackdrop: React.PropTypes.func,
-    openNewCostume: React.PropTypes.func,
-    openNewSprite: React.PropTypes.func,
-    sprites: React.PropTypes.arrayOf(
-        React.PropTypes.shape({
-            id: React.PropTypes.string,
-            name: React.PropTypes.string
-        })
-    ),
-    value: React.PropTypes.arrayOf(React.PropTypes.string)
-};
-
-module.exports = SpriteSelectorComponent;
diff --git a/src/components/sprite-selector/sprite-selector.css b/src/components/sprite-selector/sprite-selector.css
new file mode 100644
index 0000000000000000000000000000000000000000..1eadc56d506fe17bad44bb1348d64fe54b124412
--- /dev/null
+++ b/src/components/sprite-selector/sprite-selector.css
@@ -0,0 +1,3 @@
+.sprite-selector {
+    width: 400px;
+}
diff --git a/src/components/sprite-selector/sprite-selector.jsx b/src/components/sprite-selector/sprite-selector.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..770e7ca6ffd08786257cb0808bc371aa85810dde
--- /dev/null
+++ b/src/components/sprite-selector/sprite-selector.jsx
@@ -0,0 +1,55 @@
+const React = require('react');
+
+const SpriteSelectorItem = require('../../containers/sprite-selector-item.jsx');
+
+const styles = require('./sprite-selector.css');
+
+const SpriteSelectorComponent = function (props) {
+    const {
+        onSelectSprite,
+        selectedId,
+        sprites,
+        ...componentProps
+    } = props;
+    return (
+        <div
+            className={styles.spriteSelector}
+            {...componentProps}
+        >
+            {Object.keys(sprites)
+                // Re-order by list order
+                .sort((id1, id2) => sprites[id1].order - sprites[id2].order)
+                .map(id => (
+                    <SpriteSelectorItem
+                        costumeURL={sprites[id].costume.skin}
+                        id={id}
+                        key={id}
+                        name={sprites[id].name}
+                        selected={id === selectedId}
+                        onClick={onSelectSprite}
+                    />
+                ))
+            }
+        </div>
+    );
+};
+
+SpriteSelectorComponent.propTypes = {
+    onSelectSprite: React.PropTypes.func,
+    selectedId: React.PropTypes.string,
+    sprites: React.PropTypes.shape({
+        id: React.PropTypes.shape({
+            costume: React.PropTypes.shape({
+                skin: React.PropTypes.string,
+                name: React.PropTypes.string,
+                bitmapResolution: React.PropTypes.number,
+                rotationCenterX: React.PropTypes.number,
+                rotationCenterY: React.PropTypes.number
+            }),
+            name: React.PropTypes.string,
+            order: React.PropTypes.number
+        })
+    })
+};
+
+module.exports = SpriteSelectorComponent;
diff --git a/src/components/stage-selector/stage-selector.css b/src/components/stage-selector/stage-selector.css
new file mode 100644
index 0000000000000000000000000000000000000000..0981e0ebeeae4eef41fa4a2dc3965b64069aea21
--- /dev/null
+++ b/src/components/stage-selector/stage-selector.css
@@ -0,0 +1,11 @@
+.stage-selector {
+        position: absolute;
+        top: 0;
+        right: 0;
+        width: 72px;
+        border: 1px solid;
+        border-color: transparent;
+}
+.stage-selector.is-selected {
+        border-color: black;
+}
diff --git a/src/components/stage-selector/stage-selector.jsx b/src/components/stage-selector/stage-selector.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..db6b93e97c104c31d91a81d0ff0b0a31330548d5
--- /dev/null
+++ b/src/components/stage-selector/stage-selector.jsx
@@ -0,0 +1,36 @@
+const classNames = require('classnames');
+const React = require('react');
+
+const CostumeCanvas = require('../costume-canvas/costume-canvas.jsx');
+const styles = require('./stage-selector.css');
+
+const StageSelector = props => (
+    <div
+        className={classNames({
+            [styles.stageSelector]: true,
+            [styles.isSelected]: props.selected
+        })}
+        onClick={props.onClick}
+    >
+        <div>Stage</div>
+        <div>Backgrounds</div>
+        <div>{props.backdropCount}</div>
+        <hr />
+        {props.url ? (
+            <CostumeCanvas
+                height={42}
+                url={props.url}
+                width={50}
+            />
+        ) : null}
+    </div>
+);
+
+StageSelector.propTypes = {
+    backdropCount: React.PropTypes.number,
+    onClick: React.PropTypes.func,
+    selected: React.PropTypes.bool,
+    url: React.PropTypes.string
+};
+
+module.exports = StageSelector;
diff --git a/src/components/stage/stage.css b/src/components/stage/stage.css
new file mode 100644
index 0000000000000000000000000000000000000000..60d9f9a1023b2bda348bb08c01fc8eb8e88db516
--- /dev/null
+++ b/src/components/stage/stage.css
@@ -0,0 +1,5 @@
+.stage {
+    position: absolute;
+    top: 40px;
+    right: 0;
+}
diff --git a/src/components/stage.jsx b/src/components/stage/stage.jsx
similarity index 83%
rename from src/components/stage.jsx
rename to src/components/stage/stage.jsx
index 10e31209f73ecf4507bd4688a3bd9abbb60cba39..daf447999b67910517a2c63f3a99723e7c51ca9e 100644
--- a/src/components/stage.jsx
+++ b/src/components/stage/stage.jsx
@@ -1,5 +1,7 @@
 const React = require('react');
 
+const styles = require('./stage.css');
+
 class StageComponent extends React.Component {
     render () {
         const {
@@ -10,12 +12,9 @@ class StageComponent extends React.Component {
         } = this.props;
         return (
             <canvas
-                className="scratch-stage"
+                className={styles.stage}
                 ref={canvasRef}
                 style={{
-                    position: 'absolute',
-                    top: 10,
-                    right: 10,
                     width: width,
                     height: height
                 }}
diff --git a/src/components/stop-all/stop-all.css b/src/components/stop-all/stop-all.css
new file mode 100644
index 0000000000000000000000000000000000000000..ff44af122de95cbf7344bece99700e37a5c895c1
--- /dev/null
+++ b/src/components/stop-all/stop-all.css
@@ -0,0 +1,11 @@
+.stop-all {
+    position: absolute;
+    top: 8px;
+    right: calc(480px - 16px - 12px - 16px);
+    width: 16px;
+    height: 16px;
+}
+
+.active {
+    filter: saturate(200%) brightness(150%);
+}
diff --git a/src/components/stop-all/stop-all.jsx b/src/components/stop-all/stop-all.jsx
index 0facbe40c5cd2a7885891be8f3afcfac3eb6bf97..8d0d8ccfb00004e4ec79c00b33e0e200ee98ebac 100644
--- a/src/components/stop-all/stop-all.jsx
+++ b/src/components/stop-all/stop-all.jsx
@@ -1,5 +1,8 @@
+const classNames = require('classnames');
 const React = require('react');
+
 const stopAllIcon = require('./stop-all.svg');
+const styles = require('./stop-all.css');
 
 const StopAllComponent = function (props) {
     const {
@@ -10,16 +13,11 @@ const StopAllComponent = function (props) {
     } = props;
     return (
         <img
-            className="scratch-stop-all"
+            className={classNames({
+                [styles.stopAll]: true,
+                [styles.active]: active
+            })}
             src={stopAllIcon}
-            style={{
-                position: 'absolute',
-                top: 380,
-                right: 380,
-                width: 50,
-                // @todo Get real design here
-                filter: active ? 'saturate(200%) brightness(150%)' : 'none'
-            }}
             title={title}
             onClick={onClick}
             {...componentProps}
diff --git a/src/components/target-pane/target-pane.css b/src/components/target-pane/target-pane.css
new file mode 100644
index 0000000000000000000000000000000000000000..626220df8b14442d1b05b38eb03122e3111d13a9
--- /dev/null
+++ b/src/components/target-pane/target-pane.css
@@ -0,0 +1,12 @@
+.target-pane {
+    position: absolute;
+    top: calc(40px + 360px + 8px);
+    right: 0;
+    width: 480px;
+}
+.target-pane-library-buttons {
+    position: absolute;
+    right: 0;
+    top: 108px;
+    width: 72px;
+}
diff --git a/src/components/target-pane/target-pane.jsx b/src/components/target-pane/target-pane.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..48883747aa4f27e5b440c92e221f4ea63356bfe9
--- /dev/null
+++ b/src/components/target-pane/target-pane.jsx
@@ -0,0 +1,116 @@
+const React = require('react');
+
+const MediaLibrary = require('../../lib/media-library');
+const VM = require('scratch-vm');
+
+const BackdropLibrary = require('../../containers/backdrop-library.jsx');
+const CostumeLibrary = require('../../containers/costume-library.jsx');
+const SpriteLibrary = require('../../containers/sprite-library.jsx');
+const SpriteSelectorComponent = require('../sprite-selector/sprite-selector.jsx');
+const StageSelector = require('../../containers/stage-selector.jsx');
+
+const styles = require('./target-pane.css');
+
+/*
+ * Pane that contains the sprite selector, sprite info, stage selector,
+ * and the new sprite, costume and backdrop buttons
+ * @param {object} props Props for the component
+ * @returns {React.Component} rendered component
+ */
+const TargetPane = function (props) {
+    const {
+        editingTarget,
+        mediaLibrary,
+        backdropLibraryVisible,
+        costumeLibraryVisible,
+        spriteLibraryVisible,
+        onNewSpriteClick,
+        onNewCostumeClick,
+        onNewBackdropClick,
+        onRequestCloseBackdropLibrary,
+        onRequestCloseCostumeLibrary,
+        onRequestCloseSpriteLibrary,
+        onSelectSprite,
+        stage,
+        sprites,
+        vm,
+        ...componentProps
+    } = props;
+    return (
+        <div
+            className={styles.targetPane}
+            {...componentProps}
+        >
+            <SpriteSelectorComponent
+                selectedId={editingTarget}
+                sprites={sprites}
+                onSelectSprite={onSelectSprite}
+            />
+            <StageSelector
+                backdropCount={stage.costumeCount}
+                id={stage.id}
+                selected={stage.id === editingTarget}
+                url={stage.costume.skin}
+                onSelect={onSelectSprite}
+            />
+            <p className={styles.targetPaneLibraryButtons}>
+                <button onClick={onNewSpriteClick}>New Sprite</button>
+                {editingTarget === stage.id ? (
+                    <button onClick={onNewBackdropClick}>New Backdrop</button>
+                ) : (
+                    <button onClick={onNewCostumeClick}>New Costume</button>
+                )}
+                <SpriteLibrary
+                    mediaLibrary={mediaLibrary}
+                    visible={spriteLibraryVisible}
+                    vm={vm}
+                    onRequestClose={onRequestCloseSpriteLibrary}
+                />
+                <CostumeLibrary
+                    mediaLibrary={mediaLibrary}
+                    visible={costumeLibraryVisible}
+                    vm={vm}
+                    onRequestClose={onRequestCloseCostumeLibrary}
+                />
+                <BackdropLibrary
+                    mediaLibrary={mediaLibrary}
+                    visible={backdropLibraryVisible}
+                    vm={vm}
+                    onRequestClose={onRequestCloseBackdropLibrary}
+                />
+            </p>
+        </div>
+    );
+};
+const spriteShape = React.PropTypes.shape({
+    costume: React.PropTypes.shape({
+        skin: React.PropTypes.string,
+        name: React.PropTypes.string,
+        bitmapResolution: React.PropTypes.number,
+        rotationCenterX: React.PropTypes.number,
+        rotationCenterY: React.PropTypes.number
+    }),
+    id: React.PropTypes.string,
+    name: React.PropTypes.string,
+    order: React.PropTypes.number
+});
+
+TargetPane.propTypes = {
+    backdropLibraryVisible: React.PropTypes.bool,
+    costumeLibraryVisible: React.PropTypes.bool,
+    editingTarget: React.PropTypes.string,
+    mediaLibrary: React.PropTypes.instanceOf(MediaLibrary),
+    onNewBackdropClick: React.PropTypes.func,
+    onNewCostumeClick: React.PropTypes.func,
+    onNewSpriteClick: React.PropTypes.func,
+    onRequestCloseBackdropLibrary: React.PropTypes.func,
+    onRequestCloseCostumeLibrary: React.PropTypes.func,
+    onRequestCloseSpriteLibrary: React.PropTypes.func,
+    onSelectSprite: React.PropTypes.func,
+    spriteLibraryVisible: React.PropTypes.bool,
+    sprites: React.PropTypes.objectOf(spriteShape),
+    stage: spriteShape,
+    vm: React.PropTypes.instanceOf(VM)
+};
+
+module.exports = TargetPane;
diff --git a/src/containers/backdrop-library.jsx b/src/containers/backdrop-library.jsx
index ace824bead4a9897a40cd85a35c910788fa26503..dbd06b5acef5ab9785587d98dfab07d1a45dcbeb 100644
--- a/src/containers/backdrop-library.jsx
+++ b/src/containers/backdrop-library.jsx
@@ -3,13 +3,16 @@ const React = require('react');
 const VM = require('scratch-vm');
 const MediaLibrary = require('../lib/media-library');
 
-const LibaryComponent = require('../components/library.jsx');
+const LibaryComponent = require('../components/library/library.jsx');
 
 
 class BackdropLibrary extends React.Component {
     constructor (props) {
         super(props);
-        bindAll(this, ['setData', 'handleItemSelect']);
+        bindAll(this, [
+            'setData',
+            'handleItemSelect'
+        ]);
         this.state = {backdropData: []};
     }
     componentWillReceiveProps (nextProps) {
diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx
index f0ac707e9b29b9ee2fc05224251079b570a3a130..5a579f6e459807eef1e0cb4149f38eb55a92da4b 100644
--- a/src/containers/blocks.jsx
+++ b/src/containers/blocks.jsx
@@ -4,7 +4,7 @@ const React = require('react');
 const ScratchBlocks = require('scratch-blocks');
 const VM = require('scratch-vm');
 
-const BlocksComponent = require('../components/blocks.jsx');
+const BlocksComponent = require('../components/blocks/blocks.jsx');
 
 class Blocks extends React.Component {
     constructor (props) {
diff --git a/src/containers/costume-library.jsx b/src/containers/costume-library.jsx
index 0dd08eabe6c40409cc9330882f962e87ea83c23d..edb1e8c3f15aa6f878956adc3a52f632e2e2f305 100644
--- a/src/containers/costume-library.jsx
+++ b/src/containers/costume-library.jsx
@@ -3,13 +3,16 @@ const React = require('react');
 const VM = require('scratch-vm');
 const MediaLibrary = require('../lib/media-library');
 
-const LibaryComponent = require('../components/library.jsx');
+const LibaryComponent = require('../components/library/library.jsx');
 
 
 class CostumeLibrary extends React.Component {
     constructor (props) {
         super(props);
-        bindAll(this, ['setData', 'handleItemSelected']);
+        bindAll(this, [
+            'handleItemSelected',
+            'setData'
+        ]);
         this.state = {costumeData: []};
     }
     componentWillReceiveProps (nextProps) {
diff --git a/src/containers/gui.jsx b/src/containers/gui.jsx
index bb44a60ca84b6c614ae6b221c67f6bbb1d0d3a9b..c254817b4bd02a77149645fcf28e32675cf38dde 100644
--- a/src/containers/gui.jsx
+++ b/src/containers/gui.jsx
@@ -1,33 +1,12 @@
-const bindAll = require('lodash.bindall');
-const defaultsDeep = require('lodash.defaultsdeep');
 const React = require('react');
 const VM = require('scratch-vm');
 
-const VMManager = require('../lib/vm-manager');
-const MediaLibrary = require('../lib/media-library');
-const shapeFromPropTypes = require('../lib/shape-from-prop-types');
+const vmListenerHOC = require('../lib/vm-listener-hoc.jsx');
 
-const Blocks = require('./blocks.jsx');
-const GUIComponent = require('../components/gui.jsx');
-const GreenFlag = require('./green-flag.jsx');
-const SpriteSelector = require('./sprite-selector.jsx');
-const Stage = require('./stage.jsx');
-const StopAll = require('./stop-all.jsx');
-
-const SpriteLibrary = require('./sprite-library.jsx');
-const CostumeLibrary = require('./costume-library.jsx');
-const BackdropLibrary = require('./backdrop-library.jsx');
+const GUIComponent = require('../components/gui/gui.jsx');
 
 class GUI extends React.Component {
-    constructor (props) {
-        super(props);
-        bindAll(this, ['closeModal']);
-        this.vmManager = new VMManager(this.props.vm);
-        this.mediaLibrary = new MediaLibrary();
-        this.state = {currentModal: null};
-    }
     componentDidMount () {
-        this.vmManager.attachKeyboardEvents();
         this.props.vm.loadProject(this.props.projectData);
         this.props.vm.start();
     }
@@ -37,105 +16,29 @@ class GUI extends React.Component {
         }
     }
     componentWillUnmount () {
-        this.vmManager.detachKeyboardEvents();
         this.props.vm.stopAll();
     }
-    openModal (modalName) {
-        this.setState({currentModal: modalName});
-    }
-    closeModal () {
-        this.setState({currentModal: null});
-    }
     render () {
-        let {
-            backdropLibraryProps,
-            basePath,
-            blocksProps,
-            costumeLibraryProps,
-            greenFlagProps,
+        const {
             projectData, // eslint-disable-line no-unused-vars
-            spriteLibraryProps,
-            spriteSelectorProps,
-            stageProps,
-            stopAllProps,
             vm,
-            ...guiProps
+            ...componentProps
         } = this.props;
-        backdropLibraryProps = defaultsDeep({}, backdropLibraryProps, {
-            mediaLibrary: this.mediaLibrary,
-            onRequestClose: this.closeModal,
-            visible: this.state.currentModal === 'backdrop-library'
-        });
-        blocksProps = defaultsDeep({}, blocksProps, {
-            options: {
-                media: `${basePath}static/blocks-media/`
-            }
-        });
-        costumeLibraryProps = defaultsDeep({}, costumeLibraryProps, {
-            mediaLibrary: this.mediaLibrary,
-            onRequestClose: this.closeModal,
-            visible: this.state.currentModal === 'costume-library'
-        });
-        spriteLibraryProps = defaultsDeep({}, spriteLibraryProps, {
-            mediaLibrary: this.mediaLibrary,
-            onRequestClose: this.closeModal,
-            visible: this.state.currentModal === 'sprite-library'
-        });
-        spriteSelectorProps = defaultsDeep({}, spriteSelectorProps, {
-            openNewBackdrop: () => this.openModal('backdrop-library'),
-            openNewCostume: () => this.openModal('costume-library'),
-            openNewSprite: () => this.openModal('sprite-library')
-        });
-        if (this.props.children) {
-            return (
-                <GUIComponent {... guiProps}>
-                    {this.props.children}
-                </GUIComponent>
-            );
-        }
-        /* eslint-disable react/jsx-max-props-per-line, lines-around-comment */
         return (
-            <GUIComponent {... guiProps}>
-                <GreenFlag vm={vm} {...greenFlagProps} />
-                <StopAll vm={vm} {...stopAllProps} />
-                <Stage vm={vm} {...stageProps} />
-                <SpriteSelector vm={vm} {... spriteSelectorProps} />
-                <Blocks vm={vm} {... blocksProps} />
-                <SpriteLibrary vm={vm} {...spriteLibraryProps} />
-                <CostumeLibrary vm={vm} {...costumeLibraryProps} />
-                <BackdropLibrary vm={vm} {...backdropLibraryProps} />
-            </GUIComponent>
+            <GUIComponent
+                vm={vm}
+                {...componentProps}
+            />
         );
-        /* eslint-enable react/jsx-max-props-per-line, lines-around-comment */
     }
 }
 
 GUI.propTypes = {
-    backdropLibraryProps: shapeFromPropTypes(BackdropLibrary.propTypes, {omit: ['vm']}),
-    basePath: React.PropTypes.string,
-    blocksProps: shapeFromPropTypes(Blocks.propTypes, {omit: ['vm']}),
-    children: React.PropTypes.node,
-    costumeLibraryProps: shapeFromPropTypes(CostumeLibrary.propTypes, {omit: ['vm']}),
-    greenFlagProps: shapeFromPropTypes(GreenFlag.propTypes, {omit: ['vm']}),
+    ...GUIComponent.propTypes,
     projectData: React.PropTypes.string,
-    spriteLibraryProps: shapeFromPropTypes(SpriteLibrary.propTypes, {omit: ['vm']}),
-    spriteSelectorProps: shapeFromPropTypes(SpriteSelector.propTypes, {omit: ['vm']}),
-    stageProps: shapeFromPropTypes(Stage.propTypes, {omit: ['vm']}),
-    stopAllProps: shapeFromPropTypes(StopAll.propTypes, {omit: ['vm']}),
     vm: React.PropTypes.instanceOf(VM)
 };
 
-GUI.defaultProps = {
-    backdropLibraryProps: {},
-    basePath: '/',
-    blocksProps: {},
-    costumeLibraryProps: {},
-    greenFlagProps: {},
-    spriteSelectorProps: {},
-    spriteLibraryProps: {},
-    stageProps: {},
-    stopAllProps: {},
-    vm: new VM()
-};
+GUI.defaultProps = GUIComponent.defaultProps;
 
-module.exports = GUI;
+module.exports = vmListenerHOC(GUI);
diff --git a/src/containers/sprite-library.jsx b/src/containers/sprite-library.jsx
index 9f2cb0a67cdd7455e27c5f5f2c3852958e32c27f..462240088e500989988405aad02678e38adfd77e 100644
--- a/src/containers/sprite-library.jsx
+++ b/src/containers/sprite-library.jsx
@@ -3,13 +3,20 @@ const React = require('react');
 const VM = require('scratch-vm');
 const MediaLibrary = require('../lib/media-library');
 
-const LibaryComponent = require('../components/library.jsx');
+const LibaryComponent = require('../components/library/library.jsx');
 
 class SpriteLibrary extends React.Component {
     constructor (props) {
         super(props);
-        bindAll(this, ['setData', 'handleItemSelect', 'setSpriteData']);
-        this.state = {data: [], spriteData: {}};
+        bindAll(this, [
+            'handleItemSelect',
+            'setData',
+            'setSpriteData'
+        ]);
+        this.state = {
+            data: [],
+            spriteData: {}
+        };
     }
     componentWillReceiveProps (nextProps) {
         if (nextProps.visible && this.state.data.length === 0) {
diff --git a/src/containers/sprite-selector-item.jsx b/src/containers/sprite-selector-item.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..9ea66dcf3c8650bf059dddcc54266ce837756ba5
--- /dev/null
+++ b/src/containers/sprite-selector-item.jsx
@@ -0,0 +1,40 @@
+const bindAll = require('lodash.bindall');
+const React = require('react');
+
+const SpriteSelectorItemComponent = require('../components/sprite-selector-item/sprite-selector-item.jsx');
+
+class SpriteSelectorItem extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, [
+            'handleClick'
+        ]);
+    }
+    handleClick (e) {
+        e.preventDefault();
+        this.props.onClick(this.props.id);
+    }
+    render () {
+        const {
+            id, // eslint-disable-line no-unused-vars
+            onClick, // eslint-disable-line no-unused-vars
+            ...props
+        } = this.props;
+        return (
+            <SpriteSelectorItemComponent
+                onClick={this.handleClick}
+                {...props}
+            />
+        );
+    }
+}
+
+SpriteSelectorItem.propTypes = {
+    costumeURL: React.PropTypes.string,
+    id: React.PropTypes.string,
+    name: React.PropTypes.string,
+    onClick: React.PropTypes.func,
+    selected: React.PropTypes.bool
+};
+
+module.exports = SpriteSelectorItem;
diff --git a/src/containers/sprite-selector.jsx b/src/containers/sprite-selector.jsx
deleted file mode 100644
index 52beebd1c47a288aa77c9921af9be3a8bc2cbe03..0000000000000000000000000000000000000000
--- a/src/containers/sprite-selector.jsx
+++ /dev/null
@@ -1,60 +0,0 @@
-const bindAll = require('lodash.bindall');
-const React = require('react');
-const VM = require('scratch-vm');
-
-const SpriteSelectorComponent = require('../components/sprite-selector.jsx');
-
-class SpriteSelector extends React.Component {
-    constructor (props) {
-        super(props);
-        bindAll(this, ['handleChange', 'targetsUpdate']);
-        this.state = {
-            targets: {
-                targetList: []
-            }
-        };
-    }
-    componentDidMount () {
-        this.props.vm.on('targetsUpdate', this.targetsUpdate);
-    }
-    handleChange (event) {
-        this.props.vm.setEditingTarget(event.target.value);
-    }
-    targetsUpdate (data) {
-        this.setState({targets: data});
-    }
-    render () {
-        const {
-            vm, // eslint-disable-line no-unused-vars
-            openNewSprite,
-            openNewCostume,
-            openNewBackdrop,
-            ...props
-        } = this.props;
-        return (
-            <SpriteSelectorComponent
-                openNewBackdrop={openNewBackdrop}
-                openNewCostume={openNewCostume}
-                openNewSprite={openNewSprite}
-                sprites={this.state.targets.targetList.map(target => (
-                    {
-                        id: target[0],
-                        name: target[1]
-                    }
-                ))}
-                value={this.state.targets.editingTarget && [this.state.targets.editingTarget]}
-                onChange={this.handleChange}
-                {...props}
-            />
-        );
-    }
-}
-
-SpriteSelector.propTypes = {
-    openNewBackdrop: React.PropTypes.func,
-    openNewCostume: React.PropTypes.func,
-    openNewSprite: React.PropTypes.func,
-    vm: React.PropTypes.instanceOf(VM)
-};
-
-module.exports = SpriteSelector;
diff --git a/src/containers/stage-selector.jsx b/src/containers/stage-selector.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..6748ce2c09df727ce13fdf80eb8cca55aa6cdcc4
--- /dev/null
+++ b/src/containers/stage-selector.jsx
@@ -0,0 +1,38 @@
+const bindAll = require('lodash.bindall');
+const React = require('react');
+
+const StageSelectorComponent = require('../components/stage-selector/stage-selector.jsx');
+
+class StageSelector extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, [
+            'handleClick'
+        ]);
+    }
+    handleClick (e) {
+        e.preventDefault();
+        this.props.onSelect(this.props.id);
+    }
+    render () {
+        const {
+            /* eslint-disable no-unused-vars */
+            id,
+            onSelect,
+            /* eslint-enable no-unused-vars */
+            ...componentProps
+        } = this.props;
+        return (
+            <StageSelectorComponent
+                onClick={this.handleClick}
+                {...componentProps}
+            />
+        );
+    }
+}
+StageSelector.propTypes = {
+    ...StageSelectorComponent.propTypes,
+    id: React.PropTypes.string,
+    onSelect: React.PropTypes.func
+};
+module.exports = StageSelector;
diff --git a/src/containers/stage.jsx b/src/containers/stage.jsx
index 53f2aa869959fa65b500321b44588eab01a30a08..55c3607248f60868f3e2527a97140a7c1cf62d5c 100644
--- a/src/containers/stage.jsx
+++ b/src/containers/stage.jsx
@@ -3,7 +3,7 @@ const React = require('react');
 const Renderer = require('scratch-render');
 const VM = require('scratch-vm');
 
-const StageComponent = require('../components/stage.jsx');
+const StageComponent = require('../components/stage/stage.jsx');
 
 class Stage extends React.Component {
     constructor (props) {
diff --git a/src/containers/target-pane.jsx b/src/containers/target-pane.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..119628930b7043c6c0180848ec8c4972b3938369
--- /dev/null
+++ b/src/containers/target-pane.jsx
@@ -0,0 +1,81 @@
+const bindAll = require('lodash.bindall');
+const React = require('react');
+
+const {connect} = require('react-redux');
+
+const {
+    openBackdropLibrary,
+    openCostumeLibrary,
+    openSpriteLibrary,
+    closeBackdropLibrary,
+    closeCostumeLibrary,
+    closeSpriteLibrary
+} = require('../reducers/modals');
+
+const TargetPaneComponent = require('../components/target-pane/target-pane.jsx');
+
+class TargetPane extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, [
+            'handleSelectSprite'
+        ]);
+    }
+    handleSelectSprite (id) {
+        this.props.vm.setEditingTarget(id);
+    }
+    render () {
+        return (
+            <TargetPaneComponent
+                {...this.props}
+                onSelectSprite={this.handleSelectSprite}
+            />
+        );
+    }
+}
+
+const {
+    onSelectSprite, // eslint-disable-line no-unused-vars
+    ...targetSelectorProps
+} = TargetPaneComponent.propTypes;
+
+TargetPane.propTypes = {
+    ...targetSelectorProps
+};
+
+const mapStateToProps = state => ({
+    editingTarget: state.targets.editingTarget,
+    sprites: state.targets.sprites,
+    stage: state.targets.stage,
+    spriteLibraryVisible: state.modals.spriteLibrary,
+    costumeLibraryVisible: state.modals.costumeLibrary,
+    backdropLibraryVisible: state.modals.backdropLibrary
+});
+const mapDispatchToProps = dispatch => ({
+    onNewBackdropClick: e => {
+        e.preventDefault();
+        dispatch(openBackdropLibrary());
+    },
+    onNewCostumeClick: e => {
+        e.preventDefault();
+        dispatch(openCostumeLibrary());
+    },
+    onNewSpriteClick: e => {
+        e.preventDefault();
+        dispatch(openSpriteLibrary());
+    },
+    onRequestCloseBackdropLibrary: () => {
+        dispatch(closeBackdropLibrary());
+    },
+    onRequestCloseCostumeLibrary: () => {
+        dispatch(closeCostumeLibrary());
+    },
+    onRequestCloseSpriteLibrary: () => {
+        dispatch(closeSpriteLibrary());
+    }
+});
+
+module.exports = connect(
+    mapStateToProps,
+    mapDispatchToProps
+)(TargetPane);
diff --git a/src/index.jsx b/src/index.jsx
index 7f2d8c07319c9335f47f64058478ba509d9a732a..393cb95deec95510962b293282667b293b15a295 100644
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -1,8 +1,12 @@
 const React = require('react');
 const ReactDOM = require('react-dom');
+const {Provider} = require('react-redux');
+const {createStore} = require('redux');
+
 const GUI = require('./containers/gui.jsx');
 const log = require('./lib/log');
 const ProjectLoader = require('./lib/project-loader');
+const reducer = require('./reducers/gui');
 
 class App extends React.Component {
     constructor (props) {
@@ -22,7 +26,7 @@ class App extends React.Component {
         window.removeEventListener('hashchange', this.updateProject);
     }
     fetchProjectId () {
-        return location.hash.substring(1);
+        return window.location.hash.substring(1);
     }
     updateProject () {
         const projectId = this.fetchProjectId();
@@ -56,5 +60,12 @@ App.propTypes = {
 
 const appTarget = document.createElement('div');
 document.body.appendChild(appTarget);
-
-ReactDOM.render(<App basePath={process.env.BASE_PATH} />, appTarget);
+const store = createStore(
+    reducer,
+    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
+);
+ReactDOM.render((
+    <Provider store={store}>
+        <App basePath={process.env.BASE_PATH} />
+    </Provider>
+), appTarget);
diff --git a/src/lib/media-library.js b/src/lib/media-library.js
index 6e2d122495e704b95b731c0aac1f9d07c4ac23e6..cadcfc761fa5185eb8d3c7ee7ffc0e0d537b8fb4 100644
--- a/src/lib/media-library.js
+++ b/src/lib/media-library.js
@@ -1,7 +1,6 @@
 const xhr = require('xhr');
 
-const LIBRARY_PREFIX = 'https://cdn.scratch.mit.edu/scratchr2/static/' +
-    '__8d9c95eb5aa1272a311775ca32568417__/medialibraries/';
+const LIBRARY_PREFIX = 'https://cdn.scratch.mit.edu/scratchr2/static/__8d9c95eb5aa1272a311775ca32568417__/medialibraries/';
 const LIBRARY_URL = {
     sprite: `${LIBRARY_PREFIX}spriteLibrary.json`,
     costume: `${LIBRARY_PREFIX}costumeLibrary.json`,
diff --git a/src/lib/vm-listener-hoc.jsx b/src/lib/vm-listener-hoc.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..87c76c56aef4fe7173f0db79ff59248f4ee48633
--- /dev/null
+++ b/src/lib/vm-listener-hoc.jsx
@@ -0,0 +1,112 @@
+const bindAll = require('lodash.bindall');
+const React = require('react');
+const VM = require('scratch-vm');
+
+const {connect} = require('react-redux');
+
+const targets = require('../reducers/targets');
+
+/*
+ * Higher Order Component to manage events emitted by the VM
+ * @param {React.Component} WrappedComponent component to manage VM events for
+ * @returns {React.Component} connected component with vm events bound to redux
+ */
+const vmListenerHOC = function (WrappedComponent) {
+    class VMListener extends React.Component {
+        constructor (props) {
+            super(props);
+            bindAll(this, [
+                'handleKeyDown',
+                'handleKeyUp'
+            ]);
+            // We have to start listening to the vm here rather than in
+            // componentDidMount because the HOC mounts the wrapped component,
+            // so the HOC componentDidMount triggers after the wrapped component
+            // mounts.
+            // If the wrapped component uses the vm in componentDidMount, then
+            // we need to start listening before mounting the wrapped component.
+            this.props.vm.on('targetsUpdate', this.props.onTargetsUpdate);
+            this.props.vm.on('SPRITE_INFO_REPORT', this.props.onSpriteInfoReport);
+        }
+        componentDidMount () {
+            if (this.props.attachKeyboardEvents) {
+                document.addEventListener('keydown', this.handleKeyDown);
+                document.addEventListener('keyup', this.handleKeyUp);
+            }
+        }
+        componentWillUnmount () {
+            if (this.props.attachKeyboardEvents) {
+                document.removeEventListener('keydown', this.handleKeyDown);
+                document.removeEventListener('keyup', this.handleKeyUp);
+            }
+        }
+        handleKeyDown (e) {
+            // Don't capture keys intended for Blockly inputs.
+            if (e.target !== document && e.target !== document.body) return;
+
+            this.props.vm.postIOData('keyboard', {
+                keyCode: e.keyCode,
+                isDown: true
+            });
+
+            // Don't stop browser keyboard shortcuts
+            if (e.metaKey || e.altKey || e.ctrlKey) return;
+
+            e.preventDefault();
+        }
+        handleKeyUp (e) {
+            // Always capture up events,
+            // even those that have switched to other targets.
+            this.props.vm.postIOData('keyboard', {
+                keyCode: e.keyCode,
+                isDown: false
+            });
+
+            // E.g., prevent scroll.
+            if (e.target !== document && e.target !== document.body) {
+                e.preventDefault();
+            }
+        }
+        render () {
+            const {
+                /* eslint-disable no-unused-vars */
+                attachKeyboardEvents,
+                onKeyDown,
+                onKeyUp,
+                onSpriteInfoReport,
+                onTargetsUpdate,
+                /* eslint-enable no-unused-vars */
+                ...props
+            } = this.props;
+            return <WrappedComponent {...props} />;
+        }
+    }
+    VMListener.propTypes = {
+        attachKeyboardEvents: React.PropTypes.bool,
+        onKeyDown: React.PropTypes.func,
+        onKeyUp: React.PropTypes.func,
+        onSpriteInfoReport: React.PropTypes.func,
+        onTargetsUpdate: React.PropTypes.func,
+        vm: React.PropTypes.instanceOf(VM).isRequired
+    };
+    VMListener.defaultProps = {
+        attachKeyboardEvents: true,
+        vm: new VM()
+    };
+    const mapStateToProps = () => ({});
+    const mapDispatchToProps = dispatch => ({
+        onTargetsUpdate: data => {
+            dispatch(targets.updateEditingTarget(data.editingTarget));
+            dispatch(targets.updateTargets(data.targetList));
+        },
+        onSpriteInfoReport: spriteInfo => {
+            dispatch(targets.updateTarget(spriteInfo));
+        }
+    });
+    return connect(
+        mapStateToProps,
+        mapDispatchToProps
+    )(VMListener);
+};
+
+module.exports = vmListenerHOC;
diff --git a/src/lib/vm-manager.js b/src/lib/vm-manager.js
deleted file mode 100644
index 9ac6f2b8197da6efd606315bdb6001c67db3d057..0000000000000000000000000000000000000000
--- a/src/lib/vm-manager.js
+++ /dev/null
@@ -1,51 +0,0 @@
-const bindAll = require('lodash.bindall');
-
-class VMManager {
-    constructor (vm) {
-        bindAll(this, [
-            'attachKeyboardEvents',
-            'detachKeyboardEvents',
-            'onKeyDown',
-            'onKeyUp'
-        ]);
-        this.vm = vm;
-    }
-    attachKeyboardEvents () {
-        // Feed keyboard events as VM I/O events.
-        document.addEventListener('keydown', this.onKeyDown);
-        document.addEventListener('keyup', this.onKeyUp);
-    }
-    detachKeyboardEvents () {
-        document.removeEventListener('keydown', this.onKeyDown);
-        document.removeEventListener('keyup', this.onKeyUp);
-    }
-    onKeyDown (e) {
-        // Don't capture keys intended for Blockly inputs.
-        if (e.target !== document && e.target !== document.body) return;
-
-        this.vm.postIOData('keyboard', {
-            keyCode: e.keyCode,
-            isDown: true
-        });
-
-        // Don't stop browser keyboard shortcuts
-        if (e.metaKey || e.altKey || e.ctrlKey) return;
-
-        e.preventDefault();
-    }
-    onKeyUp (e) {
-        // Always capture up events,
-        // even those that have switched to other targets.
-        this.vm.postIOData('keyboard', {
-            keyCode: e.keyCode,
-            isDown: false
-        });
-
-        // E.g., prevent scroll.
-        if (e.target !== document && e.target !== document.body) {
-            e.preventDefault();
-        }
-    }
-}
-
-module.exports = VMManager;
diff --git a/src/reducers/gui.js b/src/reducers/gui.js
new file mode 100644
index 0000000000000000000000000000000000000000..325c85b11382c189973bbccf5c9ff735c6265ed5
--- /dev/null
+++ b/src/reducers/gui.js
@@ -0,0 +1,6 @@
+const {combineReducers} = require('redux');
+
+module.exports = combineReducers({
+    modals: require('./modals'),
+    targets: require('./targets')
+});
diff --git a/src/reducers/modals.js b/src/reducers/modals.js
new file mode 100644
index 0000000000000000000000000000000000000000..2acce9e7621422b41cd723e69d28e7985451f648
--- /dev/null
+++ b/src/reducers/modals.js
@@ -0,0 +1,59 @@
+const OPEN_MODAL = 'scratch-gui/modals/OPEN_MODAL';
+const CLOSE_MODAL = 'scratch-gui/modals/CLOSE_MODAL';
+
+const MODAL_BACKDROP_LIBRARY = 'backdropLibrary';
+const MODAL_COSTUME_LIBRARY = 'costumeLibrary';
+const MODAL_SPRITE_LIBRARY = 'spriteLibrary';
+
+const initialState = {
+    [MODAL_BACKDROP_LIBRARY]: false,
+    [MODAL_COSTUME_LIBRARY]: false,
+    [MODAL_SPRITE_LIBRARY]: false
+};
+
+const reducer = function (state, action) {
+    if (typeof state === 'undefined') state = initialState;
+    switch (action.type) {
+    case OPEN_MODAL:
+        return Object.assign({}, state, {
+            [action.modal]: true
+        });
+    case CLOSE_MODAL:
+        return Object.assign({}, state, {
+            [action.modal]: false
+        });
+    default:
+        return state;
+    }
+};
+reducer.openModal = function (modal) {
+    return {
+        type: OPEN_MODAL,
+        modal: modal
+    };
+};
+reducer.closeModal = function (modal) {
+    return {
+        type: CLOSE_MODAL,
+        modal: modal
+    };
+};
+reducer.openBackdropLibrary = function () {
+    return reducer.openModal(MODAL_BACKDROP_LIBRARY);
+};
+reducer.openCostumeLibrary = function () {
+    return reducer.openModal(MODAL_COSTUME_LIBRARY);
+};
+reducer.openSpriteLibrary = function () {
+    return reducer.openModal(MODAL_SPRITE_LIBRARY);
+};
+reducer.closeBackdropLibrary = function () {
+    return reducer.closeModal(MODAL_BACKDROP_LIBRARY);
+};
+reducer.closeCostumeLibrary = function () {
+    return reducer.closeModal(MODAL_COSTUME_LIBRARY);
+};
+reducer.closeSpriteLibrary = function () {
+    return reducer.closeModal(MODAL_SPRITE_LIBRARY);
+};
+module.exports = reducer;
diff --git a/src/reducers/targets.js b/src/reducers/targets.js
new file mode 100644
index 0000000000000000000000000000000000000000..61c01ebb36d9505349a2831f3d4021e89da6dd44
--- /dev/null
+++ b/src/reducers/targets.js
@@ -0,0 +1,73 @@
+const defaultsDeep = require('lodash.defaultsdeep');
+
+const UPDATE_EDITING_TARGET = 'scratch-gui/targets/UPDATE_EDITING_TARGET';
+const UPDATE_TARGET_LIST = 'scratch-gui/targets/UPDATE_TARGET_LIST';
+const UPDATE_TARGET = 'scratch/targets/UPDATE_TARGET';
+
+const initialState = {
+    sprites: {},
+    stage: {}
+};
+
+const reducer = function (state, action) {
+    if (typeof state === 'undefined') state = initialState;
+    switch (action.type) {
+    case UPDATE_TARGET:
+        if (action.target.id === state.stage.id) {
+            return Object.assign({}, state, {
+                stage: Object.assign({}, state.stage, action.target)
+            });
+        }
+        return Object.assign({}, state, {
+            sprites: defaultsDeep(
+                {[action.target.id]: action.target},
+                state.sprites
+            )
+        });
+    case UPDATE_TARGET_LIST:
+        return Object.assign({}, state, {
+            sprites: action.targets
+                .filter(target => !target.isStage)
+                .reduce(
+                    (targets, target, listId) => defaultsDeep(
+                        {[target.id]: {order: listId}},
+                        {[target.id]: state.sprites[target.id]},
+                        targets
+                    ),
+                    {}
+                ),
+            stage: action.targets
+                .filter(target => target.isStage)
+                .reduce(
+                    (stage, target) => {
+                        if (target.id !== stage.id) return target;
+                        return defaultsDeep(target, stage);
+                    },
+                    state.stage
+                )
+        });
+    case UPDATE_EDITING_TARGET:
+        return Object.assign({}, state, {editingTarget: action.target});
+    default:
+        return state;
+    }
+};
+reducer.updateTarget = function (target) {
+    return {
+        type: UPDATE_TARGET,
+        target: target
+    };
+};
+reducer.updateTargets = function (targetList) {
+    return {
+        type: UPDATE_TARGET_LIST,
+        targets: targetList
+    };
+};
+reducer.updateEditingTarget = function (editingTarget) {
+    return {
+        type: UPDATE_EDITING_TARGET,
+        target: editingTarget
+    };
+};
+module.exports = reducer;
diff --git a/webpack.config.js b/webpack.config.js
index c5dc1544f85e35170c30caf161ec362c6d87d42e..3f5e68802968face09fed1809ae648f4720fbd2e 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,3 +1,5 @@
+var autoprefixer = require('autoprefixer');
+var combineLoaders = require('webpack-combine-loaders');
 var path = require('path');
 var CopyWebpackPlugin = require('copy-webpack-plugin');
 var HtmlWebpackPlugin = require('html-webpack-plugin');
@@ -26,6 +28,21 @@ module.exports = {
                 presets: ['es2015', 'react']
             }
         },
+        {
+            test: /\.css$/,
+            loader: combineLoaders([{
+                loader: 'style'
+            }, {
+                loader: 'css',
+                query: {
+                    modules: true,
+                    localIdentName: '[name]_[local]_[hash:base64:5]',
+                    camelCase: true
+                }
+            }, {
+                loader: 'postcss'
+            }])
+        },
         {
             test: /\.svg$/,
             loader: 'svg-url-loader?noquotes'
@@ -35,6 +52,7 @@ module.exports = {
             loader: 'json-loader'
         }]
     },
+    postcss: [autoprefixer],
     plugins: [
         new webpack.DefinePlugin({
             'process.env.BASE_PATH': '"' + (process.env.BASE_PATH || '/') + '"'