diff --git a/README.md b/README.md
index 0cf314d0..7ea376ee 100644
--- a/README.md
+++ b/README.md
@@ -260,7 +260,8 @@ const viewer = new GaussianSplats3D.Viewer({
     'integerBasedSort': true,
     'dynamicScene': false,
     'webXRMode': GaussianSplats3D.WebXRMode.None,
-    'renderMode': GaussianSplats3D.RenderMode.OnChange
+    'renderMode': GaussianSplats3D.RenderMode.OnChange,
+    'sceneRevealMode': GaussianSplats3D.SceneRevealMode.Instant
 });
 viewer.addSplatScene('<path to .ply, .ksplat, or .splat file>')
 .then(() => {
@@ -291,6 +292,7 @@ Advanced `Viewer` parameters
 | `dynamicScene` | Tells the viewer to not make any optimizations that depend on the scene being static. Additionally all splat data retrieved from the viewer's splat mesh will not have their respective scene transform applied to them by default.
 | `webXRMode` | Tells the viewer whether or not to enable built-in Web VR or Web AR. Valid values are defined in the `WebXRMode` enum: `None`, `VR`, and `AR`. Defaults to `None`.
 | `renderMode` | Controls when the viewer renders the scene. Valid values are defined in the `RenderMode` enum: `Always`, `OnChange`, and `Never`. Defaults to `Always`.
+| `sceneRevealMode` | Controls the fade-in effect used when the scene is loaded. Valid values are defined in the `SceneRevealMode` enum: `Default`, `Gradual`, and `Instant`. `Default` results in a nice, slow fade-in effect for progressively loaded scenes, and a fast fade-in for non progressively loaded scenes. `Gradual` will force a slow fade-in for all scenes. `Instant` will force all loaded scene data to be immediately visible.
 <br>
 
 ### Creating KSPLAT files
@@ -301,8 +303,7 @@ import * as GaussianSplats3D from '@mkkellogg/gaussian-splats-3d';
 
 const compressionLevel = 1;
 const splatAlphaRemovalThreshold = 5; // out of 255
-const plyLoader = new GaussianSplats3D.PlyLoader();
-plyLoader.loadFromURL('<path to .ply or .splat file>', compressionLevel, splatAlphaRemovalThreshold)
+GaussianSplats3D.PlyLoader.loadFromURL('<path to .ply or .splat file>', compressionLevel, splatAlphaRemovalThreshold)
 .then((splatBuffer) => {
     GaussianSplats3D.KSplatLoader.downloadFile(splatBuffer, 'converted_file.ksplat');
 });
@@ -333,15 +334,15 @@ response.setHeader("Cross-Origin-Opener-Policy", "same-origin");
 response.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
 ```
 
-If you're using Apache, you can edit the `.htaccess` file to do that by adding the lines:
+#### CORS with Apache
+
+For Apache, you can edit the `.htaccess` file to allow CORS by adding the lines:
 
 ```
 Header add Cross-Origin-Opener-Policy "same-origin"
 Header add Cross-Origin-Embedder-Policy "require-corp"
 ```
 
-For other web servers, these headers most likely can be set in a similar fashion.
-
 Additionally you may need to require a secure connection to your server by redirecting all access via `http://` to `https://`. In Apache this can be done by updating the `.htaccess` file with the following lines:
 
 ```
@@ -349,3 +350,27 @@ RewriteEngine On
 RewriteCond %{HTTPS} off
 RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
 ```
+
+#### CORS with Vite
+
+For Vite, one popular option is to install the [vite-plugin-cross-origin-isolation](https://github.com/chaosprint/vite-plugin-cross-origin-isolation) plugin via `npm` and then add the following to your `vite.config.js` file. 
+
+```javascript
+import { defineConfig } from "vite";
+
+export default defineConfig({
+  plugins: [
+    {
+      name: "configure-response-headers",
+      configureServer: (server) => {
+        server.middlewares.use((_req, res, next) => {
+          res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
+          res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
+          next();
+        });
+      },
+    },
+  ],
+});
+```
+There are other ways to configure Vite to handle this referenced in issue [#41](https://github.com/mkkellogg/GaussianSplats3D/issues/41).
diff --git a/package-lock.json b/package-lock.json
index a2a93daa..531f3c82 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
     "name": "@mkkellogg/gaussian-splats-3d",
-    "version": "0.3.4",
+    "version": "0.3.5",
     "lockfileVersion": 3,
     "requires": true,
     "packages": {
         "": {
             "name": "@mkkellogg/gaussian-splats-3d",
-            "version": "0.3.4",
+            "version": "0.3.5",
             "license": "MIT",
             "devDependencies": {
                 "@babel/core": "7.22.0",
diff --git a/package.json b/package.json
index 47d1e405..f65eca0b 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
         "type": "git",
         "url": "https://github.com/mkkellogg/GaussianSplats3D"
     },
-    "version": "0.3.4",
+    "version": "0.3.5",
     "description": "Three.js-based 3D Gaussian splat viewer",
     "module": "build/gaussian-splats-3d.module.js",
     "main": "build/gaussian-splats-3d.umd.cjs",
diff --git a/src/SceneRevealMode.js b/src/SceneRevealMode.js
new file mode 100644
index 00000000..f341b40e
--- /dev/null
+++ b/src/SceneRevealMode.js
@@ -0,0 +1,5 @@
+export const SceneRevealMode = {
+    Default: 0,
+    Gradual: 1,
+    Instant: 2
+};
diff --git a/src/SplatMesh.js b/src/SplatMesh.js
index 63770e45..42eb2625 100644
--- a/src/SplatMesh.js
+++ b/src/SplatMesh.js
@@ -5,6 +5,7 @@ import { WebGLExtensions } from './three-shim/WebGLExtensions.js';
 import { WebGLCapabilities } from './three-shim/WebGLCapabilities.js';
 import { uintEncodedFloat, rgbaArrayToInteger } from './Util.js';
 import { Constants } from './Constants.js';
+import { SceneRevealMode } from './SceneRevealMode.js';
 
 const dummyGeometry = new THREE.BufferGeometry();
 const dummyMaterial = new THREE.MeshBasicMaterial();
@@ -12,6 +13,9 @@ const dummyMaterial = new THREE.MeshBasicMaterial();
 const COVARIANCES_ELEMENTS_PER_SPLAT = 6;
 const CENTER_COLORS_ELEMENTS_PER_SPLAT = 4;
 
+const SCENE_FADEIN_RATE_FAST = 0.012;
+const SCENE_FADEIN_RATE_GRADUAL = 0.003;
+
 /**
  * SplatMesh: Container for one or more splat scenes, abstracting them into a single unified container for
  * splat data. Additionally contains data structures and code to make the splat data renderable as a Three.js mesh.
@@ -591,7 +595,6 @@ export class SplatMesh extends THREE.Mesh {
             this.visibleRegionRadius = 0;
             this.visibleRegionFadeStartRadius = 0;
             this.firstRenderTime = -1;
-            this.finalBuild = false;
             this.lastBuildScenes = [];
             this.lastBuildSplatCount = 0;
             this.lastBuildMaxSplatCount = 0;
@@ -911,16 +914,22 @@ export class SplatMesh extends THREE.Mesh {
         this.updateVisibleRegionFadeDistance();
     }
 
-    updateVisibleRegionFadeDistance() {
-        const fadeInRate = this.finalBuild ? 0.01 : 0.003;
+    updateVisibleRegionFadeDistance(sceneRevealMode = SceneRevealMode.Default) {
+        const fastFadeRate = SCENE_FADEIN_RATE_FAST;
+        const gradualFadeRate = SCENE_FADEIN_RATE_GRADUAL;
+        const defaultFadeInRate = this.finalBuild ? fastFadeRate : gradualFadeRate;
+        const fadeInRate = sceneRevealMode === SceneRevealMode.Default ? defaultFadeInRate : gradualFadeRate;
         this.visibleRegionFadeStartRadius = (this.visibleRegionRadius - this.visibleRegionFadeStartRadius) *
-                                        fadeInRate + this.visibleRegionFadeStartRadius;
-        const fadeInComplete = (this.visibleRegionFadeStartRadius / this.maxRadius) > 0.99 ? 1 : 0;
+                                             fadeInRate + this.visibleRegionFadeStartRadius;
+        const fadeInPercentage = (this.visibleRegionFadeStartRadius / this.maxRadius);
+        const fadeInComplete = fadeInPercentage > 0.99;
+        const shaderFadeInComplete = (fadeInComplete || sceneRevealMode === SceneRevealMode.Instant) ? 1 : 0;
+
         this.material.uniforms.visibleRegionFadeStartRadius.value = this.visibleRegionFadeStartRadius;
         this.material.uniforms.visibleRegionRadius.value = this.visibleRegionRadius;
         this.material.uniforms.firstRenderTime.value = this.firstRenderTime;
         this.material.uniforms.currentTime.value = performance.now();
-        this.material.uniforms.fadeInComplete.value = fadeInComplete;
+        this.material.uniforms.fadeInComplete.value = shaderFadeInComplete;
         this.material.uniformsNeedUpdate = true;
         this.visibleRegionChanging = !fadeInComplete;
     }
diff --git a/src/Viewer.js b/src/Viewer.js
index 2d40b4dc..4ca96098 100644
--- a/src/Viewer.js
+++ b/src/Viewer.js
@@ -21,6 +21,7 @@ import { ARButton } from './webxr/ARButton.js';
 import { delayedExecute } from './Util.js';
 import { LoaderStatus } from './loaders/LoaderStatus.js';
 import { RenderMode } from './RenderMode.js';
+import { SceneRevealMode } from './SceneRevealMode.js';
 
 const THREE_CAMERA_FOV = 50;
 const MINIMUM_DISTANCE_TO_NEW_FOCAL_POINT = .75;
@@ -122,8 +123,16 @@ export class Viewer {
             this.gpuAcceleratedSort = false;
         }
 
+        // if 'renderMode' is RenderMode.Always, then the viewer will rrender the scene on every update. If it is RenderMode.OnChange,
+        // it will only render when something in the scene has changed.
         this.renderMode = options.renderMode || RenderMode.Always;
 
+        // SceneRevealMode.Default results in a nice, slow fade-in effect for progressively loaded scenes,
+        // and a fast fade-in for non progressively loaded scenes.
+        // SceneRevealMode.Gradual will force a slow fade-in for all scenes.
+        // SceneRevealMode.Instant will force all loaded scene data to be immediately visible.
+        this.sceneRevealMode = options.sceneRevealMode || SceneRevealMode.Default;
+
         this.controls = null;
 
         this.showMeshCursor = false;
@@ -1170,7 +1179,7 @@ export class Viewer {
         if (this.dropInMode) this.updateForDropInMode(renderer, camera);
         if (!this.initialized || !this.splatRenderingInitialized) return;
         if (this.controls) this.controls.update();
-        this.splatMesh.updateVisibleRegionFadeDistance();
+        this.splatMesh.updateVisibleRegionFadeDistance(this.sceneRevealMode);
         this.updateSplatSort();
         this.updateForRendererSizeChanges();
         this.updateSplatMesh();
@@ -1488,8 +1497,6 @@ export class Viewer {
             return tempMax.copy(node.max).sub(node.min).length();
         };
 
-        const MaximumDistanceToRender = 125;
-
         return function(gatherAllNodes = false) {
 
             this.getRenderDimensions(renderDimensions);
@@ -1533,8 +1540,7 @@ export class Viewer {
                         const ns = nodeSize(node);
                         const outOfFovY = cameraAngleYZDot < (cosFovYOver2 - .6);
                         const outOfFovX = cameraAngleXZDot < (cosFovXOver2 - .6);
-                        if (!gatherAllNodes && ((outOfFovX || outOfFovY ||
-                             distanceToNode > MaximumDistanceToRender) && distanceToNode > ns)) {
+                        if (!gatherAllNodes && ((outOfFovX || outOfFovY) && distanceToNode > ns)) {
                             continue;
                         }
                         splatRenderCount += node.data.indexes.length;
diff --git a/src/index.js b/src/index.js
index 709b4d49..536e4d6d 100644
--- a/src/index.js
+++ b/src/index.js
@@ -15,6 +15,7 @@ import { AbortablePromise } from './AbortablePromise.js';
 import { SceneFormat } from './loaders/SceneFormat.js';
 import { WebXRMode } from './webxr/WebXRMode.js';
 import { RenderMode } from './RenderMode.js';
+import { SceneRevealMode } from './SceneRevealMode.js';
 
 export {
     PlyParser,
@@ -33,5 +34,6 @@ export {
     AbortablePromise,
     SceneFormat,
     WebXRMode,
-    RenderMode
+    RenderMode,
+    SceneRevealMode
 };
diff --git a/src/splattree/SplatTree.js b/src/splattree/SplatTree.js
index 72bf703d..a4151339 100644
--- a/src/splattree/SplatTree.js
+++ b/src/splattree/SplatTree.js
@@ -81,6 +81,8 @@ class SplatSubTree {
 let splatTreeWorker;
 function createSplatTreeWorker(self) {
 
+    let WorkerSplatTreeNodeIDGen = 0;
+
     class WorkerBox3 {
 
         constructor(min, max) {
@@ -112,7 +114,7 @@ function createSplatTreeWorker(self) {
     }
 
     class WorkerSplatTreeNode {
-        static idGen = 0;
+
         constructor(min, max, depth, id) {
             this.min = [min[0], min[1], min[2]];
             this.max = [max[0], max[1], max[2]];
@@ -122,7 +124,7 @@ function createSplatTreeWorker(self) {
             this.depth = depth;
             this.children = [];
             this.data = null;
-            this.id = id || WorkerSplatTreeNode.idGen++;
+            this.id = id || WorkerSplatTreeNodeIDGen++;
         }
 
     }