diff --git a/src/react-components/ui-root.js b/src/react-components/ui-root.js
index cc31044b9ec0079e6bda336ff631c4d3f023994d..53f4455185bdd0662172b6ba7a26daeb0be86861 100644
--- a/src/react-components/ui-root.js
+++ b/src/react-components/ui-root.js
@@ -2,8 +2,9 @@ import React, { Component } from 'react';
 import PropTypes from 'prop-types';
 import { VR_DEVICE_AVAILABILITY } from "../utils/vr-caps-detect.js";
 import queryString from "query-string";
-
+import { SCHEMA } from "../storage/store";
 const { detect } = require("detect-browser");
+
 const browser = detect();
 
 const ENTRY_STEPS = {
@@ -48,34 +49,12 @@ const DaydreamEntryButton = (props) => (
   </button>
 );
 
-class ProfileEntryPanel extends Component {
-  static propTypes = {
-    store: PropTypes.object
-  };
-
-  state = {
-    name: "",
-  }
-
-  nameChanged = (ev) => {
-    this.setState({ name: ev.target.value });
-  }
-
-  render() {
-    return (
-      <div>
-        <input type="text" value={this.state.name} onChange={this.nameChanged}/>
-      </div>
-    );
-  }
-}
-
 const AutoExitWarning = (props) => (
   <div>
     <p>
     Exit in <span>{props.secondsRemaining}</span>
     </p>
-    
+
     <button onClick={props.onCancel}>
     Cancel
     </button>
@@ -98,11 +77,11 @@ class UIRoot extends Component {
   static propTypes = {
     enterScene: PropTypes.func,
     availableVREntryTypes: PropTypes.object,
-    store: PropTypes.object,
     concurrentLoadDetector: PropTypes.object,
     disableAutoExitOnConcurrentLoad: PropTypes.bool,
-    forcedVREntryType: PropTypes.string
-  };
+    forcedVREntryType: PropTypes.string,
+    store: PropTypes.object,
+  }
 
   state = {
     entryStep: ENTRY_STEPS.start,
@@ -143,7 +122,7 @@ class UIRoot extends Component {
     }
   }
 
-  setupTestTone = () => { 
+  setupTestTone = () => {
     const toneClip = document.querySelector("#test-tone");
     const toneLength = 1800;
     const toneDelay = 5000;
@@ -354,20 +333,24 @@ class UIRoot extends Component {
       }
     }
 
-    this.props.enterScene(mediaStream);
     this.stopTestTone();
+    this.props.enterScene(this.state.mediaStream);
     this.setState({ entryStep: ENTRY_STEPS.finished });
   }
 
+  saveName = (e) => {
+    e.preventDefault();
+    this.props.store.update({ profile: { display_name: this.nameInput.value } });
+  }
+
   render() {
-    const entryPanel = this.state.entryStep === ENTRY_STEPS.start 
+    const entryPanel = this.state.entryStep === ENTRY_STEPS.start
     ? (
       <div>
         <TwoDEntryButton onClick={this.enter2D}/>
         { this.props.availableVREntryTypes.generic !== VR_DEVICE_AVAILABILITY.no && <GenericEntryButton onClick={this.enterVR}/> }
         { this.props.availableVREntryTypes.gearvr !== VR_DEVICE_AVAILABILITY.no && <GearVREntryButton onClick={this.enterGearVR}/> }
         { this.props.availableVREntryTypes.daydream !== VR_DEVICE_AVAILABILITY.no && <DaydreamEntryButton onClick={this.enterDaydream}/> }
-        <ProfileEntryPanel profileName={ this.state.profileNamePending }/>
       </div>
     ) : null;
 
@@ -401,12 +384,31 @@ class UIRoot extends Component {
         </div>
       ) : null;
 
+    const nameEntryPanel = (
+      <div>
+        Name Entry
+        <form onSubmit={this.saveName}>
+          <label>Name:
+            <input
+              defaultValue={this.props.store.state.profile.display_name}
+              required pattern={SCHEMA.definitions.profile.properties.display_name.pattern}
+              title="Alphanumerics and hyphens. At least 3 characters, no more than 32"
+              ref={inp => this.nameInput = inp}/>
+          </label>
+          <input type="submit" value="Save" />
+        </form>
+      </div>
+    );
+
     const overlay = this.isWaitingForAutoExit() ?
       (<AutoExitWarning secondsRemaining={this.state.secondsRemainingBeforeAutoExit} onCancel={this.endAutoExitTimer} />) :
-      (<div>
-        {entryPanel}
-        {micPanel}
-        {audioSetupPanel}
+      (
+        <div>
+          {entryPanel}
+          {micPanel}
+          {audioSetupPanel}
+
+          {nameEntryPanel}
         </div>
       );
 
diff --git a/src/room.css b/src/room.css
index b74a6c28f48547c09097cfc5b5d9b96119bb1ab9..d98df797ef70bcb1d09f98d5447d7196d4dfedd4 100644
--- a/src/room.css
+++ b/src/room.css
@@ -19,3 +19,8 @@
   left: 0;
   position: absolute;
 }
+
+.rs-base {
+  top: auto;
+  bottom: 20px;
+}
diff --git a/src/room.js b/src/room.js
index 97e5311aaf4adbb50df42f2d2c3412f44ebc7afd..3e0ef36c6ac18e18a776f3bbc23be977fb9cdd57 100644
--- a/src/room.js
+++ b/src/room.js
@@ -121,6 +121,11 @@ async function exitScene() {
   document.body.removeChild(scene);
 }
 
+function setNameTagFromStore() {
+  const myNametag = document.querySelector("#player-rig .nametag");
+  myNametag.setAttribute("text", "value", store.state.profile.display_name);
+}
+
 async function enterScene(mediaStream) {
   const qs = queryString.parse(location.search);
   const scene = document.querySelector("a-scene");
@@ -139,8 +144,8 @@ async function enterScene(mediaStream) {
     playerRig.setAttribute("virtual-gamepad-controls", {});
   }
 
-  const myNametag = document.querySelector("#player-rig .nametag");
-  myNametag.setAttribute("text", "value", store.state.profile.display_name);
+  setNameTagFromStore();
+  store.subscribe(setNameTagFromStore);
 
   const avatarScale = parseInt(qs.avatarScale, 10);
 
@@ -208,9 +213,9 @@ function mountUI() {
       exitScene,
       concurrentLoadDetector,
       disableAutoExitOnConcurrentLoad,
-      forcedVREntryType
+      forcedVREntryType,
+      store
     }} />, document.getElementById("ui-root"));
-
     document.getElementById("loader").style.display = "none";
   });
 }
diff --git a/src/storage/store.js b/src/storage/store.js
index 34caa9edb55add11d60f6a739dc45f551bfbc39b..b1b362d534dfb5db7f0bf0483a6cd7581346b529 100644
--- a/src/storage/store.js
+++ b/src/storage/store.js
@@ -7,7 +7,7 @@ const validator = new Validator();
 
 // Durable (via local-storage) schema-enforced state that is meant to be consumed via forward data flow.
 // (Think flux but with way less incidental complexity, at least for now :))
-const SCHEMA = {
+export const SCHEMA = {
   id: "/MozillaDuckStore",
 
   definitions: {