diff --git a/src/assets/stylesheets/scene-ui.scss b/src/assets/stylesheets/scene-ui.scss
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/assets/stylesheets/scene.scss b/src/assets/stylesheets/scene.scss
new file mode 100644
index 0000000000000000000000000000000000000000..44e6591aacfa994bb79a4a0354b129ae171c4741
--- /dev/null
+++ b/src/assets/stylesheets/scene.scss
@@ -0,0 +1,2 @@
+@import 'shared';
+@import 'loader';
diff --git a/src/react-components/scene-ui.js b/src/react-components/scene-ui.js
new file mode 100644
index 0000000000000000000000000000000000000000..7164b500add1989b40242c3dc40158958a323c5c
--- /dev/null
+++ b/src/react-components/scene-ui.js
@@ -0,0 +1,66 @@
+import React, { Component } from "react";
+import PropTypes from "prop-types";
+//import classNames from "classnames";
+import { IntlProvider, /*FormattedMessage, */ addLocaleData } from "react-intl";
+import en from "react-intl/locale-data/en";
+import styles from "../assets/stylesheets/scene-ui.scss";
+
+import { lang, messages } from "../utils/i18n";
+
+addLocaleData([...en]);
+
+class SceneUI extends Component {
+  static propTypes = {
+    store: PropTypes.object,
+    scene: PropTypes.object,
+    sceneLoaded: PropTypes.bool,
+    sceneId: PropTypes.string,
+    sceneName: PropTypes.string,
+    sceneDescription: PropTypes.string,
+    sceneAttribution: PropTypes.string
+  };
+
+  state = {};
+
+  constructor(props) {
+    super(props);
+  }
+
+  componentDidMount() {
+    this.props.scene.addEventListener("loaded", this.onSceneLoaded);
+  }
+
+  componentWillUnmount() {
+    this.props.scene.removeEventListener("loaded", this.onSceneLoaded);
+  }
+
+  onSceneLoaded = () => {
+    this.setState({ sceneLoaded: true });
+  };
+
+  render() {
+    if (!this.props.sceneLoaded || !this.props.sceneId) {
+      return (
+        <IntlProvider locale={lang} messages={messages}>
+          <div className="loading-panel">
+            <div className="loader-wrap">
+              <div className="loader">
+                <div className="loader-center" />
+              </div>
+            </div>
+
+            <img className="loading-panel__logo" src="../assets/images/logo.svg" />
+          </div>
+        </IntlProvider>
+      );
+    }
+
+    return (
+      <IntlProvider locale={lang} messages={messages}>
+        <div className={styles.ui}>hello</div>
+      </IntlProvider>
+    );
+  }
+}
+
+export default SceneUI;
diff --git a/src/scene.html b/src/scene.html
new file mode 100644
index 0000000000000000000000000000000000000000..6a4ebaa0f56d91acb74427387016d87a333f78a9
--- /dev/null
+++ b/src/scene.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <!-- DO NOT REMOVE/EDIT THIS COMMENT - SCENE_META_TAGS -->
+
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+
+    <link rel="shortcut icon" type="image/png" href="/favicon.ico">
+    <title>Scene | Hubs by Mozilla</title>
+    <link href="https://fonts.googleapis.com/css?family=Zilla+Slab:300,300i,400,400i,700" rel="stylesheet">
+</head>
+
+<body>
+    <a-scene
+        renderer="antialias: true; gammaOutput: true; sortObjects: true; physicallyCorrectLights: true;"
+        vr-mode-ui="enabled: false"
+        gamma-factor
+    >
+        <a-entity
+            id="scene-root"
+            static-body="shape: none;"
+        ></a-entity>
+    </a-scene>
+
+    <div id="ui-root"></div>
+</body>
+
+</html>
diff --git a/src/scene.js b/src/scene.js
new file mode 100644
index 0000000000000000000000000000000000000000..d84cb3a447c08c121966b4e247a785209acad3e6
--- /dev/null
+++ b/src/scene.js
@@ -0,0 +1,107 @@
+console.log(`Hubs version: ${process.env.BUILD_VERSION || "?"}`);
+
+import "./assets/stylesheets/scene.scss";
+
+import "aframe";
+import "./utils/logging";
+import { patchWebGLRenderingContext } from "./utils/webgl";
+patchWebGLRenderingContext();
+
+import "three/examples/js/loaders/GLTFLoader";
+
+import "./components/skybox";
+import "./components/layers";
+import "./components/debug";
+import "./components/animation-mixer";
+import "./components/loop-animation";
+import "./components/gltf-model-plus";
+import "./components/ambient-light";
+import "./components/directional-light";
+import "./components/hemisphere-light";
+import "./components/point-light";
+import "./components/spot-light";
+
+import ReactDOM from "react-dom";
+import React from "react";
+import SceneUI from "./react-components/scene-ui";
+import { disableiOSZoom } from "./utils/disable-ios-zoom";
+
+import "./gltf-component-mappings";
+
+import { App } from "./App";
+
+window.APP = new App();
+window.APP.RENDER_ORDER = {
+  HUD_BACKGROUND: 1,
+  HUD_ICONS: 2,
+  CURSOR: 3
+};
+const store = window.APP.store;
+
+const qs = new URLSearchParams(location.search);
+const isMobile = AFRAME.utils.device.isMobile();
+
+window.APP.quality = qs.get("quality") || isMobile ? "low" : "high";
+
+import "aframe-physics-system";
+import "aframe-physics-extras";
+import "./components/event-repeater";
+import "./components/controls-shape-offset";
+
+import registerTelemetry from "./telemetry";
+
+registerTelemetry();
+
+disableiOSZoom();
+store.init();
+
+function mountUI(scene, props = {}) {
+  ReactDOM.render(
+    <SceneUI
+      {...{
+        scene,
+        store,
+        ...props
+      }}
+    />,
+    document.getElementById("ui-root")
+  );
+}
+
+const onReady = async () => {
+  const scene = document.querySelector("a-scene");
+  window.APP.scene = scene;
+
+  let uiProps = {};
+
+  mountUI(scene);
+
+  const remountUI = props => {
+    uiProps = { ...uiProps, ...props };
+    mountUI(scene, uiProps);
+  };
+
+  const sceneRoot = document.querySelector("#scene-root");
+  const sceneModelEntity = document.createElement("a-entity");
+
+  sceneModelEntity.addEventListener("scene-loaded", () => {
+    remountUI({ sceneLoaded: true });
+  });
+
+  sceneRoot.appendChild(sceneModelEntity);
+
+  const sceneId = qs.get("scene_id") || document.location.pathname.substring(1).split("/")[0];
+  console.log(`Scene ID: ${sceneId}`);
+
+  const sceneUrl = "";
+  console.log(`Scene URL: ${sceneUrl}`);
+
+  const gltfEl = document.createElement("a-entity");
+  gltfEl.setAttribute("gltf-model-plus", { src: sceneUrl, useCache: false, inflate: true });
+  gltfEl.addEventListener("model-loaded", () => sceneModelEntity.emit("scene-loaded"));
+  sceneModelEntity.appendChild(gltfEl);
+
+  //remountUI({ sceneId: scene.scene_id, sceneName: scene.name, sceneDescription: scene.description, sceneAttribution: scene.attribution  });
+};
+
+document.addEventListener("DOMContentLoaded", onReady);
diff --git a/webpack.config.js b/webpack.config.js
index 9531ceb26e70881f4bd4b5af7eb4367e2141f007..4c28ef4a04acaba07f91c52bf7d4bf804de6501d 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -64,6 +64,7 @@ module.exports = (env, argv) => ({
   entry: {
     index: path.join(__dirname, "src", "index.js"),
     hub: path.join(__dirname, "src", "hub.js"),
+    scene: path.join(__dirname, "src", "scene.js"),
     link: path.join(__dirname, "src", "link.js"),
     "avatar-selector": path.join(__dirname, "src", "avatar-selector.js")
   },
@@ -196,6 +197,20 @@ module.exports = (env, argv) => ({
         }
       ]
     }),
+    new HTMLWebpackPlugin({
+      filename: "scene.html",
+      template: path.join(__dirname, "src", "scene.html"),
+      chunks: ["vendor", "engine", "scene"],
+      inject: "head",
+      meta: [
+        {
+          "http-equiv": "origin-trial",
+          "data-feature": "WebVR (For Chrome M62+)",
+          "data-expires": process.env.ORIGIN_TRIAL_EXPIRES,
+          content: process.env.ORIGIN_TRIAL_TOKEN
+        }
+      ]
+    }),
     new HTMLWebpackPlugin({
       filename: "link.html",
       template: path.join(__dirname, "src", "link.html"),