diff --git a/.eslintignore b/.eslintignore
index 3675648e816b3221576be2393fd3496bb99dad70..93c033154fbdf0e4cb6ef0dd9c31570e2b6cd475 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,2 +1,3 @@
 node_modules/*
 build/*
+dist/*
diff --git a/.gitignore b/.gitignore
index 8f98cc55bfece970be899bd47c999bfd9ae70369..0b8a0db40e62622a65702b0b042181de5136286e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ npm-*
 
 # Build
 /build
+/dist
 /.opt-in
 
 # generated translation files
diff --git a/src/containers/language-selector.jsx b/src/containers/language-selector.jsx
index ae0d2405cffb888abd2d8500a93ea382f3b53c5b..316b1577a367a4314ee7a610f72b9bee2516874d 100644
--- a/src/containers/language-selector.jsx
+++ b/src/containers/language-selector.jsx
@@ -1,5 +1,4 @@
 import {connect} from 'react-redux';
-import {updateIntl} from '../reducers/intl.js';
 
 import LanguageSelectorComponent from '../components/language-selector/language-selector.jsx';
 
@@ -7,10 +6,9 @@ const mapStateToProps = state => ({
     currentLocale: state.intl.locale
 });
 
-const mapDispatchToProps = dispatch => ({
+const mapDispatchToProps = () => ({
     onChange: e => {
         e.preventDefault();
-        dispatch(updateIntl(e.target.value));
     }
 });
 
diff --git a/src/lib/app-state-hoc.jsx b/src/lib/app-state-hoc.jsx
index 2894cda13e372e2936868b6cd913c9f040f9bb45..158ac40d05408f2324614e409e4af2f838ff36b8 100644
--- a/src/lib/app-state-hoc.jsx
+++ b/src/lib/app-state-hoc.jsx
@@ -3,7 +3,9 @@ import {Provider} from 'react-redux';
 import {createStore, applyMiddleware, compose} from 'redux';
 import throttle from 'redux-throttle';
 
-import {intlInitialState, IntlProvider} from '../reducers/intl.js';
+import {intlShape} from 'react-intl';
+import {IntlProvider, updateIntl} from 'react-intl-redux';
+import {intlInitialState} from '../reducers/intl.js';
 import reducer from '../reducers/gui';
 
 const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
@@ -12,7 +14,6 @@ const enhancer = composeEnhancers(
         throttle(300, {leading: true, trailing: true})
     )
 );
-const store = createStore(reducer, intlInitialState, enhancer);
 
 import ErrorBoundary from '../containers/error-boundary.jsx';
 
@@ -22,15 +23,32 @@ import ErrorBoundary from '../containers/error-boundary.jsx';
  * @returns {React.Component} component with redux and intl state provided
  */
 const AppStateHOC = function (WrappedComponent) {
-    const AppStateWrapper = ({...props}) => (
-        <Provider store={store}>
-            <IntlProvider>
-                <ErrorBoundary>
-                    <WrappedComponent {...props} />
-                </ErrorBoundary>
-            </IntlProvider>
-        </Provider>
-    );
+    class AppStateWrapper extends React.Component {
+        constructor (props) {
+            super(props);
+            this.store = createStore(reducer, (props.intl || intlInitialState), enhancer);
+        }
+        componentDidUpdate (prevProps) {
+            if (prevProps.intl !== this.props.intl) updateIntl(this.props.intl);
+        }
+        render () {
+            return (
+                <Provider store={this.store}>
+                    <IntlProvider>
+                        <ErrorBoundary>
+                            <WrappedComponent {...this.props} />
+                        </ErrorBoundary>
+                    </IntlProvider>
+                </Provider>
+            );
+
+        }
+
+
+    }
+    AppStateWrapper.propTypes = {
+        intl: intlShape
+    };
     return AppStateWrapper;
 };
 
diff --git a/src/examples/blocks-only.css b/src/playground/blocks-only.css
similarity index 100%
rename from src/examples/blocks-only.css
rename to src/playground/blocks-only.css
diff --git a/src/examples/blocks-only.jsx b/src/playground/blocks-only.jsx
similarity index 93%
rename from src/examples/blocks-only.jsx
rename to src/playground/blocks-only.jsx
index 8d5159e825105374827e818ce7009e57587e87de..417ab85c9ff0143ec77b80b2eaa9810e9bd5cd9c 100644
--- a/src/examples/blocks-only.jsx
+++ b/src/playground/blocks-only.jsx
@@ -6,7 +6,7 @@ import AppStateHOC from '../lib/app-state-hoc.jsx';
 import Controls from '../containers/controls.jsx';
 import Blocks from '../containers/blocks.jsx';
 import GUI from '../containers/gui.jsx';
-import ProjectLoaderHOC from '../lib/project-loader-hoc.jsx';
+import ProjectLoaderHOC from './project-loader-hoc.jsx';
 
 import styles from './blocks-only.css';
 
diff --git a/src/examples/compatibility-testing.jsx b/src/playground/compatibility-testing.jsx
similarity index 97%
rename from src/examples/compatibility-testing.jsx
rename to src/playground/compatibility-testing.jsx
index 3fa8e71d94e34e4722ec1a1f329c9df46de2688c..513758023df0209ebdd0045d2a71b753fab71411 100644
--- a/src/examples/compatibility-testing.jsx
+++ b/src/playground/compatibility-testing.jsx
@@ -7,7 +7,7 @@ import Controls from '../containers/controls.jsx';
 import Stage from '../containers/stage.jsx';
 import Box from '../components/box/box.jsx';
 import GUI from '../containers/gui.jsx';
-import ProjectLoaderHOC from '../lib/project-loader-hoc.jsx';
+import ProjectLoaderHOC from './project-loader-hoc.jsx';
 
 const mapStateToProps = state => ({vm: state.vm});
 
diff --git a/src/index.css b/src/playground/index.css
similarity index 100%
rename from src/index.css
rename to src/playground/index.css
diff --git a/src/index.ejs b/src/playground/index.ejs
similarity index 100%
rename from src/index.ejs
rename to src/playground/index.ejs
diff --git a/src/index.jsx b/src/playground/index.jsx
similarity index 76%
rename from src/index.jsx
rename to src/playground/index.jsx
index 114c45ce0ad6194d76270bee6e79bea378ecb9ec..0574c8d09b04d885c2c13773ea11d46b04a8c009 100644
--- a/src/index.jsx
+++ b/src/playground/index.jsx
@@ -3,10 +3,10 @@ import React from 'react';
 import ReactDOM from 'react-dom';
 import Modal from 'react-modal';
 
-import analytics from './lib/analytics';
-import AppStateHOC from './lib/app-state-hoc.jsx';
-import GUI from './containers/gui.jsx';
-import ProjectLoaderHOC from './lib/project-loader-hoc.jsx';
+import analytics from '../lib/analytics';
+import AppStateHOC from '../lib/app-state-hoc.jsx';
+import GUI from '../containers/gui.jsx';
+import ProjectLoaderHOC from './project-loader-hoc.jsx';
 
 import styles from './index.css';
 
diff --git a/src/playground/intl.js b/src/playground/intl.js
new file mode 100644
index 0000000000000000000000000000000000000000..bc427c402a022d03fa3bd64b0a6ffd6ff5b5afbf
--- /dev/null
+++ b/src/playground/intl.js
@@ -0,0 +1,25 @@
+import {addLocaleData} from 'react-intl';
+import defaultsDeep from 'lodash.defaultsdeep';
+
+import localeData from 'scratch-l10n';
+import guiMessages from 'scratch-l10n/locales/gui-msgs';
+import paintMessages from 'scratch-l10n/locales/paint-msgs';
+import penMessages from 'scratch-l10n/locales/pen-msgs';
+
+const combinedMessages = defaultsDeep({}, guiMessages.messages, paintMessages.messages, penMessages.messages);
+
+Object.keys(localeData).forEach(locale => {
+    // TODO: will need to handle locales not in the default intl - see www/custom-locales
+    addLocaleData(localeData[locale].localeData);
+});
+
+const intlDefault = {
+    defaultLocale: 'en',
+    locale: 'en',
+    messages: combinedMessages.en.messages
+};
+
+export {
+    intlDefault as default,
+    combinedMessages
+};
diff --git a/src/examples/player.css b/src/playground/player.css
similarity index 100%
rename from src/examples/player.css
rename to src/playground/player.css
diff --git a/src/examples/player.jsx b/src/playground/player.jsx
similarity index 97%
rename from src/examples/player.jsx
rename to src/playground/player.jsx
index ab50527cde1ae1d4be7788e7545397ff48b3700c..30b18e8ed89efc3e8c373c9882588c0130b98b42 100644
--- a/src/examples/player.jsx
+++ b/src/playground/player.jsx
@@ -7,7 +7,7 @@ import Controls from '../containers/controls.jsx';
 import Stage from '../containers/stage.jsx';
 import Box from '../components/box/box.jsx';
 import GUI from '../containers/gui.jsx';
-import ProjectLoaderHOC from '../lib/project-loader-hoc.jsx';
+import ProjectLoaderHOC from './project-loader-hoc.jsx';
 
 import './player.css';
 
diff --git a/src/lib/project-loader-hoc.jsx b/src/playground/project-loader-hoc.jsx
similarity index 96%
rename from src/lib/project-loader-hoc.jsx
rename to src/playground/project-loader-hoc.jsx
index 5ccb382b2560f27756bb04276ab7eaff3440e8a8..3ebacee17ff8d4b3d40c704c664019a150f30d22 100644
--- a/src/lib/project-loader-hoc.jsx
+++ b/src/playground/project-loader-hoc.jsx
@@ -1,8 +1,8 @@
 import React from 'react';
 
-import analytics from './analytics';
-import log from './log';
-import storage from './storage';
+import analytics from '../lib/analytics';
+import log from '../lib/log';
+import storage from '../lib/storage';
 
 /* Higher Order Component to provide behavior for loading projects by id from
  * the window's hash (#this part in the url)
diff --git a/src/reducers/intl.js b/src/reducers/intl.js
index 15a2d307b885917cf75e363bf9b484d412edd2fb..8c49ee10475c5a960c35d6eba723203dbb772091 100644
--- a/src/reducers/intl.js
+++ b/src/reducers/intl.js
@@ -1,36 +1,14 @@
-import {addLocaleData} from 'react-intl';
-import {updateIntl as superUpdateIntl} from 'react-intl-redux';
-import {IntlProvider, intlReducer} from 'react-intl-redux';
-import defaultsDeep from 'lodash.defaultsdeep';
-
-import localeData from 'scratch-l10n';
-import guiMessages from 'scratch-l10n/locales/gui-msgs';
-import paintMessages from 'scratch-l10n/locales/paint-msgs';
-import penMessages from 'scratch-l10n/locales/pen-msgs';
-
-const combinedMessages = defaultsDeep({}, guiMessages.messages, paintMessages.messages, penMessages.messages);
-
-Object.keys(localeData).forEach(locale => {
-    // TODO: will need to handle locales not in the default intl - see www/custom-locales
-    addLocaleData(localeData[locale].localeData);
-});
+import {intlReducer} from 'react-intl-redux';
 
 const intlInitialState = {
     intl: {
         defaultLocale: 'en',
         locale: 'en',
-        messages: combinedMessages.en.messages
+        messages: {}
     }
 };
 
-const updateIntl = locale => superUpdateIntl({
-    locale: locale,
-    messages: combinedMessages[locale].messages || combinedMessages.en.messages
-});
-
 export {
     intlReducer as default,
-    IntlProvider,
-    intlInitialState,
-    updateIntl
+    intlInitialState
 };
diff --git a/test/unit/util/project-loader-hoc.test.jsx b/test/unit/util/project-loader-hoc.test.jsx
index 5acde098e53b8630f1a9b2dbc74177faadcb70d8..997224e7415a2e771dac892ac8d2e8fe80d26ee6 100644
--- a/test/unit/util/project-loader-hoc.test.jsx
+++ b/test/unit/util/project-loader-hoc.test.jsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import ProjectLoaderHOC from '../../../src/lib/project-loader-hoc.jsx';
+import ProjectLoaderHOC from '../../../src/playground/project-loader-hoc.jsx';
 import storage from '../../../src/lib/storage';
 import {mount} from 'enzyme';
 
diff --git a/webpack.config.js b/webpack.config.js
index 389cf8abd6db12e1deb277d680469a688d518cb6..4a94a9a0dc0a4ab975c784983bc6436b6aa7a526 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -19,10 +19,10 @@ module.exports = {
     devtool: 'cheap-module-source-map',
     entry: {
         lib: ['react', 'react-dom'],
-        gui: './src/index.jsx',
-        blocksonly: './src/examples/blocks-only.jsx',
-        compatibilitytesting: './src/examples/compatibility-testing.jsx',
-        player: './src/examples/player.jsx'
+        gui: './src/playground/index.jsx',
+        blocksonly: './src/playground/blocks-only.jsx',
+        compatibilitytesting: './src/playground/compatibility-testing.jsx',
+        player: './src/playground/player.jsx'
     },
     output: {
         path: path.resolve(__dirname, 'build'),
@@ -82,24 +82,24 @@ module.exports = {
         }),
         new HtmlWebpackPlugin({
             chunks: ['lib', 'gui'],
-            template: 'src/index.ejs',
+            template: 'src/playground/index.ejs',
             title: 'Scratch 3.0 GUI'
         }),
         new HtmlWebpackPlugin({
             chunks: ['lib', 'blocksonly'],
-            template: 'src/index.ejs',
+            template: 'src/playground/index.ejs',
             filename: 'blocks-only.html',
             title: 'Scratch 3.0 GUI: Blocks Only Example'
         }),
         new HtmlWebpackPlugin({
             chunks: ['lib', 'compatibilitytesting'],
-            template: 'src/index.ejs',
+            template: 'src/playground/index.ejs',
             filename: 'compatibility-testing.html',
             title: 'Scratch 3.0 GUI: Compatibility Testing'
         }),
         new HtmlWebpackPlugin({
             chunks: ['lib', 'player'],
-            template: 'src/index.ejs',
+            template: 'src/playground/index.ejs',
             filename: 'player.html',
             title: 'Scratch 3.0 GUI: Player Example'
         }),