diff --git a/src/assets/stylesheets/hub-create.scss b/src/assets/stylesheets/hub-create.scss
index c2e3c94114f87d0663fb85baf1278e4c4625a13c..b9a69e4bc03dfdc4436426af55dcd0fa300cef70 100644
--- a/src/assets/stylesheets/hub-create.scss
+++ b/src/assets/stylesheets/hub-create.scss
@@ -143,15 +143,24 @@
           top: 0;
           left: 0;
           background: rgb(2,0,36);
-          background: linear-gradient(0deg, rgba(2,0,36,0) 0%, rgba(1,0,11,0.2189076314119398) 60%, rgba(0,0,0,0.5242297602634804) 100%); 
+          background: linear-gradient(0deg, rgba(2,0,36,0.324) 0%, rgba(1,0,11,0.1189076314119398) 60%, rgba(0,0,0,0.3242297602634804) 100%); 
 
-          :local(.footer) {
+          :local(.customButton) {
+            @extend %default-font;
+            cursor: pointer;
             position: absolute;
             bottom: 14px;
             left: 12px;
-            font-size: 1.2em;
+            font-size: 1.3em;
             text-shadow: 0px 0px 6px #202020;
             color: $light-text;
+            appearance: none;
+            text-decoration: underline;
+            -moz-appearance: none;
+            -webkit-appearance: none;
+            background: transparent;
+            border: none;
+            pointer-events: auto;
           }
 
           :local(.header) {
diff --git a/src/assets/stylesheets/info-dialog.scss b/src/assets/stylesheets/info-dialog.scss
index 58b2259fc71f0097d8f2b032b1fcc9bfa5305251..05aec48c469e721d3c90406ee62606ba9535bd92 100644
--- a/src/assets/stylesheets/info-dialog.scss
+++ b/src/assets/stylesheets/info-dialog.scss
@@ -79,7 +79,7 @@
   }
 }
 
-.invite-form, .add-media-form {
+.invite-form, .add-media-form, .custom-scene-form {
   display: flex;
   flex-direction: column;
   align-items: center;
diff --git a/src/assets/translations.data.json b/src/assets/translations.data.json
index 49b6188286d236029a167b167bfea9f4b95f0810..0dfe136d19d4c1db8c78c4a591cf4c5130354c6f 100644
--- a/src/assets/translations.data.json
+++ b/src/assets/translations.data.json
@@ -45,7 +45,7 @@
     "autoexit.title_units": " seconds",
     "autoexit.subtitle": "You have started another session.",
     "autoexit.cancel": "CANCEL",
-    "home.environment_picker_footer": "Choose a scene",
+    "home.room_create_options": "Options",
     "home.create_name.validation_warning": "Invalid name, limited to 4 to 64 characters and limited symbols.",
     "home.webvr_disclaimer_pre": "A ",
     "home.webvr_disclaimer_post": " experiment by ",
diff --git a/src/components/gltf-model-plus.js b/src/components/gltf-model-plus.js
index 0b9755a4a8a449b2001a4d44180df73c3b9f7545..5e54e729e38c6d2360059e04f8fa4cb827d7b86f 100644
--- a/src/components/gltf-model-plus.js
+++ b/src/components/gltf-model-plus.js
@@ -80,7 +80,7 @@ function cloneGltf(gltf) {
 /// or templates associated with any of their nodes.)
 ///
 /// Returns the A-Frame entity associated with the given node, if one was constructed.
-const inflateEntities = function(node, templates, gltfPath) {
+const inflateEntities = function(node, templates, gltfPath, isRoot) {
   // inflate subtrees first so that we can determine whether or not this node needs to be inflated
   const childEntities = [];
   const children = node.children.slice(0); // setObject3D mutates the node's parent, so we have to copy
@@ -92,7 +92,7 @@ const inflateEntities = function(node, templates, gltfPath) {
   }
 
   const nodeHasBehavior = node.userData.components || node.name in templates;
-  if (!nodeHasBehavior && !childEntities.length) {
+  if (!nodeHasBehavior && !childEntities.length && !isRoot) {
     return null; // we don't need an entity for this node
   }
 
@@ -257,7 +257,7 @@ AFRAME.registerComponent("gltf-model-plus", {
       this.model.animations = model.animations;
 
       let object3DToSet = this.model;
-      if (this.data.inflate && (this.inflatedEl = inflateEntities(this.model, this.templates, gltfPath))) {
+      if (this.data.inflate && (this.inflatedEl = inflateEntities(this.model, this.templates, gltfPath, true))) {
         this.el.appendChild(this.inflatedEl);
         object3DToSet = this.inflatedEl.object3D;
         // TODO: Still don't fully understand the lifecycle here and how it differs between browsers, we should dig in more
diff --git a/src/gltf-component-mappings.js b/src/gltf-component-mappings.js
index 0552e61c854ad7efe6ed5e97020b512ed5d0feac..cc22ef521f2ee74281f2de9e636d867c21d89b1d 100644
--- a/src/gltf-component-mappings.js
+++ b/src/gltf-component-mappings.js
@@ -11,6 +11,9 @@ AFRAME.GLTFModelPlus.registerComponent("gltf-model-plus", "gltf-model-plus");
 AFRAME.GLTFModelPlus.registerComponent("body", "body");
 AFRAME.GLTFModelPlus.registerComponent("hide-when-quality", "hide-when-quality");
 AFRAME.GLTFModelPlus.registerComponent("light", "light");
+AFRAME.GLTFModelPlus.registerComponent("directional-light", "light");
+AFRAME.GLTFModelPlus.registerComponent("ambient-light", "light");
+AFRAME.GLTFModelPlus.registerComponent("point-light", "light");
 AFRAME.GLTFModelPlus.registerComponent("skybox", "skybox");
 AFRAME.GLTFModelPlus.registerComponent("layers", "layers");
 AFRAME.GLTFModelPlus.registerComponent("shadow", "shadow");
diff --git a/src/hub.js b/src/hub.js
index 94a423315a65ad7424ecb8ab77bb69735ac410fa..38b0019d53a7254c2f6d65e59dc2f8cc57f0b7ed 100644
--- a/src/hub.js
+++ b/src/hub.js
@@ -510,9 +510,21 @@ const onReady = async () => {
     .receive("ok", data => {
       const hub = data.hubs[0];
       const defaultSpaceTopic = hub.topics[0];
-      const gltfBundleUrl = defaultSpaceTopic.assets.find(a => a.asset_type === "gltf_bundle").src;
+      const sceneUrl = defaultSpaceTopic.assets.find(a => a.asset_type === "gltf_bundle").src;
+
+      console.log(`Scene URL: ${sceneUrl}`);
+
+      if (/\.gltf/i.test(sceneUrl) || /\.glb/i.test(sceneUrl)) {
+        const gltfEl = document.createElement("a-entity");
+        gltfEl.setAttribute("gltf-model-plus", { src: sceneUrl, inflate: true });
+        gltfEl.addEventListener("model-loaded", () => initialEnvironmentEl.emit("bundleloaded"));
+        initialEnvironmentEl.appendChild(gltfEl);
+      } else {
+        // TODO remove, and remove bundleloaded event
+        initialEnvironmentEl.setAttribute("gltf-bundle", `src: ${sceneUrl}`);
+      }
+
       setRoom(hub.hub_id, hub.name);
-      initialEnvironmentEl.setAttribute("gltf-bundle", `src: ${gltfBundleUrl}`);
       hubChannel.setPhoenixChannel(channel);
     })
     .receive("error", res => {
diff --git a/src/react-components/hub-create-panel.js b/src/react-components/hub-create-panel.js
index 9a107a54983fba8e44a71931cbda068e72a74ba9..8d83218341e07218aafb5126cf0cc75e4fe829ec 100644
--- a/src/react-components/hub-create-panel.js
+++ b/src/react-components/hub-create-panel.js
@@ -2,16 +2,17 @@ import React, { Component } from "react";
 import PropTypes from "prop-types";
 import { injectIntl, FormattedMessage } from "react-intl";
 import { generateHubName } from "../utils/name-generation";
-import classNames from "classnames";
 import { faAngleLeft } from "@fortawesome/free-solid-svg-icons/faAngleLeft";
 import { faAngleRight } from "@fortawesome/free-solid-svg-icons/faAngleRight";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { resolveURL, extractUrlBase } from "../utils/resolveURL";
+import InfoDialog from "./info-dialog.js";
 
 import default_scene_preview_thumbnail from "../assets/images/default_thumbnail.png";
 import styles from "../assets/stylesheets/hub-create.scss";
 
 const HUB_NAME_PATTERN = "^[A-Za-z0-9-'\":!@#$%^&*(),.?~ ]{4,64}$";
+const dialogTypes = InfoDialog.dialogTypes;
 
 class HubCreatePanel extends Component {
   static propTypes = {
@@ -34,7 +35,9 @@ class HubCreatePanel extends Component {
     this.state = {
       ready: false,
       name: generateHubName(),
-      environmentIndex
+      environmentIndex,
+      showCustomSceneDialog: false,
+      customSceneUrl: null
     };
 
     // Optimisticly preload all environment thumbnails
@@ -71,11 +74,15 @@ class HubCreatePanel extends Component {
   };
 
   createHub = async e => {
-    e.preventDefault();
+    if (e) {
+      e.preventDefault();
+    }
+
     const environment = this.props.environments[this.state.environmentIndex];
+    const sceneUrl = this.state.customSceneUrl || environment.bundle_url;
 
     const payload = {
-      hub: { name: this.state.name, default_environment_gltf_bundle_url: environment.bundle_url }
+      hub: { name: this.state.name, default_environment_gltf_bundle_url: sceneUrl }
     };
 
     let createUrl = "/api/v1/hubs";
@@ -129,6 +136,12 @@ class HubCreatePanel extends Component {
     this.setToEnvironmentOffset(-1);
   };
 
+  showCustomSceneDialog = e => {
+    e.preventDefault();
+    e.stopPropagation();
+    this.setState({ showCustomSceneDialog: true });
+  };
+
   shuffle = () => {
     this.setState({
       name: generateHubName(),
@@ -152,93 +165,106 @@ class HubCreatePanel extends Component {
     const environmentThumbnail = this._getEnvironmentThumbnail(this.state.environmentIndex);
 
     return (
-      <form onSubmit={this.createHub}>
-        <div className={styles.createPanel}>
-          <div className={styles.form}>
-            <div
-              className={styles.leftContainer}
-              onClick={async () => {
-                this.shuffle();
-              }}
-            >
-              <button type="button" tabIndex="3" className={styles.rotateButton}>
-                <img src="../assets/images/dice_icon.svg" />
-              </button>
-            </div>
-            <div className={styles.rightContainer}>
-              <button type="submit" tabIndex="5" className={styles.submitButton}>
-                {this.isHubNameValid() ? (
-                  <img src="../assets/images/hub_create_button_enabled.svg" />
-                ) : (
-                  <img src="../assets/images/hub_create_button_disabled.svg" />
-                )}
-              </button>
-            </div>
-            <div className={styles.environment}>
-              <div className={styles.picker}>
-                <img className={styles.image} srcSet={environmentThumbnail.srcset} />
-                <div className={styles.labels}>
-                  <div className={styles.header}>
-                    {meta.url ? (
-                      <a href={meta.url} rel="noopener noreferrer" className={styles.title}>
-                        {environmentTitle}
-                      </a>
-                    ) : (
-                      <span className={styles.itle}>environmentTitle</span>
-                    )}
-                    {environmentAuthor &&
-                      environmentAuthor.name &&
-                      (environmentAuthor.url ? (
-                        <a href={environmentAuthor.url} rel="noopener noreferrer" className={styles.author}>
-                          <FormattedMessage id="home.environment_author_by" />
-                          <span>{environmentAuthor.name}</span>
-                        </a>
-                      ) : (
-                        <span className={styles.author}>
-                          <FormattedMessage id="home.environment_author_by" />
-                          <span>{environmentAuthor.name}</span>
-                        </span>
-                      ))}
-                    {environmentAuthor &&
-                      environmentAuthor.organization &&
-                      (environmentAuthor.organization.url ? (
-                        <a href={environmentAuthor.organization.url} rel="noopener noreferrer" className={styles.org}>
-                          <span>{environmentAuthor.organization.name}</span>
+      <div>
+        <form onSubmit={this.createHub}>
+          <div className={styles.createPanel}>
+            <div className={styles.form}>
+              <div
+                className={styles.leftContainer}
+                onClick={async () => {
+                  this.shuffle();
+                }}
+              >
+                <button type="button" tabIndex="3" className={styles.rotateButton}>
+                  <img src="../assets/images/dice_icon.svg" />
+                </button>
+              </div>
+              <div className={styles.rightContainer}>
+                <button type="submit" tabIndex="5" className={styles.submitButton}>
+                  {this.isHubNameValid() ? (
+                    <img src="../assets/images/hub_create_button_enabled.svg" />
+                  ) : (
+                    <img src="../assets/images/hub_create_button_disabled.svg" />
+                  )}
+                </button>
+              </div>
+              <div className={styles.environment}>
+                <div className={styles.picker}>
+                  <img className={styles.image} srcSet={environmentThumbnail.srcset} />
+                  <div className={styles.labels}>
+                    <div className={styles.header}>
+                      {meta.url ? (
+                        <a href={meta.url} rel="noopener noreferrer" className={styles.title}>
+                          {environmentTitle}
                         </a>
                       ) : (
-                        <span className={styles.org}>
-                          <span>{environmentAuthor.organization.name}</span>
-                        </span>
-                      ))}
+                        <span className={styles.itle}>environmentTitle</span>
+                      )}
+                      {environmentAuthor &&
+                        environmentAuthor.name &&
+                        (environmentAuthor.url ? (
+                          <a href={environmentAuthor.url} rel="noopener noreferrer" className={styles.author}>
+                            <FormattedMessage id="home.environment_author_by" />
+                            <span>{environmentAuthor.name}</span>
+                          </a>
+                        ) : (
+                          <span className={styles.author}>
+                            <FormattedMessage id="home.environment_author_by" />
+                            <span>{environmentAuthor.name}</span>
+                          </span>
+                        ))}
+                      {environmentAuthor &&
+                        environmentAuthor.organization &&
+                        (environmentAuthor.organization.url ? (
+                          <a href={environmentAuthor.organization.url} rel="noopener noreferrer" className={styles.org}>
+                            <span>{environmentAuthor.organization.name}</span>
+                          </a>
+                        ) : (
+                          <span className={styles.org}>
+                            <span>{environmentAuthor.organization.name}</span>
+                          </span>
+                        ))}
+                    </div>
+                    <div className={styles.footer}>
+                      <button onClick={this.showCustomSceneDialog} className={styles.customButton}>
+                        <FormattedMessage id="home.room_create_options" />
+                      </button>
+                    </div>
                   </div>
-                  <div className={styles.footer}>
-                    <FormattedMessage id="home.environment_picker_footer" />
+                  <div className={styles.controls}>
+                    <button className={styles.prev} type="button" tabIndex="1" onClick={this.setToPreviousEnvironment}>
+                      <FontAwesomeIcon icon={faAngleLeft} />
+                    </button>
+
+                    <button className={styles.next} type="button" tabIndex="2" onClick={this.setToNextEnvironment}>
+                      <FontAwesomeIcon icon={faAngleRight} />
+                    </button>
                   </div>
                 </div>
-                <div className={styles.controls}>
-                  <button className={styles.prev} type="button" tabIndex="1" onClick={this.setToPreviousEnvironment}>
-                    <FontAwesomeIcon icon={faAngleLeft} />
-                  </button>
-
-                  <button className={styles.next} type="button" tabIndex="2" onClick={this.setToNextEnvironment}>
-                    <FontAwesomeIcon icon={faAngleRight} />
-                  </button>
-                </div>
               </div>
+              <input
+                tabIndex="4"
+                className={styles.name}
+                value={this.state.name}
+                onChange={e => this.setState({ name: e.target.value })}
+                onFocus={e => e.target.select()}
+                required
+                pattern={HUB_NAME_PATTERN}
+                title={formatMessage({ id: "home.create_name.validation_warning" })}
+              />
             </div>
-            <input
-              tabIndex="4"
-              className={styles.name}
-              value={this.state.name}
-              onChange={e => this.setState({ name: e.target.value })}
-              onFocus={e => e.target.select()}
-              required
-              pattern={HUB_NAME_PATTERN}
-              title={formatMessage({ id: "home.create_name.validation_warning" })}
-            />
           </div>
-        </div>
-      </form>
+        </form>
+        {this.state.showCustomSceneDialog && (
+          <InfoDialog
+            dialogType={dialogTypes.custom_scene}
+            onCloseDialog={() => this.setState({ showCustomSceneDialog: false })}
+            onCustomScene={url => {
+              this.setState({ showCustomSceneDialog: false, customSceneUrl: url }, () => this.createHub());
+            }}
+          />
+        )}
+      </div>
     );
   }
 }
diff --git a/src/react-components/info-dialog.js b/src/react-components/info-dialog.js
index ff9b4da1b86f19c864bcab89b2eb997fc2eb6a1f..2111626fb344714eb7ddc7599f2d05bff3bf73a0 100644
--- a/src/react-components/info-dialog.js
+++ b/src/react-components/info-dialog.js
@@ -20,13 +20,15 @@ class InfoDialog extends Component {
     help: Symbol("help"),
     link: Symbol("link"),
     webvr_recommend: Symbol("webvr_recommend"),
-    add_media: Symbol("add_media")
+    add_media: Symbol("add_media"),
+    custom_scene: Symbol("custom_scene")
   };
   static propTypes = {
     dialogType: PropTypes.oneOf(Object.values(InfoDialog.dialogTypes)),
     onCloseDialog: PropTypes.func,
     onSubmittedEmail: PropTypes.func,
     onAddMedia: PropTypes.func,
+    onCustomScene: PropTypes.func,
     linkCode: PropTypes.string
   };
 
@@ -53,11 +55,16 @@ class InfoDialog extends Component {
     }
   }
 
-  onContainerClicked(e) {
+  onContainerClicked = e => {
     if (e.currentTarget === e.target) {
       this.props.onCloseDialog();
     }
-  }
+  };
+
+  onCustomSceneClicked = () => {
+    this.props.onCustomScene(this.state.customSceneUrl);
+    this.props.onCloseDialog();
+  };
 
   shareLinkClicked = () => {
     navigator.share({
@@ -74,7 +81,9 @@ class InfoDialog extends Component {
   state = {
     mailingListEmail: "",
     mailingListPrivacy: false,
-    copyLinkButtonText: "Copy"
+    copyLinkButtonText: "Copy",
+    addMediaUrl: "",
+    customSceneUrl: ""
   };
 
   signUpForMailingList = async e => {
@@ -191,6 +200,31 @@ class InfoDialog extends Component {
         dialogTitle = "Add Media";
         dialogBody = <MediaToolsDialog onAddMedia={this.props.onAddMedia} onCloseDialog={this.props.onCloseDialog} />;
         break;
+      case InfoDialog.dialogTypes.custom_scene:
+        dialogTitle = "Use Custom Scene";
+        dialogBody = (
+          <div>
+            <div>Enter a URL to a GLTF file to use for your room&apos;s scene:</div>
+            <form onSubmit={this.onCustomSceneClicked}>
+              <div className="custom-scene-form">
+                <input
+                  type="url"
+                  placeholder="URL to Scene GLTF or GLB"
+                  className="custom-scene-form__link_field"
+                  value={this.state.customSceneUrl}
+                  onChange={e => this.setState({ customSceneUrl: e.target.value })}
+                  required
+                />
+                <div className="custom-scene-form__buttons">
+                  <button className="custom-scene-form__action-button">
+                    <span>Create Room</span>
+                  </button>
+                </div>
+              </div>
+            </form>
+          </div>
+        );
+        break;
       case InfoDialog.dialogTypes.updates:
         dialogTitle = "";
         dialogBody = (