From 3ca56576e187e2f3cc87770b0fbdf8aa6cae73f3 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 14 Apr 2021 23:12:19 -0400
Subject: fixed image templates to set/use the appropriate nativewidth/height.
 fixed carousel views and style provider to better support properties for
 components of a document view.  fixed menus to show text options when
 captions and other sub text components are focused.

---
 src/client/views/collections/CollectionMenu.tsx | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'src/client/views/collections/CollectionMenu.tsx')

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index a26953ff6..95b0ef790 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -37,6 +37,7 @@ import { LightboxView } from "../LightboxView";
 import { Docs } from "../../documents/Documents";
 import { DocumentManager } from "../../util/DocumentManager";
 import { CollectionDockingView } from "./CollectionDockingView";
+import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox";
 
 @observer
 export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -260,6 +261,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
             case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" {...this.props} />);
             case CollectionViewType.Tree: return (<CollectionTreeViewChrome key="collchrome" {...this.props} />);
             case CollectionViewType.Masonry: return (<CollectionStackingViewChrome key="collchrome" {...this.props} />);
+            case CollectionViewType.Carousel:
             case CollectionViewType.Carousel3D: return (<Collection3DCarouselViewChrome key="collchrome" {...this.props} />);
             case CollectionViewType.Grid: return (<CollectionGridViewChrome key="collchrome" {...this.props} />);
             case CollectionViewType.Docking: return (<CollectionDockingChrome key="collchrome" {...this.props} />);
@@ -1021,6 +1023,7 @@ export class Collection3DCarouselViewChrome extends React.Component<CollectionMe
         return (
             <div className="collection3DCarouselViewChrome-cont">
                 <div className="collection3DCarouselViewChrome-scrollSpeed-cont">
+                    {FormattedTextBox.Focused ? <RichTextMenu /> : (null)}
                     <div className="collectionStackingViewChrome-scrollSpeed-label">
                         AUTOSCROLL SPEED:
                     </div>
-- 
cgit v1.2.3-70-g09d2


From 4334a553fdfdf44b1d1c609290fe2a874a408967 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 15 Apr 2021 00:04:18 -0400
Subject: fixed up carousels to work with templated documents

---
 .../views/collections/CollectionCarousel3DView.tsx | 40 +++++++++++++++++-----
 .../views/collections/CollectionCarouselView.tsx   | 32 +++++++++++++----
 src/client/views/collections/CollectionMenu.tsx    |  2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  1 +
 4 files changed, 59 insertions(+), 16 deletions(-)

(limited to 'src/client/views/collections/CollectionMenu.tsx')

diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 9a3183d88..7cebabaa9 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -9,10 +9,11 @@ import { makeInterface } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
 import { NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { OmitKeys, returnFalse, Utils } from '../../../Utils';
-import { DragManager } from '../../util/DragManager';
+import { DragManager, dropActionType } from '../../util/DragManager';
 import { DocumentView } from '../nodes/DocumentView';
 import "./CollectionCarousel3DView.scss";
 import { CollectionSubView } from './CollectionSubView';
+import { StyleProp } from '../StyleProvider';
 
 type Carousel3DDocument = makeInterface<[typeof documentSchema, typeof collectionSchema]>;
 const Carousel3DDocument = makeInterface(documentSchema, collectionSchema);
@@ -42,17 +43,36 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
         const displayDoc = (childPair: { layout: Doc, data: Doc }) => {
             const script = ScriptField.MakeScript("this._showCaption = 'caption'", { this: Doc.name });
             const onChildClick = script && (() => script);
-            return <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
-                onDoubleClick={this.onChildDoubleClick}
-                onClick={onChildClick}
-                renderDepth={this.props.renderDepth + 1}
+            return <DocumentView
+                Document={childPair.layout}
+                DataDoc={childPair.layout.resolvedDataDoc as Doc}
+                styleProvider={this.props.styleProvider}
+                layerProvider={this.props.layerProvider}
+                docViewPath={this.props.docViewPath}
                 LayoutTemplate={this.props.childLayoutTemplate}
                 LayoutTemplateString={this.props.childLayoutString}
-                Document={childPair.layout}
-                DataDoc={childPair.data}
+                freezeDimensions={this.props.childFreezeDimensions}
+                renderDepth={this.props.renderDepth + 1}
                 PanelWidth={this.panelWidth}
                 PanelHeight={this.panelHeight}
+                rootSelected={this.rootSelected}
+                dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
                 ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+                focus={this.props.focus}
+                docFilters={this.docFilters}
+                onDoubleClick={this.onChildDoubleClick}
+                onClick={onChildClick}
+                isContentActive={returnFalse}
+                docRangeFilters={this.docRangeFilters}
+                searchFilterDocs={this.searchFilterDocs}
+                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+                ContainingCollectionView={this.props.CollectionView}
+                addDocument={this.props.addDocument}
+                moveDocument={this.props.moveDocument}
+                removeDocument={this.props.removeDocument}
+                whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+                addDocTab={this.props.addDocTab}
+                pinToPres={this.props.pinToPres}
                 bringToFront={returnFalse}
             />;
         };
@@ -146,7 +166,11 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
         const index = NumCast(this.layoutDoc._itemIndex);
         const translateX = this.panelWidth() * (1 - index);
 
-        return <div className="collectionCarousel3DView-outer" ref={this.createDashEventsTarget}>
+        return <div className="collectionCarousel3DView-outer" ref={this.createDashEventsTarget}
+            style={{
+                background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
+                color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
+            }}  >
             <div className="carousel-wrapper" style={{ transform: `translateX(${translateX}px)` }}>
                 {this.content}
             </div>
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 0642a1f9b..4a7bdf6db 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -7,7 +7,7 @@ import { collectionSchema, documentSchema } from '../../../fields/documentSchema
 import { makeInterface } from '../../../fields/Schema';
 import { NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { OmitKeys, returnFalse } from '../../../Utils';
-import { DragManager } from '../../util/DragManager';
+import { DragManager, dropActionType } from '../../util/DragManager';
 import { DocumentView } from '../nodes/DocumentView';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import { StyleProp } from '../StyleProvider';
@@ -47,16 +47,34 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
         return !(curDoc?.layout instanceof Doc) ? (null) :
             <>
                 <div className="collectionCarouselView-image" key="image">
-                    <DocumentView  {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
-                        onDoubleClick={this.onContentDoubleClick}
-                        onClick={this.onContentClick}
-                        renderDepth={this.props.renderDepth + 1}
+                    <DocumentView
+                        Document={curDoc.layout}
+                        DataDoc={curDoc.layout.resolvedDataDoc as Doc}
+                        styleProvider={this.props.styleProvider}
+                        layerProvider={this.props.layerProvider}
+                        docViewPath={this.props.docViewPath}
                         LayoutTemplate={this.props.childLayoutTemplate}
                         LayoutTemplateString={this.props.childLayoutString}
-                        Document={curDoc.layout}
-                        DataDoc={curDoc.data}
+                        freezeDimensions={this.props.childFreezeDimensions}
+                        renderDepth={this.props.renderDepth + 1}
+                        PanelWidth={this.props.PanelWidth}
                         PanelHeight={this.panelHeight}
+                        rootSelected={this.rootSelected}
+                        dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
                         ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+                        focus={this.props.focus}
+                        docFilters={this.docFilters}
+                        isContentActive={returnFalse}
+                        docRangeFilters={this.docRangeFilters}
+                        searchFilterDocs={this.searchFilterDocs}
+                        ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+                        ContainingCollectionView={this.props.CollectionView}
+                        addDocument={this.props.addDocument}
+                        moveDocument={this.props.moveDocument}
+                        removeDocument={this.props.removeDocument}
+                        whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+                        addDocTab={this.props.addDocTab}
+                        pinToPres={this.props.pinToPres}
                         bringToFront={returnFalse}
                     />
                 </div>
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 95b0ef790..ab4f197a6 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -554,7 +554,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                         <div className="collectionMenu-divider" key="divider3"></div>
                         {this.lightboxButton}
                         {this.recordButton}
-                        {/* {!this._buttonizableCommands ? (null) : this.templateChrome} */}
+                        {!this._buttonizableCommands ? (null) : this.templateChrome}
                     </div>
                 </div>
             </div>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 9203207d7..25dc93605 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1342,6 +1342,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         this._undoTyping = undefined;
         return wasUndoing;
     }
+    @action
     onBlur = (e: any) => {
         FormattedTextBox.Focused === this && (FormattedTextBox.Focused = undefined);
         if (RichTextMenu.Instance?.view === this._editorView && !this.props.isSelected(true)) {
-- 
cgit v1.2.3-70-g09d2


From 51b234e66dc819bb6fb714e55a62d8515a9c8886 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 23 Apr 2021 14:15:11 -0400
Subject: fixed code warnings. updated some npm pacakges including typescript.

---
 package-lock.json                               | 616 +++++++++++++++++-------
 package.json                                    |  19 +-
 src/client/util/CaptureManager.tsx              |   4 +-
 src/client/util/Scripting.ts                    |   1 +
 src/client/views/MarqueeAnnotator.tsx           |   2 +-
 src/client/views/PropertiesView.tsx             |   4 +-
 src/client/views/StyleProvider.tsx              |   2 +-
 src/client/views/collections/CollectionMenu.tsx |   2 +-
 src/client/views/nodes/DocumentContentsView.tsx |  44 +-
 src/client/views/nodes/ImageBox.tsx             |   2 -
 src/client/views/nodes/ScreenshotBox.tsx        | 217 ++++-----
 src/fields/Schema.ts                            |  32 +-
 webpack.config.js                               |   4 +-
 13 files changed, 593 insertions(+), 356 deletions(-)

(limited to 'src/client/views/collections/CollectionMenu.tsx')

diff --git a/package-lock.json b/package-lock.json
index d286a4e02..3637b14ac 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -512,6 +512,42 @@
                 "react-is": "^16.8.0"
             }
         },
+        "@react-three/fiber": {
+            "version": "6.0.16",
+            "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-6.0.16.tgz",
+            "integrity": "sha512-oKMYNJOd5t+V4o18aRMhaRhcDQ1NeeCDy52yJvXpu7zrsR04YZtXD4RacW0FDH0KnwkOLDst95LCCphm3Thk/A==",
+            "requires": {
+                "@babel/runtime": "^7.13.10",
+                "react-merge-refs": "^1.1.0",
+                "react-reconciler": "^0.26.2",
+                "react-three-fiber": "0.0.0-deprecated",
+                "react-use-measure": "^2.0.4",
+                "resize-observer-polyfill": "^1.5.1",
+                "scheduler": "^0.20.2",
+                "use-asset": "^1.0.4",
+                "utility-types": "^3.10.0",
+                "zustand": "^3.3.3"
+            },
+            "dependencies": {
+                "@babel/runtime": {
+                    "version": "7.13.17",
+                    "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.17.tgz",
+                    "integrity": "sha512-NCdgJEelPTSh+FEFylhnP1ylq848l1z9t9N0j1Lfbcw0+KXGjsTvUmkxy+voLLXB5SOKMbLLx4jxYliGrYQseA==",
+                    "requires": {
+                        "regenerator-runtime": "^0.13.4"
+                    }
+                },
+                "scheduler": {
+                    "version": "0.20.2",
+                    "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
+                    "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
+                    "requires": {
+                        "loose-envify": "^1.1.0",
+                        "object-assign": "^4.1.1"
+                    }
+                }
+            }
+        },
         "@rkusa/linebreak": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/@rkusa/linebreak/-/linebreak-1.0.0.tgz",
@@ -683,6 +719,37 @@
                 "@types/express": "*"
             }
         },
+        "@types/d3-axis": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-2.0.0.tgz",
+            "integrity": "sha512-gUdlEwGBLl3tXGiBnBNmNzph9W3bCfa4tBgWZD60Z1eDQKTY4zyCAcZ3LksignGfKawYatmDYcBdjJ5h/54sqA==",
+            "requires": {
+                "@types/d3-selection": "*"
+            }
+        },
+        "@types/d3-color": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-2.0.1.tgz",
+            "integrity": "sha512-u7LTCL7RnaavFSmob2rIAJLNwu50i6gFwY9cHFr80BrQURYQBRkJ+Yv47nA3Fm7FeRhdWTiVTeqvSeOuMAOzBQ=="
+        },
+        "@types/d3-scale": {
+            "version": "3.2.2",
+            "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.2.2.tgz",
+            "integrity": "sha512-qpQe8G02tzUwt9sdWX1h8A/W0Q1+N48wMnYXVOkrzeLUkCfvzJYV9Ee3aORCS4dN4ONRLFmMvaXdziQ29XGLjQ==",
+            "requires": {
+                "@types/d3-time": "*"
+            }
+        },
+        "@types/d3-selection": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-2.0.0.tgz",
+            "integrity": "sha512-EF0lWZ4tg7oDFg4YQFlbOU3936e3a9UmoQ2IXlBy1+cv2c2Pv7knhKUzGlH5Hq2sF/KeDTH1amiRPey2rrLMQA=="
+        },
+        "@types/d3-time": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.0.0.tgz",
+            "integrity": "sha512-Abz8bTzy8UWDeYs9pCa3D37i29EWDjNTjemdk0ei1ApYVNqulYlGUKip/jLOpogkPSsPz/GvZCYiC7MFlEk0iQ=="
+        },
         "@types/dotenv": {
             "version": "6.1.1",
             "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz",
@@ -845,9 +912,9 @@
             "dev": true
         },
         "@types/memory-fs": {
-            "version": "0.3.2",
-            "resolved": "https://registry.npmjs.org/@types/memory-fs/-/memory-fs-0.3.2.tgz",
-            "integrity": "sha512-j5AcZo7dbMxHoOimcHEIh0JZe5e1b8q8AqGSpZJrYc7xOgCIP79cIjTdx5jSDLtySnQDwkDTqwlC7Xw7uXw7qg==",
+            "version": "0.3.3",
+            "resolved": "https://registry.npmjs.org/@types/memory-fs/-/memory-fs-0.3.3.tgz",
+            "integrity": "sha512-rLEYzl1xODshz+Lm+YX8NYws8Xw7/qcYbQInMkotl96VpLZmUvoCfYYGxfajMSiugANV02QO5Fc+R98KKeE4gQ==",
             "dev": true,
             "requires": {
                 "@types/node": "*"
@@ -1195,6 +1262,14 @@
                 "@types/react": "*"
             }
         },
+        "@types/react-reconciler": {
+            "version": "0.26.1",
+            "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.1.tgz",
+            "integrity": "sha512-jeizEH5o/k6tv42RYNbaulR9KvoSM4RAUq1Q2SXd2HZ7dqgTxN9OIf+GU/sErT7CohB/mUxy9hSjaRLiCPGF5w==",
+            "requires": {
+                "@types/react": "*"
+            }
+        },
         "@types/react-select": {
             "version": "3.0.13",
             "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-3.0.13.tgz",
@@ -1337,9 +1412,9 @@
             "dev": true
         },
         "@types/tapable": {
-            "version": "1.0.6",
-            "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz",
-            "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==",
+            "version": "1.0.7",
+            "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.7.tgz",
+            "integrity": "sha512-0VBprVqfgFD7Ehb2vd8Lh9TG3jP98gvr8rgehQqzztZNI7o8zS8Ad4jyZneKELphpuE212D8J70LnSNQSyO6bQ==",
             "dev": true
         },
         "@types/three": {
@@ -1363,9 +1438,9 @@
             }
         },
         "@types/uglify-js": {
-            "version": "3.9.2",
-            "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.9.2.tgz",
-            "integrity": "sha512-d6dIfpPbF+8B7WiCi2ELY7m0w1joD8cRW4ms88Emdb2w062NeEpbNCeWwVCgzLRpVG+5e74VFSg4rgJ2xXjEiQ==",
+            "version": "3.13.0",
+            "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.0.tgz",
+            "integrity": "sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==",
             "dev": true,
             "requires": {
                 "source-map": "^0.6.1"
@@ -1392,14 +1467,14 @@
             "dev": true
         },
         "@types/webpack": {
-            "version": "4.41.18",
-            "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.18.tgz",
-            "integrity": "sha512-mQm2R8vV2BZE/qIDVYqmBVLfX73a8muwjs74SpjEyJWJxeXBbsI9L65Pcia9XfYLYWzD1c1V8m+L0p30y2N7MA==",
+            "version": "4.41.27",
+            "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.27.tgz",
+            "integrity": "sha512-wK/oi5gcHi72VMTbOaQ70VcDxSQ1uX8S2tukBK9ARuGXrYM/+u4ou73roc7trXDNmCxCoerE8zruQqX/wuHszA==",
             "dev": true,
             "requires": {
                 "@types/anymatch": "*",
                 "@types/node": "*",
-                "@types/tapable": "*",
+                "@types/tapable": "^1",
                 "@types/uglify-js": "*",
                 "@types/webpack-sources": "*",
                 "source-map": "^0.6.0"
@@ -1414,30 +1489,31 @@
             }
         },
         "@types/webpack-dev-middleware": {
-            "version": "2.0.5",
-            "resolved": "https://registry.npmjs.org/@types/webpack-dev-middleware/-/webpack-dev-middleware-2.0.5.tgz",
-            "integrity": "sha512-B/1X0xAYz62rtjn3gYWaYLRISKzjWehpjndCvpCNuv0OJi4TbIV6QQt9xq/moVxB83u2RjsG8E8S6U/Efg/Vvw==",
+            "version": "2.0.7",
+            "resolved": "https://registry.npmjs.org/@types/webpack-dev-middleware/-/webpack-dev-middleware-2.0.7.tgz",
+            "integrity": "sha512-pArv7YnqpbSCOBWiRlR1KgqVorlzkIiwto66hI8Gdgp5ATQAC+Ug4QVz69ZI1dP+D5Rs8QWnbT81tE4tcMuTag==",
             "dev": true,
             "requires": {
                 "@types/connect": "*",
                 "@types/memory-fs": "*",
-                "@types/webpack": "*"
+                "@types/webpack": "^4",
+                "loglevel": "^1.6.2"
             }
         },
         "@types/webpack-hot-middleware": {
-            "version": "2.25.3",
-            "resolved": "https://registry.npmjs.org/@types/webpack-hot-middleware/-/webpack-hot-middleware-2.25.3.tgz",
-            "integrity": "sha512-zGkTzrwQnhSadIXGYGZLu7tpXQwn4+6y9nGeql+5UeRtW/k54Jp4SnzB0Qw00ednw0ZFoZOvqTFfXSbFXohc5Q==",
+            "version": "2.25.4",
+            "resolved": "https://registry.npmjs.org/@types/webpack-hot-middleware/-/webpack-hot-middleware-2.25.4.tgz",
+            "integrity": "sha512-6tQb9EBKIANZYUVLQYWiWfDFVe7FhXSj4bB2EF5QB7VtYWL3HDR+y/zqjZPAnCorv0spLqVMRqjRK8AmhfocMw==",
             "dev": true,
             "requires": {
                 "@types/connect": "*",
-                "@types/webpack": "*"
+                "@types/webpack": "^4"
             }
         },
         "@types/webpack-sources": {
-            "version": "1.4.0",
-            "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-1.4.0.tgz",
-            "integrity": "sha512-c88dKrpSle9BtTqR6ifdaxu1Lvjsl3C5OsfvuUbUwdXymshv1TkufUAXBajCCUM/f/TmnkZC/Esb03MinzSiXQ==",
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz",
+            "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==",
             "dev": true,
             "requires": {
                 "@types/node": "*",
@@ -2138,14 +2214,23 @@
             }
         },
         "asn1.js": {
-            "version": "4.10.1",
-            "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
-            "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
+            "version": "5.4.1",
+            "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
+            "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
             "dev": true,
             "requires": {
                 "bn.js": "^4.0.0",
                 "inherits": "^2.0.1",
-                "minimalistic-assert": "^1.0.0"
+                "minimalistic-assert": "^1.0.0",
+                "safer-buffer": "^2.1.0"
+            },
+            "dependencies": {
+                "bn.js": {
+                    "version": "4.12.0",
+                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+                    "dev": true
+                }
             }
         },
         "assert": {
@@ -2597,9 +2682,9 @@
             "integrity": "sha512-6sTGh1OiUmuH8ftAYvUzALivoOmcnahinGmjZFI4puZVowXoKTn/bXtth7N1skW5AlezEOfjgFH4lNXHeNRQog=="
         },
         "bn.js": {
-            "version": "4.11.8",
-            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
-            "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
+            "version": "5.2.0",
+            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
+            "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==",
             "dev": true
         },
         "body-parser": {
@@ -2793,28 +2878,38 @@
             }
         },
         "browserify-rsa": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
-            "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
+            "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
             "dev": true,
             "requires": {
-                "bn.js": "^4.1.0",
+                "bn.js": "^5.0.0",
                 "randombytes": "^2.0.1"
             }
         },
         "browserify-sign": {
-            "version": "4.0.4",
-            "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
-            "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
+            "version": "4.2.1",
+            "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
+            "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
             "dev": true,
             "requires": {
-                "bn.js": "^4.1.1",
-                "browserify-rsa": "^4.0.0",
-                "create-hash": "^1.1.0",
-                "create-hmac": "^1.1.2",
-                "elliptic": "^6.0.0",
-                "inherits": "^2.0.1",
-                "parse-asn1": "^5.0.0"
+                "bn.js": "^5.1.1",
+                "browserify-rsa": "^4.0.1",
+                "create-hash": "^1.2.0",
+                "create-hmac": "^1.1.7",
+                "elliptic": "^6.5.3",
+                "inherits": "^2.0.4",
+                "parse-asn1": "^5.1.5",
+                "readable-stream": "^3.6.0",
+                "safe-buffer": "^5.2.0"
+            },
+            "dependencies": {
+                "safe-buffer": {
+                    "version": "5.2.1",
+                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+                    "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+                    "dev": true
+                }
             }
         },
         "browserify-zlib": {
@@ -3680,13 +3775,10 @@
             }
         },
         "chrome-trace-event": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz",
-            "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==",
-            "dev": true,
-            "requires": {
-                "tslib": "^1.9.0"
-            }
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
+            "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
+            "dev": true
         },
         "ci-info": {
             "version": "1.6.0",
@@ -4341,13 +4433,21 @@
             }
         },
         "create-ecdh": {
-            "version": "4.0.3",
-            "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
-            "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==",
+            "version": "4.0.4",
+            "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
+            "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
             "dev": true,
             "requires": {
                 "bn.js": "^4.1.0",
-                "elliptic": "^6.0.0"
+                "elliptic": "^6.5.3"
+            },
+            "dependencies": {
+                "bn.js": {
+                    "version": "4.12.0",
+                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+                    "dev": true
+                }
             }
         },
         "create-emotion": {
@@ -5323,6 +5423,14 @@
                 "bn.js": "^4.1.0",
                 "miller-rabin": "^4.0.0",
                 "randombytes": "^2.0.0"
+            },
+            "dependencies": {
+                "bn.js": {
+                    "version": "4.12.0",
+                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+                    "dev": true
+                }
             }
         },
         "dir-glob": {
@@ -5532,18 +5640,26 @@
             "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
         },
         "elliptic": {
-            "version": "6.5.2",
-            "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
-            "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
+            "version": "6.5.4",
+            "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
+            "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
             "dev": true,
             "requires": {
-                "bn.js": "^4.4.0",
-                "brorand": "^1.0.1",
+                "bn.js": "^4.11.9",
+                "brorand": "^1.1.0",
                 "hash.js": "^1.0.0",
-                "hmac-drbg": "^1.0.0",
-                "inherits": "^2.0.1",
-                "minimalistic-assert": "^1.0.0",
-                "minimalistic-crypto-utils": "^1.0.0"
+                "hmac-drbg": "^1.0.1",
+                "inherits": "^2.0.4",
+                "minimalistic-assert": "^1.0.1",
+                "minimalistic-crypto-utils": "^1.0.1"
+            },
+            "dependencies": {
+                "bn.js": {
+                    "version": "4.12.0",
+                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+                    "dev": true
+                }
             }
         },
         "emoji-regex": {
@@ -5821,12 +5937,20 @@
             "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
         },
         "esrecurse": {
-            "version": "4.2.1",
-            "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
-            "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+            "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
             "dev": true,
             "requires": {
-                "estraverse": "^4.1.0"
+                "estraverse": "^5.2.0"
+            },
+            "dependencies": {
+                "estraverse": {
+                    "version": "5.2.0",
+                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+                    "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+                    "dev": true
+                }
             }
         },
         "estraverse": {
@@ -5857,9 +5981,9 @@
             "dev": true
         },
         "events": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz",
-            "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==",
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+            "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
             "dev": true
         },
         "eventsource": {
@@ -7251,13 +7375,22 @@
             }
         },
         "hash-base": {
-            "version": "3.0.4",
-            "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
-            "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+            "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
             "dev": true,
             "requires": {
-                "inherits": "^2.0.1",
-                "safe-buffer": "^5.0.1"
+                "inherits": "^2.0.4",
+                "readable-stream": "^3.6.0",
+                "safe-buffer": "^5.2.0"
+            },
+            "dependencies": {
+                "safe-buffer": {
+                    "version": "5.2.1",
+                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+                    "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+                    "dev": true
+                }
             }
         },
         "hash.js": {
@@ -9190,6 +9323,14 @@
             "requires": {
                 "bn.js": "^4.0.0",
                 "brorand": "^1.0.1"
+            },
+            "dependencies": {
+                "bn.js": {
+                    "version": "4.12.0",
+                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+                    "dev": true
+                }
             }
         },
         "mime": {
@@ -13487,14 +13628,13 @@
             }
         },
         "parse-asn1": {
-            "version": "5.1.5",
-            "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz",
-            "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==",
+            "version": "5.1.6",
+            "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
+            "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
             "dev": true,
             "requires": {
-                "asn1.js": "^4.0.0",
+                "asn1.js": "^5.2.0",
                 "browserify-aes": "^1.0.0",
-                "create-hash": "^1.1.0",
                 "evp_bytestokey": "^1.0.0",
                 "pbkdf2": "^3.0.3",
                 "safe-buffer": "^5.1.1"
@@ -13650,9 +13790,9 @@
             "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
         },
         "pbkdf2": {
-            "version": "3.0.17",
-            "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
-            "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==",
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+            "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
             "dev": true,
             "requires": {
                 "create-hash": "^1.1.2",
@@ -14174,6 +14314,14 @@
                 "parse-asn1": "^5.0.0",
                 "randombytes": "^2.0.1",
                 "safe-buffer": "^5.1.2"
+            },
+            "dependencies": {
+                "bn.js": {
+                    "version": "4.12.0",
+                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+                    "dev": true
+                }
             }
         },
         "pug": {
@@ -14801,13 +14949,13 @@
             }
         },
         "react-reconciler": {
-            "version": "0.26.1",
-            "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.26.1.tgz",
-            "integrity": "sha512-6E/CvH9zcDmHjhiNJlP0qJ8+3ufnY2b5RWs774Uy8XKWN0l6qfnlkz0XnDacxqj2rbJdq76w9dlFXjPPOQrmqA==",
+            "version": "0.26.2",
+            "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.26.2.tgz",
+            "integrity": "sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q==",
             "requires": {
                 "loose-envify": "^1.1.0",
                 "object-assign": "^4.1.1",
-                "scheduler": "^0.20.1"
+                "scheduler": "^0.20.2"
             },
             "dependencies": {
                 "scheduler": {
@@ -14918,39 +15066,9 @@
             }
         },
         "react-three-fiber": {
-            "version": "5.3.22",
-            "resolved": "https://registry.npmjs.org/react-three-fiber/-/react-three-fiber-5.3.22.tgz",
-            "integrity": "sha512-TAOsFg7oerXDkUK/NUwlaMd+drteokXdDMACDmeBKzx64Z0IruJl/ORW7x3giWzqG3fs6BBv+rpcreFW9Ofuyg==",
-            "requires": {
-                "@babel/runtime": "^7.12.1",
-                "react-merge-refs": "^1.1.0",
-                "react-reconciler": "0.26.1",
-                "react-use-measure": "^2.0.3",
-                "resize-observer-polyfill": "^1.5.1",
-                "scheduler": "0.20.1",
-                "tiny-emitter": "^2.1.0",
-                "use-asset": "^1.0.4",
-                "utility-types": "^3.10.0"
-            },
-            "dependencies": {
-                "@babel/runtime": {
-                    "version": "7.13.10",
-                    "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz",
-                    "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==",
-                    "requires": {
-                        "regenerator-runtime": "^0.13.4"
-                    }
-                },
-                "scheduler": {
-                    "version": "0.20.1",
-                    "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.1.tgz",
-                    "integrity": "sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw==",
-                    "requires": {
-                        "loose-envify": "^1.1.0",
-                        "object-assign": "^4.1.1"
-                    }
-                }
-            }
+            "version": "0.0.0-deprecated",
+            "resolved": "https://registry.npmjs.org/react-three-fiber/-/react-three-fiber-0.0.0-deprecated.tgz",
+            "integrity": "sha512-EblIqTAsIpkYeM8bZtC4lcpTE0A2zCEGipFB52RgcQq/q+0oryrk7Sxt+sqhIjUu6xMNEVywV8dr74lz5yWO6A=="
         },
         "react-transition-group": {
             "version": "2.9.0",
@@ -16847,9 +16965,9 @@
             }
         },
         "terser": {
-            "version": "4.6.12",
-            "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.12.tgz",
-            "integrity": "sha512-fnIwuaKjFPANG6MAixC/k1TDtnl1YlPLUlLVIxxGZUn1gfUx2+l3/zGNB72wya+lgsb50QBi2tUV75RiODwnww==",
+            "version": "4.8.0",
+            "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
+            "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
             "dev": true,
             "requires": {
                 "commander": "^2.20.0",
@@ -16866,16 +16984,16 @@
             }
         },
         "terser-webpack-plugin": {
-            "version": "1.4.3",
-            "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
-            "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
+            "version": "1.4.5",
+            "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz",
+            "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==",
             "dev": true,
             "requires": {
                 "cacache": "^12.0.2",
                 "find-cache-dir": "^2.1.0",
                 "is-wsl": "^1.1.0",
                 "schema-utils": "^1.0.0",
-                "serialize-javascript": "^2.1.2",
+                "serialize-javascript": "^4.0.0",
                 "source-map": "^0.6.1",
                 "terser": "^4.1.2",
                 "webpack-sources": "^1.4.0",
@@ -16962,23 +17080,15 @@
                         "glob": "^7.1.3"
                     }
                 },
-                "schema-utils": {
-                    "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
-                    "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+                "serialize-javascript": {
+                    "version": "4.0.0",
+                    "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
+                    "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
                     "dev": true,
                     "requires": {
-                        "ajv": "^6.1.0",
-                        "ajv-errors": "^1.0.0",
-                        "ajv-keywords": "^3.1.0"
+                        "randombytes": "^2.1.0"
                     }
                 },
-                "serialize-javascript": {
-                    "version": "2.1.2",
-                    "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
-                    "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
-                    "dev": true
-                },
                 "source-map": {
                     "version": "0.6.1",
                     "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -16986,9 +17096,9 @@
                     "dev": true
                 },
                 "ssri": {
-                    "version": "6.0.1",
-                    "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
-                    "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
+                    "version": "6.0.2",
+                    "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
+                    "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
                     "dev": true,
                     "requires": {
                         "figgy-pudding": "^3.5.1"
@@ -17050,19 +17160,14 @@
             "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8="
         },
         "timers-browserify": {
-            "version": "2.0.11",
-            "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz",
-            "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==",
+            "version": "2.0.12",
+            "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
+            "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
             "dev": true,
             "requires": {
                 "setimmediate": "^1.0.4"
             }
         },
-        "tiny-emitter": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
-            "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
-        },
         "tiny-inflate": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
@@ -17578,9 +17683,9 @@
             "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
         },
         "typescript": {
-            "version": "3.9.5",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz",
-            "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==",
+            "version": "3.9.9",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
+            "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
             "dev": true
         },
         "typescript-collections": {
@@ -18170,14 +18275,136 @@
             }
         },
         "watchpack": {
-            "version": "1.6.1",
-            "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz",
-            "integrity": "sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA==",
+            "version": "1.7.5",
+            "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
+            "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==",
             "dev": true,
             "requires": {
-                "chokidar": "^2.1.8",
+                "chokidar": "^3.4.1",
                 "graceful-fs": "^4.1.2",
-                "neo-async": "^2.5.0"
+                "neo-async": "^2.5.0",
+                "watchpack-chokidar2": "^2.0.1"
+            },
+            "dependencies": {
+                "anymatch": {
+                    "version": "3.1.2",
+                    "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+                    "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "normalize-path": "^3.0.0",
+                        "picomatch": "^2.0.4"
+                    }
+                },
+                "binary-extensions": {
+                    "version": "2.2.0",
+                    "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+                    "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+                    "dev": true,
+                    "optional": true
+                },
+                "braces": {
+                    "version": "3.0.2",
+                    "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+                    "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "fill-range": "^7.0.1"
+                    }
+                },
+                "chokidar": {
+                    "version": "3.5.1",
+                    "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
+                    "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "anymatch": "~3.1.1",
+                        "braces": "~3.0.2",
+                        "fsevents": "~2.3.1",
+                        "glob-parent": "~5.1.0",
+                        "is-binary-path": "~2.1.0",
+                        "is-glob": "~4.0.1",
+                        "normalize-path": "~3.0.0",
+                        "readdirp": "~3.5.0"
+                    }
+                },
+                "fill-range": {
+                    "version": "7.0.1",
+                    "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+                    "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "to-regex-range": "^5.0.1"
+                    }
+                },
+                "fsevents": {
+                    "version": "2.3.2",
+                    "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+                    "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+                    "dev": true,
+                    "optional": true
+                },
+                "glob-parent": {
+                    "version": "5.1.2",
+                    "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+                    "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "is-glob": "^4.0.1"
+                    }
+                },
+                "is-binary-path": {
+                    "version": "2.1.0",
+                    "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+                    "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "binary-extensions": "^2.0.0"
+                    }
+                },
+                "is-number": {
+                    "version": "7.0.0",
+                    "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+                    "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+                    "dev": true,
+                    "optional": true
+                },
+                "readdirp": {
+                    "version": "3.5.0",
+                    "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
+                    "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "picomatch": "^2.2.1"
+                    }
+                },
+                "to-regex-range": {
+                    "version": "5.0.1",
+                    "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+                    "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "is-number": "^7.0.0"
+                    }
+                }
+            }
+        },
+        "watchpack-chokidar2": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz",
+            "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==",
+            "dev": true,
+            "optional": true,
+            "requires": {
+                "chokidar": "^2.1.8"
             }
         },
         "wbuf": {
@@ -18204,9 +18431,9 @@
             "dev": true
         },
         "webpack": {
-            "version": "4.43.0",
-            "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.43.0.tgz",
-            "integrity": "sha512-GW1LjnPipFW2Y78OOab8NJlCflB7EFskMih2AHdvjbpKMeDJqEgSx24cXXXiPS65+WSwVyxtDsJH6jGX2czy+g==",
+            "version": "4.46.0",
+            "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz",
+            "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==",
             "dev": true,
             "requires": {
                 "@webassemblyjs/ast": "1.9.0",
@@ -18217,7 +18444,7 @@
                 "ajv": "^6.10.2",
                 "ajv-keywords": "^3.4.1",
                 "chrome-trace-event": "^1.0.2",
-                "enhanced-resolve": "^4.1.0",
+                "enhanced-resolve": "^4.5.0",
                 "eslint-scope": "^4.0.3",
                 "json-parse-better-errors": "^1.0.2",
                 "loader-runner": "^2.4.0",
@@ -18230,16 +18457,39 @@
                 "schema-utils": "^1.0.0",
                 "tapable": "^1.1.3",
                 "terser-webpack-plugin": "^1.4.3",
-                "watchpack": "^1.6.1",
+                "watchpack": "^1.7.4",
                 "webpack-sources": "^1.4.1"
             },
             "dependencies": {
                 "acorn": {
-                    "version": "6.4.1",
-                    "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
-                    "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
+                    "version": "6.4.2",
+                    "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
+                    "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
                     "dev": true
                 },
+                "enhanced-resolve": {
+                    "version": "4.5.0",
+                    "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
+                    "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
+                    "dev": true,
+                    "requires": {
+                        "graceful-fs": "^4.1.2",
+                        "memory-fs": "^0.5.0",
+                        "tapable": "^1.0.0"
+                    },
+                    "dependencies": {
+                        "memory-fs": {
+                            "version": "0.5.0",
+                            "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
+                            "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
+                            "dev": true,
+                            "requires": {
+                                "errno": "^0.1.3",
+                                "readable-stream": "^2.0.1"
+                            }
+                        }
+                    }
+                },
                 "memory-fs": {
                     "version": "0.4.1",
                     "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
@@ -18264,17 +18514,6 @@
                         "string_decoder": "~1.1.1",
                         "util-deprecate": "~1.0.1"
                     }
-                },
-                "schema-utils": {
-                    "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
-                    "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
-                    "dev": true,
-                    "requires": {
-                        "ajv": "^6.1.0",
-                        "ajv-errors": "^1.0.0",
-                        "ajv-keywords": "^3.1.0"
-                    }
                 }
             }
         },
@@ -18328,9 +18567,9 @@
             }
         },
         "webpack-dev-middleware": {
-            "version": "3.7.2",
-            "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz",
-            "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==",
+            "version": "3.7.3",
+            "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz",
+            "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==",
             "dev": true,
             "requires": {
                 "memory-fs": "^0.4.1",
@@ -18351,9 +18590,9 @@
                     }
                 },
                 "mime": {
-                    "version": "2.4.4",
-                    "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
-                    "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==",
+                    "version": "2.5.2",
+                    "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
+                    "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==",
                     "dev": true
                 },
                 "readable-stream": {
@@ -18925,6 +19164,11 @@
                 "compress-commons": "^2.1.1",
                 "readable-stream": "^3.4.0"
             }
+        },
+        "zustand": {
+            "version": "3.4.1",
+            "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.4.1.tgz",
+            "integrity": "sha512-Kb91vSjy5vwBQ/PQ1a5GE6naS3gCxCgpkujT9zqZSO85+gnvmzgqraMW3ao1I0jR4PwHBXtLTf26r9j7EXoUiQ=="
         }
     }
 }
diff --git a/package.json b/package.json
index 8853714f1..6cbde9e1f 100644
--- a/package.json
+++ b/package.json
@@ -85,9 +85,9 @@
         "@types/typescript": "^2.0.0",
         "@types/uuid": "^3.4.6",
         "@types/valid-url": "^1.0.3",
-        "@types/webpack": "^4.41.18",
-        "@types/webpack-dev-middleware": "^2.0.5",
-        "@types/webpack-hot-middleware": "^2.25.3",
+        "@types/webpack": "^4.41.27",
+        "@types/webpack-dev-middleware": "^2.0.7",
+        "@types/webpack-hot-middleware": "^2.25.4",
         "@types/xregexp": "^4.3.0",
         "@types/youtube": "0.0.39",
         "awesome-typescript-loader": "^5.2.1",
@@ -108,10 +108,10 @@
         "ts-node-dev": "^1.0.0-pre.49",
         "tslint": "^5.20.1",
         "tslint-loader": "^3.6.0",
-        "typescript": "^3.9.5",
-        "webpack": "^4.41.5",
+        "typescript": "^3.9.9",
+        "webpack": "^4.46.0",
         "webpack-cli": "^3.3.12",
-        "webpack-dev-middleware": "^3.7.2",
+        "webpack-dev-middleware": "^3.7.3",
         "webpack-dev-server": "^3.11.0",
         "webpack-hot-middleware": "^2.24.3"
     },
@@ -125,8 +125,14 @@
         "@hig/theme-context": "^2.1.3",
         "@hig/theme-data": "^2.16.1",
         "@material-ui/core": "^4.11.0",
+        "@react-three/fiber": "^6.0.16",
         "@types/cors": "^2.8.8",
+        "@types/d3-axis": "^2.0.0",
+        "@types/d3-color": "^2.0.1",
+        "@types/d3-scale": "^3.2.2",
+        "@types/d3-selection": "^2.0.0",
         "@types/google-maps": "^3.2.2",
+        "@types/react-reconciler": "^0.26.1",
         "@types/reveal": "^3.3.33",
         "@types/three": "^0.126.2",
         "@types/webscopeio__react-textarea-autocomplete": "^4.6.1",
@@ -241,7 +247,6 @@
         "react-reveal": "^1.2.2",
         "react-select": "^3.1.0",
         "react-table": "^6.11.5",
-        "react-three-fiber": "^5.3.22",
         "readline": "^1.3.0",
         "request": "^2.88.0",
         "request-promise": "^4.2.5",
diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx
index c38337c91..c247afa26 100644
--- a/src/client/util/CaptureManager.tsx
+++ b/src/client/util/CaptureManager.tsx
@@ -99,7 +99,7 @@ export class CaptureManager extends React.Component<{}> {
                     Cancel
                 </div>
             </div>
-        </div>
+        </div>;
     }
 
 
@@ -135,6 +135,6 @@ export class CaptureManager extends React.Component<{}> {
             dialogueBoxStyle={{ width: "500px", height: "350px", border: "none", background: "whitesmoke" }}
             overlayStyle={{ background: "black" }}
             overlayDisplayedOpacity={0.6}
-        />
+        />;
     }
 }
\ No newline at end of file
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index cb0a4bea0..c3c3083be 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -1,5 +1,6 @@
 import * as ts from "typescript";
 export { ts };
+
 // export const ts = (window as any).ts;
 
 // // @ts-ignore
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 8c4bdcc41..d2074d653 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -67,7 +67,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
 
         AnchorMenu.Instance.OnClick = (e: PointerEvent) => {
             this.props.anchorMenuClick?.()?.(this.highlight("rgba(173, 216, 230, 0.75)", true));
-        }
+        };
         AnchorMenu.Instance.Highlight = this.highlight;
         /**
          * This function is used by the AnchorMenu to create an anchor highlight and a new linked text annotation.  
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index bb0ad4c66..d09d949ff 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -328,7 +328,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
      */
     @undoBatch
     changePermissions = (e: any, user: string) => {
-        const docs = SelectionManager.Views().length < 2 ? [this.selectedDoc!] : SelectionManager.Views().map(docView => docView.props.Document);
+        const docs = SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(docView => docView.props.Document);
         SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs);
     }
 
@@ -409,7 +409,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
         // all selected docs
         const docs = SelectionManager.Views().length < 2 ?
-            [this.layoutDocAcls ? this.selectedDoc! : this.selectedDoc![DataSym]]
+            [this.layoutDocAcls ? this.selectedDoc : this.selectedDoc[DataSym]]
             : SelectionManager.Views().map(docView => this.layoutDocAcls ? docView.props.Document : docView.props.Document[DataSym]);
 
         const target = docs[0];
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 96f9eab97..0fca61913 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -81,7 +81,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
     const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
     const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity);
     const showTitle = () => props?.styleProvider?.(doc, props, StyleProp.ShowTitle);
-    const random = (min: number, max: number, x: number, y: number) => { /* min should not be equal to max */ return min + ((Math.abs(x * y) * 9301 + 49297) % 233280 / 233280) * (max - min); }
+    const random = (min: number, max: number, x: number, y: number) => /* min should not be equal to max */ min + ((Math.abs(x * y) * 9301 + 49297) % 233280 / 233280) * (max - min);
     switch (property.split(":")[0]) {
         case StyleProp.TreeViewIcon: return Doc.toIcon(doc, isOpen);
         case StyleProp.DocContents: return undefined;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index ab4f197a6..08290a9b3 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -535,7 +535,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                     <FontAwesomeIcon icon={["fab", "buffer"]} size={"lg"} />
                 </button>
             </Tooltip>
-        </>
+        </>;
     }
 
     render() {
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index b53827371..f0a54e4ac 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -1,46 +1,45 @@
 import { computed } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, Opt, Field, AclPrivate } from "../../../fields/Doc";
-import { Cast, StrCast, NumCast } from "../../../fields/Types";
-import { OmitKeys, Without, emptyPath } from "../../../Utils";
+import { AclPrivate, Doc, Opt } from "../../../fields/Doc";
+import { ScriptField } from "../../../fields/ScriptField";
+import { Cast, StrCast } from "../../../fields/Types";
+import { GetEffectiveAcl, TraceMobx } from "../../../fields/util";
+import { emptyPath, OmitKeys, Without } from "../../../Utils";
 import { DirectoryImportBox } from "../../util/Import & Export/DirectoryImportBox";
 import { CollectionDockingView } from "../collections/CollectionDockingView";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
 import { CollectionSchemaView } from "../collections/CollectionSchemaView";
 import { CollectionView } from "../collections/CollectionView";
+import { InkingStroke } from "../InkingStroke";
+import { PresElementBox } from "../presentationview/PresElementBox";
+import { SearchBox } from "../search/SearchBox";
+import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo";
 import { YoutubeBox } from "./../../apis/youtube/YoutubeBox";
 import { AudioBox } from "./AudioBox";
-import { LabelBox } from "./LabelBox";
-import { EquationBox } from "./EquationBox";
-import { FunctionPlotBox } from "./FunctionPlotBox";
-import { SliderBox } from "./SliderBox";
-import { LinkBox } from "./LinkBox";
-import { ScriptingBox } from "./ScriptingBox";
+import { ColorBox } from "./ColorBox";
+import { ComparisonBox } from "./ComparisonBox";
 import { DocumentViewProps } from "./DocumentView";
 import "./DocumentView.scss";
-import { FontIconBox } from "./FontIconBox";
+import { EquationBox } from "./EquationBox";
 import { FieldView, FieldViewProps } from "./FieldView";
+import { FilterBox } from "./FilterBox";
+import { FontIconBox } from "./FontIconBox";
 import { FormattedTextBox, FormattedTextBoxProps } from "./formattedText/FormattedTextBox";
+import { FunctionPlotBox } from "./FunctionPlotBox";
 import { ImageBox } from "./ImageBox";
 import { KeyValueBox } from "./KeyValueBox";
+import { LabelBox } from "./LabelBox";
+import { LinkAnchorBox } from "./LinkAnchorBox";
+import { LinkBox } from "./LinkBox";
 import { PDFBox } from "./PDFBox";
 import { PresBox } from "./PresBox";
-import { SearchBox } from "../search/SearchBox";
-import { FilterBox } from "./FilterBox";
-import { ColorBox } from "./ColorBox";
-import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo";
-import { LinkAnchorBox } from "./LinkAnchorBox";
-import { PresElementBox } from "../presentationview/PresElementBox";
 import { ScreenshotBox } from "./ScreenshotBox";
-import { ComparisonBox } from "./ComparisonBox";
+import { ScriptingBox } from "./ScriptingBox";
+import { SliderBox } from "./SliderBox";
 import { VideoBox } from "./VideoBox";
 import { WebBox } from "./WebBox";
-import { InkingStroke } from "../InkingStroke";
 import React = require("react");
-import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
-import { ScriptField } from "../../../fields/ScriptField";
 import XRegExp = require("xregexp");
-import { DocumentType } from "../../documents/DocumentTypes";
 
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
@@ -226,7 +225,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
                     CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
                     PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, SearchBox, FilterBox, FunctionPlotBox,
                     ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, LinkBox, ScriptingBox,
-                    ScreenshotBox, HTMLtag, ComparisonBox
+                    ScreenshotBox,
+                    HTMLtag, ComparisonBox
                 }}
                 bindings={bindings}
                 jsx={layoutFrame}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index c7067f313..e2e08a0e6 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -29,8 +29,6 @@ import React = require("react");
 const path = require('path');
 
 export const pageSchema = createSchema({
-    _curPage: "number",
-    fitWidth: "boolean",
     googlePhotosUrl: "string",
     googlePhotosTags: "string"
 });
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 753483772..252c029e4 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -1,9 +1,11 @@
 import React = require("react");
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+// import { Canvas } from '@react-three/fiber';
 import { action, computed, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
+// import { BufferAttribute, Camera, Vector2, Vector3 } from 'three';
 import { DateField } from "../../../fields/DateField";
-import { Doc, WidthSym, HeightSym } from "../../../fields/Doc";
+import { Doc, WidthSym } from "../../../fields/Doc";
 import { documentSchema } from "../../../fields/documentSchemas";
 import { Id } from "../../../fields/FieldSymbols";
 import { InkTool } from "../../../fields/InkField";
@@ -11,7 +13,8 @@ import { makeInterface } from "../../../fields/Schema";
 import { ComputedField } from "../../../fields/ScriptField";
 import { Cast, NumCast } from "../../../fields/Types";
 import { AudioField, VideoField } from "../../../fields/URLField";
-import { emptyFunction, OmitKeys, returnFalse, returnOne, Utils, numberRange } from "../../../Utils";
+import { TraceMobx } from "../../../fields/util";
+import { emptyFunction, numberRange, OmitKeys, returnFalse, returnOne, Utils } from "../../../Utils";
 import { DocUtils } from "../../documents/Documents";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { Networking } from "../../Network";
@@ -25,10 +28,6 @@ import { FieldView, FieldViewProps } from './FieldView';
 import { FormattedTextBox } from "./formattedText/FormattedTextBox";
 import "./ScreenshotBox.scss";
 import { VideoBox } from "./VideoBox";
-import { TraceMobx } from "../../../fields/util";
-import { Canvas } from 'react-three-fiber';
-import * as THREE from 'three';
-import { Vector3, Vector2, Camera } from "three"
 declare class MediaRecorder {
     constructor(e: any, options?: any);  // whatever MediaRecorder has
 }
@@ -36,81 +35,81 @@ declare class MediaRecorder {
 type ScreenshotDocument = makeInterface<[typeof documentSchema]>;
 const ScreenshotDocument = makeInterface(documentSchema);
 
-interface VideoTileProps {
-    raised: { coord: Vector2, off: Vector3 }[];
-    setRaised: (r: { coord: Vector2, off: Vector3 }[]) => void;
-    x: number;
-    y: number;
-    rootDoc: Doc;
-    color: string;
-}
+// interface VideoTileProps {
+//     raised: { coord: Vector2, off: Vector3 }[];
+//     setRaised: (r: { coord: Vector2, off: Vector3 }[]) => void;
+//     x: number;
+//     y: number;
+//     rootDoc: Doc;
+//     color: string;
+// }
 
-@observer
-export class VideoTile extends React.Component<VideoTileProps> {
-    @observable _videoRef: HTMLVideoElement | undefined;
-    _mesh: any = undefined;
+// @observer
+// export class VideoTile extends React.Component<VideoTileProps> {
+//     @observable _videoRef: HTMLVideoElement | undefined;
+//     _mesh: any = undefined;
 
-    render() {
-        const topLeft = [this.props.x, this.props.y];
-        const raised = this.props.raised;
-        const find = (raised: { coord: Vector2, off: Vector3 }[], what: Vector2) => raised.find(r => r.coord.x === what.x && r.coord.y === what.y);
-        const tl1 = find(raised, new Vector2(topLeft[0], topLeft[1] + 1));
-        const tl2 = find(raised, new Vector2(topLeft[0] + 1, topLeft[1] + 1));
-        const tl3 = find(raised, new Vector2(topLeft[0] + 1, topLeft[1]));
-        const tl4 = find(raised, new Vector2(topLeft[0], topLeft[1]));
-        const quad_indices = [0, 2, 1, 0, 3, 2];
-        const quad_uvs = [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0];
-        const quad_normals = [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,];
-        const quad_vertices =
-            [
-                topLeft[0] - 0.0 + (tl1?.off.x || 0), topLeft[1] + 1.0 + (tl1?.off.y || 0), 0.0 + (tl1?.off.z || 0),
-                topLeft[0] + 1.0 + (tl2?.off.x || 0), topLeft[1] + 1.0 + (tl2?.off.y || 0), 0.0 + (tl2?.off.z || 0),
-                topLeft[0] + 1.0 + (tl3?.off.x || 0), topLeft[1] - 0.0 + (tl3?.off.y || 0), 0.0 + (tl3?.off.z || 0),
-                topLeft[0] - 0.0 + (tl4?.off.x || 0), topLeft[1] - 0.0 + (tl4?.off.y || 0), 0.0 + (tl4?.off.z || 0)
-            ];
+//     render() {
+//         const topLeft = [this.props.x, this.props.y];
+//         const raised = this.props.raised;
+//         const find = (raised: { coord: Vector2, off: Vector3 }[], what: Vector2) => raised.find(r => r.coord.x === what.x && r.coord.y === what.y);
+//         const tl1 = find(raised, new Vector2(topLeft[0], topLeft[1] + 1));
+//         const tl2 = find(raised, new Vector2(topLeft[0] + 1, topLeft[1] + 1));
+//         const tl3 = find(raised, new Vector2(topLeft[0] + 1, topLeft[1]));
+//         const tl4 = find(raised, new Vector2(topLeft[0], topLeft[1]));
+//         const quad_indices = [0, 2, 1, 0, 3, 2];
+//         const quad_uvs = [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0];
+//         const quad_normals = [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,];
+//         const quad_vertices =
+//             [
+//                 topLeft[0] - 0.0 + (tl1?.off.x || 0), topLeft[1] + 1.0 + (tl1?.off.y || 0), 0.0 + (tl1?.off.z || 0),
+//                 topLeft[0] + 1.0 + (tl2?.off.x || 0), topLeft[1] + 1.0 + (tl2?.off.y || 0), 0.0 + (tl2?.off.z || 0),
+//                 topLeft[0] + 1.0 + (tl3?.off.x || 0), topLeft[1] - 0.0 + (tl3?.off.y || 0), 0.0 + (tl3?.off.z || 0),
+//                 topLeft[0] - 0.0 + (tl4?.off.x || 0), topLeft[1] - 0.0 + (tl4?.off.y || 0), 0.0 + (tl4?.off.z || 0)
+//             ];
 
-        const vertices = new Float32Array(quad_vertices);
-        const normals = new Float32Array(quad_normals);
-        const uvs = new Float32Array(quad_uvs); // Each vertex has one uv coordinate for texture mapping
-        const indices = new Uint32Array(quad_indices);          // Use the four vertices to draw the two triangles that make up the square.
-        const popOut = () => NumCast(this.props.rootDoc.popOut);
-        const popOff = () => NumCast(this.props.rootDoc.popOff);
-        return (
-            <mesh key={`mesh${topLeft[0]}${topLeft[1]}`} onClick={action(async e => {
-                this.props.setRaised([
-                    { coord: new Vector2(topLeft[0], topLeft[1]), off: new Vector3(-popOff(), -popOff(), popOut()) },
-                    { coord: new Vector2(topLeft[0] + 1, topLeft[1]), off: new Vector3(popOff(), -popOff(), popOut()) },
-                    { coord: new Vector2(topLeft[0], topLeft[1] + 1), off: new Vector3(-popOff(), popOff(), popOut()) },
-                    { coord: new Vector2(topLeft[0] + 1, topLeft[1] + 1), off: new Vector3(popOff(), popOff(), popOut()) }
-                ]);
-                if (!this._videoRef) {
-                    (navigator.mediaDevices as any).getDisplayMedia({ video: true }).then(action((stream: any) => {
-                        //const videoSettings = stream.getVideoTracks()[0].getSettings();
-                        this._videoRef = document.createElement("video");
-                        Object.assign(this._videoRef, {
-                            srcObject: stream,
-                            //height: videoSettings.height,
-                            //width: videoSettings.width,
-                            autoplay: true
-                        });
-                    }));
-                }
-            })} ref={(r: any) => this._mesh = r}>
-                <bufferGeometry attach="geometry" ref={(r: any) => {
-                    // itemSize = 3 because there are 3 values (components) per vertex
-                    r?.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
-                    r?.setAttribute('normal', new THREE.BufferAttribute(normals, 3));
-                    r?.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));
-                    r?.setIndex(new THREE.BufferAttribute(indices, 1));
-                }} />
-                {!this._videoRef ? <meshStandardMaterial color={this.props.color} /> :
-                    <meshBasicMaterial >
-                        <videoTexture attach="map" args={[this._videoRef]} />
-                    </meshBasicMaterial>}
-            </mesh>
-        )
-    };
-}
+//         const vertices = new Float32Array(quad_vertices);
+//         const normals = new Float32Array(quad_normals);
+//         const uvs = new Float32Array(quad_uvs); // Each vertex has one uv coordinate for texture mapping
+//         const indices = new Uint32Array(quad_indices);          // Use the four vertices to draw the two triangles that make up the square.
+//         const popOut = () => NumCast(this.props.rootDoc.popOut);
+//         const popOff = () => NumCast(this.props.rootDoc.popOff);
+//         return (
+//             <mesh key={`mesh${topLeft[0]}${topLeft[1]}`} onClick={action(async e => {
+//                 this.props.setRaised([
+//                     { coord: new Vector2(topLeft[0], topLeft[1]), off: new Vector3(-popOff(), -popOff(), popOut()) },
+//                     { coord: new Vector2(topLeft[0] + 1, topLeft[1]), off: new Vector3(popOff(), -popOff(), popOut()) },
+//                     { coord: new Vector2(topLeft[0], topLeft[1] + 1), off: new Vector3(-popOff(), popOff(), popOut()) },
+//                     { coord: new Vector2(topLeft[0] + 1, topLeft[1] + 1), off: new Vector3(popOff(), popOff(), popOut()) }
+//                 ]);
+//                 if (!this._videoRef) {
+//                     (navigator.mediaDevices as any).getDisplayMedia({ video: true }).then(action((stream: any) => {
+//                         //const videoSettings = stream.getVideoTracks()[0].getSettings();
+//                         this._videoRef = document.createElement("video");
+//                         Object.assign(this._videoRef, {
+//                             srcObject: stream,
+//                             //height: videoSettings.height,
+//                             //width: videoSettings.width,
+//                             autoplay: true
+//                         });
+//                     }));
+//                 }
+//             })} ref={(r: any) => this._mesh = r}>
+//                 <bufferGeometry attach="geometry" ref={(r: any) => {
+//                     // itemSize = 3 because there are 3 values (components) per vertex
+//                     r?.setAttribute('position', new BufferAttribute(vertices, 3));
+//                     r?.setAttribute('normal', new BufferAttribute(normals, 3));
+//                     r?.setAttribute('uv', new BufferAttribute(uvs, 2));
+//                     r?.setIndex(new BufferAttribute(indices, 1));
+//                 }} />
+//                 {!this._videoRef ? <meshStandardMaterial color={this.props.color} /> :
+//                     <meshBasicMaterial >
+//                         <videoTexture attach="map" args={[this._videoRef]} />
+//                     </meshBasicMaterial>}
+//             </mesh>
+//         );
+//     }
+// }
 
 @observer
 export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ScreenshotDocument>(ScreenshotDocument) {
@@ -153,16 +152,16 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
     componentDidMount() {
         this.dataDoc.nativeWidth = this.dataDoc.nativeHeight = 0;
         this.props.setContentView?.(this); // this tells the DocumentView that this ScreenshotBox is the "content" of the document.  this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
-        this.rootDoc.videoWall && reaction(() => ({ width: this.props.PanelWidth(), height: this.props.PanelHeight() }),
-            ({ width, height }) => {
-                if (this._camera) {
-                    const angle = -Math.abs(1 - width / height);
-                    const xz = [0, (this._numScreens - 2) / Math.abs(1 + angle)];
-                    this._camera.position.set(this._numScreens / 2 + xz[1] * Math.sin(angle), this._numScreens / 2, xz[1] * Math.cos(angle));
-                    this._camera.lookAt(this._numScreens / 2, this._numScreens / 2, 0);
-                    (this._camera as any).updateProjectionMatrix();
-                }
-            });
+        // this.rootDoc.videoWall && reaction(() => ({ width: this.props.PanelWidth(), height: this.props.PanelHeight() }),
+        //     ({ width, height }) => {
+        //         if (this._camera) {
+        //             const angle = -Math.abs(1 - width / height);
+        //             const xz = [0, (this._numScreens - 2) / Math.abs(1 + angle)];
+        //             this._camera.position.set(this._numScreens / 2 + xz[1] * Math.sin(angle), this._numScreens / 2, xz[1] * Math.cos(angle));
+        //             this._camera.lookAt(this._numScreens / 2, this._numScreens / 2, 0);
+        //             (this._camera as any).updateProjectionMatrix();
+        //         }
+        //     });
     }
     componentWillUnmount() {
         const ind = DocUtils.ActiveRecordings.indexOf(this);
@@ -196,27 +195,29 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         </video>;
     }
 
-    _numScreens = 5;
-    _camera: Camera | undefined;
-    @observable _raised = [] as { coord: Vector2, off: Vector3 }[];
-    @action setRaised = (r: { coord: Vector2, off: Vector3 }[]) => this._raised = r;
+    // _numScreens = 5;
+    // _camera: Camera | undefined;
+    // @observable _raised = [] as { coord: Vector2, off: Vector3 }[];
+    // @action setRaised = (r: { coord: Vector2, off: Vector3 }[]) => this._raised = r;
     @computed get threed() {
-        if (!this.rootDoc.videoWall) return (null);
-        const screens: any[] = [];
-        const colors = ["yellow", "red", "orange", "brown", "maroon", "gray"];
-        let count = 0;
-        numberRange(this._numScreens).forEach(x => numberRange(this._numScreens).forEach(y => screens.push(
-            <VideoTile rootDoc={this.rootDoc} color={colors[count++ % colors.length]} x={x} y={y} raised={this._raised} setRaised={this.setRaised} />)));
-        return <Canvas key="canvas" id="CANCAN" style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }} gl={{ antialias: false }} colorManagement={false} onCreated={props => {
-            this._camera = props.camera;
-            props.camera.position.set(this._numScreens / 2, this._numScreens / 2, this._numScreens - 2);
-            props.camera.lookAt(this._numScreens / 2, this._numScreens / 2, 0);
-        }}>
-            {/* <ambientLight />*/}
-            <pointLight position={[10, 10, 10]} intensity={1} />
-            {screens}
-        </ Canvas>
-    };
+        // if (this.rootDoc.videoWall) {
+        //     const screens: any[] = [];
+        //     const colors = ["yellow", "red", "orange", "brown", "maroon", "gray"];
+        //     let count = 0;
+        //     numberRange(this._numScreens).forEach(x => numberRange(this._numScreens).forEach(y => screens.push(
+        //         <VideoTile rootDoc={this.rootDoc} color={colors[count++ % colors.length]} x={x} y={y} raised={this._raised} setRaised={this.setRaised} />)));
+        //     return <Canvas key="canvas" id="CANCAN" style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }} gl={{ antialias: false }} colorManagement={false} onCreated={props => {
+        //         this._camera = props.camera;
+        //         props.camera.position.set(this._numScreens / 2, this._numScreens / 2, this._numScreens - 2);
+        //         props.camera.lookAt(this._numScreens / 2, this._numScreens / 2, 0);
+        //     }}>
+        //         {/* <ambientLight />*/}
+        //         <pointLight position={[10, 10, 10]} intensity={1} />
+        //         {screens}
+        //     </ Canvas>;
+        // }
+        return (null);
+    }
     toggleRecording = action(async () => {
         this._screenCapture = !this._screenCapture;
         if (this._screenCapture) {
diff --git a/src/fields/Schema.ts b/src/fields/Schema.ts
index 78f8a6bfb..7ad376a28 100644
--- a/src/fields/Schema.ts
+++ b/src/fields/Schema.ts
@@ -21,8 +21,6 @@ export interface InterfaceFunc<T extends Interface[]> {
 }
 
 export type makeInterface<T extends Interface[]> = AllToInterface<T> & Doc & { proto: Doc | undefined };
-// export function makeInterface<T extends Interface[], U extends Doc>(schemas: T): (doc: U) => All<T, U>;
-// export function makeInterface<T extends Interface, U extends Doc>(schema: T): (doc: U) => makeInterface<T, U>; 
 export function makeInterface<T extends Interface[]>(...schemas: T): InterfaceFunc<T> {
     const schema: Interface = {};
     for (const s of schemas) {
@@ -37,18 +35,18 @@ export function makeInterface<T extends Interface[]>(...schemas: T): InterfaceFu
                 const desc = prop === "proto" ? Doc : (schema as any)[prop]; // bcz: proto doesn't appear in schemas ... maybe it should?
                 if (typeof desc === "object" && "defaultVal" in desc && "type" in desc) {//defaultSpec
                     return Cast(field, desc.type, desc.defaultVal);
-                } else if (typeof desc === "function" && !ObjectField.isPrototypeOf(desc) && !RefField.isPrototypeOf(desc)) {
+                }
+                if (typeof desc === "function" && !ObjectField.isPrototypeOf(desc) && !RefField.isPrototypeOf(desc)) {
                     const doc = Cast(field, Doc);
                     if (doc === undefined) {
                         return undefined;
-                    } else if (doc instanceof Doc) {
+                    }
+                    if (doc instanceof Doc) {
                         return desc(doc);
-                    } else {
-                        return doc.then(doc => doc && desc(doc));
                     }
-                } else {
-                    return Cast(field, desc);
+                    return doc.then(doc => doc && desc(doc));
                 }
+                return Cast(field, desc);
             }
             return field;
         },
@@ -57,21 +55,9 @@ export function makeInterface<T extends Interface[]>(...schemas: T): InterfaceFu
             return true;
         }
     });
-    const fn = (doc: Doc) => {
-        doc = doc[SelfProxy];
-        // if (!(doc instanceof Doc)) {
-        //     throw new Error("Currently wrapping a schema in another schema isn't supported");
-        // }
-        const obj = Object.create(proto, { doc: { value: doc, writable: false } });
-        return obj;
-    };
-    return function (doc?: Doc | Doc[]) {
-        if (doc instanceof Doc || doc === undefined) {
-            return fn(doc || new Doc);
-        } else if (doc instanceof List) {
-            return doc.map(fn);
-        } else return {};
-    };
+    // !(doc instanceof Doc) && (throw new Error("Currently wrapping a schema in another schema isn't supported"));
+    const fn = (doc: Doc) => Object.create(proto, { doc: { value: doc[SelfProxy], writable: false } });
+    return ((doc?: Doc | Doc[]) => (doc instanceof List ? doc : undefined)?.map?.(fn) ?? fn((doc as Doc) ?? new Doc)) as InterfaceFunc<T>;
 }
 
 export type makeStrictInterface<T extends Interface> = Partial<ToInterface<T>>;
diff --git a/webpack.config.js b/webpack.config.js
index 30967d618..56bd428e4 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -106,7 +106,9 @@ module.exports = {
                 }
             }]
         }
-        ]
+        ],
+
+        noParse: [require.resolve('typescript/lib/typescript.js')],
     },
     plugins,
     externals: [
-- 
cgit v1.2.3-70-g09d2


From 82b9c13e3fdcf883ce97a66e24ca1dbc80e6739a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 29 Apr 2021 11:38:31 -0400
Subject: fixed up some caption things with carousel and other views.  made
 caption fontsizes increase with zoom level.

---
 src/client/views/StyleProvider.tsx                     |  7 +++++--
 .../views/collections/CollectionCarousel3DView.tsx     |  7 +++----
 .../views/collections/CollectionCarouselView.tsx       | 18 ++++++++++--------
 src/client/views/collections/CollectionMenu.tsx        |  5 ++---
 src/client/views/nodes/DocumentView.tsx                | 16 +++++++---------
 .../views/nodes/formattedText/FormattedTextBox.tsx     |  6 ++++--
 6 files changed, 31 insertions(+), 28 deletions(-)

(limited to 'src/client/views/collections/CollectionMenu.tsx')

diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 0fca61913..8cb8fea11 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -43,6 +43,7 @@ export enum StyleProp {
     ShowTitle = "showTitle",              // whether to display a title on a Document (optional :hover suffix)
     JitterRotation = "jitterRotation",    // whether documents should be randomly rotated
     BorderPath = "customBorder",          // border path for document view
+    FontSize = "fontSize",                // size of text font
 }
 
 function darkScheme() { return BoolCast(CurrentUserUtils.ActiveDashboard?.darkScheme); }
@@ -70,12 +71,12 @@ export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) {
 // 
 export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any {
     const docProps = testDocProps(props) ? props : undefined;
-    const fieldKey = (props as any)?.fieldKey ? (props as any).fieldKey + "-" : "";
     const selected = property.includes(":selected");
     const isCaption = property.includes(":caption");
     const isAnchor = property.includes(":anchor");
     const isAnnotated = property.includes(":annotated");
     const isOpen = property.includes(":open");
+    const fieldKey = (props as any)?.fieldKey ? (props as any).fieldKey + "-" : isCaption ? "caption-" : "";
     const comicStyle = () => doc && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === "comic";
     const isBackground = () => StrListCast(doc?._layerTags).includes(StyleLayers.Background);
     const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
@@ -88,6 +89,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         case StyleProp.WidgetColor: return isAnnotated ? "lightBlue" : darkScheme() ? "lightgrey" : "dimgrey";
         case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null));
         case StyleProp.HideLinkButton: return props?.hideLinkButton || (!selected && (doc?.isLinkButton || doc?.hideLinkButton));
+        case StyleProp.FontSize: return StrCast(doc?.[fieldKey + "fontSize"]);
         case StyleProp.ShowTitle: return doc && !doc.presentationTargetDoc && StrCast(doc._showTitle,
             !Doc.IsSystem(doc) && doc.type === DocumentType.RTF ?
                 (doc.author === Doc.CurrentUserEmail ? StrCast(Doc.UserDoc().showTitle) : "author;creationDate") : "") || "";
@@ -102,7 +104,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             if (colsum / col.alpha() > 400 || col.alpha() < 0.25) return "black";
             return "white";
         case StyleProp.Hidden: return BoolCast(doc?._hidden);
-        case StyleProp.BorderRounding: return StrCast(doc?.[fieldKey + "borderRounding"], StrCast(doc?._borderRounding));
+        case StyleProp.BorderRounding: return StrCast(doc?.[fieldKey + "borderRounding"]);
         case StyleProp.TitleHeight: return 15;
         case StyleProp.BorderPath: return comicStyle() && props?.renderDepth ? { path: wavyBorderPath(props?.PanelWidth?.() || 0, props?.PanelHeight?.() || 0), fill: wavyBorderPath(props?.PanelWidth?.() || 0, props?.PanelHeight?.() || 0, .08), width: 3 } : { path: undefined, width: 0 };
         case StyleProp.JitterRotation: return comicStyle() ? random(-1, 1, NumCast(doc?.x), NumCast(doc?.y)) * ((props?.PanelWidth() || 0) > (props?.PanelHeight() || 0) ? 5 : 10) : 0;
@@ -124,6 +126,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 case DocumentType.BUTTON: docColor = docColor || (darkScheme() ? "#2d2d2d" : "lightgray"); break;
                 case DocumentType.LINKANCHOR: docColor = isAnchor ? "lightblue" : "transparent"; break;
                 case DocumentType.LINK: docColor = docColor || "transparent"; break;
+                case DocumentType.IMG:
                 case DocumentType.WEB:
                 case DocumentType.PDF:
                 case DocumentType.SCREENSHOT:
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 2251b60e5..3c66faf0c 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -133,10 +133,9 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
     }
 
     @computed get dots() {
-        return (this.childLayoutPairs.map((_child, index) => {
-            return <div key={Utils.GenerateGuid()} className={`dot${index === NumCast(this.layoutDoc._itemIndex) ? "-active" : ""}`}
-                onClick={() => this.layoutDoc._itemIndex = index} />;
-        }));
+        return (this.childLayoutPairs.map((_child, index) =>
+            <div key={Utils.GenerateGuid()} className={`dot${index === NumCast(this.layoutDoc._itemIndex) ? "-active" : ""}`}
+                onClick={() => this.layoutDoc._itemIndex = index} />));
     }
 
     render() {
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index cd81a99c9..6c2c27e8e 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -38,9 +38,10 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
         e.stopPropagation();
         this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length;
     }
-    captionStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
-        const captionProps = { ...this.props, fieldKey: "caption" };
-        return this.props.styleProvider?.(doc, props, property) || this.props.styleProvider?.(this.layoutDoc, captionProps, property);
+    captionStyleProvider = (doc: (Doc | undefined), captionProps: Opt<DocumentViewProps>, property: string): any => {
+        // first look for properties on the document in the carousel, then fallback to properties on the container
+        const childValue = doc?.["caption-" + property] ? this.props.styleProvider?.(doc, captionProps, property) : undefined;
+        return childValue ?? this.props.styleProvider?.(this.layoutDoc, captionProps, property);
     }
     panelHeight = () => this.props.PanelHeight() - (StrCast(this.layoutDoc._showCaption) ? 50 : 0);
     onContentDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
@@ -51,12 +52,14 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
         const captionProps = { ...this.props, fieldKey: "caption" };
         const marginX = NumCast(this.layoutDoc["caption-xMargin"]);
         const marginY = NumCast(this.layoutDoc["caption-yMargin"]);
+        const showCaptions = StrCast(this.layoutDoc._showCaption);
         return !(curDoc?.layout instanceof Doc) ? (null) :
             <>
                 <div className="collectionCarouselView-image" key="image">
                     <DocumentView  {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "childLayoutTemplate", "childLayoutString"]).omit}
                         onDoubleClick={this.onContentDoubleClick}
                         onClick={this.onContentClick}
+                        hideCaptions={showCaptions ? true : false}
                         renderDepth={this.props.renderDepth + 1}
                         ContainingCollectionView={this}
                         LayoutTemplate={this.props.childLayoutTemplate}
@@ -69,17 +72,16 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
                 </div>
                 <div className="collectionCarouselView-caption" key="caption"
                     style={{
-                        display: StrCast(this.layoutDoc._showCaption) ? undefined : "none",
+                        display: showCaptions ? undefined : "none",
                         borderRadius: this.props.styleProvider?.(this.layoutDoc, captionProps, StyleProp.BorderRounding),
                         marginRight: marginX, marginLeft: marginX,
                         width: `calc(100% - ${marginX * 2}px)`
                     }}>
                     <FormattedTextBox key={index} {...captionProps}
+                        fieldKey={showCaptions}
                         styleProvider={this.captionStyleProvider}
-                        Document={curDoc.layout} DataDoc={undefined}
-                        fontSize={NumCast(this.layoutDoc["caption-fontSize"])}
-                        xPadding={NumCast(this.layoutDoc["caption-xPadding"])}
-                        yPadding={NumCast(this.layoutDoc["caption-yPadding"])} />
+                        Document={curDoc.layout}
+                        DataDoc={undefined} />
                 </div>
             </>;
     }
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 08290a9b3..6e6fabd0d 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -763,7 +763,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     render() {
         return !this.props.docView.layoutDoc ? (null) :
             <div className="collectionFreeFormMenu-cont">
-
+                <RichTextMenu key="rich" />
                 {!this.isText ?
                     <>
                         {this.drawButtons}
@@ -789,8 +789,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
                                     </div>
                                 </Tooltip>
                             </>}
-                    </> :
-                    <RichTextMenu />
+                    </> : (null)
                 }
                 {!this.selectedDocumentView?.ComponentView?.menuControls ? (null) : this.selectedDocumentView?.ComponentView?.menuControls?.()}
             </div>;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 37394ba83..7ec9f5f74 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -121,6 +121,7 @@ export interface DocumentViewSharedProps {
     dropAction?: dropActionType;
     dontRegisterView?: boolean;
     hideLinkButton?: boolean;
+    hideCaptions?: boolean;
     ignoreAutoHeight?: boolean;
     disableDocBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
     pointerEvents?: string;
@@ -908,22 +909,19 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         TraceMobx();
         const showTitle = this.ShowTitle?.split(":")[0];
         const showTitleHover = this.ShowTitle?.includes(":hover");
-        const showCaption = StrCast(this.layoutDoc._showCaption) && this.Document._viewType !== CollectionViewType.Carousel;
+        const showCaption = !this.props.hideCaptions && this.Document._viewType !== CollectionViewType.Carousel ? StrCast(this.layoutDoc._showCaption) : undefined;
         const captionView = !showCaption ? (null) :
-            <div className="documentView-captionWrapper"
-                style={{
-                    backgroundColor: StrCast(this.layoutDoc["caption-backgroundColor"]),
-                    color: StrCast(this.layoutDoc["caption-color"])
-                }}>
-                <DocumentContentsView {...OmitKeys(this.props, ['children']).omit}
+            <div className="documentView-captionWrapper">
+                <FormattedTextBox {...OmitKeys(this.props, ['children']).omit}
                     yPadding={10}
                     xPadding={10}
+                    fieldKey={showCaption}
+                    fontSize={Math.min(32, 12 * this.props.ScreenToLocalTransform().Scale)}
                     hideOnLeave={true}
                     styleProvider={this.captionStyleProvider}
                     dontRegisterView={true}
-                    LayoutTemplateString={`<FormattedTextBox {...props} fieldKey={'${showCaption}'}/>`}
                     onClick={this.onClickFunc}
-                    layoutKey={this.finalLayoutKey} />
+                />
             </div>;
         const titleView = !showTitle ? (null) :
             <div className={`documentView-titleWrapper${showTitleHover ? "-hover" : ""}`} key="title" style={{
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index b98ec870a..2a1ff5540 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1514,6 +1514,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const selPad = Math.min(margins, 10);
         const padding = Math.max(margins + ((selected && !this.layoutDoc._singleLine) || minimal ? -selPad : 0), 0);
         const selPaddingClass = selected && !this.layoutDoc._singleLine && margins >= 10 ? "-selected" : "";
+        const col = this.props.color ? this.props.color : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color);
+        const back = this.props.background ? this.props.background : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor);
         return (
             <div className="formattedTextBox-cont"
                 onWheel={e => this.isContentActive() && e.stopPropagation()}
@@ -1531,10 +1533,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                         height: this.props.height || (this.autoHeight && this.props.renderDepth ? "max-content" : undefined),
                         background: this.props.background ? this.props.background : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
                         color: this.props.color ? this.props.color : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
-                        pointerEvents: interactive ? undefined : "none",
-                        fontSize: this.props.fontSize || Cast(this.layoutDoc._fontSize, "string", null),
+                        fontSize: this.props.fontSize ? this.props.fontSize : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontSize),
                         fontWeight: Cast(this.layoutDoc._fontWeight, "number", null),
                         fontFamily: StrCast(this.layoutDoc._fontFamily, "inherit"),
+                        pointerEvents: interactive ? undefined : "none",
                     }}
                     onContextMenu={this.specificContextMenu}
                     onKeyDown={this.onKeyDown}
-- 
cgit v1.2.3-70-g09d2

