From fb9ec75c46bc237bc6c8df24ee998e6de90168a1 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 12 Apr 2023 20:55:14 -0400
Subject: readonly fields and schema key info display

---
 src/client/views/collections/collectionSchema/SchemaRowBox.tsx | 1 +
 1 file changed, 1 insertion(+)

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

diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 2defaae00..aa8a61205 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -123,6 +123,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         <SchemaTableCell
                             key={key}
                             Document={this.rootDoc}
+                            schemaView={this.schemaView}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
                             isRowActive={this.props.isContentActive}
-- 
cgit v1.2.3-70-g09d2


From 99326044a2d81a9f0d0312b4d209946e0f119b78 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 24 Apr 2023 17:47:54 -0400
Subject: crappy version of schema image cell preview on hover

---
 .../collections/collectionSchema/SchemaRowBox.tsx  |  2 +-
 .../collectionSchema/SchemaTableCell.tsx           | 65 ++++++++++++++--------
 2 files changed, 43 insertions(+), 24 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 59b571b58..79808d8f8 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -88,7 +88,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return (
             <div
                 className="schema-row"
-                style={{ height: CollectionSchemaView._rowHeight, backgroundColor: this.props.isSelected() ? Colors.LIGHT_BLUE : undefined, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined }}
+                style={{ height: CollectionSchemaView._rowHeight, backgroundColor: this.props.isSelected() ? Colors.LIGHT_BLUE : undefined }}
                 onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 4e31b1e1e..2325339fc 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -58,7 +58,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         };
 
         return (
-            <div className="schemacell-edit-wrapper">
+            <div className="schemacell-edit-wrapper" style={{ cursor: !this.readOnly ? 'text' : 'default', pointerEvents: !this.readOnly && this.props.isRowActive() ? 'all' : 'none' }}>
                 <EditableView
                     contents={<FieldView {...props} />}
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
@@ -76,9 +76,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 
     getCellWithContent(content: any) {
         return (
-            <div
-                className="schema-table-cell"
-                style={this.props.isRowActive() && !this.readOnly ? { width: this.props.columnWidth, cursor: 'text', pointerEvents: 'auto' } : { width: this.props.columnWidth, cursor: 'default', pointerEvents: 'none' }}>
+            <div className="schema-table-cell" style={this.props.isRowActive() && !this.readOnly ? { width: this.props.columnWidth } : { width: this.props.columnWidth }}>
                 {content}
             </div>
         );
@@ -107,7 +105,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             case ColumnType.Image:
                 return <SchemaImageCell {...this.props} />;
             case ColumnType.Date:
-                return <SchemaDateCell {...this.props} />;
+            // return <SchemaDateCell {...this.props} />;
             default:
                 return this.getCellWithContent(this.defaultCellContent);
         }
@@ -117,16 +115,18 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 // mj: most of this is adapted from old schema code so I'm not sure what it does tbh
 @observer
 export class SchemaImageCell extends SchemaTableCell {
+    @observable _previewRef: HTMLImageElement | undefined;
+
     choosePath(url: URL) {
         if (url.protocol === 'data') return url.href; // if the url ises the data protocol, just return the href
         if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); // otherwise, put it through the cors proxy erver
         if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href; //Why is this here — good question
 
         const ext = extname(url.href);
-        return url.href.replace(ext, '_o' + ext);
+        return url.href.replace(ext, '_s' + ext);
     }
 
-    get content() {
+    get url() {
         const field = Cast(this.props.Document[this.props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
         const alts = DocListCast(this.props.Document[this.props.fieldKey + '-alternates']); // retrieve alternate documents that may be rendered as alternate images
         const altpaths = alts
@@ -136,13 +136,42 @@ export class SchemaImageCell extends SchemaTableCell {
         const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
         // If there is a path, follow it; otherwise, follow a link to a default image icon
         const url = paths.length ? paths : [Utils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png')];
+        return url[0];
+    }
+
+    @action
+    showHoverPreview = (e: React.PointerEvent) => {
+        this._previewRef = document.createElement('img');
+        document.body.appendChild(this._previewRef);
+        const ext = extname(this.url);
+        this._previewRef.src = this.url.replace('_s' + ext, '_m' + ext);
+        this._previewRef.style.position = 'absolute';
+        this._previewRef.style.left = e.clientX + 10 + 'px';
+        this._previewRef.style.top = e.clientY + 10 + 'px';
+        this._previewRef.style.zIndex = '1000';
+    };
+
+    @action
+    moveHoverPreview = (e: React.PointerEvent) => {
+        if (!this._previewRef) return;
+        this._previewRef.style.left = e.clientX + 10 + 'px';
+        this._previewRef.style.top = e.clientY + 10 + 'px';
+    };
 
+    @action
+    removeHoverPreview = (e: React.PointerEvent) => {
+        if (!this._previewRef) return;
+        document.body.removeChild(this._previewRef);
+    };
+
+    get content() {
         const aspect = Doc.NativeAspect(this.props.Document); // aspect ratio
-        let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
-        const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
-        width = height * aspect; // increase the width of the image if necessary to maintain proportionality
+        // let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
+        // const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
+        const height = CollectionSchemaView._rowHeight - 10;
+        const width = height * aspect; // increase the width of the image if necessary to maintain proportionality
 
-        return <img src={url[0]} width={paths.length ? width : '20px'} height={paths.length ? height : '20px'} />;
+        return <img src={this.url} width={width} height={height} style={{}} draggable="false" onPointerEnter={this.showHoverPreview} onPointerMove={this.moveHoverPreview} onPointerLeave={this.removeHoverPreview} />;
     }
 
     render() {
@@ -171,18 +200,8 @@ export class SchemaDateCell extends SchemaTableCell {
     };
 
     get content() {
-        return !this._pickingDate ? (
-            <div onPointerDown={action(() => (this._pickingDate = true))}>{this.defaultCellContent}</div>
-        ) : (
-            <DatePicker
-                selected={this.date.date}
-                onSelect={(date: any) => {
-                    this.handleChange(date);
-                    this._pickingDate = false;
-                }}
-                onChange={(date: any) => this.handleChange(date)}
-            />
-        );
+        return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
+        // return !this._pickingDate ? <div onPointerDown={action(() => (this._pickingDate = true))}>{this.defaultCellContent}</div> : <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
     }
 
     render() {
-- 
cgit v1.2.3-70-g09d2


From bc550e43b6042176cf59f04cbff51e1b21adaa8a Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 27 Apr 2023 00:41:43 -0400
Subject: trying to get schema keyboard controls working

---
 .../collectionSchema/CollectionSchemaView.tsx      | 43 ++++++++++++--
 .../collections/collectionSchema/SchemaRowBox.tsx  |  1 +
 .../collectionSchema/SchemaTableCell.tsx           | 65 +++++++++++++---------
 3 files changed, 78 insertions(+), 31 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index f6dc2a3d7..92a04f5ec 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -74,6 +74,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _menuValue: string = '';
     @observable _filterColumnIndex: number | undefined;
     @observable _filterSearchValue: string = '';
+    @observable _selectedCell: [Doc, number] | undefined;
 
     get fieldInfos() {
         const docs = this.childDocs;
@@ -174,8 +175,11 @@ export class CollectionSchemaView extends CollectionSubView() {
                             !e.shiftKey && this.clearSelection();
                             const newDoc = this.sortedDocs.docs[lastIndex + 1];
                             if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
-                            else this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
-                            this.scrollToDoc(newDoc, {});
+                            else {
+                                this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
+                                this._selectedCell && (this._selectedCell[0] = newDoc);
+                                this.scrollToDoc(newDoc, {});
+                            }
                         }
                         e.stopPropagation();
                         e.preventDefault();
@@ -191,13 +195,37 @@ export class CollectionSchemaView extends CollectionSubView() {
                             !e.shiftKey && this.clearSelection();
                             const newDoc = this.sortedDocs.docs[firstIndex - 1];
                             if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
-                            else this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1);
-                            this.scrollToDoc(newDoc, {});
+                            else {
+                                this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1);
+                                this._selectedCell && (this._selectedCell[0] = newDoc);
+                                this.scrollToDoc(newDoc, {});
+                            }
                         }
                         e.stopPropagation();
                         e.preventDefault();
                     }
                     break;
+                case 'ArrowRight':
+                    if (this._selectedCell) {
+                        this._selectedCell[1] = Math.min(this._selectedCell[1] + 1, this.columnKeys.length - 1);
+                    } else if (this._selectedDocs.length > 0) {
+                        this.selectCell(this._selectedDocs[0], 0);
+                    }
+                    break;
+                case 'ArrowLeft':
+                    if (this._selectedCell) {
+                        this._selectedCell[1] = Math.max(this._selectedCell[1] - 1, 0);
+                    } else if (this._selectedDocs.length > 0) {
+                        this.selectCell(this._selectedDocs[0], 0);
+                    }
+                    break;
+                case 'Backspace': {
+                    this.removeDocument(this._selectedDocs);
+                    break;
+                }
+                case 'Escape': {
+                    this._selectedCell = undefined;
+                }
             }
         }
     };
@@ -392,6 +420,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         }
     };
 
+    @action
+    selectCell = (doc: Doc, index: number) => {
+        this._selectedCell = [doc, index];
+    };
+
     sortedSelectedDocs = () => this.sortedDocs.docs.filter(doc => this._selectedDocs.includes(doc));
 
     setDropIndex = (index: number) => (this._closestDropIndex = index);
@@ -428,7 +461,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             const pushedAndDraggedDocs = [...pushedDocs, ...draggedDocs];
             const removed = this.childDocs.slice().filter(doc => !pushedAndDraggedDocs.includes(doc));
             this.dataDoc[this.fieldKey ?? 'data'] = new List<Doc>([...removed, ...draggedDocs, ...pushedDocs]);
-            SelectionManager.DeselectAll();
+            this.clearSelection();
             draggedDocs.forEach(doc => {
                 const draggedView = DocumentManager.Instance.getFirstDocumentView(doc);
                 if (draggedView) DocumentManager.Instance.RemoveView(draggedView);
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 79808d8f8..f5a16cec0 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -123,6 +123,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         <SchemaTableCell
                             key={key}
                             Document={this.rootDoc}
+                            col={index}
                             schemaView={this.schemaView}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 2325339fc..2b61ea261 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -11,13 +11,16 @@ import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSc
 import './CollectionSchemaView.scss';
 import { action, computed, observable } from 'mobx';
 import { extname } from 'path';
-import { Cast, DateCast } from '../../../../fields/Types';
+import { Cast, DateCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { DateField } from '../../../../fields/DateField';
 import DatePicker from 'react-datepicker';
+import { Colors } from '../../global/globalEnums';
+import { SelectionManager } from '../../../util/SelectionManager';
 
 export interface SchemaTableCellProps {
     Document: Doc;
+    col: number;
     schemaView: CollectionSchemaView | undefined;
     fieldKey: string;
     columnWidth: number;
@@ -27,10 +30,23 @@ export interface SchemaTableCellProps {
 
 @observer
 export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
-    get readOnly() {
+    private _editorRef: EditableView | null = null;
+
+    @computed get readOnly() {
         return this.props.schemaView?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
     }
 
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.schemaView?._selectedCell;
+        return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
+    }
+
+    componentDidUpdate() {
+        if (!this.selected) {
+            this._editorRef?.setIsFocused(false);
+        }
+    }
+
     get defaultCellContent() {
         const props: FieldViewProps = {
             Document: this.props.Document,
@@ -60,6 +76,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         return (
             <div className="schemacell-edit-wrapper" style={{ cursor: !this.readOnly ? 'text' : 'default', pointerEvents: !this.readOnly && this.props.isRowActive() ? 'all' : 'none' }}>
                 <EditableView
+                    ref={ref => (this._editorRef = ref)}
                     contents={<FieldView {...props} />}
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
@@ -68,20 +85,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
                     }}
-                    editing={this.props.isRowActive() ? undefined : false}
+                    editing={this.selected ? undefined : false}
                 />
             </div>
         );
     }
 
-    getCellWithContent(content: any) {
-        return (
-            <div className="schema-table-cell" style={this.props.isRowActive() && !this.readOnly ? { width: this.props.columnWidth } : { width: this.props.columnWidth }}>
-                {content}
-            </div>
-        );
-    }
-
     get getCellType() {
         const columnTypeStr = this.props.schemaView?.fieldInfos[this.props.fieldKey]?.fieldType;
         if (columnTypeStr) {
@@ -99,7 +108,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         return ColumnType.Any;
     }
 
-    render() {
+    get content() {
         const cellType: ColumnType = this.getCellType;
         switch (cellType) {
             case ColumnType.Image:
@@ -107,14 +116,27 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             case ColumnType.Date:
             // return <SchemaDateCell {...this.props} />;
             default:
-                return this.getCellWithContent(this.defaultCellContent);
+                return this.defaultCellContent;
         }
     }
+
+    render() {
+        return (
+            <div
+                className="schema-table-cell"
+                onPointerDown={action(e => {
+                    if (!this.selected) this.props.schemaView?.selectCell(this.props.Document, this.props.col);
+                })}
+                style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
+                {this.content}
+            </div>
+        );
+    }
 }
 
 // mj: most of this is adapted from old schema code so I'm not sure what it does tbh
 @observer
-export class SchemaImageCell extends SchemaTableCell {
+export class SchemaImageCell extends React.Component<SchemaTableCellProps> {
     @observable _previewRef: HTMLImageElement | undefined;
 
     choosePath(url: URL) {
@@ -164,7 +186,7 @@ export class SchemaImageCell extends SchemaTableCell {
         document.body.removeChild(this._previewRef);
     };
 
-    get content() {
+    render() {
         const aspect = Doc.NativeAspect(this.props.Document); // aspect ratio
         // let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
         // const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
@@ -173,14 +195,10 @@ export class SchemaImageCell extends SchemaTableCell {
 
         return <img src={this.url} width={width} height={height} style={{}} draggable="false" onPointerEnter={this.showHoverPreview} onPointerMove={this.moveHoverPreview} onPointerLeave={this.removeHoverPreview} />;
     }
-
-    render() {
-        return this.getCellWithContent(this.content);
-    }
 }
 
 @observer
-export class SchemaDateCell extends SchemaTableCell {
+export class SchemaDateCell extends React.Component<SchemaTableCellProps> {
     @observable _pickingDate: boolean = false;
 
     @computed get date(): DateField {
@@ -199,12 +217,7 @@ export class SchemaDateCell extends SchemaTableCell {
         //}
     };
 
-    get content() {
-        return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
-        // return !this._pickingDate ? <div onPointerDown={action(() => (this._pickingDate = true))}>{this.defaultCellContent}</div> : <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
-    }
-
     render() {
-        return this.getCellWithContent(this.content);
+        return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
     }
 }
-- 
cgit v1.2.3-70-g09d2


From b82a909a63a6de414d075735453240ebc02f5aa3 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 27 Apr 2023 13:20:52 -0400
Subject: fixed editing schema cells with keyboard only

---
 src/client/views/EditableView.tsx                  |  6 +++++
 .../collectionSchema/CollectionSchemaView.tsx      | 19 +++++++++------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  6 +++--
 .../collectionSchema/SchemaTableCell.tsx           | 28 ++++++++++++++++------
 4 files changed, 43 insertions(+), 16 deletions(-)

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

diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 164b6c57a..d1311a60a 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -106,6 +106,12 @@ export class EditableView extends React.Component<EditableProps> {
             case ':':
                 this.props.menuCallback?.(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y);
                 break;
+            case 'ArrowUp':
+            case 'ArrowDown':
+            case 'ArrowLeft':
+            case 'ArrowRight':
+                e.stopPropagation();
+                break;
             case 'Shift':
             case 'Alt':
             case 'Meta':
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 92a04f5ec..8cd307adf 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,6 +1,6 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, ObservableMap, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, trace, untracked } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc';
@@ -170,12 +170,12 @@ export class CollectionSchemaView extends CollectionSubView() {
                         const lastDoc = this._selectedDocs.lastElement();
                         const lastIndex = this.rowIndex(lastDoc);
                         const curDoc = this.sortedDocs.docs[lastIndex];
-                        // const curDoc = this.childDocs[lastIndex];
                         if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
                             !e.shiftKey && this.clearSelection();
                             const newDoc = this.sortedDocs.docs[lastIndex + 1];
-                            if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
-                            else {
+                            if (this._selectedDocs.includes(newDoc)) {
+                                SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
+                            } else {
                                 this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
                                 this._selectedCell && (this._selectedCell[0] = newDoc);
                                 this.scrollToDoc(newDoc, {});
@@ -189,7 +189,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                     {
                         const firstDoc = this._selectedDocs.lastElement();
                         const firstIndex = this.rowIndex(firstDoc);
-                        // const curDoc = this.childDocs[firstIndex];
                         const curDoc = this.sortedDocs.docs[firstIndex];
                         if (firstIndex > 0 && firstIndex < this.childDocs.length) {
                             !e.shiftKey && this.clearSelection();
@@ -224,7 +223,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     break;
                 }
                 case 'Escape': {
-                    this._selectedCell = undefined;
+                    this.deselectCell();
                 }
             }
         }
@@ -425,6 +424,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._selectedCell = [doc, index];
     };
 
+    @action
+    deselectCell = () => {
+        this._selectedCell = undefined;
+    };
+
     sortedSelectedDocs = () => this.sortedDocs.docs.filter(doc => this._selectedDocs.includes(doc));
 
     setDropIndex = (index: number) => (this._closestDropIndex = index);
@@ -456,7 +460,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             return true;
         }
         const draggedDocs = de.complete.docDragData?.draggedDocuments;
-        if (draggedDocs && super.onInternalDrop(e, de)) {
+        if (draggedDocs && super.onInternalDrop(e, de) && !this.sortField) {
             const pushedDocs = this.childDocs.filter((doc, index) => index >= this._closestDropIndex && !draggedDocs.includes(doc));
             const pushedAndDraggedDocs = [...pushedDocs, ...draggedDocs];
             const removed = this.childDocs.slice().filter(doc => !pushedAndDraggedDocs.includes(doc));
@@ -829,6 +833,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get sortedDocs() {
+        trace();
         const field = StrCast(this.layoutDoc.sortField);
         const desc = BoolCast(this.layoutDoc.sortDesc);
         const docs = !field
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index f5a16cec0..9864820a3 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -28,6 +28,8 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as CollectionSchemaView) : undefined;
     }
 
+    schemaViewFunc = () => this.schemaView;
+
     @computed get schemaDoc() {
         return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
@@ -124,11 +126,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             key={key}
                             Document={this.rootDoc}
                             col={index}
-                            schemaView={this.schemaView}
+                            schemaView={this.schemaViewFunc}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
                             isRowActive={this.props.isContentActive}
-                            setColumnValues={(field, value) => this.schemaView?.setColumnValues(field, value) ?? false}
+                            // setColumnValues={(field, value) => this.schemaView?.setColumnValues(field, value) ?? false}
                         />
                     ))}
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 2b61ea261..374b92d72 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -21,11 +21,11 @@ import { SelectionManager } from '../../../util/SelectionManager';
 export interface SchemaTableCellProps {
     Document: Doc;
     col: number;
-    schemaView: CollectionSchemaView | undefined;
+    schemaView: () => CollectionSchemaView | undefined;
     fieldKey: string;
     columnWidth: number;
     isRowActive: () => boolean | undefined;
-    setColumnValues: (field: string, value: string) => boolean;
+    // setColumnValues: (field: string, value: string) => boolean;
 }
 
 @observer
@@ -33,20 +33,34 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     private _editorRef: EditableView | null = null;
 
     @computed get readOnly() {
-        return this.props.schemaView?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
+        return this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
     }
 
     @computed get selected() {
-        const selected: [Doc, number] | undefined = this.props.schemaView?._selectedCell;
+        const selected: [Doc, number] | undefined = this.props.schemaView()?._selectedCell;
         return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
     }
 
     componentDidUpdate() {
         if (!this.selected) {
             this._editorRef?.setIsFocused(false);
+            document.removeEventListener('keydown', this.onKeyDown);
+        } else if (!this.readOnly) {
+            document.addEventListener('keydown', this.onKeyDown);
         }
     }
 
+    @action
+    onKeyDown = (e: KeyboardEvent) => {
+        e.stopPropagation();
+        if (e.key == 'Enter') {
+            this._editorRef?.setIsFocused(true);
+        }
+        if (e.key == 'Escape') {
+            this.props.schemaView()?.deselectCell();
+        }
+    };
+
     get defaultCellContent() {
         const props: FieldViewProps = {
             Document: this.props.Document,
@@ -81,7 +95,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
-                            this.props.setColumnValues(this.props.fieldKey, value);
+                            // this.props.setColumnValues(this.props.fieldKey, value);
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
                     }}
@@ -92,7 +106,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     }
 
     get getCellType() {
-        const columnTypeStr = this.props.schemaView?.fieldInfos[this.props.fieldKey]?.fieldType;
+        const columnTypeStr = this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.fieldType;
         if (columnTypeStr) {
             if (columnTypeStr in FInfotoColType) {
                 return FInfotoColType[columnTypeStr];
@@ -125,7 +139,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             <div
                 className="schema-table-cell"
                 onPointerDown={action(e => {
-                    if (!this.selected) this.props.schemaView?.selectCell(this.props.Document, this.props.col);
+                    if (!this.selected) this.props.schemaView()?.selectCell(this.props.Document, this.props.col);
                 })}
                 style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
                 {this.content}
-- 
cgit v1.2.3-70-g09d2


From ba5b687011526188bb024ddf37c254aaf285c06d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 16:45:59 -0400
Subject: performance tuning for schema views to avoid re-rendering each table
 cell when child docs change.

---
 .../collectionLinear/CollectionLinearView.tsx      |  20 ++--
 .../collectionSchema/CollectionSchemaView.tsx      | 105 +++++++++------------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  19 ++--
 .../collectionSchema/SchemaTableCell.tsx           |  48 +++++-----
 4 files changed, 94 insertions(+), 98 deletions(-)

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

diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 97eed7752..efd73a927 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -255,15 +255,17 @@ export class CollectionLinearView extends CollectionSubView() {
                         })}
                     />
 
-                    <div
-                        className="collectionLinearView-content"
-                        style={{
-                            height: this.dimension(),
-                            flexDirection: flexDir as any,
-                            gap: flexGap,
-                        }}>
-                        {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
-                    </div>
+                    {!this.layoutDoc.linearViewIsExpanded ? null : (
+                        <div
+                            className="collectionLinearView-content"
+                            style={{
+                                height: this.dimension(),
+                                flexDirection: flexDir as any,
+                                gap: flexGap,
+                            }}>
+                            {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
+                        </div>
+                    )}
                 </div>
             </div>
         );
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 8cd307adf..50a91a60a 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,9 +1,9 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, ObservableMap, trace, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, observe, reaction, trace, untracked } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
-import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field, NumListCast, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { listSpec } from '../../../../fields/Schema';
@@ -47,6 +47,7 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate',
 
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
+    private _keysDisposer: any;
     private _closestDropIndex: number = 0;
     private _previewRef: HTMLDivElement | null = null;
     private _makeNewColumn: boolean = false;
@@ -58,15 +59,13 @@ export class CollectionSchemaView extends CollectionSubView() {
     public static _rowMenuWidth: number = 60;
     public static _previewDividerWidth: number = 4;
     public static _newNodeInputHeight: number = 30;
+    public fieldInfos = new ObservableMap<string, FInfo>();
 
-    @computed get _selectedDocs() {
-        return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.props.Document));
-    }
+    @observable _menuKeys: string[] = [];
     @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
     @observable _colEles: HTMLDivElement[] = [];
     @observable _displayColumnWidths: number[] | undefined;
     @observable _columnMenuIndex: number | undefined;
-    @observable _fieldInfos: [string, FInfo][] = [];
     @observable _newFieldWarning: string = '';
     @observable _makeNewField: boolean = false;
     @observable _newFieldDefault: any = 0;
@@ -76,34 +75,12 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _filterSearchValue: string = '';
     @observable _selectedCell: [Doc, number] | undefined;
 
-    get fieldInfos() {
-        const docs = this.childDocs;
-        const keys: { [key: string]: boolean } = {};
-        // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
-        //  then as each document's fields come back, we update the documents _proxies.  Each time we do this, the whole schema will be
-        //  invalidated and re-rendered.   This workaround will inquire all of the document fields before the options button is clicked.
-        //  then by the time the options button is clicked, all of the fields should be in place.  If a new field is added while this menu
-        //  is displayed (unlikely) it won't show up until something else changes.
-        //TODO Types
-        untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)))));
-
-        let computedKeys: { [key: string]: FInfo } = {};
-
-        Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => {
-            computedKeys[pair[0]] = pair[1];
-        });
-
-        Object.keys(keys).forEach((key: string) => {
-            if (!(key in computedKeys)) {
-                computedKeys[key] = new FInfo('');
-            }
-        });
-
-        return computedKeys;
+    @computed get _selectedDocs() {
+        return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.rootDoc));
     }
 
-    get documentKeys() {
-        return Object.keys(this.fieldInfos);
+    @computed get documentKeys() {
+        return Array.from(this.fieldInfos.keys());
     }
 
     @computed get previewWidth() {
@@ -119,20 +96,15 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get storedColumnWidths() {
-        let widths = Cast(
+        const widths = NumListCast(
             this.layoutDoc.columnWidths,
-            listSpec('number'),
             this.columnKeys.map(() => (this.tableWidth - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length)
         );
 
         const totalWidth = widths.reduce((sum, width) => sum + width, 0);
         if (totalWidth !== this.tableWidth - CollectionSchemaView._rowMenuWidth) {
-            widths = widths.map(w => {
-                const proportion = w / totalWidth;
-                return proportion * (this.tableWidth - CollectionSchemaView._rowMenuWidth);
-            });
+            return widths.map(w => (w / totalWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth));
         }
-
         return widths;
     }
 
@@ -148,19 +120,37 @@ export class CollectionSchemaView extends CollectionSubView() {
         return BoolCast(this.layoutDoc.sortDesc);
     }
 
-    rowIndex(doc: Doc) {
-        return this.sortedDocs.docs.indexOf(doc);
-    }
-
+    @action
     componentDidMount() {
         this.props.setContentView?.(this);
         document.addEventListener('keydown', this.onKeyDown);
+
+        Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1]));
+        this._keysDisposer = observe(
+            this.rootDoc[this.fieldKey ?? 'data'] as List<Doc>,
+            change => {
+                switch (change.type as any) {
+                    case 'splice':
+                        // prettier-ignore
+                        (change as any).added.forEach((doc: Doc) => // for each document added 
+                            Doc.GetAllPrototypes(doc).forEach(proto => // for all of its prototypes (and itself)
+                                Object.keys(proto).forEach(action(key => // check if any of its keys are new, and add them
+                                    !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo(''))))));
+                        break;
+                    case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list
+                }
+            },
+            true
+        );
     }
 
     componentWillUnmount() {
+        this._keysDisposer?.();
         document.removeEventListener('keydown', this.onKeyDown);
     }
 
+    rowIndex = (doc: Doc) => this.sortedDocs.docs.indexOf(doc);
+
     @action
     onKeyDown = (e: KeyboardEvent) => {
         if (this._selectedDocs.length > 0) {
@@ -554,8 +544,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     onSearchKeyDown = (e: React.KeyboardEvent) => {
         switch (e.key) {
             case 'Enter':
-                const menuKeys = Object.keys(this._fieldInfos);
-                menuKeys.length > 0 && this._menuValue.length > 0 ? this.setKey(menuKeys[0]) : action(() => (this._makeNewField = true))();
+                this._menuKeys.length > 0 && this._menuValue.length > 0 ? this.setKey(this._menuKeys[0]) : action(() => (this._makeNewField = true))();
                 break;
             case 'Escape':
                 this.closeColumnMenu();
@@ -584,7 +573,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._makeNewColumn = false;
         this._columnMenuIndex = index;
         this._menuValue = '';
-        this._fieldInfos = Object.entries(this.fieldInfos);
+        this._menuKeys = this.documentKeys;
         this._makeNewField = false;
         this._newFieldWarning = '';
         this._makeNewField = false;
@@ -630,7 +619,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     updateKeySearch = (e: React.ChangeEvent<HTMLInputElement>) => {
         this._menuValue = e.target.value;
-        this._fieldInfos = Object.entries(this.fieldInfos).filter(value => value[0].toLowerCase().includes(this._menuValue.toLowerCase()));
+        this._menuKeys = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
     getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
@@ -732,7 +721,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                             { passive: false }
                         )
                     }>
-                    {this._fieldInfos.map(([key, info]) => (
+                    {this._menuKeys.map(key => (
                         <div
                             className="schema-search-result"
                             onPointerDown={e => {
@@ -742,13 +731,13 @@ export class CollectionSchemaView extends CollectionSubView() {
                             <p>
                                 <span className="schema-search-result-key">
                                     {key}
-                                    {info.fieldType ? ', ' : ''}
+                                    {this.fieldInfos.get(key)!.fieldType ? ', ' : ''}
                                 </span>
-                                <span className="schema-search-result-type" style={{ color: info.readOnly ? 'red' : 'inherit' }}>
-                                    {info.fieldType}
+                                <span className="schema-search-result-type" style={{ color: this.fieldInfos.get(key)!.readOnly ? 'red' : 'inherit' }}>
+                                    {this.fieldInfos.get(key)!.fieldType}
                                 </span>
                             </p>
-                            <p className="schema-search-result-desc">{info.description}</p>
+                            <p className="schema-search-result-desc">{this.fieldInfos.get(key)!.description}</p>
                         </div>
                     ))}
                 </div>
@@ -888,13 +877,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     </div>
                     {this._columnMenuIndex !== undefined && this.renderColumnMenu}
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
-                    <CollectionSchemaViewDocs
-                        schema={this}
-                        childDocs={this.sortedDocsFunc}
-                        setRef={(ref: HTMLDivElement | null) => {
-                            this._tableContentRef = ref;
-                        }}
-                    />
+                    <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} setRef={(ref: HTMLDivElement | null) => (this._tableContentRef = ref)} />
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} height={CollectionSchemaView._newNodeInputHeight} />
                 </div>
                 {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
@@ -923,7 +906,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 moveDocument={this.props.moveDocument}
                                 addDocument={this.addRow}
                                 removeDocument={this.props.removeDocument}
-                                whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+                                whenChildContentsActiveChanged={returnFalse}
                                 addDocTab={this.props.addDocTab}
                                 pinToPres={this.props.pinToPres}
                                 bringToFront={returnFalse}
@@ -978,7 +961,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 bringToFront={emptyFunction}
                                 isDocumentActive={this.props.schema.props.childDocumentsActive?.() ? this.props.schema.props.isDocumentActive : this.props.schema.isContentActive}
                                 isContentActive={emptyFunction}
-                                whenChildContentsActiveChanged={active => this.props.schema.props.whenChildContentsActiveChanged(active)}
+                                whenChildContentsActiveChanged={this.props.schema.props.whenChildContentsActiveChanged}
                                 hideDecorations={true}
                                 hideTitle={true}
                                 hideDocumentButtonBar={true}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 9864820a3..9772ce118 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -12,6 +12,8 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
+import { computedFn } from 'mobx-utils';
+import { Doc } from '../../../../fields/Doc';
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -24,12 +26,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     bounds = () => this._ref?.getBoundingClientRect();
 
     @computed get schemaView() {
-        const vpath = this.props.docViewPath();
-        return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as CollectionSchemaView) : undefined;
+        return this.props.DocumentView?.().props.docViewPath().lastElement()?.ComponentView as CollectionSchemaView;
     }
 
-    schemaViewFunc = () => this.schemaView;
-
     @computed get schemaDoc() {
         return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
@@ -86,6 +85,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         document.removeEventListener('pointermove', this.onPointerMove);
     };
 
+    getFinfo = computedFn((fieldKey: string) => this.schemaView?.fieldInfos.get(fieldKey));
+    selectCell = (doc: Doc, col: number) => this.schemaView?.selectCell(doc, col);
+    deselectCell = () => this.schemaView?.deselectCell();
+    selectedCell = () => this.schemaView?._selectedCell;
+    setColumnValues = (field: any, value: any) => this.schemaView?.setColumnValues(field, value) ?? false;
     render() {
         return (
             <div
@@ -126,11 +130,14 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             key={key}
                             Document={this.rootDoc}
                             col={index}
-                            schemaView={this.schemaViewFunc}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
                             isRowActive={this.props.isContentActive}
-                            // setColumnValues={(field, value) => this.schemaView?.setColumnValues(field, value) ?? false}
+                            getFinfo={this.getFinfo}
+                            selectCell={this.selectCell}
+                            deselectCell={this.deselectCell}
+                            selectedCell={this.selectedCell}
+                            setColumnValues={this.setColumnValues}
                         />
                     ))}
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 374b92d72..686b21283 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,31 +1,34 @@
 import React = require('react');
+import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
-import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../../Utils';
+import { extname } from 'path';
+import DatePicker from 'react-datepicker';
+import { DateField } from '../../../../fields/DateField';
+import { Doc, DocListCast, Field } from '../../../../fields/Doc';
+import { Cast, DateCast } from '../../../../fields/Types';
+import { ImageField } from '../../../../fields/URLField';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
 import { Transform } from '../../../util/Transform';
 import { EditableView } from '../../EditableView';
+import { Colors } from '../../global/globalEnums';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
 import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
-import { action, computed, observable } from 'mobx';
-import { extname } from 'path';
-import { Cast, DateCast, StrCast } from '../../../../fields/Types';
-import { ImageField } from '../../../../fields/URLField';
-import { DateField } from '../../../../fields/DateField';
-import DatePicker from 'react-datepicker';
-import { Colors } from '../../global/globalEnums';
-import { SelectionManager } from '../../../util/SelectionManager';
+import { FInfo } from '../../../documents/Documents';
 
 export interface SchemaTableCellProps {
     Document: Doc;
     col: number;
-    schemaView: () => CollectionSchemaView | undefined;
+    deselectCell: () => void;
+    selectCell: (doc: Doc, col: number) => void;
+    selectedCell: () => [Doc, number] | undefined;
     fieldKey: string;
     columnWidth: number;
     isRowActive: () => boolean | undefined;
-    // setColumnValues: (field: string, value: string) => boolean;
+    getFinfo: (fieldKey: string) => FInfo | undefined;
+    setColumnValues: (field: string, value: string) => boolean;
 }
 
 @observer
@@ -33,11 +36,11 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     private _editorRef: EditableView | null = null;
 
     @computed get readOnly() {
-        return this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
+        return this.props.getFinfo(this.props.fieldKey)?.readOnly ?? false;
     }
 
     @computed get selected() {
-        const selected: [Doc, number] | undefined = this.props.schemaView()?._selectedCell;
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
         return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
     }
 
@@ -57,11 +60,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             this._editorRef?.setIsFocused(true);
         }
         if (e.key == 'Escape') {
-            this.props.schemaView()?.deselectCell();
+            this.props.deselectCell();
         }
     };
-
-    get defaultCellContent() {
+    colWidthFunc = () => this.props.columnWidth;
+    colRowHeightFunc = () => CollectionSchemaView._rowHeight;
+    @computed get defaultCellContent() {
         const props: FieldViewProps = {
             Document: this.props.Document,
             docFilters: returnEmptyFilter,
@@ -81,8 +85,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             whenChildContentsActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
-            PanelWidth: () => this.props.columnWidth,
-            PanelHeight: () => CollectionSchemaView._rowHeight,
+            PanelWidth: this.colWidthFunc,
+            PanelHeight: this.colRowHeightFunc,
             addDocTab: returnFalse,
             pinToPres: returnZero,
         };
@@ -95,7 +99,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
-                            // this.props.setColumnValues(this.props.fieldKey, value);
+                            this.props.setColumnValues(this.props.fieldKey, value);
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
                     }}
@@ -106,7 +110,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     }
 
     get getCellType() {
-        const columnTypeStr = this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.fieldType;
+        const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
         if (columnTypeStr) {
             if (columnTypeStr in FInfotoColType) {
                 return FInfotoColType[columnTypeStr];
@@ -139,7 +143,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             <div
                 className="schema-table-cell"
                 onPointerDown={action(e => {
-                    if (!this.selected) this.props.schemaView()?.selectCell(this.props.Document, this.props.col);
+                    if (!this.selected) this.props.selectCell(this.props.Document, this.props.col);
                 })}
                 style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
                 {this.content}
-- 
cgit v1.2.3-70-g09d2


From 223dde9f35408c229a4da583083d10cbf81fc264 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 22:23:42 -0400
Subject: fixed some undo issues with schema fill down.  added bool cell view. 
 added UI for showing/setting values on layout vs data docs.

---
 .../collections/collectionSchema/SchemaRowBox.tsx  |   3 +-
 .../collectionSchema/SchemaTableCell.tsx           | 156 ++++++++++++---------
 src/client/views/nodes/KeyValueBox.tsx             |   2 -
 3 files changed, 89 insertions(+), 72 deletions(-)

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

diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 9772ce118..ca9e0bda0 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -90,6 +90,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     deselectCell = () => this.schemaView?.deselectCell();
     selectedCell = () => this.schemaView?._selectedCell;
     setColumnValues = (field: any, value: any) => this.schemaView?.setColumnValues(field, value) ?? false;
+    columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth);
     render() {
         return (
             <div
@@ -131,7 +132,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             Document={this.rootDoc}
                             col={index}
                             fieldKey={key}
-                            columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
+                            columnWidth={this.columnWidth(index)}
                             isRowActive={this.props.isContentActive}
                             getFinfo={this.getFinfo}
                             selectCell={this.selectCell}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 4f4986b90..1fa4312e1 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -5,10 +5,13 @@ import { extname } from 'path';
 import DatePicker from 'react-datepicker';
 import { DateField } from '../../../../fields/DateField';
 import { Doc, DocListCast, Field } from '../../../../fields/Doc';
-import { Cast, DateCast } from '../../../../fields/Types';
+import { BoolCast, Cast, DateCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
+import { FInfo } from '../../../documents/Documents';
+import { dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
+import { undoBatch } from '../../../util/UndoManager';
 import { EditableView } from '../../EditableView';
 import { Colors } from '../../global/globalEnums';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
@@ -16,7 +19,6 @@ import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
 import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
-import { FInfo } from '../../../documents/Documents';
 
 export interface SchemaTableCellProps {
     Document: Doc;
@@ -25,7 +27,7 @@ export interface SchemaTableCellProps {
     selectCell: (doc: Doc, col: number) => void;
     selectedCell: () => [Doc, number] | undefined;
     fieldKey: string;
-    columnWidth: number;
+    columnWidth: () => number;
     isRowActive: () => boolean | undefined;
     getFinfo: (fieldKey: string) => FInfo | undefined;
     setColumnValues: (field: string, value: string) => boolean;
@@ -33,95 +35,78 @@ export interface SchemaTableCellProps {
 
 @observer
 export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
-    private _editorRef: EditableView | null = null;
-
-    @computed get readOnly() {
-        return this.props.getFinfo(this.props.fieldKey)?.readOnly ?? false;
-    }
-
-    @computed get selected() {
-        const selected: [Doc, number] | undefined = this.props.selectedCell();
-        return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
+    public static colRowHeightFunc() {
+        return CollectionSchemaView._rowHeight;
     }
-
-    componentDidUpdate() {
-        if (!this.selected) {
-            this._editorRef?.setIsFocused(false);
-            document.removeEventListener('keydown', this.onKeyDown);
-        } else if (!this.readOnly) {
-            document.addEventListener('keydown', this.onKeyDown);
-        }
-    }
-
-    @action
-    onKeyDown = (e: KeyboardEvent) => {
-        e.stopPropagation();
-        if (e.key == 'Enter') {
-            this._editorRef?.setIsFocused(true);
-        }
-        if (e.key == 'Escape') {
-            this.props.deselectCell();
+    public static renderProps(props: SchemaTableCellProps) {
+        const { Document, fieldKey, getFinfo, columnWidth, isRowActive } = props;
+        let protoCount = 0;
+        let doc: Doc | undefined = Document;
+        while (doc) {
+            if (Object.keys(doc).includes(fieldKey.replace(/^_/, ''))) {
+                break;
+            }
+            protoCount++;
+            doc = doc.proto;
         }
-    };
-    colWidthFunc = () => this.props.columnWidth;
-    colRowHeightFunc = () => CollectionSchemaView._rowHeight;
-    @computed get defaultCellContent() {
-        const props: FieldViewProps = {
-            Document: this.props.Document,
+        const parenCount = Math.max(0, protoCount - 1);
+        const color = protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue';
+        const textDecoration = color !== 'black' && parenCount ? 'underline' : '';
+        const fieldProps: FieldViewProps = {
             docFilters: returnEmptyFilter,
             docRangeFilters: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
-            fieldKey: this.props.fieldKey,
             rootSelected: returnFalse,
             isSelected: returnFalse,
             setHeight: returnFalse,
             select: emptyFunction,
-            dropAction: 'alias',
+            dropAction: 'alias' as dropActionType,
             bringToFront: emptyFunction,
             renderDepth: 1,
             isContentActive: returnFalse,
             whenChildContentsActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
-            PanelWidth: this.colWidthFunc,
-            PanelHeight: this.colRowHeightFunc,
             addDocTab: returnFalse,
             pinToPres: returnZero,
+            Document,
+            fieldKey,
+            PanelWidth: columnWidth,
+            PanelHeight: SchemaTableCell.colRowHeightFunc,
         };
-        let protoCount = 0;
-        let doc: Doc | undefined = this.props.Document;
-        while (doc) {
-            if (Object.keys(doc).includes(this.props.fieldKey.replace(/^_/, ''))) {
-                break;
-            }
-            protoCount++;
-            doc = doc.proto;
-        }
-        const parenCount = Math.max(0, protoCount - 1);
-        const color = protoCount === 0 ? 'black' : 'blue';
+        const readOnly = getFinfo(fieldKey)?.readOnly ?? false;
+        const cursor = !readOnly ? 'text' : 'default';
+        const pointerEvents: 'all' | 'none' = !readOnly && isRowActive() ? 'all' : 'none';
+        return { color, textDecoration, fieldProps, cursor, pointerEvents };
+    }
+
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
+        return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+    }
+
+    @computed get defaultCellContent() {
+        const { color, textDecoration, fieldProps } = SchemaTableCell.renderProps(this.props);
 
         return (
             <div
                 className="schemacell-edit-wrapper"
                 style={{
                     color,
-                    textDecoration: parenCount ? 'underline' : undefined,
-                    cursor: !this.readOnly ? 'text' : 'default',
-                    pointerEvents: !this.readOnly && this.props.isRowActive() ? 'all' : 'none',
+                    textDecoration,
                 }}>
                 <EditableView
-                    ref={ref => (this._editorRef = ref)}
-                    contents={<FieldView {...props} />}
+                    contents={<FieldView {...fieldProps} />}
+                    editing={this.selected ? undefined : false}
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
-                    SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
+                    SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
                             this.props.setColumnValues(this.props.fieldKey, value);
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
-                    }}
-                    editing={this.selected ? undefined : false}
+                    })}
                 />
             </div>
         );
@@ -146,13 +131,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 
     get content() {
         const cellType: ColumnType = this.getCellType;
+        // prettier-ignore
         switch (cellType) {
-            case ColumnType.Image:
-                return <SchemaImageCell {...this.props} />;
-            case ColumnType.Date:
-            // return <SchemaDateCell {...this.props} />;
-            default:
-                return this.defaultCellContent;
+            case ColumnType.Image: return <SchemaImageCell {...this.props} />;
+            case ColumnType.Boolean: return <SchemaBoolCell {...this.props} />;
+            case ColumnType.Date: // return <SchemaDateCell {...this.props} />;
+            default:  return this.defaultCellContent;
         }
     }
 
@@ -160,10 +144,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         return (
             <div
                 className="schema-table-cell"
-                onPointerDown={action(e => {
-                    if (!this.selected) this.props.selectCell(this.props.Document, this.props.col);
-                })}
-                style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
+                onPointerDown={action(e => !this.selected && this.props.selectCell(this.props.Document, this.props.col))}
+                style={{ width: this.props.columnWidth(), border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
                 {this.content}
             </div>
         );
@@ -257,3 +239,39 @@ export class SchemaDateCell extends React.Component<SchemaTableCellProps> {
         return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
     }
 }
+@observer
+export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
+        return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+    }
+    render() {
+        const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this.props);
+        return (
+            <div className="schemaBoolCell" style={{ display: 'flex', color, textDecoration, cursor, pointerEvents }}>
+                <input
+                    style={{ marginRight: 4 }}
+                    type="checkbox"
+                    checked={BoolCast(this.props.Document[this.props.fieldKey])}
+                    onChange={undoBatch((value: React.ChangeEvent<HTMLInputElement> | undefined) => {
+                        if ((value?.nativeEvent as any).shiftKey) {
+                            this.props.setColumnValues(this.props.fieldKey, (color === 'black' ? '=' : '') + value?.target?.checked.toString());
+                        }
+                        KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
+                    })}
+                />
+                <EditableView
+                    contents={<FieldView {...fieldProps} />}
+                    editing={this.selected ? undefined : false}
+                    GetValue={() => (color === 'black' ? '=' : '') + Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
+                    SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => {
+                        if (shiftDown && enterKey) {
+                            this.props.setColumnValues(this.props.fieldKey, value);
+                        }
+                        return KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
+                    })}
+                />
+            </div>
+        );
+    }
+}
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 57018fb93..11220c300 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -20,14 +20,12 @@ import { ImageBox } from './ImageBox';
 import './KeyValueBox.scss';
 import { KeyValuePair } from './KeyValuePair';
 import React = require('react');
-import e = require('express');
 
 export type KVPScript = {
     script: CompiledScript;
     type: 'computed' | 'script' | false;
     onDelegate: boolean;
 };
-
 @observer
 export class KeyValueBox extends React.Component<FieldViewProps> {
     public static LayoutString() {
-- 
cgit v1.2.3-70-g09d2


From dca61505ba138eef3819b16b760ec81becf9329e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 13 May 2023 09:55:48 -0400
Subject: changed EditableViews to support oneline and multiline.  Also added
 transformer UI to allow documents to be entered. changed transformer to write
 doc id's, not variables..  made schema view support oneline and fixed bug
 with docdecoration hader occluding things invisibly.   updated web pages to
 be zoomable and for its anchors to update web page and scroll location
 properly.  made autolinkanchor directly go to target on click.

---
 package-lock.json                                  |  39 +++
 src/client/documents/Documents.ts                  |   4 +-
 src/client/util/CurrentUserUtils.ts                |   5 +-
 src/client/util/DocumentManager.ts                 |  24 +-
 src/client/util/Scripting.ts                       |  30 +-
 src/client/views/DocumentDecorations.tsx           |   8 +-
 src/client/views/EditableView.scss                 |  11 +-
 src/client/views/EditableView.tsx                  |  98 ++++--
 src/client/views/MarqueeAnnotator.tsx              |   3 +-
 src/client/views/ScriptingRepl.scss                |   5 +-
 src/client/views/ScriptingRepl.tsx                 | 113 ++++---
 .../views/collections/CollectionStackingView.scss  |   6 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  18 +-
 .../collectionSchema/CollectionSchemaView.scss     |   4 +-
 .../collectionSchema/CollectionSchemaView.tsx      |  23 +-
 .../collectionSchema/SchemaColumnHeader.tsx        |   1 +
 .../collections/collectionSchema/SchemaRowBox.tsx  |  10 +-
 .../collectionSchema/SchemaTableCell.tsx           |  44 ++-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |   3 +-
 src/client/views/nodes/DocumentIcon.tsx            |  56 ++--
 src/client/views/nodes/DocumentView.tsx            |   4 +-
 src/client/views/nodes/KeyValueBox.tsx             |   6 +-
 src/client/views/nodes/KeyValuePair.scss           |  64 ++--
 src/client/views/nodes/KeyValuePair.tsx            |   8 +-
 src/client/views/nodes/WebBox.tsx                  | 359 ++++++++++-----------
 src/client/views/nodes/button/FontIconBox.tsx      |  13 +-
 .../views/nodes/formattedText/DashFieldView.tsx    | 150 ++-------
 .../views/nodes/formattedText/FormattedTextBox.tsx |   3 +-
 src/client/views/nodes/formattedText/marks_rts.ts  |   2 +-
 src/client/views/nodes/trails/PresBox.tsx          |  18 +-
 src/client/views/pdf/PDFViewer.tsx                 |   3 +-
 src/fields/Doc.ts                                  |   2 +-
 32 files changed, 605 insertions(+), 532 deletions(-)

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

diff --git a/package-lock.json b/package-lock.json
index 196906718..111d1838a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5597,6 +5597,16 @@
             "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
             "dev": true
         },
+        "d": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+            "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+            "dev": true,
+            "requires": {
+                "es5-ext": "^0.10.50",
+                "type": "^1.0.1"
+            }
+        },
         "d3": {
             "version": "7.8.4",
             "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.4.tgz",
@@ -6977,6 +6987,28 @@
                 "is-symbol": "^1.0.2"
             }
         },
+        "es5-ext": {
+            "version": "0.10.62",
+            "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+            "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+            "dev": true,
+            "requires": {
+                "es6-iterator": "^2.0.3",
+                "es6-symbol": "^3.1.3",
+                "next-tick": "^1.1.0"
+            }
+        },
+        "es6-iterator": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+            "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+            "dev": true,
+            "requires": {
+                "d": "1",
+                "es5-ext": "^0.10.35",
+                "es6-symbol": "^3.1.1"
+            }
+        },
         "es6-promise": {
             "version": "3.2.1",
             "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
@@ -6988,6 +7020,7 @@
             "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
             "dev": true,
             "requires": {
+                "d": "^1.0.1",
                 "ext": "^1.1.2"
             }
         },
@@ -22660,6 +22693,12 @@
             "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
             "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
         },
+        "type": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+            "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
+            "dev": true
+        },
         "type-check": {
             "version": "0.4.0",
             "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 5a7894c08..bb12ce568 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1054,8 +1054,8 @@ export namespace Docs {
             return inst;
         }
 
-        export function WebanchorDocument(url?: string, options: DocumentOptions = {}, id?: string) {
-            return InstanceFromProto(Prototypes.get(DocumentType.MARKER), url, options, id);
+        export function WebanchorDocument(options: DocumentOptions = {}, id?: string) {
+            return InstanceFromProto(Prototypes.get(DocumentType.MARKER), undefined, options, id);
         }
 
         export function CollectionAnchorDocument(options: DocumentOptions = {}, id?: string) {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 80a5f0993..fbfe306a4 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -669,7 +669,10 @@ export class CurrentUserUtils {
     }
 
     static schemaTools():Button[] {
-        return [{ title: "Show preview", toolTip: "Show selection preview", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", scripts:{ onClick: '{ return toggleSchemaPreview(_readOnly_); }'}, }];
+        return [
+            {title: "Show preview", toolTip: "Show selection preview", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", scripts:{ onClick: '{ return toggleSchemaPreview(_readOnly_); }'} },
+            {title: "Single Lines", toolTip: "Single Line Rows",       btnType: ButtonType.ToggleButton, buttonText: "Single Line",  icon: "eye", scripts:{ onClick: '{ return toggleSingleLineSchema(_readOnly_); }'} },
+        ];
     }
 
     static webTools() {
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 3a192f712..695b003a6 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,4 +1,4 @@
-import { action, observable, ObservableSet } from 'mobx';
+import { action, computed, observable, ObservableSet } from 'mobx';
 import { AnimationSym, Doc, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { listSpec } from '../../fields/Schema';
@@ -10,6 +10,7 @@ import { TabDocView } from '../views/collections/TabDocView';
 import { LightboxView } from '../views/LightboxView';
 import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView';
 import { FormattedTextBox } from '../views/nodes/formattedText/FormattedTextBox';
+import { KeyValueBox } from '../views/nodes/KeyValueBox';
 import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox';
 import { PresBox } from '../views/nodes/trails';
 import { ScriptingGlobals } from './ScriptingGlobals';
@@ -18,10 +19,13 @@ const { Howl } = require('howler');
 
 export class DocumentManager {
     //global holds all of the nodes (regardless of which collection they're in)
-    @observable public DocumentViews = new Set<DocumentView>();
+    @observable _documentViews = new Set<DocumentView>();
     @observable public LinkAnchorBoxViews: DocumentView[] = [];
     @observable public RecordingEvent = 0;
     @observable public LinkedDocumentViews: { a: DocumentView; b: DocumentView; l: Doc }[] = [];
+    @computed public get DocumentViews() {
+        return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox));
+    }
 
     private static _instance: DocumentManager;
     public static get Instance(): DocumentManager {
@@ -78,7 +82,7 @@ export class DocumentManager {
             // this.LinkedDocumentViews.forEach(view => console.log("  LV = " + view.a.props.Document.title + "/" + view.a.props.LayoutTemplateString + " --> " +
             //     view.b.props.Document.title + "/" + view.b.props.LayoutTemplateString));
         } else {
-            this.DocumentViews.add(view);
+            this._documentViews.add(view);
         }
         this.callAddViewFuncs(view);
     };
@@ -96,7 +100,7 @@ export class DocumentManager {
             const index = this.LinkAnchorBoxViews.indexOf(view);
             this.LinkAnchorBoxViews.splice(index, 1);
         } else {
-            this.DocumentViews.delete(view);
+            this._documentViews.delete(view);
         }
         SelectionManager.DeselectView(view);
     });
@@ -104,13 +108,13 @@ export class DocumentManager {
     //gets all views
     public getDocumentViewsById(id: string) {
         const toReturn: DocumentView[] = [];
-        Array.from(DocumentManager.Instance.DocumentViews).map(view => {
+        DocumentManager.Instance.DocumentViews.forEach(view => {
             if (view.rootDoc[Id] === id) {
                 toReturn.push(view);
             }
         });
         if (toReturn.length === 0) {
-            Array.from(DocumentManager.Instance.DocumentViews).map(view => {
+            DocumentManager.Instance.DocumentViews.forEach(view => {
                 const doc = view.rootDoc.proto;
                 if (doc && doc[Id] && doc[Id] === id) {
                     toReturn.push(view);
@@ -133,7 +137,7 @@ export class DocumentManager {
             //         ((DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href && (DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href === (DocCast(toFind.annotationOn)?.data as any)?.url?.href)
             // )?.rootDoc ??
             toFind;
-        const docViewArray = Array.from(DocumentManager.Instance.DocumentViews);
+        const docViewArray = DocumentManager.Instance.DocumentViews;
         const passes = !doc ? [] : preferredCollection ? [preferredCollection, undefined] : [undefined];
         return passes.reduce(
             (pass, toReturn) =>
@@ -146,7 +150,7 @@ export class DocumentManager {
 
     public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
         const views: DocumentView[] = [];
-        Array.from(DocumentManager.Instance.DocumentViews).map(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view));
+        DocumentManager.Instance.DocumentViews.forEach(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view));
         return views?.find(view => view.ContentDiv?.getBoundingClientRect().width /*&& view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse*/) || (views.length ? views[0] : undefined);
     };
     public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
@@ -164,8 +168,8 @@ export class DocumentManager {
             toFindIn;
 
         const toReturn: DocumentView[] = [];
-        const docViews = Array.from(DocumentManager.Instance.DocumentViews).filter(view => !LightboxView.IsLightboxDocView(view.docViewPath));
-        const lightViews = Array.from(DocumentManager.Instance.DocumentViews).filter(view => LightboxView.IsLightboxDocView(view.docViewPath));
+        const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.IsLightboxDocView(view.docViewPath));
+        const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.IsLightboxDocView(view.docViewPath));
 
         // heuristic to return the "best" documents first:
         //   choose a document in the lightbox first
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index f17a98616..70c2e3842 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -7,8 +7,6 @@
 import * as typescriptlib from '!!raw-loader!./type_decls.d';
 import * as ts from 'typescript';
 import { Doc, Field } from '../../fields/Doc';
-import { ToScriptString } from '../../fields/FieldSymbols';
-import { ObjectField } from '../../fields/ObjectField';
 import { RefField } from '../../fields/RefField';
 import { ScriptField } from '../../fields/ScriptField';
 import { scriptingGlobals, ScriptingGlobals } from './ScriptingGlobals';
@@ -60,7 +58,14 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an
     // let fieldTypes = [Doc, ImageField, PdfField, VideoField, AudioField, List, RichTextField, ScriptField, ComputedField, CompileScript];
     // let paramNames = ["Docs", ...fieldTypes.map(fn => fn.name)];
     // let params: any[] = [Docs, ...fieldTypes];
-    const compiledFunction = new Function(...paramNames, `return ${script}`);
+    const compiledFunction = (() => {
+        try {
+            return new Function(...paramNames, `return ${script}`);
+        } catch {
+            return undefined;
+        }
+    })();
+    if (!compiledFunction) return { compiled: false, errors };
     const { capturedVariables = {} } = options;
     const run = (args: { [name: string]: any } = {}, onError?: (e: any) => void, errorVal?: any): ScriptResult => {
         const argsArray: any[] = [];
@@ -155,7 +160,7 @@ export type Traverser = (node: ts.Node, indentation: string) => boolean | void;
 export type TraverserParam = Traverser | { onEnter: Traverser; onLeave: Traverser };
 export type Transformer = {
     transformer: ts.TransformerFactory<ts.SourceFile>;
-    getVars?: () => { capturedVariables: { [name: string]: Field } };
+    getVars?: () => { [name: string]: Field };
 };
 export interface ScriptOptions {
     requiredType?: string; // does function required a typed return value
@@ -205,16 +210,17 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
     if (options.transformer) {
         const sourceFile = ts.createSourceFile('script.ts', script, ts.ScriptTarget.ES2015, true);
         const result = ts.transform(sourceFile, [options.transformer.transformer]);
-        if (options.transformer.getVars) {
-            const newCaptures = options.transformer.getVars();
+        const newCaptures = options.transformer.getVars?.();
+        if (Object.keys(newCaptures ?? {}).length) {
             // tslint:disable-next-line: prefer-object-spread
-            options.capturedVariables = Object.assign(capturedVariables, newCaptures.capturedVariables) as any;
+            //options.capturedVariables = Object.assign(capturedVariables, newCaptures!) as any;
+
+            const transformed = result.transformed;
+            const printer = ts.createPrinter({
+                newLine: ts.NewLineKind.LineFeed,
+            });
+            script = printer.printFile(transformed[0]);
         }
-        const transformed = result.transformed;
-        const printer = ts.createPrinter({
-            newLine: ts.NewLineKind.LineFeed,
-        });
-        script = printer.printFile(transformed[0]);
         result.dispose();
     }
     const paramNames: string[] = [];
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 85d36dbf8..26b64bfdd 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -867,11 +867,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                 width: bounds.r - bounds.x + this._resizeBorderWidth + 'px',
                                 height: bounds.b - bounds.y + this._resizeBorderWidth + this._titleHeight + 'px',
                             }}>
-                            <div className="documentDecorations-topbar" onPointerDown={this.onContainerDown}>
-                                {hideDeleteButton ? <div /> : topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')}
-                                {hideResizers || hideDeleteButton ? <div /> : topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')}
+                            <div className="documentDecorations-topbar" style={{ display: hideDeleteButton && hideTitle && hideOpenButton ? 'none' : undefined }} onPointerDown={this.onContainerDown}>
+                                {hideDeleteButton ? null : topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')}
+                                {hideResizers || hideDeleteButton ? null : topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')}
                                 {hideTitle ? null : titleArea}
-                                {hideOpenButton ? <div /> : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')}
+                                {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')}
                             </div>
                             {hideResizers ? null : (
                                 <>
diff --git a/src/client/views/EditableView.scss b/src/client/views/EditableView.scss
index ed7ec9dc1..0955ba8ff 100644
--- a/src/client/views/EditableView.scss
+++ b/src/client/views/EditableView.scss
@@ -10,12 +10,14 @@
 
 .editableView-container-editing-oneLine {
     width: 100%;
+    height: max-content;
 
     span {
-        white-space: nowrap;
-        overflow: hidden;
-        text-overflow: ellipsis;
-        display: block;
+        p {
+            white-space: pre;
+            overflow: hidden;
+            text-overflow: ellipsis;
+        }
     }
 
     input {
@@ -33,4 +35,3 @@
     border: none;
     outline: none;
 }
- 
\ No newline at end of file
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index d1311a60a..6b4132814 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -1,9 +1,11 @@
 import React = require('react');
-import { action, observable } from 'mobx';
+import { action, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as Autosuggest from 'react-autosuggest';
 import { ObjectField } from '../../fields/ObjectField';
 import './EditableView.scss';
+import { DocumentIconContainer } from './nodes/DocumentIcon';
+import { OverlayView } from './OverlayView';
 
 export interface EditableProps {
     /**
@@ -37,7 +39,8 @@ export interface EditableProps {
         onChange: (e: React.ChangeEvent, { newValue }: { newValue: string }) => void;
         autosuggestProps: Autosuggest.AutosuggestProps<string, any>;
     };
-    oneLine?: boolean;
+    oneLine?: boolean; // whether to display the editable view as a single input line or as a textarea
+    allowCRs?: boolean; // can carriage returns be entered
     editing?: boolean;
     isEditingCallback?: (isEditing: boolean) => void;
     menuCallback?: (x: number, y: number) => void;
@@ -45,6 +48,7 @@ export interface EditableProps {
     showMenuOnLoad?: boolean;
     background?: string | undefined;
     placeholder?: string;
+    wrap?: string; // nowrap, pre-wrap, etc
 }
 
 /**
@@ -55,7 +59,9 @@ export interface EditableProps {
 @observer
 export class EditableView extends React.Component<EditableProps> {
     private _ref = React.createRef<HTMLDivElement>();
-    private _inputref = React.createRef<HTMLInputElement>();
+    private _inputref: HTMLInputElement | HTMLTextAreaElement | null = null;
+    _overlayDisposer?: () => void;
+    _editingDisposer?: IReactionDisposer;
     @observable _editing: boolean = false;
 
     constructor(props: EditableProps) {
@@ -63,21 +69,53 @@ export class EditableView extends React.Component<EditableProps> {
         this._editing = this.props.editing ? true : false;
     }
 
+    componentDidMount(): void {
+        this._editingDisposer = reaction(
+            () => this._editing,
+            editing => {
+                if (editing) {
+                    setTimeout(() => {
+                        if (this._inputref?.value.startsWith('=') || this._inputref?.value.startsWith(':=')) {
+                            this._overlayDisposer?.();
+                            this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
+                        }
+                    });
+                } else {
+                    this._overlayDisposer?.();
+                    this._overlayDisposer = undefined;
+                }
+            },
+            { fireImmediately: true }
+        );
+    }
+
     @action
     componentDidUpdate() {
         if (this._editing && this.props.editing === false) {
-            this._inputref.current?.value && this.finalizeEdit(this._inputref.current.value, false, true, false);
+            this._inputref?.value && this.finalizeEdit(this._inputref.value, false, true, false);
         } else if (this.props.editing !== undefined) {
             this._editing = this.props.editing;
         }
     }
 
     componentWillUnmount() {
-        this._inputref.current?.value && this.finalizeEdit(this._inputref.current.value, false, true, false);
+        this._overlayDisposer?.();
+        this._editingDisposer?.();
+        this._inputref?.value && this.finalizeEdit(this._inputref.value, false, true, false);
     }
 
+    onChange = (e: React.ChangeEvent) => {
+        const targVal = (e.target as any).value;
+        if (!(targVal.startsWith(':=') || targVal.startsWith('='))) {
+            this._overlayDisposer?.();
+            this._overlayDisposer = undefined;
+        } else if (!this._overlayDisposer) {
+            this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
+        }
+    };
+
     @action
-    onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
+    onKeyDown = (e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
         switch (e.key) {
             case 'Tab':
                 e.stopPropagation();
@@ -89,13 +127,15 @@ export class EditableView extends React.Component<EditableProps> {
                 if (!e.currentTarget.value) this.props.OnEmpty?.();
                 break;
             case 'Enter':
-                e.stopPropagation();
-                if (!e.ctrlKey) {
-                    this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, true);
-                } else if (this.props.OnFillDown) {
-                    this.props.OnFillDown(e.currentTarget.value);
-                    this._editing = false;
-                    this.props.isEditingCallback?.(false);
+                if (this.props.allowCRs !== true) {
+                    e.stopPropagation();
+                    if (!e.ctrlKey) {
+                        this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, true);
+                    } else if (this.props.OnFillDown) {
+                        this.props.OnFillDown(e.currentTarget.value);
+                        this._editing = false;
+                        this.props.isEditingCallback?.(false);
+                    }
                 }
                 break;
             case 'Escape':
@@ -103,9 +143,6 @@ export class EditableView extends React.Component<EditableProps> {
                 this._editing = false;
                 this.props.isEditingCallback?.(false);
                 break;
-            case ':':
-                this.props.menuCallback?.(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y);
-                break;
             case 'ArrowUp':
             case 'ArrowDown':
             case 'ArrowLeft':
@@ -117,6 +154,12 @@ export class EditableView extends React.Component<EditableProps> {
             case 'Meta':
             case 'Control':
                 break;
+            case ':':
+                if (this.props.menuCallback) {
+                    this.props.menuCallback(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y);
+                    break;
+                }
+
             default:
                 if (this.props.textCallback?.(e.key)) {
                     this._editing = false;
@@ -186,15 +229,32 @@ export class EditableView extends React.Component<EditableProps> {
                     onChange: this.props.autosuggestProps.onChange,
                 }}
             />
-        ) : (
+        ) : this.props.oneLine !== false && this.props.GetValue()?.toString().indexOf('\n') === -1 ? (
             <input
                 className="editableView-input"
-                ref={this._inputref}
+                ref={r => (this._inputref = r)}
                 style={{ display: this.props.display, overflow: 'auto', fontSize: this.props.fontSize, minWidth: 20, background: this.props.background }}
                 placeholder={this.props.placeholder}
                 onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)}
                 defaultValue={this.props.GetValue()}
                 autoFocus={true}
+                onChange={this.onChange}
+                onKeyDown={this.onKeyDown}
+                onKeyPress={this.stopPropagation}
+                onPointerDown={this.stopPropagation}
+                onClick={this.stopPropagation}
+                onPointerUp={this.stopPropagation}
+            />
+        ) : (
+            <textarea
+                className="editableView-input"
+                ref={r => (this._inputref = r)}
+                style={{ display: this.props.display, overflow: 'auto', fontSize: this.props.fontSize, minHeight: `min(100%, ${(this.props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, background: this.props.background }}
+                placeholder={this.props.placeholder}
+                onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)}
+                defaultValue={this.props.GetValue()}
+                autoFocus={true}
+                onChange={this.onChange}
                 onKeyDown={this.onKeyDown}
                 onKeyPress={this.stopPropagation}
                 onPointerDown={this.stopPropagation}
@@ -220,7 +280,7 @@ export class EditableView extends React.Component<EditableProps> {
             <div
                 className={`editableView-container-editing${this.props.oneLine ? '-oneLine' : ''}`}
                 ref={this._ref}
-                style={{ display: this.props.display, textOverflow: this.props.overflow, minHeight: '10px', whiteSpace: 'nowrap', height: this.props.height || 'auto', maxHeight: this.props.maxHeight }}
+                style={{ display: this.props.display, textOverflow: this.props.overflow, minHeight: '10px', whiteSpace: this.props.oneLine ? 'nowrap' : 'pre-line', height: this.props.height, maxHeight: this.props.maxHeight }}
                 //onPointerDown={this.stopPropagation}
                 onClick={this.onClick}
                 placeholder={this.props.placeholder}>
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 8fd2b87cc..556d9b6a0 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -8,14 +8,13 @@ import { GetEffectiveAcl } from '../../fields/util';
 import { unimplementedFunction, Utils } from '../../Utils';
 import { Docs, DocUtils } from '../documents/Documents';
 import { DragManager } from '../util/DragManager';
+import { FollowLinkScript } from '../util/LinkFollower';
 import { undoBatch, UndoManager } from '../util/UndoManager';
 import './MarqueeAnnotator.scss';
 import { DocumentView } from './nodes/DocumentView';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { AnchorMenu } from './pdf/AnchorMenu';
 import React = require('react');
-import { ScriptField } from '../../fields/ScriptField';
-import { FollowLinkScript } from '../util/LinkFollower';
 const _global = (window /* browser */ || global) /* node */ as any;
 
 export interface MarqueeAnnotatorProps {
diff --git a/src/client/views/ScriptingRepl.scss b/src/client/views/ScriptingRepl.scss
index 778e9c445..adc82238e 100644
--- a/src/client/views/ScriptingRepl.scss
+++ b/src/client/views/ScriptingRepl.scss
@@ -31,6 +31,9 @@
     border-radius: 25%;
     padding: 2px;
 }
+.documentIcon-outerDiv:hover {
+    opacity: 0.3;
+}
 
 .scriptingObject-icon {
     padding: 3px;
@@ -48,4 +51,4 @@
 
 .scriptingObject-leaf {
     margin-left: 15px;
-}
\ No newline at end of file
+}
diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx
index 4fecfa4d9..5dfe10def 100644
--- a/src/client/views/ScriptingRepl.tsx
+++ b/src/client/views/ScriptingRepl.tsx
@@ -10,34 +10,49 @@ import { OverlayView } from './OverlayView';
 import './ScriptingRepl.scss';
 
 @observer
-export class ScriptingObjectDisplay extends React.Component<{ scrollToBottom: () => void, value: { [key: string]: any }, name?: string }> {
+export class ScriptingObjectDisplay extends React.Component<{ scrollToBottom: () => void; value: { [key: string]: any }; name?: string }> {
     @observable collapsed = true;
 
     @action
     toggle = () => {
         this.collapsed = !this.collapsed;
         this.props.scrollToBottom();
-    }
+    };
 
     render() {
         const val = this.props.value;
         const proto = Object.getPrototypeOf(val);
         const name = (proto && proto.constructor && proto.constructor.name) || String(val);
-        const title = this.props.name ? <><b>{this.props.name} : </b>{name}</> : name;
+        const title = this.props.name ? (
+            <>
+                <b>{this.props.name} : </b>
+                {name}
+            </>
+        ) : (
+            name
+        );
         if (this.collapsed) {
             return (
                 <div className="scriptingObject-collapsed">
-                    <span onClick={this.toggle} className="scriptingObject-icon scriptingObject-iconCollapsed"><FontAwesomeIcon icon="caret-right" size="sm" /></span>{title} (+{Object.keys(val).length})
+                    <span onClick={this.toggle} className="scriptingObject-icon scriptingObject-iconCollapsed">
+                        <FontAwesomeIcon icon="caret-right" size="sm" />
+                    </span>
+                    {title} (+{Object.keys(val).length})
                 </div>
             );
         } else {
             return (
                 <div className="scriptingObject-open">
                     <div>
-                        <span onClick={this.toggle} className="scriptingObject-icon"><FontAwesomeIcon icon="caret-down" size="sm" /></span>{title}
+                        <span onClick={this.toggle} className="scriptingObject-icon">
+                            <FontAwesomeIcon icon="caret-down" size="sm" />
+                        </span>
+                        {title}
                     </div>
                     <div className="scriptingObject-fields">
-                        {Object.keys(val).map(key => <ScriptingValueDisplay {...this.props} name={key} />)}
+                        {Object.keys(val).map(key => (
+                            <ScriptingValueDisplay {...this.props} name={key} />
+                        ))}
                     </div>
                 </div>
             );
@@ -46,18 +61,32 @@ export class ScriptingObjectDisplay extends React.Component<{ scrollToBottom: ()
 }
 
 @observer
-export class ScriptingValueDisplay extends React.Component<{ scrollToBottom: () => void, value: any, name?: string }> {
+export class ScriptingValueDisplay extends React.Component<{ scrollToBottom: () => void; value: any; name?: string }> {
     render() {
         const val = this.props.name ? this.props.value[this.props.name] : this.props.value;
-        if (typeof val === "object") {
+        if (typeof val === 'object') {
             return <ScriptingObjectDisplay scrollToBottom={this.props.scrollToBottom} value={val} name={this.props.name} />;
-        } else if (typeof val === "function") {
-            const name = "[Function]";
-            const title = this.props.name ? <><b>{this.props.name} : </b>{name}</> : name;
+        } else if (typeof val === 'function') {
+            const name = '[Function]';
+            const title = this.props.name ? (
+                <>
+                    <b>{this.props.name} : </b>
+                    {name}
+                </>
+            ) : (
+                name
+            );
             return <div className="scriptingObject-leaf">{title}</div>;
         } else {
             const name = String(val);
-            const title = this.props.name ? <><b>{this.props.name} : </b>{name}</> : name;
+            const title = this.props.name ? (
+                <>
+                    <b>{this.props.name} : </b>
+                    {name}
+                </>
+            ) : (
+                name
+            );
             return <div className="scriptingObject-leaf">{title}</div>;
         }
     }
@@ -65,11 +94,11 @@ export class ScriptingValueDisplay extends React.Component<{ scrollToBottom: ()
 
 @observer
 export class ScriptingRepl extends React.Component {
-    @observable private commands: { command: string, result: any }[] = [];
+    @observable private commands: { command: string; result: any }[] = [];
     private commandsHistory: string[] = [];
 
-    @observable private commandString: string = "";
-    private commandBuffer: string = "";
+    @observable private commandString: string = '';
+    private commandBuffer: string = '';
 
     @observable private historyIndex: number = -1;
 
@@ -82,7 +111,7 @@ export class ScriptingRepl extends React.Component {
             transformer: context => {
                 const knownVars: { [name: string]: number } = {};
                 const usedDocuments: number[] = [];
-                ScriptingGlobals.getGlobals().forEach((global: any) => knownVars[global] = 1);
+                ScriptingGlobals.getGlobals().forEach((global: any) => (knownVars[global] = 1));
                 return root => {
                     function visit(node: ts.Node) {
                         let skip = false;
@@ -105,7 +134,7 @@ export class ScriptingRepl extends React.Component {
                                     const m = parseInt(match[1]);
                                     usedDocuments.push(m);
                                 } else {
-                                    return ts.createPropertyAccess(ts.createIdentifier("args"), node);
+                                    return ts.createPropertyAccess(ts.createIdentifier('args'), node);
                                 }
                             }
                         }
@@ -114,20 +143,20 @@ export class ScriptingRepl extends React.Component {
                     }
                     return ts.visitNode(root, visit);
                 };
-            }
+            },
         };
-    }
+    };
 
     @action
     onKeyDown = (e: React.KeyboardEvent) => {
         let stopProp = true;
         switch (e.key) {
-            case "Enter": {
+            case 'Enter': {
                 e.stopPropagation();
                 const docGlobals: { [name: string]: any } = {};
-                Array.from(DocumentManager.Instance.DocumentViews).forEach((dv, i) => docGlobals[`d${i}`] = dv.props.Document);
+                DocumentManager.Instance.DocumentViews.forEach((dv, i) => (docGlobals[`d${i}`] = dv.props.Document));
                 const globals = ScriptingGlobals.makeMutableGlobalsCopy(docGlobals);
-                const script = CompileScript(this.commandString, { typecheck: false, addReturn: true, editable: true, params: { args: "any" }, transformer: this.getTransformer(), globals });
+                const script = CompileScript(this.commandString, { typecheck: false, addReturn: true, editable: true, params: { args: 'any' }, transformer: this.getTransformer(), globals });
                 if (!script.compiled) {
                     this.commands.push({ command: this.commandString, result: script.errors });
                     return;
@@ -139,13 +168,13 @@ export class ScriptingRepl extends React.Component {
 
                     this.maybeScrollToBottom();
 
-                    this.commandString = "";
-                    this.commandBuffer = "";
+                    this.commandString = '';
+                    this.commandBuffer = '';
                     this.historyIndex = -1;
                 }
                 break;
             }
-            case "ArrowUp": {
+            case 'ArrowUp': {
                 if (this.historyIndex < this.commands.length - 1) {
                     this.historyIndex++;
                     if (this.historyIndex === 0) {
@@ -155,12 +184,12 @@ export class ScriptingRepl extends React.Component {
                 }
                 break;
             }
-            case "ArrowDown": {
+            case 'ArrowDown': {
                 if (this.historyIndex >= 0) {
                     this.historyIndex--;
                     if (this.historyIndex === -1) {
                         this.commandString = this.commandBuffer;
-                        this.commandBuffer = "";
+                        this.commandBuffer = '';
                     } else {
                         this.commandString = this.commandsHistory[this.commands.length - 1 - this.historyIndex];
                     }
@@ -176,25 +205,25 @@ export class ScriptingRepl extends React.Component {
             e.stopPropagation();
             e.preventDefault();
         }
-    }
+    };
 
     @action
     onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
         this.commandString = e.target.value;
-    }
+    };
 
     private shouldScroll: boolean = false;
     private maybeScrollToBottom = () => {
         const ele = this.commandsRef.current;
-        if (ele && ele.scrollTop === (ele.scrollHeight - ele.offsetHeight)) {
+        if (ele && ele.scrollTop === ele.scrollHeight - ele.offsetHeight) {
             this.shouldScroll = true;
             this.forceUpdate();
         }
-    }
+    };
 
     private scrollToBottom() {
         const ele = this.commandsRef.current;
-        ele && ele.scroll({ behavior: "auto", top: ele.scrollHeight });
+        ele && ele.scroll({ behavior: 'auto', top: ele.scrollHeight });
     }
 
     componentDidUpdate() {
@@ -206,15 +235,11 @@ export class ScriptingRepl extends React.Component {
 
     overlayDisposer?: () => void;
     onFocus = () => {
-        if (this.overlayDisposer) {
-            this.overlayDisposer();
-        }
+        this.overlayDisposer?.();
         this.overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
-    }
+    };
 
-    onBlur = () => {
-        this.overlayDisposer?.();
-    }
+    onBlur = () => this.overlayDisposer?.();
 
     render() {
         return (
@@ -229,14 +254,8 @@ export class ScriptingRepl extends React.Component {
                         );
                     })}
                 </div>
-                <input
-                    className="scriptingRepl-commandInput"
-                    onFocus={this.onFocus}
-                    onBlur={this.onBlur}
-                    value={this.commandString}
-                    onChange={this.onChange}
-                    onKeyDown={this.onKeyDown}></input>
+                <input className="scriptingRepl-commandInput" onFocus={this.onFocus} onBlur={this.onBlur} value={this.commandString} onChange={this.onChange} onKeyDown={this.onKeyDown}></input>
             </div>
         );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index f3397e2c4..99a68e94b 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -372,7 +372,8 @@
         .editableView-container-editing-oneLine,
         .editableView-container-editing {
             color: grey;
-            padding-top: 10px;
+            padding-top: 5px;
+            padding-bottom: 5px;
             width: 100%;
         }
 
@@ -387,7 +388,8 @@
             letter-spacing: 2px;
             color: grey;
             border: 0px;
-            padding-top: 10px; // 12px 10px 11px 10px;
+            padding-top: 5px; // 12px 10px 11px 10px;
+            padding-bottom: 5px; // 12px 10px 11px 10px;
         }
     }
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 29bdc0e2d..08e3174d1 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -53,7 +53,6 @@ import { MarqueeView } from './MarqueeView';
 import React = require('react');
 
 export type collectionFreeformViewProps = {
-    noPointerWheel?: () => boolean; // turn off pointerwheel interactions (see PDFViewer)
     NativeWidth?: () => number;
     NativeHeight?: () => number;
     originTopLeft?: boolean;
@@ -1023,13 +1022,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             deltaScale = 20 / invTransform.Scale;
         }
         if (deltaScale < 1 && invTransform.Scale <= NumCast(this.rootDoc._viewScaleMin, 1) && this.isAnnotationOverlay) {
+            this.setPan(0, 0);
             return;
         }
         if (deltaScale * invTransform.Scale < NumCast(this.rootDoc._viewScaleMin, 1) && this.isAnnotationOverlay) {
             deltaScale = NumCast(this.rootDoc._viewScaleMin, 1) / invTransform.Scale;
         }
 
-        const localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y);
+        const localTransform = invTransform.scaleAbout(deltaScale, x, y);
         if (localTransform.Scale >= 0.05 || localTransform.Scale > this.zoomScaling()) {
             const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20);
             this.props.Document[this.scaleFieldKey] = Math.abs(safeScale);
@@ -1039,17 +1039,19 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     onPointerWheel = (e: React.WheelEvent): void => {
-        if (this.props.noPointerWheel?.() || this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom
+        if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom
         PresBox.Instance?.pauseAutoPres();
         if (this.layoutDoc._Transform || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
         e.stopPropagation();
-        e.preventDefault();
         switch (!e.ctrlKey ? Doc.UserDoc().freeformScrollMode : freeformScrollMode.Pan) {
             case freeformScrollMode.Pan:
                 // if ctrl is selected then zoom
                 if (e.ctrlKey) {
                     if (this.props.isContentActive(true)) {
-                        this.zoom(e.clientX, e.clientY, e.deltaY); // if (!this.props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
+                        if (this.props.isAnnotationOverlayScrollable) {
+                            // bcz: zooming on a webbox doesn't get the correct coordinates here for unknown reasons.
+                            // so better to do nothing than having things jump around.
+                        } else this.zoom(e.screenX, e.screenY, e.deltaY);
                     }
                 } // otherwise pan
                 else if (this.props.isContentActive(true)) {
@@ -1123,16 +1125,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 (1 - minScale / scale) * NumCast(this.rootDoc._panYMax, nativeHeight) +
                 (!this.props.getScrollHeight?.() ? fitYscroll : 0); // when not zoomed, scrolling is handled via a scrollbar, not panning
             let newPanY = Math.max(minPanY, Math.min(maxPanY, panY));
-            if (NumCast(this.rootDoc.scrollTop) && NumCast(this.rootDoc._viewScale, minScale) !== minScale) {
+            if (false && NumCast(this.rootDoc.scrollTop) && NumCast(this.rootDoc._viewScale, minScale) !== minScale) {
                 const relTop = NumCast(this.rootDoc.scrollTop) / maxScrollTop;
                 this.rootDoc.scrollTop = undefined;
                 newPanY = minPanY + relTop * (maxPanY - minPanY);
             } else if (fitYscroll && this.rootDoc.scrollTop === undefined && NumCast(this.rootDoc._viewScale, minScale) === minScale) {
                 const maxPanY = minPanY + fitYscroll;
                 const relTop = (panY - minPanY) / (maxPanY - minPanY);
-                setTimeout(() => {
-                    this.rootDoc.scrollTop = relTop * maxScrollTop;
-                }, 10);
+                setTimeout(() => (this.rootDoc.scrollTop = relTop * maxScrollTop), 10);
                 newPanY = minPanY;
             }
             !this.Document._verticalScroll && (this.Document[this.panXFieldKey] = this.isAnnotationOverlay ? newPanX : panX);
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index a9434fde3..3a0c2c85c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -182,8 +182,10 @@
 .schema-table-cell,
 .row-menu {
     border: 1px solid $medium-gray;
-    overflow: hidden;
+    overflow-x: hidden;
+    overflow-y: auto;
     padding: 5px;
+    display: inline-block;
 }
 
 .schema-row {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index a59d7e5a3..588affc1c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -56,7 +56,8 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _documentOptions: DocumentOptions = new DocumentOptions();
     private _tableContentRef: HTMLDivElement | null = null;
 
-    public static _rowHeight: number = 50;
+    static _rowHeight: number = 50;
+    static _rowSingleLineHeight: number = 32;
     public static _minColWidth: number = 25;
     public static _rowMenuWidth: number = 60;
     public static _previewDividerWidth: number = 4;
@@ -515,9 +516,9 @@ export class CollectionSchemaView extends CollectionSubView() {
         if (found) {
             const rect = found.getBoundingClientRect();
             const localRect = this.props.ScreenToLocalTransform().transformBounds(rect.left, rect.top, rect.width, rect.height);
-            if (localRect.y < CollectionSchemaView._rowHeight || localRect.y + localRect.height > this.props.PanelHeight()) {
+            if (localRect.y < this.rowHeightFunc() || localRect.y + localRect.height > this.props.PanelHeight()) {
                 let focusSpeed = options.zoomTime ?? 50;
-                smoothScroll(focusSpeed, this._tableContentRef!, localRect.y + this._tableContentRef!.scrollTop - CollectionSchemaView._rowHeight, options.easeFunc);
+                smoothScroll(focusSpeed, this._tableContentRef!, localRect.y + this._tableContentRef!.scrollTop - this.rowHeightFunc(), options.easeFunc);
                 return focusSpeed;
             }
         }
@@ -836,6 +837,7 @@ export class CollectionSchemaView extends CollectionSubView() {
               });
         return { docs };
     }
+    rowHeightFunc = () => (BoolCast(this.layoutDoc._singleLine) ? CollectionSchemaView._rowSingleLineHeight : CollectionSchemaView._rowHeight);
     sortedDocsFunc = () => this.sortedDocs;
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
     screenToLocal = () => this.props.ScreenToLocalTransform().translate(-this.tableWidth, 0);
@@ -850,7 +852,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                         // prevent wheel events from passively propagating up through containers
                         r?.addEventListener('wheel', (e: WheelEvent) => {}, { passive: false });
                     }}>
-                    <div className="schema-header-row" style={{ height: CollectionSchemaView._rowHeight }}>
+                    <div className="schema-header-row" style={{ height: this.rowHeightFunc() }}>
                         <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}>
                             <div className="schema-header-button" onPointerDown={e => (this._columnMenuIndex === -1 ? this.closeColumnMenu() : this.openColumnMenu(-1, true))}>
                                 <FontAwesomeIcon icon="plus" />
@@ -865,6 +867,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 sortField={this.sortField}
                                 sortDesc={this.sortDesc}
                                 setSort={this.setSort}
+                                rowHeight={this.rowHeightFunc}
                                 removeColumn={this.removeColumn}
                                 resizeColumn={this.startResize}
                                 openContextMenu={this.openContextMenu}
@@ -875,7 +878,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     </div>
                     {this._columnMenuIndex !== undefined && this.renderColumnMenu}
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
-                    <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} setRef={(ref: HTMLDivElement | null) => (this._tableContentRef = ref)} />
+                    <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} rowHeight={this.rowHeightFunc} setRef={(ref: HTMLDivElement | null) => (this._tableContentRef = ref)} />
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} height={CollectionSchemaView._newNodeInputHeight} />
                 </div>
                 {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
@@ -922,20 +925,20 @@ interface CollectionSchemaViewDocsProps {
     schema: CollectionSchemaView;
     setRef: (ref: HTMLDivElement | null) => void;
     childDocs: () => { docs: Doc[] };
+    rowHeight: () => number;
 }
 
 @observer
 class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsProps> {
     tableWidthFunc = () => this.props.schema.tableWidth;
-    rowHeightFunc = () => CollectionSchemaView._rowHeight;
-    childScreenToLocal = computedFn((index: number) => () => this.props.schema.props.ScreenToLocalTransform().translate(0, -CollectionSchemaView._rowHeight - index * this.rowHeightFunc()));
+    childScreenToLocal = computedFn((index: number) => () => this.props.schema.props.ScreenToLocalTransform().translate(0, -this.props.rowHeight() - index * this.props.rowHeight()));
     render() {
         return (
-            <div className="schema-table-content" ref={this.props.setRef} style={{ height: `calc(100% - ${CollectionSchemaView._newNodeInputHeight + CollectionSchemaView._rowHeight}px)` }}>
+            <div className="schema-table-content" ref={this.props.setRef} style={{ height: `calc(100% - ${CollectionSchemaView._newNodeInputHeight + this.props.rowHeight()}px)` }}>
                 {this.props.childDocs().docs.map((doc: Doc, index: number) => {
                     const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.schema.props.DataDoc;
                     return (
-                        <div className="schema-row-wrapper" style={{ height: CollectionSchemaView._rowHeight }}>
+                        <div className="schema-row-wrapper" style={{ height: this.props.rowHeight() }}>
                             <DocumentView
                                 key={doc[Id]}
                                 {...this.props.schema.props}
@@ -945,7 +948,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 DataDoc={dataDoc}
                                 renderDepth={this.props.schema.props.renderDepth + 1}
                                 PanelWidth={this.tableWidthFunc}
-                                PanelHeight={this.rowHeightFunc}
+                                PanelHeight={this.props.rowHeight}
                                 styleProvider={DefaultStyleProvider}
                                 waitForDoubleClickToClick={returnNever}
                                 defaultDoubleClick={returnIgnore}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 243fe0c61..7da3c042c 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -16,6 +16,7 @@ export interface SchemaColumnHeaderProps {
     sortDesc: boolean;
     setSort: (field: string | undefined, desc?: boolean) => void;
     removeColumn: (index: number) => void;
+    rowHeight: () => number;
     resizeColumn: (e: any, index: number) => void;
     dragColumn: (e: any, index: number) => boolean;
     openContextMenu: (x: number, y: number, index: number) => void;
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index ca9e0bda0..34631e0b7 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -2,6 +2,9 @@ import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { computed } from 'mobx';
 import { observer } from 'mobx-react';
+import { computedFn } from 'mobx-utils';
+import { Doc } from '../../../../fields/Doc';
+import { BoolCast } from '../../../../fields/Types';
 import { DragManager } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
 import { undoBatch } from '../../../util/UndoManager';
@@ -12,8 +15,6 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
-import { computedFn } from 'mobx-utils';
-import { Doc } from '../../../../fields/Doc';
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -95,7 +96,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return (
             <div
                 className="schema-row"
-                style={{ height: CollectionSchemaView._rowHeight, backgroundColor: this.props.isSelected() ? Colors.LIGHT_BLUE : undefined }}
+                style={{ height: this.props.PanelHeight(), backgroundColor: this.props.isSelected() ? Colors.LIGHT_BLUE : undefined }}
                 onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
@@ -132,13 +133,16 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             Document={this.rootDoc}
                             col={index}
                             fieldKey={key}
+                            allowCRs={false} // to enter text with new lines, must use \n
                             columnWidth={this.columnWidth(index)}
+                            rowHeight={this.schemaView.rowHeightFunc}
                             isRowActive={this.props.isContentActive}
                             getFinfo={this.getFinfo}
                             selectCell={this.selectCell}
                             deselectCell={this.deselectCell}
                             selectedCell={this.selectedCell}
                             setColumnValues={this.setColumnValues}
+                            oneLine={BoolCast(this.schemaDoc?._singleLine)}
                         />
                     ))}
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 712bd4491..12daa1252 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -5,22 +5,24 @@ import { extname } from 'path';
 import DatePicker from 'react-datepicker';
 import { DateField } from '../../../../fields/DateField';
 import { Doc, DocListCast, Field } from '../../../../fields/Doc';
+import { RichTextField } from '../../../../fields/RichTextField';
 import { BoolCast, Cast, DateCast, FieldValue } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
 import { FInfo } from '../../../documents/Documents';
+import { DocFocusOrOpen } from '../../../util/DocumentManager';
 import { dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
 import { EditableView } from '../../EditableView';
 import { Colors } from '../../global/globalEnums';
+import { OpenWhere } from '../../nodes/DocumentView';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
+import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
-import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
+import { ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
-import { RichTextField } from '../../../../fields/RichTextField';
-import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 
 export interface SchemaTableCellProps {
     Document: Doc;
@@ -29,17 +31,24 @@ export interface SchemaTableCellProps {
     selectCell: (doc: Doc, col: number) => void;
     selectedCell: () => [Doc, number] | undefined;
     fieldKey: string;
+    maxWidth?: () => number;
     columnWidth: () => number;
+    rowHeight: () => number;
+    padding?: number; // default is 5 -- see scss
     isRowActive: () => boolean | undefined;
     getFinfo: (fieldKey: string) => FInfo | undefined;
     setColumnValues: (field: string, value: string) => boolean;
+    oneLine?: boolean; // whether all input should fit on one line vs allowing textare multiline inputs
+    allowCRs?: boolean; // allow carriage returns in text input (othewrise CR ends the edit)
+    finishEdit?: () => void; // notify container that edit is over (eg. to hide view in DashFieldView)
 }
 
 @observer
 export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
-    public static colRowHeightFunc() {
-        return CollectionSchemaView._rowHeight;
-    }
+    static addFieldDoc = (doc: Doc, where: OpenWhere) => {
+        DocFocusOrOpen(doc);
+        return true;
+    };
     public static renderProps(props: SchemaTableCellProps) {
         const { Document, fieldKey, getFinfo, columnWidth, isRowActive } = props;
         let protoCount = 0;
@@ -71,12 +80,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             whenChildContentsActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
-            addDocTab: returnFalse,
+            addDocTab: SchemaTableCell.addFieldDoc,
             pinToPres: returnZero,
             Document,
             fieldKey,
             PanelWidth: columnWidth,
-            PanelHeight: SchemaTableCell.colRowHeightFunc,
+            PanelHeight: props.rowHeight,
         };
         const readOnly = getFinfo(fieldKey)?.readOnly ?? false;
         const cursor = !readOnly ? 'text' : 'default';
@@ -98,8 +107,11 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                 style={{
                     color,
                     textDecoration,
+                    width: '100%',
                 }}>
                 <EditableView
+                    oneLine={this.props.oneLine}
+                    allowCRs={this.props.allowCRs}
                     contents={<FieldView {...fieldProps} />}
                     editing={this.selected ? undefined : false}
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
@@ -107,7 +119,9 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                         if (shiftDown && enterKey) {
                             this.props.setColumnValues(this.props.fieldKey.replace(/^_/, ''), value);
                         }
-                        return KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
+                        const ret = KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
+                        this.props.finishEdit?.();
+                        return ret;
                     })}
                 />
             </div>
@@ -121,7 +135,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         if (cellValue instanceof RichTextField) return ColumnType.RTF;
         if (typeof cellValue === 'number') return ColumnType.Any;
         if (typeof cellValue === 'string') return ColumnType.Any;
-        if (typeof cellValue === 'boolean') return ColumnType.Any;
+        if (typeof cellValue === 'boolean') return ColumnType.Boolean;
 
         const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
         if (columnTypeStr && columnTypeStr in FInfotoColType) {
@@ -148,7 +162,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             <div
                 className="schema-table-cell"
                 onPointerDown={action(e => !this.selected && this.props.selectCell(this.props.Document, this.props.col))}
-                style={{ width: this.props.columnWidth(), border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
+                style={{ padding: this.props.padding, maxWidth: this.props.maxWidth?.(), width: this.props.columnWidth() || undefined, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
                 {this.content}
             </div>
         );
@@ -211,8 +225,8 @@ export class SchemaImageCell extends React.Component<SchemaTableCellProps> {
         const aspect = Doc.NativeAspect(this.props.Document); // aspect ratio
         // let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
         // const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
-        const height = CollectionSchemaView._rowHeight - 10;
-        const width = height * aspect; // increase the width of the image if necessary to maintain proportionality
+        const height = this.props.rowHeight() ? this.props.rowHeight() - (this.props.padding || 6) * 2 : undefined;
+        const width = height ? height * aspect : undefined; // increase the width of the image if necessary to maintain proportionality
 
         return <img src={this.url} width={width} height={height} style={{}} draggable="false" onPointerEnter={this.showHoverPreview} onPointerMove={this.moveHoverPreview} onPointerLeave={this.removeHoverPreview} />;
     }
@@ -288,7 +302,9 @@ export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
                         if (shiftDown && enterKey) {
                             this.props.setColumnValues(this.props.fieldKey.replace(/^_/, ''), value);
                         }
-                        return KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
+                        const set = KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
+                        this.props.finishEdit?.();
+                        return set;
                     })}
                 />
             </div>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index a8c8a0d2e..862d0da8c 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -12,12 +12,11 @@ import { SelectionManager } from '../../util/SelectionManager';
 import { Transform } from '../../util/Transform';
 import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
 import { DocComponent } from '../DocComponent';
+import { InkingStroke } from '../InkingStroke';
 import { StyleProp } from '../StyleProvider';
 import './CollectionFreeFormDocumentView.scss';
 import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView';
 import React = require('react');
-import { DocumentType } from '../../documents/DocumentTypes';
-import { InkingStroke } from '../InkingStroke';
 
 export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
     dataProvider?: (doc: Doc, replica: string) => { x: number; y: number; zIndex?: number; rotation?: number; color?: string; backgroundColor?: string; opacity?: number; highlight?: boolean; z: number; transition?: string } | undefined;
diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx
index 56de2d1fc..6e2ed72b8 100644
--- a/src/client/views/nodes/DocumentIcon.tsx
+++ b/src/client/views/nodes/DocumentIcon.tsx
@@ -1,23 +1,39 @@
-
-import { observer } from "mobx-react";
-import * as React from "react";
-import { DocumentView } from "./DocumentView";
-import { DocumentManager } from "../../util/DocumentManager";
-import { Transformer, ts } from "../../util/Scripting";
-import { Field } from "../../../fields/Doc";
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { DocumentView } from './DocumentView';
+import { DocumentManager } from '../../util/DocumentManager';
+import { Transformer, ts } from '../../util/Scripting';
+import { Field } from '../../../fields/Doc';
+import { Tooltip } from '@material-ui/core';
+import { action, observable } from 'mobx';
+import { Id } from '../../../fields/FieldSymbols';
+import { factory } from 'typescript';
+import { LightboxView } from '../LightboxView';
 
 @observer
-export class DocumentIcon extends React.Component<{ view: DocumentView, index: number }> {
+export class DocumentIcon extends React.Component<{ view: DocumentView; index: number }> {
+    @observable _hovered = false;
+    static get DocViews() {
+        return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.IsLightboxDocView(v.props.docViewPath())) : DocumentManager.Instance.DocumentViews;
+    }
     render() {
         const view = this.props.view;
         const { left, top, right, bottom } = view.getBounds() || { left: 0, top: 0, right: 0, bottom: 0 };
 
         return (
-            <div className="documentIcon-outerDiv" style={{
-                position: "absolute",
-                transform: `translate(${(left + right) / 2}px, ${top}px)`,
-            }}>
-                <p>d{this.props.index}</p>
+            <div
+                className="documentIcon-outerDiv"
+                onPointerEnter={action(e => (this._hovered = true))}
+                onPointerLeave={action(e => (this._hovered = false))}
+                style={{
+                    pointerEvents: 'all',
+                    opacity: this._hovered ? 0.3 : 1,
+                    position: 'absolute',
+                    transform: `translate(${(left + right) / 2}px, ${top}px)`,
+                }}>
+                <Tooltip title={<>{this.props.view.rootDoc.title}</>}>
+                    <p>d{this.props.index}</p>
+                </Tooltip>
             </div>
         );
     }
@@ -41,7 +57,9 @@ export class DocumentIconContainer extends React.Component {
                                 const match = node.text.match(/d([0-9]+)/);
                                 if (match) {
                                     const m = parseInt(match[1]);
+                                    const doc = DocumentIcon.DocViews[m].rootDoc;
                                     usedDocuments.add(m);
+                                    return factory.createIdentifier(`idToDoc("${doc[Id]}")`);
                                 }
                             }
                         }
@@ -52,14 +70,14 @@ export class DocumentIconContainer extends React.Component {
                 };
             },
             getVars() {
-                const docs = Array.from(DocumentManager.Instance.DocumentViews);
+                const docs = DocumentIcon.DocViews;
                 const capturedVariables: { [name: string]: Field } = {};
-                usedDocuments.forEach(index => capturedVariables[`d${index}`] = docs[index].props.Document);
-                return { capturedVariables };
-            }
+                usedDocuments.forEach(index => (capturedVariables[`d${index}`] = docs.length > index ? docs[index].props.Document : `d${index}`));
+                return capturedVariables;
+            },
         };
     }
     render() {
-        return Array.from(DocumentManager.Instance.DocumentViews).map((dv, i) => <DocumentIcon key={i} index={i} view={dv} />);
+        return DocumentIcon.DocViews.map((dv, i) => <DocumentIcon key={i} index={i} view={dv} />);
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b61a468bd..ffbde18ca 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -48,6 +48,7 @@ import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
 import React = require('react');
 import { InkingStroke } from '../InkingStroke';
+import { RefField } from '../../../fields/RefField';
 const { Howl } = require('howler');
 
 interface Window {
@@ -127,6 +128,7 @@ export interface DocComponentView {
     IsPlaying?: () => boolean; // is a media document playing
     TogglePause?: (keep?: boolean) => void; // toggle media document playing state
     setFocus?: () => void; // sets input focus to the componentView
+    setData?: (data: Field | Promise<RefField | undefined>) => boolean;
     componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null;
     incrementalRendering?: () => void;
     fitWidth?: () => boolean; // whether the component always fits width (eg, KeyValueBox)
@@ -434,7 +436,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                         }, console.log  );
                     UndoManager.RunInBatch(() => (func().result?.select === true ? this.props.select(false) : ''), 'on double click');
                 } else if (!Doc.IsSystem(this.rootDoc) && (defaultDblclick === undefined || defaultDblclick === 'default')) {
-                    UndoManager.RunInBatch(() => this.props.addDocTab(this.rootDoc, OpenWhere.lightbox), 'double tap');
+                    UndoManager.RunInBatch(() => LightboxView.AddDocTab(this.rootDoc, OpenWhere.lightbox), 'double tap');
                     SelectionManager.DeselectAll();
                     Doc.UnBrushDoc(this.props.Document);
                 } else {
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index e317de11e..f3c8ba62d 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -20,6 +20,10 @@ import { ImageBox } from './ImageBox';
 import './KeyValueBox.scss';
 import { KeyValuePair } from './KeyValuePair';
 import React = require('react');
+import { DocumentManager } from '../../util/DocumentManager';
+import { ScriptingGlobals } from '../../util/ScriptingGlobals';
+import { ScriptingRepl } from '../ScriptingRepl';
+import { DocumentIconContainer } from './DocumentIcon';
 
 export type KVPScript = {
     script: CompiledScript;
@@ -75,7 +79,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
         value = dubEq ? value.substring(2) : value;
         const options: ScriptOptions = { addReturn: true, typecheck: false, params: { this: Doc.name, self: Doc.name, _last_: 'any', _readOnly_: 'boolean' }, editable: true };
         if (dubEq) options.typecheck = false;
-        const script = CompileScript(value, options);
+        const script = CompileScript(value, { ...options, transformer: DocumentIconContainer.getTransformer() });
         return !script.compiled ? undefined : { script, type: dubEq, onDelegate: eq };
     }
 
diff --git a/src/client/views/nodes/KeyValuePair.scss b/src/client/views/nodes/KeyValuePair.scss
index 5b660e582..57d36932e 100644
--- a/src/client/views/nodes/KeyValuePair.scss
+++ b/src/client/views/nodes/KeyValuePair.scss
@@ -1,60 +1,52 @@
-@import "../global/globalCssVariables";
-
+@import '../global/globalCssVariables';
 
 .keyValuePair-td-key {
-    display:inline-block;
+    display: inline-block;
 
-    .keyValuePair-td-key-container{
-        width:100%;
-        height:100%;
-        display: flex;                 
-        flex-direction: row;           
-        flex-wrap: nowrap;              
-        justify-content: space-between; 
-        align-items: center;
-        .keyValuePair-td-key-delete{
+    .keyValuePair-td-key-container {
+        width: 100%;
+        height: 100%;
+        display: flex;
+        flex-direction: row;
+        flex-wrap: nowrap;
+        justify-content: space-between;
+        .keyValuePair-td-key-delete {
             position: relative;
             background-color: transparent;
-            color:red;
+            color: red;
         }
         .keyValuePair-td-key-check {
             position: relative;
             margin: 0;
         }
         .keyValuePair-keyField {
-            width:100%;
+            width: 100%;
             margin-left: 20px;
-            margin-top: -1px;
             font-family: monospace;
-            // text-align: center;
-            align-self: center;
             position: relative;
             overflow: auto;
+            display: inline;
         }
     }
 }
 .keyValuePair-td-value {
-    display:inline-block;
+    display: inline-block;
     overflow: scroll;
     font-family: monospace;
     height: 30px;
-        .keyValuePair-td-value-container {
-            display: flex;
-            align-items: center;
-            align-content: center;
-            flex-direction: row;
-            justify-content: space-between;
-            flex-wrap: nowrap;
-            width: 100%;
-            height: 100%;
+    .keyValuePair-td-value-container {
+        display: inline;
+        justify-content: space-between;
+        width: 100%;
+        height: 100%;
 
-            img { 
-                max-height: 36px;
-                width: auto;
-            }
-            .videoBox-cont{
-                width: auto; 
-                max-height: 36px; 
-            }
+        img {
+            max-height: 36px;
+            width: auto;
+        }
+        .videoBox-cont {
+            width: auto;
+            max-height: 36px;
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 7ea6d42ff..85641124f 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -118,13 +118,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
                 </td>
                 <td className="keyValuePair-td-value" style={{ width: `${100 - this.props.keyWidth}%` }} onContextMenu={this.onContextMenu}>
                     <div className="keyValuePair-td-value-container">
-                        <EditableView
-                            contents={contents}
-                            maxHeight={36}
-                            height={'auto'}
-                            GetValue={() => Field.toKeyValueString(props.Document, props.fieldKey)}
-                            SetValue={(value: string) => KeyValueBox.SetField(props.Document, props.fieldKey, value)}
-                        />
+                        <EditableView contents={contents} GetValue={() => Field.toKeyValueString(props.Document, props.fieldKey)} SetValue={(value: string) => KeyValueBox.SetField(props.Document, props.fieldKey, value)} />
                     </div>
                 </td>
             </tr>
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index e05b48c0b..82c8e796d 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -2,16 +2,16 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as WebRequest from 'web-request';
-import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
+import { Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { HtmlField } from '../../../fields/HtmlField';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
-import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, ImageCast, NumCast, StrCast, WebCast } from '../../../fields/Types';
 import { ImageField, WebField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, getWordAtPoint, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from '../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, getWordAtPoint, removeStyleSheetRule, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from '../../util/DragManager';
@@ -31,12 +31,13 @@ import { Annotation } from '../pdf/Annotation';
 import { GPTPopup } from '../pdf/GPTPopup/GPTPopup';
 import { SidebarAnnos } from '../SidebarAnnos';
 import { StyleProp } from '../StyleProvider';
-import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from './DocumentView';
+import { DocComponentView, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
 import { LinkDocPreview } from './LinkDocPreview';
 import { PinProps, PresBox } from './trails';
 import './WebBox.scss';
 import React = require('react');
+import { RefField } from '../../../fields/RefField';
 const { CreateImage } = require('./WebBoxRenderer');
 const _global = (window /* browser */ || global) /* node */ as any;
 const htmlToText = require('html-to-text');
@@ -47,6 +48,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     }
     public static openSidebarWidth = 250;
     public static sidebarResizerWidth = 5;
+    static webStyleSheet = addStyleSheet();
     private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void);
     private _setBrushViewer: undefined | ((view: { width: number; height: number; panX: number; panY: number }) => void);
     private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
@@ -58,15 +60,15 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     private _sidebarRef = React.createRef<SidebarAnnos>();
     private _searchRef = React.createRef<HTMLInputElement>();
     private _searchString = '';
+    private _scrollTimer: any;
 
     private get _getAnchor() {
         return AnchorMenu.Instance?.GetAnchor;
     }
-    @observable private _webUrl = ''; // url of the src parameter of the embedded iframe but not necessarily the rendered page - eg, when following a link, the rendered page changes but we don't wan the src parameter to also change as that would cause an unnecessary re-render.
+    @observable private _webUrl = ''; // url of the src parameter of the embedded iframe but not necessarily the rendered page - eg, when following a link, the rendered page changes but we don't want the src parameter to also change as that would cause an unnecessary re-render.
     @observable private _hackHide = false; // apparently changing the value of the 'sandbox' prop doesn't necessarily apply it to the active iframe.  so thisforces the ifrmae to be rebuilt when allowScripts is toggled
     @observable private _searching: boolean = false;
     @observable private _showSidebar = false;
-    @observable private _scrollTimer: any;
     @observable private _webPageHasBeenRendered = false;
     @observable private _overlayAnnoInfo: Opt<Doc>;
     @observable private _marqueeing: number[] | undefined;
@@ -141,51 +143,40 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
 
     updateThumb = async () => {
-        const imageBitmap = ImageCast(this.layoutDoc['thumb-frozen'])?.url.href;
+        if (!this._iframe) return;
         const scrollTop = NumCast(this.layoutDoc._scrollTop);
         const nativeWidth = NumCast(this.layoutDoc.nativeWidth);
         const nativeHeight = (nativeWidth * this.props.PanelHeight()) / this.props.PanelWidth();
-        if (
-            !this.props.isSelected(true) &&
-            !Doc.IsBrushedDegree(this.rootDoc) &&
-            !this.isAnyChildContentActive() &&
-            !this.rootDoc.thumbLockout &&
-            !this.props.dontRegisterView &&
-            this._iframe &&
-            !imageBitmap &&
-            (scrollTop !== this.layoutDoc.thumbScrollTop || nativeWidth !== this.layoutDoc.thumbNativeWidth || nativeHeight !== this.layoutDoc.thumbNativeHeight)
-        ) {
-            var htmlString = this._iframe.contentDocument && new XMLSerializer().serializeToString(this._iframe.contentDocument);
-            if (!htmlString) {
-                htmlString = await (await fetch(Utils.CorsProxy(this.webField!.href))).text();
-            }
-            this.layoutDoc.thumb = undefined;
-            this.rootDoc.thumbLockout = true; // lock to prevent multiple thumb updates.
-            CreateImage(this._webUrl.endsWith('/') ? this._webUrl.substring(0, this._webUrl.length - 1) : this._webUrl, this._iframe.contentDocument?.styleSheets ?? [], htmlString, nativeWidth, nativeHeight, scrollTop)
-                .then((data_url: any) => {
-                    if (data_url.includes('<!DOCTYPE')) {
-                        console.log('BAD DATA IN THUMB CREATION');
-                        return;
-                    }
-                    Utils.convertDataUri(data_url, this.layoutDoc[Id] + '-icon' + new Date().getTime(), true, this.layoutDoc[Id] + '-icon').then(returnedfilename =>
-                        setTimeout(
-                            action(() => {
-                                this.rootDoc.thumbLockout = false;
-                                this.layoutDoc.thumb = new ImageField(returnedfilename);
-                                this.layoutDoc.thumbScrollTop = scrollTop;
-                                this.layoutDoc.thumbNativeWidth = nativeWidth;
-                                this.layoutDoc.thumbNativeHeight = nativeHeight;
-                            }),
-                            500
-                        )
-                    );
-                })
-                .catch(function (error: any) {
-                    console.error('oops, something went wrong!', error);
-                });
+        var htmlString = this._iframe.contentDocument && new XMLSerializer().serializeToString(this._iframe.contentDocument);
+        if (!htmlString) {
+            htmlString = await (await fetch(Utils.CorsProxy(this.webField!.href))).text();
         }
+        this.layoutDoc.thumb = undefined;
+        this.rootDoc.thumbLockout = true; // lock to prevent multiple thumb updates.
+        CreateImage(this._webUrl.endsWith('/') ? this._webUrl.substring(0, this._webUrl.length - 1) : this._webUrl, this._iframe.contentDocument?.styleSheets ?? [], htmlString, nativeWidth, nativeHeight, scrollTop)
+            .then((data_url: any) => {
+                if (data_url.includes('<!DOCTYPE')) {
+                    console.log('BAD DATA IN THUMB CREATION');
+                    return;
+                }
+                Utils.convertDataUri(data_url, this.layoutDoc[Id] + '-icon' + new Date().getTime(), true, this.layoutDoc[Id] + '-icon').then(returnedfilename =>
+                    setTimeout(
+                        action(() => {
+                            this.rootDoc.thumbLockout = false;
+                            this.layoutDoc.thumb = new ImageField(returnedfilename);
+                            this.layoutDoc.thumbScrollTop = scrollTop;
+                            this.layoutDoc.thumbNativeWidth = nativeWidth;
+                            this.layoutDoc.thumbNativeHeight = nativeHeight;
+                        }),
+                        500
+                    )
+                );
+            })
+            .catch(function (error: any) {
+                console.error('oops, something went wrong!', error);
+            });
     };
-    _thumbTimer: any;
+
     async componentDidMount() {
         this.props.setContentView?.(this); // this tells the DocumentView that this WebBox is the "content" of the document.  this allows the DocumentView to call WebBox relevant methods to configure the UI (eg, show back/forward buttons)
 
@@ -196,24 +187,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             reqdFuncs[this.fieldKey + '-annotations'] = `copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"])`;
             reqdFuncs[this.fieldKey + '-annotations-setter'] = `this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"] = value`;
             reqdFuncs[this.fieldKey + '-sidebar'] = `copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"])`;
-            DocUtils.AssignScripts(this.rootDoc, {}, reqdFuncs);
+            DocUtils.AssignScripts(this.dataDoc, {}, reqdFuncs);
         });
-        reaction(
-            () => this.props.isSelected(true) || this.isAnyChildContentActive() || Doc.isBrushedHighlightedDegree(this.props.Document),
-            async selected => {
-                if (selected) {
-                    this._thumbTimer && clearTimeout(this._thumbTimer);
-                    this._webPageHasBeenRendered = true;
-                } else if (
-                    (!this.props.isContentActive(true) || SnappingManager.GetIsDragging()) && // update thumnail when unselected AND (no child annotation is active OR we've started dragging the document in which case no additional deselect will occur so this is the only chance to update the thumbnail)
-                    LightboxView.LightboxDoc !== this.rootDoc
-                ) {
-                    // don't create a thumbnail if entering Lightbox from maximize either, since thumb will be empty.
-                    this._thumbTimer && clearTimeout(this._thumbTimer);
-                    this._thumbTimer = setTimeout(this.updateThumb, 2000);
-                }
-            },
-            { fireImmediately: this.props.isSelected(true) || this.isAnyChildContentActive() || (Doc.isBrushedHighlightedDegreeUnmemoized(this.props.Document) ? true : false) }
+        this._disposers.urlchange = reaction(
+            () => WebCast(this.rootDoc.data),
+            url => {
+                this.submitURL(url.url.href, false, false);
+            }
         );
 
         this._disposers.autoHeight = reaction(
@@ -296,8 +276,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return this._savedAnnotations;
     };
 
-    menuControls = () => this.urlEditor; // controls to be added to the top bar when a document of this type is selected
-
     setBrushViewer = (func?: (view: { width: number; height: number; panX: number; panY: number }) => void) => (this._setBrushViewer = func);
     brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._setBrushViewer?.(view);
     focus = (anchor: Doc, options: DocFocusOptions) => {
@@ -316,9 +294,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         }
     };
 
-    getView = async (doc: Doc) => {
+    @action
+    getView = (doc: Doc) => {
         if (this.rootDoc.layoutKey === 'layout_icon') this.props.DocumentView?.().iconify();
-        if (this._url && StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl));
+        if (this._url && WebCast(doc.presData).url.href !== this._url) this.setData(WebCast(doc.presData).url.href);
         if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(false);
         return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
     };
@@ -341,13 +320,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         } catch (e) {}
         const anchor =
             this._getAnchor(this._savedAnnotations, false) ??
-            Docs.Create.WebanchorDocument(this._url, {
+            Docs.Create.WebanchorDocument({
                 title: StrCast(this.rootDoc.title + ' ' + this.layoutDoc._scrollTop),
                 y: NumCast(this.layoutDoc._scrollTop),
                 unrendered: true,
                 annotationOn: this.rootDoc,
             });
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true, pannable: true } }, this.rootDoc);
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: pinProps?.pinData ? true : false, pannable: true } }, this.rootDoc);
         anchor.text = ele?.textContent ?? '';
         anchor.textHtml = ele?.innerHTML;
         //addAsAnnotation &&
@@ -413,7 +392,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     iframeClick = () => this._iframeClick;
     iframeScaling = () => 1 / this.props.ScreenToLocalTransform().Scale;
 
-    addStyleSheet(document: any, styleType: string = 'text/css') {
+    addWebStyleSheet(document: any, styleType: string = 'text/css') {
         if (document) {
             const style = document.createElement('style');
             style.type = styleType;
@@ -421,7 +400,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             return (sheets as any).sheet;
         }
     }
-    addStyleSheetRule(sheet: any, selector: any, css: any, selectorPrefix = '.') {
+    addWebStyleSheetRule(sheet: any, selector: any, css: any, selectorPrefix = '.') {
         const propText =
             typeof css === 'string'
                 ? css
@@ -438,8 +417,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (this._initialScroll !== undefined) {
             this.setScrollPos(this._initialScroll);
         }
-
-        this.addStyleSheetRule(this.addStyleSheet(this._iframe?.contentDocument), '::selection', { color: 'white', background: 'orange' }, '');
+        this._scrollHeight = this._iframe?.contentDocument?.body?.scrollHeight ?? 0;
+        this.addWebStyleSheetRule(this.addWebStyleSheet(this._iframe?.contentDocument), '::selection', { color: 'white', background: 'orange' }, '');
 
         let href: Opt<string>;
         try {
@@ -463,12 +442,19 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     .replace('search&', 'search?')
                     .replace('?gbv=1', '');
             }
-            this.submitURL(requrlraw, undefined, true);
+            this.setData(requrlraw);
         }
         const iframeContent = iframe?.contentDocument;
         if (iframeContent) {
             iframeContent.addEventListener('pointerup', this.iframeUp);
             iframeContent.addEventListener('pointerdown', this.iframeDown);
+            // iframeContent.addEventListener(
+            //     'wheel',
+            //     e => {
+            //         e.ctrlKey && e.preventDefault();
+            //     },
+            //     { passive: false }
+            // );
             const initHeights = () => {
                 this._scrollHeight = Math.max(this._scrollHeight, (iframeContent.body.children[0] as any)?.scrollHeight || 0);
                 if (this._scrollHeight) {
@@ -482,11 +468,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 action(() => initHeights),
                 5000
             );
-            iframe.setAttribute('enable-annotation', 'true');
             iframeContent.addEventListener(
                 'click',
                 undoBatch(
                     action((e: MouseEvent) => {
+                        const batch = UndoManager.StartBatch('webclick');
                         let href = '';
                         for (let ele = e.target as any; ele; ele = ele.parentElement) {
                             href = (typeof ele.href === 'string' ? ele.href : ele.href?.baseVal) || ele.parentElement?.href || href;
@@ -494,7 +480,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         const origin = this.webField?.origin;
                         if (href && origin) {
                             e.stopPropagation();
-                            setTimeout(() => this.submitURL(href.replace(Utils.prepend(''), origin)));
+                            setTimeout(() => {
+                                this.setData(href.replace(Utils.prepend(''), origin));
+                                batch.end();
+                            });
                             if (this._outerRef.current) {
                                 this._outerRef.current.scrollTop = NumCast(this.layoutDoc._scrollTop);
                                 this._outerRef.current.scrollLeft = 0;
@@ -503,39 +492,49 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     })
                 )
             );
-            iframe.contentDocument.addEventListener('wheel', this.iframeWheel, false);
-            //iframe.contentDocument.addEventListener('scroll', () => !this.active() && this._iframe && (this._iframe.scrollTop = NumCast(this.layoutDoc._scrollTop), false));
+            iframe.contentDocument.addEventListener('wheel', this.iframeWheel, { passive: false });
         }
     };
 
     @action
-    iframeWheel = (e: any) => {
+    iframeWheel = (e: WheelEvent) => {
         if (!this._scrollTimer) {
-            this._scrollTimer = setTimeout(
-                action(() => (this._scrollTimer = undefined)),
-                250
-            ); // this turns events off on the iframe which allows scrolling to change direction smoothly
+            addStyleSheetRule(WebBox.webStyleSheet, 'webBox-iframe', { 'pointer-events': 'none' });
+            this._scrollTimer = setTimeout(() => {
+                this._scrollTimer = undefined;
+                clearStyleSheetRules(WebBox.webStyleSheet);
+            }, 250); // this turns events off on the iframe which allows scrolling to change direction smoothly
+        }
+        if (e.ctrlKey) {
+            if (this._innerCollectionView) {
+                this._innerCollectionView.zoom(e.screenX, e.screenY, e.deltaY);
+                const offset = e.clientY - NumCast(this.layoutDoc._scrollTop);
+                this.layoutDoc.panY = offset - offset / NumCast(this.layoutDoc._viewScale) + NumCast(this.layoutDoc._scrollTop) - NumCast(this.layoutDoc._scrollTop) / NumCast(this.layoutDoc._viewScale);
+            }
+            e.preventDefault();
         }
     };
 
     @action
     setDashScrollTop = (scrollTop: number, timeout: number = 250) => {
         const iframeHeight = Math.max(scrollTop, this._scrollHeight - this.panelHeight());
-        this._scrollTimer && clearTimeout(this._scrollTimer);
-        this._scrollTimer = setTimeout(
-            action(() => {
-                this._scrollTimer = undefined;
-                const newScrollTop = scrollTop > iframeHeight ? iframeHeight : scrollTop;
-                if (!LinkDocPreview.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()))) {
-                    this.layoutDoc.thumb = undefined;
-                    this.layoutDoc.thumbScrollTop = undefined;
-                    this.layoutDoc.thumbNativeWidth = undefined;
-                    this.layoutDoc.thumbNativeHeight = undefined;
-                    this.layoutDoc.scrollTop = this._outerRef.current.scrollTop = newScrollTop;
-                } else if (this._outerRef.current) this._outerRef.current.scrollTop = newScrollTop;
-            }),
-            timeout
-        );
+        if (this._scrollTimer) {
+            clearTimeout(this._scrollTimer);
+            clearStyleSheetRules(WebBox.webStyleSheet);
+        }
+        addStyleSheetRule(WebBox.webStyleSheet, 'webBox-iframe', { 'pointer-events': 'none' });
+        this._scrollTimer = setTimeout(() => {
+            clearStyleSheetRules(WebBox.webStyleSheet);
+            this._scrollTimer = undefined;
+            const newScrollTop = scrollTop > iframeHeight ? iframeHeight : scrollTop;
+            if (!LinkDocPreview.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()))) {
+                this.layoutDoc.thumb = undefined;
+                this.layoutDoc.thumbScrollTop = undefined;
+                this.layoutDoc.thumbNativeWidth = undefined;
+                this.layoutDoc.thumbNativeHeight = undefined;
+                this.layoutDoc.scrollTop = this._outerRef.current.scrollTop = newScrollTop;
+            } else if (this._outerRef.current) this._outerRef.current.scrollTop = newScrollTop;
+        }, timeout);
     };
 
     goTo = (scrollTop: number, duration: number, easeFunc: 'linear' | 'ease' | undefined) => {
@@ -557,8 +556,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         runInAction(() => {
             if (future.length) {
                 const curUrl = this._url;
-                this.rootDoc[this.fieldKey + '-history'] = new List<string>([...history, this._url]);
-                this.rootDoc[this.fieldKey] = new WebField(new URL(future.pop()!));
+                this.dataDoc[this.fieldKey + '-history'] = new List<string>([...history, this._url]);
+                this.dataDoc[this.fieldKey] = new WebField(new URL(future.pop()!));
+                this._scrollHeight = 0;
                 if (this._webUrl === this._url) {
                     this._webUrl = curUrl;
                     setTimeout(action(() => (this._webUrl = this._url)));
@@ -578,9 +578,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         runInAction(() => {
             if (history.length) {
                 const curUrl = this._url;
-                if (future === undefined) this.rootDoc[this.fieldKey + '-future'] = new List<string>([this._url]);
-                else this.rootDoc[this.fieldKey + '-future'] = new List<string>([...future, this._url]);
-                this.layoutDoc[this.fieldKey] = new WebField(new URL(history.pop()!));
+                if (future === undefined) this.dataDoc[this.fieldKey + '-future'] = new List<string>([this._url]);
+                else this.dataDoc[this.fieldKey + '-future'] = new List<string>([...future, this._url]);
+                this.dataDoc[this.fieldKey] = new WebField(new URL(history.pop()!));
+                this._scrollHeight = 0;
                 if (this._webUrl === this._url) {
                     this._webUrl = curUrl;
                     setTimeout(action(() => (this._webUrl = this._url)));
@@ -607,23 +608,18 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (!newUrl) return;
         if (!newUrl.startsWith('http')) newUrl = 'http://' + newUrl;
         try {
-            const future = Cast(this.rootDoc[this.fieldKey + '-future'], listSpec('string'));
-            const history = Cast(this.rootDoc[this.fieldKey + '-history'], listSpec('string'));
-            const url = this.webField?.toString();
-            if (url && !preview) {
-                this.rootDoc[this.fieldKey + '-history'] = new List<string>([...(history || []), url]);
-                this.layoutDoc._scrollTop = 0;
+            if (!preview) {
                 if (this._webPageHasBeenRendered) {
                     this.layoutDoc.thumb = undefined;
                     this.layoutDoc.thumbScrollTop = undefined;
                     this.layoutDoc.thumbNativeWidth = undefined;
                     this.layoutDoc.thumbNativeHeight = undefined;
                 }
-                future && (future.length = 0);
             }
             if (!preview) {
-                this.layoutDoc[this.fieldKey] = new WebField(new URL(newUrl));
-                !dontUpdateIframe && (this._webUrl = this._url);
+                if (!dontUpdateIframe) {
+                    this._webUrl = this._url;
+                }
             }
         } catch (e) {
             console.log('WebBox URL error:' + this._url);
@@ -637,48 +633,28 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const uri = dataTransfer.getData('text/uri-list');
         const url = uri || html || this._url || '';
         const newurl = url.startsWith(window.location.origin) ? url.replace(window.location.origin, this._url?.match(/http[s]?:\/\/[^\/]*/)?.[0] || '') : url;
-        this.submitURL(newurl);
+        this.setData(newurl);
         e.stopPropagation();
     };
+
+    @action
+    setData = (data: Field | Promise<RefField | undefined>) => {
+        if (!(typeof data === 'string') && !(data instanceof WebField)) return false;
+        if (Field.toString(data) === this._url) return false;
+        this._scrollHeight = 0;
+        const oldUrl = this._url;
+        const history = Cast(this.rootDoc[this.fieldKey + '-history'], listSpec('string'), []);
+        const weburl = new WebField(Field.toString(data));
+        this.dataDoc[this.fieldKey + '-future'] = new List<string>([]);
+        this.dataDoc[this.fieldKey + '-history'] = new List<string>([...(history || []), oldUrl]);
+        this.dataDoc[this.fieldKey] = weburl;
+        return true;
+    };
     onWebUrlValueKeyDown = (e: React.KeyboardEvent) => {
-        e.key === 'Enter' && this.submitURL(this._keyInput.current!.value);
+        if (e.key === 'Enter') this.setData(this._keyInput.current!.value);
         e.stopPropagation();
     };
 
-    @computed get urlEditor() {
-        return (
-            <div className="collectionMenu-webUrlButtons" onDrop={this.onWebUrlDrop} onDragOver={e => e.preventDefault()}>
-                <input
-                    className="collectionMenu-urlInput"
-                    key={this._url}
-                    placeholder="ENTER URL"
-                    defaultValue={this._url}
-                    onDrop={this.onWebUrlDrop}
-                    onDragOver={e => e.preventDefault()}
-                    onKeyDown={this.onWebUrlValueKeyDown}
-                    onClick={e => {
-                        this._keyInput.current!.select();
-                        e.stopPropagation();
-                    }}
-                    ref={this._keyInput}
-                />
-                <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', maxWidth: '250px' }}>
-                    <button className="submitUrl" onClick={() => this.submitURL(this._keyInput.current!.value)} onDragOver={e => e.stopPropagation()} onDrop={this.onWebUrlDrop}>
-                        GO
-                    </button>
-                    <button className="submitUrl" onClick={() => this.back}>
-                        {' '}
-                        <FontAwesomeIcon icon="caret-left" size="lg" />{' '}
-                    </button>
-                    <button className="submitUrl" onClick={() => this.forward}>
-                        {' '}
-                        <FontAwesomeIcon icon="caret-right" size="lg" />{' '}
-                    </button>
-                </div>
-            </div>
-        );
-    }
-
     specificContextMenu = (e: React.MouseEvent | PointerEvent): void => {
         const cm = ContextMenu.Instance;
         const funcs: ContextMenuProps[] = [];
@@ -706,6 +682,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 },
                 icon: 'snowflake',
             });
+            funcs.push({ description: 'Create Thumbnail', event: () => this.updateThumb(), icon: 'portrait' });
             cm.addItem({ description: 'Options...', subitems: funcs, icon: 'asterisk' });
         }
     };
@@ -746,19 +723,23 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
 
     @computed get urlContent() {
-        if (this._hackHide || (this.webThumb && !this._webPageHasBeenRendered && LightboxView.LightboxDoc !== this.rootDoc)) return null;
-        this.props.thumbShown?.();
+        setTimeout(
+            action(() => {
+                if (this._initialScroll === undefined && !this._webPageHasBeenRendered) {
+                    this.setScrollPos(NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.scrollTop)));
+                }
+                this._webPageHasBeenRendered = true;
+            })
+        );
         const field = this.rootDoc[this.props.fieldKey];
-        let view;
         if (field instanceof HtmlField) {
-            view = <span className="webBox-htmlSpan" contentEditable onPointerDown={e => e.stopPropagation()} dangerouslySetInnerHTML={{ __html: field.html }} />;
-        } else if (field instanceof WebField) {
+            return <span className="webBox-htmlSpan" contentEditable onPointerDown={e => e.stopPropagation()} dangerouslySetInnerHTML={{ __html: field.html }} />;
+        }
+        if (field instanceof WebField) {
             const url = this.layoutDoc.useCors ? Utils.CorsProxy(this._webUrl) : this._webUrl;
-            view = (
+            return (
                 <iframe
                     className="webBox-iframe"
-                    enable-annotation={'true'}
-                    style={{ pointerEvents: this._scrollTimer ? 'none' : undefined }}
                     ref={action((r: HTMLIFrameElement | null) => (this._iframe = r))}
                     src={url}
                     onLoad={this.iframeLoaded}
@@ -767,32 +748,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     sandbox={`${this.layoutDoc.allowScripts ? 'allow-scripts' : ''} allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin`}
                 />
             );
-        } else {
-            view = (
-                <iframe
-                    className="webBox-iframe"
-                    enable-annotation={'true'}
-                    style={{ pointerEvents: this._scrollTimer ? 'none' : undefined }} // if we allow pointer events when scrolling is on, then reversing direction does not work smoothly
-                    ref={action((r: HTMLIFrameElement | null) => (this._iframe = r))}
-                    src={'https://crossorigin.me/https://cs.brown.edu'}
-                />
-            );
         }
-        setTimeout(
-            action(() => {
-                this._scrollHeight = Math.max(this._scrollHeight, this._iframe && this._iframe.contentDocument && this._iframe.contentDocument.body ? this._iframe.contentDocument.body.scrollHeight : 0);
-                if (this._initialScroll === undefined && !this._webPageHasBeenRendered) {
-                    this.setScrollPos(NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.scrollTop)));
-                }
-                this._webPageHasBeenRendered = true;
-            })
-        );
-        return view;
+        return <iframe className="webBox-iframe" ref={action((r: HTMLIFrameElement | null) => (this._iframe = r))} src={'https://crossorigin.me/https://cs.brown.edu'} />;
     }
 
     addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => {
-        console.log(annotationKey);
-        (doc instanceof Doc ? [doc] : doc).forEach(doc => (doc.webUrl = this._url));
+        (doc instanceof Doc ? [doc] : doc).forEach(doc => (doc.presData = new WebField(this._url)));
         return this.addDocument(doc, annotationKey);
     };
 
@@ -843,7 +804,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 title="Toggle Sidebar"
                 style={{
                     display: !this.props.isContentActive() ? 'none' : undefined,
-                    top: StrCast(this.rootDoc._showTitle) === 'title' ? 20 : 5,
+                    top: StrCast(this.layoutDoc._showTitle) === 'title' ? 20 : 5,
                     backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
                 }}
                 onPointerDown={e => this.sidebarBtnDown(e, true)}>
@@ -878,17 +839,33 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             }
         }
     });
+    @action
+    onZoomWheel = (e: React.WheelEvent) => {
+        if (this.props.isContentActive(true)) {
+            e.stopPropagation();
+        }
+    };
     sidebarWidth = () => {
         if (!this.SidebarShown) return 0;
         if (this._previewWidth) return WebBox.sidebarResizerWidth + WebBox.openSidebarWidth; // return default sidebar if previewing (as in viewing a link target)
         const nativeDiff = NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc);
         return WebBox.sidebarResizerWidth + nativeDiff * (this.props.NativeDimScaling?.() || 1);
     };
+    _innerCollectionView: CollectionFreeFormView | undefined;
+    zoomScaling = () => this._innerCollectionView?.zoomScaling() ?? 1;
+    setInnerContent = (component: DocComponentView) => (this._innerCollectionView = component as CollectionFreeFormView);
+
     @computed get content() {
         const interactive = this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && Doc.ActiveTool === InkTool.None;
         return (
-            <div className={'webBox-cont' + (interactive ? '-interactive' : '')} onKeyDown={e => e.stopPropagation()} style={{ width: !this.layoutDoc.forceReflow ? NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']) || `100%` : '100%' }}>
-                {this.urlContent}
+            <div
+                className={'webBox-cont' + (interactive ? '-interactive' : '')}
+                onKeyDown={e => e.stopPropagation()}
+                style={{
+                    width: !this.layoutDoc.forceReflow ? NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']) || `100%` : '100%',
+                    transform: `scale(${this.zoomScaling()})  translate(${-NumCast(this.layoutDoc.panX)}px, ${-NumCast(this.layoutDoc.panY)}px)`,
+                }}>
+                {this._hackHide || (this.webThumb && !this._webPageHasBeenRendered && LightboxView.LightboxDoc !== this.rootDoc) ? null : this.urlContent}
             </div>
         );
     }
@@ -896,7 +873,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @computed get annotationLayer() {
         TraceMobx();
         return (
-            <div className="webBox-annotationLayer" style={{ height: Doc.NativeHeight(this.Document) || undefined }} ref={this._annotationLayer}>
+            <div
+                className="webBox-annotationLayer"
+                style={{
+                    transform: `scale(${this.zoomScaling()})  translate(${-NumCast(this.layoutDoc.panX)}px, ${-NumCast(this.layoutDoc.panY)}px)`,
+                    height: Doc.NativeHeight(this.Document) || undefined,
+                }}
+                ref={this._annotationLayer}>
                 {this.inlineTextAnnotations
                     .sort((a, b) => NumCast(a.y) - NumCast(b.y))
                     .map(anno => (
@@ -916,9 +899,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const renderAnnotations = (docFilters: () => string[]) => (
             <CollectionFreeFormView
                 {...this.props}
-                setContentView={emptyFunction}
+                setContentView={this.setInnerContent}
                 NativeWidth={returnZero}
                 NativeHeight={returnZero}
+                originTopLeft={false}
+                isAnnotationOverlayScrollable={true}
                 renderDepth={this.props.renderDepth + 1}
                 isAnnotationOverlay={true}
                 fieldKey={this.annotationKey}
@@ -945,16 +930,17 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         );
         return (
             <div
-                className={'webBox-outerContent'}
+                className="webBox-outerContent"
                 ref={this._outerRef}
                 style={{
                     height: `${100 / scale}%`,
                     pointerEvents,
                 }}
-                onWheel={StopEvent} // block wheel events from propagating since they're handled by the iframe
+                // when active, block wheel events from propagating since they're handled by the iframe
+                onWheel={this.onZoomWheel}
                 onScroll={e => this.setDashScrollTop(this._outerRef.current?.scrollTop || 0)}
                 onPointerDown={this.onMarqueeDown}>
-                <div className={'webBox-innerContent'} style={{ height: this._webPageHasBeenRendered && this._scrollHeight ? this.scrollHeight : '100%', pointerEvents }}>
+                <div className="webBox-innerContent" style={{ height: (this._webPageHasBeenRendered && this._scrollHeight) || '100%', pointerEvents }}>
                     {this.content}
                     {<div style={{ display: DragManager.docsBeingDragged.length ? 'none' : undefined, mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div>}
                     {renderAnnotations(this.opaqueFilter)}
@@ -1016,7 +1002,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     pointerEvents = () => (!this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance?.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none');
     annotationPointerEvents = () => (this._isAnnotating || SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None ? 'all' : 'none');
     render() {
-        setTimeout(() => DocListCast(this.rootDoc[this.annotationKey]).forEach(doc => (doc.webUrl = this._url)));
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
         const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any);
         const scale = previewScale * (this.props.NativeDimScaling?.() || 1);
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 26515da30..a4968dcd0 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -505,7 +505,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
             <div className="menuButton editableText">
                 <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'lock'} />
                 <div style={{ width: 'calc(100% - .875em)', paddingLeft: '4px' }}>
-                    <EditableView GetValue={() => script?.script.run({ value: '', _readOnly_: true }).result} SetValue={setValue} contents={checkResult} />
+                    <EditableView GetValue={() => script?.script.run({ value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} />
                 </div>
             </div>
         );
@@ -889,7 +889,7 @@ ScriptingGlobals.add(function webSetURL(url: string, checkResult?: boolean) {
         if (checkResult) {
             return StrCast(selected.rootDoc.data, Cast(selected.rootDoc.data, WebField, null)?.url?.href);
         }
-        (selected.ComponentView as WebBox).submitURL(url);
+        selected.ComponentView?.setData?.(url);
         //selected.rootDoc.data = new WebField(url);
     }
 });
@@ -925,6 +925,15 @@ ScriptingGlobals.add(function toggleSchemaPreview(checkResult?: boolean) {
         }
     }
 });
+ScriptingGlobals.add(function toggleSingleLineSchema(checkResult?: boolean) {
+    const selected = SelectionManager.Docs().lastElement();
+    if (checkResult && selected) {
+        return NumCast(selected._singleLine) > 0 ? Colors.MEDIUM_BLUE : 'transparent';
+    }
+    if (selected) {
+        selected._singleLine = !selected._singleLine;
+    }
+});
 
 /** STACK
  *      groupBy
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index bf6fa2ec6..a9e59ab1c 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -2,18 +2,17 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@material-ui/core';
 import { action, computed, IReactionDisposer, observable } from 'mobx';
 import { observer } from 'mobx-react';
-import { NodeSelection } from 'prosemirror-state';
 import * as ReactDOM from 'react-dom/client';
-import { DataSym, Doc, DocListCast, Field } from '../../../../fields/Doc';
+import { DataSym, Doc, Field } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
 import { listSpec } from '../../../../fields/Schema';
 import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
-import { ComputedField } from '../../../../fields/ScriptField';
 import { Cast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../../Utils';
+import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils';
 import { DocServer } from '../../../DocServer';
 import { CollectionViewType } from '../../../documents/DocumentTypes';
 import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu';
+import { SchemaTableCell } from '../../collections/collectionSchema/SchemaTableCell';
 import { OpenWhere } from '../DocumentView';
 import './DashFieldView.scss';
 import { FormattedTextBox } from './FormattedTextBox';
@@ -70,10 +69,10 @@ export class DashFieldView {
             } catch {}
         });
     }
-    deselectNode() {
+    @action deselectNode() {
         this.dom.classList.remove('ProseMirror-selectednode');
     }
-    selectNode() {
+    @action selectNode() {
         this.dom.classList.add('ProseMirror-selectednode');
     }
 }
@@ -98,6 +97,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     _fieldKey: string;
     _fieldStringRef = React.createRef<HTMLSpanElement>();
     @observable _dashDoc: Doc | undefined;
+    @observable _expanded = false;
 
     constructor(props: IDashFieldViewInternal) {
         super(props);
@@ -114,126 +114,32 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
         this._reactionDisposer?.();
     }
 
-    public static multiValueDelimeter = ';';
-    public static fieldContent(textBoxDoc: Doc, dashDoc: Doc, fieldKey: string) {
-        const dashVal = dashDoc[fieldKey] ?? dashDoc[DataSym][fieldKey] ?? '';
-        const fval = dashVal instanceof List ? dashVal.join(DashFieldViewInternal.multiValueDelimeter) : StrCast(dashVal).startsWith(':=') || dashVal === '' ? Doc.Layout(textBoxDoc)[fieldKey] : dashVal;
-        return { boolVal: Cast(fval, 'boolean', null), strVal: Field.toString(fval as Field) || '' };
-    }
-
     // set the display of the field's value (checkbox for booleans, span of text for strings)
     @computed get fieldValueContent() {
-        if (this._dashDoc) {
-            const { boolVal, strVal } = DashFieldViewInternal.fieldContent(this._textBoxDoc, this._dashDoc, this._fieldKey);
-            // field value is a boolean, so use a checkbox or similar widget to display it
-            if (boolVal === true || boolVal === false) {
-                return (
-                    <input
-                        className="dashFieldView-fieldCheck"
-                        type="checkbox"
-                        checked={boolVal}
-                        onChange={e => {
-                            if (this._fieldKey.startsWith('_')) Doc.Layout(this._textBoxDoc)[this._fieldKey] = e.target.checked;
-                            Doc.SetInPlace(this._dashDoc!, this._fieldKey, e.target.checked, true);
-                        }}
-                    />
-                );
-            } // field value is a string, so display it as an editable span
-            else {
-                // bcz: this is unfortunate, but since this React component is nested within a non-React text box (prosemirror), we can't
-                // use React events.  Essentially, React events occur after native events have been processed, so corresponding React events
-                // will never fire because Prosemirror has handled the native events.  So we add listeners for native events here.
-                return (
-                    <span
-                        className="dashFieldView-fieldSpan"
-                        contentEditable={!this.props.unclickable()}
-                        style={{ display: strVal.length < 2 ? 'inline-block' : undefined }}
-                        suppressContentEditableWarning={true}
-                        defaultValue={strVal}
-                        ref={r => {
-                            r?.addEventListener('keydown', e => this.fieldSpanKeyDown(e, r));
-                            r?.addEventListener('blur', e => r && this.updateText(r.textContent!, false));
-                            r?.addEventListener(
-                                'pointerdown',
-                                action(e => {
-                                    // let target = e.target as any; // hrefs are stored on the dataset of the <a> node that wraps the hyerlink <span>
-                                    // while (target && !target.dataset?.targethrefs) target = target.parentElement;
-                                    this.props.tbox.EditorView!.dispatch(this.props.tbox.EditorView!.state.tr.setSelection(new NodeSelection(this.props.tbox.EditorView!.state.doc.resolve(this.props.getPos()))));
-                                    // FormattedTextBoxComment.update(this.props.tbox, this.props.tbox.EditorView!, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc);
-                                    // e.stopPropagation();
-                                })
-                            );
-                        }}>
-                        {strVal}
-                    </span>
-                );
-            }
-        }
+        return !this._dashDoc ? null : (
+            <div onClick={action(e => (this._expanded = !this.props.editable ? !this._expanded : true))} style={{ fontSize: 'smaller', width: this.props.hideKey ? this.props.tbox.props.PanelWidth() - 20 : undefined }}>
+                <SchemaTableCell
+                    Document={this._dashDoc}
+                    col={0}
+                    deselectCell={emptyFunction}
+                    selectCell={emptyFunction}
+                    maxWidth={this.props.hideKey ? undefined : () => 100}
+                    columnWidth={this.props.hideKey ? () => this.props.tbox.props.PanelWidth() - 20 : returnZero}
+                    selectedCell={() => [this._dashDoc!, 0]}
+                    fieldKey={this._fieldKey}
+                    rowHeight={returnZero}
+                    isRowActive={() => this._expanded && this.props.editable}
+                    padding={0}
+                    getFinfo={emptyFunction}
+                    setColumnValues={returnFalse}
+                    allowCRs={true}
+                    oneLine={!this._expanded}
+                    finishEdit={action(() => (this._expanded = false))}
+                />
+            </div>
+        );
     }
 
-    // we need to handle all key events on the input span or else they will propagate to prosemirror.
-    @action
-    fieldSpanKeyDown = (e: KeyboardEvent, span: HTMLSpanElement) => {
-        if (e.key === 'c' && (e.ctrlKey || e.metaKey)) {
-            navigator.clipboard.writeText(window.getSelection()?.toString() || '');
-            return;
-        }
-        if (e.key === 'Enter') {
-            // handle the enter key by "submitting" the current text to Dash's database.
-            this.updateText(span.textContent!, true);
-            e.preventDefault(); // prevent default to avoid a newline from being generated and wiping out this field view
-        }
-        if (e.key === 'a' && (e.ctrlKey || e.metaKey)) {
-            // handle ctrl-A to select all the text within the span
-            if (window.getSelection) {
-                const range = document.createRange();
-                range.selectNodeContents(span);
-                window.getSelection()!.removeAllRanges();
-                window.getSelection()!.addRange(range);
-            }
-            e.preventDefault(); //prevent default so that all the text in the prosemirror text box isn't selected
-        }
-        if (!this.props.editable) {
-            e.preventDefault();
-        }
-        e.stopPropagation(); // we need to handle all events or else they will propagate to prosemirror.
-    };
-
-    @action
-    updateText = (nodeText: string, forceMatch: boolean) => {
-        if (nodeText) {
-            const newText = nodeText.startsWith(':=') || nodeText.startsWith('=:=') ? ':=-computed-' : nodeText;
-            // look for a document whose id === the fieldKey being displayed.  If there's a match, then that document
-            // holds the different enumerated values for the field in the titles of its collected documents.
-            // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down.
-            DocServer.GetRefField(this._fieldKey).then(options => {
-                let modText = '';
-                options instanceof Doc && DocListCast(options.data).forEach(opt => (forceMatch ? StrCast(opt.title).startsWith(newText) : StrCast(opt.title) === newText) && (modText = StrCast(opt.title)));
-                if (modText) {
-                    //  elementfieldSpan.innerHTML = this._dashDoc![this._fieldKey as string] = modText;
-                    Doc.SetInPlace(this._dashDoc!, this._fieldKey, modText, true);
-                } // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key
-                else if (nodeText.startsWith(':=')) {
-                    this._dashDoc![DataSym][this._fieldKey] = ComputedField.MakeFunction(nodeText.substring(2));
-                } else if (nodeText.startsWith('=:=')) {
-                    Doc.Layout(this._textBoxDoc)[this._fieldKey] = ComputedField.MakeFunction(nodeText.substring(3));
-                } else {
-                    if (Number(newText).toString() === newText) {
-                        if (this._fieldKey.startsWith('_')) Doc.Layout(this._textBoxDoc)[this._fieldKey] = Number(newText);
-                        Doc.SetInPlace(this._dashDoc!, this._fieldKey, Number(newText), true);
-                    } else {
-                        const splits = newText.split(DashFieldViewInternal.multiValueDelimeter);
-                        if (!this._textBoxDoc[this._fieldKey]) {
-                            const strVal = splits.length > 1 ? new List<string>(splits) : newText;
-                            if (this._fieldKey.startsWith('_')) Doc.Layout(this._textBoxDoc)[this._fieldKey] = strVal;
-                            Doc.SetInPlace(this._dashDoc!, this._fieldKey, strVal, true);
-                        }
-                    }
-                }
-            });
-        }
-    };
-
     createPivotForField = (e: React.MouseEvent) => {
         let container = this.props.tbox.props.DocumentView?.().props.docViewPath().lastElement();
         if (container) {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index b5aa34a29..68160ac9b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1575,7 +1575,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         if (!state.selection.empty && !(state.selection instanceof NodeSelection)) this.setupAnchorMenu();
         else if (this.props.isContentActive(true)) {
             const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
-            !this.props.isSelected(true) && editor.dispatch(state.tr.setSelection(new TextSelection(state.doc.resolve(pcords?.pos || 0))));
+            // !this.props.isSelected(true) &&
+            editor.dispatch(state.tr.setSelection(new TextSelection(state.doc.resolve(pcords?.pos || 0))));
             let target = e.target as any; // hrefs are stored on the dataset of the <a> node that wraps the hyerlink <span>
             while (target && !target.dataset?.targethrefs) target = target.parentElement;
             FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview === 'true');
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index 5b47e8a70..7e17008bb 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -46,7 +46,7 @@ export const marks: { [index: string]: MarkSpec } = {
         toDOM(node: any) {
             const targethrefs = node.attrs.allAnchors.reduce((p: string, item: { href: string; title: string; anchorId: string }) => (p ? p + ' ' + item.href : item.href), '');
             const anchorids = node.attrs.allAnchors.reduce((p: string, item: { href: string; title: string; anchorId: string }) => (p ? p + ' ' + item.anchorId : item.anchorId), '');
-            return ['a', { class: anchorids, 'data-targethrefs': targethrefs, 'data-linkdoc': node.attrs.linkDoc, title: node.attrs.title, location: node.attrs.location, style: `background: lightBlue` }, 0];
+            return ['a', { class: anchorids, 'data-targethrefs': targethrefs, 'data-noPreview': 'true', 'data-linkdoc': node.attrs.linkDoc, title: node.attrs.title, location: node.attrs.location, style: `background: lightBlue` }, 0];
         },
     },
     noAutoLinkAnchor: {
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index bd2be8f11..c22107c03 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -5,7 +5,7 @@ import { action, computed, IReactionDisposer, observable, ObservableSet, reactio
 import { observer } from 'mobx-react';
 import { AnimationSym, Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../../fields/Doc';
 import { Copy, Id } from '../../../../fields/FieldSymbols';
-import { InkField, InkTool } from '../../../../fields/InkField';
+import { InkField } from '../../../../fields/InkField';
 import { List } from '../../../../fields/List';
 import { ObjectField } from '../../../../fields/ObjectField';
 import { listSpec } from '../../../../fields/Schema';
@@ -429,6 +429,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 }
             }
         }
+        if ((pinDataTypes?.dataview && activeItem.presData !== undefined) || (!pinDataTypes && activeItem.presData !== undefined)) {
+            bestTarget._dataTransition = `all ${transTime}ms`;
+            const fkey = Doc.LayoutFieldKey(bestTarget);
+            const setData = bestTargetView?.ComponentView?.setData;
+            if (setData) setData(activeItem.presData);
+            else Doc.GetProto(bestTarget)[fkey] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
+            bestTarget[fkey + '-usePath'] = activeItem.presUsePath;
+            setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10);
+        }
         if (pinDataTypes?.datarange || (!pinDataTypes && activeItem.presXRange !== undefined)) {
             if (bestTarget.xRange !== activeItem.presXRange) {
                 bestTarget.xRange = (activeItem.presXRange as ObjectField)?.[Copy]();
@@ -521,13 +530,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const newList = new List<Doc>([...oldItems, ...hiddenItems, ...newItems]);
             Doc.GetProto(bestTarget)[fkey + '-annotations'] = newList;
         }
-        if ((pinDataTypes?.dataview && activeItem.presData !== undefined) || (!pinDataTypes && activeItem.presData !== undefined)) {
-            bestTarget._dataTransition = `all ${transTime}ms`;
-            const fkey = Doc.LayoutFieldKey(bestTarget);
-            Doc.GetProto(bestTarget)[fkey] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
-            bestTarget[fkey + '-usePath'] = activeItem.presUsePath;
-            setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10);
-        }
         if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.presPinLayoutData !== undefined)) {
             changed = true;
             const layoutField = Doc.LayoutFieldKey(bestTarget);
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index fce67e7fc..ea709a859 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -528,7 +528,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
             style={{
                 mixBlendMode: mixBlendMode,
                 display: display,
-                transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})`,
                 pointerEvents: Doc.ActiveTool !== InkTool.None ? 'all' : undefined,
             }}>
             <CollectionFreeFormView
@@ -537,7 +536,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 NativeHeight={returnZero}
                 setContentView={emptyFunction} // override setContentView to do nothing
                 pointerEvents={SnappingManager.GetIsDragging() ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it.
-                childPointerEvents={'all'} // but freeform children need to get events to allow text editing, etc
+                childPointerEvents="all" // but freeform children need to get events to allow text editing, etc
                 renderDepth={this.props.renderDepth + 1}
                 isAnnotationOverlay={true}
                 fieldKey={this.props.fieldKey + '-annotations'}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index b8ac8fb5d..5e3e27a7c 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -41,7 +41,7 @@ export namespace Field {
         switch (typeof field) {
             case 'string':
                 if (field.startsWith('{"')) return `'${field}'`; // bcz: hack ... want to quote the string the right way. if there are nested "'s, then use ' instead of ".  In this case, test for the start of a JSON string of the format {"property": ... } and use outer 's instead of "s
-                return `"${field}"`;
+                return !field.includes('`') ? `\`${field}\`` : `"${field}"`;
             case 'number':
             case 'boolean':
                 return String(field);
-- 
cgit v1.2.3-70-g09d2


From 42afc0250de658fc3e924864bfae5afb4edec335 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 14 May 2023 12:03:40 -0400
Subject: major overhaul of field naming conventions.

---
 .../apis/google_docs/GooglePhotosClientUtils.ts    |  88 +++---
 src/client/documents/DocumentTypes.ts              |   2 +-
 src/client/documents/Documents.ts                  | 324 ++++++++++-----------
 src/client/documents/Gitlike.ts                    |  26 +-
 src/client/util/CaptureManager.tsx                 |   2 +-
 src/client/util/CurrentUserUtils.ts                | 179 ++++++------
 src/client/util/DictationManager.ts                |   2 +-
 src/client/util/DocumentManager.ts                 |  22 +-
 src/client/util/DragManager.ts                     |  12 +-
 src/client/util/DropConverter.ts                   |   4 +-
 src/client/util/GroupManager.tsx                   |   8 +-
 src/client/util/HypothesisUtils.ts                 |   2 +-
 src/client/util/Import & Export/ImageUtils.ts      |  32 +-
 src/client/util/InteractionUtils.tsx               |   1 +
 src/client/util/LinkFollower.ts                    |  34 +--
 src/client/util/LinkManager.ts                     |  32 +-
 src/client/util/ReplayMovements.ts                 |   4 +-
 src/client/util/SearchUtil.ts                      |  94 +++---
 src/client/util/SettingsManager.tsx                |   4 +-
 src/client/util/SharingManager.tsx                 |   4 +-
 src/client/util/SnappingManager.ts                 |   4 +-
 src/client/util/TrackMovements.ts                  |   2 +-
 src/client/views/AudioWaveform.tsx                 | 124 ++++----
 src/client/views/DashboardView.tsx                 |  18 +-
 src/client/views/DocComponent.tsx                  |  21 +-
 src/client/views/DocumentButtonBar.tsx             |  22 +-
 src/client/views/DocumentDecorations.tsx           |  70 ++---
 src/client/views/FilterPanel.tsx                   |   6 +-
 src/client/views/GestureOverlay.tsx                |  14 +-
 src/client/views/GlobalKeyHandler.ts               |   4 +-
 src/client/views/InkStrokeProperties.ts            |  14 +-
 src/client/views/InkTranscription.tsx              |   2 +-
 src/client/views/InkingStroke.tsx                  |  30 +-
 src/client/views/LightboxView.tsx                  |  44 +--
 src/client/views/MainView.tsx                      |  32 +-
 src/client/views/MarqueeAnnotator.tsx              |  12 +-
 src/client/views/PreviewCursor.tsx                 |   2 +-
 src/client/views/PropertiesButtons.tsx             |  36 +--
 .../views/PropertiesDocBacklinksSelector.tsx       |   2 +-
 src/client/views/PropertiesDocContextSelector.tsx  |  10 +-
 src/client/views/PropertiesView.tsx                |  78 ++---
 src/client/views/SidebarAnnos.tsx                  |  20 +-
 src/client/views/StyleProvider.tsx                 |  38 +--
 src/client/views/TemplateMenu.tsx                  |   4 +-
 src/client/views/animationtimeline/Timeline.tsx    |  14 +-
 src/client/views/animationtimeline/Track.tsx       | 261 +++++++++--------
 .../views/collections/CollectionCarouselView.tsx   |  14 +-
 .../views/collections/CollectionDockingView.tsx    |  22 +-
 .../collections/CollectionMasonryViewFieldRow.tsx  |  44 +--
 src/client/views/collections/CollectionMenu.tsx    |  85 +++---
 .../views/collections/CollectionNoteTakingView.tsx |  78 ++---
 .../collections/CollectionNoteTakingViewColumn.tsx |  23 +-
 .../views/collections/CollectionPileView.tsx       |   6 +-
 .../collections/CollectionStackedTimeline.tsx      |  39 +--
 .../views/collections/CollectionStackingView.tsx   |  82 +++---
 .../CollectionStackingViewFieldColumn.tsx          |  30 +-
 src/client/views/collections/CollectionSubView.tsx |  14 +-
 .../views/collections/CollectionTimeView.tsx       |   8 +-
 .../views/collections/CollectionTreeView.tsx       |  28 +-
 src/client/views/collections/CollectionView.tsx    |  16 +-
 src/client/views/collections/TabDocView.tsx        |  34 +--
 src/client/views/collections/TreeView.tsx          |  64 ++--
 .../CollectionFreeFormLinkView.tsx                 |  62 ++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 186 ++++++------
 .../collections/collectionFreeForm/MarqueeView.tsx |  32 +-
 .../collectionSchema/CollectionSchemaView.tsx      |  34 +--
 .../collections/collectionSchema/SchemaRowBox.tsx  |   2 +-
 .../collectionSchema/SchemaTableCell.tsx           |   4 +-
 src/client/views/linking/LinkMenuGroup.tsx         |  21 +-
 src/client/views/linking/LinkMenuItem.tsx          |  30 +-
 .../views/linking/LinkRelationshipSearch.tsx       |  52 ++--
 src/client/views/nodes/AudioBox.tsx                |  37 +--
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  16 +-
 src/client/views/nodes/ColorBox.tsx                |   4 +-
 src/client/views/nodes/ComparisonBox.tsx           |  28 +-
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |  18 +-
 .../nodes/DataVizBox/components/LineChart.tsx      |  14 +-
 .../views/nodes/DataVizBox/components/TableBox.tsx |  12 +-
 src/client/views/nodes/DocumentContentsView.tsx    |  12 +-
 src/client/views/nodes/DocumentLinksButton.tsx     |   6 +-
 src/client/views/nodes/DocumentView.tsx            | 145 ++++-----
 src/client/views/nodes/EquationBox.tsx             |   2 +-
 src/client/views/nodes/FieldView.tsx               |   2 +-
 src/client/views/nodes/FunctionPlotBox.tsx         |   2 +-
 src/client/views/nodes/ImageBox.tsx                |  90 +++---
 src/client/views/nodes/KeyValueBox.tsx             |  32 +-
 src/client/views/nodes/KeyValuePair.scss           |   4 +
 src/client/views/nodes/KeyValuePair.tsx            |   6 +-
 src/client/views/nodes/LabelBox.tsx                |   8 +-
 src/client/views/nodes/LinkAnchorBox.tsx           |  16 +-
 src/client/views/nodes/LinkBox.tsx                 |   4 +-
 src/client/views/nodes/LinkDescriptionPopup.tsx    |   2 +-
 src/client/views/nodes/LinkDocPreview.tsx          |  20 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |  42 +--
 src/client/views/nodes/MapBox/MapBox2.tsx          |  42 +--
 src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx |   6 +-
 src/client/views/nodes/PDFBox.tsx                  |  72 ++---
 .../views/nodes/RecordingBox/RecordingBox.tsx      |   2 +-
 src/client/views/nodes/ScreenshotBox.tsx           |  10 +-
 src/client/views/nodes/ScriptingBox.tsx            |  10 +-
 src/client/views/nodes/VideoBox.tsx                | 102 +++----
 src/client/views/nodes/WebBox.tsx                  | 123 ++++----
 src/client/views/nodes/button/FontIconBox.tsx      | 245 ++++++++--------
 .../views/nodes/formattedText/DashDocView.tsx      |  45 +--
 .../views/nodes/formattedText/DashFieldView.tsx    |  13 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 223 +++++++-------
 .../views/nodes/formattedText/RichTextMenu.tsx     |  14 +-
 .../views/nodes/formattedText/RichTextRules.ts     |  28 +-
 src/client/views/nodes/formattedText/nodes_rts.ts  |   2 +-
 src/client/views/nodes/trails/PresBox.tsx          | 101 ++++---
 src/client/views/nodes/trails/PresElementBox.tsx   |   8 +-
 src/client/views/pdf/GPTPopup/GPTPopup.tsx         |   4 +-
 src/client/views/pdf/PDFViewer.tsx                 |  56 ++--
 src/client/views/search/SearchBox.tsx              |  44 +--
 src/fields/Doc.ts                                  | 117 ++++----
 src/fields/RichTextUtils.ts                        |   6 +-
 src/fields/Types.ts                                |   5 +-
 src/fields/documentSchemas.ts                      |  52 ++--
 src/fields/util.ts                                 |   4 +-
 src/mobile/AudioUpload.tsx                         |  10 +-
 src/server/ApiManagers/SearchManager.ts            | 151 +++++-----
 src/server/updateProtos.ts                         |  24 +-
 src/server/websocket.ts                            |   4 +-
 123 files changed, 2424 insertions(+), 2391 deletions(-)

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

diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
index ff9460b62..e8fd8fb8a 100644
--- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts
+++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
@@ -1,27 +1,26 @@
-import { AssertionError } from "assert";
-import { EditorState } from "prosemirror-state";
-import { Doc, DocListCastAsync, Opt } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { RichTextField } from "../../../fields/RichTextField";
-import { RichTextUtils } from "../../../fields/RichTextUtils";
-import { Cast, StrCast } from "../../../fields/Types";
-import { ImageField } from "../../../fields/URLField";
-import { MediaItem, NewMediaItemResult } from "../../../server/apis/google/SharedTypes";
-import { Utils } from "../../../Utils";
-import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
-import { Networking } from "../../Network";
-import { FormattedTextBox } from "../../views/nodes/formattedText/FormattedTextBox";
-import { GoogleAuthenticationManager } from "../GoogleAuthenticationManager";
+import { AssertionError } from 'assert';
+import { EditorState } from 'prosemirror-state';
+import { Doc, DocListCastAsync, Opt } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
+import { RichTextField } from '../../../fields/RichTextField';
+import { RichTextUtils } from '../../../fields/RichTextUtils';
+import { Cast, StrCast } from '../../../fields/Types';
+import { ImageField } from '../../../fields/URLField';
+import { MediaItem, NewMediaItemResult } from '../../../server/apis/google/SharedTypes';
+import { Utils } from '../../../Utils';
+import { Docs, DocumentOptions, DocUtils } from '../../documents/Documents';
+import { Networking } from '../../Network';
+import { FormattedTextBox } from '../../views/nodes/formattedText/FormattedTextBox';
+import { GoogleAuthenticationManager } from '../GoogleAuthenticationManager';
 import Photos = require('googlephotos');
 
 export namespace GooglePhotos {
-
     const endpoint = async () => new Photos(await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken());
 
     export enum MediaType {
         ALL_MEDIA = 'ALL_MEDIA',
         PHOTO = 'PHOTO',
-        VIDEO = 'VIDEO'
+        VIDEO = 'VIDEO',
     }
 
     export type AlbumReference = { id: string } | { title: string };
@@ -58,11 +57,10 @@ export namespace GooglePhotos {
         HOUSES: 'HOUSES',
         GARDENS: 'GARDENS',
         FLOWERS: 'FLOWERS',
-        HOLIDAYS: 'HOLIDAYS'
+        HOLIDAYS: 'HOLIDAYS',
     };
 
     export namespace Export {
-
         export interface AlbumCreationResult {
             albumId: string;
             mediaItems: MediaItem[];
@@ -82,20 +80,20 @@ export namespace GooglePhotos {
             if (!images || !images.length) {
                 return undefined;
             }
-            const resolved = title ? title : (StrCast(collection.title) || `Dash Collection (${collection[Id]}`);
+            const resolved = title ? title : StrCast(collection.title) || `Dash Collection (${collection[Id]}`;
             const { id, productUrl } = await Create.Album(resolved);
             const response = await Transactions.UploadImages(images, { id }, descriptionKey);
             if (response) {
                 const { results, failed } = response;
                 let index: Opt<number>;
                 while ((index = failed.pop()) !== undefined) {
-                    Doc.RemoveDocFromList(dataDocument, "data", images.splice(index, 1)[0]);
+                    Doc.RemoveDocFromList(dataDocument, 'data', images.splice(index, 1)[0]);
                 }
                 const mediaItems: MediaItem[] = results.map(item => item.mediaItem);
                 if (mediaItems.length !== images.length) {
                     throw new AssertionError({ actual: mediaItems.length, expected: images.length });
                 }
-                const idMapping = new Doc;
+                const idMapping = new Doc();
                 for (let i = 0; i < images.length; i++) {
                     const image = Doc.GetProto(images[i]);
                     const mediaItem = mediaItems[i];
@@ -117,38 +115,30 @@ export namespace GooglePhotos {
                 return { albumId: id, mediaItems };
             }
         };
-
     }
 
     export namespace Import {
-
         export type CollectionConstructor = (data: Array<Doc>, options: DocumentOptions, ...args: any) => Doc;
 
         export const CollectionFromSearch = async (constructor: CollectionConstructor, requested: Opt<Partial<Query.SearchOptions>>): Promise<Doc> => {
             await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
             const response = await Query.ContentSearch(requested);
             const uploads = await Transactions.WriteMediaItemsToServer(response);
-            const children = uploads.map((upload: Transactions.UploadInformation) => {
-                const document = Docs.Create.ImageDocument(Utils.fileUrl(upload.fileNames.clean));
-                document.contentSize = upload.contentSize;
-                return document;
-            });
+            const children = uploads.map((upload: Transactions.UploadInformation) => Docs.Create.ImageDocument(Utils.fileUrl(upload.fileNames.clean) /*, {"data_contentSize":upload.contentSize}*/));
             const options = { _width: 500, _height: 500 };
             return constructor(children, options);
         };
-
     }
 
     export namespace Query {
-
-        const delimiter = ", ";
-        const comparator = (a: string, b: string) => (a < b) ? -1 : (a > b ? 1 : 0);
+        const delimiter = ', ';
+        const comparator = (a: string, b: string) => (a < b ? -1 : a > b ? 1 : 0);
 
         export const TagChildImages = async (collection: Doc) => {
             await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
             const idMapping = await Cast(collection.googlePhotosIdMapping, Doc);
             if (!idMapping) {
-                throw new Error("Appending image metadata requires that the targeted collection have already been mapped to an album!");
+                throw new Error('Appending image metadata requires that the targeted collection have already been mapped to an album!');
             }
             const tagMapping = new Map<string, string>();
             const images = (await DocListCastAsync(collection.data))!.map(Doc.GetProto);
@@ -169,7 +159,7 @@ export namespace GooglePhotos {
                 const concatenated = tagMapping.get(image[Id])!;
                 const tags = concatenated.split(delimiter);
                 if (tags.length > 1) {
-                    const cleaned = concatenated.replace(ContentCategories.NONE + delimiter, "");
+                    const cleaned = concatenated.replace(ContentCategories.NONE + delimiter, '');
                     image.googlePhotosTags = cleaned.split(delimiter).sort(comparator).join(delimiter);
                 } else {
                     image.googlePhotosTags = ContentCategories.NONE;
@@ -253,19 +243,15 @@ export namespace GooglePhotos {
         export const GetImage = async (mediaItemId: string): Promise<Transactions.MediaItem> => {
             return (await endpoint()).mediaItems.get(mediaItemId);
         };
-
     }
 
     namespace Create {
-
         export const Album = async (title: string) => {
             return (await endpoint()).albums.create(title);
         };
-
     }
 
     export namespace Transactions {
-
         export interface UploadInformation {
             mediaPaths: string[];
             fileNames: { [key: string]: string };
@@ -295,18 +281,20 @@ export namespace GooglePhotos {
         };
 
         export const WriteMediaItemsToServer = async (body: { mediaItems: any[] }): Promise<UploadInformation[]> => {
-            const uploads = await Networking.PostToServer("/googlePhotosMediaGet", body);
+            const uploads = await Networking.PostToServer('/googlePhotosMediaGet', body);
             return uploads;
         };
 
-        export const UploadThenFetch = async (sources: Doc[], album?: AlbumReference, descriptionKey = "caption") => {
+        export const UploadThenFetch = async (sources: Doc[], album?: AlbumReference, descriptionKey = 'caption') => {
             const response = await UploadImages(sources, album, descriptionKey);
             if (!response) {
                 return undefined;
             }
-            const baseUrls: string[] = await Promise.all(response.results.map(item => {
-                return new Promise<string>(resolve => Query.GetImage(item.mediaItem.id).then(item => resolve(item.baseUrl)));
-            }));
+            const baseUrls: string[] = await Promise.all(
+                response.results.map(item => {
+                    return new Promise<string>(resolve => Query.GetImage(item.mediaItem.id).then(item => resolve(item.baseUrl)));
+                })
+            );
             return baseUrls;
         };
 
@@ -315,9 +303,9 @@ export namespace GooglePhotos {
             failed: number[];
         }
 
-        export const UploadImages = async (sources: Doc[], album?: AlbumReference, descriptionKey = "caption"): Promise<Opt<ImageUploadResults>> => {
+        export const UploadImages = async (sources: Doc[], album?: AlbumReference, descriptionKey = 'caption'): Promise<Opt<ImageUploadResults>> => {
             await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
-            if (album && "title" in album) {
+            if (album && 'title' in album) {
                 album = await Create.Album(album.title);
             }
             const media: MediaInput[] = [];
@@ -327,13 +315,13 @@ export namespace GooglePhotos {
                     return;
                 }
                 const url = data.url.href;
-                const target = Doc.MakeAlias(source);
+                const target = Doc.MakeEmbedding(source);
                 const description = parseDescription(target, descriptionKey);
                 await DocUtils.makeCustomViewClicked(target, Docs.Create.FreeformDocument);
                 media.push({ url, description });
             }
             if (media.length) {
-                const results = await Networking.PostToServer("/googlePhotosMediaPost", { media, album });
+                const results = await Networking.PostToServer('/googlePhotosMediaPost', { media, album });
                 return results;
             }
         };
@@ -341,14 +329,12 @@ export namespace GooglePhotos {
         const parseDescription = (document: Doc, descriptionKey: string) => {
             let description: string = Utils.prepend(`/doc/${document[Id]}?sharing=true`);
             const target = document[descriptionKey];
-            if (typeof target === "string") {
+            if (typeof target === 'string') {
                 description = target;
             } else if (target instanceof RichTextField) {
                 description = RichTextUtils.ToPlainText(EditorState.fromJSON(FormattedTextBox.Instance.config, JSON.parse(target.Data)));
             }
             return description;
         };
-
     }
-
-}
\ No newline at end of file
+}
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index d99cd2dac..2da3a24fd 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -11,7 +11,7 @@ export enum DocumentType {
     AUDIO = 'audio',
     REC = 'recording',
     PDF = 'pdf',
-    INK = 'inks',
+    INK = 'ink',
     SCREENSHOT = 'screenshot',
     FONTICON = 'fonticonbox',
     FILTER = 'filter',
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index e28e29267..849a5d6ae 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -37,7 +37,6 @@ import { FontIconBox } from '../views/nodes/button/FontIconBox';
 import { ColorBox } from '../views/nodes/ColorBox';
 import { ComparisonBox } from '../views/nodes/ComparisonBox';
 import { DataVizBox } from '../views/nodes/DataVizBox/DataVizBox';
-import { OpenWhereMod } from '../views/nodes/DocumentView';
 import { EquationBox } from '../views/nodes/EquationBox';
 import { FieldViewProps } from '../views/nodes/FieldView';
 import { FormattedTextBox } from '../views/nodes/formattedText/FormattedTextBox';
@@ -120,7 +119,7 @@ class PEInfo extends FInfo {
 }
 class DAInfo extends FInfo {
     fieldType? = 'dropActionType';
-    values? = ['alias', 'copy', 'move', 'same', 'proto', 'none'];
+    values? = ['embed', 'copy', 'move', 'same', 'proto', 'none'];
     readOnly = true;
 }
 class DateInfo extends FInfo {
@@ -139,7 +138,7 @@ export class DocumentOptions {
     x?: NUMt = new NumInfo('x coordinate of document in a freeform view');
     y?: NUMt = new NumInfo('y coordinage of document in a freeform view');
     z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, [1, 0]);
-    system?: BOOLt = new BoolInfo('is this a system created/owned doc', true);
+    isSystem?: BOOLt = new BoolInfo('is this a system created/owned doc', true);
     type?: STRt = new StrInfo('type of document', true, Array.from(Object.keys(DocumentType)));
     title?: string;
     creationDate?: DATEt = new DateInfo('date the document was created', true);
@@ -150,33 +149,33 @@ export class DocumentOptions {
     userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
     color?: STRt = new StrInfo('foreground color data doc');
     backgroundColor?: STRt = new StrInfo('background color for data doc');
-    _autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
+    _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
     _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title');
     _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes');
     _headerPointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume');
-    _panX?: NUMt = new NumInfo('horizontal pan location of a freeform view');
-    _panY?: NUMt = new NumInfo('vertical pan location of a freeform view');
+    _freeform_panX?: NUMt = new NumInfo('horizontal pan location of a freeform view');
+    _freeform_panY?: NUMt = new NumInfo('vertical pan location of a freeform view');
     _width?: NUMt = new NumInfo('displayed width of a document');
     _height?: NUMt = new NumInfo('displayed height of document');
-    'data-nativeWidth'?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)');
-    'data-nativeHeight'?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)');
+    data_nativeWidth?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)');
+    data_nativeHeight?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)');
     _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)');
     _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)');
     _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers');
     _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers');
     _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height");
     _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
-    _fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)');
-    _fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
+    _layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)');
+    _layoutFitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
     _contentBounds?: List<number>; // the (forced) bounds of the document to display. format is: [left, top, right, bottom]
     _lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged
-    _lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed
+    _lockedTransform?: boolean; // lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed
     _followLinkToggle?: boolean; // whether document, when clicked, toggles display of its link target
-    _showTitle?: string; // field name to display in header (:hover is an optional suffix)
-    _showAltContentUI?: boolean; // whether to show alternate content button
+    _layout_showTitle?: string; // field name to display in header (:hover is an optional suffix)
+    _layout_altContentUI?: boolean; // whether to show alternate content button
     _isLightbox?: boolean; // whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target
-    _showCaption?: string; // which field to display in the caption area.  leave empty to have no caption
-    _scrollTop?: number; // scroll location for pdfs
+    _layout_showCaption?: string; // which field to display in the caption area.  leave empty to have no caption
+    _layoutScrollTop?: number; // scroll location for pdfs
     _noAutoscroll?: boolean; // whether collections autoscroll when this item is dragged
     _chromeHidden?: boolean; // whether the editing chrome for a document is hidden
     _searchDoc?: boolean; // is this a search document (used to change UI for search results in schema view)
@@ -188,15 +187,16 @@ export class DocumentOptions {
     _viewType?: string; // sub type of a collection
     viewType?: string; // sub type of a collection
     _gridGap?: number; // gap between items in masonry view
-    _viewScale?: number; // how much a freeform view has been scaled (zoomed)
+    _freeform_scale?: number; // how much a freeform view has been scaled (zoomed)
     _overflow?: string; // set overflow behavior
     _xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts
     _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts
     _xPadding?: number;
     _yPadding?: number;
     _itemIndex?: number; // which item index the carousel viewer is showing
-    _showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts
-    _singleLine?: boolean; // whether text document is restricted to a single line (carriage returns make new document)
+    _layout_showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts
+    _singleLine?: boolean; // whether label box is restricted to one line of text
+    _createDocOnCR?: boolean; // whether carriage returns and tabs create new text documents
     _minFontSize?: number; // minimum font size for labelBoxes
     _maxFontSize?: number; // maximum font size for labelBoxes
     _columnWidth?: number;
@@ -205,24 +205,24 @@ export class DocumentOptions {
     _fontFamily?: string;
     _fontWeight?: string;
     _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
-    _curPage?: number; // current page of a PDF or other? paginated document
-    _currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video)  value is in seconds
+    _layout_curPage?: number; // current page of a PDF or other? paginated document
+    _layout_currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video)  value is in seconds
     _currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide)
     _timecodeToShow?: number; // the time that a document should be displayed (e.g., when an annotation shows up as a video plays)
     _timecodeToHide?: number; // the time that a document should be hidden
     _timelineLabel?: boolean; // whether the document exists on a timeline
-    '_carousel-caption-xMargin'?: NUMt = new NumInfo('x margin of caption inside of a carouself collection', true);
-    '_carousel-caption-yMargin'?: NUMt = new NumInfo('y margin of caption inside of a carouself collection', true);
-    'icon-nativeWidth'?: NUMt = new NumInfo('native width of icon view', true);
-    'icon-nativeHeight'?: NUMt = new NumInfo('native height of icon view', true);
-    'dragFactory-count'?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
+    _caption_xMargin?: NUMt = new NumInfo('x margin of caption inside of a carousel collection', true);
+    _caption_yMargin?: NUMt = new NumInfo('y margin of caption inside of a carousel collection', true);
+    icon_nativeWidth?: NUMt = new NumInfo('native width of icon view', true);
+    icon_nativeHeight?: NUMt = new NumInfo('native height of icon view', true);
+    dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
     openFactoryLocation?: string; // an OpenWhere value to place the factory created document
     openFactoryAsDelegate?: boolean; //
     lat?: number;
     lng?: number;
     infoWindowOpen?: boolean;
     author?: string;
-    _layoutKey?: string;
+    _layout_fieldKey?: string;
     fieldValues?: List<any>; // possible field values used by fieldInfos
     fieldType?: string; // type of afield used by fieldInfos
     unrendered?: boolean; // denotes an annotation that is not rendered with a DocumentView (e.g, rtf/pdf text selections and links to scroll locations in web/pdf)
@@ -249,7 +249,6 @@ export class DocumentOptions {
     defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or deafult (undefined) means open document full screen
     waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire.  'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
     dontUndo?: boolean; // whether button clicks should be undoable (this is set to true for Undo/Redo/and sidebar buttons that open the siebar panel)
-    description?: string; // added for links
     layout?: string | Doc; // default layout string for a document
     contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
     childLimitHeight?: number; // whether to limit the height of collection children.  0 - means  height can be no bigger than width
@@ -263,11 +262,11 @@ export class DocumentOptions {
     childContextMenuLabels?: List<string>;
     childContextMenuIcons?: List<string>;
     followLinkZoom?: boolean; // whether to zoom to the target of a link
-    hideLinkButton?: boolean; // whether the blue link counter button should be hidden
+    layout_hideLinkButton?: boolean; // whether the blue link counter button should be hidden
     disableDocBrushing?: boolean; // whether to suppress border highlighting
-    hideDecorationTitle?: boolean;
+    layout_hideDecorationTitle?: boolean;
     hideOpenButton?: boolean;
-    hideResizeHandles?: boolean;
+    layout_hideResizeHandles?: boolean;
     hideDocumentButtonBar?: boolean;
     hideAllLinks?: boolean; // whether all individual blue anchor dots should be hidden
     isTemplateForField?: string; // the field key for which the containing document is a rendering template
@@ -278,8 +277,8 @@ export class DocumentOptions {
     caption?: RichTextField;
     opacity?: number;
     defaultBackgroundColor?: string;
-    _linkAutoMove?: boolean; // whether link endpoint should move around the edges of a document to make shortest path to other link endpoint
-    hideLinkAnchors?: boolean; // suppresses link anchor dots from being displayed
+    _layout_autoMoveAnchors?: boolean; // whether link endpoint should move around the edges of a document to make shortest path to other link endpoint
+    layout_hideLinkAnchors?: boolean; // suppresses link anchor dots from being displayed
     isFolder?: boolean;
     lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide)
     activeFrame?: number; // the active frame of a document in a frame base collection
@@ -294,12 +293,11 @@ export class DocumentOptions {
     borderRounding?: string;
     boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow
     data?: any;
-    baseProto?: boolean; // is this a base prototoype
+    isBaseProto?: boolean; // this Doc is base level prototype for data documents as opposed to data documents which are prototypes for layout documents.  base protos are not cloned during a deep
     dontRegisterView?: boolean;
     lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document.  see PresBox.
     columnHeaders?: List<SchemaHeaderField>; // headers for stacking views
     schemaHeaders?: List<SchemaHeaderField>; // headers for schema view
-    clipWidth?: number; // percent transition from before to after in comparisonBox
     dockingConfig?: string;
     annotationOn?: Doc;
     followLinkToggle?: boolean;
@@ -307,7 +305,7 @@ export class DocumentOptions {
     _removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped.  e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
     noteType?: string;
     // BACKGROUND GRID
-    _backgroundGridShow?: boolean;
+    _freeform_backgroundGrid?: boolean;
 
     //BUTTONS
     buttonText?: string;
@@ -318,7 +316,6 @@ export class DocumentOptions {
     userColorBtn?: string;
     canClick?: string;
     script?: ScriptField;
-    numBtnType?: string;
     numBtnMax?: number;
     numBtnMin?: number;
     switchToggle?: boolean;
@@ -335,12 +332,14 @@ export class DocumentOptions {
 
     layout_linkView?: Doc; // view template for a link document
     layout_keyValue?: string; // view tempalte for key value docs
-    linkRelationship?: string; // type of relatinoship a link represents
-    linkDisplay?: boolean; // whether a link line should be dipslayed between the two link anchors
-    anchor1?: Doc;
-    anchor2?: Doc;
-    'anchor1-useLinkSmallAnchor'?: boolean; // whether anchor1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
-    'anchor2-useLinkSmallAnchor'?: boolean; // whether anchor1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
+    link_description?: string; // added for links
+    link_relationship?: string; // type of relatinoship a link represents
+    layout_linkDisplay?: boolean; // whether a link line should be dipslayed between the two link anchors
+    layout_linkDisplayArrow?: boolean; // whether to display link's directional arrowhead
+    link_anchor_1?: Doc;
+    link_anchor_2?: Doc;
+    link_anchor_1_useLinkSmallAnchor?: boolean; // whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
+    link_anchor_2_useLinkSmallAnchor?: boolean; // whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
     ignoreClick?: boolean;
     onClick?: ScriptField;
     onDoubleClick?: ScriptField;
@@ -354,13 +353,13 @@ export class DocumentOptions {
     onDragStart?: ScriptField; //script to execute at start of drag operation --  e.g., when a "creator" button is dragged this script generates a different document to drop
     cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
     filterBoolean?: string;
-    useCors?: boolean;
+    data_useCors?: boolean;
     icon?: string;
     target?: Doc; // available for use in scripts as the primary target document
     sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script
     targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script
     searchFileTypes?: List<string>; // file types allowed in a search query
-    strokeWidth?: number;
+    stroke_width?: number;
     freezeChildren?: string; // whether children are now allowed to be added and or removed from a collection
     treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view
     treeViewHideUnrendered?: boolean; // tells tree view not to display documents that have an 'unrendered' tag unless they also have a treeViewFieldKey tag (presBox)
@@ -395,8 +394,8 @@ export class DocumentOptions {
     useLinkSmallAnchor?: boolean; // whether links to this document should use a miniature linkAnchorBox
     border?: string; //for searchbox
     hoverBackgroundColor?: string; // background color of a label when hovered
-    linkRelationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor)
-    linkRelationshipSizes?: List<number>; //stores number of links contained in each relationship
+    link_relationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor)
+    link_relationshipSizes?: List<number>; //stores number of links contained in each relationship
     linkColorList?: List<string>; // colors of links corresponding to specific link relationships
 }
 export namespace Docs {
@@ -427,7 +426,7 @@ export namespace Docs {
                         _yMargin: 10,
                         nativeDimModifiable: true,
                         nativeHeightUnfrozen: true,
-                        forceReflow: true,
+                        layout_forceReflow: true,
                         defaultDoubleClick: 'ignore',
                     },
                 },
@@ -457,35 +456,35 @@ export namespace Docs {
                 DocumentType.WEB,
                 {
                     layout: { view: WebBox, dataField: defaultDataKey },
-                    options: { _height: 300, _fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, waitForDoubleClickToClick: 'always' },
+                    options: { _height: 300, _layout_fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, waitForDoubleClickToClick: 'always' },
                 },
             ],
             [
                 DocumentType.COL,
                 {
                     layout: { view: CollectionView, dataField: defaultDataKey },
-                    options: { _fitWidth: true, _panX: 0, _panY: 0, _viewScale: 1 },
+                    options: { _layout_fitWidth: true, _freeform_panX: 0, _freeform_panY: 0, _freeform_scale: 1 },
                 },
             ],
             [
                 DocumentType.KVP,
                 {
                     layout: { view: KeyValueBox, dataField: defaultDataKey },
-                    options: { _fitWidth: true, _height: 150 },
+                    options: { _layout_fitWidth: true, _height: 150 },
                 },
             ],
             [
                 DocumentType.VID,
                 {
                     layout: { view: VideoBox, dataField: defaultDataKey },
-                    options: { _currentTimecode: 0 },
+                    options: { _layout_currentTimecode: 0 },
                 },
             ],
             [
                 DocumentType.AUDIO,
                 {
                     layout: { view: AudioBox, dataField: defaultDataKey },
-                    options: { _height: 100, fitWidth: true, forceReflow: true, nativeDimModifiable: true },
+                    options: { _height: 100, layout_fitWidth: true, layout_forceReflow: true, nativeDimModifiable: true },
                 },
             ],
             [
@@ -499,7 +498,7 @@ export namespace Docs {
                 DocumentType.PDF,
                 {
                     layout: { view: PDFBox, dataField: defaultDataKey },
-                    options: { _curPage: 1, _fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true },
+                    options: { _layout_curPage: 1, _layout_fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true },
                 },
             ],
             [
@@ -519,14 +518,15 @@ export namespace Docs {
             [
                 DocumentType.LINK,
                 {
-                    layout: { view: LinkBox, dataField: defaultDataKey },
+                    layout: { view: LinkBox, dataField: 'link' },
                     options: {
                         childDontRegisterViews: true,
                         onClick: FollowLinkScript(),
-                        hideLinkAnchors: true,
+                        layout_hideLinkAnchors: true,
                         _height: 150,
-                        description: '',
-                        showCaption: 'description',
+                        link: '',
+                        link_description: '',
+                        layout_showCaption: 'link_description',
                         backgroundColor: 'lightblue', // lightblue is default color for linking dot and link documents text comment area
                         _removeDropProperties: new List(['onClick']),
                     },
@@ -537,7 +537,7 @@ export namespace Docs {
                 {
                     data: new List<Doc>(),
                     layout: { view: EmptyBox, dataField: defaultDataKey },
-                    options: { childDropAction: 'alias', title: 'Global Link Database' },
+                    options: { childDropAction: 'embed', title: 'Global Link Database' },
                 },
             ],
             [
@@ -545,7 +545,7 @@ export namespace Docs {
                 {
                     data: new List<Doc>(),
                     layout: { view: EmptyBox, dataField: defaultDataKey },
-                    options: { childDropAction: 'alias', title: 'Global Script Database' },
+                    options: { childDropAction: 'embed', title: 'Global Script Database' },
                 },
             ],
             [
@@ -571,8 +571,8 @@ export namespace Docs {
             [
                 DocumentType.EQUATION,
                 {
-                    layout: { view: EquationBox, dataField: defaultDataKey },
-                    options: { nativeDimModifiable: true, fontSize: '14px', hideResizeHandles: true, hideDecorationTitle: true },
+                    layout: { view: EquationBox, dataField: 'text' },
+                    options: { nativeDimModifiable: true, fontSize: '14px', layout_hideResizeHandles: true, layout_hideDecorationTitle: true },
                 },
             ],
             [
@@ -600,14 +600,14 @@ export namespace Docs {
                 DocumentType.PRES,
                 {
                     layout: { view: PresBox, dataField: defaultDataKey },
-                    options: { defaultDoubleClick: 'ignore', hideLinkAnchors: true },
+                    options: { defaultDoubleClick: 'ignore', layout_hideLinkAnchors: true },
                 },
             ],
             [
                 DocumentType.FONTICON,
                 {
                     layout: { view: FontIconBox, dataField: 'icon' },
-                    options: { defaultDoubleClick: 'ignore', waitForDoubleClickToClick: 'never', enableDragWhenActive: true, hideLinkButton: true, _width: 40, _height: 40 },
+                    options: { defaultDoubleClick: 'ignore', waitForDoubleClickToClick: 'never', enableDragWhenActive: true, layout_hideLinkButton: true, _width: 40, _height: 40 },
                 },
             ],
             [
@@ -621,21 +621,21 @@ export namespace Docs {
                 DocumentType.PRESELEMENT,
                 {
                     layout: { view: PresElementBox, dataField: defaultDataKey },
-                    options: { title: 'pres element template', _fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: 'data' },
+                    options: { title: 'pres element template', _layout_fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: 'data' },
                 },
             ],
             [
                 DocumentType.MARKER,
                 {
                     layout: { view: CollectionView, dataField: defaultDataKey },
-                    options: { hideLinkButton: true, pointerEvents: 'none' },
+                    options: { layout_hideLinkButton: true, pointerEvents: 'none' },
                 },
             ],
             [
                 DocumentType.INK,
                 {
                     // NOTE: this is unused!! ink fields are filled in directly within the InkDocument() method
-                    layout: { view: InkingStroke, dataField: defaultDataKey },
+                    layout: { view: InkingStroke, dataField: 'stroke' },
                     options: {},
                 },
             ],
@@ -649,8 +649,9 @@ export namespace Docs {
             [
                 DocumentType.COMPARISON,
                 {
+                    data: '',
                     layout: { view: ComparisonBox, dataField: defaultDataKey },
-                    options: { clipWidth: 50, nativeDimModifiable: true, backgroundColor: 'gray', targetDropAction: 'alias' },
+                    options: { nativeDimModifiable: true, backgroundColor: 'gray', targetDropAction: 'embed' },
                 },
             ],
             [
@@ -658,7 +659,7 @@ export namespace Docs {
                 {
                     data: new List<Doc>(),
                     layout: { view: EmptyBox, dataField: defaultDataKey },
-                    options: { childDropAction: 'alias', title: 'Global Group Database' },
+                    options: { childDropAction: 'embed', title: 'Global Group Database' },
                 },
             ],
             [
@@ -672,14 +673,14 @@ export namespace Docs {
                 DocumentType.DATAVIZ,
                 {
                     layout: { view: DataVizBox, dataField: defaultDataKey },
-                    options: { _fitWidth: true, nativeDimModifiable: true },
+                    options: { _layout_fitWidth: true, nativeDimModifiable: true },
                 },
             ],
             [
                 DocumentType.LOADING,
                 {
                     layout: { view: LoadingBox, dataField: '' },
-                    options: { _fitWidth: true, _fitHeight: true, nativeDimModifiable: true },
+                    options: { _layout_fitWidth: true, _fitHeight: true, nativeDimModifiable: true },
                 },
             ],
         ]);
@@ -773,11 +774,11 @@ export namespace Docs {
             // synthesize the default options, the type and title from computed values and
             // whatever options pertain to this specific prototype
             const options: DocumentOptions = {
-                system: true,
-                _layoutKey: 'layout',
+                isSystem: true,
+                _layout_fieldKey: 'layout',
                 title,
                 type,
-                baseProto: true,
+                isBaseProto: true,
                 x: 0,
                 y: 0,
                 _width: 300,
@@ -818,24 +819,24 @@ export namespace Docs {
          * main document.
          */
         function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDoc?: Doc) {
-            const viewKeys = ['x', 'y', 'system']; // keys that should be addded to the view document even though they don't begin with an "_"
+            const viewKeys = ['x', 'y', 'isSystem']; // keys that should be addded to the view document even though they don't begin with an "_"
             const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, '^_');
 
             // dataProps['acl-Override'] = SharingPermissions.Unset;
             dataProps['acl-Public'] = options['acl-Public'] ? options['acl-Public'] : Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
 
-            dataProps.system = viewProps.system;
-            dataProps.isPrototype = true;
+            dataProps.isSystem = viewProps.isSystem;
+            dataProps.isDataDoc = true;
             dataProps.author = Doc.CurrentUserEmail;
             dataProps.creationDate = new DateField();
             if (fieldKey) {
-                dataProps[`${fieldKey}-lastModified`] = new DateField();
+                dataProps[`${fieldKey}_modificationDate`] = new DateField();
                 dataProps[fieldKey] = data;
 
                 // so that the list of annotations is already initialised, prevents issues in addonly.
                 // without this, if a doc has no annotations but the user has AddOnly privileges, they won't be able to add an annotation because they would have needed to create the field's list which they don't have permissions to do.
-                dataProps[fieldKey + '-annotations'] = new List<Doc>();
-                dataProps[fieldKey + '-sidebar'] = new List<Doc>();
+                dataProps[fieldKey + '_annotations'] = new List<Doc>();
+                dataProps[fieldKey + '_sidebar'] = new List<Doc>();
             }
 
             // users placeholderDoc as proto if it exists
@@ -901,7 +902,7 @@ export namespace Docs {
         }
 
         export function ComparisonDocument(options: DocumentOptions = { title: 'Comparison Box' }) {
-            return InstanceFromProto(Prototypes.get(DocumentType.COMPARISON), '', options);
+            return InstanceFromProto(Prototypes.get(DocumentType.COMPARISON), undefined, options);
         }
 
         export function AudioDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) {
@@ -954,11 +955,12 @@ export namespace Docs {
                 Prototypes.get(DocumentType.LINK),
                 undefined,
                 {
-                    anchor1: source,
-                    anchor2: target,
+                    link_anchor_1: source,
+                    link_anchor_2: target,
                     ...options,
                 },
-                id
+                id,
+                'link'
             );
 
             LinkManager.Instance.addLink(linkDoc);
@@ -966,36 +968,24 @@ export namespace Docs {
             return linkDoc;
         }
 
-        export function InkDocument(
-            color: string,
-            tool: string,
-            strokeWidth: number,
-            strokeBezier: string,
-            fillColor: string,
-            arrowStart: string,
-            arrowEnd: string,
-            dash: string,
-            points: PointData[],
-            isInkMask: boolean,
-            options: DocumentOptions = {}
-        ) {
+        export function InkDocument(color: string, strokeWidth: number, stroke_bezier: string, fillColor: string, arrowStart: string, arrowEnd: string, dash: string, points: PointData[], isInkMask: boolean, options: DocumentOptions = {}) {
             const I = new Doc();
             I[Initializing] = true;
-            I.isInkMask = isInkMask;
             I.type = DocumentType.INK;
-            I.layout = InkingStroke.LayoutString('data');
-            I.color = color;
-            I.hideDecorationTitle = true; // don't show title when selected
+            I.layout = InkingStroke.LayoutString('stroke');
+            I.layout_fitWidth = true;
+            I.layout_hideDecorationTitle = true; // don't show title when selected
             // I.hideOpenButton = true; // don't show open full screen button when selected
+            I.color = color;
             I.fillColor = fillColor;
-            I.strokeWidth = strokeWidth;
-            I.strokeBezier = strokeBezier;
-            I.strokeStartMarker = arrowStart;
-            I.strokeEndMarker = arrowEnd;
-            I.strokeDash = dash;
-            I.tool = tool;
-            I.fitWidth = true;
-            I['text-align'] = 'center';
+            I.stroke = new InkField(points);
+            I.stroke_width = strokeWidth;
+            I.stroke_bezier = stroke_bezier;
+            I.stroke_startMarker = arrowStart;
+            I.stroke_endMarker = arrowEnd;
+            I.stroke_dash = dash;
+            I.stroke_isInkMask = isInkMask;
+            I.text_align = 'center';
             I.title = 'ink';
             I.x = options.x as number;
             I.y = options.y as number;
@@ -1004,7 +994,6 @@ export namespace Docs {
             I._fontFamily = 'cursive';
             I.author = Doc.CurrentUserEmail;
             I.rotation = 0;
-            I.data = new InkField(points);
             I.defaultDoubleClick = 'click';
             I.creationDate = new DateField();
             I['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
@@ -1050,7 +1039,7 @@ export namespace Docs {
 
         export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
             const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, ...options, _viewType: CollectionViewType.Freeform }, id);
-            documents.map(d => (d.context = inst));
+            documents.map(d => (d.embedContainer = inst));
             return inst;
         }
 
@@ -1136,7 +1125,7 @@ export namespace Docs {
         }
 
         export function EquationDocument(options?: DocumentOptions) {
-            return InstanceFromProto(Prototypes.get(DocumentType.EQUATION), undefined, { ...(options || {}) });
+            return InstanceFromProto(Prototypes.get(DocumentType.EQUATION), undefined, { ...(options || {}) }, undefined, 'text');
         }
 
         export function FunctionPlotDocument(documents: Array<Doc>, options?: DocumentOptions) {
@@ -1263,7 +1252,7 @@ export namespace DocUtils {
                           ? true
                           : matches.some(value => {
                                 if (facetKey.startsWith('*')) {
-                                    //  fields starting with a '*' are used to match families of related fields.  ie, *lastModified will match text-lastModified, data-lastModified, etc
+                                    //  fields starting with a '*' are used to match families of related fields.  ie, *modificationDate will match text_modificationDate, data_modificationDate, etc
                                     const allKeys = Array.from(Object.keys(d));
                                     allKeys.push(...Object.keys(Doc.GetProto(d)));
                                     const keys = allKeys.filter(key => key.includes(facetKey.substring(1)));
@@ -1304,12 +1293,12 @@ export namespace DocUtils {
         broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1));
         return DocUtils.ActiveRecordings.map(audio => {
             const sourceDoc = getSourceDoc();
-            return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { linkDisplay: false, linkRelationship: 'recording annotation:linked recording', description: 'recording timeline' });
+            return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { layout_linkDisplay: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' });
         });
     }
 
-    export function MakeLink(source: Doc, target: Doc, linkSettings: { linkRelationship?: string; description?: string; linkDisplay?: boolean }, id?: string, showPopup?: number[]) {
-        if (!linkSettings.linkRelationship) linkSettings.linkRelationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link';
+    export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string; layout_linkDisplay?: boolean }, id?: string, showPopup?: number[]) {
+        if (!linkSettings.link_relationship) linkSettings.link_relationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link';
         const sv = DocumentManager.Instance.getDocumentView(source);
         if (target.doc === Doc.UserDoc()) return undefined;
 
@@ -1350,16 +1339,16 @@ export namespace DocUtils {
                 target,
                 {
                     title: ComputedField.MakeFunction('generateLinkTitle(self)') as any,
-                    'anchor1-useLinkSmallAnchor': source.useLinkSmallAnchor ? true : undefined,
-                    'anchor2-useLinkSmallAnchor': target.useLinkSmallAnchor ? true : undefined,
+                    link_anchor_1_useLinkSmallAnchor: source.useLinkSmallAnchor ? true : undefined,
+                    link_anchor_2_useLinkSmallAnchor: target.useLinkSmallAnchor ? true : undefined,
                     'acl-Public': SharingPermissions.Augment,
                     '_acl-Public': SharingPermissions.Augment,
-                    linkDisplay: linkSettings.linkDisplay,
-                    _linkAutoMove: true,
-                    linkRelationship: linkSettings.linkRelationship,
-                    _showCaption: 'description',
-                    _showTitle: 'linkRelationship',
-                    description: linkSettings.description,
+                    layout_linkDisplay: linkSettings.layout_linkDisplay,
+                    link_relationship: linkSettings.link_relationship,
+                    link_description: linkSettings.link_description,
+                    _layout_autoMoveAnchors: true,
+                    _layout_showCaption: 'link_description',
+                    _layout_showTitle: 'link_relationship',
                 },
                 id
             ),
@@ -1443,13 +1432,13 @@ export namespace DocUtils {
             created = Docs.Create.AudioDocument(field.url.href, resolved);
             created.layout = AudioBox.LayoutString(fieldKey);
         } else if (field instanceof InkField) {
-            created = Docs.Create.InkDocument(ActiveInkColor(), Doc.ActiveTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), field.inkData, ActiveIsInkMask(), resolved);
+            created = Docs.Create.InkDocument(ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), field.inkData, ActiveIsInkMask(), resolved);
             created.layout = InkingStroke.LayoutString(fieldKey);
         } else if (field instanceof List && field[0] instanceof Doc) {
             created = Docs.Create.StackingDocument(DocListCast(field), resolved);
             created.layout = CollectionView.LayoutString(fieldKey);
         } else {
-            created = Docs.Create.TextDocument('', { ...{ _width: 200, _height: 25, _autoHeight: true }, ...resolved });
+            created = Docs.Create.TextDocument('', { ...{ _width: 200, _height: 25, _layout_autoHeight: true }, ...resolved });
             created.layout = FormattedTextBox.LayoutString(fieldKey);
         }
         if (created) {
@@ -1503,12 +1492,12 @@ export namespace DocUtils {
                 const id = s[s.length - 1];
                 return DocServer.GetRefField(id).then(field => {
                     if (field instanceof Doc) {
-                        const alias = Doc.MakeAlias(field);
-                        alias.x = (options.x as number) || 0;
-                        alias.y = (options.y as number) || 0;
-                        alias._width = (options._width as number) || 300;
-                        alias._height = (options._height as number) || (options._width as number) || 300;
-                        return alias;
+                        const embedding = Doc.MakeEmbedding(field);
+                        embedding.x = (options.x as number) || 0;
+                        embedding.y = (options.y as number) || 0;
+                        embedding._width = (options._width as number) || 300;
+                        embedding._height = (options._height as number) || (options._width as number) || 300;
+                        return embedding;
                     }
                     return undefined;
                 });
@@ -1531,11 +1520,11 @@ export namespace DocUtils {
                             _width: 200,
                             x,
                             y,
-                            _autoHeight: note._autoHeight !== false,
-                            title: StrCast(note.title) + '#' + (note.aliasCount = NumCast(note.aliasCount) + 1),
+                            _layout_autoHeight: note._layout_autoHeight !== false,
+                            title: StrCast(note.title) + '#' + (note.embeddingCount = NumCast(note.embeddingCount) + 1),
                         });
-                        textDoc.layoutKey = 'layout_' + note.title;
-                        textDoc[textDoc.layoutKey] = note;
+                        textDoc.layout_fieldKey = 'layout_' + note.title;
+                        textDoc[textDoc.layout_fieldKey] = note;
                         if (pivotField) {
                             textDoc[pivotField] = pivotValue;
                         }
@@ -1576,7 +1565,7 @@ export namespace DocUtils {
     export function makeCustomViewClicked(doc: Doc, creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = 'custom', docLayoutTemplate?: Doc) {
         const batch = UndoManager.StartBatch('makeCustomViewClicked');
         runInAction(() => {
-            doc.layoutKey = 'layout_' + templateSignature;
+            doc.layout_fieldKey = 'layout_' + templateSignature;
             createCustomView(doc, creator, templateSignature, docLayoutTemplate);
         });
         batch.end();
@@ -1607,7 +1596,7 @@ export namespace DocUtils {
         const customName = 'layout_' + templateSignature;
         const _width = NumCast(doc._width);
         const _height = NumCast(doc._height);
-        const options = { title: 'data', backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: -_height / 2, _showSidebar: false };
+        const options = { title: 'data', backgroundColor: StrCast(doc.backgroundColor), _layout_autoHeight: true, _width, x: -_width / 2, y: -_height / 2, _layout_showSidebar: false };
 
         if (docLayoutTemplate) {
             if (docLayoutTemplate !== doc[customName]) {
@@ -1638,9 +1627,9 @@ export namespace DocUtils {
         }
     }
     export function iconify(doc: Doc) {
-        const layoutKey = Cast(doc.layoutKey, 'string', null);
+        const layout_fieldKey = Cast(doc.layout_fieldKey, 'string', null);
         DocUtils.makeCustomViewClicked(doc, Docs.Create.StackingDocument, 'icon', undefined);
-        if (layoutKey && layoutKey !== 'layout' && layoutKey !== 'layout_icon') doc.deiconifyLayout = layoutKey.replace('layout_', '');
+        if (layout_fieldKey && layout_fieldKey !== 'layout' && layout_fieldKey !== 'layout_icon') doc.deiconifyLayout = layout_fieldKey.replace('layout_', '');
     }
 
     export function pileup(docList: Doc[], x?: number, y?: number, size: number = 55, create: boolean = true) {
@@ -1680,8 +1669,8 @@ export namespace DocUtils {
 
     export function LeavePushpin(doc: Doc, annotationField: string) {
         if (doc.followLinkToggle) return undefined;
-        const context = Cast(doc.context, Doc, null) ?? Cast(doc.annotationOn, Doc, null);
-        const hasContextAnchor = LinkManager.Links(doc).some(l => (l.anchor2 === doc && Cast(l.anchor1, Doc, null)?.annotationOn === context) || (l.anchor1 === doc && Cast(l.anchor2, Doc, null)?.annotationOn === context));
+        const context = Cast(doc.embedContainer, Doc, null) ?? Cast(doc.annotationOn, Doc, null);
+        const hasContextAnchor = LinkManager.Links(doc).some(l => (l.link_anchor_2 === doc && Cast(l.link_anchor_1, Doc, null)?.annotationOn === context) || (l.link_anchor_1 === doc && Cast(l.link_anchor_2, Doc, null)?.annotationOn === context));
         if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) {
             const pushpin = Docs.Create.FontIconDocument({
                 title: 'pushpin',
@@ -1700,7 +1689,7 @@ export namespace DocUtils {
                 _timecodeToShow: Cast(doc._timecodeToShow, 'number', null),
             });
             Doc.AddDocToList(context, annotationField, pushpin);
-            const pushpinLink = DocUtils.MakeLink(pushpin, doc, { linkRelationship: 'pushpin' }, '');
+            const pushpinLink = DocUtils.MakeLink(pushpin, doc, { link_relationship: 'pushpin' }, '');
             doc._timecodeToShow = undefined;
             return pushpin;
         }
@@ -1745,21 +1734,17 @@ export namespace DocUtils {
         if (doc) {
             const proto = Doc.GetProto(doc);
             proto.text = result.rawText;
-            proto.fileUpload = pathname
-                .replace(/.*\//, '')
-                .replace('upload_', '')
-                .replace(/\.[a-z0-9]*$/, '');
             if (Upload.isImageInformation(result)) {
                 const maxNativeDim = Math.min(Math.max(result.nativeHeight, result.nativeWidth), defaultNativeImageDim);
                 const exifRotation = StrCast((result.exifData?.data as any)?.Orientation).toLowerCase();
                 proto['data-nativeOrientation'] = result.exifData?.data?.image?.Orientation ?? (exifRotation.includes('rotate 90') || exifRotation.includes('rotate 270') ? 5 : undefined);
-                proto['data-nativeWidth'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim;
-                proto['data-nativeHeight'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight);
+                proto['data_nativeWidth'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim;
+                proto['data_nativeHeight'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight);
                 if (NumCast(proto['data-nativeOrientation']) >= 5) {
-                    proto['data-nativeHeight'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim;
-                    proto['data-nativeWidth'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight);
+                    proto['data_nativeHeight'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim;
+                    proto['data_nativeWidth'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight);
                 }
-                proto.contentSize = result.contentSize;
+                proto.data_contentSize = result.contentSize;
                 // exif gps data coordinates are stored in DMS (Degrees Minutes Seconds), the following operation converts that to decimal coordinates
                 const latitude = result.exifData?.data?.GPSLatitude;
                 const latitudeDirection = result.exifData?.data?.GPSLatitudeRef;
@@ -1771,12 +1756,12 @@ export namespace DocUtils {
                 }
             }
             if (Upload.isVideoInformation(result)) {
-                proto['data-duration'] = result.duration;
+                proto.data_duration = result.duration;
             }
             if (overwriteDoc) {
                 Doc.removeCurrentlyLoading(overwriteDoc);
                 // loading doc icons are just labels. so any icon views of loading docs need to be replaced with the proper icon view.
-                DocumentManager.Instance.getAllDocumentViews(overwriteDoc).forEach(dv => StrCast(dv.rootDoc.layoutKey) === 'layout_icon' && dv.iconify(() => dv.iconify()));
+                DocumentManager.Instance.getAllDocumentViews(overwriteDoc).forEach(dv => StrCast(dv.rootDoc.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify()));
             }
             generatedDocuments.push(doc);
         }
@@ -1793,16 +1778,16 @@ export namespace DocUtils {
             _height: 35,
             x: x,
             y: y,
-            _fitWidth: true,
-            _autoHeight: true,
-            _showAltContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards),
+            _layout_fitWidth: true,
+            _layout_autoHeight: true,
+            _layout_altContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards),
             title,
         });
         const template = Doc.UserDoc().defaultTextLayout;
         if (template instanceof Doc) {
             tbox._width = NumCast(template._width);
-            tbox.layoutKey = 'layout_' + StrCast(template.title);
-            Doc.GetProto(tbox)[StrCast(tbox.layoutKey)] = template;
+            tbox.layout_fieldKey = 'layout_' + StrCast(template.title);
+            Doc.GetProto(tbox)[StrCast(tbox.layout_fieldKey)] = template;
         }
         return tbox;
     }
@@ -1857,9 +1842,9 @@ export namespace DocUtils {
         if (!dragFactory) return undefined;
         const ndoc = dragFactory.isTemplateDoc ? Doc.ApplyTemplate(dragFactory) : Doc.MakeCopy(dragFactory, true);
         ndoc && Doc.AddFileOrphan(Doc.GetProto(ndoc));
-        if (ndoc && dragFactory['dragFactory-count'] !== undefined) {
-            dragFactory['dragFactory-count'] = NumCast(dragFactory['dragFactory-count']) + 1;
-            Doc.SetInPlace(ndoc, 'title', ndoc.title + ' ' + NumCast(dragFactory['dragFactory-count']).toString(), true);
+        if (ndoc && dragFactory['dragFactory_count'] !== undefined) {
+            dragFactory['dragFactory_count'] = NumCast(dragFactory['dragFactory_count']) + 1;
+            Doc.SetInPlace(ndoc, 'title', ndoc.title + ' ' + NumCast(dragFactory['dragFactory_count']).toString(), true);
         }
 
         if (ndoc && Doc.ActiveDashboard) inheritParentAcls(Doc.ActiveDashboard, ndoc);
@@ -1868,9 +1853,9 @@ export namespace DocUtils {
     }
     export function delegateDragFactory(dragFactory: Doc) {
         const ndoc = Doc.MakeDelegateWithProto(dragFactory);
-        if (ndoc && dragFactory['dragFactory-count'] !== undefined) {
-            dragFactory['dragFactory-count'] = NumCast(dragFactory['dragFactory-count']) + 1;
-            Doc.GetProto(ndoc).title = ndoc.title + ' ' + NumCast(dragFactory['dragFactory-count']).toString();
+        if (ndoc && dragFactory['dragFactory_count'] !== undefined) {
+            dragFactory['dragFactory_count'] = NumCast(dragFactory['dragFactory_count']) + 1;
+            Doc.GetProto(ndoc).title = ndoc.title + ' ' + NumCast(dragFactory['dragFactory_count']).toString();
         }
         return ndoc;
     }
@@ -1885,11 +1870,8 @@ ScriptingGlobals.add(function makeDelegate(proto: any) {
     return d;
 });
 ScriptingGlobals.add(function generateLinkTitle(self: Doc) {
-    const anchor1title = self.anchor1 && self.anchor1 !== self ? Cast(self.anchor1, Doc, null)?.title : '<?>';
-    const anchor2title = self.anchor2 && self.anchor2 !== self ? Cast(self.anchor2, Doc, null)?.title : '<?>';
-    const relation = self.linkRelationship || 'to';
-    return `${anchor1title} (${relation}) ${anchor2title}`;
-});
-ScriptingGlobals.add(function openTabAlias(tab: Doc) {
-    CollectionDockingView.AddSplit(Doc.MakeAlias(tab), OpenWhereMod.right);
+    const link_anchor_1title = self.link_anchor_1 && self.link_anchor_1 !== self ? Cast(self.link_anchor_1, Doc, null)?.title : '<?>';
+    const link_anchor_2title = self.link_anchor_2 && self.link_anchor_2 !== self ? Cast(self.link_anchor_2, Doc, null)?.title : '<?>';
+    const relation = self.link_relationship || 'to';
+    return `${link_anchor_1title} (${relation}) ${link_anchor_2title}`;
 });
diff --git a/src/client/documents/Gitlike.ts b/src/client/documents/Gitlike.ts
index 5e2baf924..f35f33f65 100644
--- a/src/client/documents/Gitlike.ts
+++ b/src/client/documents/Gitlike.ts
@@ -9,24 +9,24 @@
 // // we don't have individual timestamps for all fields -- this is a problematic design issue.
 // function GitlikeSynchDocs(bd: Doc, md: Doc) {
 //     const fieldKey = Doc.LayoutFieldKey(md);
-//     const bdate = DateCast(bd[`${fieldKey}-lastModified`])?.date;
-//     const mdate = DateCast(md[`${fieldKey}-lastModified`])?.date;
+//     const bdate = DateCast(bd[`${fieldKey}_modificationDate`])?.date;
+//     const mdate = DateCast(md[`${fieldKey}_modificationDate`])?.date;
 //     const bdproto = bd && Doc.GetProto(bd);
 //     if (bdate !== mdate && bdate <= mdate) {
 //         if (bdproto && md) {
 //             bdproto[fieldKey] = Field.Copy(md[fieldKey]);
-//             bdproto[`${fieldKey}-lastModified`] = new DateField();
+//             bdproto[`${fieldKey}_modificationDate`] = new DateField();
 //         }
 //     }
-//     const bldate = DateCast(bd._lastModified)?.date;
-//     const mldate = DateCast(md._lastModified)?.date;
+//     const bldate = DateCast(bd._layout_modificationDate)?.date;
+//     const mldate = DateCast(md._layout_modificationDate)?.date;
 //     if (bldate === mldate || bldate > mldate) return;
 //     if (bdproto && md) {
 //         bd.x = Field.Copy(md.x);
 //         bd.y = Field.Copy(md.y);
 //         bd.width = Field.Copy(md.width);
 //         bd.height = Field.Copy(md.height);
-//         bdproto._lastModified = new DateField();
+//         bdproto._layout_modificationDate = new DateField();
 //     }
 // }
 
@@ -53,10 +53,10 @@
 //     const newlyBranchedDocs = await Promise.all(newDocsFromMaster?.map(async md => (await Doc.MakeClone(md, false, true, cloneMap)).clone) || []);
 //     newlyBranchedDocs.forEach(nd => {
 //         Doc.AddDocToList(branch, Doc.LayoutFieldKey(branch) + suffix, nd);
-//         nd.context = branch;
+//         nd.embedContainer = branch;
 //     });
-//     // if a branch doc's corresponding main branch doc doesn't have a context, then it was deleted.
-//     const remDocsFromMaster = branchMainDocs?.filter(bd => Cast(bd.branchOf, Doc, null) && !Cast(bd.branchOf, Doc, null)?.context);
+//     // if a branch doc's corresponding main branch doc doesn't have a embedContainer, then it was deleted.
+//     const remDocsFromMaster = branchMainDocs?.filter(bd => Cast(bd.branchOf, Doc, null) && !Cast(bd.branchOf, Doc, null)?.embedContainer);
 //     // so then remove all the deleted main docs from this branch.
 //     remDocsFromMaster?.forEach(rd => Doc.RemoveDocFromList(branch, Doc.LayoutFieldKey(branch) + suffix, rd));
 // }
@@ -87,14 +87,14 @@
 //                 branchDocProto.branchOf = masterChild;                                 // the branch child is now a branch of the master child
 //             }
 //             Doc.AddDocToList(master, Doc.LayoutFieldKey(master) + suffix, masterChild); // add the masterChild to master (if it's already there, this is a no-op)
-//             masterChild.context = master;
+//             masterChild.embedContainer = master;
 //             GitlikeSynchDocs(masterChild, bd);//Doc.GetProto(masterChild), bd);
 //         }));
 //         const masterChildren = await DocListCastAsync(master[Doc.LayoutFieldKey(master) + suffix]);
 //         masterChildren?.forEach(mc => {                      // see if any master children
 //             if (!branchChildren?.find(bc => bc.branchOf === mc)) { //    are not in the list of children for this branch.
 //                 Doc.RemoveDocFromList(master, Doc.LayoutFieldKey(master) + suffix, mc); // if so, delete the master child since the branch has deleted it.
-//                 mc.context = undefined;      // NOTE if we merge a branch that didn't do a pull, it will look like the branch deleted documents -- need edit timestamps that prevent merging if branch isn't up-to-date with last edit timestamp
+//                 mc.embedContainer = undefined;      // NOTE if we merge a branch that didn't do a pull, it will look like the branch deleted documents -- need edit timestamps that prevent merging if branch isn't up-to-date with last edit timestamp
 //             }
 //         });
 //     });
@@ -109,8 +109,8 @@
 // export async function BranchTask(target: Doc, action: "pull" | "merge") {
 //     const func = action === "pull" ? GitlikePullFromMaster : GitlikeMergeWithMaster;
 //     await func(target, "");
-//     await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "-annotations"));
-//     await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "-sidebar"));
+//     await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "_annotations"));
+//     await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "_sidebar"));
 // }
 
 // export async function BranchCreate(target: Doc) {
diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx
index c9fcc84a3..d68761ba7 100644
--- a/src/client/util/CaptureManager.tsx
+++ b/src/client/util/CaptureManager.tsx
@@ -53,7 +53,7 @@ export class CaptureManager extends React.Component<{}> {
                 order.push(
                     <div className="list-item">
                         <div className="number">{i}</div>
-                        {StrCast(DocCast(l.anchor1)?.title)}
+                        {StrCast(DocCast(l.link_anchor_1)?.title)}
                     </div>
                 )
             );
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index fbfe306a4..5cfd77937 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -20,7 +20,7 @@ import { TreeViewType } from "../views/collections/CollectionTreeView";
 import { DashboardView } from "../views/DashboardView";
 import { Colors } from "../views/global/globalEnums";
 import { MainView } from "../views/MainView";
-import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox";
+import { ButtonType } from "../views/nodes/button/FontIconBox";
 import { OpenWhere } from "../views/nodes/DocumentView";
 import { OverlayView } from "../views/OverlayView";
 import { DragManager } from "./DragManager";
@@ -37,7 +37,6 @@ interface Button {
     toolTip?: string;
     icon?: string;
     btnType?: ButtonType;
-    numBtnType?: NumButtonType;
     numBtnMin?: number;
     numBtnMax?: number;
     switchToggle?: boolean;
@@ -65,11 +64,11 @@ export class CurrentUserUtils {
         const requiredTypeNameFields:{btnOpts:DocumentOptions, templateOpts:DocumentOptions, template:(opts:DocumentOptions) => Doc}[] = [
             {
                 btnOpts: { title: "slide", icon: "address-card" }, 
-                templateOpts: { _width: 400, _height: 300, title: "slideView",  _xMargin: 3, _yMargin: 3, system: true }, 
+                templateOpts: { _width: 400, _height: 300, title: "slideView",  _xMargin: 3, _yMargin: 3, isSystem: true }, 
                 template: (opts:DocumentOptions) => Docs.Create.MultirowDocument(
                     [
-                        Docs.Create.MulticolumnDocument([], { title: "data", _height: 200,  system: true }),
-                        Docs.Create.TextDocument("", { title: "text", _fitWidth:true,  _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) })
+                        Docs.Create.MulticolumnDocument([], { title: "data", _height: 200,  isSystem: true }),
+                        Docs.Create.TextDocument("", { title: "text", _layout_fitWidth:true,  _height: 100, isSystem: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) })
                     ], opts)
             },
             {
@@ -97,9 +96,9 @@ export class CurrentUserUtils {
         });
 
         const reqdOpts:DocumentOptions = {
-            title: "Experimental Tools", _xMargin: 0, _showTitle: "title", _chromeHidden: true,
-            _stayInCollection: true, _hideContextMenu: true, _forceActive: true, system: true,
-            _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
+            title: "Experimental Tools", _xMargin: 0, _layout_showTitle: "title", _chromeHidden: true,
+            _stayInCollection: true, _hideContextMenu: true, _forceActive: true, isSystem: true,
+            _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
         };
         const reqdScripts = { dropConverter : "convertToButtons(dragData)" };
         const reqdFuncs = { hidden: "IsNoviceMode()" };
@@ -109,7 +108,7 @@ export class CurrentUserUtils {
     /// Initializes templates for editing click funcs of a document 
     static setupChildClickEditors(doc: Doc, field = "clickFuncs-child") {
         const tempClicks = DocCast(doc[field]);
-        const reqdClickOpts:DocumentOptions = {_width: 300, _height:200, system: true};
+        const reqdClickOpts:DocumentOptions = {_width: 300, _height:200, isSystem: true};
         const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [
             { opts: { title: "Open In Target",        targetScriptKey: "onChildClick"},       script: "docCast(documentView?.props.docViewPath().lastElement()?.rootDoc.target).then((target) => target && (target.proto.data = new List([self])))"},
             { opts: { title: "Open Detail On Right",  targetScriptKey: "onChildDoubleClick"}, script: `openDoc(self.doubleClickView.${OpenWhere.addRight})`}];
@@ -119,14 +118,14 @@ export class CurrentUserUtils {
             return DocUtils.AssignOpts(clickDoc, allOpts) ?? Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, allOpts),allOpts);
         });
 
-        const reqdOpts:DocumentOptions = { title: "child click editors", _height:75, system: true};
+        const reqdOpts:DocumentOptions = { title: "child click editors", _height:75, isSystem: true};
         return DocUtils.AssignOpts(tempClicks, reqdOpts, reqdClickList) ?? (doc[field] = Docs.Create.TreeDocument(reqdClickList, reqdOpts));
     }
 
     /// Initializes templates for editing click funcs of a document 
     static setupClickEditorTemplates(doc: Doc, field = "template-clickFuncs") {
         const tempClicks = DocCast(doc[field]);
-        const reqdClickOpts:DocumentOptions = { _width: 300, _height:200, system: true};
+        const reqdClickOpts:DocumentOptions = { _width: 300, _height:200, isSystem: true};
         const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [
             { opts: { title: "onClick"},             script: "console.log('click')"},
             { opts: { title: "onDoubleClick"},       script: "console.log('click')"},
@@ -140,7 +139,7 @@ export class CurrentUserUtils {
             return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name}), allOpts), true, opts.opts.title);
         });
 
-        const reqdOpts:DocumentOptions = {title: "click editor templates", _height:75, system: true};
+        const reqdOpts:DocumentOptions = {title: "click editor templates", _height:75, isSystem: true};
         return DocUtils.AssignOpts(tempClicks, reqdOpts, reqdClickList) ?? (doc[field] = Docs.Create.TreeDocument(reqdClickList, reqdOpts));
     }
 
@@ -152,12 +151,12 @@ export class CurrentUserUtils {
             { noteType: "Idea", backgroundColor: "pink", icon: "lightbulb" },
             { noteType: "Topic", backgroundColor: "lightblue", icon: "book-open" }];
         const reqdNoteList = reqdTempOpts.map(opts => {
-            const reqdOpts = {...opts, title: "text", width:200, autoHeight: true, fitWidth: true};
+            const reqdOpts = {...opts, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true};
             const noteType = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.noteType === opts.noteType): undefined;
             return DocUtils.AssignOpts(noteType, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts), true, opts.noteType??"Note");
         });
 
-        const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, system: true };
+        const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, isSystem: true };
         return DocUtils.AssignOpts(tempNotes, reqdOpts, reqdNoteList) ?? (doc[field] = Docs.Create.TreeDocument(reqdNoteList, reqdOpts));
     }
 
@@ -169,14 +168,14 @@ export class CurrentUserUtils {
             CurrentUserUtils.setupClickEditorTemplates(doc)
         ];
         CurrentUserUtils.setupChildClickEditors(doc)
-        const reqdOpts = { title: "template layouts", _xMargin: 0, system: true,  };
+        const reqdOpts = { title: "template layouts", _xMargin: 0, isSystem: true,  };
         const reqdScripts = {  dropConverter: "convertToButtons(dragData)"  };
         return DocUtils.AssignDocField(doc, field, (opts,items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, templates, reqdScripts);
     }
 
     // setup templates for different document types when they are iconified from Document Decorations
     static setupDefaultIconTemplates(doc: Doc, field="template-icons") {
-        const reqdOpts = { title: "icon templates", _height: 75, system: true };
+        const reqdOpts = { title: "icon templates", _height: 75, isSystem: true };
         const templateIconsDoc = DocUtils.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts));
 
         const makeIconTemplate = (type: DocumentType | undefined, templateField: string, opts:DocumentOptions) => {
@@ -187,7 +186,7 @@ export class CurrentUserUtils {
                 case DocumentType.IMG : creator = imageBox; break;
                 case DocumentType.FONTICON: creator = fontBox; break;
             }
-            const allopts = {system: true, onClickScriptDisable: "never",  ...opts};
+            const allopts = {isSystem: true, onClickScriptDisable: "never",  ...opts};
             return DocUtils.AssignScripts(  (curIcon?.iconTemplate === opts.iconTemplate ? 
                       DocUtils.AssignOpts(curIcon, allopts):undefined) ?? ((templateIconsDoc[iconFieldName] = MakeTemplate(creator(allopts), true, iconFieldName, templateField))),
                 {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", });
@@ -195,14 +194,14 @@ export class CurrentUserUtils {
         const labelBox = (opts: DocumentOptions, data?:string) => Docs.Create.LabelDocument({
             textTransform: "unset", letterSpacing: "unset", _singleLine: false, _minFontSize: 14, _maxFontSize: 24, borderRounding: "5px",  _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
         });
-        const imageBox = (opts: DocumentOptions, url?:string) => Docs.Create.ImageDocument(url ?? "http://www.cs.brown.edu/~bcz/noImage.png", { "icon-nativeWidth": 360 / 4, "icon-nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG,  _width: 360 / 4, _height: 270 / 4,  _showTitle: "title", ...opts });
+        const imageBox = (opts: DocumentOptions, url?:string) => Docs.Create.ImageDocument(url ?? "http://www.cs.brown.edu/~bcz/noImage.png", { "icon_nativeWidth": 360 / 4, "icon_nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG,  _width: 360 / 4, _height: 270 / 4,  _layout_showTitle: "title", ...opts });
         const fontBox = (opts:DocumentOptions, data?:string) => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts  });
         const iconTemplates = [
             makeIconTemplate(undefined,          "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "dimgray"}),
             makeIconTemplate(DocumentType.AUDIO, "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "lightgreen"}),
             makeIconTemplate(DocumentType.PDF,   "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "pink"}),
             makeIconTemplate(DocumentType.WEB,   "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "brown"}),
-            makeIconTemplate(DocumentType.RTF,   "text",  { iconTemplate:DocumentType.LABEL, _showTitle: "creationDate"}),
+            makeIconTemplate(DocumentType.RTF,   "text",  { iconTemplate:DocumentType.LABEL, _layout_showTitle: "creationDate"}),
             makeIconTemplate(DocumentType.IMG,   "data",  { iconTemplate:DocumentType.IMG,   _height: undefined}),
             makeIconTemplate(DocumentType.COL,   "icon",  { iconTemplate:DocumentType.IMG}),
             makeIconTemplate(DocumentType.COL,   "icon",  { iconTemplate:DocumentType.IMG}),
@@ -220,7 +219,7 @@ export class CurrentUserUtils {
         title: string, toolTip: string, icon: string,  ignoreClick?: boolean, dragFactory?: Doc, 
         backgroundColor?: string, openFactoryAsDelegate?:boolean, openFactoryLocation?:string, clickFactory?: Doc, scripts?: { onClick?: string, onDragStart?: string}, funcs?: {onDragStart?:string, hidden?: string},
     }[] {
-        const standardOps = (key:string) => ({ title : "Untitled "+ key, _fitWidth: false, system: true, "dragFactory-count": 0, cloneFieldFilter: new List<string>(["system"]) });
+        const standardOps = (key:string) => ({ title : "Untitled "+ key, _layout_fitWidth: false, isSystem: true, "dragFactory_count": 0, cloneFieldFilter: new List<string>(["isSystem"]) });
         const json = {
             doc: {
                 type: "doc",
@@ -247,7 +246,7 @@ export class CurrentUserUtils {
                 "<HTMLdiv transformOrigin='top left' width='{100/scale}%' height='{100/scale}%' transform='scale({scale})'>" +
                 `    <FormattedTextBox {...props} dontScale='true' fieldKey={'text'} height='calc(100% - ${headerBtnHgt}px - {this._headerHeight||0}px)'/>` +
                 "    <FormattedTextBox {...props} dontScale='true' fieldKey={'header'} dontSelectOnLoad='true' ignoreAutoHeight='true' fontSize='{this._headerFontSize||9}px' height='{(this._headerHeight||0)}px' backgroundColor='{this._headerColor || MySharedDocs().userColor||`lightGray`}' />" +
-                `    <HTMLdiv fontSize='${headerBtnHgt - 1}px' height='${headerBtnHgt}px' backgroundColor='yellow' onClick={‘(this._headerHeight=scale*Math.min(Math.max(0,this._height-30),this._headerHeight===0?50:0)) + (this._autoHeightMargins=this._headerHeight ? this._headerHeight+${headerBtnHgt}:0)’}  >Metadata</HTMLdiv>` +
+                `    <HTMLdiv fontSize='${headerBtnHgt - 1}px' height='${headerBtnHgt}px' backgroundColor='yellow' onClick={‘(this._headerHeight=scale*Math.min(Math.max(0,this._height-30),this._headerHeight===0?50:0)) + (this._layout_autoHeightMargins=this._headerHeight ? this._headerHeight+${headerBtnHgt}:0)’}  >Metadata</HTMLdiv>` +
                 "</HTMLdiv>"
             }, "header");
 
@@ -263,27 +262,27 @@ export class CurrentUserUtils {
                           funcs?:{[key:string]: any},  // computed fields that are rquired for the empth thing
                           creator:(opts:DocumentOptions)=> any // how to create the empty thing if it doesn't exist
               }[] = [
-            {key: "Note",       creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _autoHeight: true }},
-            {key: "Flashcard",  creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _autoHeight: true, _showAltContentUI: true}},
-            {key: "Equation",   creator: opts => Docs.Create.EquationDocument(opts),        opts: { _width: 300, _height: 35, _backgroundGridShow: true, }},
-            {key: "Noteboard",  creator: opts => Docs.Create.NoteTakingDocument([], opts),  opts: { _width: 250, _height: 200, _fitWidth: true}},
-            {key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 150, _height: 100, _fitWidth: true }},
-            {key: "Webpage",    creator: opts => Docs.Create.WebDocument("",opts),          opts: { _width: 400, _height: 512, _nativeWidth: 850, useCors: true, }},
+            {key: "Note",       creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _layout_autoHeight: true }},
+            {key: "Flashcard",  creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _layout_autoHeight: true, _layout_altContentUI: true}},
+            {key: "Equation",   creator: opts => Docs.Create.EquationDocument(opts),        opts: { _width: 300, _height: 35, }},
+            {key: "Noteboard",  creator: opts => Docs.Create.NoteTakingDocument([], opts),  opts: { _width: 250, _height: 200, _layout_fitWidth: true}},
+            {key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 150, _height: 100, _layout_fitWidth: true }},
+            {key: "Webpage",    creator: opts => Docs.Create.WebDocument("",opts),          opts: { _width: 400, _height: 512, _nativeWidth: 850, data_useCors: true, }},
             {key: "Comparison", creator: Docs.Create.ComparisonDocument,                    opts: { _width: 300, _height: 300 }},
             {key: "Audio",      creator: opts => Docs.Create.AudioDocument(nullAudio, opts),opts: { _width: 200, _height: 100, }},
-            {key: "Map",        creator: opts => Docs.Create.MapDocument([], opts),         opts: { _width: 800, _height: 600, _fitWidth: true, _showSidebar: true,  }},
+            {key: "Map",        creator: opts => Docs.Create.MapDocument([], opts),         opts: { _width: 800, _height: 600, _layout_fitWidth: true, _layout_showSidebar: true,  }},
             {key: "Screengrab", creator: Docs.Create.ScreenshotDocument,                    opts: { _width: 400, _height: 200 }},
-            {key: "WebCam",     creator: opts => Docs.Create.WebCamDocument("", opts),      opts: { _width: 400, _height: 200, recording:true, system: true, cloneFieldFilter: new List<string>(["system"]) }},
+            {key: "WebCam",     creator: opts => Docs.Create.WebCamDocument("", opts),      opts: { _width: 400, _height: 200, recording:true, isSystem: true, cloneFieldFilter: new List<string>(["isSystem"]) }},
             {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, onClick: FollowLinkScript()}},
             {key: "Script",     creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }},
             {key: "DataViz",    creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts),   opts: { _width: 300, _height: 300 }},
-            {key: "Header",     creator: headerTemplate,                                    opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, treeViewHideUnrendered: true}},
-            {key: "Trail",      creator: Docs.Create.PresDocument,                          opts: { _width: 400, _height: 30, _viewType: CollectionViewType.Stacking, targetDropAction: "alias" as any, treeViewHideTitle: true, _fitWidth:true, _chromeHidden: true, boxShadow: "0 0" }},
-            {key: "Tab",        creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 500, _height: 800, _fitWidth: true, _backgroundGridShow: true, }},
+            {key: "Header",     creator: headerTemplate,                                    opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeViewHideUnrendered: true}},
+            {key: "Trail",      creator: Docs.Create.PresDocument,                          opts: { _width: 400, _height: 30, _viewType: CollectionViewType.Stacking, targetDropAction: "embed" as any, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, boxShadow: "0 0" }},
+            {key: "Tab",        creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }},
             {key: "Slide",      creator: opts => Docs.Create.TreeDocument([], opts),        opts: { _width: 300, _height: 200, _viewType: CollectionViewType.Tree, 
-                                                                                                treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, 
+                                                                                                treeViewHasOverlay: true, _fontSize: "20px", _layout_autoHeight: true, 
                                                                                                 allowOverlayDrop: true, treeViewType: TreeViewType.outline, 
-                                                                                                backgroundColor: "white", _xMargin: 0, _yMargin: 0, _singleLine: true 
+                                                                                                backgroundColor: "white", _xMargin: 0, _yMargin: 0, _createDocOnCR: true 
                                                                                             }, funcs: {title: 'self.text?.Text'}},
             ];
 
@@ -320,16 +319,16 @@ export class CurrentUserUtils {
             const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined;
             const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["funcs", "scripts", "backgroundColor"]).omit, 
                 _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, 
-                btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, system: true,
+                btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, isSystem: true,
                 _removeDropProperties: new List<string>(["_stayInCollection"]),
                 };
             return DocUtils.AssignScripts(DocUtils.AssignOpts(btn, opts) ?? Docs.Create.FontIconDocument(opts), reqdOpts.scripts, reqdOpts.funcs);
         });
 
         const reqdOpts:DocumentOptions = {
-            title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, system: true,
-            _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true,
-             childDropAction: 'alias' 
+            title: "Basic Item Creators", _layout_showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, isSystem: true,
+            _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true,
+             childDropAction: 'embed' 
         };
         const reqdScripts = { dropConverter: "convertToButtons(dragData)" };
         return DocUtils.AssignScripts(DocUtils.AssignOpts(dragCreatorDoc, reqdOpts, creatorBtns) ?? Docs.Create.MasonryDocument(creatorBtns, reqdOpts), reqdScripts);
@@ -354,7 +353,7 @@ export class CurrentUserUtils {
 
     /// the empty panel that is filled with whichever left menu button's panel has been selected
     static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") {
-        DocUtils.AssignDocField(doc, field, (opts) => ((doc:Doc) => {doc.system = true; return doc;})(new Doc()), {system:true});
+        DocUtils.AssignDocField(doc, field, (opts) => ((doc:Doc) => {doc.isSystem = true; return doc;})(new Doc()), {isSystem:true});
     }
 
     /// Initializes the left sidebar menu buttons and the panels they open up
@@ -364,8 +363,8 @@ export class CurrentUserUtils {
         const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, scripts, funcs }) => {
             const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
             const reqdBtnOpts:DocumentOptions = {
-                title, icon, target, btnType: ButtonType.MenuButton, system: true, dontUndo: true,  dontRegisterView: true,
-                _width: 60, _height: 60,  _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, 
+                title, icon, target, btnType: ButtonType.MenuButton, isSystem: true, dontUndo: true,  dontRegisterView: true,
+                _width: 60, _height: 60,  _stayInCollection: true, _hideContextMenu: true,
                 _removeDropProperties: new List<string>(["_stayInCollection"]),
             };
             return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs);
@@ -373,14 +372,14 @@ export class CurrentUserUtils {
 
         const reqdStackOpts:DocumentOptions ={
             title: "menuItemPanel", childDropAction: "same", backgroundColor: Colors.DARK_GRAY, boxShadow: "rgba(0,0,0,0)",  dontRegisterView: true, ignoreClick: true,
-            _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, system: true,
+            _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _layout_autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, isSystem: true,
         };
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdStackOpts, menuBtns, { dropConverter: "convertToButtons(dragData)" });
     }
 
     // Sets up mobile menu if it is undefined creates a new one, otherwise returns existing menu
     static setupActiveMobileMenu(doc: Doc, field="activeMobileMenu") {
-        const reqdOpts = { _width: 980, ignoreClick: true, _lockedPosition: false, title: "home", _yMargin: 100, system: true, _chromeHidden: true,};
+        const reqdOpts = { _width: 980, ignoreClick: true, _lockedPosition: false, title: "home", _yMargin: 100, isSystem: true, _chromeHidden: true,};
         DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(this.setupMobileButtons(), opts), reqdOpts);
     }
 
@@ -401,9 +400,9 @@ export class CurrentUserUtils {
                 title: data.title,
                 _lockedPosition: true,
                 onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
-                backgroundColor: data.backgroundColor, system: true
+                backgroundColor: data.backgroundColor, isSystem: true
             },
-                [this.createToolButton({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)", system: true, btnType: ButtonType.ClickButton, }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])])
+                [this.createToolButton({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)", isSystem: true, btnType: ButtonType.ClickButton, }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])])
         );
     }
 
@@ -411,51 +410,51 @@ export class CurrentUserUtils {
     static mobileButton = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MulticolumnDocument(docs, {
         ...opts,
          _nativeWidth: 900, _nativeHeight: 250, _width: 900, _height: 250, _yMargin: 15,
-        borderRounding: "5px", boxShadow: "0 0", system: true
+        borderRounding: "5px", boxShadow: "0 0", isSystem: true
     }) as any as Doc
 
     // sets up the text container for the information contained within the mobile button
     static mobileTextContainer = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MultirowDocument(docs, {
         ...opts,
         _nativeWidth: 450, _nativeHeight: 250, _width: 450, _height: 250, _yMargin: 25,
-        backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", ignoreClick: true, system: true
+        backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", ignoreClick: true, isSystem: true
     }) as any as Doc
 
     // Sets up the title of the button
     static mobileButtonText = (opts: DocumentOptions, buttonTitle: string) => Docs.Create.TextDocument(buttonTitle, {
         ...opts,
-        title: buttonTitle, _fontSize: "37px", _xMargin: 0, _yMargin: 0, ignoreClick: true, backgroundColor: "rgba(0,0,0,0)", system: true
+        title: buttonTitle, _fontSize: "37px", _xMargin: 0, _yMargin: 0, ignoreClick: true, backgroundColor: "rgba(0,0,0,0)", isSystem: true
     }) as any as Doc
 
     // Sets up the description of the button
     static mobileButtonInfo = (opts: DocumentOptions, buttonInfo: string) => Docs.Create.TextDocument(buttonInfo, {
         ...opts,
-        title: "info", _fontSize: "25px", _xMargin: 0, _yMargin: 0, ignoreClick: true, backgroundColor: "rgba(0,0,0,0)", _dimMagnitude: 2, system: true
+        title: "info", _fontSize: "25px", _xMargin: 0, _yMargin: 0, ignoreClick: true, backgroundColor: "rgba(0,0,0,0)", _dimMagnitude: 2, isSystem: true
     }) as any as Doc
 
 
 
     static setupMobileInkingDoc(userDoc: Doc) {
-        return Docs.Create.FreeformDocument([], { title: "Mobile Inking", backgroundColor: "white", system: true });
+        return Docs.Create.FreeformDocument([], { title: "Mobile Inking", backgroundColor: "white", isSystem: true });
     }
 
     static setupMobileUploadDoc(userDoc: Doc) {
         // const addButton = Docs.Create.FontIconDocument({ onDragStart: ScriptField.MakeScript('addWebToMobileUpload()'), title: "Add Web Doc to Upload Collection", icon: "plus", backgroundColor: "black" })
         const webDoc = Docs.Create.WebDocument("https://www.britannica.com/biography/Miles-Davis", {
-            title: "Upload Images From the Web", _lockedPosition: true, system: true
+            title: "Upload Images From the Web", _lockedPosition: true, isSystem: true
         });
         const uploadDoc = Docs.Create.StackingDocument([], {
-            title: "Mobile Upload Collection", backgroundColor: "white", _lockedPosition: true, system: true, _chromeHidden: true,
+            title: "Mobile Upload Collection", backgroundColor: "white", _lockedPosition: true, isSystem: true, _chromeHidden: true,
         });
         return Docs.Create.StackingDocument([webDoc, uploadDoc], {
-            _width: screen.width, _lockedPosition: true, title: "Upload", _autoHeight: true, _yMargin: 80, backgroundColor: "lightgray", system: true, _chromeHidden: true,
+            _width: screen.width, _lockedPosition: true, title: "Upload", _layout_autoHeight: true, _yMargin: 80, backgroundColor: "lightgray", isSystem: true, _chromeHidden: true,
         });
     }
 
     /// Search option on the left side button panel
     static setupSearcher(doc: Doc, field:string) {
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.SearchDocument(opts), {
-                dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", system: true, childDropAction: "alias", 
+                dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", isSystem: true, childDropAction: "embed", 
                 _lockedPosition: true, _viewType: CollectionViewType.Schema, _searchDoc: true,  });
     }
 
@@ -465,8 +464,8 @@ export class CurrentUserUtils {
         const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, DocListCast(myTools?.data)?.length ? DocListCast(myTools.data)[0]:undefined);
         const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc,DocListCast(myTools?.data)?.length > 1 ? DocListCast(myTools.data)[1]:undefined);
         const reqdToolOps:DocumentOptions = {
-            title: "My Tools", system: true, ignoreClick: true, boxShadow: "0 0",
-            _showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, 
+            title: "My Tools", isSystem: true, ignoreClick: true, boxShadow: "0 0",
+            _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, 
         };
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdToolOps, [creatorBtns, templateBtns]);
     }
@@ -479,7 +478,7 @@ export class CurrentUserUtils {
         const newDashboard = `createNewDashboard()`;
 
         const reqdBtnOpts:DocumentOptions = { _forceActive: true,  _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true,
-             title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", system: true };
+             title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", isSystem: true };
         const reqdBtnScript = {onClick: newDashboard,}
         const newDashboardButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myDashboards?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
        
@@ -492,9 +491,9 @@ export class CurrentUserUtils {
         const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters
         const reqdOpts:DocumentOptions = {
             title: "My Dashboards", childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, boxShadow: "0 0", childDontRegisterViews: true,
-            targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true,  treeViewTruncateTitleWidth: 350, ignoreClick: true, 
-            buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "alias",
-            _showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
+            targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true,  treeViewTruncateTitleWidth: 350, ignoreClick: true, 
+            buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "embed",
+            _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
             contextMenuLabels:new List<string>(contextMenuLabels),
             contextMenuIcons:new List<string>(contextMenuIcons),
             childContextMenuLabels:new List<string>(childContextMenuLabels),
@@ -517,20 +516,20 @@ export class CurrentUserUtils {
     /// initializes the left sidebar File system pane
     static setupFilesystem(doc: Doc, field:string) {
         var myFilesystem = DocCast(doc[field]);
-        const myFileOrphans = DocUtils.AssignDocField(doc, "myFileOrphans", (opts) => Docs.Create.TreeDocument([], opts), { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true });
+        const myFileOrphans = DocUtils.AssignDocField(doc, "myFileOrphans", (opts) => Docs.Create.TreeDocument([], opts), { title: "Unfiled", _stayInCollection: true, isSystem: true, isFolder: true });
         
         const newFolder = `TreeView_addNewFolder()`;
         const newFolderOpts: DocumentOptions = {
             _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _width: 30, _height: 30,
-            title: "New folder", btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", system: true
+            title: "New folder", btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true
         };
         const newFolderScript = { onClick: newFolder};
         const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.buttonMenuDoc), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
         
-        const reqdOpts:DocumentOptions = { _showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, 
-            title: "My Documents", buttonMenu: true, buttonMenuDoc: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", system: true,
+        const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, 
+            title: "My Documents", buttonMenu: true, buttonMenuDoc: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", isSystem: true,
             isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, boxShadow: "0 0", childDontRegisterViews: true, 
-            treeViewTruncateTitleWidth: 350, ignoreClick: true, childDropAction: "alias",
+            treeViewTruncateTitleWidth: 350, ignoreClick: true, childDropAction: "embed",
             childContextMenuLabels: new List<string>(["Create new folder"]),
             childContextMenuIcons: new List<string>(["plus"]),
             explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
@@ -545,8 +544,8 @@ export class CurrentUserUtils {
 
     /// initializes the panel displaying docs that have been recently closed
     static setupRecentlyClosed(doc: Doc, field:string) {
-        const reqdOpts:DocumentOptions = { _showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, 
-            title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "alias", system: true,
+        const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, 
+            title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "embed", isSystem: true,
             treeViewTruncateTitleWidth: 350, ignoreClick: true,  boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same",
             contextMenuLabels: new List<string>(["Empty recently closed"]),
             contextMenuIcons:new List<string>(["trash"]),
@@ -556,7 +555,7 @@ export class CurrentUserUtils {
 
         const clearAll = (target:string) => `getProto(${target}).data = new List([])`;
         const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, 
-            title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton,  buttonText: "Empty", icon: "trash", system: true,
+            title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton,  buttonText: "Empty", icon: "trash", isSystem: true,
             toolTip: "Empty recently closed",};
         const clearDocsButton = DocUtils.AssignDocField(recentlyClosed, "clearDocsBtn", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
 
@@ -572,7 +571,7 @@ export class CurrentUserUtils {
     static setupUserDocView(doc: Doc, field:string) {
         const reqdOpts:DocumentOptions = {
             _lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view",
-            boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, system: true,
+            boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, isSystem: true,
             treeViewHideTitle: true, treeViewTruncateTitleWidth: 350
         };
         if (!doc[field]) DocUtils.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" });
@@ -582,13 +581,13 @@ export class CurrentUserUtils {
     static linearButtonList = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.LinearDocument(docs, {
         ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, boxShadow: "0 0", _forceActive: true,
         dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
-        _lockedPosition: true, system: true, flexDirection: "row"
+        _lockedPosition: true, isSystem: true, flexDirection: "row"
     })
 
     static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({
         btnType: ButtonType.ToolButton, _forceActive: true, _hideContextMenu: true, 
         _removeDropProperties: new List<string>([ "_hideContextMenu", "stayInCollection"]), 
-        _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true, ...opts,
+        _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, isSystem: true, ...opts,
     })
 
     /// initializes the required buttons in the expanding button menu at the bottom of the Dash window
@@ -606,7 +605,7 @@ export class CurrentUserUtils {
         ];
         const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts));
         const dockBtnsReqdOpts:DocumentOptions = {
-            title: "docked buttons", _height: 40, flexGap: 0, boxShadow: "standard", childDropAction: 'alias',
+            title: "docked buttons", _height: 40, flexGap: 0, boxShadow: "standard", childDropAction: 'embed',
             childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true
         };
         reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
@@ -623,7 +622,7 @@ export class CurrentUserUtils {
     }
     static viewTools(): Button[] {
         return [
-            { title: "Snap\xA0Lines", icon: "th",           toolTip: "Show Snap Lines",     btnType: ButtonType.ToggleButton, expertMode: false, toolType:"snap lines", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
+            { title: "Snap\xA0Lines", icon: "th",           toolTip: "Show Snap Lines",     btnType: ButtonType.ToggleButton, expertMode: false, toolType:"snaplines",  funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
             { title: "Grid",          icon: "border-all",   toolTip: "Show Grid",           btnType: ButtonType.ToggleButton, expertMode: false, toolType:"grid",       funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
             { title: "View\xA0All",   icon: "object-group", toolTip: "Fit all Docs to View",btnType: ButtonType.ToggleButton, expertMode: false, toolType:"viewAll",    funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
             { title: "Clusters",      icon: "braille",      toolTip: "Show Doc Clusters",   btnType: ButtonType.ToggleButton, expertMode: false, toolType:"clusters",   funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
@@ -635,7 +634,7 @@ export class CurrentUserUtils {
         return [
             { title: "Font",    toolTip: "Font", width: 100,     btnType: ButtonType.DropdownList,                      toolType:"font",     ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'},
               btnList: new List<string>(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) },
-            { title: "Size",    toolTip: "Font size (%size)",    btnType: ButtonType.NumberButton, width: 75,           toolType:"fontSize", ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 0, numBtnType: NumButtonType.DropdownOptions },
+            { title: "Size",    toolTip: "Font size (%size)",    btnType: ButtonType.NumberDropdownButton, width: 75,           toolType:"fontSize", ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 0 },
             { title: "Color",   toolTip: "Font color (%color)",  btnType: ButtonType.ColorButton,  icon: "font",        toolType:"fontColor",ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'}},
             { title: "Highlight",toolTip:"Font highlight",       btnType: ButtonType.ColorButton,  icon: "highlighter", toolType:"highlight",ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} },
             { title: "Bold",    toolTip: "Bold (Ctrl+B)",        btnType: ButtonType.ToggleButton, icon: "bold",        toolType:"bold",                          scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
@@ -663,7 +662,7 @@ export class CurrentUserUtils {
             { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square",     toolType:GestureUtils.Gestures.Rectangle,   scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} },
             { title: "Line",   toolTip: "Line (double tap to lock mode)",   btnType: ButtonType.ToggleButton, icon: "minus",      toolType:GestureUtils.Gestures.Line,        scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} },
             { title: "Mask",   toolTip: "Mask",                             btnType: ButtonType.ToggleButton, icon: "user-circle",toolType: "inkMask",                        scripts: {onClick:'{ return setInkProperty(self.toolType, value, _readOnly_);}'} },
-            { title: "Width",  toolTip: "Stroke width",                     btnType: ButtonType.NumberButton,                     toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'}, numBtnType: NumButtonType.Slider, numBtnMin: 1},
+            { title: "Width",  toolTip: "Stroke width",                     btnType: ButtonType.NumberSliderButton,               toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'}, numBtnMin: 1},
             { title: "Ink",    toolTip: "Stroke color",                     btnType: ButtonType.ColorButton,  icon: "pen",        toolType: "strokeColor", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'} },
         ];
     }
@@ -712,7 +711,7 @@ export class CurrentUserUtils {
         const reqdOpts:DocumentOptions = {
             ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit,
             backgroundColor: params.backgroundColor ??"transparent", ///  a bit hacky. if an onClick is specified, then assume a toggle uses onClick to get the backgroundColor (see below).  Otherwise, assume a transparent background
-            color: Colors.WHITE, system: true, dontUndo: true, 
+            color: Colors.WHITE, isSystem: true, dontUndo: true, 
             _nativeWidth: params.width ?? 30, _width: params.width ?? 30,
             _height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth,
             toolType: params.toolType, expertMode: params.expertMode,
@@ -728,7 +727,7 @@ export class CurrentUserUtils {
 
     /// Initializes all the default buttons for the top bar context menu
     static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") {
-        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", flexGap: 0, childDropAction: 'alias', childDontRegisterViews: true,  linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 };
+        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", flexGap: 0, childDropAction: 'embed', childDontRegisterViews: true,  linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 };
         const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined);
         const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => {
             const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title);
@@ -750,11 +749,11 @@ export class CurrentUserUtils {
 
     /// collection of documents rendered in the overlay layer above all tabs and other UI
     static setupOverlays(doc: Doc, field = "myOverlayDocs") {
-        return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.FreeformDocument([], opts), { title: "overlay documents", backgroundColor: "#aca3a6", system: true });
+        return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.FreeformDocument([], opts), { title: "overlay documents", backgroundColor: "#aca3a6", isSystem: true });
     }
 
     static setupPublished(doc:Doc, field = "myPublishedDocs") {
-        return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), { title: "published docs", backgroundColor: "#aca3a6", system: true });
+        return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), { title: "published docs", backgroundColor: "#aca3a6", isSystem: true });
     }
     
     /// The database of all links on all documents
@@ -788,9 +787,9 @@ export class CurrentUserUtils {
             childContextMenuLabels: new List<string>(["Add to Dashboards",]),
             childContextMenuIcons: new List<string>(["user-plus",]),
             "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment,
-            childDropAction: "alias", system: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true,
-            // NOTE: treeViewHideTitle & _showTitle is for a TreeView's editable title, _showTitle is for DocumentViews title bar
-            _showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, 
+            childDropAction: "embed", isSystem: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true,
+            // NOTE: treeViewHideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar
+            _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, 
             explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
         };
         
@@ -800,16 +799,16 @@ export class CurrentUserUtils {
     /// Import option on the left side button panel 
     static setupImportSidebar(doc: Doc, field:string) {   
         const reqdOpts:DocumentOptions = {
-            title: "My Imports", _forceActive: true, buttonMenu: true, ignoreClick: true, _showTitle: "title", 
+            title: "My Imports", _forceActive: true, buttonMenu: true, ignoreClick: true, _layout_showTitle: "title", 
             _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0,
-            childDropAction: "copy", _autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, system: true, _chromeHidden: true,
+            childDropAction: "copy", _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true,
             dontRegisterView: true, explainer: "This is where documents that are Imported into Dash will go."
         };
         const myImports = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.StackingDocument([], opts), reqdOpts);
     
         const reqdBtnOpts:DocumentOptions = { _forceActive: true, toolTip: "Import from computer",
             _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, 
-            buttonText: "Import", icon: "upload", system: true };
+            buttonText: "Import", icon: "upload", isSystem: true };
         DocUtils.AssignDocField(myImports, "buttonMenuDoc", (opts) => Docs.Create.FontIconDocument(opts), reqdBtnOpts, undefined, { onClick: "importDocument()" });
         return myImports;
     }
@@ -818,13 +817,13 @@ export class CurrentUserUtils {
     /// whether to revert to "default" values, or to leave them as the user/system last set them.
     static updateUserDocument(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) {
         DocUtils.AssignDocField(doc, "globalGroupDatabase", () => Docs.Prototypes.MainGroupDocument(), {});
-        reaction(() => DateCast(DocCast(doc.globalGroupDatabase)["data-lastModified"]),
+        reaction(() => DateCast(DocCast(doc.globalGroupDatabase)["data_modificationDate"]),
             async () => {
                 const groups = await DocListCastAsync(DocCast(doc.globalGroupDatabase).data);
                 const mygroups = groups?.filter(group => JSON.parse(StrCast(group.members)).includes(Doc.CurrentUserEmail)) || [];
                 SetCachedGroups(["Public", ...mygroups?.map(g => StrCast(g.title))]);
             }, { fireImmediately: true });
-        doc.system ?? (doc.system = true);
+        doc.isSystem ?? (doc.isSystem = true);
         doc.title ?? (doc.title = Doc.CurrentUserEmail);
         Doc.noviceMode ?? (Doc.noviceMode = true);
         doc._raiseWhenDragged ?? (doc._raiseWhenDragged = true);
@@ -860,7 +859,7 @@ export class CurrentUserUtils {
         this.setupDocTemplates(doc); // sets up the template menu of templates
         this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption
         DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) =>  Docs.Prototypes.MainScriptDocument(), {});
-        DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "header bar", system: true }); // drop down panel at top of dashboard for stashing documents
+        DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "header bar", isSystem: true }); // drop down panel at top of dashboard for stashing documents
         
         Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs)
 
@@ -874,13 +873,13 @@ export class CurrentUserUtils {
         return doc;
     }
     static setupFieldInfos(doc:Doc, field="fieldInfos") {
-        const fieldInfoOpts = { title: "Field Infos", system: true}; // bcz: all possible document options have associated field infos which are stored onn the FieldInfos document **except for title and system which are used as part of the definition of the fieldInfos object
+        const fieldInfoOpts = { title: "Field Infos", isSystem: true}; // bcz: all possible document options have associated field infos which are stored onn the FieldInfos document **except for title and system which are used as part of the definition of the fieldInfos object
         const infos = DocUtils.AssignDocField(doc, field, opts => Doc.assign(new Doc(), opts as any), fieldInfoOpts);
         const entries = Object.entries(new DocumentOptions());
         entries.forEach(pair => {
             if (!Array.from(Object.keys(fieldInfoOpts)).includes(pair[0])) {
                 const options = pair[1] as FInfo;
-                const opts:DocumentOptions = { system: true, title: pair[0], ...OmitKeys(options, ["values"]).omit, fieldIsLayout: pair[0].startsWith("_")};
+                const opts:DocumentOptions = { isSystem: true, title: pair[0], ...OmitKeys(options, ["values"]).omit, fieldIsLayout: pair[0].startsWith("_")};
                 switch (options.fieldType) {
                     case "boolean": opts.fieldValues = new List<boolean>(options.values as any); break;
                     case "number": opts.fieldValues = new List<number>(options.values as any); break;
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index e116ae14b..1cce21034 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -327,7 +327,7 @@ export namespace DictationManager {
                 'new outline',
                 {
                     action: (target: DocumentView) => {
-                        const newBox = Docs.Create.TextDocument('', { _width: 400, _height: 200, title: 'My Outline', _autoHeight: true });
+                        const newBox = Docs.Create.TextDocument('', { _width: 400, _height: 200, title: 'My Outline', _layout_autoHeight: true });
                         const proto = newBox.proto!;
                         const prompt = 'Press alt + r to start dictating here...';
                         const head = 3;
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 695b003a6..6eed4dc86 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -69,12 +69,12 @@ export class DocumentManager {
     public AddView = (view: DocumentView) => {
         //console.log("MOUNT " + view.props.Document.title + "/" + view.props.LayoutTemplateString);
         if (view.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) {
-            const viewAnchorIndex = view.props.LayoutTemplateString.includes('anchor2') ? 'anchor2' : 'anchor1';
+            const viewAnchorIndex = view.props.LayoutTemplateString.includes('link_anchor_2') ? 'link_anchor_2' : 'link_anchor_1';
             const link = view.rootDoc;
             this.LinkAnchorBoxViews?.filter(dv => Doc.AreProtosEqual(dv.rootDoc, link) && !dv.props.LayoutTemplateString?.includes(viewAnchorIndex)).forEach(otherView =>
                 this.LinkedDocumentViews.push({
-                    a: viewAnchorIndex === 'anchor2' ? otherView : view,
-                    b: viewAnchorIndex === 'anchor2' ? view : otherView,
+                    a: viewAnchorIndex === 'link_anchor_2' ? otherView : view,
+                    b: viewAnchorIndex === 'link_anchor_2' ? view : otherView,
                     l: link,
                 })
             );
@@ -173,7 +173,7 @@ export class DocumentManager {
 
         // heuristic to return the "best" documents first:
         //   choose a document in the lightbox first
-        //   choose an exact match over an alias match
+        //   choose an exact match over an embedding match
         lightViews.map(view => view.rootDoc === toFind && toReturn.push(view));
         lightViews.map(view => view.rootDoc !== toFind && Doc.AreProtosEqual(view.rootDoc, toFind) && toReturn.push(view));
         docViews.map(view => view.rootDoc === toFind && toReturn.push(view));
@@ -184,15 +184,15 @@ export class DocumentManager {
 
     static GetContextPath(doc: Opt<Doc>, includeExistingViews?: boolean) {
         if (!doc) return [];
-        const srcContext = DocCast(doc.annotationOn, DocCast(doc.context));
+        const srcContext = DocCast(doc.annotationOn, DocCast(doc.embedContainer));
         var containerDocContext = srcContext ? [srcContext, doc] : [doc];
         while (
             containerDocContext.length &&
-            containerDocContext[0]?.context &&
-            DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking &&
+            containerDocContext[0]?.embedContainer &&
+            DocCast(containerDocContext[0].embedContainer)?.viewType !== CollectionViewType.Docking &&
             (includeExistingViews || !DocumentManager.Instance.getDocumentView(containerDocContext[0]))
         ) {
-            containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext];
+            containerDocContext = [Cast(containerDocContext[0].embedContainer, Doc, null), ...containerDocContext];
         }
         return containerDocContext;
     }
@@ -256,7 +256,7 @@ export class DocumentManager {
         if (options.openLocation === OpenWhere.lightbox) {
             // even if we found the document view, if the target is a lightbox, we try to open it in the lightbox to preserve lightbox semantics (eg, there's only one active doc in the lightbox)
             const target = DocCast(targetDoc.annotationOn, targetDoc);
-            const contextView = this.getDocumentView(DocCast(target.context));
+            const contextView = this.getDocumentView(DocCast(target.embedContainer));
             if (contextView?.docView?._componentView?.addDocTab?.(target, OpenWhere.lightbox)) {
                 await new Promise<void>(waitres => setTimeout(() => waitres()));
             }
@@ -275,7 +275,7 @@ export class DocumentManager {
     focusViewsInPath = async (docView: DocumentView, options: DocFocusOptions, iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt<Doc>; childDocView: Opt<DocumentView> }>) => {
         let contextView: DocumentView | undefined; // view containing context that contains target
         while (true) {
-            docView.rootDoc.layoutKey === 'layout_icon' ? await new Promise<void>(res => docView.iconify(res)) : undefined;
+            docView.rootDoc.layout_fieldKey === 'layout_icon' ? await new Promise<void>(res => docView.iconify(res)) : undefined;
             docView.props.focus(docView.rootDoc, options); // focus the view within its container
             const { childDocView, viewSpec } = await iterator(docView);
             if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.rootDoc, docView, contextView };
@@ -315,7 +315,7 @@ export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCe
         if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) {
             DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc));
         } else {
-            const container = DocCast(containingDoc ?? doc.context);
+            const container = DocCast(containingDoc ?? doc.embedContainer);
             const showDoc = !Doc.IsSystem(container) ? container : doc;
             options.toggleTarget = undefined;
             DocumentManager.Instance.showDocument(showDoc, options, () => DocumentManager.Instance.showDocument(doc, { ...options, openLocation: undefined })).then(() => {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index b6de5604d..070e0f918 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -15,7 +15,7 @@ import { SelectionManager } from './SelectionManager';
 import { SnappingManager } from './SnappingManager';
 import { UndoManager } from './UndoManager';
 
-export type dropActionType = 'alias' | 'copy' | 'move' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call removeDropProperties
+export type dropActionType = 'embed' | 'copy' | 'move' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call removeDropProperties
 
 /**
  * Initialize drag
@@ -131,7 +131,7 @@ export namespace DragManager {
         canEmbed?: boolean;
         userDropAction: dropActionType; // the user requested drop action -- this will be honored as specified by modifier keys
         defaultDropAction?: dropActionType; // an optionally specified default drop action when there is no user drop actionl - this will be honored if there is no user drop action
-        dropAction: dropActionType; // a drop action request by the initiating code.  the actual drop action may be different -- eg, if the request is 'alias', but the document is dropped within the same collection, the drop action will be switched to 'move'
+        dropAction: dropActionType; // a drop action request by the initiating code.  the actual drop action may be different -- eg, if the request is 'embed', but the document is dropped within the same collection, the drop action will be switched to 'move'
         removeDropProperties?: string[];
         moveDocument?: MoveFunction;
         removeDocument?: RemoveFunction;
@@ -193,7 +193,7 @@ export namespace DragManager {
         };
     }
 
-    // drag a document and drop it (or make an alias/copy on drop)
+    // drag a document and drop it (or make an embed/copy on drop)
     export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions, dropEvent?: () => any) {
         const addAudioTag = (dropDoc: any) => {
             dropDoc && !dropDoc.creationDate && (dropDoc.creationDate = new DateField());
@@ -210,8 +210,8 @@ export namespace DragManager {
                         dragData.draggedDocuments.map(async d =>
                             !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart)
                                 ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result)
-                                : docDragData.dropAction === 'alias'
-                                ? Doc.BestAlias(d)
+                                : docDragData.dropAction === 'embed'
+                                ? Doc.BestEmbedding(d)
                                 : docDragData.dropAction === 'proto'
                                 ? Doc.GetProto(d)
                                 : docDragData.dropAction === 'copy'
@@ -487,7 +487,7 @@ export namespace DragManager {
         const moveHandler = (e: PointerEvent) => {
             e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop
             if (dragData instanceof DocumentDragData) {
-                dragData.userDropAction = e.ctrlKey && e.altKey ? 'copy' : e.ctrlKey ? 'alias' : dragData.defaultDropAction;
+                dragData.userDropAction = e.ctrlKey && e.altKey ? 'copy' : e.ctrlKey ? 'embed' : dragData.defaultDropAction;
             }
             if (((e.target as any)?.className === 'lm_tabs' || (e.target as any)?.className === 'lm_header' || e?.shiftKey) && dragData.draggedDocuments.length === 1) {
                 if (!startWindowDragTimer) {
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index 2e1d6ba23..f46ea393a 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -58,8 +58,8 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
         // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant
         if (doc.type === DocumentType.FONTICON || StrCast(Doc.Layout(doc).layout).includes('FontIconBox')) {
             if (data.removeDropProperties || dbox.removeDropProperties) {
-                //dbox = Doc.MakeAlias(doc);  // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon
-                dbox = Doc.MakeAlias(dbox);
+                //dbox = Doc.MakeEmbedding(doc);  // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon
+                dbox = Doc.MakeEmbedding(dbox);
                 const dragProps = Cast(dbox.removeDropProperties, listSpec('string'), []);
                 const remProps = (data.removeDropProperties || []).concat(Array.from(dragProps));
                 remProps.map(prop => (dbox[prop] = undefined));
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index c8b784390..da947aba6 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -155,7 +155,7 @@ export class GroupManager extends React.Component<{}> {
     addGroup(groupDoc: Doc): boolean {
         if (this.GroupManagerDoc) {
             Doc.AddDocToList(this.GroupManagerDoc, 'data', groupDoc);
-            this.GroupManagerDoc['data-lastModified'] = new DateField();
+            this.GroupManagerDoc['data_modificationDate'] = new DateField();
             return true;
         }
         return false;
@@ -176,7 +176,7 @@ export class GroupManager extends React.Component<{}> {
                     const index = DocListCast(this.GroupManagerDoc.data).findIndex(grp => grp === group);
                     index !== -1 && Cast(this.GroupManagerDoc.data, listSpec(Doc), [])?.splice(index, 1);
                 }
-                this.GroupManagerDoc['data-lastModified'] = new DateField();
+                this.GroupManagerDoc['data_modificationDate'] = new DateField();
                 if (group === this.currentGroup) {
                     this.currentGroup = undefined;
                 }
@@ -197,7 +197,7 @@ export class GroupManager extends React.Component<{}> {
             !memberList.includes(email) && memberList.push(email);
             groupDoc.members = JSON.stringify(memberList);
             SharingManager.Instance.shareWithAddedMember(groupDoc, email);
-            this.GroupManagerDoc && (this.GroupManagerDoc['data-lastModified'] = new DateField());
+            this.GroupManagerDoc && (this.GroupManagerDoc['data_modificationDate'] = new DateField());
         }
     }
 
@@ -214,7 +214,7 @@ export class GroupManager extends React.Component<{}> {
                 const user = memberList.splice(index, 1)[0];
                 groupDoc.members = JSON.stringify(memberList);
                 SharingManager.Instance.removeMember(groupDoc, email);
-                this.GroupManagerDoc && (this.GroupManagerDoc['data-lastModified'] = new DateField());
+                this.GroupManagerDoc && (this.GroupManagerDoc['data_modificationDate'] = new DateField());
             }
         }
     }
diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts
index 297520d5d..151f18d6f 100644
--- a/src/client/util/HypothesisUtils.ts
+++ b/src/client/util/HypothesisUtils.ts
@@ -20,7 +20,7 @@ export namespace Hypothesis {
     export const getSourceWebDoc = async (uri: string) => {
         const result = await findWebDoc(uri);
         console.log(result ? 'existing doc found' : 'existing doc NOT found');
-        return result || Docs.Create.WebDocument(uri, { title: uri, _nativeWidth: 850, _height: 512, _width: 400, useCors: true }); // create and return a new Web doc with given uri if no matching docs are found
+        return result || Docs.Create.WebDocument(uri, { title: uri, _nativeWidth: 850, _height: 512, _width: 400, data_useCors: true }); // create and return a new Web doc with given uri if no matching docs are found
     };
 
     /**
diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts
index 9bd92a316..55d37f544 100644
--- a/src/client/util/Import & Export/ImageUtils.ts	
+++ b/src/client/util/Import & Export/ImageUtils.ts	
@@ -1,12 +1,11 @@
-import { Doc } from "../../../fields/Doc";
-import { ImageField } from "../../../fields/URLField";
-import { Cast, StrCast, NumCast } from "../../../fields/Types";
-import { Networking } from "../../Network";
-import { Id } from "../../../fields/FieldSymbols";
-import { Utils } from "../../../Utils";
+import { Doc } from '../../../fields/Doc';
+import { ImageField } from '../../../fields/URLField';
+import { Cast, StrCast, NumCast } from '../../../fields/Types';
+import { Networking } from '../../Network';
+import { Id } from '../../../fields/FieldSymbols';
+import { Utils } from '../../../Utils';
 
 export namespace ImageUtils {
-
     export const ExtractExif = async (document: Doc): Promise<boolean> => {
         const field = Cast(document.data, ImageField);
         if (!field) {
@@ -17,23 +16,22 @@ export namespace ImageUtils {
             contentSize,
             nativeWidth,
             nativeHeight,
-            exifData: { error, data }
-        } = await Networking.PostToServer("/inspectImage", { source });
+            exifData: { error, data },
+        } = await Networking.PostToServer('/inspectImage', { source });
         document.exif = error || Doc.Get.FromJson({ data });
         const proto = Doc.GetProto(document);
-        nativeWidth && (document._height = NumCast(document._width) * nativeHeight / nativeWidth);
-        proto["data-nativeWidth"] = nativeWidth;
-        proto["data-nativeHeight"] = nativeHeight;
-        proto["data-path"] = source;
-        proto.contentSize = contentSize ? contentSize : undefined;
+        nativeWidth && (document._height = (NumCast(document._width) * nativeHeight) / nativeWidth);
+        proto['data_nativeWidth'] = nativeWidth;
+        proto['data_nativeHeight'] = nativeHeight;
+        proto['data-path'] = source;
+        proto.data_contentSize = contentSize ? contentSize : undefined;
         return data !== undefined;
     };
 
     export const ExportHierarchyToFileSystem = async (collection: Doc): Promise<void> => {
-        const a = document.createElement("a");
+        const a = document.createElement('a');
         a.href = Utils.prepend(`/imageHierarchyExport/${collection[Id]}`);
         a.download = `Dash Export [${StrCast(collection.title)}].zip`;
         a.click();
     };
-
-}
\ No newline at end of file
+}
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 9591dbed3..043f0f1f3 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -161,6 +161,7 @@ export namespace InteractionUtils {
                                 <polygon
                                     style={{ stroke: color }}
                                     strokeLinejoin={lineJoin as any}
+                                    strokeDasharray={dashArray}
                                     strokeWidth={(markerStrokeWidth * 2) / 3}
                                     points={`0 ${-markerStrokeWidth * arrowWidthFactor}, ${markerStrokeWidth * arrowNotchFactor} 0, 0 ${markerStrokeWidth * arrowWidthFactor}, ${arrowLengthFactor * markerStrokeWidth} 0`}
                                 />
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts
index ba2edb65c..246f5bb8c 100644
--- a/src/client/util/LinkFollower.ts
+++ b/src/client/util/LinkFollower.ts
@@ -12,8 +12,8 @@ import { SelectionManager } from './SelectionManager';
 import { UndoManager } from './UndoManager';
 /*
  * link doc:
- * - anchor1: doc
- * - anchor2: doc
+ * - link_anchor_1: doc
+ * - link_anchor_2: doc
  *
  * group doc:
  * - type: string representing the group type/name/category
@@ -43,10 +43,10 @@ export class LinkFollower {
 
     public static traverseLink(link: Opt<Doc>, sourceDoc: Doc, finished?: () => void, traverseBacklink?: boolean) {
         const linkDocs = link ? [link] : LinkManager.Links(sourceDoc);
-        const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor1
-        const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor2 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor2
-        const fwdLinkWithoutTargetView = firstDocs.find(d => DocumentManager.Instance.getDocumentViews((d.anchor2 as Doc).type === DocumentType.MARKER ? DocCast((d.anchor2 as Doc).annotationOn) : (d.anchor2 as Doc)).length === 0);
-        const backLinkWithoutTargetView = secondDocs.find(d => DocumentManager.Instance.getDocumentViews((d.anchor1 as Doc).type === DocumentType.MARKER ? DocCast((d.anchor1 as Doc).annotationOn) : (d.anchor1 as Doc)).length === 0);
+        const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.link_anchor_1 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.link_anchor_1 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is link_anchor_1
+        const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.link_anchor_2 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.link_anchor_2 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is link_anchor_2
+        const fwdLinkWithoutTargetView = firstDocs.find(d => DocumentManager.Instance.getDocumentViews((d.link_anchor_2 as Doc).type === DocumentType.MARKER ? DocCast((d.link_anchor_2 as Doc).annotationOn) : (d.link_anchor_2 as Doc)).length === 0);
+        const backLinkWithoutTargetView = secondDocs.find(d => DocumentManager.Instance.getDocumentViews((d.link_anchor_1 as Doc).type === DocumentType.MARKER ? DocCast((d.link_anchor_1 as Doc).annotationOn) : (d.link_anchor_1 as Doc)).length === 0);
         const linkWithoutTargetDoc = traverseBacklink === undefined ? fwdLinkWithoutTargetView || backLinkWithoutTargetView : traverseBacklink ? backLinkWithoutTargetView : fwdLinkWithoutTargetView;
         const linkDocList = linkWithoutTargetDoc && !sourceDoc.followAllLinks ? [linkWithoutTargetDoc] : traverseBacklink === undefined ? firstDocs.concat(secondDocs) : traverseBacklink ? secondDocs : firstDocs;
         const followLinks = sourceDoc.followLinkToggle || sourceDoc.followAllLinks ? linkDocList : linkDocList.slice(0, 1);
@@ -55,13 +55,13 @@ export class LinkFollower {
         if (!followLinks.length) finished?.();
         followLinks.forEach(async linkDoc => {
             const target = (
-                sourceDoc === linkDoc.anchor1
-                    ? linkDoc.anchor2
-                    : sourceDoc === linkDoc.anchor2
-                    ? linkDoc.anchor1
-                    : Doc.AreProtosEqual(sourceDoc, linkDoc.anchor1 as Doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, sourceDoc)
-                    ? linkDoc.anchor2
-                    : linkDoc.anchor1
+                sourceDoc === linkDoc.link_anchor_1
+                    ? linkDoc.link_anchor_2
+                    : sourceDoc === linkDoc.link_anchor_2
+                    ? linkDoc.link_anchor_1
+                    : Doc.AreProtosEqual(sourceDoc, linkDoc.link_anchor_1 as Doc) || Doc.AreProtosEqual((linkDoc.link_anchor_1 as Doc).annotationOn as Doc, sourceDoc)
+                    ? linkDoc.link_anchor_2
+                    : linkDoc.link_anchor_1
             ) as Doc;
             if (target) {
                 const doFollow = (canToggle?: boolean) => {
@@ -92,16 +92,16 @@ export class LinkFollower {
                 };
                 let movedTarget = false;
                 if (sourceDoc.followLinkLocation === OpenWhere.inParent) {
-                    const sourceDocParent = DocCast(sourceDoc.context);
-                    if (target.context instanceof Doc && target.context !== sourceDocParent) {
-                        Doc.RemoveDocFromList(target.context, Doc.LayoutFieldKey(target.context), target);
+                    const sourceDocParent = DocCast(sourceDoc.embedContainer);
+                    if (target.embedContainer instanceof Doc && target.embedContainer !== sourceDocParent) {
+                        Doc.RemoveDocFromList(target.embedContainer, Doc.LayoutFieldKey(target.embedContainer), target);
                         movedTarget = true;
                     }
                     if (!DocListCast(sourceDocParent[Doc.LayoutFieldKey(sourceDocParent)]).includes(target)) {
                         Doc.AddDocToList(sourceDocParent, Doc.LayoutFieldKey(sourceDocParent), target);
                         movedTarget = true;
                     }
-                    target.context = sourceDocParent;
+                    target.embedContainer = sourceDocParent;
                     const moveTo = [NumCast(sourceDoc.x) + NumCast(sourceDoc.followLinkXoffset), NumCast(sourceDoc.y) + NumCast(sourceDoc.followLinkYoffset)];
                     if (sourceDoc.followLinkXoffset !== undefined && moveTo[0] !== target.x) {
                         target.x = moveTo[0];
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 555215417..5e6107e5f 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -7,8 +7,8 @@ import { Cast, DocCast, PromiseValue, StrCast } from '../../fields/Types';
 import { ScriptingGlobals } from './ScriptingGlobals';
 /*
  * link doc:
- * - anchor1: doc
- * - anchor2: doc
+ * - link_anchor_1: doc
+ * - link_anchor_2: doc
  *
  * group doc:
  * - type: string representing the group type/name/category
@@ -33,7 +33,7 @@ export class LinkManager {
         await Promise.all(
             ((await DocListCastAsync(linkDb.data)) ?? []).map(link =>
                 // makes sure link anchors are loaded to avoid incremental updates to computedFns in LinkManager
-                [PromiseValue(link?.anchor1), PromiseValue(link?.anchor2)]
+                [PromiseValue(link?.link_anchor_1), PromiseValue(link?.link_anchor_2)]
             )
         );
         LinkManager.userLinkDBs.push(linkDb);
@@ -42,13 +42,13 @@ export class LinkManager {
     static _links: Doc[] = [];
     constructor() {
         LinkManager._instance = this;
-        this.createLinkrelationshipLists();
+        this.createlink_relationshipLists();
         LinkManager.userLinkDBs = [];
         const addLinkToDoc = (link: Doc) => {
             Promise.all([link]).then(linkdoc => {
                 const link = DocCast(linkdoc[0]);
                 Promise.all([link.proto]).then(linkproto => {
-                    Promise.all([link.anchor1, link.anchor2]).then(linkdata => {
+                    Promise.all([link.link_anchor_1, link.link_anchor_2]).then(linkdata => {
                         const a1 = DocCast(linkdata[0]);
                         const a2 = DocCast(linkdata[1]);
                         a1 &&
@@ -64,8 +64,8 @@ export class LinkManager {
             });
         };
         const remLinkFromDoc = (link: Doc) => {
-            const a1 = link?.anchor1;
-            const a2 = link?.anchor2;
+            const a1 = link?.link_anchor_1;
+            const a2 = link?.link_anchor_2;
             Promise.all([a1, a2]).then(
                 action(() => {
                     if (a1 instanceof Doc && a2 instanceof Doc && ((a1.author !== undefined && a2.author !== undefined) || link.author === Doc.CurrentUserEmail)) {
@@ -130,11 +130,11 @@ export class LinkManager {
         LinkManager.addLinkDB(Doc.LinkDBDoc());
     }
 
-    public createLinkrelationshipLists = () => {
+    public createlink_relationshipLists = () => {
         //create new lists for link relations and their associated colors if the lists don't already exist
-        !Doc.UserDoc().linkRelationshipList && (Doc.UserDoc().linkRelationshipList = new List<string>());
+        !Doc.UserDoc().link_relationshipList && (Doc.UserDoc().link_relationshipList = new List<string>());
         !Doc.UserDoc().linkColorList && (Doc.UserDoc().linkColorList = new List<string>());
-        !Doc.UserDoc().linkRelationshipSizes && (Doc.UserDoc().linkRelationshipSizes = new List<number>());
+        !Doc.UserDoc().link_relationshipSizes && (Doc.UserDoc().link_relationshipSizes = new List<number>());
     };
 
     public addLink(linkDoc: Doc, checkExists = false) {
@@ -162,7 +162,7 @@ export class LinkManager {
             return [];
         }
         const dirLinks = Doc.GetProto(anchor)[DirectLinksSym];
-        const annos = DocListCast(anchor[Doc.LayoutFieldKey(anchor) + '-annotations']);
+        const annos = DocListCast(anchor[Doc.LayoutFieldKey(anchor) + '_annotations']);
         if (!annos) debugger;
         return annos.reduce((list, anno) => [...list, ...LinkManager.Instance.relatedLinker(anno)], Array.from(dirLinks).slice());
     }, true);
@@ -171,9 +171,9 @@ export class LinkManager {
     public getRelatedGroupedLinks(anchor: Doc): Map<string, Array<Doc>> {
         const anchorGroups = new Map<string, Array<Doc>>();
         this.relatedLinker(anchor).forEach(link => {
-            if (link.linkRelationship && link.linkRelationship !== '-ungrouped-') {
-                const relation = StrCast(link.linkRelationship);
-                const anchorRelation = relation.indexOf(':') !== -1 ? relation.split(':')[Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), anchor) ? 0 : 1] : relation;
+            if (link.link_relationship && link.link_relationship !== '-ungrouped-') {
+                const relation = StrCast(link.link_relationship);
+                const anchorRelation = relation.indexOf(':') !== -1 ? relation.split(':')[Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), anchor) ? 0 : 1] : relation;
                 const group = anchorGroups.get(anchorRelation);
                 anchorGroups.set(anchorRelation, group ? [...group, link] : [link]);
             } else {
@@ -189,8 +189,8 @@ export class LinkManager {
     //TODO This should probably return undefined if there isn't an opposite anchor
     //TODO This should also await the return value of the anchor so we don't filter out promises
     public static getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined {
-        const a1 = Cast(linkDoc.anchor1, Doc, null);
-        const a2 = Cast(linkDoc.anchor2, Doc, null);
+        const a1 = Cast(linkDoc.link_anchor_1, Doc, null);
+        const a2 = Cast(linkDoc.link_anchor_2, Doc, null);
         if (Doc.AreProtosEqual(anchor, a1)) return a2;
         if (Doc.AreProtosEqual(anchor, a2)) return a1;
         if (Doc.AreProtosEqual(anchor, a1.annotationOn as Doc)) return a2;
diff --git a/src/client/util/ReplayMovements.ts b/src/client/util/ReplayMovements.ts
index 22cca4a2e..cbc465d6a 100644
--- a/src/client/util/ReplayMovements.ts
+++ b/src/client/util/ReplayMovements.ts
@@ -127,8 +127,8 @@ export class ReplayMovements {
     zoomAndPan = (movement: Movement, document: CollectionFreeFormView) => {
         const { panX, panY, scale } = movement;
         scale !== 0 && document.zoomSmoothlyAboutPt([panX, panY], scale, 0);
-        document.Document._panX = panX;
-        document.Document._panY = panY;
+        document.Document._freeform_panX = panX;
+        document.Document._freeform_panY = panY;
     };
 
     getFirstMovements = (movements: Movement[]): Map<Doc, Movement> => {
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 79759a71d..d154c48a4 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -24,51 +24,57 @@ export namespace SearchUtil {
 
     export interface SearchParams {
         hl?: string;
-        "hl.fl"?: string;
+        'hl.fl'?: string;
         start?: number;
         rows?: number;
         fq?: string;
         sort?: string;
-        allowAliases?: boolean;
-        onlyAliases?: boolean;
-        "facet"?: string;
-        "facet.field"?: string;
+        allowEmbeddings?: boolean;
+        onlyEmbeddings?: boolean;
+        facet?: string;
+        'facet.field'?: string;
     }
     export function Search(query: string, returnDocs: true, options?: SearchParams): Promise<DocSearchResult>;
     export function Search(query: string, returnDocs: false, options?: SearchParams): Promise<IdSearchResult>;
     export async function Search(query: string, returnDocs: boolean, options: SearchParams = {}) {
-        query = query || "*"; //If we just have a filter query, search for * as the query
-        const rpquery = Utils.prepend("/dashsearch");
+        query = query || '*'; //If we just have a filter query, search for * as the query
+        const rpquery = Utils.prepend('/dashsearch');
         let replacedQuery = query.replace(/type_t:([^ )])/g, (substring, arg) => `{!join from=id to=proto_i}*:* AND ${arg}`);
-        if (options.onlyAliases) {
-            const header = query.match(/_[atnb]?:/) ? replacedQuery : "DEFAULT:" + replacedQuery;
+        if (options.onlyEmbeddings) {
+            const header = query.match(/_[atnb]?:/) ? replacedQuery : 'DEFAULT:' + replacedQuery;
             replacedQuery = `{!join from=id to=proto_i}* AND ${header}`;
         }
         //console.log("Q: " + replacedQuery + " fq: " + options.fq);
         const gotten = await rp.get(rpquery, { qs: { ...options, q: replacedQuery } });
-        const result: IdSearchResult = gotten.startsWith("<") ? { ids: [], docs: [], numFound: 0, lines: [] } : JSON.parse(gotten);
+        const result: IdSearchResult = gotten.startsWith('<') ? { ids: [], docs: [], numFound: 0, lines: [] } : JSON.parse(gotten);
         if (!returnDocs) {
             return result;
         }
 
         const { ids, highlighting } = result;
 
-        const txtresult = query !== "*" && JSON.parse(await rp.get(Utils.prepend("/textsearch"), {
-            qs: { ...options, q: query.replace(/^[ \+\?\*\|]*/, "") }, // a leading '+' leads to a server crash since findInFiles doesn't handle regex failures
-        }));
+        const txtresult =
+            query !== '*' &&
+            JSON.parse(
+                await rp.get(Utils.prepend('/textsearch'), {
+                    qs: { ...options, q: query.replace(/^[ \+\?\*\|]*/, '') }, // a leading '+' leads to a server crash since findInFiles doesn't handle regex failures
+                })
+            );
 
         const fileids = txtresult ? txtresult.ids : [];
         const newIds: string[] = [];
         const newLines: string[][] = [];
-        if (fileids) {
-            await Promise.all(fileids.map(async (tr: string, i: number) => {
-                const docQuery = "fileUpload_t:" + tr.substr(0, 7); //If we just have a filter query, search for * as the query
-                const docResult = JSON.parse(await rp.get(Utils.prepend("/dashsearch"), { qs: { ...options, q: docQuery } }));
-                newIds.push(...docResult.ids);
-                newLines.push(...docResult.ids.map((dr: any) => txtresult.lines[i]));
-            }));
-        }
-
+        // bcz: we stopped storing fileUpload id's, so this won't find anything
+        // if (fileids) {
+        //     await Promise.all(
+        //         fileids.map(async (tr: string, i: number) => {
+        //             const docQuery = 'fileUpload_t:' + tr.substr(0, 7); //If we just have a filter query, search for * as the query
+        //             const docResult = JSON.parse(await rp.get(Utils.prepend('/dashsearch'), { qs: { ...options, q: docQuery } }));
+        //             newIds.push(...docResult.ids);
+        //             newLines.push(...docResult.ids.map((dr: any) => txtresult.lines[i]));
+        //         })
+        //     );
+        // }
 
         const theDocs: Doc[] = [];
         const theLines: string[][] = [];
@@ -86,7 +92,7 @@ export namespace SearchUtil {
         const docs = ids.map((id: string) => docMap[id]).map(doc => doc as Doc);
         for (let i = 0; i < ids.length; i++) {
             const testDoc = docs[i];
-            if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && (options.allowAliases || testDoc.proto === undefined || theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1)) {
+            if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && (options.allowEmbeddings || testDoc.proto === undefined || theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1)) {
                 theDocs.push(testDoc);
                 theLines.push([]);
             } else {
@@ -97,48 +103,46 @@ export namespace SearchUtil {
         return { docs: theDocs, numFound: Math.max(0, result.numFound), highlighting, lines: theLines };
     }
 
-    export async function GetAliasesOfDocument(doc: Doc): Promise<Doc[]>;
-    export async function GetAliasesOfDocument(doc: Doc, returnDocs: false): Promise<string[]>;
-    export async function GetAliasesOfDocument(doc: Doc, returnDocs = true): Promise<Doc[] | string[]> {
+    export async function GetEmbeddingsOfDocument(doc: Doc): Promise<Doc[]>;
+    export async function GetEmbeddingsOfDocument(doc: Doc, returnDocs: false): Promise<string[]>;
+    export async function GetEmbeddingsOfDocument(doc: Doc, returnDocs = true): Promise<Doc[] | string[]> {
         const proto = Doc.GetProto(doc);
         const protoId = proto[Id];
         if (returnDocs) {
-            return (await Search("", returnDocs, { fq: `proto_i:"${protoId}"`, allowAliases: true })).docs;
+            return (await Search('', returnDocs, { fq: `proto_i:"${protoId}"`, allowEmbeddings: true })).docs;
         } else {
-            return (await Search("", returnDocs, { fq: `proto_i:"${protoId}"`, allowAliases: true })).ids;
+            return (await Search('', returnDocs, { fq: `proto_i:"${protoId}"`, allowEmbeddings: true })).ids;
         }
         // return Search(`{!join from=id to=proto_i}id:${protoId}`, true);
     }
 
     export async function GetViewsOfDocument(doc: Doc): Promise<Doc[]> {
-        const results = await Search("", true, { fq: `proto_i:"${doc[Id]}"` });
+        const results = await Search('', true, { fq: `proto_i:"${doc[Id]}"` });
         return results.docs;
     }
 
-    export async function GetContextsOfDocument(doc: Doc): Promise<{ contexts: Doc[], aliasContexts: Doc[] }> {
-        const docContexts = (await Search("", true, { fq: `data_l:"${doc[Id]}"` })).docs;
-        const aliases = await GetAliasesOfDocument(doc, false);
-        const aliasContexts = (await Promise.all(aliases.map(doc => Search("", true, { fq: `data_l:"${doc}"` }))));
-        const contexts = { contexts: docContexts, aliasContexts: [] as Doc[] };
-        aliasContexts.forEach(result => contexts.aliasContexts.push(...result.docs));
+    export async function GetContextsOfDocument(doc: Doc): Promise<{ contexts: Doc[]; embeddingContexts: Doc[] }> {
+        const docContexts = (await Search('', true, { fq: `data_l:"${doc[Id]}"` })).docs;
+        const embeddings = await GetEmbeddingsOfDocument(doc, false);
+        const embeddingContexts = await Promise.all(embeddings.map(doc => Search('', true, { fq: `data_l:"${doc}"` })));
+        const contexts = { contexts: docContexts, embeddingContexts: [] as Doc[] };
+        embeddingContexts.forEach(result => contexts.embeddingContexts.push(...result.docs));
         return contexts;
     }
 
-    export async function GetContextIdsOfDocument(doc: Doc): Promise<{ contexts: string[], aliasContexts: string[] }> {
-        const docContexts = (await Search("", false, { fq: `data_l:"${doc[Id]}"` })).ids;
-        const aliases = await GetAliasesOfDocument(doc, false);
-        const aliasContexts = (await Promise.all(aliases.map(doc => Search("", false, { fq: `data_l:"${doc}"` }))));
-        const contexts = { contexts: docContexts, aliasContexts: [] as string[] };
-        aliasContexts.forEach(result => contexts.aliasContexts.push(...result.ids));
+    export async function GetContextIdsOfDocument(doc: Doc): Promise<{ contexts: string[]; embeddingContexts: string[] }> {
+        const docContexts = (await Search('', false, { fq: `data_l:"${doc[Id]}"` })).ids;
+        const embeddings = await GetEmbeddingsOfDocument(doc, false);
+        const embeddingContexts = await Promise.all(embeddings.map(doc => Search('', false, { fq: `data_l:"${doc}"` })));
+        const contexts = { contexts: docContexts, embeddingContexts: [] as string[] };
+        embeddingContexts.forEach(result => contexts.embeddingContexts.push(...result.ids));
         return contexts;
     }
 
     export async function GetAllDocs() {
-        const query = "*";
+        const query = '*';
         const response = await rp.get(Utils.prepend('/dashsearch'), {
-            qs:
-                { start: 0, rows: 10000, q: query },
-
+            qs: { start: 0, rows: 10000, q: query },
         });
         const result: IdSearchResult = JSON.parse(response);
         const { ids, numFound, highlighting } = result;
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index 396d754b6..a3a924b75 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -74,7 +74,7 @@ export class SettingsManager extends React.Component<{}> {
     };
 
     @undoBatch selectUserMode = action((e: React.ChangeEvent) => (Doc.noviceMode = (e.currentTarget as any)?.value === 'Novice'));
-    @undoBatch changeShowTitle = action((e: React.ChangeEvent) => (Doc.UserDoc().showTitle = (e.currentTarget as any).value ? 'title' : undefined));
+    @undoBatch changelayout_showTitle = action((e: React.ChangeEvent) => (Doc.UserDoc().layout_showTitle = (e.currentTarget as any).value ? 'title' : undefined));
     @undoBatch changeFontFamily = action((e: React.ChangeEvent) => (Doc.UserDoc().fontFamily = (e.currentTarget as any).value));
     @undoBatch changeFontSize = action((e: React.ChangeEvent) => (Doc.UserDoc().fontSize = (e.currentTarget as any).value));
     @undoBatch switchActiveBackgroundColor = action((color: ColorState) => (Doc.UserDoc().activeCollectionBackground = String(color.hex)));
@@ -176,7 +176,7 @@ export class SettingsManager extends React.Component<{}> {
         return (
             <div className="prefs-content">
                 <div>
-                    <input type="checkbox" onChange={e => (Doc.UserDoc().showTitle = Doc.UserDoc().showTitle ? undefined : 'creationDate')} checked={Doc.UserDoc().showTitle !== undefined} />
+                    <input type="checkbox" onChange={e => (Doc.UserDoc().layout_showTitle = Doc.UserDoc().layout_showTitle ? undefined : 'creationDate')} checked={Doc.UserDoc().layout_showTitle !== undefined} />
                     <div className="preferences-check">Show doc header</div>
                 </div>
                 <div>
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 4937866f8..0eecb31cf 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -172,7 +172,7 @@ export class SharingManager extends React.Component<{}> {
 
                 this.setDashboardBackground(doc, permission as SharingPermissions);
                 if (permission !== SharingPermissions.None) return Doc.AddDocToList(sharingDoc, storage, doc);
-                else return GetEffectiveAcl(doc, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.aliasOf as Doc) || doc);
+                return GetEffectiveAcl(doc, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.createdFrom as Doc) || doc);
             })
             .some(success => !success);
     };
@@ -215,7 +215,7 @@ export class SharingManager extends React.Component<{}> {
                     return users
                         .map(({ user, sharingDoc }) => {
                             if (permission !== SharingPermissions.None) return Doc.AddDocToList(sharingDoc, storage, doc); // add the doc to the sharingDoc if it hasn't already been added
-                            else return GetEffectiveAcl(doc, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.aliasOf as Doc) || doc); // remove the doc from the list if it already exists
+                            else return GetEffectiveAcl(doc, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.createdFrom as Doc) || doc); // remove the doc from the list if it already exists
                         })
                         .some(success => !success);
                 }
diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts
index 2c0a1da8b..ed9819fc0 100644
--- a/src/client/util/SnappingManager.ts
+++ b/src/client/util/SnappingManager.ts
@@ -40,9 +40,9 @@ export namespace SnappingManager {
     }
 
     export function SetShowSnapLines(show: boolean) {
-        runInAction(() => (Doc.UserDoc().showSnapLines = show));
+        runInAction(() => (Doc.UserDoc().freeform_snapLines = show));
     }
     export function GetShowSnapLines() {
-        return Doc.UserDoc().showSnapLines;
+        return Doc.UserDoc().freeform_snapLines;
     }
 }
diff --git a/src/client/util/TrackMovements.ts b/src/client/util/TrackMovements.ts
index cb8225643..a755c5dc9 100644
--- a/src/client/util/TrackMovements.ts
+++ b/src/client/util/TrackMovements.ts
@@ -68,7 +68,7 @@ export class TrackMovements {
         }
 
         const disposeFunc = reaction(
-            () => ({ x: NumCast(doc.panX, -1), y: NumCast(doc.panY, -1), scale: NumCast(doc.viewScale, 0) }),
+            () => ({ x: NumCast(doc.freeform_panX, -1), y: NumCast(doc.freeform_panY, -1), scale: NumCast(doc.freeform_scale, 0) }),
             res => res.x !== -1 && res.y !== -1 && this.tracking && this.trackMovement(res.x, res.y, doc, res.scale)
         );
         this.recordingFFViews?.set(doc, disposeFunc);
diff --git a/src/client/views/AudioWaveform.tsx b/src/client/views/AudioWaveform.tsx
index 525c0ce5a..14c922526 100644
--- a/src/client/views/AudioWaveform.tsx
+++ b/src/client/views/AudioWaveform.tsx
@@ -1,27 +1,25 @@
-import React = require("react");
-import axios from "axios";
-import { action, computed, IReactionDisposer, reaction } from "mobx";
-import { observer } from "mobx-react";
-import Waveform from "react-audio-waveform";
-import { Doc } from "../../fields/Doc";
-import { List } from "../../fields/List";
-import { listSpec } from "../../fields/Schema";
-import { Cast } from "../../fields/Types";
-import { numberRange } from "../../Utils";
-import "./AudioWaveform.scss";
-import { Colors } from "./global/globalEnums";
-
+import React = require('react');
+import axios from 'axios';
+import { action, computed, IReactionDisposer, reaction } from 'mobx';
+import { observer } from 'mobx-react';
+import Waveform from 'react-audio-waveform';
+import { Doc } from '../../fields/Doc';
+import { List } from '../../fields/List';
+import { listSpec } from '../../fields/Schema';
+import { Cast } from '../../fields/Types';
+import { numberRange } from '../../Utils';
+import './AudioWaveform.scss';
+import { Colors } from './global/globalEnums';
 
 /**
  * AudioWaveform
- * 
+ *
  * Used in CollectionStackedTimeline to render a canvas with a visual of an audio waveform for AudioBox and VideoBox documents.
  * Uses react-audio-waveform package.
  * Bins the audio data into audioBuckets which are passed to package to render the lines.
  * Calculates new buckets each time a new zoom factor or new set of trim bounds is created and stores it in a field on the layout doc with a title indicating the bounds and zoom for that list (see audioBucketField)
  */
 
-
 export interface AudioWaveformProps {
     duration: number; // length of media clip
     rawDuration: number; // length of underlying media data
@@ -32,6 +30,7 @@ export interface AudioWaveformProps {
     zoomFactor: number;
     PanelHeight: number;
     PanelWidth: number;
+    fieldKey: string;
 }
 
 @observer
@@ -40,80 +39,71 @@ export class AudioWaveform extends React.Component<AudioWaveformProps> {
 
     _disposer: IReactionDisposer | undefined;
 
-    @computed get waveHeight() { return Math.max(50, this.props.PanelHeight); }
-
-    @computed get clipStart() { return this.props.clipStart; }
-    @computed get clipEnd() { return this.props.clipEnd; }
-    @computed get zoomFactor() { return this.props.zoomFactor; }
+    @computed get waveHeight() {
+        return Math.max(50, this.props.PanelHeight);
+    }
 
-    @computed get audioBuckets() { return Cast(this.props.layoutDoc[this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor)], listSpec("number"), []); }
-    audioBucketField = (start: number, end: number, zoomFactor: number) => "audioBuckets/" + "/" + start.toFixed(2).replace(".", "_") + "/" + end.toFixed(2).replace(".", "_") + "/" + (zoomFactor * 10);
+    @computed get clipStart() {
+        return this.props.clipStart;
+    }
+    @computed get clipEnd() {
+        return this.props.clipEnd;
+    }
+    @computed get zoomFactor() {
+        return this.props.zoomFactor;
+    }
 
+    @computed get audioBuckets() {
+        return Cast(this.props.layoutDoc[this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor)], listSpec('number'), []);
+    }
+    audioBucketField = (start: number, end: number, zoomFactor: number) => this.props.fieldKey + '_audioBuckets/' + '/' + start.toFixed(2).replace('.', '_') + '/' + end.toFixed(2).replace('.', '_') + '/' + zoomFactor * 10;
 
     componentWillUnmount() {
         this._disposer?.();
     }
 
     componentDidMount() {
-        this._disposer = reaction(() => ({ clipStart: this.clipStart, clipEnd: this.clipEnd, fieldKey: this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor), zoomFactor: this.props.zoomFactor }),
+        this._disposer = reaction(
+            () => ({ clipStart: this.clipStart, clipEnd: this.clipEnd, fieldKey: this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor), zoomFactor: this.props.zoomFactor }),
             ({ clipStart, clipEnd, fieldKey, zoomFactor }) => {
                 if (!this.props.layoutDoc[fieldKey]) {
                     // setting these values here serves as a "lock" to prevent multiple attempts to create the waveform at nerly the same time.
-                    const waveform = Cast(this.props.layoutDoc[this.audioBucketField(0, this.props.rawDuration, 1)], listSpec("number"));
-                    this.props.layoutDoc[fieldKey] = waveform && new List<number>(waveform.slice(clipStart / this.props.rawDuration * waveform.length, clipEnd / this.props.rawDuration * waveform.length));
+                    const waveform = Cast(this.props.layoutDoc[this.audioBucketField(0, this.props.rawDuration, 1)], listSpec('number'));
+                    this.props.layoutDoc[fieldKey] = waveform && new List<number>(waveform.slice((clipStart / this.props.rawDuration) * waveform.length, (clipEnd / this.props.rawDuration) * waveform.length));
                     setTimeout(() => this.createWaveformBuckets(fieldKey, clipStart, clipEnd, zoomFactor));
                 }
-            }, { fireImmediately: true });
+            },
+            { fireImmediately: true }
+        );
     }
 
     // decodes the audio file into peaks for generating the waveform
     createWaveformBuckets = async (fieldKey: string, clipStart: number, clipEnd: number, zoomFactor: number) => {
-        axios({ url: this.props.mediaPath, responseType: "arraybuffer" }).then(
-            (response) => {
-                const context = new window.AudioContext();
-                context.decodeAudioData(
-                    response.data,
-                    action((buffer) => {
-                        const rawDecodedAudioData = buffer.getChannelData(0);
-                        const startInd = clipStart / this.props.rawDuration;
-                        const endInd = clipEnd / this.props.rawDuration;
-                        const decodedAudioData = rawDecodedAudioData.slice(Math.floor(startInd * rawDecodedAudioData.length), Math.floor(endInd * rawDecodedAudioData.length));
-                        const numBuckets = Math.floor(AudioWaveform.NUMBER_OF_BUCKETS * zoomFactor);
+        axios({ url: this.props.mediaPath, responseType: 'arraybuffer' }).then(response => {
+            const context = new window.AudioContext();
+            context.decodeAudioData(
+                response.data,
+                action(buffer => {
+                    const rawDecodedAudioData = buffer.getChannelData(0);
+                    const startInd = clipStart / this.props.rawDuration;
+                    const endInd = clipEnd / this.props.rawDuration;
+                    const decodedAudioData = rawDecodedAudioData.slice(Math.floor(startInd * rawDecodedAudioData.length), Math.floor(endInd * rawDecodedAudioData.length));
+                    const numBuckets = Math.floor(AudioWaveform.NUMBER_OF_BUCKETS * zoomFactor);
 
-                        const bucketDataSize = Math.floor(
-                            decodedAudioData.length / numBuckets
-                        );
-                        const brange = Array.from(Array(bucketDataSize));
-                        const bucketList = numberRange(numBuckets).map(
-                            (i: number) =>
-                                brange.reduce(
-                                    (p, x, j) =>
-                                        Math.abs(
-                                            Math.max(p, decodedAudioData[i * bucketDataSize + j])
-                                        ),
-                                    0
-                                ) / 2
-                        );
-                        this.props.layoutDoc[fieldKey] = new List<number>(bucketList);
-                    })
-                );
-            }
-        );
-    }
+                    const bucketDataSize = Math.floor(decodedAudioData.length / numBuckets);
+                    const brange = Array.from(Array(bucketDataSize));
+                    const bucketList = numberRange(numBuckets).map((i: number) => brange.reduce((p, x, j) => Math.abs(Math.max(p, decodedAudioData[i * bucketDataSize + j])), 0) / 2);
+                    this.props.layoutDoc[fieldKey] = new List<number>(bucketList);
+                })
+            );
+        });
+    };
 
     render() {
         return (
             <div className="audioWaveform">
-                <Waveform
-                    color={Colors.MEDIUM_BLUE_ALT}
-                    height={this.waveHeight}
-                    barWidth={200 / this.audioBuckets.length}
-                    pos={this.props.duration}
-                    duration={this.props.duration}
-                    peaks={this.audioBuckets}
-                    progressColor={Colors.MEDIUM_BLUE_ALT}
-                />
+                <Waveform color={Colors.MEDIUM_BLUE_ALT} height={this.waveHeight} barWidth={200 / this.audioBuckets.length} pos={this.props.duration} duration={this.props.duration} peaks={this.audioBuckets} progressColor={Colors.MEDIUM_BLUE_ALT} />
             </div>
         );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index dee161931..02c5085a2 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -358,15 +358,15 @@ export class DashboardView extends React.Component {
             y: 400,
             _width: 1500,
             _height: 1000,
-            _fitWidth: true,
-            _backgroundGridShow: true,
+            _layout_fitWidth: true,
+            _freeform_backgroundGrid: true,
             backgroundColor: background,
             title: `Untitled Tab 1`,
         };
         const title = name ? name : `Dashboard ${dashboardCount}`;
         const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
         const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row');
-        freeformDoc.context = dashboardDoc;
+        freeformDoc.embedContainer = dashboardDoc;
 
         // switching the tabs from the datadoc to the regular doc
         const dashboardTabs = DocListCast(dashboardDoc[DataSym].data);
@@ -396,7 +396,7 @@ export class DashboardView extends React.Component {
             btnType: ButtonType.ClickButton,
             buttonText: 'New trail',
             icon: 'plus',
-            system: true,
+            isSystem: true,
         };
         const reqdBtnScript = { onClick: `createNewPresentation()` };
         const myTrailsBtn = DocUtils.AssignScripts(Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
@@ -406,13 +406,13 @@ export class DashboardView extends React.Component {
         // but we don't want to create the list of trails here-- but rather in createDashboard
         const reqdOpts: DocumentOptions = {
             title: 'My Trails',
-            _showTitle: 'title',
+            _layout_showTitle: 'title',
             _height: 100,
             treeViewHideTitle: true,
-            _fitWidth: true,
+            _layout_fitWidth: true,
             _gridGap: 5,
             _forceActive: true,
-            childDropAction: 'alias',
+            childDropAction: 'embed',
             treeViewTruncateTitleWidth: 150,
             ignoreClick: true,
             buttonMenu: true,
@@ -423,7 +423,7 @@ export class DashboardView extends React.Component {
             boxShadow: '0 0',
             childDontRegisterViews: true,
             targetDropAction: 'same',
-            system: true,
+            isSystem: true,
             explainer: 'All of the trails that you have created will appear here.',
         };
         const myTrails = DocUtils.AssignScripts(Docs.Create.TreeDocument([], reqdOpts), { treeViewChildDoubleClick: 'openPresentation(documentView.rootDoc)' });
@@ -453,7 +453,7 @@ ScriptingGlobals.add(function resetDashboard(dashboard: Doc) {
     DashboardView.resetDashboard(dashboard);
 }, 'move all dashboard tabs to single stack');
 ScriptingGlobals.add(function addToDashboards(dashboard: Doc) {
-    DashboardView.openDashboard(Doc.MakeAlias(dashboard));
+    DashboardView.openDashboard(Doc.MakeEmbedding(dashboard));
 }, 'adds Dashboard to set of Dashboards');
 ScriptingGlobals.add(function snapshotDashboard() {
     DashboardView.snapshotDashboard();
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index eba55e30c..ffb2d92f6 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -133,7 +133,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
         @computed public get annotationKey() {
-            return this.fieldKey + (this._annotationKeySuffix() ? '-' + this._annotationKeySuffix() : '');
+            return this.fieldKey + (this._annotationKeySuffix() ? '_' + this._annotationKeySuffix() : '');
         }
 
         @action.bound
@@ -152,7 +152,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                 toRemove.forEach(doc => {
                     leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
                     Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
-                    doc.context = undefined;
+                    doc.embedContainer = undefined;
                     if (recent) {
                         Doc.RemoveDocFromList(recent, 'data', doc);
                         doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true);
@@ -193,18 +193,19 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
             }
             const added = docs;
             if (added.length) {
-                if (this.props.Document[AclSym] && Object.keys(this.props.Document[AclSym]).length) {
+                const aclKeys = Object.keys(this.props.Document[AclSym] ?? {});
+                aclKeys.forEach(key =>
                     added.forEach(d => {
-                        for (const key of Object.keys(this.props.Document[AclSym])) {
-                            if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d);
+                        if (d.author === denormalizeEmail(key.substring(4)) && !d.createdFrom) {
+                            distributeAcls(key, SharingPermissions.Admin, d);
                         }
-                    });
-                }
+                    })
+                );
 
                 if (effectiveAcl === AclAugment) {
                     added.map(doc => {
                         if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc)) && Doc.ActiveDashboard) inheritParentAcls(Doc.ActiveDashboard, doc);
-                        doc.context = this.props.Document;
+                        doc.embedContainer = this.props.Document;
                         if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
                         Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
                     });
@@ -215,7 +216,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                             // only make a pushpin if we have acl's to edit the document
                             //DocUtils.LeavePushpin(doc);
                             doc._stayInCollection = undefined;
-                            doc.context = this.props.Document;
+                            doc.embedContainer = this.props.Document;
                             if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.rootDoc;
 
                             Doc.ActiveDashboard && inheritParentAcls(Doc.ActiveDashboard, doc);
@@ -223,7 +224,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                     const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List<Doc>;
                     if (annoDocs instanceof List) annoDocs.push(...added);
                     else targetDataDoc[annotationKey ?? this.annotationKey] = new List<Doc>(added);
-                    targetDataDoc[(annotationKey ?? this.annotationKey) + '-lastModified'] = new DateField(new Date(Date.now()));
+                    targetDataDoc[(annotationKey ?? this.annotationKey) + '_modificationDate'] = new DateField(new Date(Date.now()));
                 }
             }
             return true;
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 30e41b06c..547d844ca 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -178,7 +178,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                             e.preventDefault();
                             let googleDoc = await Cast(dataDoc.googleDoc, Doc);
                             if (!googleDoc) {
-                                const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, useCors: false };
+                                const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, data_useCors: false };
                                 googleDoc = Docs.Create.WebDocument(googleDocUrl, options);
                                 dataDoc.googleDoc = googleDoc;
                             }
@@ -473,17 +473,17 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
             </Tooltip>
         );
     }
-    @observable _aliasDown = false;
+    @observable _embedDown = false;
     onTemplateButton = action((e: React.PointerEvent): void => {
         this._tooltipOpen = false;
-        setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction);
+        setupMoveUpEvents(this, e, this.onEmbedButtonMoved, emptyFunction, emptyFunction);
     });
-    onAliasButtonMoved = () => {
+    onEmbedButtonMoved = () => {
         if (this._dragRef.current) {
             const dragDocView = this.view0!;
             const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]);
             const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
-            dragData.defaultDropAction = 'alias';
+            dragData.defaultDropAction = 'embed';
             dragData.canEmbed = true;
             DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, { hideSource: false });
             return true;
@@ -498,14 +498,14 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
         const view0 = this.view0;
         const views = this.props.views();
         return !view0 ? null : (
-            <Tooltip title={<div className="dash-tooltip">Tap to Customize Layout. Drag an embeddable alias</div>} open={this._tooltipOpen} onClose={action(() => (this._tooltipOpen = false))} placement="bottom">
+            <Tooltip title={<div className="dash-tooltip">Tap to Customize Layout. Drag an embedding</div>} open={this._tooltipOpen} onClose={action(() => (this._tooltipOpen = false))} placement="bottom">
                 <div className="documentButtonBar-linkFlyout" ref={this._dragRef} onPointerEnter={action(() => !this._ref.current?.getBoundingClientRect().width && (this._tooltipOpen = true))}>
                     <Flyout
                         anchorPoint={anchorPoints.LEFT_TOP}
-                        onOpen={action(() => (this._aliasDown = true))}
-                        onClose={action(() => (this._aliasDown = false))}
+                        onOpen={action(() => (this._embedDown = true))}
+                        onClose={action(() => (this._embedDown = false))}
                         content={
-                            !this._aliasDown ? null : (
+                            !this._embedDown ? null : (
                                 <div ref={this._ref}>
                                     {' '}
                                     <TemplateMenu docViews={views.filter(v => v).map(v => v as DocumentView)} />
@@ -564,7 +564,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
             const anchor = rootView.ComponentView?.getAnchor?.(false) ?? rootDoc;
             const trail = DocCast(anchor.presTrail) ?? Doc.MakeCopy(DocCast(Doc.UserDoc().emptyTrail), true);
             if (trail !== anchor.presTrail) {
-                DocUtils.MakeLink(anchor, trail, { linkRelationship: 'link trail' });
+                DocUtils.MakeLink(anchor, trail, { link_relationship: 'link trail' });
                 anchor.presTrail = trail;
             }
             Doc.ActivePresentation = trail;
@@ -589,7 +589,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                         <LinkPopup
                             key="popup"
                             showPopup={this._showLinkPopup}
-                            linkCreated={link => (link.linkDisplay = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
+                            linkCreated={link => (link.layout_linkDisplay = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
                             linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)}
                             linkFrom={() => this.props.views().lastElement()?.rootDoc}
                         />
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 26b64bfdd..39073d763 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -121,7 +121,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                     titleFieldKey &&
                     SelectionManager.Views().forEach(d => {
                         if (titleFieldKey === 'title') {
-                            d.dataDoc['title-custom'] = !this._accumulatedTitle.startsWith('-');
+                            d.dataDoc.title_custom = !this._accumulatedTitle.startsWith('-');
                             if (StrCast(d.rootDoc.title).startsWith('@') && !this._accumulatedTitle.startsWith('@')) {
                                 Doc.RemoveDocFromList(Doc.MyPublishedDocs, undefined, d.rootDoc);
                             }
@@ -138,12 +138,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                             if (curKey !== title) {
                                 if (title) {
                                     if (d.dataDoc[title] === undefined || d.dataDoc[title] instanceof RichTextField || typeof d.dataDoc[title] === 'string') {
-                                        d.rootDoc.layoutKey = `layout_${title}`;
+                                        d.rootDoc.layout_fieldKey = `layout_${title}`;
                                         d.rootDoc[`layout_${title}`] = FormattedTextBox.LayoutString(title);
-                                        d.rootDoc[`${title}-nativeWidth`] = d.rootDoc[`${title}-nativeHeight`] = 0;
+                                        d.rootDoc[`${title}_nativeWidth`] = d.rootDoc[`${title}_nativeHeight`] = 0;
                                     }
                                 } else {
-                                    d.rootDoc.layoutKey = undefined;
+                                    d.rootDoc.layout_fieldKey = undefined;
                                 }
                             }
                         } else {
@@ -272,22 +272,22 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         const selectedDocs = SelectionManager.Views();
         if (selectedDocs.length) {
             if (e.ctrlKey) {
-                // open an alias in a new tab with Ctrl Key
-                CollectionDockingView.AddSplit(Doc.BestAlias(selectedDocs[0].props.Document), OpenWhereMod.right);
+                // open an embedding in a new tab with Ctrl Key
+                CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0].props.Document), OpenWhereMod.right);
             } else if (e.shiftKey) {
                 // open centered in a new workspace with Shift Key
-                const alias = Doc.MakeAlias(selectedDocs[0].props.Document);
-                alias.context = undefined;
-                alias.x = -alias[WidthSym]() / 2;
-                alias.y = -alias[HeightSym]() / 2;
-                CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([alias], { title: 'Tab for ' + alias.title }), OpenWhereMod.right);
+                const embedding = Doc.MakeEmbedding(selectedDocs[0].props.Document);
+                embedding.embedContainer = undefined;
+                embedding.x = -embedding[WidthSym]() / 2;
+                embedding.y = -embedding[HeightSym]() / 2;
+                CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([embedding], { title: 'Tab for ' + embedding.title }), OpenWhereMod.right);
             } else if (e.altKey) {
                 // open same document in new tab
                 CollectionDockingView.ToggleSplit(selectedDocs[0].props.Document, OpenWhereMod.right);
             } else {
                 var openDoc = selectedDocs[0].props.Document;
-                if (openDoc.layoutKey === 'layout_icon') {
-                    openDoc = DocListCast(openDoc.aliases).find(alias => !alias.context) ?? Doc.MakeAlias(openDoc);
+                if (openDoc.layout_fieldKey === 'layout_icon') {
+                    openDoc = DocListCast(openDoc.proto_embeddings).find(embedding => !embedding.embedContainer) ?? Doc.MakeEmbedding(openDoc);
                     Doc.deiconifyView(openDoc);
                 }
                 LightboxView.SetLightboxDoc(
@@ -368,8 +368,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         const newloccentern = seldocview.props.ScreenToLocalTransform().transformPoint(rotCenter[0], rotCenter[1]);
         const newlocenter = [newloccentern[0] - NumCast(seldocview.layoutDoc._width) / 2, newloccentern[1] - NumCast(seldocview.layoutDoc._height) / 2];
         const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.rootDoc._rotation) / 180) * Math.PI);
-        seldocview.rootDoc.rotateCenterX = final.x / NumCast(seldocview.layoutDoc._width);
-        seldocview.rootDoc.rotateCenterY = final.y / NumCast(seldocview.layoutDoc._height);
+        seldocview.rootDoc.rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width);
+        seldocview.rootDoc.rotation_centerY = final.y / NumCast(seldocview.layoutDoc._height);
     };
 
     @action
@@ -386,8 +386,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             action(action(() => (this._isRotating = false))), // upEvent
             action((e, doubleTap) => {
                 if (doubleTap) {
-                    seldocview.rootDoc.rotateCenterX = 0.5;
-                    seldocview.rootDoc.rotateCenterY = 0.5;
+                    seldocview.rootDoc.rotation_centerX = 0.5;
+                    seldocview.rootDoc.rotation_centerY = 0.5;
                 }
             })
         );
@@ -586,7 +586,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                     let dW = docwidth * (dWin / refWidth);
                     let dH = docheight * (dHin / refHeight);
                     const scale = docView.props.ScreenToLocalTransform().Scale;
-                    const modifyNativeDim = (e.ctrlKey || doc.forceReflow) && doc.nativeDimModifiable && ((!dragBottom && !dragTop) || e.ctrlKey || doc.nativeHeightUnfrozen);
+                    const modifyNativeDim = (e.ctrlKey || doc.layout_forceReflow) && doc.nativeDimModifiable && ((!dragBottom && !dragTop) || e.ctrlKey || doc.nativeHeightUnfrozen);
                     if (nwidth && nheight) {
                         if (nwidth / nheight !== docwidth / docheight && !dragBottom && !dragTop) {
                             docheight = (nheight / nwidth) * docwidth;
@@ -602,7 +602,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                     let dX = !dWin ? 0 : scale * refCent[0] * (1 - (1 + dWin / refWidth));
                     let dY = !dHin ? 0 : scale * refCent[1] * (1 - (1 + dHin / refHeight));
                     const preserveNativeDim = doc._nativeHeightUnfrozen === false && doc._nativeDimModifiable === false;
-                    const fixedAspect = nwidth && nheight && (!doc._fitWidth || preserveNativeDim || e.ctrlKey || doc.nativeHeightUnfrozen || doc.nativeDimModifiable);
+                    const fixedAspect = nwidth && nheight && (!doc._layout_fitWidth || preserveNativeDim || e.ctrlKey || doc.nativeHeightUnfrozen || doc.nativeDimModifiable);
                     if (fixedAspect) {
                         if ((Math.abs(dW) > Math.abs(dH) && ((!dragBottom && !dragTop) || !modifyNativeDim)) || dragRight) {
                             if (dragRight && modifyNativeDim) {
@@ -610,7 +610,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                     doc._nativeWidth = (actualdW / (docwidth || 1)) * Doc.NativeWidth(doc);
                                 }
                             } else {
-                                if (!doc._fitWidth || preserveNativeDim) {
+                                if (!doc._layout_fitWidth || preserveNativeDim) {
                                     actualdH = (nheight / nwidth) * actualdW;
                                     doc._height = actualdH;
                                 } else if (!modifyNativeDim || dragBotRight) {
@@ -619,14 +619,14 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                             }
                             doc._width = actualdW;
                         } else {
-                            if ((dragBottom || dragTop) && (modifyNativeDim || (docView.layoutDoc.nativeHeightUnfrozen && docView.layoutDoc._fitWidth))) {
+                            if ((dragBottom || dragTop) && (modifyNativeDim || (docView.layoutDoc.nativeHeightUnfrozen && docView.layoutDoc._layout_fitWidth))) {
                                 // frozen web pages, PDFs, and some RTFS have frozen nativewidth/height.  But they are marked to allow their nativeHeight
                                 // to be explicitly modified with fitWidth and vertical resizing. (ie, with fitWidth they can't grow horizontally to match
                                 // a vertical resize so it makes more sense to change their nativeheight even if the ctrl key isn't used)
                                 doc._nativeHeight = (actualdH / (docheight || 1)) * Doc.NativeHeight(doc);
-                                doc._autoHeight = false;
+                                doc._layout_autoHeight = false;
                             } else {
-                                if (!doc._fitWidth || preserveNativeDim) {
+                                if (!doc._layout_fitWidth || preserveNativeDim) {
                                     actualdW = (nwidth / nheight) * actualdH;
                                     doc._width = actualdW;
                                 } else if (!modifyNativeDim || dragBotRight) {
@@ -642,10 +642,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                         const rotCtr = [docwidth / 2, docheight / 2];
                         const tlRotated = Utils.rotPt(-rotCtr[0], -rotCtr[1], (NumCast(doc._rotation) / 180) * Math.PI);
 
-                        const maxHeight = doc.nativeHeightUnfrozen || !nheight ? 0 : Math.max(nheight, NumCast(doc.scrollHeight, NumCast(doc[docView.LayoutFieldKey + '-scrollHeight']))) * docView.NativeDimScaling();
+                        const maxHeight = doc.nativeHeightUnfrozen || !nheight ? 0 : Math.max(nheight, NumCast(doc.scrollHeight, NumCast(doc[docView.LayoutFieldKey + '_scrollHeight']))) * docView.NativeDimScaling();
                         dH && (doc._height = actualdH > maxHeight && maxHeight ? maxHeight : actualdH);
                         dW && (doc._width = actualdW);
-                        dH && (doc._autoHeight = false);
+                        dH && (doc._layout_autoHeight = false);
 
                         const rotCtr2 = [NumCast(doc._width) / 2, NumCast(doc._height) / 2];
                         const tlRotated2 = Utils.rotPt(-rotCtr2[0], -rotCtr2[1], (NumCast(doc._rotation) / 180) * Math.PI);
@@ -654,7 +654,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                     }
                     doc.x = NumCast(doc.x) + dX;
                     doc.y = NumCast(doc.y) + dY;
-                    doc._lastModified = new DateField();
+                    doc._layout_modificationDate = new DateField();
                 }
                 const val = this._dragHeights.get(docView.layoutDoc);
                 if (val) this._dragHeights.set(docView.layoutDoc, { start: val.start, lowest: Math.min(val.lowest, NumCast(docView.layoutDoc._height)) });
@@ -670,11 +670,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         this._resizeUndo?.end();
         SnappingManager.clearSnapLines();
 
-        // detect autoHeight gesture and apply
+        // detect layout_autoHeight gesture and apply
         SelectionManager.Views()
             .map(docView => ({ doc: docView.layoutDoc, hgts: this._dragHeights.get(docView.layoutDoc) }))
             .filter(pair => pair.hgts && pair.hgts.lowest < pair.hgts.start && pair.hgts.lowest <= 20)
-            .forEach(pair => (pair.doc._autoHeight = true));
+            .forEach(pair => (pair.doc._layout_autoHeight = true));
         //need to change points for resize, or else rotation/control points will fail.
         this._inkDragDocs
             .map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
@@ -713,7 +713,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     }
 
     @computed get hasIcons() {
-        return SelectionManager.Views().some(docView => docView.rootDoc.layoutKey === 'layout_icon');
+        return SelectionManager.Views().some(docView => docView.rootDoc.layout_fieldKey === 'layout_icon');
     }
 
     @observable _showRotCenter = false;
@@ -722,8 +722,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         if (SelectionManager.Views().length) {
             const seldocview = SelectionManager.Views()[0];
             const loccenter = Utils.rotPt(
-                NumCast(seldocview.rootDoc.rotateCenterX) * NumCast(seldocview.layoutDoc._width),
-                NumCast(seldocview.rootDoc.rotateCenterY) * NumCast(seldocview.layoutDoc._height),
+                NumCast(seldocview.rootDoc.rotation_centerX) * NumCast(seldocview.layoutDoc._width),
+                NumCast(seldocview.rootDoc.rotation_centerY) * NumCast(seldocview.layoutDoc._height),
                 (NumCast(seldocview.rootDoc._rotation) / 180) * Math.PI
             );
             return seldocview.props
@@ -746,8 +746,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         }
         // hide the decorations if the parent chooses to hide it or if the document itself hides it
         const hideDecorations = seldocview.props.hideDecorations || seldocview.rootDoc.hideDecorations;
-        const hideResizers = hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.hideResizeHandles || this._isRounding || this._isRotating;
-        const hideTitle = hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.hideDecorationTitle || this._isRounding || this._isRotating;
+        const hideResizers = hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating;
+        const hideTitle = hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.layout_hideDecorationTitle || this._isRounding || this._isRotating;
         const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.hideDocumentButtonBar || this._isRounding || this._isRotating;
         // if multiple documents have been opened at the same time, then don't show open button
         const hideOpenButton =
@@ -765,7 +765,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             seldocview.rootDoc.hideDeleteButton ||
             SelectionManager.Views().some(docView => {
                 const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DataSym]) : AclEdit;
-                return docView.rootDoc.stayInCollection || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
+                return (docView.rootDoc.stayInCollection && !docView.rootDoc.timelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
             });
 
         const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
@@ -871,7 +871,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                 {hideDeleteButton ? null : topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')}
                                 {hideResizers || hideDeleteButton ? null : topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')}
                                 {hideTitle ? null : titleArea}
-                                {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')}
+                                {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as new embedding, shift: in new collection)')}
                             </div>
                             {hideResizers ? null : (
                                 <>
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 84b2e1407..75e0e7c4c 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -46,14 +46,14 @@ export class FilterPanel extends React.Component<filterProps> {
     @computed get _allFacets() {
         // trace();
         const noviceReqFields = ['author', 'tags', 'text', 'type'];
-        const noviceLayoutFields: string[] = []; //["_curPage"];
+        const noviceLayoutFields: string[] = []; //["_layout_curPage"];
         const noviceFields = [...noviceReqFields, ...noviceLayoutFields];
 
         const keys = new Set<string>(noviceFields);
         this.allDocs.forEach(doc => SearchBox.documentKeys(doc).filter(key => keys.add(key)));
         const sortedKeys = Array.from(keys.keys())
             .filter(key => key[0])
-            .filter(key => key.indexOf('lastModified') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('_')) || noviceFields.includes(key) || !Doc.noviceMode)
+            .filter(key => key.indexOf('modificationDate') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('_')) || noviceFields.includes(key) || !Doc.noviceMode)
             .sort();
         noviceFields.forEach(key => sortedKeys.splice(sortedKeys.indexOf(key), 1));
         return [...noviceFields, ...sortedKeys];
@@ -88,7 +88,7 @@ export class FilterPanel extends React.Component<filterProps> {
                     (facetVal === true || facetVal == false) && valueSet.add(Field.toString(!facetVal));
                     const fieldKey = Doc.LayoutFieldKey(t);
                     const annos = !Field.toString(Doc.LayoutField(t) as Field).includes('CollectionView');
-                    DocListCast(t[annos ? fieldKey + '-annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc));
+                    DocListCast(t[annos ? fieldKey + '_annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc));
                 });
                 subDocs = newarray;
             }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index b04769c1e..141e99c66 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -102,7 +102,7 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 icon: 'clipboard',
                 pointerUp: 'GestureOverlay.Instance.closeFloatingDoc()',
                 pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)',
-                clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300, system: true }),
+                clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300, isSystem: true }),
                 backgroundColor: 'orange',
             },
             { title: 'interpret text', icon: 'font', toolType: 'inktotext', pointerUp: "setToolglass('none')", pointerDown: 'setToolglass(self.toolType)', backgroundColor: 'orange' },
@@ -125,7 +125,7 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 onPointerDown: data.pointerDown ? ScriptField.MakeScript(data.pointerDown) : undefined,
                 backgroundColor: data.backgroundColor,
                 dragFactory: data.dragFactory,
-                system: true,
+                isSystem: true,
             })
         );
     }
@@ -138,19 +138,19 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 ignoreClick: true,
                 _lockedPosition: true,
                 title: 'buttons',
-                _autoHeight: true,
+                _layout_autoHeight: true,
                 _yMargin: 5,
                 linearViewIsExpanded: true,
                 backgroundColor: 'white',
-                system: true,
+                isSystem: true,
             });
             thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], {
                 _width: 300,
                 _height: 25,
-                _autoHeight: true,
+                _layout_autoHeight: true,
                 linearViewIsExpanded: true,
                 flexDirection: 'column',
-                system: true,
+                isSystem: true,
             });
             userDoc.thumbDoc = thumbDoc;
         }
@@ -916,7 +916,7 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
 
     @computed get elements() {
         const selView = GestureOverlay.DownDocView;
-        const width = Number(ActiveInkWidth()) * NumCast(selView?.rootDoc._viewScale, 1); // * (selView?.props.ScreenToLocalTransform().Scale || 1);
+        const width = Number(ActiveInkWidth()) * NumCast(selView?.rootDoc._freeform_scale, 1); // * (selView?.props.ScreenToLocalTransform().Scale || 1);
         const rect = this._overlayRef.current?.getBoundingClientRect();
         const B = { left: -20000, right: 20000, top: -20000, bottom: 20000, width: 40000, height: 40000 }; //this.getBounds(this._points, true);
         B.left = B.left - width / 2;
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 0f8b46dbe..b9b92dd2b 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -374,10 +374,10 @@ export class KeyManager {
                             if (count === docids.length) {
                                 const added = await Promise.all(list.filter(d => !docList.includes(d)).map(async d => (clone ? (await Doc.MakeClone(d, true)).clone : d)));
                                 if (added.length) {
-                                    added.map(doc => (doc.context = targetDataDoc));
+                                    added.map(doc => (doc.embedContainer = targetDataDoc));
                                     undoBatch(() => {
                                         targetDataDoc[fieldKey] = new List<Doc>([...docList, ...added]);
-                                        targetDataDoc[fieldKey + '-lastModified'] = new DateField(new Date(Date.now()));
+                                        targetDataDoc[fieldKey + '_modificationDate'] = new DateField(new Date(Date.now()));
                                     })();
                                 }
                             }
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index 156825f41..d28981e17 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -50,21 +50,21 @@ export class InkStrokeProperties {
                 if (!requireCurrPoint || this._currentPoint !== -1) {
                     const doc = inkView.rootDoc;
                     if (doc.type === DocumentType.INK && doc.width && doc.height) {
-                        const ink = Cast(doc.data, InkField)?.inkData;
+                        const ink = Cast(doc.stroke, InkField)?.inkData;
                         if (ink) {
                             const oldXrange = (xs => ({ coord: NumCast(doc.x), min: Math.min(...xs), max: Math.max(...xs) }))(ink.map(p => p.X));
                             const oldYrange = (ys => ({ coord: NumCast(doc.y), min: Math.min(...ys), max: Math.max(...ys) }))(ink.map(p => p.Y));
-                            const ptsXscale = (NumCast(doc._width) - NumCast(doc.strokeWidth)) / (oldXrange.max - oldXrange.min || 1) || 1;
-                            const ptsYscale = (NumCast(doc._height) - NumCast(doc.strokeWidth)) / (oldYrange.max - oldYrange.min || 1) || 1;
-                            const newPoints = func(inkView, ink, ptsXscale, ptsYscale, NumCast(doc.strokeWidth));
+                            const ptsXscale = (NumCast(doc._width) - NumCast(doc.stroke_width)) / (oldXrange.max - oldXrange.min || 1) || 1;
+                            const ptsYscale = (NumCast(doc._height) - NumCast(doc.stroke_width)) / (oldYrange.max - oldYrange.min || 1) || 1;
+                            const newPoints = func(inkView, ink, ptsXscale, ptsYscale, NumCast(doc.stroke_width));
                             if (newPoints) {
                                 const newXrange = (xs => ({ min: Math.min(...xs), max: Math.max(...xs) }))(newPoints.map(p => p.X));
                                 const newYrange = (ys => ({ min: Math.min(...ys), max: Math.max(...ys) }))(newPoints.map(p => p.Y));
-                                doc._width = (newXrange.max - newXrange.min) * ptsXscale + NumCast(doc.strokeWidth);
-                                doc._height = (newYrange.max - newYrange.min) * ptsYscale + NumCast(doc.strokeWidth);
+                                doc._width = (newXrange.max - newXrange.min) * ptsXscale + NumCast(doc.stroke_width);
+                                doc._height = (newYrange.max - newYrange.min) * ptsYscale + NumCast(doc.stroke_width);
                                 doc.x = oldXrange.coord + (newXrange.min - oldXrange.min) * ptsXscale;
                                 doc.y = oldYrange.coord + (newYrange.min - oldYrange.min) * ptsYscale;
-                                Doc.GetProto(doc).data = new InkField(newPoints);
+                                Doc.GetProto(doc).stroke = new InkField(newPoints);
                                 appliedFunc = true;
                             }
                         }
diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx
index 246b887a6..d6a6a64bf 100644
--- a/src/client/views/InkTranscription.tsx
+++ b/src/client/views/InkTranscription.tsx
@@ -172,7 +172,7 @@ export class InkTranscription extends React.Component {
             if (!selected) {
                 return;
             }
-            const ctx = await Cast(selected[0].context, Doc);
+            const ctx = await Cast(selected[0].embedContainer, Doc);
             if (!ctx) {
                 return;
             }
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 2fd6cc4d6..14c5dc58d 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -6,7 +6,7 @@
               point 1, tangent pt 1, tangent pt 2, point 2, point 3, tangent pt 3, ...  (Note that segment endpoints are duplicated ie Point2 = Point 3)
         brokenIndices - an array of indexes into the data field where the incoming and outgoing tangents are not constrained to be equal
         text - a text field that will be centered within a closed ink stroke
-        isInkMask - a flag that makes the ink stroke render as a mask over its collection where the stroke itself is mixBlendMode multiplied by 
+        stroke_isInkMask - a flag that makes the ink stroke render as a mask over its collection where the stroke itself is mixBlendMode multiplied by 
                the underlying collection content, and everything outside the stroke is covered by a semi-opaque dark gray mask.
 
     The coordinates of the ink data need to be mapped to the screen since ink points are not changed when the DocumentView is translated or scaled.
@@ -134,7 +134,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
      *  dimmed by a semi-opaque overlay mask.
      */
     public static toggleMask = action((inkDoc: Doc) => {
-        inkDoc.isInkMask = !inkDoc.isInkMask;
+        inkDoc.stroke_isInkMask = !inkDoc.stroke_isInkMask;
     });
     @observable controlUndo: UndoManager.Batch | undefined;
     /**
@@ -241,7 +241,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
      */
     inkScaledData = () => {
         const inkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
-        const inkStrokeWidth = NumCast(this.rootDoc.strokeWidth, 1);
+        const inkStrokeWidth = NumCast(this.rootDoc.stroke_width, 1);
         const inkTop = Math.min(...inkData.map(p => p.Y)) - inkStrokeWidth / 2;
         const inkBottom = Math.max(...inkData.map(p => p.Y)) + inkStrokeWidth / 2;
         const inkLeft = Math.min(...inkData.map(p => p.X)) - inkStrokeWidth / 2;
@@ -310,8 +310,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
             .map(p => ({ X: p[0], Y: p[1] }));
         const screenHdlPts = screenPts;
 
-        const startMarker = StrCast(this.layoutDoc.strokeStartMarker);
-        const endMarker = StrCast(this.layoutDoc.strokeEndMarker);
+        const startMarker = StrCast(this.layoutDoc.stroke_startMarker);
+        const endMarker = StrCast(this.layoutDoc.stroke_endMarker);
         const markerScale = NumCast(this.layoutDoc.strokeMarkerScale);
         return SnappingManager.GetIsDragging() ? null : !InkStrokeProperties.Instance._controlButton ? (
             !this.props.isSelected() || InkingStroke.IsClosed(inkData) ? null : (
@@ -330,12 +330,12 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
                     screenSpaceCenterlineStrokeWidth,
                     StrCast(inkDoc.strokeLineJoin),
                     StrCast(this.layoutDoc.strokeLineCap),
-                    StrCast(inkDoc.strokeBezier),
+                    StrCast(inkDoc.stroke_bezier),
                     'none',
                     startMarker,
                     endMarker,
                     markerScale * Math.min(screenSpaceCenterlineStrokeWidth, screenInkWidth[0] / screenSpaceCenterlineStrokeWidth),
-                    StrCast(inkDoc.strokeDash),
+                    StrCast(inkDoc.stroke_dash),
                     1,
                     1,
                     '',
@@ -355,11 +355,11 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
         TraceMobx();
         const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData();
 
-        const startMarker = StrCast(this.layoutDoc.strokeStartMarker);
-        const endMarker = StrCast(this.layoutDoc.strokeEndMarker);
+        const startMarker = StrCast(this.layoutDoc.stroke_startMarker);
+        const endMarker = StrCast(this.layoutDoc.stroke_endMarker);
         const markerScale = NumCast(this.layoutDoc.strokeMarkerScale, 1);
         const closed = InkingStroke.IsClosed(inkData);
-        const isInkMask = BoolCast(this.layoutDoc.isInkMask);
+        const isInkMask = BoolCast(this.layoutDoc.stroke_isInkMask);
         const fillColor = isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.FillColor) ?? 'transparent';
         const strokeColor = !closed && fillColor && fillColor !== 'transparent' ? fillColor : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color) ?? StrCast(this.layoutDoc.color);
 
@@ -381,12 +381,12 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
             inkStrokeWidth,
             StrCast(this.layoutDoc.strokeLineJoin),
             StrCast(this.layoutDoc.strokeLineCap),
-            StrCast(this.layoutDoc.strokeBezier),
+            StrCast(this.layoutDoc.stroke_bezier),
             !closed ? 'none' : fillColor === 'transparent' ? 'none' : fillColor,
             startMarker,
             endMarker,
             markerScale,
-            StrCast(this.layoutDoc.strokeDash),
+            StrCast(this.layoutDoc.stroke_dash),
             inkScaleX,
             inkScaleY,
             '',
@@ -408,7 +408,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
                 inkStrokeWidth + (fillColor ? (closed ? 2 : (highlightIndex ?? 0) + 2) : 2),
                 StrCast(this.layoutDoc.strokeLineJoin),
                 StrCast(this.layoutDoc.strokeLineCap),
-                StrCast(this.layoutDoc.strokeBezier),
+                StrCast(this.layoutDoc.stroke_bezier),
                 !closed ? 'none' : !isInkMask && (fillColor === 'transparent' || suppressFill) ? 'none' : fillColor,
                 '',
                 '',
@@ -444,7 +444,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
                 <svg
                     className="inkStroke"
                     style={{
-                        transform: this.props.Document.isInkMask ? `rotate(-${NumCast(this.props.CollectionFreeFormDocumentView?.().Rot)}deg) translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined,
+                        transform: isInkMask ? `rotate(-${NumCast(this.props.CollectionFreeFormDocumentView?.().Rot)}deg) translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined,
                         // mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? 'multiply' : 'unset',
                         cursor: this.props.isSelected() ? 'default' : undefined,
                     }}
@@ -469,7 +469,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
                             setContentView={this.setSubContentView} // this makes the inkingStroke the "dominant" component - ie, it will show the inking UI when selected (not text)
                             yPadding={10}
                             xPadding={10}
-                            fieldKey={'text'}
+                            fieldKey="text"
                             fontSize={fsize}
                             dontRegisterView={true}
                             noSidebar={true}
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index c18a89481..1b309a6be 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -31,7 +31,7 @@ type LightboxSavedState = {
     panY: Opt<number>;
     scale: Opt<number>;
     scrollTop: Opt<number>;
-    layoutKey: Opt<string>;
+    layout_fieldKey: Opt<string>;
 };
 @observer
 export class LightboxView extends React.Component<LightboxViewProps> {
@@ -51,11 +51,11 @@ export class LightboxView extends React.Component<LightboxViewProps> {
     static path: { doc: Opt<Doc>; target: Opt<Doc>; history: Opt<{ doc: Doc; target?: Doc }[]>; future: Opt<Doc[]>; saved: Opt<LightboxSavedState> }[] = [];
     @action public static SetLightboxDoc(doc: Opt<Doc>, target?: Doc, future?: Doc[], layoutTemplate?: Doc | string) {
         if (this.LightboxDoc && this.LightboxDoc !== doc && this._savedState) {
-            if (this._savedState.panX !== undefined) this.LightboxDoc._panX = this._savedState.panX;
-            if (this._savedState.panY !== undefined) this.LightboxDoc._panY = this._savedState.panY;
-            if (this._savedState.scrollTop !== undefined) this.LightboxDoc._scrollTop = this._savedState.scrollTop;
-            if (this._savedState.scale !== undefined) this.LightboxDoc._viewScale = this._savedState.scale;
-            this.LightboxDoc.layoutKey = this._savedState.layoutKey;
+            if (this._savedState.panX !== undefined) this.LightboxDoc._freeform_panX = this._savedState.panX;
+            if (this._savedState.panY !== undefined) this.LightboxDoc._freeform_panY = this._savedState.panY;
+            if (this._savedState.scrollTop !== undefined) this.LightboxDoc._layout_scrollTop = this._savedState.scrollTop;
+            if (this._savedState.scale !== undefined) this.LightboxDoc._freeform_scale = this._savedState.scale;
+            this.LightboxDoc.layout_fieldKey = this._savedState.layout_fieldKey;
         }
         if (!doc) {
             this._docFilters && (this._docFilters.length = 0);
@@ -64,17 +64,17 @@ export class LightboxView extends React.Component<LightboxViewProps> {
             MainView.Instance._exploreMode = false;
         } else {
             const l = DocUtils.MakeLinkToActiveAudio(() => doc).lastElement();
-            l && (Cast(l.anchor2, Doc, null).backgroundColor = 'lightgreen');
+            l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen');
             CollectionStackedTimeline.CurrentlyPlaying?.forEach(dv => dv.ComponentView?.Pause?.());
             //TabDocView.PinDoc(doc, { hidePresBox: true });
             this._history ? this._history.push({ doc, target }) : (this._history = [{ doc, target }]);
             if (doc !== LightboxView.LightboxDoc) {
                 this._savedState = {
-                    layoutKey: StrCast(doc.layoutKey),
-                    panX: Cast(doc.panX, 'number', null),
-                    panY: Cast(doc.panY, 'number', null),
-                    scale: Cast(doc.viewScale, 'number', null),
-                    scrollTop: Cast(doc.scrollTop, 'number', null),
+                    layout_fieldKey: StrCast(doc.layout_fieldKey),
+                    panX: Cast(doc.freeform_panX, 'number', null),
+                    panY: Cast(doc.freeform_panY, 'number', null),
+                    scale: Cast(doc.freeform_scale, 'number', null),
+                    scrollTop: Cast(doc.layout_scrollTop, 'number', null),
                 };
             }
         }
@@ -91,7 +91,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
         this._doc = doc;
         this._layoutTemplate = layoutTemplate instanceof Doc ? layoutTemplate : undefined;
         if (doc && (typeof layoutTemplate === 'string' ? layoutTemplate : undefined)) {
-            doc.layoutKey = layoutTemplate;
+            doc.layout_fieldKey = layoutTemplate;
         }
         this._docTarget = target || doc;
 
@@ -142,7 +142,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
         return LightboxView.SetLightboxDoc(
             doc,
             undefined,
-            [...DocListCast(doc[Doc.LayoutFieldKey(doc)]), ...DocListCast(doc[Doc.LayoutFieldKey(doc) + '-annotations']).filter(anno => anno.annotationOn !== doc), ...(LightboxView._future ?? [])].sort(
+            [...DocListCast(doc[Doc.LayoutFieldKey(doc)]), ...DocListCast(doc[Doc.LayoutFieldKey(doc) + '_annotations']).filter(anno => anno.annotationOn !== doc), ...(LightboxView._future ?? [])].sort(
                 (a: Doc, b: Doc) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)
             ),
             layoutTemplate
@@ -156,17 +156,17 @@ export class LightboxView extends React.Component<LightboxViewProps> {
         const targetDocView = target && DocumentManager.Instance.getLightboxDocumentView(target);
         if (targetDocView && target) {
             const l = DocUtils.MakeLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.(true) || target).lastElement();
-            l && (Cast(l.anchor2, Doc, null).backgroundColor = 'lightgreen');
+            l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen');
             DocumentManager.Instance.showDocument(target, { willZoomCentered: true, zoomScale: 0.9 });
             if (LightboxView._history?.lastElement().target !== target) LightboxView._history?.push({ doc, target });
         } else {
             if (!target && LightboxView.path.length) {
                 const saved = LightboxView._savedState;
                 if (LightboxView.LightboxDoc && saved) {
-                    LightboxView.LightboxDoc._panX = saved.panX;
-                    LightboxView.LightboxDoc._panY = saved.panY;
-                    LightboxView.LightboxDoc._viewScale = saved.scale;
-                    LightboxView.LightboxDoc._scrollTop = saved.scrollTop;
+                    LightboxView.LightboxDoc._freeform_panX = saved.panX;
+                    LightboxView.LightboxDoc._freeform_panY = saved.panY;
+                    LightboxView.LightboxDoc._freeform_scale = saved.scale;
+                    LightboxView.LightboxDoc._layout_scrollTop = saved.scrollTop;
                 }
                 const pop = LightboxView.path.pop();
                 if (pop) {
@@ -210,7 +210,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
         const coll = LightboxView._docTarget;
         if (coll) {
             const fieldKey = Doc.LayoutFieldKey(coll);
-            const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '-annotations'])];
+            const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '_annotations'])];
             const links = LinkManager.Links(coll)
                 .map(link => LinkManager.getOppositeAnchor(link, coll))
                 .filter(doc => doc)
@@ -305,9 +305,9 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                     title="toggle fit width"
                     onClick={e => {
                         e.stopPropagation();
-                        LightboxView.LightboxDoc!._fitWidth = !LightboxView.LightboxDoc!._fitWidth;
+                        LightboxView.LightboxDoc!._layout_fitWidth = !LightboxView.LightboxDoc!._layout_fitWidth;
                     }}>
-                    <FontAwesomeIcon icon={LightboxView.LightboxDoc?._fitWidth ? 'arrows-alt-h' : 'arrows-alt-v'} size="2x" />
+                    <FontAwesomeIcon icon={LightboxView.LightboxDoc?._layout_fitWidth ? 'arrows-alt-h' : 'arrows-alt-v'} size="2x" />
                 </div>
                 <div
                     className="lightboxView-tabBtn"
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 5af9a9f9a..ce29b63cd 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -157,26 +157,26 @@ export class MainView extends React.Component {
                 'dataTransition',
                 'viewTransition',
                 'treeViewOpen',
-                'showSidebar',
+                'layout_showSidebar',
                 'itemIndex', // for changing slides in presentations
-                'sidebarWidthPercent',
-                'currentTimecode',
-                'timelineHeightPercent',
+                'layout_sidebarWidthPercent',
+                'layout_currentTimecode',
+                'layout_timelineHeightPercent',
                 'presStatus',
-                'panX',
-                'panY',
+                'freeform_panX',
+                'freeform_panY',
                 'overlayX',
                 'overlayY',
-                'fitWidth',
+                'layout_fitWidth',
                 'nativeWidth',
                 'nativeHeight',
-                'text-scrollHeight',
-                'text-height',
-                'hideMinimap',
-                'viewScale',
-                'scrollTop',
+                'text_scrollHeight',
+                'text_height',
+                'layout_hideMinimap',
+                'freeform_scale',
+                'layout_scrollTop',
                 'hidden',
-                'curPage',
+                'layout_curPage',
                 'viewType',
                 'chromeHidden',
                 'currentFrame',
@@ -880,8 +880,8 @@ export class MainView extends React.Component {
                 <CollectionLinearView
                     Document={Doc.MyDockedBtns}
                     DataDoc={undefined}
-                    fieldKey={'data'}
-                    dropAction={'alias'}
+                    fieldKey="data"
+                    dropAction="embed"
                     setHeight={returnFalse}
                     styleProvider={DefaultStyleProvider}
                     rootSelected={returnTrue}
@@ -911,7 +911,7 @@ export class MainView extends React.Component {
         );
     }
     @computed get snapLines() {
-        return !SelectionManager.Views().some(dv => dv.rootDoc.showSnapLines) ? null : (
+        return !SelectionManager.Views().some(dv => dv.rootDoc.freeform_snapLines) ? null : (
             <div className="mainView-snapLines">
                 <svg style={{ width: '100%', height: '100%' }}>
                     {SnappingManager.horizSnapLines().map(l => (
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 556d9b6a0..eb0fd0c7a 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -123,9 +123,9 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
                   DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, {
                       dragComplete: e => {
                           if (!e.aborted && e.linkDocument) {
-                              Doc.GetProto(e.linkDocument).linkRelationship = 'cropped image';
+                              Doc.GetProto(e.linkDocument).link_relationship = 'cropped image';
                               Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.docView.rootDoc.title;
-                              Doc.GetProto(e.linkDocument).linkDisplay = false;
+                              Doc.GetProto(e.linkDocument).layout_linkDisplay = false;
                           }
                       },
                   });
@@ -153,10 +153,10 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
                 annotationOn: this.props.rootDoc,
                 title: 'Annotation on ' + this.props.rootDoc.title,
             });
-            marqueeAnno.x = NumCast(this.props.docView.props.Document.panXMin) + (parseInt(anno.style.left || '0') - containerOffset[0]) / scale / NumCast(this.props.docView.props.Document._viewScale, 1);
-            marqueeAnno.y = NumCast(this.props.docView.props.Document.panYMin) + (parseInt(anno.style.top || '0') - containerOffset[1]) / scale / NumCast(this.props.docView.props.Document._viewScale, 1) + NumCast(this.props.scrollTop);
-            marqueeAnno._height = parseInt(anno.style.height || '0') / scale / NumCast(this.props.docView.props.Document._viewScale, 1);
-            marqueeAnno._width = parseInt(anno.style.width || '0') / scale / NumCast(this.props.docView.props.Document._viewScale, 1);
+            marqueeAnno.x = NumCast(this.props.docView.props.Document.freeform_panXMin) + (parseInt(anno.style.left || '0') - containerOffset[0]) / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1);
+            marqueeAnno.y = NumCast(this.props.docView.props.Document.freeform_panYMin) + (parseInt(anno.style.top || '0') - containerOffset[1]) / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1) + NumCast(this.props.scrollTop);
+            marqueeAnno._height = parseInt(anno.style.height || '0') / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1);
+            marqueeAnno._width = parseInt(anno.style.width || '0') / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1);
             anno.remove();
             savedAnnoMap.clear();
             return marqueeAnno;
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index c7a603897..f7fb443c0 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -57,7 +57,7 @@ export class PreviewCursor extends React.Component<{}> {
                                 title: url,
                                 _width: 500,
                                 _height: 300,
-                                useCors: true,
+                                data_useCors: true,
                                 x: newPoint[0],
                                 y: newPoint[1],
                             })
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index cf808f801..86230ca78 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -74,7 +74,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     @computed get maskButton() {
         return this.propertyToggleBtn(
             'Mask',
-            'isInkMask',
+            'stroke_isInkMask',
             on => (on ? 'Make plain ink' : 'Make highlight mask'),
             on => 'paint-brush',
             (dv, doc) => InkingStroke.toggleMask(dv?.layoutDoc || doc)
@@ -91,7 +91,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     @computed get clustersButton() {
         return this.propertyToggleBtn(
             'Clusters',
-            '_useClusters',
+            '_freeform_useClusters',
             on => `${on ? 'Hide' : 'Show'} clusters`,
             on => 'braille'
         );
@@ -115,7 +115,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     @computed get fitContentButton() {
         return this.propertyToggleBtn(
             'View All',
-            '_fitContentsToBox',
+            '_freeform_fitContentsToBox',
             on => `${on ? "Don't" : 'Do'} fit content to container visible area`,
             on => 'object-group'
         );
@@ -136,20 +136,20 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                     // containerDoc.noShadow =
                     // containerDoc.disableDocBrushing =
                     // containerDoc._forceActive =
-                    //containerDoc._fitContentsToBox =
+                    //containerDoc._freeform_fitContentsToBox =
                     containerDoc._isLightbox = !containerDoc._isLightbox;
                     //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined;
                     const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]);
                     //dv.rootDoc.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' });
-                    containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.linkDisplay = false)));
+                    containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.layout_linkDisplay = false)));
                 });
             }
         );
     }
-    @computed get fitWidthButton() {
+    @computed get layout_fitWidthButton() {
         return this.propertyToggleBtn(
             'Fit\xA0Width',
-            '_fitWidth',
+            '_layout_fitWidth',
             on => `${on ? "Don't" : 'Do'} fit content to width of container`,
             on => 'arrows-alt-h'
         );
@@ -157,10 +157,10 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     @computed get captionButton() {
         return this.propertyToggleBtn(
             'Caption',
-            '_showCaption',
+            '_layout_showCaption',
             on => `${on ? 'Hide' : 'Show'} caption footer`,
             on => 'closed-captioning',
-            (dv, doc) => ((dv?.rootDoc || doc)._showCaption = (dv?.rootDoc || doc)._showCaption === undefined ? 'caption' : undefined)
+            (dv, doc) => ((dv?.rootDoc || doc)._layout_showCaption = (dv?.rootDoc || doc)._layout_showCaption === undefined ? 'caption' : undefined)
         );
     }
     @computed get chromeButton() {
@@ -175,20 +175,20 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     @computed get titleButton() {
         return this.propertyToggleBtn(
             'Title',
-            '_showTitle',
+            '_layout_showTitle',
             on => 'Switch between title styles',
             on => 'text-width',
             (dv, doc) => {
                 const tdoc = dv?.rootDoc || doc;
-                const newtitle = !tdoc._showTitle ? 'title' : tdoc._showTitle === 'title' ? 'title:hover' : '';
-                tdoc._showTitle = newtitle;
+                const newtitle = !tdoc._layout_showTitle ? 'title' : tdoc._layout_showTitle === 'title' ? 'title:hover' : '';
+                tdoc._layout_showTitle = newtitle;
             }
         );
     }
-    @computed get autoHeightButton() {
+    @computed get layout_autoHeightButton() {
         return this.propertyToggleBtn(
             'Auto\xA0Size',
-            '_autoHeight',
+            '_layout_autoHeight',
             on => `Automatical vertical sizing to show all content`,
             on => 'arrows-alt-v'
         );
@@ -196,7 +196,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     @computed get gridButton() {
         return this.propertyToggleBtn(
             'Grid',
-            '_backgroundGridShow',
+            '_freeform_backgroundGrid',
             on => `Display background grid in collection`,
             on => 'border-all'
         );
@@ -236,7 +236,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     @computed get snapButton() {
         return this.propertyToggleBtn(
             'Snap\xA0Lines',
-            'showSnapLines',
+            'freeform_snapLines',
             on => `Display snapping lines when objects are dragged`,
             on => 'th',
             undefined,
@@ -412,12 +412,12 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 {toggle(this.captionButton)}
                 {toggle(this.lockButton)}
                 {toggle(this.onClickButton)}
-                {toggle(this.fitWidthButton)}
+                {toggle(this.layout_fitWidthButton)}
                 {toggle(this.freezeThumb)}
                 {toggle(this.forceActiveButton, { display: !isFreeForm && !isMap ? 'none' : '' })}
                 {toggle(this.fitContentButton, { display: !isFreeForm && !isMap ? 'none' : '' })}
                 {toggle(this.isLightboxButton, { display: !isFreeForm && !isMap ? 'none' : '' })}
-                {toggle(this.autoHeightButton, { display: !isText && !isStacking && !isTree ? 'none' : '' })}
+                {toggle(this.layout_autoHeightButton, { display: !isText && !isStacking && !isTree ? 'none' : '' })}
                 {toggle(this.maskButton, { display: !isInk ? 'none' : '' })}
                 {toggle(this.hideImageButton, { display: !isImage ? 'none' : '' })}
                 {toggle(this.chromeButton, { display: !isCollection || isNovice ? 'none' : '' })}
diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx
index 935d551c6..46e6fd188 100644
--- a/src/client/views/PropertiesDocBacklinksSelector.tsx
+++ b/src/client/views/PropertiesDocBacklinksSelector.tsx
@@ -25,7 +25,7 @@ export class PropertiesDocBacklinksSelector extends React.Component<PropertiesDo
 
         if (otherdoc) {
             otherdoc.hidden = false;
-            this.props.addDocTab(Doc.IsPrototype(otherdoc) ? Doc.MakeDelegate(otherdoc) : otherdoc, OpenWhere.toggleRight);
+            this.props.addDocTab(Doc.IsDocDataProto(otherdoc) ? Doc.MakeDelegate(otherdoc) : otherdoc, OpenWhere.toggleRight);
         }
     };
 
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index c14d7ef73..12a09196e 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -23,14 +23,14 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
         if (!this.props.DocView) return [];
         const target = this.props.DocView.props.Document;
         const targetContext = this.props.DocView.props.docViewPath().lastElement()?.rootDoc;
-        const aliases = DocListCast(target.aliases);
-        const containerProtos = aliases.filter(alias => alias.context && alias.context instanceof Doc).reduce((set, alias) => set.add(Cast(alias.context, Doc, null)), new Set<Doc>());
-        const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.aliases));
+        const embeddings = DocListCast(target.proto_embeddings);
+        const containerProtos = embeddings.filter(embedding => embedding.embedContainer && embedding.embedContainer instanceof Doc).reduce((set, embedding) => set.add(Cast(embedding.embedContainer, Doc, null)), new Set<Doc>());
+        const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.proto_embeddings));
         const containers = containerSets.reduce((p, set) => {
             set.map(s => p.add(s));
             return p;
         }, new Set<Doc>());
-        const doclayoutSets = Array.from(containers.keys()).map(dp => DocListCast(dp.aliases));
+        const doclayoutSets = Array.from(containers.keys()).map(dp => DocListCast(dp.proto_embeddings));
         const doclayouts = Array.from(
             doclayoutSets
                 .reduce((p, set) => {
@@ -48,7 +48,7 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
 
     getOnClick = (col: Doc, target: Doc) => {
         if (!this.props.DocView) return;
-        col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col;
+        col = Doc.IsDocDataProto(col) ? Doc.MakeDelegate(col) : col;
         DocFocusOrOpen(Doc.GetProto(this.props.DocView.props.Document), undefined, col);
     };
 
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 0b14c7b10..19c138a21 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -123,7 +123,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     docWidth = () => {
         if (this.selectedDoc) {
             const layoutDoc = this.selectedDoc;
-            const aspect = Doc.NativeAspect(layoutDoc, undefined, !layoutDoc._fitWidth);
+            const aspect = Doc.NativeAspect(layoutDoc, undefined, !layoutDoc._layout_fitWidth);
             if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.width - 20));
             return Doc.NativeWidth(layoutDoc) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20;
         } else {
@@ -141,7 +141,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     this.MAX_EMBED_HEIGHT,
                     Doc.NativeAspect(layoutDoc, undefined, true)
                         ? this.docWidth() / Doc.NativeAspect(layoutDoc, undefined, true)
-                        : layoutDoc._fitWidth
+                        : layoutDoc._layout_fitWidth
                         ? !Doc.NativeHeight(this.dataDoc)
                             ? NumCast(this.props.height)
                             : Math.min((this.docWidth() * Doc.NativeHeight(layoutDoc)) / Doc.NativeWidth(layoutDoc) || NumCast(this.props.height))
@@ -199,8 +199,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get noviceFields() {
-        const noviceReqFields = ['author', 'creationDate', 'tags', '_curPage'];
-        return this.editableFields(key => key.indexOf('lastModified') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('acl')), noviceReqFields);
+        const noviceReqFields = ['author', 'creationDate', 'tags', '_layout_curPage'];
+        return this.editableFields(key => key.indexOf('modificationDate') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('acl')), noviceReqFields);
     }
 
     @undoBatch
@@ -576,7 +576,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 this.selectedDoc && (this.selectedDoc.y = NumCast(this.selectedDoc?.y) + (dirs === 'up' ? 10 : -10));
                 break;
             case 'stk':
-                this.selectedDoc && (this.selectedDoc.strokeWidth = NumCast(this.selectedDoc?.strokeWidth) + (dirs === 'up' ? 0.1 : -0.1));
+                this.selectedDoc && (this.selectedDoc.stroke_width = NumCast(this.selectedDoc?.stroke_width) + (dirs === 'up' ? 0.1 : -0.1));
                 break;
             case 'wid':
                 const oldWidth = NumCast(this.selectedDoc?._width);
@@ -813,25 +813,25 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get solidStk() {
-        return this.selectedDoc?.color && (!this.selectedDoc?.strokeDash || this.selectedDoc?.strokeDash === '0') ? true : false;
+        return this.selectedDoc?.color && (!this.selectedDoc?.stroke_dash || this.selectedDoc?.stroke_dash === '0') ? true : false;
     }
     @computed get dashdStk() {
-        return this.selectedDoc?.strokeDash || '';
+        return this.selectedDoc?.stroke_dash || '';
     }
     @computed get unStrokd() {
         return this.selectedDoc?.color ? true : false;
     }
     @computed get widthStk() {
-        return this.getField('strokeWidth') || '1';
+        return this.getField('stroke_width') || '1';
     }
     @computed get markScal() {
         return Number(this.getField('strokeMakerScale') || '1');
     }
     @computed get markHead() {
-        return this.getField('strokeStartMarker') || '';
+        return this.getField('stroke_startMarker') || '';
     }
     @computed get markTail() {
-        return this.getField('strokeEndMarker') || '';
+        return this.getField('stroke_endMarker') || '';
     }
     set solidStk(value) {
         this.dashdStk = '';
@@ -839,22 +839,22 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
     set dashdStk(value) {
         value && (this._lastDash = value) && (this.unStrokd = false);
-        this.selectedDoc && (this.selectedDoc.strokeDash = value ? this._lastDash : undefined);
+        this.selectedDoc && (this.selectedDoc.stroke_dash = value ? this._lastDash : undefined);
     }
     set markScal(value) {
         this.selectedDoc && (this.selectedDoc.strokeMarkerScale = Number(value));
     }
     set widthStk(value) {
-        this.selectedDoc && (this.selectedDoc.strokeWidth = Number(value));
+        this.selectedDoc && (this.selectedDoc.stroke_width = Number(value));
     }
     set unStrokd(value) {
         this.colorStk = value ? '' : this._lastLine;
     }
     set markHead(value) {
-        this.selectedDoc && (this.selectedDoc.strokeStartMarker = value);
+        this.selectedDoc && (this.selectedDoc.stroke_startMarker = value);
     }
     set markTail(value) {
-        this.selectedDoc && (this.selectedDoc.strokeEndMarker = value);
+        this.selectedDoc && (this.selectedDoc.stroke_endMarker = value);
     }
 
     @computed get stkInput() {
@@ -1151,16 +1151,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get description() {
-        return Field.toString(LinkManager.currentLink?.description as any as Field);
+        return Field.toString(LinkManager.currentLink?.link_description as any as Field);
     }
     @computed get relationship() {
-        return StrCast(LinkManager.currentLink?.linkRelationship);
+        return StrCast(LinkManager.currentLink?.link_relationship);
     }
     @observable private relationshipButtonColor: string = '';
 
     // @action
-    // handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; }
-    // handleRelationshipChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.relationship = e.target.value; }
+    // handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.link_description = e.target.value; }
+    // handleRelationshipChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.link_relationship = e.target.value; }
 
     @undoBatch
     handleDescriptionChange = action((value: string) => {
@@ -1171,9 +1171,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     });
 
     @undoBatch
-    handleLinkRelationshipChange = action((value: string) => {
+    handlelinkRelationshipChange = action((value: string) => {
         if (LinkManager.currentLink && this.selectedDoc) {
-            this.setLinkRelationshipValue(value);
+            this.setlinkRelationshipValue(value);
             return true;
         }
     });
@@ -1181,19 +1181,19 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @undoBatch
     setDescripValue = action((value: string) => {
         if (LinkManager.currentLink) {
-            Doc.GetProto(LinkManager.currentLink).description = value;
+            Doc.GetProto(LinkManager.currentLink).link_description = value;
             return true;
         }
     });
 
     @undoBatch
-    setLinkRelationshipValue = action((value: string) => {
+    setlinkRelationshipValue = action((value: string) => {
         if (LinkManager.currentLink) {
-            const prevRelationship = LinkManager.currentLink.linkRelationship as string;
-            LinkManager.currentLink.linkRelationship = value;
-            Doc.GetProto(LinkManager.currentLink).linkRelationship = value;
-            const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList);
-            const linkRelationshipSizes = NumListCast(Doc.UserDoc().linkRelationshipSizes);
+            const prevRelationship = StrCast(LinkManager.currentLink.link_relationship);
+            LinkManager.currentLink.link_relationship = value;
+            Doc.GetProto(LinkManager.currentLink).link_relationship = value;
+            const linkRelationshipList = StrListCast(Doc.UserDoc().link_relationshipList);
+            const linkRelationshipSizes = NumListCast(Doc.UserDoc().link_relationshipSizes);
             const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
 
             // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color
@@ -1264,13 +1264,13 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     };
 
     onSelectOutRelationship = () => {
-        this.setLinkRelationshipValue(this.relationship);
+        this.setlinkRelationshipValue(this.relationship);
         document.getElementById('link_relationship_input')?.blur();
     };
 
     onRelationshipKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.key === 'Enter') {
-            this.setLinkRelationshipValue(this.relationship);
+            this.setlinkRelationshipValue(this.relationship);
             document.getElementById('link_relationship_input')?.blur();
         }
     };
@@ -1283,7 +1283,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         const ldoc = LinkManager.currentLink;
         const lanch = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.currentLinkAnchor;
         if (ldoc && lanch) return LinkManager.getOppositeAnchor(ldoc, lanch) ?? lanch;
-        return ldoc ? DocCast(ldoc.anchor2) : ldoc;
+        return ldoc ? DocCast(ldoc.link_anchor_2) : ldoc;
     }
 
     @computed get sourceAnchor() {
@@ -1314,10 +1314,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             <input
                 autoComplete={'off'}
                 id="link_relationship_input"
-                value={StrCast(this.selectedDoc?.linkRelationship)}
+                value={StrCast(LinkManager.currentLink?.link_relationship)}
                 onKeyDown={this.onRelationshipKey}
                 onBlur={this.onSelectOutRelationship}
-                onChange={e => this.handleLinkRelationshipChange(e.currentTarget.value)}
+                onChange={e => this.handlelinkRelationshipChange(e.currentTarget.value)}
                 className="text"
                 type="text"
             />
@@ -1331,7 +1331,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 autoComplete="off"
                 style={{ textAlign: 'left' }}
                 id="link_description_input"
-                value={StrCast(this.selectedDoc?.description)}
+                value={Field.toString(LinkManager.currentLink?.link_description as any as Field)}
                 onKeyDown={this.onDescriptionKey}
                 onBlur={this.onSelectOutDesc}
                 onChange={e => this.handleDescriptionChange(e.currentTarget.value)}
@@ -1406,8 +1406,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline">
                                         <p>Show link</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.linkDisplay ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'linkDisplay')}
+                                            style={{ background: !LinkManager.currentLink?.layout_linkDisplay ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_linkDisplay')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
@@ -1416,8 +1416,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
                                         <p>Auto-move anchors</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.linkAutoMove ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'linkAutoMove')}
+                                            style={{ background: !LinkManager.currentLink?.layout_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_autoMoveAnchors')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
@@ -1426,8 +1426,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
                                         <p>Display arrow</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.linkDisplayArrow ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'linkDisplayArrow')}
+                                            style={{ background: !LinkManager.currentLink?.layout_linkDisplayArrow ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_linkDisplayArrow')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index b0aab968e..741e87644 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -67,15 +67,15 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
             annotationOn: this.props.rootDoc,
             _width: 200,
             _height: 50,
-            _fitWidth: true,
-            _autoHeight: true,
+            _layout_fitWidth: true,
+            _layout_autoHeight: true,
             _fontSize: StrCast(Doc.UserDoc().fontSize),
             _fontFamily: StrCast(Doc.UserDoc().fontFamily),
         });
         FormattedTextBox.SelectOnLoad = target[Id];
         FormattedTextBox.DontSelectInitialText = true;
-        const link = DocUtils.MakeLink(anchor, target, { linkRelationship: 'inline comment:comment on' });
-        link && (link.linkDisplay = false);
+        const link = DocUtils.MakeLink(anchor, target, { link_relationship: 'inline comment:comment on' });
+        link && (link.layout_linkDisplay = false);
 
         const taggedContent = this.docFilters()
             .filter(data => data.split(':')[0])
@@ -151,7 +151,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     };
 
     get sidebarKey() {
-        return this.props.fieldKey + '-sidebar';
+        return this.props.fieldKey + '_sidebar';
     }
     filtersHeight = () => 38;
     screenToLocalTransform = () =>
@@ -170,11 +170,11 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(doc, targetCollection, addDocument, this.sidebarKey);
     removeDocument = (doc: Doc | Doc[]) => this.props.removeDocument(doc, this.sidebarKey);
     docFilters = () => [...StrListCast(this.props.layoutDoc._docFilters), ...StrListCast(this.props.layoutDoc[this.filtersKey])];
-    showTitle = () => 'title';
+    layout_showTitle = () => 'title';
     setHeightCallback = (height: number) => this.props.setHeight?.(height + this.filtersHeight());
     sortByLinkAnchorY = (a: Doc, b: Doc) => {
-        const ay = LinkManager.Links(a).length && DocCast(LinkManager.Links(a)[0].anchor1).y;
-        const by = LinkManager.Links(b).length && DocCast(LinkManager.Links(b)[0].anchor1).y;
+        const ay = LinkManager.Links(a).length && DocCast(LinkManager.Links(a)[0].link_anchor_1).y;
+        const by = LinkManager.Links(b).length && DocCast(LinkManager.Links(b)[0].link_anchor_1).y;
         return NumCast(ay) - NumCast(by);
     };
     render() {
@@ -208,7 +208,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                 style={{
                     position: 'absolute',
                     pointerEvents: this.props.isContentActive() ? 'all' : undefined,
-                    top: this.props.rootDoc.type !== DocumentType.RTF && StrCast(this.props.rootDoc._showTitle) === 'title' ? 15 : 0,
+                    top: this.props.rootDoc.type !== DocumentType.RTF && StrCast(this.props.rootDoc._layout_showTitle) === 'title' ? 15 : 0,
                     right: 0,
                     background: this.props.styleProvider?.(this.props.rootDoc, this.props, StyleProp.WidgetColor),
                     width: `100%`,
@@ -235,7 +235,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                         isAnnotationOverlay={false}
                         select={emptyFunction}
                         NativeDimScaling={returnOne}
-                        //childShowTitle={this.showTitle}
+                        //childlayout_showTitle={this.layout_showTitle}
                         isAnyChildContentActive={returnFalse}
                         childDocumentsActive={this.props.isContentActive}
                         whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 192a501f2..e852d9297 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -41,9 +41,9 @@ export enum StyleProp {
     PointerEvents = 'pointerEvents', // pointer events for DocumentView -- inherits pointer events if not specified
     Decorations = 'decorations', // additional decoration to display above a DocumentView -- currently only used to display a Lock for making things background
     HeaderMargin = 'headerMargin', // margin at top of documentview, typically for displaying a title -- doc contents will start below that
-    ShowCaption = 'showCaption',
+    showCaption = 'layout_showCaption',
     TitleHeight = 'titleHeight', // Height of Title area
-    ShowTitle = 'showTitle', // whether to display a title on a Document (optional :hover suffix)
+    layout_showTitle = 'layout_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
@@ -92,11 +92,11 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
     const isAnnotated = property.includes(':annotated');
     const isOpen = property.includes(':open');
     const boxBackground = property.includes(':box');
-    const fieldKey = props?.fieldKey ? props.fieldKey + '-' : isCaption ? 'caption-' : '';
+    const fieldKey = props?.fieldKey ? props.fieldKey + '_' : isCaption ? 'caption_' : '';
     const lockedPosition = () => doc && BoolCast(doc._lockedPosition);
     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 layout_showTitle = () => props?.styleProvider?.(doc, props, StyleProp.layout_showTitle);
     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:
@@ -138,25 +138,25 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         case StyleProp.Opacity:
             return props?.LayoutTemplateString?.includes(KeyValueBox.name) ? 1 : Cast(doc?._opacity, 'number', Cast(doc?.opacity, 'number', null));
         case StyleProp.HideLinkButton:
-            return props?.hideLinkButton || (!selected && doc?.hideLinkButton);
+            return props?.hideLinkButton || (!selected && doc?.layout_hideLinkButton);
         case StyleProp.FontSize:
             return StrCast(doc?.[fieldKey + 'fontSize'], StrCast(doc?._fontSize, StrCast(Doc.UserDoc().fontSize)));
         case StyleProp.FontFamily:
             return StrCast(doc?.[fieldKey + 'fontFamily'], StrCast(doc?._fontFamily, StrCast(Doc.UserDoc().fontFamily)));
         case StyleProp.FontWeight:
             return StrCast(doc?.[fieldKey + 'fontWeight'], StrCast(doc?._fontWeight, StrCast(Doc.UserDoc().fontWeight)));
-        case StyleProp.ShowTitle:
+        case StyleProp.layout_showTitle:
             return (
                 (doc &&
                     !doc.presentationTargetDoc &&
                     !props?.LayoutTemplateString?.includes(KeyValueBox.name) &&
-                    props?.showTitle?.() !== '' &&
+                    props?.layout_showTitle?.() !== '' &&
                     StrCast(
-                        doc._showTitle,
-                        props?.showTitle?.() ||
+                        doc._layout_showTitle,
+                        props?.layout_showTitle?.() ||
                             (!Doc.IsSystem(doc) && [DocumentType.COL, DocumentType.FUNCPLOT, DocumentType.LABEL, DocumentType.RTF, DocumentType.IMG, DocumentType.VID].includes(doc.type as any)
                                 ? doc.author === Doc.CurrentUserEmail
-                                    ? StrCast(Doc.UserDoc().showTitle)
+                                    ? StrCast(Doc.UserDoc().layout_showTitle)
                                     : remoteDocHeader
                                 : '')
                     )) ||
@@ -194,19 +194,19 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                   };
         case StyleProp.JitterRotation:
             return Doc.IsComicStyle(doc) ? random(-1, 1, NumCast(doc?.x), NumCast(doc?.y)) * ((props?.PanelWidth() || 0) > (props?.PanelHeight() || 0) ? 5 : 10) : 0;
-        case StyleProp.ShowCaption:
-            return doc?._viewType === CollectionViewType.Carousel || props?.hideCaptions ? undefined : StrCast(doc?._showCaption);
+        case StyleProp.showCaption:
+            return doc?._viewType === CollectionViewType.Carousel || props?.hideCaptions ? undefined : StrCast(doc?._layout_showCaption);
         case StyleProp.HeaderMargin:
             return ([CollectionViewType.Stacking, CollectionViewType.NoteTaking, CollectionViewType.Masonry, CollectionViewType.Tree].includes(doc?._viewType as any) ||
-                (doc?.type === DocumentType.RTF && !showTitle()?.includes('noMargin')) ||
+                (doc?.type === DocumentType.RTF && !layout_showTitle()?.includes('noMargin')) ||
                 doc?.type === DocumentType.LABEL) &&
-                showTitle() &&
-                !StrCast(doc?.showTitle).includes(':hover')
+                layout_showTitle() &&
+                !StrCast(doc?.layout_showTitle).includes(':hover')
                 ? 15
                 : 0;
         case StyleProp.BackgroundColor: {
             if (MainView.Instance.LastButton === doc) return Colors.LIGHT_GRAY;
-            let docColor: Opt<string> = StrCast(doc?.[fieldKey + 'backgroundColor'], StrCast(doc?._backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : ''));
+            let docColor: Opt<string> = StrCast(doc?.[fieldKey + '_backgroundColor'], StrCast(doc?._backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : ''));
             switch (doc?.type) {
                 case DocumentType.PRESELEMENT:
                     docColor = docColor || (darkScheme() ? '' : '');
@@ -224,7 +224,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                     docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : 'rgba(105, 105, 105, 0.432)');
                     break;
                 case DocumentType.INK:
-                    docColor = doc?.isInkMask ? 'rgba(0,0,0,0.7)' : undefined;
+                    docColor = doc?.stroke_isInkMask ? 'rgba(0,0,0,0.7)' : undefined;
                     break;
                 case DocumentType.SLIDER:
                     break;
@@ -293,7 +293,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 default:
                     return doc.z
                         ? `#9c9396  ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
-                        : props?.docViewPath().lastElement()?.rootDoc._useClusters
+                        : props?.docViewPath().lastElement()?.rootDoc._freeform_useClusters
                         ? `${backgroundCol()} ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : NumCast(doc.group, -1) !== -1
                         ? `gray ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
@@ -381,7 +381,7 @@ export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps
         return doc._viewType === CollectionViewType.Docking ? null : (
             <>
                 {DashboardToggleButton(doc, 'hidden', 'eye-slash', 'eye', () => {
-                    DocFocusOrOpen(doc, { toggleTarget: true, willZoomCentered: true, zoomScale: 0 }, DocCast(doc?.context ?? doc?.annotationOn));
+                    DocFocusOrOpen(doc, { toggleTarget: true, willZoomCentered: true, zoomScale: 0 }, DocCast(doc?.embedContainer ?? doc?.annotationOn));
                 })}
             </>
         );
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 1c816aa05..814a95ab8 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -91,12 +91,12 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
     }
     templateIsUsed = (selDoc: Doc, templateDoc: Doc) => {
         const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title);
-        return StrCast(selDoc.layoutKey) === 'layout_' + template ? 'check' : 'unchecked';
+        return StrCast(selDoc.layout_fieldKey) === 'layout_' + template ? 'check' : 'unchecked';
     };
     render() {
         TraceMobx();
         const firstDoc = this.props.docViews[0].props.Document;
-        const templateName = StrCast(firstDoc.layoutKey, 'layout').replace('layout_', '');
+        const templateName = StrCast(firstDoc.layout_fieldKey, 'layout').replace('layout_', '');
         const noteTypes = DocListCast(Cast(Doc.UserDoc()['template-notes'], Doc, null)?.data);
         const addedTypes = DocListCast(Cast(Doc.UserDoc()['template-clickFuncs'], Doc, null)?.data);
         const templateMenu: Array<JSX.Element> = [];
diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx
index 7a393a4f7..adc97bbb4 100644
--- a/src/client/views/animationtimeline/Timeline.tsx
+++ b/src/client/views/animationtimeline/Timeline.tsx
@@ -76,7 +76,7 @@ export class Timeline extends React.Component<FieldViewProps> {
     private get children(): Doc[] {
         const annotatedDoc = [DocumentType.IMG, DocumentType.VID, DocumentType.PDF, DocumentType.MAP].includes(StrCast(this.props.Document.type) as any);
         if (annotatedDoc) {
-            return DocListCast(this.props.Document[Doc.LayoutFieldKey(this.props.Document) + '-annotations']);
+            return DocListCast(this.props.Document[Doc.LayoutFieldKey(this.props.Document) + '_annotations']);
         }
         return DocListCast(this.props.Document[this.props.fieldKey]);
     }
@@ -290,15 +290,15 @@ export class Timeline extends React.Component<FieldViewProps> {
     };
 
     resetView(doc: Doc) {
-        doc._panX = doc._customOriginX ?? 0;
-        doc._panY = doc._customOriginY ?? 0;
-        doc._viewScale = doc._customOriginScale ?? 1;
+        doc._freeform_panX = doc._customOriginX ?? 0;
+        doc._freeform_panY = doc._customOriginY ?? 0;
+        doc._freeform_scale = doc._customOriginScale ?? 1;
     }
 
     setView(doc: Doc) {
-        doc._customOriginX = doc._panX;
-        doc._customOriginY = doc._panY;
-        doc._customOriginScale = doc._viewScale;
+        doc._customOriginX = doc._freeform_panX;
+        doc._customOriginY = doc._freeform_panY;
+        doc._customOriginScale = doc._freeform_scale;
     }
     /**
      * zooming mechanism (increment and spacing changes)
diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx
index 25c2e68e7..2349ba786 100644
--- a/src/client/views/animationtimeline/Track.tsx
+++ b/src/client/views/animationtimeline/Track.tsx
@@ -1,15 +1,15 @@
-import { action, computed, intercept, observable, reaction, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import * as React from "react";
-import { Doc, DocListCast, Opt, DocListCastAsync } from "../../../fields/Doc";
-import { Copy } from "../../../fields/FieldSymbols";
-import { List } from "../../../fields/List";
-import { ObjectField } from "../../../fields/ObjectField";
-import { listSpec } from "../../../fields/Schema";
-import { Cast, NumCast } from "../../../fields/Types";
-import { Transform } from "../../util/Transform";
-import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe";
-import "./Track.scss";
+import { action, computed, intercept, observable, reaction, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc, DocListCast, Opt, DocListCastAsync } from '../../../fields/Doc';
+import { Copy } from '../../../fields/FieldSymbols';
+import { List } from '../../../fields/List';
+import { ObjectField } from '../../../fields/ObjectField';
+import { listSpec } from '../../../fields/Schema';
+import { Cast, NumCast } from '../../../fields/Types';
+import { Transform } from '../../util/Transform';
+import { Keyframe, KeyframeFunc, RegionData } from './Keyframe';
+import './Track.scss';
 
 interface IProps {
     node: Doc;
@@ -32,27 +32,22 @@ export class Track extends React.Component<IProps> {
     @observable private _newKeyframe: boolean = false;
     private readonly MAX_TITLE_HEIGHT = 75;
     @observable private _trackHeight = 0;
-    private primitiveWhitelist = [
-        "x",
-        "y",
-        "_width",
-        "_height",
-        "opacity",
-        "_scrollTop"
-    ];
-    private objectWhitelist = [
-        "data"
-    ];
+    private primitiveWhitelist = ['x', 'y', '_width', '_height', 'opacity', '_layout_scrollTop'];
+    private objectWhitelist = ['data'];
 
-    @computed private get regions() { return DocListCast(this.props.node.regions); }
-    @computed private get time() { return NumCast(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); }
+    @computed private get regions() {
+        return DocListCast(this.props.node.regions);
+    }
+    @computed private get time() {
+        return NumCast(KeyframeFunc.convertPixelTime(this.props.currentBarX, 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement));
+    }
 
     async componentDidMount() {
         const regions = await DocListCastAsync(this.props.node.regions);
         if (!regions) this.props.node.regions = new List<Doc>(); //if there is no region, then create new doc to store stuff
-        //these two lines are exactly same from timeline.tsx 
+        //these two lines are exactly same from timeline.tsx
         const relativeHeight = window.innerHeight / 20;
-        runInAction(() => this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT); //for responsiveness
+        runInAction(() => (this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT)); //for responsiveness
         this._timelineVisibleReaction = this.timelineVisibleReaction();
         this._currentBarXReaction = this.currentBarXReaction();
         if (DocListCast(this.props.node.regions).length === 0) this.createRegion(this.time);
@@ -71,7 +66,6 @@ export class Track extends React.Component<IProps> {
     }
     ////////////////////////////////
 
-
     getLastRegionTime = () => {
         let lastTime: number = 0;
         let lastRegion: Opt<Doc>;
@@ -83,11 +77,11 @@ export class Track extends React.Component<IProps> {
             }
         });
         return lastRegion ? lastTime + NumCast(lastRegion.duration) : 0;
-    }
+    };
 
     /**
      * keyframe save logic. Needs to be changed so it's more efficient
-     * 
+     *
      */
     @action
     saveKeyframe = async () => {
@@ -97,16 +91,18 @@ export class Track extends React.Component<IProps> {
         if (this._newKeyframe) {
             DocListCast(this.saveStateRegion?.keyframes).forEach((kf, index) => {
                 this.copyDocDataToKeyFrame(kf);
-                kf.opacity = (index === 0 || index === 3) ? 0.1 : 1;
+                kf.opacity = index === 0 || index === 3 ? 0.1 : 1;
             });
             this._newKeyframe = false;
         }
         if (!kf) return;
-        if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades
+        if (kf.type === KeyframeFunc.KeyframeType.default) {
+            // only save for non-fades
             this.copyDocDataToKeyFrame(kf);
             const leftkf = KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, kf); // lef keyframe, if it exists
-            const rightkf = KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, kf); //right keyframe, if it exists 
-            if (leftkf?.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades
+            const rightkf = KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, kf); //right keyframe, if it exists
+            if (leftkf?.type === KeyframeFunc.KeyframeType.fade) {
+                //replicating this keyframe to fades
                 const edge = KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, leftkf);
                 edge && this.copyDocDataToKeyFrame(edge);
                 leftkf && this.copyDocDataToKeyFrame(leftkf);
@@ -124,8 +120,7 @@ export class Track extends React.Component<IProps> {
         keyframes[kfIndex] = kf;
         this.saveStateKf = undefined;
         this.saveStateRegion = undefined;
-    }
-
+    };
 
     /**
      * autocreates keyframe
@@ -136,23 +131,27 @@ export class Track extends React.Component<IProps> {
         intercept(this.props.node, change => {
             return change;
         });
-        return reaction(() => {
-            return [...this.primitiveWhitelist.map(key => this.props.node[key]), ...objects];
-        }, (changed, reaction) => {
-            //check for region 
-            const region = this.findRegion(this.time);
-            if (region !== undefined) { //if region at scrub time exist
-                const r = region as RegionData; //for some region is returning undefined... which is not the case
-                if (DocListCast(r.keyframes).find(kf => kf.time === this.time) === undefined) { //basically when there is no additional keyframe at that timespot 
-                    this.makeKeyData(r, this.time, KeyframeFunc.KeyframeType.default);
+        return reaction(
+            () => {
+                return [...this.primitiveWhitelist.map(key => this.props.node[key]), ...objects];
+            },
+            (changed, reaction) => {
+                //check for region
+                const region = this.findRegion(this.time);
+                if (region !== undefined) {
+                    //if region at scrub time exist
+                    const r = region as RegionData; //for some region is returning undefined... which is not the case
+                    if (DocListCast(r.keyframes).find(kf => kf.time === this.time) === undefined) {
+                        //basically when there is no additional keyframe at that timespot
+                        this.makeKeyData(r, this.time, KeyframeFunc.KeyframeType.default);
+                    }
                 }
-            }
-        }, { fireImmediately: false });
-    }
-
-
+            },
+            { fireImmediately: false }
+        );
+    };
 
-    // @observable private _storedState:(Doc | undefined) = undefined; 
+    // @observable private _storedState:(Doc | undefined) = undefined;
     // /**
     //  * reverting back to previous state before editing on AT
     //  */
@@ -161,54 +160,62 @@ export class Track extends React.Component<IProps> {
     //     if (this._storedState) this.applyKeys(this._storedState);
     // }
 
-
     /**
      * Reaction when scrubber bar changes
      * made into function so it's easier to dispose later
-    */
+     */
     @action
     currentBarXReaction = () => {
-        return reaction(() => this.props.currentBarX, () => {
-            const regiondata = this.findRegion(this.time);
-            if (regiondata) {
-                this.props.node.hidden = false;
-                // if (!this._autoKfReaction) {
-                //     // this._autoKfReaction = this.autoCreateKeyframe(); 
-                // }
-                this.timeChange();
-            } else {
-                this.props.node.hidden = true;
-                this.props.node.opacity = 0;
-                //if (this._autoKfReaction) this._autoKfReaction(); 
+        return reaction(
+            () => this.props.currentBarX,
+            () => {
+                const regiondata = this.findRegion(this.time);
+                if (regiondata) {
+                    this.props.node.hidden = false;
+                    // if (!this._autoKfReaction) {
+                    //     // this._autoKfReaction = this.autoCreateKeyframe();
+                    // }
+                    this.timeChange();
+                } else {
+                    this.props.node.hidden = true;
+                    this.props.node.opacity = 0;
+                    //if (this._autoKfReaction) this._autoKfReaction();
+                }
             }
-        });
-    }
+        );
+    };
 
     /**
      * when timeline is visible, reaction is ran so states are reverted
      */
     @action
     timelineVisibleReaction = () => {
-        return reaction(() => {
-            return this.props.timelineVisible;
-        }, isVisible => {
-            if (isVisible) {
-                this.regions.filter(region => !region.hasData).forEach(region => {
-                    for (let i = 0; i < 4; i++) {
-                        this.copyDocDataToKeyFrame(DocListCast(region.keyframes)[i]);
-                        if (i === 0 || i === 3) { //manually inputing fades
-                            DocListCast(region.keyframes)[i].opacity = 0.1;
-                        }
-                    }
-                });
-            } else {
-                //this.revertState(); 
+        return reaction(
+            () => {
+                return this.props.timelineVisible;
+            },
+            isVisible => {
+                if (isVisible) {
+                    this.regions
+                        .filter(region => !region.hasData)
+                        .forEach(region => {
+                            for (let i = 0; i < 4; i++) {
+                                this.copyDocDataToKeyFrame(DocListCast(region.keyframes)[i]);
+                                if (i === 0 || i === 3) {
+                                    //manually inputing fades
+                                    DocListCast(region.keyframes)[i].opacity = 0.1;
+                                }
+                            }
+                        });
+                } else {
+                    //this.revertState();
+                }
             }
-        });
-    }
+        );
+    };
 
-    @observable private saveStateKf: (Doc | undefined) = undefined;
-    @observable private saveStateRegion: (Doc | undefined) = undefined;
+    @observable private saveStateKf: Doc | undefined = undefined;
+    @observable private saveStateRegion: Doc | undefined = undefined;
 
     /**w
      * when scrubber position changes. Need to edit the logic
@@ -222,9 +229,9 @@ export class Track extends React.Component<IProps> {
         }
         const regiondata = await this.findRegion(Math.round(this.time)); //finds a region that the scrubber is on
         if (regiondata) {
-            const leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, this.time); // lef keyframe, if it exists
-            const rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists        
-            const currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe
+            const leftkf: Doc | undefined = await KeyframeFunc.calcMinLeft(regiondata, this.time); // lef keyframe, if it exists
+            const rightkf: Doc | undefined = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists
+            const currentkf: Doc | undefined = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe
             if (currentkf) {
                 await this.applyKeys(currentkf);
                 this.saveStateKf = currentkf;
@@ -233,10 +240,10 @@ export class Track extends React.Component<IProps> {
                 await this.interpolate(leftkf, rightkf);
             }
         }
-    }
+    };
 
     /**
-     * applying changes (when saving the keyframe) 
+     * applying changes (when saving the keyframe)
      * need to change the logic here
      */
     @action
@@ -249,73 +256,73 @@ export class Track extends React.Component<IProps> {
                 this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored;
             }
         });
-    }
-
+    };
 
     /**
      *  calculating current keyframe, if the scrubber is right on the keyframe
      */
     @action
     calcCurrent = (region: Doc) => {
-        let currentkf: (Doc | undefined) = undefined;
+        let currentkf: Doc | undefined = undefined;
         const keyframes = DocListCast(region.keyframes!);
-        keyframes.forEach((kf) => {
+        keyframes.forEach(kf => {
             if (NumCast(kf.time) === Math.round(this.time)) currentkf = kf;
         });
         return currentkf;
-    }
-
+    };
 
     /**
-     * basic linear interpolation function 
+     * basic linear interpolation function
      */
     @action
     interpolate = async (left: Doc, right: Doc) => {
         this.primitiveWhitelist.forEach(key => {
-            if (left[key] && right[key] && typeof (left[key]) === "number" && typeof (right[key]) === "number") { //if it is number, interpolate
+            if (left[key] && right[key] && typeof left[key] === 'number' && typeof right[key] === 'number') {
+                //if it is number, interpolate
                 const dif = NumCast(right[key]) - NumCast(left[key]);
                 const deltaLeft = this.time - NumCast(left.time);
                 const ratio = deltaLeft / (NumCast(right.time) - NumCast(left.time));
-                this.props.node[key] = NumCast(left[key]) + (dif * ratio);
-            } else { // case data 
+                this.props.node[key] = NumCast(left[key]) + dif * ratio;
+            } else {
+                // case data
                 const stored = left[key];
                 this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored;
             }
         });
-    }
+    };
 
     /**
      * finds region that corresponds to specific time (is there a region at this time?)
      * linear O(n) (maybe possible to optimize this with other Data structures?)
      */
     findRegion = (time: number) => {
-        return this.regions?.find(rd => (time >= NumCast(rd.position) && time <= (NumCast(rd.position) + NumCast(rd.duration))));
-    }
-
+        return this.regions?.find(rd => time >= NumCast(rd.position) && time <= NumCast(rd.position) + NumCast(rd.duration));
+    };
 
     /**
-     * double click on track. Signalling keyframe creation. 
+     * double click on track. Signalling keyframe creation.
      */
     @action
     onInnerDoubleClick = (e: React.MouseEvent) => {
         const inner = this._inner.current!;
         const offsetX = Math.round((e.clientX - inner.getBoundingClientRect().left) * this.props.transform.Scale);
-        this.createRegion(KeyframeFunc.convertPixelTime(offsetX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement));
-    }
-
+        this.createRegion(KeyframeFunc.convertPixelTime(offsetX, 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement));
+    };
 
     /**
-     * creates a region (KEYFRAME.TSX stuff). 
+     * creates a region (KEYFRAME.TSX stuff).
      */
     @action
     createRegion = (time: number) => {
-        if (this.findRegion(time) === undefined) {  //check if there is a region where double clicking (prevents phantom regions)
+        if (this.findRegion(time) === undefined) {
+            //check if there is a region where double clicking (prevents phantom regions)
             const regiondata = KeyframeFunc.defaultKeyframe(); //create keyframe data
 
             regiondata.position = time; //set position
             const rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, regiondata, this.regions);
 
-            if (rightRegion && rightRegion.position - regiondata.position <= 4000) { //edge case when there is less than default 4000 duration space between this and right region
+            if (rightRegion && rightRegion.position - regiondata.position <= 4000) {
+                //edge case when there is less than default 4000 duration space between this and right region
                 regiondata.duration = rightRegion.position - regiondata.position;
             }
             if (this.regions.length === 0 || !rightRegion || (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))) {
@@ -325,27 +332,30 @@ export class Track extends React.Component<IProps> {
                 return regiondata;
             }
         }
-    }
+    };
 
     @action
-    makeKeyData = (regiondata: RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time 
+    makeKeyData = (regiondata: RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => {
+        //Kfpos is mouse offsetX, representing time
         const trackKeyFrames = DocListCast(regiondata.keyframes);
         const existingkf = trackKeyFrames.find(TK => TK.time === time);
         if (existingkf) return existingkf;
-        //else creates a new doc. 
+        //else creates a new doc.
         const newKeyFrame: Doc = new Doc();
         newKeyFrame.time = time;
         newKeyFrame.type = type;
         this.copyDocDataToKeyFrame(newKeyFrame);
         //assuming there are already keyframes (for keeping keyframes in order, sorted by time)
         if (trackKeyFrames.length === 0) regiondata.keyframes!.push(newKeyFrame);
-        trackKeyFrames.map(kf => NumCast(kf.time)).forEach((kfTime, index) => {
-            if ((kfTime < time && index === trackKeyFrames.length - 1) || (kfTime < time && time < NumCast(trackKeyFrames[index + 1].time))) {
-                regiondata.keyframes!.splice(index + 1, 0, newKeyFrame);
-            }
-        });
+        trackKeyFrames
+            .map(kf => NumCast(kf.time))
+            .forEach((kfTime, index) => {
+                if ((kfTime < time && index === trackKeyFrames.length - 1) || (kfTime < time && time < NumCast(trackKeyFrames[index + 1].time))) {
+                    regiondata.keyframes!.splice(index + 1, 0, newKeyFrame);
+                }
+            });
         return newKeyFrame;
-    }
+    };
 
     @action
     copyDocDataToKeyFrame = (doc: Doc) => {
@@ -353,7 +363,7 @@ export class Track extends React.Component<IProps> {
             const originalVal = this.props.node[key];
             doc[key] = originalVal instanceof ObjectField ? originalVal[Copy]() : originalVal;
         });
-    }
+    };
 
     /**
      * UI sstuff here. Not really much to change
@@ -362,10 +372,13 @@ export class Track extends React.Component<IProps> {
         return (
             <div className="track-container">
                 <div className="track">
-                    <div className="inner" ref={this._inner} style={{ height: `${this._trackHeight}px` }}
+                    <div
+                        className="inner"
+                        ref={this._inner}
+                        style={{ height: `${this._trackHeight}px` }}
                         onDoubleClick={this.onInnerDoubleClick}
                         onPointerOver={() => Doc.BrushDoc(this.props.node)}
-                        onPointerOut={() => Doc.UnBrushDoc(this.props.node)} >
+                        onPointerOut={() => Doc.UnBrushDoc(this.props.node)}>
                         {this.regions?.map((region, i) => {
                             return <Keyframe key={`${i}`} {...this.props} RegionData={region} makeKeyData={this.makeKeyData} />;
                         })}
@@ -374,4 +387,4 @@ export class Track extends React.Component<IProps> {
             </div>
         );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 02f925bea..9ec78155c 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -41,16 +41,16 @@ export class CollectionCarouselView extends CollectionSubView() {
         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);
+    panelHeight = () => this.props.PanelHeight() - (StrCast(this.layoutDoc._layout_showCaption) ? 50 : 0);
     onContentDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
     onContentClick = () => ScriptCast(this.layoutDoc.onChildClick);
     @computed get content() {
         const index = NumCast(this.layoutDoc._itemIndex);
         const curDoc = this.childLayoutPairs?.[index];
         const captionProps = { ...this.props, fieldKey: 'caption', setHeight: undefined };
-        const marginX = NumCast(this.layoutDoc['caption-xMargin']);
-        const marginY = NumCast(this.layoutDoc['caption-yMargin']);
-        const showCaptions = StrCast(this.layoutDoc._showCaption);
+        const marginX = NumCast(this.layoutDoc['caption_xMargin']);
+        const marginY = NumCast(this.layoutDoc['caption_yMargin']);
+        const show_captions = StrCast(this.layoutDoc._layout_showCaption);
         return !(curDoc?.layout instanceof Doc) ? null : (
             <>
                 <div className="collectionCarouselView-image" key="image">
@@ -60,7 +60,7 @@ export class CollectionCarouselView extends CollectionSubView() {
                         NativeHeight={returnZero}
                         onDoubleClick={this.onContentDoubleClick}
                         onClick={this.onContentClick}
-                        hideCaptions={showCaptions ? true : false}
+                        hideCaptions={show_captions ? true : false}
                         renderDepth={this.props.renderDepth + 1}
                         LayoutTemplate={this.props.childLayoutTemplate}
                         LayoutTemplateString={this.props.childLayoutString}
@@ -75,13 +75,13 @@ export class CollectionCarouselView extends CollectionSubView() {
                     key="caption"
                     onWheel={StopEvent}
                     style={{
-                        display: showCaptions ? undefined : 'none',
+                        display: show_captions ? 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} allowScroll={true} fieldKey={showCaptions} styleProvider={this.captionStyleProvider} Document={curDoc.layout} DataDoc={undefined} />
+                    <FormattedTextBox key={index} {...captionProps} allowScroll={true} fieldKey={show_captions} styleProvider={this.captionStyleProvider} Document={curDoc.layout} DataDoc={undefined} />
                 </div>
             </>
         );
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index bb1f788d4..3a4691484 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -127,12 +127,12 @@ export class CollectionDockingView extends CollectionSubView() {
         SelectionManager.DeselectAll();
         const instance = CollectionDockingView.Instance;
         if (instance) {
-            if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === 'layout') {
+            if (doc._viewType === CollectionViewType.Docking && doc.layout_fieldKey === 'layout') {
                 return DashboardView.openDashboard(doc);
             }
             const newItemStackConfig = {
                 type: 'stack',
-                content: [CollectionDockingView.makeDocumentConfig(Doc.MakeAlias(doc))],
+                content: [CollectionDockingView.makeDocumentConfig(Doc.MakeEmbedding(doc))],
             };
             const docconfig = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
             instance._goldenLayout.root.contentItems[0].addChild(docconfig);
@@ -411,8 +411,8 @@ export class CollectionDockingView extends CollectionSubView() {
             const _height = Number(getComputedStyle(content).height.replace('px', ''));
             return CollectionFreeFormView.UpdateIcon(this.layoutDoc[Id] + '-icon' + new Date().getTime(), content, _width, _height, _width, _height, 0, 1, true, this.layoutDoc[Id] + '-icon', (iconFile, _nativeWidth, _nativeHeight) => {
                 const proto = this.dataDoc; // Cast(img.proto, Doc, null)!;
-                proto['thumb-nativeWidth'] = _width;
-                proto['thumb-nativeHeight'] = _height;
+                proto['thumb_nativeWidth'] = _width;
+                proto['thumb_nativeHeight'] = _height;
                 proto.thumb = new ImageField(iconFile);
             });
         }
@@ -434,11 +434,11 @@ export class CollectionDockingView extends CollectionSubView() {
             .map(f => f as Doc);
         const newtabs = origtabs.map(origtab => {
             const origtabdocs = DocListCast(origtab.data);
-            const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true, undefined, true) : Doc.MakeAlias(origtab);
-            const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeAlias(origtabdoc));
+            const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true, undefined, true) : Doc.MakeEmbedding(origtab);
+            const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeEmbedding(origtabdoc));
             if (newtabdocs.length) {
                 Doc.GetProto(newtab).data = new List<Doc>(newtabdocs);
-                newtabdocs.forEach(ntab => (ntab.context = newtab));
+                newtabdocs.forEach(ntab => (ntab.embedContainer = newtab));
             }
             json = json.replace(origtab[Id], newtab[Id]);
             return newtab;
@@ -498,8 +498,8 @@ export class CollectionDockingView extends CollectionSubView() {
                 const docToAdd = Docs.Create.FreeformDocument([], {
                     _width: this.props.PanelWidth(),
                     _height: this.props.PanelHeight(),
-                    _backgroundGridShow: true,
-                    _fitWidth: true,
+                    _freeform_backgroundGrid: true,
+                    _layout_fitWidth: true,
                     title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
                 });
                 this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd);
@@ -541,8 +541,8 @@ export class CollectionDockingView extends CollectionSubView() {
                         const docToAdd = Docs.Create.FreeformDocument([], {
                             _width: this.props.PanelWidth(),
                             _height: this.props.PanelHeight(),
-                            _fitWidth: true,
-                            _backgroundGridShow: true,
+                            _layout_fitWidth: true,
+                            _freeform_backgroundGrid: true,
                             title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
                         });
                         this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd);
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index befd89e41..528781991 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -44,7 +44,7 @@ interface CMVFieldRowProps {
 @observer
 export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowProps> {
     @observable private _background = 'inherit';
-    @observable private _createAliasSelected: boolean = false;
+    @observable private _createEmbeddingSelected: boolean = false;
     @observable private heading: string = '';
     @observable private color: string = '#f1efeb';
     @observable private collapsed: boolean = false;
@@ -95,7 +95,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
 
     @undoBatch
     rowDrop = action((e: Event, de: DragManager.DropEvent) => {
-        this._createAliasSelected = false;
+        this._createEmbeddingSelected = false;
         if (de.complete.docDragData) {
             this.props.parent.Document.dropConverter instanceof ScriptField && this.props.parent.Document.dropConverter.script.run({ dragData: de.complete.docDragData });
             const key = this.props.pivotField;
@@ -117,12 +117,12 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
 
     @action
     headingChanged = (value: string, shiftDown?: boolean) => {
-        this._createAliasSelected = false;
+        this._createEmbeddingSelected = false;
         const key = this.props.pivotField;
         const castedValue = this.getValue(value);
         if (castedValue) {
-            if (this.props.parent.columnHeaders) {
-                if (this.props.parent.columnHeaders.map(i => i.heading).indexOf(castedValue.toString()) > -1) {
+            if (this.props.parent.colHeaderData) {
+                if (this.props.parent.colHeaderData.map(i => i.heading).indexOf(castedValue.toString()) > -1) {
                     return false;
                 }
             }
@@ -135,7 +135,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
 
     @action
     changeColumnColor = (color: string) => {
-        this._createAliasSelected = false;
+        this._createEmbeddingSelected = false;
         this._color = color;
     };
 
@@ -143,16 +143,16 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
 
     @action
     pointerLeaveRow = () => {
-        this._createAliasSelected = false;
+        this._createEmbeddingSelected = false;
         this._background = 'inherit';
     };
 
     @action
     addDocument = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
         if (!value && !forceEmptyNote) return false;
-        this._createAliasSelected = false;
+        this._createEmbeddingSelected = false;
         const key = this.props.pivotField;
-        const newDoc = Docs.Create.TextDocument('', { _autoHeight: true, _width: 200, _fitWidth: true, title: value });
+        const newDoc = Docs.Create.TextDocument('', { _layout_autoHeight: true, _width: 200, _layout_fitWidth: true, title: value });
         const onLayoutDoc = this.onLayoutDoc(key);
         FormattedTextBox.SelectOnLoad = newDoc[Id];
         FormattedTextBox.SelectOnLoadChar = value;
@@ -163,33 +163,33 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
 
     deleteRow = undoBatch(
         action(() => {
-            this._createAliasSelected = false;
+            this._createEmbeddingSelected = false;
             const key = this.props.pivotField;
             this.props.docList.forEach(d => Doc.SetInPlace(d, key, undefined, true));
-            if (this.props.parent.columnHeaders && this.props.headingObject) {
-                const index = this.props.parent.columnHeaders.indexOf(this.props.headingObject);
-                this.props.parent.columnHeaders.splice(index, 1);
+            if (this.props.parent.colHeaderData && this.props.headingObject) {
+                const index = this.props.parent.colHeaderData.indexOf(this.props.headingObject);
+                this.props.parent.colHeaderData.splice(index, 1);
             }
         })
     );
 
     @action
     collapseSection = (e: any) => {
-        this._createAliasSelected = false;
+        this._createEmbeddingSelected = false;
         this.toggleVisibility();
         e.stopPropagation();
     };
 
     headerMove = (e: PointerEvent) => {
-        const alias = Doc.MakeAlias(this.props.Document);
+        const embedding = Doc.MakeEmbedding(this.props.Document);
         const key = this.props.pivotField;
         let value = this.getValue(this.heading);
         value = typeof value === 'string' ? `"${value}"` : value;
         const script = `return doc.${key} === ${value}`;
         const compiled = CompileScript(script, { params: { doc: Doc.name } });
         if (compiled.compiled) {
-            alias.viewSpecScript = new ScriptField(compiled);
-            DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY);
+            embedding.viewSpecScript = new ScriptField(compiled);
+            DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([embedding]), e.clientX, e.clientY);
         }
         return true;
     };
@@ -198,7 +198,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
         if (e.button === 0 && !e.ctrlKey) {
             setupMoveUpEvents(this, e, this.headerMove, emptyFunction, e => !this.props.chromeHidden && this.collapseSection(e));
-            this._createAliasSelected = false;
+            this._createEmbeddingSelected = false;
         }
     };
 
@@ -242,16 +242,16 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         );
     };
 
-    toggleAlias = action(() => (this._createAliasSelected = true));
+    toggleEmbedding = action(() => (this._createEmbeddingSelected = true));
     toggleVisibility = () => (this._collapsed = !this.collapsed);
 
     renderMenu = () => {
-        const selected = this._createAliasSelected;
+        const selected = this._createEmbeddingSelected;
         return (
             <div className="collectionStackingView-optionPicker">
                 <div className="optionOptions">
-                    <div className={'optionPicker' + (selected === true ? ' active' : '')} onClick={this.toggleAlias}>
-                        Create Alias
+                    <div className={'optionPicker' + (selected === true ? ' active' : '')} onClick={this.toggleEmbedding}>
+                        Create Embedding
                     </div>
                     <div className={'optionPicker' + (selected === true ? ' active' : '')} onClick={this.deleteRow}>
                         Delete
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 2154016bd..615014c4a 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -108,8 +108,8 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
                 <CollectionLinearView
                     Document={selDoc}
                     DataDoc={undefined}
-                    fieldKey={'data'}
-                    dropAction={'alias'}
+                    fieldKey="data"
+                    dropAction="embed"
                     setHeight={returnFalse}
                     styleProvider={DefaultStyleProvider}
                     rootSelected={returnTrue}
@@ -246,32 +246,32 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
     _viewCommand = {
         params: ['target'],
         title: 'bookmark view',
-        script: "self.target._panX = self['target-panX']; self.target._panY = self['target-panY']; self.target._viewScale = self['target-viewScale']; gotoFrame(self.target, self['target-currentFrame']);",
+        script: "self.target._freeform_panX = self['target-freeform_panX']; self.target._freeform_panY = self['target-freeform_panY']; self.target._freeform_scale = self['target_freeform_scale']; gotoFrame(self.target, self['target-currentFrame']);",
         immediate: undoBatch((source: Doc[]) => {
-            this.target._panX = 0;
-            this.target._panY = 0;
-            this.target._viewScale = 1;
+            this.target._freeform_panX = 0;
+            this.target._freeform_panY = 0;
+            this.target._freeform_scale = 1;
             this.target._currentFrame = this.target._currentFrame === undefined ? undefined : 0;
         }),
         initialize: (button: Doc) => {
-            button['target-panX'] = this.target._panX;
-            button['target-panY'] = this.target._panY;
-            button['target-viewScale'] = this.target._viewScale;
+            button['target-panX'] = this.target._freeform_panX;
+            button['target-panY'] = this.target._freeform_panY;
+            button['target-_ayout_scale'] = this.target._freeform_scale;
             button['target-currentFrame'] = this.target._currentFrame;
         },
     };
     _clusterCommand = {
         params: ['target'],
         title: 'fit content',
-        script: 'self.target._fitContentsToBox = !self.target._fitContentsToBox;',
-        immediate: undoBatch((source: Doc[]) => (this.target._fitContentsToBox = !this.target._fitContentsToBox)),
+        script: 'self.target._freeform_fitContentsToBox = !self.target._freeform_fitContentsToBox;',
+        immediate: undoBatch((source: Doc[]) => (this.target._freeform_fitContentsToBox = !this.target._freeform_fitContentsToBox)),
         initialize: emptyFunction,
     };
     _fitContentCommand = {
         params: ['target'],
         title: 'toggle clusters',
-        script: 'self.target._useClusters = !self.target._useClusters;',
-        immediate: undoBatch((source: Doc[]) => (this.target._useClusters = !this.target._useClusters)),
+        script: 'self.target._freeform_useClusters = !self.target._freeform_useClusters;',
+        immediate: undoBatch((source: Doc[]) => (this.target._freeform_useClusters = !this.target._freeform_useClusters)),
         initialize: emptyFunction,
     };
     _saveFilterCommand = {
@@ -548,7 +548,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
     @undoBatch
     @action
     startRecording = () => {
-        const doc = Docs.Create.ScreenshotDocument({ title: 'screen recording', _fitWidth: true, _width: 400, _height: 200, mediaState: 'pendingRecording' });
+        const doc = Docs.Create.ScreenshotDocument({ title: 'screen recording', _layout_fitWidth: true, _width: 400, _height: 200, mediaState: 'pendingRecording' });
         //Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
         CollectionDockingView.AddSplit(doc, OpenWhereMod.right);
     };
@@ -568,29 +568,29 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
     }
 
     @undoBatch
-    onAlias = () => {
+    onEmbed = () => {
         if (this.selectedDoc && this.selectedDocumentView) {
             // const copy = Doc.MakeCopy(this.selectedDocumentView.props.Document, true);
             // copy.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width);
             // copy.y = NumCast(this.selectedDoc.y) + 30;
             // this.selectedDocumentView.props.addDocument?.(copy);
-            const alias = Doc.MakeAlias(this.selectedDoc);
-            alias.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width);
-            alias.y = NumCast(this.selectedDoc.y) + 30;
-            this.selectedDocumentView.props.addDocument?.(alias);
+            const embedding = Doc.MakeEmbedding(this.selectedDoc);
+            embedding.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width);
+            embedding.y = NumCast(this.selectedDoc.y) + 30;
+            this.selectedDocumentView.props.addDocument?.(embedding);
         }
     };
-    onAliasButtonDown = (e: React.PointerEvent): void => {
-        setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction);
+    onEmbedButtonDown = (e: React.PointerEvent): void => {
+        setupMoveUpEvents(this, e, this.onEmbedButtonMoved, emptyFunction, emptyFunction);
     };
 
     @undoBatch
-    onAliasButtonMoved = (e: PointerEvent) => {
+    onEmbedButtonMoved = (e: PointerEvent) => {
         const contentDiv = this.selectedDocumentView?.ContentDiv;
         if (contentDiv && this.selectedDoc) {
             const dragData = new DragManager.DocumentDragData([this.selectedDoc]);
             const offset = [e.clientX - contentDiv.getBoundingClientRect().x, e.clientY - contentDiv.getBoundingClientRect().y];
-            dragData.defaultDropAction = 'alias';
+            dragData.defaultDropAction = 'embed';
             dragData.canEmbed = true;
             DragManager.StartDocumentDrag([contentDiv], dragData, e.clientX, e.clientY, {
                 offsetX: offset[0],
@@ -603,11 +603,11 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
     };
 
     @computed
-    get aliasButton() {
+    get embedButton() {
         const targetDoc = this.selectedDoc;
         return !targetDoc || targetDoc.type === DocumentType.PRES ? null : (
-            <Tooltip title={<div className="dash-tooltip">{'Tap or Drag to create an alias'}</div>} placement="top">
-                <button className="antimodeMenu-button" onPointerDown={this.onAliasButtonDown} onClick={this.onAlias} style={{ cursor: 'drag' }}>
+            <Tooltip title={<div className="dash-tooltip">{'Tap or Drag to create an embedding'}</div>} placement="top">
+                <button className="antimodeMenu-button" onPointerDown={this.onEmbedButtonDown} onClick={this.onEmbed} style={{ cursor: 'drag' }}>
                     <FontAwesomeIcon className="colMenu-icon" icon="copy" size="lg" />
                 </button>
             </Tooltip>
@@ -657,7 +657,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
                     <div className="collectionViewBaseChrome">
                         {this.notACollection || this.props.type === CollectionViewType.Invalid ? null : this.viewModes}
                         <div className="collectionMenu-divider" key="divider1"></div>
-                        {this.aliasButton}
+                        {this.embedButton}
                         {/* {this.pinButton} */}
                         {this.toggleOverlayButton}
                         <div className="collectionMenu-divider" key="divider2"></div>
@@ -691,7 +691,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
         return this.props.docView.props.Document;
     }
     @computed get dataField() {
-        return this.document[this.props.docView.LayoutFieldKey + (this.props.isOverlay ? '-annotations' : '')];
+        return this.document[this.props.docView.LayoutFieldKey + (this.props.isOverlay ? '_annotations' : '')];
     }
     @computed get childDocs() {
         return DocListCast(this.dataField);
@@ -798,7 +798,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
                 if (doc.type === DocumentType.INK) {
                     switch (field) {
                         case 'width':
-                            doc.strokeWidth = Number(value);
+                            doc.stroke_width = Number(value);
                             break;
                         case 'color':
                             doc.color = String(value);
@@ -807,7 +807,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
                             doc.fillColor = String(value);
                             break;
                         case 'dash':
-                            doc.strokeDash = value;
+                            doc.stroke_dash = value;
                     }
                 }
             })
@@ -1005,16 +1005,15 @@ export class CollectionStackingViewChrome extends React.Component<CollectionView
 
         if (Doc.noviceMode) {
             if (docs instanceof Doc) {
-                const keys = Object.keys(docs).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('lastModified') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_'));
+                const keys = Object.keys(docs).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_'));
                 return keys.filter(key => key.toLowerCase().indexOf(val) > -1);
-            } else {
-                const keys = new Set<string>();
-                docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
-                const noviceKeys = Array.from(keys).filter(
-                    key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('lastModified') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_')
-                );
-                return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1);
             }
+            const keys = new Set<string>();
+            docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
+            const noviceKeys = Array.from(keys).filter(
+                key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_')
+            );
+            return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1);
         }
 
         if (docs instanceof Doc) {
@@ -1125,13 +1124,13 @@ export class CollectionNoteTakingViewChrome extends React.Component<CollectionVi
 
         if (Doc.UserDoc().noviceMode) {
             if (docs instanceof Doc) {
-                const keys = Object.keys(docs).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('lastModified') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_'));
+                const keys = Object.keys(docs).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_'));
                 return keys.filter(key => key.toLowerCase().indexOf(val) > -1);
             } else {
                 const keys = new Set<string>();
                 docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
                 const noviceKeys = Array.from(keys).filter(
-                    key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('lastModified') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_')
+                    key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_')
                 );
                 return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1);
             }
@@ -1235,9 +1234,9 @@ export class CollectionSchemaViewChrome extends React.Component<CollectionViewMe
         const dividerWidth = 4;
         const borderWidth = Number(COLLECTION_BORDER_WIDTH);
         const panelWidth = this.props.docView.props.PanelWidth();
-        const previewWidth = NumCast(this.document.schemaPreviewWidth);
+        const previewWidth = NumCast(this.document.schema_previewWidth);
         const tableWidth = panelWidth - 2 * borderWidth - dividerWidth - previewWidth;
-        this.document.schemaPreviewWidth = previewWidth === 0 ? Math.min(tableWidth / 3, 200) : 0;
+        this.document.schema_previewWidth = previewWidth === 0 ? Math.min(tableWidth / 3, 200) : 0;
     };
 
     @undoBatch
@@ -1254,7 +1253,7 @@ export class CollectionSchemaViewChrome extends React.Component<CollectionViewMe
     };
 
     render() {
-        const previewWidth = NumCast(this.document.schemaPreviewWidth);
+        const previewWidth = NumCast(this.document.schema_previewWidth);
         const textWrapped = Cast(this.document.textwrappedSchemaRows, listSpec('string'), []).length > 0;
 
         return (
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 99d4d0bee..a65e23911 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -49,12 +49,12 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         return BoolCast(this.layoutDoc.chromeHidden);
     }
     // columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns
-    @computed get columnHeaders() {
-        const columnHeaders = Cast(this.dataDoc.columnHeaders, listSpec(SchemaHeaderField), null);
-        const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders?.find(sh => sh.heading === 'unset'));
-        if (needsUnsetCategory || columnHeaders === undefined || columnHeaders.length === 0) {
+    @computed get colHeaderData() {
+        const colHeaderData = Cast(this.dataDoc[this.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null);
+        const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !colHeaderData?.find(sh => sh.heading === 'unset'));
+        if (needsUnsetCategory || colHeaderData === undefined || colHeaderData.length === 0) {
             setTimeout(() => {
-                const columnHeaders = Array.from(Cast(this.dataDoc.columnHeaders, listSpec(SchemaHeaderField), null) ?? []);
+                const columnHeaders = Array.from(Cast(this.dataDoc[this.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null) ?? []);
                 const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders?.find(sh => sh.heading === 'unset'));
                 if (needsUnsetCategory || columnHeaders.length === 0) {
                     columnHeaders.push(new SchemaHeaderField('unset', undefined, undefined, 1));
@@ -62,7 +62,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 }
             });
         }
-        return columnHeaders ?? ([] as SchemaHeaderField[]);
+        return colHeaderData ?? ([] as SchemaHeaderField[]);
     }
     @computed get headerMargin() {
         return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin);
@@ -78,7 +78,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     }
     // numGroupColumns returns the number of columns
     @computed get numGroupColumns() {
-        return this.columnHeaders.length;
+        return this.colHeaderData.length;
     }
     // PanelWidth returns the size of the total available space the view occupies
     @computed get PanelWidth() {
@@ -117,7 +117,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     // (2) documentView gets unmounted as you remove it from the list
     @computed get Sections() {
         TraceMobx();
-        const columnHeaders = this.columnHeaders;
+        const columnHeaders = this.colHeaderData;
         // filter out the currently dragged docs from the child docs, since we will insert them later
         const docs = this.childDocs.filter(d => !DragManager.docsBeingDragged.includes(d));
         const sections = new Map<SchemaHeaderField, Doc[]>(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
@@ -149,9 +149,10 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     componentDidMount() {
         super.componentDidMount?.();
         document.addEventListener('pointerup', this.removeDocDragHighlight, true);
-        this._disposers.autoHeight = reaction(
-            () => this.layoutDoc._autoHeight,
-            autoHeight => autoHeight && this.props.setHeight?.(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), this.headerMargin + Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))))
+        this._disposers.layout_autoHeight = reaction(
+            () => this.layoutDoc._layout_autoHeight,
+            layout_autoHeight =>
+                layout_autoHeight && this.props.setHeight?.(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), this.headerMargin + Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))))
         );
     }
 
@@ -230,7 +231,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 PanelHeight={height}
                 styleProvider={this.styleProvider}
                 docViewPath={this.props.docViewPath}
-                fitWidth={this.props.childFitWidth}
+                layout_fitWidth={this.props.childLayoutFitWidth}
                 isContentActive={emptyFunction}
                 onKey={this.onKeyDown}
                 //TODO: change this from a prop to a parameter passed into a function
@@ -238,12 +239,12 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 isDocumentActive={this.isContentActive}
                 LayoutTemplate={this.props.childLayoutTemplate}
                 LayoutTemplateString={this.props.childLayoutString}
-                NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
-                NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeHeight(doc)) ? height : undefined}
+                NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childLayoutFitWidth?.(doc) || (doc._layout_fitWidth && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
+                NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childLayoutFitWidth?.(doc) || (doc._layout_fitWidth && !Doc.NativeHeight(doc)) ? height : undefined}
                 dontCenter={this.props.childIgnoreNativeSize ? 'xy' : undefined}
                 dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)}
                 rootSelected={this.rootSelected}
-                showTitle={this.props.childShowTitle}
+                layout_showTitle={this.props.childlayout_showTitle}
                 dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
                 onClick={this.onChildClickHandler}
                 onDoubleClick={this.onChildDoubleClickHandler}
@@ -280,10 +281,10 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     // if a note doc. Otherwise, returns the normal width (for graphs, images, etc...)
     getDocWidth(d: Doc) {
         const heading = !d[this.notetakingCategoryField] ? 'unset' : Field.toString(d[this.notetakingCategoryField] as Field);
-        const existingHeader = this.columnHeaders.find(sh => sh.heading === heading);
+        const existingHeader = this.colHeaderData.find(sh => sh.heading === heading);
         const existingWidth = existingHeader?.width ? existingHeader.width : 0;
         const maxWidth = existingWidth > 0 ? existingWidth * this.availableWidth : this.maxColWidth;
-        const width = d.fitWidth ? maxWidth : d[WidthSym]();
+        const width = d.layout_fitWidth ? maxWidth : d[WidthSym]();
         return Math.min(maxWidth - CollectionNoteTakingViewColumn.ColumnMargin, width < maxWidth ? width : maxWidth);
     }
 
@@ -293,14 +294,14 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
         const childDataDoc = !d.isTemplateDoc && !d.isTemplateForField ? undefined : this.props.DataDoc;
         const maxHeight = (lim => (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1));
-        const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[WidthSym]() : 0);
-        const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[HeightSym]() : 0);
+        const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[WidthSym]() : 0);
+        const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[HeightSym]() : 0);
         if (nw && nh) {
             const docWid = this.getDocWidth(d);
             return Math.min(maxHeight, (docWid * nh) / nw);
         }
         const childHeight = NumCast(childLayoutDoc._height);
-        const panelHeight = childLayoutDoc._fitWidth || this.props.childFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin;
+        const panelHeight = childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin;
         return Math.min(childHeight, maxHeight, panelHeight);
     }
 
@@ -318,7 +319,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         const n = headers.length;
         const curWidths = headers.reduce((sum, hdr) => sum + Math.abs(hdr.width), 0);
         const scaleFactor = 1 / curWidths;
-        this.dataDoc.columnHeaders = new List<SchemaHeaderField>(
+        this.dataDoc[this.fieldKey + '_columnHeaders'] = new List<SchemaHeaderField>(
             headers.map(h => {
                 h.setWidth(Math.abs(h.width) * scaleFactor);
                 return h;
@@ -352,7 +353,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
             });
             // we alter the pivot fields of the docs in case they are moved to a new column.
             const colIndex = this.getColumnFromXCoord(xCoord);
-            const colHeader = colIndex === undefined ? 'unset' : StrCast(this.columnHeaders[colIndex].heading);
+            const colHeader = colIndex === undefined ? 'unset' : StrCast(this.colHeaderData[colIndex].heading);
             DragManager.docsBeingDragged.forEach(d => (d[this.notetakingCategoryField] = colHeader));
             // used to notify sections to re-render
             this.docsDraggedRowCol.length = 0;
@@ -365,12 +366,12 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     // This function is used to know which document a column SHOULD be in while it is being dragged.
     getColumnFromXCoord = (xCoord: number): number | undefined => {
         let colIndex: number | undefined = undefined;
-        const numColumns = this.columnHeaders.length;
+        const numColumns = this.colHeaderData.length;
         const coords = [];
         let colStartXCoord = 0;
         for (let i = 0; i < numColumns; i++) {
             coords.push(colStartXCoord);
-            colStartXCoord += this.columnHeaders[i].width * this.availableWidth + this.DividerWidth;
+            colStartXCoord += this.colHeaderData[i].width * this.availableWidth + this.DividerWidth;
         }
         coords.push(this.PanelWidth);
         for (let i = 0; i < numColumns; i++) {
@@ -386,7 +387,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     getDocsFromXCoord = (xCoord: number): Doc[] => {
         const docsMatchingHeader: Doc[] = [];
         const colIndex = this.getColumnFromXCoord(xCoord);
-        const colHeader = colIndex === undefined ? 'unset' : StrCast(this.columnHeaders[colIndex].heading);
+        const colHeader = colIndex === undefined ? 'unset' : StrCast(this.colHeaderData[colIndex].heading);
         this.childDocs?.map(d => {
             if (d instanceof Promise) return;
             const sectionValue = (d[this.notetakingCategoryField] as object) ?? 'unset';
@@ -401,7 +402,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     @action
     onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
         const docView = fieldProps.DocumentView?.();
-        if (docView && (e.ctrlKey || docView.rootDoc._singleLine) && ['Enter'].includes(e.key)) {
+        if (docView && (e.ctrlKey || docView.rootDoc._createDocOnCR) && ['Enter'].includes(e.key)) {
             e.stopPropagation?.();
             const newDoc = Doc.MakeCopy(docView.rootDoc, true);
             Doc.GetProto(newDoc).text = undefined;
@@ -436,10 +437,10 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                     }
                 }
             }
-        } else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
-            const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _fitWidth: true, title: 'dropped annotation' });
+        } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
+            const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' });
             this.props.addDocument?.(source);
-            de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { linkRelationship: 'doc annotation' }); // TODODO this is where in text links get passed
+            de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed
             e.stopPropagation();
         } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
         return false;
@@ -468,7 +469,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                     this.onPointerMove(true, e.clientX, e.clientY);
                     docus?.map((doc: Doc) => this.addDocument(doc));
                     const newDoc = this.childDocs.lastElement();
-                    const colHeader = colInd === undefined ? 'unset' : StrCast(this.columnHeaders[colInd].heading);
+                    const colHeader = colInd === undefined ? 'unset' : StrCast(this.colHeaderData[colInd].heading);
                     newDoc[this.notetakingCategoryField] = colHeader;
                     const docs = this.childDocList;
                     if (docs && targInd !== -1) {
@@ -502,7 +503,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                         this.refList.push(ref);
                         this.observer = new _global.ResizeObserver(
                             action((entries: any) => {
-                                if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
+                                if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
                                     const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))));
                                     if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) {
                                         this.props.setHeight?.(height);
@@ -516,7 +517,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 select={this.props.select}
                 addDocument={this.addDocument}
                 chromeHidden={this.chromeHidden}
-                columnHeaders={this.columnHeaders}
+                colHeaderData={this.colHeaderData}
                 Document={this.props.Document}
                 DataDoc={this.props.DataDoc}
                 resizeColumns={this.resizeColumns}
@@ -524,6 +525,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 numGroupColumns={this.numGroupColumns}
                 gridGap={this.gridGap}
                 pivotField={this.notetakingCategoryField}
+                fieldKey={this.fieldKey}
                 dividerWidth={this.DividerWidth}
                 maxColWidth={this.maxColWidth}
                 availableWidth={this.availableWidth}
@@ -546,15 +548,15 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     @undoBatch
     @action
     addGroup = (value: string) => {
-        if (this.columnHeaders) {
-            for (const header of this.columnHeaders) {
+        if (this.colHeaderData) {
+            for (const header of this.colHeaderData) {
                 if (header.heading === value) {
                     alert('You cannot use an existing column name. Please try a new column name');
                     return value;
                 }
             }
         }
-        const columnHeaders = Array.from(Cast(this.props.Document.columnHeaders, listSpec(SchemaHeaderField), null));
+        const columnHeaders = Array.from(Cast(this.dataDoc[this.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null));
         const newColWidth = 1 / (this.numGroupColumns + 1);
         columnHeaders.push(new SchemaHeaderField(value, undefined, undefined, newColWidth));
         value && this.resizeColumns(columnHeaders);
@@ -566,7 +568,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         if (!e.isPropagationStopped()) {
             const subItems: ContextMenuProps[] = [];
             subItems.push({ description: `${this.layoutDoc._columnsFill ? 'Variable Size' : 'Autosize'} Column`, event: () => (this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill), icon: 'plus' });
-            subItems.push({ description: `${this.layoutDoc._autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight), icon: 'plus' });
+            subItems.push({ description: `${this.layoutDoc._layout_autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight), icon: 'plus' });
             subItems.push({ description: 'Clear All', event: () => (this.dataDoc.data = new List([])), icon: 'times' });
             ContextMenu.Instance.addItem({ description: 'Options...', subitems: subItems, icon: 'eye' });
         }
@@ -576,8 +578,8 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     @action
     setColumnStartXCoords = (movementXScreen: number, colIndex: number) => {
         const movementX = this.props.ScreenToLocalTransform().transformDirection(movementXScreen, 0)[0];
-        const leftHeader = this.columnHeaders[colIndex];
-        const rightHeader = this.columnHeaders[colIndex + 1];
+        const leftHeader = this.colHeaderData[colIndex];
+        const rightHeader = this.colHeaderData[colIndex + 1];
         leftHeader.setWidth(leftHeader.width + movementX / this.availableWidth);
         rightHeader.setWidth(rightHeader.width - movementX / this.availableWidth);
     };
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index 28bdd0cb9..63becac1e 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -29,8 +29,9 @@ interface CSVFieldColumnProps {
     docList: Doc[];
     heading: string;
     pivotField: string;
+    fieldKey: string | undefined;
     chromeHidden?: boolean;
-    columnHeaders: SchemaHeaderField[] | undefined;
+    colHeaderData: SchemaHeaderField[] | undefined;
     headingObject: SchemaHeaderField | undefined;
     yMargin: number;
     numGroupColumns: number;
@@ -61,9 +62,9 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
 
     // columnWidth returns the width of a column in absolute pixels
     @computed get columnWidth() {
-        if (!this.props.columnHeaders || !this.props.headingObject || this.props.columnHeaders.length === 1) return '100%';
-        const i = this.props.columnHeaders.indexOf(this.props.headingObject);
-        return this.props.columnHeaders[i].width * 100 + '%';
+        if (!this.props.colHeaderData || !this.props.headingObject || this.props.colHeaderData.length === 1) return '100%';
+        const i = this.props.colHeaderData.indexOf(this.props.headingObject);
+        return this.props.colHeaderData[i].width * 100 + '%';
     }
 
     private dropDisposer?: DragManager.DragDropDisposer;
@@ -105,7 +106,7 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
     headingChanged = (value: string, shiftDown?: boolean) => {
         const castedValue = this.getValue(value);
         if (castedValue) {
-            if (this.props.columnHeaders?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) {
+            if (this.props.colHeaderData?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) {
                 return false;
             }
             this.props.docList.forEach(d => (d[this.props.pivotField] = castedValue));
@@ -127,7 +128,7 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
     addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
         if (!value && !forceEmptyNote) return false;
         const key = this.props.pivotField;
-        const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _fitWidth: true, title: value, _autoHeight: true });
+        const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _layout_fitWidth: true, title: value, _layout_autoHeight: true });
         const colValue = this.getValue(this.props.heading);
         newDoc[key] = colValue;
         FormattedTextBox.SelectOnLoad = newDoc[Id];
@@ -141,11 +142,11 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
     @undoBatch
     @action
     deleteColumn = () => {
-        const columnHeaders = Array.from(Cast(this.props.Document.columnHeaders, listSpec(SchemaHeaderField), null));
+        const colHdrData = Array.from(Cast(this.props.Document[this.props.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null));
         if (this.props.headingObject) {
             this.props.docList.forEach(d => (d[this.props.pivotField] = undefined));
-            columnHeaders.splice(columnHeaders.indexOf(this.props.headingObject), 1);
-            this.props.resizeColumns(columnHeaders);
+            colHdrData.splice(colHdrData.indexOf(this.props.headingObject), 1);
+            this.props.resizeColumns(colHdrData);
         }
     };
 
@@ -211,7 +212,7 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
         !Doc.UserDoc().noviceMode && ContextMenu.Instance.addItem({ description: 'Containers ...', subitems: layoutItems, icon: 'eye' });
         ContextMenu.Instance.setDefaultItem('::', (name: string): void => {
             Doc.GetProto(this.props.Document)[name] = '';
-            const created = Docs.Create.TextDocument('', { title: name, _width: 250, _autoHeight: true });
+            const created = Docs.Create.TextDocument('', { title: name, _width: 250, _layout_autoHeight: true });
             if (created) {
                 if (this.props.Document.isTemplateDoc) {
                     Doc.MakeMetadataFieldTemplate(created, this.props.Document);
@@ -243,7 +244,7 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
                     style={{ background: evContents !== `No Value` ? this._color : 'inherit' }}>
                     <EditableView GetValue={() => evContents} isEditingCallback={isEditing => isEditing && this.props.select(false)} SetValue={this.headingChanged} contents={evContents} oneLine={true} />
                 </div>
-                {(this.props.columnHeaders?.length ?? 0) > 1 && (
+                {(this.props.colHeaderData?.length ?? 0) > 1 && (
                     <button className="collectionNoteTakingView-sectionDelete" onClick={this.deleteColumn}>
                         <FontAwesomeIcon icon="trash" size="lg" />
                     </button>
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 5b96a8682..ea0fbbc54 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -82,8 +82,8 @@ export class CollectionPileView extends CollectionSubView() {
             this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize);
             this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize);
             DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false);
-            this.layoutDoc._panX = 0;
-            this.layoutDoc._panY = -10;
+            this.layoutDoc._freeform_panX = 0;
+            this.layoutDoc._freeform_panY = -10;
             this.props.Document._pileLayoutEngine = computePassLayout.name;
         } else {
             const defaultSize = NumCast(this.rootDoc._starburstDiameter, 500);
@@ -91,7 +91,7 @@ export class CollectionPileView extends CollectionSubView() {
             this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - defaultSize / 2;
             this.layoutDoc._starburstPileWidth = this.layoutDoc[WidthSym]();
             this.layoutDoc._starburstPileHeight = this.layoutDoc[HeightSym]();
-            this.layoutDoc._panX = this.layoutDoc._panY = 0;
+            this.layoutDoc._freeform_panX = this.layoutDoc._freeform_panY = 0;
             this.layoutDoc._width = this.layoutDoc._height = defaultSize;
             this.props.Document._pileLayoutEngine = computeStarburstLayout.name;
         }
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 22a575989..6b4c8a3e9 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -24,7 +24,7 @@ import { undoBatch, UndoManager } from '../../util/UndoManager';
 import { AudioWaveform } from '../AudioWaveform';
 import { CollectionSubView } from '../collections/CollectionSubView';
 import { LightboxView } from '../LightboxView';
-import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView';
+import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../nodes/DocumentView';
 import { LabelBox } from '../nodes/LabelBox';
 import { VideoBox } from '../nodes/VideoBox';
 import './CollectionStackedTimeline.scss';
@@ -41,7 +41,9 @@ export type CollectionStackedTimelineProps = {
     mediaPath: string;
     dictationKey: string;
     rawDuration: number;
+    dataFieldKey: string;
     fieldKey: string;
+    thumbnails?: () => string[];
 };
 
 // trimming state: shows full clip, current trim bounds, or not trimming
@@ -80,6 +82,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
     get minTrimLength() {
         return Math.max(this._timeline?.getBoundingClientRect() ? 0.05 * this.clipDuration : 0, 0.5);
     }
+    @computed get thumbnails() {
+        return this.props.thumbnails?.();
+    }
 
     @computed get trimStart() {
         return this.IsTrimming !== TrimScope.None ? this._trimStart : this.clipStart;
@@ -102,7 +107,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
     }
 
     @computed get currentTime() {
-        return NumCast(this.layoutDoc._currentTimecode);
+        return NumCast(this.layoutDoc._layout_currentTimecode);
     }
 
     @computed get zoomFactor() {
@@ -219,12 +224,12 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
     };
 
     getLinkData(l: Doc) {
-        let la1 = l.anchor1 as Doc;
-        let la2 = l.anchor2 as Doc;
+        let la1 = l.link_anchor_1 as Doc;
+        let la2 = l.link_anchor_2 as Doc;
         const linkTime = NumCast(la2[this.props.startTag], NumCast(la1[this.props.startTag]));
         if (Doc.AreProtosEqual(la1, this.dataDoc)) {
-            la1 = l.anchor2 as Doc;
-            la2 = l.anchor1 as Doc;
+            la1 = l.link_anchor_2 as Doc;
+            la2 = l.link_anchor_1 as Doc;
         }
         return { la1, la2, linkTime };
     }
@@ -292,10 +297,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
         const clientX = e.clientX;
         if (rect) {
             this._hoverTime = this.toTimeline(clientX - rect.x, rect.width);
-            if (this.dataDoc.thumbnails) {
+            if (this.thumbnails) {
                 const nearest = Math.floor((this._hoverTime / this.props.rawDuration) * VideoBox.numThumbnails);
-                const thumbnails = StrListCast(this.dataDoc.thumbnails);
-                const imgField = thumbnails?.length > 0 ? new ImageField(thumbnails[nearest]) : undefined;
+                const imgField = this.thumbnails.length > 0 ? new ImageField(this.thumbnails[nearest]) : undefined;
                 this._thumbnail = imgField?.url?.href ? imgField.url.href.replace('.png', '_m.png') : undefined;
             }
         }
@@ -401,11 +405,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                 title: ComputedField.MakeFunction(`self["${endTag}"] ? "#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"]) : "#" + formatToTime(self["${startTag}"])`) as any,
                 _minFontSize: 12,
                 _maxFontSize: 24,
-                _singleLine: true,
                 _stayInCollection: true,
                 backgroundColor: 'rgba(128, 128, 128, 0.5)',
-                useLinkSmallAnchor: true,
-                hideLinkButton: true,
+                layout_hideLinkButton: true,
                 onClick: FollowLinkScript(),
                 annotationOn: rootDoc,
                 _timelineLabel: true,
@@ -434,7 +436,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                 this.scrollToTime(seekTimeInSeconds);
             }
         } else {
-            if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) && endTime > NumCast(this.layoutDoc._currentTimecode)) {
+            if (seekTimeInSeconds < NumCast(this.layoutDoc._layout_currentTimecode) && endTime > NumCast(this.layoutDoc._layout_currentTimecode)) {
                 if (!this.layoutDoc.autoPlayAnchors && this.props.playing()) {
                     this.props.Pause();
                 } else {
@@ -455,7 +457,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
         }
         const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.05;
         const endTime = this.anchorEnd(anchorDoc);
-        if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) + 1e-4 && endTime > NumCast(this.layoutDoc._currentTimecode) - 1e-4) {
+        if (seekTimeInSeconds < NumCast(this.layoutDoc._layout_currentTimecode) + 1e-4 && endTime > NumCast(this.layoutDoc._layout_currentTimecode) - 1e-4) {
             if (this.props.playing()) this.props.Pause();
             else if (this.layoutDoc.autoPlayAnchors) this.props.Play();
             else if (!this.layoutDoc.autoPlayAnchors) {
@@ -596,6 +598,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                         {!this.props.PanelHeight() ? null : (
                             <AudioWaveform
                                 rawDuration={this.props.rawDuration}
+                                fieldKey={this.props.dataFieldKey}
                                 duration={this.clipDuration}
                                 mediaPath={this.props.mediaPath}
                                 layoutDoc={this.layoutDoc}
@@ -661,6 +664,8 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
 
 interface StackedTimelineAnchorProps {
     mark: Doc;
+    whenChildContentsActiveChanged: (isActive: boolean) => void;
+    addDocTab: (doc: Doc, where: OpenWhere) => boolean;
     rangeClickScript: () => ScriptField;
     rangePlayScript: () => ScriptField;
     left: number;
@@ -709,7 +714,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
             () => this.props.currentTimecode(),
             time => {
                 const dictationDoc = Cast(this.props.layoutDoc['data-dictation'], Doc, null);
-                const isDictation = dictationDoc && LinkManager.Links(this.props.mark).some(link => Cast(link.anchor1, Doc, null)?.annotationOn === dictationDoc);
+                const isDictation = dictationDoc && LinkManager.Links(this.props.mark).some(link => Cast(link.link_anchor_1, Doc, null)?.annotationOn === dictationDoc);
                 if (
                     !LightboxView.LightboxDoc &&
                     // bcz: when should links be followed?  we don't want to move away from the video to follow a link but we can open it in a sidebar/etc.  But we don't know that upfront.
@@ -808,11 +813,9 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                     isDocumentActive={this.props.isDocumentActive}
                     PanelWidth={width}
                     PanelHeight={height}
-                    fitWidth={returnTrue}
+                    layout_fitWidth={returnTrue}
                     ScreenToLocalTransform={screenXf}
-                    addDocTab={returnFalse}
                     pinToPres={emptyFunction}
-                    whenChildContentsActiveChanged={emptyFunction}
                     focus={focusFunc}
                     isContentActive={returnFalse}
                     searchFilterDocs={returnEmptyDoclist}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index eedf639aa..404ca5d65 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -49,7 +49,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     // Not sure what a pivot field is. Seems like we cause reaction in MobX get rid of it once we exit this view
     _pivotFieldDisposer?: IReactionDisposer;
     // Seems like we cause reaction in MobX get rid of our height once we exit this view
-    _autoHeightDisposer?: IReactionDisposer;
+    _layout_autoHeightDisposer?: IReactionDisposer;
     // keeping track of documents. Updated on internal and external drops. What's the difference?
     _docXfs: { height: () => number; width: () => number; stackedDocTransform: () => Transform }[] = [];
     // Doesn't look like this field is being used anywhere. Obsolete?
@@ -65,8 +65,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden);
     }
     // it looks like this gets the column headers that Mehek was showing just now
-    @computed get columnHeaders() {
-        return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null);
+    @computed get colHeaderData() {
+        return Cast(this.layoutDoc['_' + this.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null);
     }
     // Still not sure what a pivot is, but it appears that we can actually filter docs somehow?
     @computed get pivotField() {
@@ -116,10 +116,10 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     constructor(props: any) {
         super(props);
 
-        if (this.columnHeaders === undefined) {
+        if (this.colHeaderData === undefined) {
             // TODO: what is a layout doc? Is it literally how this document is supposed to be layed out?
             // here we're making an empty list of column headers (again, what Mehek showed us)
-            this.layoutDoc._columnHeaders = new List<SchemaHeaderField>();
+            this.layoutDoc['_' + this.fieldKey + '_columnHeaders'] = new List<SchemaHeaderField>();
         }
     }
 
@@ -154,14 +154,14 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     //TODO: this seems important
     get Sections() {
         // appears that pivot field IS actually for sorting
-        if (!this.pivotField || this.columnHeaders instanceof Promise) return new Map<SchemaHeaderField, Doc[]>();
+        if (!this.pivotField || this.colHeaderData instanceof Promise) return new Map<SchemaHeaderField, Doc[]>();
 
-        if (this.columnHeaders === undefined) {
-            setTimeout(() => (this.layoutDoc._columnHeaders = new List<SchemaHeaderField>()), 0);
+        if (this.colHeaderData === undefined) {
+            setTimeout(() => (this.layoutDoc['_' + this.fieldKey + '_columnHeaders'] = new List<SchemaHeaderField>()), 0);
             return new Map<SchemaHeaderField, Doc[]>();
         }
-        const columnHeaders = Array.from(this.columnHeaders);
-        const fields = new Map<SchemaHeaderField, Doc[]>(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
+        const colHeaderData = Array.from(this.colHeaderData);
+        const fields = new Map<SchemaHeaderField, Doc[]>(colHeaderData.map(sh => [sh, []] as [SchemaHeaderField, []]));
         let changed = false;
         this.filteredChildren.map(d => {
             const sectionValue = (d[this.pivotField] ? d[this.pivotField] : `NO ${this.pivotField.toUpperCase()} VALUE`) as object;
@@ -170,13 +170,13 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             const castedSectionValue = !isNaN(parsed) ? parsed : sectionValue;
 
             // look for if header exists already
-            const existingHeader = columnHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`));
+            const existingHeader = colHeaderData.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`));
             if (existingHeader) {
                 fields.get(existingHeader)!.push(d);
             } else {
                 const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`);
                 fields.set(newSchemaHeader, [d]);
-                columnHeaders.push(newSchemaHeader);
+                colHeaderData.push(newSchemaHeader);
                 changed = true;
             }
         });
@@ -187,13 +187,13 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 .filter(key => !fields.get(key)!.length)
                 .map(header => {
                     fields.delete(header);
-                    columnHeaders.splice(columnHeaders.indexOf(header), 1);
+                    colHeaderData.splice(colHeaderData.indexOf(header), 1);
                     changed = true;
                 });
         }
         changed &&
             setTimeout(
-                action(() => this.columnHeaders?.splice(0, this.columnHeaders.length, ...columnHeaders)),
+                action(() => this.colHeaderData?.splice(0, this.colHeaderData.length, ...colHeaderData)),
                 0
             );
         return fields;
@@ -206,12 +206,12 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         // reset section headers when a new filter is inputted
         this._pivotFieldDisposer = reaction(
             () => this.pivotField,
-            () => (this.layoutDoc._columnHeaders = new List())
+            () => (this.layoutDoc['_' + this.fieldKey + '_columnHeaders'] = new List())
         );
-        this._autoHeightDisposer = reaction(
-            () => this.layoutDoc._autoHeight,
-            autoHeight =>
-                autoHeight &&
+        this._layout_autoHeightDisposer = reaction(
+            () => this.layoutDoc._layout_autoHeight,
+            layout_autoHeight =>
+                layout_autoHeight &&
                 this.props.setHeight?.(
                     Math.min(
                         NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
@@ -224,7 +224,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     componentWillUnmount() {
         super.componentWillUnmount();
         this._pivotFieldDisposer?.();
-        this._autoHeightDisposer?.();
+        this._layout_autoHeightDisposer?.();
     }
 
     isAnyChildContentActive = () => this.props.isAnyChildContentActive();
@@ -282,12 +282,12 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         if (docView && ['Enter'].includes(e.key) && e.ctrlKey) {
             e.stopPropagation?.();
             const below = !e.altKey && e.key !== 'Tab';
-            const layoutKey = StrCast(docView.LayoutFieldKey);
+            const layout_fieldKey = StrCast(docView.LayoutFieldKey);
             const newDoc = Doc.MakeCopy(docView.rootDoc, true);
             const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)];
             newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
-            if (layoutKey !== 'layout' && docView.rootDoc[layoutKey] instanceof Doc) {
-                newDoc[layoutKey] = docView.rootDoc[layoutKey];
+            if (layout_fieldKey !== 'layout' && docView.rootDoc[layout_fieldKey] instanceof Doc) {
+                newDoc[layout_fieldKey] = docView.rootDoc[layout_fieldKey];
             }
             Doc.GetProto(newDoc).text = undefined;
             FormattedTextBox.SelectOnLoad = newDoc[Id];
@@ -327,19 +327,19 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 pointerEvents={this.props.DocumentView?.().props.onClick?.() ? returnNone : undefined} // if the stack has an onClick, then we don't want the contents to be interactive (see CollectionPileView)
                 styleProvider={this.styleProvider}
                 docViewPath={this.props.docViewPath}
-                fitWidth={this.props.childFitWidth}
+                layout_fitWidth={this.props.childLayoutFitWidth}
                 isContentActive={doc.onClick ? this.isChildButtonContentActive : this.isChildContentActive}
                 onKey={this.onKeyDown}
                 onBrowseClick={this.props.onBrowseClick}
                 isDocumentActive={this.isContentActive}
                 LayoutTemplate={this.props.childLayoutTemplate}
                 LayoutTemplateString={this.props.childLayoutString}
-                NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
-                NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeHeight(doc)) ? height : undefined}
+                NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childLayoutFitWidth?.(doc) || (doc._layout_fitWidth && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
+                NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childLayoutFitWidth?.(doc) || (doc._layout_fitWidth && !Doc.NativeHeight(doc)) ? height : undefined}
                 dontCenter={this.props.childIgnoreNativeSize ? 'xy' : undefined}
-                dontRegisterView={BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)} // used to be true if DataDoc existed, but template textboxes won't autoHeight resize if dontRegisterView is set, but they need to.
+                dontRegisterView={BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)} // used to be true if DataDoc existed, but template textboxes won't layout_autoHeight resize if dontRegisterView is set, but they need to.
                 rootSelected={this.rootSelected}
-                showTitle={this.props.childShowTitle}
+                layout_showTitle={this.props.childlayout_showTitle}
                 dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
                 onClick={this.onChildClickHandler}
                 onDoubleClick={this.onChildDoubleClickHandler}
@@ -376,7 +376,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         if (!d) return 0;
         const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
         const maxWidth = this.columnWidth / this.numGroupColumns;
-        if (!this.layoutDoc._columnsFill && !(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d))) {
+        if (!this.layoutDoc._columnsFill && !(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d))) {
             return Math.min(d[WidthSym](), maxWidth);
         }
         return maxWidth;
@@ -386,15 +386,15 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
         const childDataDoc = !d.isTemplateDoc && !d.isTemplateForField ? undefined : this.props.DataDoc;
         const maxHeight = (lim => (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1));
-        const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[WidthSym]() : 0);
-        const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[HeightSym]() : 0);
+        const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[WidthSym]() : 0);
+        const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[HeightSym]() : 0);
         if (nw && nh) {
             const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
             const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid);
             return Math.min(maxHeight, (docWid * nh) / nw);
         }
         const childHeight = NumCast(childLayoutDoc._height);
-        const panelHeight = childLayoutDoc._fitWidth || this.props.childFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin;
+        const panelHeight = childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin;
         return Math.min(childHeight, maxHeight, panelHeight);
     }
 
@@ -460,10 +460,10 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                     docs.splice(insertInd - offset, 0, ...newDocs);
                 }
             }
-        } else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
-            const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _fitWidth: true, title: 'dropped annotation' });
+        } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
+            const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' });
             this.props.addDocument?.(source);
-            de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { linkRelationship: 'doc annotation' }); // TODODO this is where in text links get passed
+            de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed
             e.stopPropagation();
         } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
         return false;
@@ -526,7 +526,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         this.refList.push(ref);
                         this.observer = new _global.ResizeObserver(
                             action((entries: any) => {
-                                if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
+                                if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
                                     const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))));
                                     if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) {
                                         this.props.setHeight?.(height);
@@ -539,7 +539,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 }}
                 addDocument={this.addDocument}
                 chromeHidden={this.chromeHidden}
-                columnHeaders={this.columnHeaders}
+                colHeaderData={this.colHeaderData}
                 Document={this.props.Document}
                 DataDoc={this.props.DataDoc}
                 renderChildren={this.children}
@@ -581,7 +581,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         this.refList.push(ref);
                         this.observer = new _global.ResizeObserver(
                             action((entries: any) => {
-                                if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
+                                if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
                                     const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0);
                                     this.props.setHeight?.(this.headerMargin + height);
                                 }
@@ -608,9 +608,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     /// add a new group category (column) to the active set of note categories.  (e.g., if the pivot field is 'transportation', groups might be 'car', 'plane', 'bike', etc)
     @action
     addGroup = (value: string) => {
-        if (value && this.columnHeaders) {
+        if (value && this.colHeaderData) {
             const schemaHdrField = new SchemaHeaderField(value);
-            this.columnHeaders.push(schemaHdrField);
+            this.colHeaderData.push(schemaHdrField);
             return true;
         }
         return false;
@@ -630,7 +630,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             const options = cm.findByDescription('Options...');
             const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : [];
             optionItems.push({ description: `${this.layoutDoc._columnsFill ? 'Variable Size' : 'Autosize'} Column`, event: () => (this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill), icon: 'plus' });
-            optionItems.push({ description: `${this.layoutDoc._autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight), icon: 'plus' });
+            optionItems.push({ description: `${this.layoutDoc._layout_autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight), icon: 'plus' });
             optionItems.push({ description: 'Clear All', event: () => (this.dataDoc[this.fieldKey ?? 'data'] = new List([])), icon: 'times' });
             !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' });
         }
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index d62c4dc62..243550c0b 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -34,7 +34,7 @@ interface CSVFieldColumnProps {
     heading: string;
     pivotField: string;
     chromeHidden?: boolean;
-    columnHeaders: SchemaHeaderField[] | undefined;
+    colHeaderData: SchemaHeaderField[] | undefined;
     headingObject: SchemaHeaderField | undefined;
     yMargin: number;
     columnWidth: number;
@@ -93,7 +93,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     @undoBatch
     columnDrop = action((e: Event, de: DragManager.DropEvent) => {
         const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) };
-        drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false));
+        this.props.pivotField && drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false));
     });
     getValue = (value: string): any => {
         const parsed = parseInt(value);
@@ -107,7 +107,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     headingChanged = (value: string, shiftDown?: boolean) => {
         const castedValue = this.getValue(value);
         if (castedValue) {
-            if (this.props.columnHeaders?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) {
+            if (this.props.colHeaderData?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) {
                 return false;
             }
             this.props.docList.forEach(d => (d[this.props.pivotField] = castedValue));
@@ -134,7 +134,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
         if (!value && !forceEmptyNote) return false;
         const key = this.props.pivotField;
-        const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _fitWidth: true, title: value, _autoHeight: true });
+        const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _layout_fitWidth: true, title: value, _layout_autoHeight: true });
         newDoc[key] = this.getValue(this.props.heading);
         const maxHeading = this.props.docList.reduce((maxHeading, doc) => (NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading), 0);
         const heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3;
@@ -147,9 +147,9 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     @action
     deleteColumn = () => {
         this.props.docList.forEach(d => (d[this.props.pivotField] = undefined));
-        if (this.props.columnHeaders && this.props.headingObject) {
-            const index = this.props.columnHeaders.indexOf(this.props.headingObject);
-            this.props.columnHeaders.splice(index, 1);
+        if (this.props.colHeaderData && this.props.headingObject) {
+            const index = this.props.colHeaderData.indexOf(this.props.headingObject);
+            this.props.colHeaderData.splice(index, 1);
         }
     };
 
@@ -163,15 +163,15 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     //TODO: I think this is where I'm supposed to edit stuff
     startDrag = (e: PointerEvent, down: number[], delta: number[]) => {
-        // is MakeAlias a way to make a copy of a doc without rendering it?
-        const alias = Doc.MakeAlias(this.props.Document);
-        alias._width = this.props.columnWidth / (this.props.columnHeaders?.length || 1);
-        alias._pivotField = undefined;
+        // is MakeEmbedding a way to make a copy of a doc without rendering it?
+        const embedding = Doc.MakeEmbedding(this.props.Document);
+        embedding._width = this.props.columnWidth / (this.props.colHeaderData?.length || 1);
+        embedding._pivotField = undefined;
         let value = this.getValue(this._heading);
         value = typeof value === 'string' ? `"${value}"` : value;
-        alias.viewSpecScript = ScriptField.MakeFunction(`doc.${this.props.pivotField} === ${value}`, { doc: Doc.name });
-        if (alias.viewSpecScript) {
-            DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY);
+        embedding.viewSpecScript = ScriptField.MakeFunction(`doc.${this.props.pivotField} === ${value}`, { doc: Doc.name });
+        if (embedding.viewSpecScript) {
+            DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([embedding]), e.clientX, e.clientY);
             return true;
         }
         return false;
@@ -266,7 +266,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Containers ...', subitems: layoutItems, icon: 'eye' });
         ContextMenu.Instance.setDefaultItem('::', (name: string): void => {
             Doc.GetProto(this.props.Document)[name] = '';
-            const created = Docs.Create.TextDocument('', { title: name, _width: 250, _autoHeight: true });
+            const created = Docs.Create.TextDocument('', { title: name, _width: 250, _layout_autoHeight: true });
             if (created) {
                 if (this.props.Document.isTemplateDoc) {
                     Doc.MakeMetadataFieldTemplate(created, this.props.Document);
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 5b9453666..008de1944 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -129,7 +129,7 @@ export function CollectionSubView<X>(moreProps?: X) {
                     notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, docRangeFilters, this.props.Document).length > 0;
                     const fieldKey = Doc.LayoutFieldKey(d);
                     const annos = !Field.toString(Doc.LayoutField(d) as Field).includes(CollectionView.name);
-                    const data = d[annos ? fieldKey + '-annotations' : fieldKey];
+                    const data = d[annos ? fieldKey + '_annotations' : fieldKey];
                     if (data !== undefined) {
                         let subDocs = DocListCast(data);
                         if (subDocs.length > 0) {
@@ -141,7 +141,7 @@ export function CollectionSubView<X>(moreProps?: X) {
                                     const fieldKey = Doc.LayoutFieldKey(t);
                                     const annos = !Field.toString(Doc.LayoutField(t) as Field).includes(CollectionView.name);
                                     notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], childDocFilters, docRangeFilters, d).length));
-                                    DocListCast(t[annos ? fieldKey + '-annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc));
+                                    DocListCast(t[annos ? fieldKey + '_annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc));
                                 });
                                 subDocs = newarray;
                             }
@@ -188,9 +188,9 @@ export function CollectionSubView<X>(moreProps?: X) {
 
         protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, targetAction: dropActionType) {
             if (de.complete.docDragData) {
-                // if targetDropAction is, say 'alias', but we're just dragging within a collection, we want to ignore the targetAction.
+                // if targetDropAction is, say 'embed', but we're just dragging within a collection, we want to ignore the targetAction.
                 // otherwise, the targetAction should become the actual action (which can still be overridden by the userDropAction -eg, shift/ctrl keys)
-                if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.context === this.props.Document && this.childDocs.includes(d))) {
+                if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.props.Document && this.childDocs.includes(d))) {
                     de.complete.docDragData.dropAction = targetAction;
                 }
                 e.stopPropagation();
@@ -282,7 +282,7 @@ export function CollectionSubView<X>(moreProps?: X) {
                             addDocument(Docs.Create.WebDocument(href, { ...options, title: href }));
                         }
                     } else if (text) {
-                        addDocument(Docs.Create.TextDocument(text, { ...options, _showTitle: StrCast(Doc.UserDoc().showTitle), _width: 100, _height: 25 }));
+                        addDocument(Docs.Create.TextDocument(text, { ...options, _layout_showTitle: StrCast(Doc.UserDoc().layout_showTitle), _width: 100, _height: 25 }));
                     }
                     return;
                 }
@@ -375,7 +375,7 @@ export function CollectionSubView<X>(moreProps?: X) {
                         _width: 400,
                         _height: 512,
                         _nativeWidth: 850,
-                        useCors: true,
+                        data_useCors: true,
                     })
                 );
                 return;
@@ -417,7 +417,7 @@ export function CollectionSubView<X>(moreProps?: X) {
                                         proto._height = 20;
                                         return proto;
                                     }),
-                                    { _width: 150, _height: 600, title: 'across', backgroundColor: 'white', _singleLine: true }
+                                    { _width: 150, _height: 600, title: 'across', backgroundColor: 'white', _createDocOnCR: true }
                                 )
                             );
                         });
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 3cdb460a3..6135154c3 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -35,7 +35,7 @@ export class CollectionTimeView extends CollectionSubView() {
     async componentDidMount() {
         this.props.setContentView?.(this);
         //const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.rootDoc.type), "");
-        ///const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; useRightSplit(alias, shiftKey); ";
+        ///const childText = "const embedding = getEmbedding(self); switchView(embedding, detailView); embedding.dropAction='embed'; useRightSplit(embedding, shiftKey); ";
         runInAction(() => {
             this._childClickedScript = ScriptField.MakeScript('openInLightbox(self)', { this: Doc.name });
             this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' });
@@ -55,10 +55,10 @@ export class CollectionTimeView extends CollectionSubView() {
 
         if (addAsAnnotation) {
             // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered
-            if (Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), null) !== undefined) {
-                Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), []).push(anchor);
+            if (Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) {
+                Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), []).push(anchor);
             } else {
-                this.dataDoc[this.props.fieldKey + '-annotations'] = new List<Doc>([anchor]);
+                this.dataDoc[this.props.fieldKey + '_annotations'] = new List<Doc>([anchor]);
             }
         }
         return anchor;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index f774781ab..095e34c39 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -104,7 +104,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     componentDidMount() {
         //this.props.setContentView?.(this);
         this._disposers.autoheight = reaction(
-            () => this.rootDoc.autoHeight,
+            () => this.rootDoc.layout_autoHeight,
             auto => auto && this.computeHeight(),
             { fireImmediately: true }
         );
@@ -114,25 +114,25 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
         if (!this._isDisposing) {
             const titleHeight = !this._titleRef ? this.marginTop() : Number(getComputedStyle(this._titleRef).height.replace('px', ''));
             const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot()) + 6;
-            this.layoutDoc._autoHeightMargins = bodyHeight;
+            this.layoutDoc._layout_autoHeightMargins = bodyHeight;
             !this.props.dontRegisterView && this.props.setHeight?.(bodyHeight + titleHeight);
         }
     };
     unobserveHeight = (ref: any) => {
         this.refList.delete(ref);
-        this.rootDoc.autoHeight && this.computeHeight();
+        this.rootDoc.layout_autoHeight && this.computeHeight();
     };
     observeHeight = (ref: any) => {
         if (ref) {
             this.refList.add(ref);
             this.observer = new _global.ResizeObserver(
                 action((entries: any) => {
-                    if (this.rootDoc.autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) {
+                    if (this.rootDoc.layout_autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) {
                         this.computeHeight();
                     }
                 })
             );
-            this.rootDoc.autoHeight && this.computeHeight();
+            this.rootDoc.layout_autoHeight && this.computeHeight();
             this.observer.observe(ref);
         }
     };
@@ -144,7 +144,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
         const dragData = de.complete.docDragData;
         if (dragData) {
-            const isInTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.props.Document) || dragData.draggedDocuments.some(d => d.context === this.doc && this.childDocs.includes(d));
+            const isInTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.props.Document) || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d));
             dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? 'same' : dragData.dropAction;
         }
     };
@@ -176,7 +176,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
         const doAddDoc = (doc: Doc | Doc[]) =>
             (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => {
                 const res = flg && Doc.AddDocToList(this.doc[DataSym], this.props.fieldKey, doc, relativeTo, before);
-                res && (doc.context = this.props.Document);
+                res && (doc.embedContainer = this.props.Document);
                 return res;
             }, true);
         if (this.doc.resolvedDataDoc instanceof Promise) return false;
@@ -234,7 +234,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 isContentActive={this.isContentActive}
                 isDocumentActive={this.isContentActive}
                 rootSelected={returnTrue}
-                forceAutoHeight={true} // needed to make the title resize even if the rest of the tree view is not autoHeight
+                forceAutoHeight={true} // needed to make the title resize even if the rest of the tree view is not layout_autoHeight
                 PanelWidth={this.documentTitleWidth}
                 PanelHeight={this.documentTitleHeight}
                 NativeDimScaling={returnOne}
@@ -369,15 +369,15 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     marginTop = () => NumCast(this.doc._yMargin);
     marginBot = () => NumCast(this.doc._yMargin);
     documentTitleWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.panelWidth());
-    documentTitleHeight = () => (this.layoutDoc?.[HeightSym]() || 0) - NumCast(this.layoutDoc.autoHeightMargins);
+    documentTitleHeight = () => (this.layoutDoc?.[HeightSym]() || 0) - NumCast(this.layoutDoc.layout_autoHeightMargins);
     truncateTitleWidth = () => this.treeViewtruncateTitleWidth;
     onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick);
     panelWidth = () => Math.max(0, this.props.PanelWidth() - 2 * this.marginX() * (this.props.NativeDimScaling?.() || 1));
 
-    addAnnotationDocument = (doc: Doc | Doc[]) => this.addDocument(doc, `${this.props.fieldKey}-annotations`) || false;
-    remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this.props.fieldKey}-annotations`) || false;
+    addAnnotationDocument = (doc: Doc | Doc[]) => this.addDocument(doc, `${this.props.fieldKey}_annotations`) || false;
+    remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this.props.fieldKey}_annotations`) || false;
     moveAnnotationDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) =>
-        this.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}-annotations`) || false;
+        this.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}_annotations`) || false;
 
     @observable _headerHeight = 0;
     @computed get content() {
@@ -430,7 +430,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     render() {
         TraceMobx();
 
-        const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1) || 1;
+        const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1) || 1;
         return (
             <div style={{ transform: `scale(${scale})`, transformOrigin: 'top left', width: `${100 / scale}%`, height: `${100 / scale}%` }}>
                 {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeViewHasOverlay ? (
@@ -443,7 +443,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                         isAnnotationOverlay={true}
                         isAnnotationOverlayScrollable={true}
                         childDocumentsActive={this.props.isDocumentActive}
-                        fieldKey={this.props.fieldKey + '-annotations'}
+                        fieldKey={this.props.fieldKey + '_annotations'}
                         dropAction={'move'}
                         select={emptyFunction}
                         addDocument={this.addAnnotationDocument}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index b76033a0c..dd7bf1740 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -47,8 +47,8 @@ interface CollectionViewProps_ extends FieldViewProps {
     childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
     childDocumentsActive?: () => boolean | undefined; // whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode)
     childContentsActive?: () => boolean | undefined;
-    childFitWidth?: (child: Doc) => boolean;
-    childShowTitle?: () => string;
+    childLayoutFitWidth?: (child: Doc) => boolean;
+    childlayout_showTitle?: () => string;
     childOpacity?: () => number;
     childContextMenuItems?: () => { script: ScriptField; label: string }[];
     childHideTitle?: () => boolean; // whether to hide the documentdecorations title for children
@@ -134,8 +134,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
                 { description: 'Freeform',    event: () => func(CollectionViewType.Freeform), icon: 'signature' },
                 { description: 'Schema',      event: () => func(CollectionViewType.Schema), icon: 'th-list' },
                 { description: 'Tree',        event: () => func(CollectionViewType.Tree), icon: 'tree' },
-                { description: 'Stacking',    event: () => (func(CollectionViewType.Stacking)._autoHeight = true), icon: 'ellipsis-v' },
-                { description: 'Notetaking',  event: () => (func(CollectionViewType.NoteTaking)._autoHeight = true), icon: 'ellipsis-v' },
+                { description: 'Stacking',    event: () => (func(CollectionViewType.Stacking)._layout_autoHeight = true), icon: 'ellipsis-v' },
+                { description: 'Notetaking',  event: () => (func(CollectionViewType.NoteTaking)._layout_autoHeight = true), icon: 'ellipsis-v' },
                 { description: 'Multicolumn', event: () => func(CollectionViewType.Multicolumn), icon: 'columns' },
                 { description: 'Multirow',    event: () => func(CollectionViewType.Multirow), icon: 'columns' },
                 { description: 'Masonry',     event: () => func(CollectionViewType.Masonry), icon: 'columns' },
@@ -159,7 +159,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
             !Doc.noviceMode &&
                 this.setupViewTypes('UI Controls...', vtype => {
-                    const newRendition = Doc.MakeAlias(this.rootDoc);
+                    const newRendition = Doc.MakeEmbedding(this.rootDoc);
                     newRendition._viewType = vtype;
                     this.props.addDocTab(newRendition, OpenWhere.addRight);
                     return newRendition;
@@ -190,9 +190,9 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
                         description: `Edit ${func.name} script`,
                         icon: 'edit',
                         event: (obj: any) => {
-                            const alias = Doc.MakeAlias(this.rootDoc);
-                            DocUtils.makeCustomViewClicked(alias, undefined, func.key);
-                            this.props.addDocTab(alias, OpenWhere.addRight);
+                            const embedding = Doc.MakeEmbedding(this.rootDoc);
+                            DocUtils.makeCustomViewClicked(embedding, undefined, func.key);
+                            this.props.addDocTab(embedding, OpenWhere.addRight);
                         },
                     })
                 );
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 45604c1bf..69963736b 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -252,11 +252,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             const pinDoc = Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc);
             pinDoc.presentationTargetDoc = anchorDoc ?? doc;
             pinDoc.title = doc.title + ' - Slide';
-            pinDoc.data = new List<Doc>(); // the children of the alias' layout are the presentation slide children.  the alias' data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data
+            pinDoc.data = new List<Doc>(); // the children of the embedding's layout are the presentation slide children.  the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data
             pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom;
             pinDoc.presDuration = pinDoc.presDuration ?? 1000;
             pinDoc.groupWithUp = false;
-            pinDoc.context = curPres;
+            pinDoc.embedContainer = curPres;
             // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements.  That way the PresBox could configure all of its children at render time
             pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area
             pinDoc.treeViewHeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling.
@@ -264,7 +264,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             pinDoc.treeViewFieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field
             pinDoc.treeViewExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view
             pinDoc.treeViewHideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header
-            const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], null);
+            const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], null);
 
             if (pinProps.pinViewport) PresBox.pinDocView(pinDoc, pinProps, anchorDoc ?? doc);
             if (!pinProps?.audioRange && duration !== undefined) {
@@ -283,7 +283,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 pinDoc.title = doc.title + ' (move)';
                 pinDoc.presMovement = PresMovement.Pan;
             }
-            if (pinDoc.isInkMask) {
+            if (pinDoc.stroke_isInkMask) {
                 pinDoc.presHideAfter = true;
                 pinDoc.presHideBefore = true;
                 pinDoc.presMovement = PresMovement.None;
@@ -357,7 +357,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         switch (whereFields[0]) {
             case undefined:
             case OpenWhere.lightbox:   if (this.layoutDoc?._isLightbox) {
-                                            const lightboxView = !doc.annotationOn && DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined;
+                                            const lightboxView = !doc.annotationOn && DocCast(doc.embedContainer) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.embedContainer)) : undefined;
                                             const data = lightboxView?.dataDoc[Doc.LayoutFieldKey(lightboxView.rootDoc)];
                                             if (lightboxView && (!data || data instanceof List)) {
                                                 lightboxView.layoutDoc[Doc.LayoutFieldKey(lightboxView.rootDoc)] = new List<Doc>([doc]);
@@ -409,7 +409,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     miniMapColor = () => this.tabColor;
     tabView = () => this._view;
     disableMinimap = () => !this._document || this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform;
-    hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.hideMinimap);
+    hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.layout_hideMinimap);
 
     @computed get docView() {
         return !this._activated || !this._document ? null : (
@@ -449,19 +449,19 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     pinToPres={TabDocView.PinDoc}
                 />
                 <TabMinimapView key="minimap" hideMinimap={this.hideMinimap} addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} />
-                <Tooltip key="ttip" title={<div className="dash-tooltip">{this._document.hideMinimap ? 'Open minimap' : 'Close minimap'}</div>}>
+                <Tooltip key="ttip" title={<div className="dash-tooltip">{this._document.layout_hideMinimap ? 'Open minimap' : 'Close minimap'}</div>}>
                     <div
                         className="miniMap-hidden"
                         style={{
                             display: this.disableMinimap() || this._document._viewType !== 'freeform' ? 'none' : undefined,
-                            color: this._document.hideMinimap ? Colors.BLACK : Colors.WHITE,
-                            backgroundColor: this._document.hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE,
-                            boxShadow: this._document.hideMinimap ? Shadows.STANDARD_SHADOW : undefined,
+                            color: this._document.layout_hideMinimap ? Colors.BLACK : Colors.WHITE,
+                            backgroundColor: this._document.layout_hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE,
+                            boxShadow: this._document.layout_hideMinimap ? Shadows.STANDARD_SHADOW : undefined,
                         }}
                         onPointerDown={e => e.stopPropagation()}
                         onClick={action(e => {
                             e.stopPropagation();
-                            this._document!.hideMinimap = !this._document!.hideMinimap;
+                            this._document!.layout_hideMinimap = !this._document!.layout_hideMinimap;
                         })}>
                         <FontAwesomeIcon icon={'globe-asia'} size="lg" />
                     </div>
@@ -559,8 +559,8 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                 this,
                 e,
                 action((e: PointerEvent, down: number[], delta: number[]) => {
-                    doc._panX = clamp(NumCast(doc._panX) + (delta[0] / miniSize) * renderBounds.dim, renderBounds.l, renderBounds.l + renderBounds.dim);
-                    doc._panY = clamp(NumCast(doc._panY) + (delta[1] / miniSize) * renderBounds.dim, renderBounds.t, renderBounds.t + renderBounds.dim);
+                    doc._freeform_panX = clamp(NumCast(doc._freeform_panX) + (delta[0] / miniSize) * renderBounds.dim, renderBounds.l, renderBounds.l + renderBounds.dim);
+                    doc._freeform_panY = clamp(NumCast(doc._freeform_panY) + (delta[1] / miniSize) * renderBounds.dim, renderBounds.t, renderBounds.t + renderBounds.dim);
                     return false;
                 }),
                 emptyFunction,
@@ -569,10 +569,10 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
     };
     render() {
         if (!this.renderBounds) return null;
-        const miniWidth = (this.props.PanelWidth() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim) * 100;
-        const miniHeight = (this.props.PanelHeight() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim) * 100;
-        const miniLeft = 50 + ((NumCast(this.props.document._panX) - this.renderBounds.cx) / this.renderBounds.dim) * 100 - miniWidth / 2;
-        const miniTop = 50 + ((NumCast(this.props.document._panY) - this.renderBounds.cy) / this.renderBounds.dim) * 100 - miniHeight / 2;
+        const miniWidth = (this.props.PanelWidth() / NumCast(this.props.document._freeform_scale, 1) / this.renderBounds.dim) * 100;
+        const miniHeight = (this.props.PanelHeight() / NumCast(this.props.document._freeform_scale, 1) / this.renderBounds.dim) * 100;
+        const miniLeft = 50 + ((NumCast(this.props.document._freeform_) - this.renderBounds.cx) / this.renderBounds.dim) * 100 - miniWidth / 2;
+        const miniTop = 50 + ((NumCast(this.props.document._freeform_panY) - this.renderBounds.cy) / this.renderBounds.dim) * 100 - miniHeight / 2;
         const miniSize = this.returnMiniSize();
         return this.props.hideMinimap() ? null : (
             <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 4adf86683..92b70cb5a 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -102,7 +102,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     private _treedropDisposer?: DragManager.DragDropDisposer;
 
     get treeViewOpenIsTransient() {
-        return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsPrototype(this.doc);
+        return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsDocDataProto(this.doc);
     }
     set treeViewOpen(c: boolean) {
         if (this.treeViewOpenIsTransient) this._transientOpenState = c;
@@ -125,7 +125,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             : this.props.treeView.fileSysMode
             ? this.doc.isFolder
                 ? this.fieldKey
-                : 'aliases' // for displaying
+                : 'embeddings' // for displaying
             : this.props.treeView.outlineMode || this.childDocs
             ? this.fieldKey
             : Doc.noviceMode
@@ -160,11 +160,11 @@ export class TreeView extends React.Component<TreeViewProps> {
     @computed get childLinks() {
         return this.childDocList('links');
     }
-    @computed get childAliases() {
-        return this.childDocList('aliases');
+    @computed get childEmbeddings() {
+        return this.childDocList('proto_embeddings');
     }
     @computed get childAnnos() {
-        return this.childDocList(this.fieldKey + '-annotations');
+        return this.childDocList(this.fieldKey + '_annotations');
     }
     @computed get selected() {
         return SelectionManager.IsSelected(this._docRef);
@@ -219,11 +219,13 @@ export class TreeView extends React.Component<TreeViewProps> {
         if (this.props.document.isFolder || Doc.IsSystem(this.props.document)) {
             this.treeViewOpen = !this.treeViewOpen;
         } else {
-            // choose an appropriate alias or make one. --- choose the first alias that (1) user owns,  (2) has no context field ... otherwise make a new alias
-            const bestAlias =
-                docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsPrototype(docView.props.Document) ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
-            const nextBestAlias = DocListCast(this.props.document.aliases).find(doc => doc.author === Doc.CurrentUserEmail);
-            this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), OpenWhere.lightbox);
+            // choose an appropriate embedding or make one. --- choose the first embedding that (1) user owns,  (2) has no context field ... otherwise make a new embedding
+            const bestEmbedding =
+                docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsDocDataProto(docView.props.Document)
+                    ? docView.props.Document
+                    : DocListCast(this.props.document.proto_embeddings).find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail);
+            const nextBestEmbedding = DocListCast(this.props.document.proto_embeddings).find(doc => doc.author === Doc.CurrentUserEmail);
+            this.props.addDocTab(bestEmbedding ?? nextBestEmbedding ?? Doc.MakeEmbedding(this.props.document), OpenWhere.lightbox);
         }
     };
 
@@ -311,16 +313,16 @@ export class TreeView extends React.Component<TreeViewProps> {
             treeViewExpandedViewLock: true,
             treeViewExpandedView: 'data',
             _viewType: CollectionViewType.Tree,
-            hideLinkButton: true,
-            _showSidebar: true,
-            _fitWidth: true,
+            layout_hideLinkButton: true,
+            _layout_showSidebar: true,
+            _layout_fitWidth: true,
             treeViewType: TreeViewType.outline,
             x: 0,
             y: 0,
             _xMargin: 0,
             _yMargin: 0,
-            _autoHeight: true,
-            _singleLine: true,
+            _layout_autoHeight: true,
+            _createDocOnCR: true,
             _width: 1000,
             _height: 10,
         });
@@ -359,7 +361,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         if (de.complete.linkDragData) {
             const sourceDoc = de.complete.linkDragData.linkSourceGetAnchor();
             const destDoc = this.doc;
-            DocUtils.MakeLink(sourceDoc, destDoc, { linkRelationship: 'tree link' });
+            DocUtils.MakeLink(sourceDoc, destDoc, { link_relationship: 'tree link' });
             e.stopPropagation();
         }
         const docDragData = de.complete.docDragData;
@@ -378,7 +380,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             const innerAdd = (doc: Doc) => {
                 const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[this.fieldKey])) instanceof ComputedField;
                 const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, this.fieldKey, doc);
-                dataIsComputed && (doc.context = this.doc.context);
+                dataIsComputed && (doc.embedContainer = this.doc.embedContainer);
                 return added;
             };
             return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
@@ -413,7 +415,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             (() => {
                 const aspect = Doc.NativeAspect(layoutDoc);
                 if (aspect) return this.embeddedPanelWidth() / (aspect || 1);
-                return layoutDoc._fitWidth
+                return layoutDoc._layout_fitWidth
                     ? !Doc.NativeHeight(layoutDoc)
                         ? NumCast(layoutDoc._height)
                         : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.treeViewParent._height)))
@@ -441,7 +443,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     const innerAdd = (doc: Doc) => {
                         const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField;
                         const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
-                        dataIsComputed && (doc.context = this.doc.context);
+                        dataIsComputed && (doc.embedContainer = this.doc.embedContainer);
                         return added;
                     };
                     return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
@@ -527,7 +529,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         TraceMobx();
         const expandKey = this.treeViewExpandedView;
         const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; label: string } }) ?? {};
-        if (['links', 'annotations', 'aliases', this.fieldKey].includes(expandKey)) {
+        if (['links', 'annotations', 'embeddings', this.fieldKey].includes(expandKey)) {
             const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None);
             const sortKeys = Object.keys(sortings);
             const curSortIndex = Math.max(
@@ -549,12 +551,12 @@ export class TreeView extends React.Component<TreeViewProps> {
                 }
                 const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField;
                 const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
-                !dataIsComputed && added && (doc.context = this.doc.context);
+                !dataIsComputed && added && (doc.embedContainer = this.doc.embedContainer);
 
                 return added;
             };
             const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true);
-            const docs = expandKey === 'aliases' ? this.childAliases : expandKey === 'links' ? this.childLinks : expandKey === 'annotations' ? this.childAnnos : this.childDocs;
+            const docs = expandKey === 'embeddings' ? this.childEmbeddings : expandKey === 'links' ? this.childLinks : expandKey === 'annotations' ? this.childAnnos : this.childDocs;
             let downX = 0,
                 downY = 0;
             if (docs?.length && this._renderCount < docs?.length) {
@@ -706,13 +708,13 @@ export class TreeView extends React.Component<TreeViewProps> {
     }
 
     @computed get validExpandViewTypes() {
-        const annos = () => (DocListCast(this.doc[this.fieldKey + '-annotations']).length && !this.props.treeView.dashboardMode ? 'annotations' : '');
+        const annos = () => (DocListCast(this.doc[this.fieldKey + '_annotations']).length && !this.props.treeView.dashboardMode ? 'annotations' : '');
         const links = () => (LinkManager.Links(this.doc).length && !this.props.treeView.dashboardMode ? 'links' : '');
         const data = () => (this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : '');
-        const aliases = () => (this.props.treeView.dashboardMode ? '' : 'aliases');
+        const embeddings = () => (this.props.treeView.dashboardMode ? '' : 'embeddings');
         const fields = () => (Doc.noviceMode ? '' : 'fields');
         const layout = Doc.noviceMode || this.doc.viewType === CollectionViewType.Docking ? [] : ['layout'];
-        return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [aliases(), links(), annos()] : []), fields()].filter(m => m);
+        return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [embeddings(), links(), annos()] : []), fields()].filter(m => m);
     }
     @action
     expandNextviewType = () => {
@@ -759,7 +761,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const makeFolder = { script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: 'any' })!, icon: 'folder-plus', label: 'New Folder' };
         const deleteItem = { script: ScriptField.MakeFunction(`scriptContext.deleteItem()`, { scriptContext: 'any' })!, icon: 'folder-plus', label: 'Delete' };
         const folderOp = this.childDocs?.length ? [makeFolder] : [];
-        const openAlias = { script: ScriptField.MakeFunction(`openDoc(getAlias(self), ${OpenWhere.addRight})`)!, icon: 'copy', label: 'Open Alias' };
+        const openEmbedding = { script: ScriptField.MakeFunction(`openDoc(getEmbedding(self), ${OpenWhere.addRight})`)!, icon: 'copy', label: 'Open Embedding' };
         const focusDoc = { script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, icon: 'eye', label: 'Focus or Open' };
         return [
             ...(this.props.contextMenuItems ?? []).filter(mi => (!mi.filter ? true : mi.filter.script.run({ doc: this.doc })?.result)),
@@ -768,10 +770,10 @@ export class TreeView extends React.Component<TreeViewProps> {
                 : Doc.IsSystem(this.doc)
                 ? []
                 : this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc)
-                ? [openAlias, makeFolder]
+                ? [openEmbedding, makeFolder]
                 : this.doc.viewType === CollectionViewType.Docking
                 ? []
-                : [deleteItem, openAlias, focusDoc]),
+                : [deleteItem, openEmbedding, focusDoc]),
         ];
     };
     childContextMenuItems = () => {
@@ -896,7 +898,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     }
                 })}
                 Document={this.doc}
-                fitWidth={returnTrue}
+                layout_fitWidth={returnTrue}
                 DataDoc={undefined}
                 scriptContext={this}
                 hideDecorationTitle={this.props.treeView.outlineMode}
@@ -985,7 +987,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     ref={action((r: DocumentView | null) => (this._dref = r))}
                     Document={this.doc}
                     DataDoc={undefined}
-                    fitWidth={this.fitWidthFilter}
+                    layout_fitWidth={this.fitWidthFilter}
                     PanelWidth={this.embeddedPanelWidth}
                     PanelHeight={this.embeddedPanelHeight}
                     LayoutTemplateString={asText ? FormattedTextBox.LayoutString('text') : undefined}
@@ -1179,7 +1181,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         TreeView._editTitleOnLoad = editTitle ? { id: child[Id], parent } : undefined;
                         Doc.AddDocToList(newParent, fieldKey, child, addAfter, false);
                         newParent.treeViewOpen = true;
-                        child.context = treeView.Document;
+                        child.embedContainer = treeView.Document;
                     }
                 };
                 const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 0dfd119d7..68ba3d368 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -34,11 +34,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         this._anchorDisposer = reaction(
             () => [
                 this.props.A.props.ScreenToLocalTransform(),
-                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?.scrollTop,
-                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?.[CssSym],
+                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop,
+                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.[CssSym],
                 this.props.B.props.ScreenToLocalTransform(),
-                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?.scrollTop,
-                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?.[CssSym],
+                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop,
+                Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.[CssSym],
             ],
             action(() => {
                 this._start = Date.now();
@@ -58,7 +58,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             0
         ); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render()
         setTimeout(
-            action(() => (!LinkDocs.length || !linkDoc.linkDisplay) && (this._opacity = 0.05)),
+            action(() => (!LinkDocs.length || !linkDoc.layout_linkDisplay) && (this._opacity = 0.05)),
             750
         ); // this will unhighlight the link line.
         const a = A.ContentDiv.getBoundingClientRect();
@@ -72,36 +72,36 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         //   if there's an element in the DOM with a classname containing a link anchor's id,
         //   then that DOM element is a hyperlink source for the current anchor and we want to place our link box at it's top right
         //   otherwise, we just use the computed nearest point on the document boundary to the target Document
-        const targetAhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.anchor1 as Doc)[Id])).lastElement();
-        const targetBhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.anchor2 as Doc)[Id])).lastElement();
+        const targetAhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.link_anchor_1 as Doc)[Id])).lastElement();
+        const targetBhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.link_anchor_2 as Doc)[Id])).lastElement();
         if ((!targetAhyperlink && !a.width) || (!targetBhyperlink && !b.width)) return;
         if (!targetAhyperlink) {
-            if (linkDoc.linkAutoMove) {
-                linkDoc.anchor1_x = ((apt.point.x - aleft) / awidth) * 100;
-                linkDoc.anchor1_y = ((apt.point.y - atop) / aheight) * 100;
+            if (linkDoc.layout_autoMoveAnchors) {
+                linkDoc.link_anchor_1_x = ((apt.point.x - aleft) / awidth) * 100;
+                linkDoc.link_anchor_1_y = ((apt.point.y - atop) / aheight) * 100;
             }
         } else {
             const m = targetAhyperlink.getBoundingClientRect();
             const mp = A.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
             const mpx = mp[0] / A.props.PanelWidth();
             const mpy = mp[1] / A.props.PanelHeight();
-            if (mpx >= 0 && mpx <= 1) linkDoc.anchor1_x = mpx * 100;
-            if (mpy >= 0 && mpy <= 1) linkDoc.anchor1_y = mpy * 100;
+            if (mpx >= 0 && mpx <= 1) linkDoc.link_anchor_1_x = mpx * 100;
+            if (mpy >= 0 && mpy <= 1) linkDoc.link_anchor_1_y = mpy * 100;
             if (getComputedStyle(targetAhyperlink).fontSize === '0px') linkDoc.opacity = 0;
             else linkDoc.opacity = 1;
         }
         if (!targetBhyperlink) {
-            if (linkDoc.linkAutoMove) {
-                linkDoc.anchor2_x = ((bpt.point.x - bleft) / bwidth) * 100;
-                linkDoc.anchor2_y = ((bpt.point.y - btop) / bheight) * 100;
+            if (linkDoc.layout_autoMoveAnchors) {
+                linkDoc.link_anchor_2_x = ((bpt.point.x - bleft) / bwidth) * 100;
+                linkDoc.link_anchor_2_y = ((bpt.point.y - btop) / bheight) * 100;
             }
         } else {
             const m = targetBhyperlink.getBoundingClientRect();
             const mp = B.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
             const mpx = mp[0] / B.props.PanelWidth();
             const mpy = mp[1] / B.props.PanelHeight();
-            if (mpx >= 0 && mpx <= 1) linkDoc.anchor2_x = mpx * 100;
-            if (mpy >= 0 && mpy <= 1) linkDoc.anchor2_y = mpy * 100;
+            if (mpx >= 0 && mpx <= 1) linkDoc.link_anchor_2_x = mpx * 100;
+            if (mpy >= 0 && mpy <= 1) linkDoc.link_anchor_2_y = mpy * 100;
             if (getComputedStyle(targetBhyperlink).fontSize === '0px') linkDoc.opacity = 0;
             else linkDoc.opacity = 1;
         }
@@ -112,8 +112,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             this,
             e,
             (e, down, delta) => {
-                this.props.LinkDocs[0].linkOffsetX = NumCast(this.props.LinkDocs[0].linkOffsetX) + delta[0];
-                this.props.LinkDocs[0].linkOffsetY = NumCast(this.props.LinkDocs[0].linkOffsetY) + delta[1];
+                this.props.LinkDocs[0].link_relationship_OffsetX = NumCast(this.props.LinkDocs[0].link_relationship_OffsetX) + delta[0];
+                this.props.LinkDocs[0].link_relationship_OffsetY = NumCast(this.props.LinkDocs[0].link_relationship_OffsetY) + delta[1];
                 return false;
             },
             emptyFunction,
@@ -205,8 +205,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const bclipped = bleft !== b.left || btop !== b.top;
         if (aclipped && bclipped) return undefined;
         const clipped = aclipped || bclipped;
-        const pt1inside = NumCast(LinkDocs[0].anchor1_x) % 100 !== 0 && NumCast(LinkDocs[0].anchor1_y) % 100 !== 0;
-        const pt2inside = NumCast(LinkDocs[0].anchor2_x) % 100 !== 0 && NumCast(LinkDocs[0].anchor2_y) % 100 !== 0;
+        const pt1inside = NumCast(LinkDocs[0].link_anchor_1_x) % 100 !== 0 && NumCast(LinkDocs[0].link_anchor_1_y) % 100 !== 0;
+        const pt2inside = NumCast(LinkDocs[0].link_anchor_2_x) % 100 !== 0 && NumCast(LinkDocs[0].link_anchor_2_y) % 100 !== 0;
         const pt1 = [aleft + a.width / 2, atop + a.height / 2];
         const pt2 = [bleft + b.width / 2, btop + b.width / 2];
         const pt2vec = pt2inside ? [-0.7071, 0.7071] : [(bDocBounds.left + bDocBounds.right) / 2 - pt2[0], (bDocBounds.top + bDocBounds.bottom) / 2 - pt2[1]];
@@ -223,8 +223,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const aActive = A.isSelected() || Doc.IsBrushed(A.rootDoc);
         const bActive = B.isSelected() || Doc.IsBrushed(B.rootDoc);
 
-        const textX = (Math.min(pt1[0], pt2[0]) + Math.max(pt1[0], pt2[0])) / 2 + NumCast(LinkDocs[0].linkOffsetX);
-        const textY = (pt1[1] + pt2[1]) / 2 + NumCast(LinkDocs[0].linkOffsetY);
+        const textX = (Math.min(pt1[0], pt2[0]) + Math.max(pt1[0], pt2[0])) / 2 + NumCast(LinkDocs[0].link_relationship_OffsetX);
+        const textY = (pt1[1] + pt2[1]) / 2 + NumCast(LinkDocs[0].link_relationship_OffsetY);
         return {
             a,
             b,
@@ -244,12 +244,12 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
 
         const link = this.props.LinkDocs[0];
         const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData;
-        const linkRelationship = Field.toString(link?.linkRelationship as any as Field); //get string representing relationship
-        const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List<string>;
+        const linkRelationship = Field.toString(link?.link_relationship as any as Field); //get string representing relationship
+        const linkRelationshipList = Doc.UserDoc().link_relationshipList as List<string>;
         const linkColorList = Doc.UserDoc().linkColorList as List<string>;
-        const linkRelationshipSizes = Doc.UserDoc().linkRelationshipSizes as List<number>;
+        const linkRelationshipSizes = Doc.UserDoc().link_relationshipSizes as List<number>;
         const currRelationshipIndex = linkRelationshipList.indexOf(linkRelationship);
-        const linkDescription = Field.toString(link.description as any as Field);
+        const linkDescription = Field.toString(link.link_description as any as Field);
 
         const linkSize = currRelationshipIndex === -1 || currRelationshipIndex >= linkRelationshipSizes.length ? -1 : linkRelationshipSizes[currRelationshipIndex];
 
@@ -261,11 +261,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         //thickness varies linearly from 3px to 12px for increasing link count
         const strokeWidth = linkSize === -1 ? '3px' : Math.floor(2 + 10 * (linkSize / Math.max(...linkRelationshipSizes))) + 'px';
 
-        if (link.linkDisplayArrow === undefined) {
-            link.linkDisplayArrow = false;
+        if (link.layout_linkDisplayArrow === undefined) {
+            link.layout_linkDisplayArrow = false;
         }
 
-        return link.opacity === 0 || !a.width || !b.width || (!link.linkDisplay && !aActive && !bActive) ? null : (
+        return link.opacity === 0 || !a.width || !b.width || (!link.layout_linkDisplay && !aActive && !bActive) ? null : (
             <>
                 <defs>
                     <marker id={`${link[Id] + 'arrowhead'}`} markerWidth="4" markerHeight="3" refX="0" refY="1.5" orient="auto">
@@ -294,7 +294,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
                     style={{ pointerEvents: 'visibleStroke', opacity: this._opacity, stroke, strokeWidth }}
                     onClick={this.onClickLine}
                     d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`}
-                    markerEnd={link.linkDisplayArrow ? `url(#${link[Id] + 'arrowhead'})` : ''}
+                    markerEnd={link.layout_linkDisplayArrow ? `url(#${link[Id] + 'arrowhead'})` : ''}
                 />
                 {textX === undefined || !linkDescription ? null : (
                     <text filter={`url(#${link[Id] + 'background'})`} className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown}>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 08e3174d1..4d18ebeea 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -100,13 +100,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         return this.props.isAnnotationOverlay;
     }
     public get scaleFieldKey() {
-        return this.props.viewField ? this.props.viewField + '-viewScale' : '_viewScale';
+        return (this.props.viewField ?? '') + '_freeform_scale';
     }
     private get panXFieldKey() {
-        return this.props.viewField ? this.props.viewField + '-panX' : '_panX';
+        return (this.props.viewField ?? '') + '_freeform_panX';
     }
     private get panYFieldKey() {
-        return this.props.viewField ? this.props.viewField + '-panY' : '_panY';
+        return (this.props.viewField ?? '') + '_freeform_panY';
     }
     private get borderWidth() {
         return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH;
@@ -146,7 +146,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         };
     }
     @computed get fitContentsToBox() {
-        return (this.props.fitContentsToBox?.() || this.Document._fitContentsToBox) && !this.isAnnotationOverlay;
+        return (this.props.fitContentsToBox?.() || this.Document._freeform_fitContentsToBox) && !this.isAnnotationOverlay;
     }
     @computed get contentBounds() {
         const cb = Cast(this.rootDoc.contentBounds, listSpec('number'));
@@ -173,7 +173,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const dv = this.props.DocumentView?.();
         const scaling = this.fitContentsToBox || !this.nativeDimScaling ? 1 : this.nativeDimScaling;
         // if freeform has a native aspect, then the panel height needs to be adjusted to match it
-        const aspect = dv?.nativeWidth && dv?.nativeHeight && !dv.layoutDoc.fitWidth ? dv.nativeHeight / dv.nativeWidth : this.props.PanelHeight() / this.props.PanelWidth();
+        const aspect = dv?.nativeWidth && dv?.nativeHeight && !dv.layoutDoc.layout_fitWidth ? dv.nativeHeight / dv.nativeWidth : this.props.PanelHeight() / this.props.PanelWidth();
         return this.props.isAnnotationOverlay || this.props.originTopLeft ? 0 : (aspect * this.props.PanelWidth()) / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
     }
     @computed get cachedGetLocalTransform(): Transform {
@@ -239,16 +239,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     shrinkWrap = () => {
         if (this.props.DocumentView?.().nativeWidth) return;
         const vals = this.fitToContentVals;
-        this.layoutDoc._panX = vals.bounds.cx;
-        this.layoutDoc._panY = vals.bounds.cy;
-        this.layoutDoc._viewScale = vals.scale;
+        this.layoutDoc._freeform_panX = vals.bounds.cx;
+        this.layoutDoc._freeform_panY = vals.bounds.cy;
+        this.layoutDoc._freeform_scale = vals.scale;
     };
     freeformData = (force?: boolean) => (!this._firstRender && (this.fitContentsToBox || force) ? this.fitToContentVals : undefined);
     reverseNativeScaling = () => (this.fitContentsToBox ? true : false);
-    // panx, pany, zoomscale all attempt to get values first from the layout controller, then from the layout/dataDoc (or template layout doc), and finally from the resolved template data document.
+    // freeform_panx, freeform_pany, freeform_scale all attempt to get values first from the layout controller, then from the layout/dataDoc (or template layout doc), and finally from the resolved template data document.
     // this search order, for example, allows icons of cropped images to find the panx/pany/zoom on the cropped image's data doc instead of the usual layout doc because the zoom/panX/panY define the cropped image
-    panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panX, 1));
-    panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panY, 1));
+    panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panX, 1));
+    panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panY, 1));
     zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.[this.scaleFieldKey], 1));
     contentTransform = () =>
         this.props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`;
@@ -297,7 +297,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     isCurrent(doc: Doc) {
         const dispTime = NumCast(doc._timecodeToShow, -1);
         const endTime = NumCast(doc._timecodeToHide, dispTime + 1.5);
-        const curTime = NumCast(this.Document._currentTimecode, -1);
+        const curTime = NumCast(this.Document._layout_currentTimecode, -1);
         return dispTime === -1 || curTime === -1 || (curTime - dispTime >= -1e-4 && curTime <= endTime);
     }
 
@@ -348,7 +348,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             .map(pair => pair.layout)
             .slice()
             .sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
-        zsorted.forEach((doc, index) => (doc.zIndex = doc.isInkMask ? 5000 : index + 1));
+        zsorted.forEach((doc, index) => (doc.zIndex = doc.stroke_isInkMask ? 5000 : index + 1));
         const dvals = CollectionFreeFormDocumentView.getValues(refDoc, NumCast(refDoc.activeFrame, 1000));
         const dropPos = this.Document._currentFrame !== undefined ? [NumCast(dvals.x), NumCast(dvals.y)] : [NumCast(refDoc.x), NumCast(refDoc.y)];
 
@@ -366,7 +366,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 d.x = x + NumCast(d.x) - dropPos[0];
                 d.y = y + NumCast(d.y) - dropPos[1];
             }
-            d._lastModified = new DateField();
+            d._layout_modificationDate = new DateField();
             const nd = [Doc.NativeWidth(layoutDoc), Doc.NativeHeight(layoutDoc)];
             layoutDoc._width = NumCast(layoutDoc._width, 300);
             layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? (nd[1] / nd[0]) * NumCast(layoutDoc._width) : 300);
@@ -418,11 +418,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData, xp: number, yp: number) {
         if (linkDragData.linkDragView.props.docViewPath().includes(this.props.docViewPath().lastElement())) {
             // dragged document is a child of this collection
-            if (!linkDragData.linkDragView.props.CollectionFreeFormDocumentView?.() || linkDragData.dragDocument.context !== this.props.Document) {
-                // if the source doc view's context isn't this same freeformcollectionlinkDragData.dragDocument.context === this.props.Document
+            if (!linkDragData.linkDragView.props.CollectionFreeFormDocumentView?.() || linkDragData.dragDocument.embedContainer !== this.props.Document) {
+                // if the source doc view's embedContainer isn't this same freeformcollectionlinkDragData.dragDocument.embedContainer === this.props.Document
                 const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, x: xp, y: yp, title: 'dropped annotation' });
                 this.props.addDocument?.(source);
-                de.complete.linkDocument = DocUtils.MakeLink(linkDragData.linkSourceGetAnchor(), source, { linkRelationship: 'annotated by:annotation of' }); // TODODO this is where in text links get passed
+                de.complete.linkDocument = DocUtils.MakeLink(linkDragData.linkSourceGetAnchor(), source, { link_relationship: 'annotated by:annotation of' }); // TODODO this is where in text links get passed
             }
             e.stopPropagation(); //  do nothing if link is dropped into any freeform view parent of dragged document
             return true;
@@ -446,7 +446,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         return this.childLayoutPairs
             .map(pair => pair.layout)
             .reduce((cluster, cd) => {
-                const grouping = this.props.Document._useClusters ? NumCast(cd.cluster, -1) : NumCast(cd.group, -1);
+                const grouping = this.props.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1);
                 if (grouping !== -1) {
                     const layoutDoc = Doc.Layout(cd);
                     const cx = NumCast(cd.x) - this._clusterDistance / 2;
@@ -463,10 +463,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if (cluster !== -1) {
             const ptsParent = e instanceof PointerEvent ? e : e.targetTouches.item(0);
             if (ptsParent) {
-                const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === cluster);
+                const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster);
                 const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.DocumentView?.())!);
                 const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 };
-                const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'alias' : undefined);
+                const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'embed' : undefined);
                 de.moveDocument = this.props.moveDocument;
                 de.offset = this.getTransform().transformDirection(ptsParent.clientX - left, ptsParent.clientY - top);
                 DragManager.StartDocumentDrag(
@@ -485,8 +485,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @undoBatch
     @action
-    updateClusters(_useClusters: boolean) {
-        this.props.Document._useClusters = _useClusters;
+    updateClusters(_freeform_useClusters: boolean) {
+        this.props.Document._freeform_useClusters = _freeform_useClusters;
         this._clusterSets.length = 0;
         this.childLayoutPairs.map(pair => pair.layout).map(c => this.updateCluster(c));
     }
@@ -494,38 +494,43 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @action
     updateClusterDocs(docs: Doc[]) {
         const childLayouts = this.childLayoutPairs.map(pair => pair.layout);
-        if (this.props.Document._useClusters) {
+        if (this.props.Document._freeform_useClusters) {
             const docFirst = docs[0];
             docs.map(doc => this._clusterSets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)));
-            const preferredInd = NumCast(docFirst.cluster);
-            docs.map(doc => (doc.cluster = -1));
+            const preferredInd = NumCast(docFirst.layout_cluster);
+            docs.map(doc => (doc.layout_cluster = -1));
             docs.map(doc =>
                 this._clusterSets.map((set, i) =>
                     set.map(member => {
-                        if (docFirst.cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) {
-                            docFirst.cluster = i;
+                        if (docFirst.layout_cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) {
+                            docFirst.layout_cluster = i;
                         }
                     })
                 )
             );
-            if (docFirst.cluster === -1 && preferredInd !== -1 && this._clusterSets.length > preferredInd && (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) {
-                docFirst.cluster = preferredInd;
+            if (
+                docFirst.layout_cluster === -1 &&
+                preferredInd !== -1 &&
+                this._clusterSets.length > preferredInd &&
+                (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)
+            ) {
+                docFirst.layout_cluster = preferredInd;
             }
             this._clusterSets.map((set, i) => {
-                if (docFirst.cluster === -1 && !set.filter(member => Doc.IndexOf(member, childLayouts) !== -1).length) {
-                    docFirst.cluster = i;
+                if (docFirst.layout_cluster === -1 && !set.filter(member => Doc.IndexOf(member, childLayouts) !== -1).length) {
+                    docFirst.layout_cluster = i;
                 }
             });
-            if (docFirst.cluster === -1) {
+            if (docFirst.layout_cluster === -1) {
                 docs.map(doc => {
-                    doc.cluster = this._clusterSets.length;
+                    doc.layout_cluster = this._clusterSets.length;
                     this._clusterSets.push([doc]);
                 });
             } else if (this._clusterSets.length) {
-                for (let i = this._clusterSets.length; i <= NumCast(docFirst.cluster); i++) !this._clusterSets[i] && this._clusterSets.push([]);
-                docs.map(doc => this._clusterSets[(doc.cluster = NumCast(docFirst.cluster))].push(doc));
+                for (let i = this._clusterSets.length; i <= NumCast(docFirst.layout_cluster); i++) !this._clusterSets[i] && this._clusterSets.push([]);
+                docs.map(doc => this._clusterSets[(doc.layout_cluster = NumCast(docFirst.layout_cluster))].push(doc));
             }
-            childLayouts.map(child => !this._clusterSets.some((set, i) => Doc.IndexOf(child, set) !== -1 && child.cluster === i) && this.updateCluster(child));
+            childLayouts.map(child => !this._clusterSets.some((set, i) => Doc.IndexOf(child, set) !== -1 && child.layout_cluster === i) && this.updateCluster(child));
         }
     }
 
@@ -533,31 +538,31 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @action
     updateCluster(doc: Doc) {
         const childLayouts = this.childLayoutPairs.map(pair => pair.layout);
-        if (this.props.Document._useClusters) {
+        if (this.props.Document._freeform_useClusters) {
             this._clusterSets.forEach(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1));
-            const preferredInd = NumCast(doc.cluster);
-            doc.cluster = -1;
+            const preferredInd = NumCast(doc.layout_cluster);
+            doc.layout_cluster = -1;
             this._clusterSets.forEach((set, i) =>
                 set.forEach(member => {
-                    if (doc.cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) {
-                        doc.cluster = i;
+                    if (doc.layout_cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) {
+                        doc.layout_cluster = i;
                     }
                 })
             );
-            if (doc.cluster === -1 && preferredInd !== -1 && this._clusterSets.length > preferredInd && (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) {
-                doc.cluster = preferredInd;
+            if (doc.layout_cluster === -1 && preferredInd !== -1 && this._clusterSets.length > preferredInd && (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) {
+                doc.layout_cluster = preferredInd;
             }
             this._clusterSets.forEach((set, i) => {
-                if (doc.cluster === -1 && !set.filter(member => Doc.IndexOf(member, childLayouts) !== -1).length) {
-                    doc.cluster = i;
+                if (doc.layout_cluster === -1 && !set.filter(member => Doc.IndexOf(member, childLayouts) !== -1).length) {
+                    doc.layout_cluster = i;
                 }
             });
-            if (doc.cluster === -1) {
-                doc.cluster = this._clusterSets.length;
+            if (doc.layout_cluster === -1) {
+                doc.layout_cluster = this._clusterSets.length;
                 this._clusterSets.push([doc]);
             } else if (this._clusterSets.length) {
-                for (let i = this._clusterSets.length; i <= doc.cluster; i++) !this._clusterSets[i] && this._clusterSets.push([]);
-                this._clusterSets[doc.cluster ?? 0].push(doc);
+                for (let i = this._clusterSets.length; i <= doc.layout_cluster; i++) !this._clusterSets[i] && this._clusterSets.push([]);
+                this._clusterSets[doc.layout_cluster ?? 0].push(doc);
             }
         }
     }
@@ -566,8 +571,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         let styleProp = this.props.styleProvider?.(doc, props, property); // bcz: check 'props'  used to be renderDepth + 1
         switch (property) {
             case StyleProp.BackgroundColor:
-                const cluster = NumCast(doc?.cluster);
-                if (this.Document._useClusters && doc?.type !== DocumentType.IMG) {
+                const cluster = NumCast(doc?.layout_cluster);
+                if (this.Document._freeform_useClusters && doc?.type !== DocumentType.IMG) {
                     if (this._clusterSets.length <= cluster) {
                         setTimeout(() => doc && this.updateCluster(doc));
                     } else {
@@ -591,7 +596,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     trySelectCluster = (addToSel: boolean) => {
         if (this._hitCluster !== -1) {
             !addToSel && SelectionManager.DeselectAll();
-            const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === this._hitCluster);
+            const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster);
             this.selectDocuments(eles);
             return true;
         }
@@ -678,7 +683,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 const B = this.getTransform().transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height);
                 const inkDoc = Docs.Create.InkDocument(
                     ActiveInkColor(),
-                    Doc.ActiveTool,
                     ActiveInkWidth() * this.props.ScreenToLocalTransform().Scale,
                     ActiveInkBezierApprox(),
                     ActiveFillColor(),
@@ -834,7 +838,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         this.getEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint).forEach(intersect => {
             if (!this._deleteList.includes(intersect.inkView)) {
                 this._deleteList.push(intersect.inkView);
-                SetActiveInkWidth(StrCast(intersect.inkView.rootDoc.strokeWidth?.toString()) || '1');
+                SetActiveInkWidth(StrCast(intersect.inkView.rootDoc.stroke_width?.toString()) || '1');
                 SetActiveInkColor(StrCast(intersect.inkView.rootDoc.color?.toString()) || 'black');
                 // create a new curve by appending all curves of the current segment together in order to render a single new stroke.
                 if (!e.shiftKey) {
@@ -1021,19 +1025,19 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if (deltaScale * invTransform.Scale > 20) {
             deltaScale = 20 / invTransform.Scale;
         }
-        if (deltaScale < 1 && invTransform.Scale <= NumCast(this.rootDoc._viewScaleMin, 1) && this.isAnnotationOverlay) {
+        if (deltaScale < 1 && invTransform.Scale <= NumCast(this.rootDoc._freeform_scaleMin, 1) && this.isAnnotationOverlay) {
             this.setPan(0, 0);
             return;
         }
-        if (deltaScale * invTransform.Scale < NumCast(this.rootDoc._viewScaleMin, 1) && this.isAnnotationOverlay) {
-            deltaScale = NumCast(this.rootDoc._viewScaleMin, 1) / invTransform.Scale;
+        if (deltaScale * invTransform.Scale < NumCast(this.rootDoc._freeform_scaleMin, 1) && this.isAnnotationOverlay) {
+            deltaScale = NumCast(this.rootDoc._freeform_scaleMin, 1) / invTransform.Scale;
         }
 
         const localTransform = invTransform.scaleAbout(deltaScale, x, y);
         if (localTransform.Scale >= 0.05 || localTransform.Scale > this.zoomScaling()) {
             const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20);
             this.props.Document[this.scaleFieldKey] = Math.abs(safeScale);
-            this.setPan(-localTransform.TranslateX / safeScale, (this.props.originTopLeft ? undefined : NumCast(this.props.Document.scrollTop) * safeScale) || -localTransform.TranslateY / safeScale);
+            this.setPan(-localTransform.TranslateX / safeScale, (this.props.originTopLeft ? undefined : NumCast(this.props.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale);
         }
     };
 
@@ -1113,26 +1117,26 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc || DocListCast(Doc.MyOverlayDocs?.data).includes(this.Document)) {
             this.setPanZoomTransition(panTime);
             const scale = this.getLocalTransform().inverse().Scale;
-            const minScale = NumCast(this.rootDoc._viewScaleMin, 1);
-            const minPanX = NumCast(this.rootDoc._panXMin, 0);
-            const minPanY = NumCast(this.rootDoc._panYMin, 0);
-            const newPanX = Math.min(minPanX + (1 - minScale / scale) * NumCast(this.rootDoc._panXMax, this.nativeWidth), Math.max(minPanX, panX));
+            const minScale = NumCast(this.rootDoc._freeform_scaleMin, 1);
+            const minPanX = NumCast(this.rootDoc._freeform_panXMin, 0);
+            const minPanY = NumCast(this.rootDoc._freeform_panYMin, 0);
+            const newPanX = Math.min(minPanX + (1 - minScale / scale) * NumCast(this.rootDoc._freeform_panXMax, this.nativeWidth), Math.max(minPanX, panX));
             const fitYscroll = (((this.nativeHeight / this.nativeWidth) * this.props.PanelWidth() - this.props.PanelHeight()) * this.props.ScreenToLocalTransform().Scale) / minScale;
             const nativeHeight = (this.props.PanelHeight() / this.props.PanelWidth() / (this.nativeHeight / this.nativeWidth)) * this.nativeHeight;
             const maxScrollTop = this.nativeHeight / this.props.ScreenToLocalTransform().Scale - this.props.PanelHeight();
             const maxPanY =
-                minPanY + // minPanY + scrolling introduced by view scaling + scrolling introduced by fitWidth
+                minPanY + // minPanY + scrolling introduced by view scaling + scrolling introduced by layout_fitWidth
                 (1 - minScale / scale) * NumCast(this.rootDoc._panYMax, nativeHeight) +
                 (!this.props.getScrollHeight?.() ? fitYscroll : 0); // when not zoomed, scrolling is handled via a scrollbar, not panning
             let newPanY = Math.max(minPanY, Math.min(maxPanY, panY));
-            if (false && NumCast(this.rootDoc.scrollTop) && NumCast(this.rootDoc._viewScale, minScale) !== minScale) {
-                const relTop = NumCast(this.rootDoc.scrollTop) / maxScrollTop;
-                this.rootDoc.scrollTop = undefined;
+            if (false && NumCast(this.rootDoc.layout_scrollTop) && NumCast(this.rootDoc._freeform_scale, minScale) !== minScale) {
+                const relTop = NumCast(this.rootDoc.layout_scrollTop) / maxScrollTop;
+                this.rootDoc.layout_scrollTop = undefined;
                 newPanY = minPanY + relTop * (maxPanY - minPanY);
-            } else if (fitYscroll && this.rootDoc.scrollTop === undefined && NumCast(this.rootDoc._viewScale, minScale) === minScale) {
+            } else if (fitYscroll && this.rootDoc.layout_scrollTop === undefined && NumCast(this.rootDoc._freeform_scale, minScale) === minScale) {
                 const maxPanY = minPanY + fitYscroll;
                 const relTop = (panY - minPanY) / (maxPanY - minPanY);
-                setTimeout(() => (this.rootDoc.scrollTop = relTop * maxScrollTop), 10);
+                setTimeout(() => (this.rootDoc.layout_scrollTop = relTop * maxScrollTop), 10);
                 newPanY = minPanY;
             }
             !this.Document._verticalScroll && (this.Document[this.panXFieldKey] = this.isAnnotationOverlay ? newPanX : panX);
@@ -1143,7 +1147,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @action
     nudge = (x: number, y: number, nudgeTime: number = 500) => {
         const collectionDoc = this.props.docViewPath().lastElement().rootDoc;
-        if (collectionDoc?._viewType !== CollectionViewType.Freeform || collectionDoc._panX !== undefined) {
+        if (collectionDoc?._viewType !== CollectionViewType.Freeform || collectionDoc._freeform_ !== undefined) {
             this.setPan(
                 NumCast(this.layoutDoc[this.panXFieldKey]) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale
                 NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(),
@@ -1162,7 +1166,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             docs.sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
             let zfirst = docs.length ? NumCast(docs[0].zIndex) : 0;
             doc.zIndex = zfirst - 1;
-        } else if (doc.isInkMask) {
+        } else if (doc.stroke_isInkMask) {
             doc.zIndex = 5000;
         } else {
             const docs = this.childLayoutPairs.map(pair => pair.layout).slice();
@@ -1222,8 +1226,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
         const panelWidth = this.props.isAnnotationOverlay ? this.nativeWidth : this.props.PanelWidth();
         const panelHeight = this.props.isAnnotationOverlay ? this.nativeHeight : this.props.PanelHeight();
-        const pw = panelWidth / NumCast(this.layoutDoc._viewScale, 1);
-        const ph = panelHeight / NumCast(this.layoutDoc._viewScale, 1);
+        const pw = panelWidth / NumCast(this.layoutDoc._freeform_scale, 1);
+        const ph = panelHeight / NumCast(this.layoutDoc._freeform_scale, 1);
         const cx = NumCast(this.layoutDoc[this.panXFieldKey]) + (this.props.isAnnotationOverlay ? pw / 2 : 0);
         const cy = NumCast(this.layoutDoc[this.panYFieldKey]) + (this.props.isAnnotationOverlay ? ph / 2 : 0);
         const screen = { left: cx - pw / 2, right: cx + pw / 2, top: cy - ph / 2, bot: cy + ph / 2 };
@@ -1248,17 +1252,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @action
     onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
         const docView = fieldProps.DocumentView?.();
-        if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.rootDoc._singleLine) && ['Tab', 'Enter'].includes(e.key)) {
+        if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.rootDoc._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) {
             e.stopPropagation?.();
             const below = !e.altKey && e.key !== 'Tab';
-            const layoutKey = StrCast(docView.LayoutFieldKey);
+            const layout_fieldKey = StrCast(docView.LayoutFieldKey);
             const newDoc = Doc.MakeCopy(docView.rootDoc, true);
             const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)];
             newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
             if (below) newDoc.y = NumCast(docView.rootDoc.y) + NumCast(docView.rootDoc._height) + 10;
             else newDoc.x = NumCast(docView.rootDoc.x) + NumCast(docView.rootDoc._width) + 10;
-            if (layoutKey !== 'layout' && docView.rootDoc[layoutKey] instanceof Doc) {
-                newDoc[layoutKey] = docView.rootDoc[layoutKey];
+            if (layout_fieldKey !== 'layout' && docView.rootDoc[layout_fieldKey] instanceof Doc) {
+                newDoc[layout_fieldKey] = docView.rootDoc[layout_fieldKey];
             }
             Doc.GetProto(newDoc).text = undefined;
             FormattedTextBox.SelectOnLoad = newDoc[Id];
@@ -1315,7 +1319,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 sizeProvider={this.childSizeProvider}
                 dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
                 bringToFront={this.bringToFront}
-                showTitle={this.props.childShowTitle}
+                layout_showTitle={this.props.childlayout_showTitle}
                 dontRegisterView={this.props.dontRenderDocuments || this.props.dontRegisterView}
                 pointerEvents={this.pointerEvents}
                 //rotation={this.props.styleProvider?.(childLayout, this.props, StyleProp.JitterRotation) || 0}
@@ -1329,7 +1333,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             case OpenWhere.inParent:
                 return this.props.addDocument?.(doc) || false;
             case OpenWhere.inParentFromScreen:
-                const docContext = DocCast((doc instanceof Doc ? doc : doc?.[0])?.context);
+                const docContext = DocCast((doc instanceof Doc ? doc : doc?.[0])?.embedContainer);
                 return (
                     (this.addDocument?.(
                         (doc instanceof Doc ? [doc] : doc).map(doc => {
@@ -1521,7 +1525,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 elements.push({
                     ele: this.getChildDocView(entry[1]),
                     bounds: childData.opacity === 0 ? { ...childData, width: 0, height: 0 } : { ...childData, width: childSize.width, height: childSize.height },
-                    inkMask: BoolCast(entry[1].pair.layout.isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1,
+                    inkMask: BoolCast(entry[1].pair.layout.stroke_isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1,
                 });
             });
 
@@ -1531,7 +1535,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             else this.props.Document[this.scaleFieldKey] = Math.max(1, this.zoomScaling()); // NumCast(this.props.Document[this.scaleFieldKey]));
         }
 
-        this.Document._useClusters && !this._clusterSets.length && this.childDocs.length && this.updateClusters(true);
+        this.Document._freeform_useClusters && !this._clusterSets.length && this.childDocs.length && this.updateClusters(true);
         return elements;
     }
 
@@ -1541,10 +1545,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document._isGroup, viewType: true, filters: true } }, this.rootDoc);
 
         if (addAsAnnotation) {
-            if (Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), null) !== undefined) {
-                Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), []).push(anchor);
+            if (Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) {
+                Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), []).push(anchor);
             } else {
-                this.dataDoc[this.props.fieldKey + '-annotations'] = new List<Doc>([anchor]);
+                this.dataDoc[this.props.fieldKey + '_annotations'] = new List<Doc>([anchor]);
             }
         }
         return anchor;
@@ -1644,8 +1648,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             '',
             (iconFile, nativeWidth, nativeHeight) => {
                 this.dataDoc.icon = new ImageField(iconFile);
-                this.dataDoc['icon-nativeWidth'] = nativeWidth;
-                this.dataDoc['icon-nativeHeight'] = nativeHeight;
+                this.dataDoc['icon_nativeWidth'] = nativeWidth;
+                this.dataDoc['icon_nativeHeight'] = nativeHeight;
             }
         );
 
@@ -1762,7 +1766,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         appearanceItems.push({ description: (Doc.UserDoc().defaultToFlashcards ? 'Disable' : 'Enable') + ' Flashcard Notes', event: () => (Doc.UserDoc().defaultToFlashcards = !Doc.UserDoc().defaultToFlashcards), icon: 'eye' });
         appearanceItems.push({
             description: `${this.fitContentsToBox ? 'Make Zoomable' : 'Scale to Window'}`,
-            event: () => (this.Document._fitContentsToBox = !this.fitContentsToBox),
+            event: () => (this.Document._freeform_fitContentsToBox = !this.fitContentsToBox),
             icon: !this.fitContentsToBox ? 'expand-arrows-alt' : 'compress-arrows-alt',
         });
         appearanceItems.push({ description: `Pin View`, event: () => TabDocView.PinDoc(this.rootDoc, { pinViewport: MarqueeView.CurViewBounds(this.rootDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' });
@@ -1781,7 +1785,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         !Doc.noviceMode
             ? viewCtrlItems.push({ description: (SnappingManager.GetShowSnapLines() ? 'Hide' : 'Show') + ' Snap Lines', event: () => SnappingManager.SetShowSnapLines(!SnappingManager.GetShowSnapLines()), icon: 'compress-arrows-alt' })
             : null;
-        !Doc.noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? 'Hide' : 'Show') + ' Clusters', event: () => this.updateClusters(!this.Document._useClusters), icon: 'braille' }) : null;
+        !Doc.noviceMode ? viewCtrlItems.push({ description: (this.Document._freeform_useClusters ? 'Hide' : 'Show') + ' Clusters', event: () => this.updateClusters(!this.Document._freeform_useClusters), icon: 'braille' }) : null;
         !viewctrls && ContextMenu.Instance.addItem({ description: 'UI Controls...', subitems: viewCtrlItems, icon: 'eye' });
 
         const options = ContextMenu.Instance.findByDescription('Options...');
@@ -1897,7 +1901,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                         r?.addEventListener('dashDragAutoScroll', this.onDragAutoScroll as any);
                     }}
                     style={{ opacity: this.props.dontRenderDocuments ? 0.7 : undefined }}>
-                    {this.layoutDoc._backgroundGridShow ? (
+                    {this.layoutDoc._freeform_backgroundGrid ? (
                         <div>
                             <CollectionFreeFormBackgroundGrid // bcz : UGHH  don't know why, but if we don't wrap in a div, then PDF's don't render whenn taking snapshot of a dashboard and the background grid is on!!?
                                 PanelWidth={this.props.PanelWidth}
@@ -1937,7 +1941,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const nh = this.nativeHeight;
         const hscale = nh ? this.props.PanelHeight() / nh : 1;
         const wscale = nw ? this.props.PanelWidth() / nw : 1;
-        return wscale < hscale || this.layoutDoc.fitWidth ? wscale : hscale;
+        return wscale < hscale || this.layoutDoc.layout_fitWidth ? wscale : hscale;
     }
     nativeDim = () => this.nativeDimScaling;
 
@@ -2310,7 +2314,7 @@ ScriptingGlobals.add(function sendToBack(doc: Doc) {
 });
 ScriptingGlobals.add(function resetView() {
     SelectionManager.Docs().forEach(doc => {
-        doc._panX = doc._panY = 0;
-        doc._viewScale = 1;
+        doc._freeform_panX = doc._freeform_panY = 0;
+        doc._freeform_scale = 1;
     });
 });
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 11d466b0f..fdff13b54 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -52,8 +52,8 @@ export interface MarqueeViewBounds {
 @observer
 export class MarqueeView extends React.Component<SubCollectionViewProps & MarqueeViewProps> {
     public static CurViewBounds(pinDoc: Doc, panelWidth: number, panelHeight: number) {
-        const ps = NumCast(pinDoc._viewScale, 1);
-        return { left: NumCast(pinDoc._panX) - panelWidth / 2 / ps, top: NumCast(pinDoc._panY) - panelHeight / 2 / ps, width: panelWidth / ps, height: panelHeight / ps };
+        const ps = NumCast(pinDoc._freeform_scale, 1);
+        return { left: NumCast(pinDoc._freeform_panX) - panelWidth / 2 / ps, top: NumCast(pinDoc._freeform_panY) - panelHeight / 2 / ps, width: panelWidth / ps, height: panelHeight / ps };
     }
 
     private _commandExecuted = false;
@@ -110,7 +110,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         const cm = ContextMenu.Instance;
         const [x, y] = this.Transform.transformPoint(this._downX, this._downY);
         if (e.key === '?') {
-            cm.setDefaultItem('?', (str: string) => this.props.addDocTab(Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: 'bing', useCors: true }), OpenWhere.addRight));
+            cm.setDefaultItem('?', (str: string) => this.props.addDocTab(Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: 'bing', data_useCors: true }), OpenWhere.addRight));
 
             cm.displayMenu(this._downX, this._downY, undefined, true);
             e.stopPropagation();
@@ -196,7 +196,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             const rowProto = new Doc();
             rowProto.title = rowProto.Id;
             rowProto._width = 200;
-            rowProto.isPrototype = true;
+            rowProto.isDataDoc = true;
             for (let i = 1; i < ns.length - 1; i++) {
                 const values = ns[i].split('\t');
                 if (values.length === 1 && columns.length > 1) {
@@ -204,7 +204,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
                     continue;
                 }
                 const docDataProto = Doc.MakeDelegate(rowProto);
-                docDataProto.isPrototype = true;
+                docDataProto.isDataDoc = true;
                 columns.forEach((col, i) => (docDataProto[columns[i]] = values.length > i ? (values[i].indexOf(Number(values[i]).toString()) !== -1 ? Number(values[i]) : values[i]) : undefined));
                 if (groupAttr) {
                     docDataProto._group = groupAttr;
@@ -379,10 +379,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
                   Doc.GetProto(doc).data = new List<Doc>(selected);
                   Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform';
                   !this.props.isAnnotationOverlay && Doc.AddFileOrphan(Doc.GetProto(doc));
-                  doc._panX = doc._panY = 0;
+                  doc._freeform_panX = doc._freeform_panY = 0;
                   return doc;
               })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
-        newCollection.system = undefined;
+        newCollection.isSystem = undefined;
         newCollection._width = this.Bounds.width;
         newCollection._height = this.Bounds.height;
         newCollection._isGroup = makeGroup;
@@ -390,8 +390,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         newCollection.enableDragWhenActive = makeGroup;
         newCollection.x = this.Bounds.left;
         newCollection.y = this.Bounds.top;
-        newCollection.fitWidth = true;
-        selected.forEach(d => (d.context = newCollection));
+        newCollection.layout_fitWidth = true;
+        selected.forEach(d => (d.embedContainer = newCollection));
         this.hideMarquee();
         return newCollection;
     });
@@ -516,9 +516,19 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             d.y = NumCast(d.y) - this.Bounds.top;
             return d;
         });
-        const summary = Docs.Create.TextDocument('', { backgroundColor: '#e2ad32', x: this.Bounds.left, y: this.Bounds.top, followLinkToggle: true, _width: 200, _height: 200, _fitContentsToBox: true, _showSidebar: true, title: 'overview' });
+        const summary = Docs.Create.TextDocument('', {
+            backgroundColor: '#e2ad32',
+            x: this.Bounds.left,
+            y: this.Bounds.top,
+            followLinkToggle: true,
+            _width: 200,
+            _height: 200,
+            _layoutFitContentsToBox: true,
+            _layout_showSidebar: true,
+            title: 'overview',
+        });
         const portal = Docs.Create.FreeformDocument(selected, { x: this.Bounds.left + 200, y: this.Bounds.top, isGroup: true, backgroundColor: 'transparent' });
-        DocUtils.MakeLink(summary, portal, { linkRelationship: 'summary of:summarized by' });
+        DocUtils.MakeLink(summary, portal, { link_relationship: 'summary of:summarized by' });
 
         portal.hidden = true;
         this.props.addDocument?.(portal);
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 588affc1c..bcc2ca129 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -79,7 +79,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _selectedCell: [Doc, number] | undefined;
 
     @computed get _selectedDocs() {
-        return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.rootDoc));
+        return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.rootDoc));
     }
 
     @computed get documentKeys() {
@@ -87,7 +87,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get previewWidth() {
-        return NumCast(this.layoutDoc.schemaPreviewWidth);
+        return NumCast(this.layoutDoc.schema_previewWidth);
     }
 
     @computed get tableWidth() {
@@ -95,12 +95,12 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get columnKeys() {
-        return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys);
+        return Cast(this.layoutDoc.schema_columnKeys, listSpec('string'), defaultColumnKeys);
     }
 
     @computed get storedColumnWidths() {
         const widths = NumListCast(
-            this.layoutDoc.columnWidths,
+            this.layoutDoc.schema_columnWidths,
             this.columnKeys.map(() => (this.tableWidth - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length)
         );
 
@@ -243,7 +243,7 @@ export class CollectionSchemaView extends CollectionSubView() {
 
         let currKeys = [...this.columnKeys];
         currKeys[index] = newKey;
-        this.layoutDoc.columnKeys = new List<string>(currKeys);
+        this.layoutDoc.schema_columnKeys = new List<string>(currKeys);
     };
 
     @undoBatch
@@ -257,11 +257,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         const currWidths = this.storedColumnWidths.slice();
         currWidths.splice(0, 0, newColWidth);
         const newDesiredTableWidth = currWidths.reduce((w, cw) => w + cw, 0);
-        this.layoutDoc.columnWidths = new List<number>(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth)));
+        this.layoutDoc.schema_columnWidths = new List<number>(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth)));
 
         let currKeys = this.columnKeys.slice();
         currKeys.splice(0, 0, key);
-        this.layoutDoc.columnKeys = new List<string>(currKeys);
+        this.layoutDoc.schema_columnKeys = new List<string>(currKeys);
     };
 
     @action
@@ -274,11 +274,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         const currWidths = this.storedColumnWidths.slice();
         currWidths.splice(index, 1);
         const newDesiredTableWidth = currWidths.reduce((w, cw) => w + cw, 0);
-        this.layoutDoc.columnWidths = new List<number>(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth)));
+        this.layoutDoc.schema_columnWidths = new List<number>(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth)));
 
         let currKeys = this.columnKeys.slice();
         currKeys.splice(index, 1);
-        this.layoutDoc.columnKeys = new List<string>(currKeys);
+        this.layoutDoc.schema_columnKeys = new List<string>(currKeys);
     };
 
     @action
@@ -317,7 +317,7 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     finishResize = () => {
-        this.layoutDoc.columnWidths = new List<number>(this._displayColumnWidths);
+        this.layoutDoc.schema_columnWidths = new List<number>(this._displayColumnWidths);
         this._displayColumnWidths = undefined;
     };
 
@@ -326,11 +326,11 @@ export class CollectionSchemaView extends CollectionSubView() {
     moveColumn = (fromIndex: number, toIndex: number) => {
         let currKeys = this.columnKeys.slice();
         currKeys.splice(toIndex, 0, currKeys.splice(fromIndex, 1)[0]);
-        this.layoutDoc.columnKeys = new List<string>(currKeys);
+        this.layoutDoc.schema_columnKeys = new List<string>(currKeys);
 
         let currWidths = this.storedColumnWidths.slice();
         currWidths.splice(toIndex, 0, currWidths.splice(fromIndex, 1)[0]);
-        this.layoutDoc.columnWidths = new List<number>(currWidths);
+        this.layoutDoc.schema_columnWidths = new List<number>(currWidths);
     };
 
     @action
@@ -480,14 +480,14 @@ export class CollectionSchemaView extends CollectionSubView() {
         const maxWidth = 1000;
         const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0];
         const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth;
-        this.layoutDoc.schemaPreviewWidth = width;
+        this.layoutDoc.schema_previewWidth = width;
         return false;
     };
 
     @action
     addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
         if (!value && !forceEmptyNote) return false;
-        const newDoc = Docs.Create.TextDocument(value, { title: value, _autoHeight: true });
+        const newDoc = Docs.Create.TextDocument(value, { title: value, _layout_autoHeight: true });
         FormattedTextBox.SelectOnLoad = newDoc[Id];
         FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' ';
         return this.addRow(newDoc) || false;
@@ -500,7 +500,7 @@ export class CollectionSchemaView extends CollectionSubView() {
 
         ContextMenu.Instance.setDefaultItem('::', (name: string): void => {
             Doc.GetProto(this.props.Document)[name] = '';
-            this.addRow(Docs.Create.TextDocument('', { title: name, _autoHeight: true }));
+            this.addRow(Docs.Create.TextDocument('', { title: name, _layout_autoHeight: true }));
         });
         ContextMenu.Instance.displayMenu(x, y, undefined, true);
     };
@@ -837,7 +837,7 @@ export class CollectionSchemaView extends CollectionSubView() {
               });
         return { docs };
     }
-    rowHeightFunc = () => (BoolCast(this.layoutDoc._singleLine) ? CollectionSchemaView._rowSingleLineHeight : CollectionSchemaView._rowHeight);
+    rowHeightFunc = () => (BoolCast(this.layoutDoc._schema_singleLine) ? CollectionSchemaView._rowSingleLineHeight : CollectionSchemaView._rowHeight);
     sortedDocsFunc = () => this.sortedDocs;
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
     screenToLocal = () => this.props.ScreenToLocalTransform().translate(-this.tableWidth, 0);
@@ -968,7 +968,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 hideTitle={true}
                                 hideDocumentButtonBar={true}
                                 hideLinkAnchors={true}
-                                fitWidth={returnTrue}
+                                layout_fitWidth={returnTrue}
                                 scriptContext={this}
                                 canEmbedOnDrag={true}
                             />
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 34631e0b7..45bfe4f77 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -59,7 +59,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     onPointerMove = (e: any) => {
         if (!SnappingManager.GetIsDragging()) return;
-        const dragIsRow = DragManager.docsBeingDragged.some(doc => doc.context === this.schemaDoc); //  this.schemaView?._selectedDocs.has(doc) ?? false;
+        const dragIsRow = DragManager.docsBeingDragged.some(doc => doc.embedContainer === this.schemaDoc); //  this.schemaView?._selectedDocs.has(doc) ?? false;
 
         if (this._ref && dragIsRow) {
             const rect = this._ref.getBoundingClientRect();
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 9f659752a..42bf32475 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -73,7 +73,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             isSelected: returnFalse,
             setHeight: returnFalse,
             select: emptyFunction,
-            dropAction: 'alias' as dropActionType,
+            dropAction: 'embed',
             bringToFront: emptyFunction,
             renderDepth: 1,
             isContentActive: returnFalse,
@@ -83,7 +83,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             addDocTab: SchemaTableCell.addFieldDoc,
             pinToPres: returnZero,
             Document,
-            fieldKey,
+            fieldKey: fieldKey,
             PanelWidth: columnWidth,
             PanelHeight: props.rowHeight,
         };
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index d02a1c4eb..b9d56541a 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -24,12 +24,12 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
     private _menuRef = React.createRef<HTMLDivElement>();
 
     getBackgroundColor = (): string => {
-        const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList);
+        const link_relationshipList = StrListCast(Doc.UserDoc().link_relationshipList);
         const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
         let color = 'white';
         // if this link's relationship property is not default "link", set its color
-        if (linkRelationshipList) {
-            const relationshipIndex = linkRelationshipList.indexOf(this.props.groupType);
+        if (link_relationshipList) {
+            const relationshipIndex = link_relationshipList.indexOf(this.props.groupType);
             const RGBcolor: string = linkColorList[relationshipIndex];
             if (RGBcolor) {
                 //set opacity to 0.25 by modifiying the rgb string
@@ -47,17 +47,18 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
             const sourceDoc =
                 this.props.docView.anchorViewDoc ??
                 (this.props.docView.rootDoc.type === DocumentType.LINK //
-                    ? this.props.docView.props.LayoutTemplateString?.includes('anchor1')
-                        ? DocCast(linkDoc.anchor1)
-                        : DocCast(linkDoc.anchor2)
+                    ? this.props.docView.props.LayoutTemplateString?.includes('link_anchor_1')
+                        ? DocCast(linkDoc.link_anchor_1)
+                        : DocCast(linkDoc.link_anchor_2)
                     : this.props.sourceDoc);
             const destDoc = !sourceDoc
                 ? undefined
                 : this.props.docView.rootDoc.type === DocumentType.LINK
-                ? this.props.docView.props.LayoutTemplateString?.includes('anchor1')
-                    ? DocCast(linkDoc.anchor2)
-                    : DocCast(linkDoc.anchor1)
-                : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) || LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, null).annotationOn === sourceDoc ? Cast(linkDoc.anchor2, Doc, null) : Cast(linkDoc.anchor1, Doc, null));
+                ? this.props.docView.props.LayoutTemplateString?.includes('link_anchor_1')
+                    ? DocCast(linkDoc.link_anchor_2)
+                    : DocCast(linkDoc.link_anchor_1)
+                : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) ||
+                  LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null).annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null));
             return !destDoc || !sourceDoc ? null : (
                 <LinkMenuItem
                     key={linkDoc[Id]}
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 19d6c2ae2..5af05e491 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -8,15 +8,13 @@ import { Cast, DocCast, StrCast } from '../../../fields/Types';
 import { WebField } from '../../../fields/URLField';
 import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils';
 import { DocumentType } from '../../documents/DocumentTypes';
-import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from '../../util/DragManager';
 import { LinkFollower } from '../../util/LinkFollower';
 import { LinkManager } from '../../util/LinkManager';
 import { SelectionManager } from '../../util/SelectionManager';
 import { SettingsManager } from '../../util/SettingsManager';
 import { undoBatch } from '../../util/UndoManager';
-import { MainView } from '../MainView';
-import { DocumentView, OpenWhere } from '../nodes/DocumentView';
+import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView';
 import { LinkDocPreview } from '../nodes/LinkDocPreview';
 import './LinkMenuItem.scss';
 import React = require('react');
@@ -32,7 +30,7 @@ interface LinkMenuItemProps {
     itemHandler?: (doc: Doc) => void;
 }
 
-// drag links and drop link targets (aliasing them if needed)
+// drag links and drop link targets (embedding them if needed)
 export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: DocumentView, downX: number, downY: number, sourceDoc: Doc, specificLinks?: Doc[]) {
     const draggedDocs = (specificLinks ? specificLinks : LinkManager.Links(sourceDoc)).map(link => LinkManager.getOppositeAnchor(link, sourceDoc)).filter(l => l) as Doc[];
 
@@ -45,7 +43,7 @@ export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: Docume
 
         const dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs);
         dragData.canEmbed = true;
-        dragData.dropAction = 'alias';
+        dragData.dropAction = 'embed';
 
         DragManager.StartDocumentDrag([dragEle], dragData, downX, downY, undefined);
     }
@@ -65,9 +63,9 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
 
     @computed get sourceAnchor() {
         const ldoc = this.props.linkDoc;
-        if (this.props.sourceDoc !== ldoc.anchor1 && this.props.sourceDoc !== ldoc.anchor2) {
-            if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor1);
-            if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor2);
+        if (this.props.sourceDoc !== ldoc.link_anchor_1 && this.props.sourceDoc !== ldoc.link_anchor_2) {
+            if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.link_anchor_1);
+            if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.link_anchor_2);
         }
         return this.props.sourceDoc;
     }
@@ -79,7 +77,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
             this,
             e,
             e => {
-                const dragData = new DragManager.DocumentDragData([this.props.linkDoc], 'alias');
+                const dragData = new DragManager.DocumentDragData([this.props.linkDoc], 'embed');
                 dragData.removeDropProperties = ['hidden'];
                 DragManager.StartDocumentDrag([this._editRef.current!], dragData, e.x, e.y);
                 return true;
@@ -89,7 +87,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
                 const trail = DocCast(this.props.docView.rootDoc.presTrail);
                 if (trail) {
                     Doc.ActivePresentation = trail;
-                    MainView.addDocTabFunc(trail, OpenWhere.replaceRight);
+                    DocumentViewInternal.addDocTabFunc(trail, OpenWhere.replaceRight);
                 } else {
                     SelectionManager.SelectView(this.props.docView, false);
                     if ((SettingsManager.propertiesWidth ?? 0) < 100) {
@@ -118,10 +116,10 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
                     this.props.itemHandler?.(this.props.linkDoc);
                 } else {
                     const focusDoc =
-                        Cast(this.props.linkDoc.anchor1, Doc, null)?.annotationOn === this.props.sourceDoc
-                            ? Cast(this.props.linkDoc.anchor1, Doc, null)
-                            : Cast(this.props.linkDoc.anchor2, Doc, null)?.annotationOn === this.props.sourceDoc
-                            ? Cast(this.props.linkDoc.anchor12, Doc, null)
+                        Cast(this.props.linkDoc.link_anchor_1, Doc, null)?.annotationOn === this.props.sourceDoc
+                            ? Cast(this.props.linkDoc.link_anchor_1, Doc, null)
+                            : Cast(this.props.linkDoc.link_anchor_2, Doc, null)?.annotationOn === this.props.sourceDoc
+                            ? Cast(this.props.linkDoc.link_anchor_12, Doc, null)
                             : undefined;
 
                     if (focusDoc) this.props.docView.props.focus(focusDoc, { instant: true });
@@ -149,7 +147,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
 
         return (
             <div className="linkMenu-item" style={{ background: LinkManager.currentLink === this.props.linkDoc ? 'lightBlue' : undefined }}>
-                <div className={'linkMenu-item-content expand-two'}>
+                <div className="linkMenu-item-content expand-two">
                     <div
                         ref={this._drag}
                         className="linkMenu-name" //title="drag to view target. click to customize."
@@ -190,7 +188,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
                                     {this.props.linkDoc.linksToAnnotation && Cast(this.props.destinationDoc.data, WebField)?.url.href === this.props.linkDoc.annotationUri ? 'Annotation in' : ''} {StrCast(title)}
                                 </p>
                             </div>
-                            {!this.props.linkDoc.description ? null : <p className="linkMenu-description">{StrCast(this.props.linkDoc.description)}</p>}
+                            {!this.props.linkDoc.link_description ? null : <p className="linkMenu-description">{StrCast(this.props.linkDoc.link_description)}</p>}
                         </div>
 
                         <div className="linkMenu-item-buttons">
diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx
index 53da880e4..9662b2fea 100644
--- a/src/client/views/linking/LinkRelationshipSearch.tsx
+++ b/src/client/views/linking/LinkRelationshipSearch.tsx
@@ -1,8 +1,8 @@
-import { observer } from "mobx-react";
+import { observer } from 'mobx-react';
 import './LinkEditor.scss';
-import React = require("react");
+import React = require('react');
 
-interface LinkRelationshipSearchProps {
+interface link_relationshipSearchProps {
     results: string[] | undefined;
     display: string;
     //callback fn to set rel + hide dropdown upon setting
@@ -10,48 +10,48 @@ interface LinkRelationshipSearchProps {
     toggleSearch: () => void;
 }
 @observer
-export class LinkRelationshipSearch extends React.Component<LinkRelationshipSearchProps> {
-
+export class link_relationshipSearch extends React.Component<link_relationshipSearchProps> {
     handleResultClick = (e: React.MouseEvent) => {
         const relationship = (e.target as HTMLParagraphElement).textContent;
         if (relationship) {
             this.props.handleRelationshipSearchChange(relationship);
         }
-    }
+    };
 
     handleMouseEnter = () => {
         this.props.toggleSearch();
-    }
+    };
 
     handleMouseLeave = () => {
         this.props.toggleSearch();
-    }
+    };
 
     /**
-     * Render an empty div to increase the height of LinkEditor to accommodate 2+ results 
-    */
+     * Render an empty div to increase the height of LinkEditor to accommodate 2+ results
+     */
     emptyDiv = () => {
-        if (this.props.results && this.props.results.length > 2 && this.props.display === "block") {
-            return <div style={{ height: "50px" }} />;
+        if (this.props.results && this.props.results.length > 2 && this.props.display === 'block') {
+            return <div style={{ height: '50px' }} />;
         }
-    }
+    };
 
     render() {
         return (
             <div className="linkEditor-relationship-dropdown-container">
-                <div className="linkEditor-relationship-dropdown"
-                    style={{ display: this.props.display }}
-                    onMouseEnter={this.handleMouseEnter}
-                    onMouseLeave={this.handleMouseLeave}
-                >
-                    {   // return a dropdown of relationship results if there exist results
-                        this.props.results
-                            ? this.props.results.map(result => {
-                                return <p key={result} onClick={this.handleResultClick}>
-                                    {result}
-                                </p>;
+                <div className="linkEditor-relationship-dropdown" style={{ display: this.props.display }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
+                    {
+                        // return a dropdown of relationship results if there exist results
+                        this.props.results ? (
+                            this.props.results.map(result => {
+                                return (
+                                    <p key={result} onClick={this.handleResultClick}>
+                                        {result}
+                                    </p>
+                                );
                             })
-                            : <p>No matching relationships</p>
+                        ) : (
+                            <p>No matching relationships</p>
+                        )
                     }
                 </div>
 
@@ -60,4 +60,4 @@ export class LinkRelationshipSearch extends React.Component<LinkRelationshipSear
             </div>
         );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 68fb19208..8e83cf121 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -76,7 +76,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         return DateCast(this.dataDoc[this.fieldKey + '-recordingStart'])?.date.getTime();
     }
     @computed get rawDuration() {
-        return NumCast(this.dataDoc[`${this.fieldKey}-duration`]);
+        return NumCast(this.dataDoc[`${this.fieldKey}_duration`]);
     } // bcz: shouldn't be needed since it's computed from audio element
     // mehek: not 100% sure but i think due to the order in which things are loaded this is necessary ^^
     // if you get rid of it and set the value to 0 the timeline and waveform will set their bounds incorrectly
@@ -123,12 +123,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     }
 
     getLinkData(l: Doc) {
-        let la1 = l.anchor1 as Doc;
-        let la2 = l.anchor2 as Doc;
+        let la1 = l.link_anchor_1 as Doc;
+        let la2 = l.link_anchor_2 as Doc;
         const linkTime = this.timeline?.anchorStart(la2) || this.timeline?.anchorStart(la1) || 0;
         if (Doc.AreProtosEqual(la1, this.dataDoc)) {
-            la1 = l.anchor2 as Doc;
-            la2 = l.anchor1 as Doc;
+            la1 = l.link_anchor_2 as Doc;
+            la2 = l.link_anchor_1 as Doc;
         }
         return { la1, la2, linkTime };
     }
@@ -139,7 +139,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 this.rootDoc,
                 this.dataDoc,
                 this.annotationKey,
-                this._ele?.currentTime || Cast(this.props.Document._currentTimecode, 'number', null) || (this.mediaState === media_state.Recording ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined),
+                this._ele?.currentTime || Cast(this.props.Document._layout_currentTimecode, 'number', null) || (this.mediaState === media_state.Recording ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined),
                 undefined,
                 undefined,
                 addAsAnnotation
@@ -155,12 +155,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             this.links
                 .map(l => this.getLinkData(l))
                 .forEach(({ la1, la2, linkTime }) => {
-                    if (linkTime > NumCast(this.layoutDoc._currentTimecode) && linkTime < this._ele!.currentTime) {
+                    if (linkTime > NumCast(this.layoutDoc._layout_currentTimecode) && linkTime < this._ele!.currentTime) {
                         Doc.linkFollowHighlight(la1);
                     }
                 });
-            this.layoutDoc._currentTimecode = this._ele.currentTime;
-            this.timeline?.scrollToTime(NumCast(this.layoutDoc._currentTimecode));
+            this.layoutDoc._layout_currentTimecode = this._ele.currentTime;
+            this.timeline?.scrollToTime(NumCast(this.layoutDoc._layout_currentTimecode));
         }
     };
 
@@ -221,7 +221,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         if (this.mediaState === media_state.Recording) {
             setTimeout(this.updateRecordTime, 30);
             if (!this._paused) {
-                this.layoutDoc._currentTimecode = (new Date().getTime() - this._recordStart - this._pausedTime) / 1000;
+                this.layoutDoc._layout_currentTimecode = (new Date().getTime() - this._recordStart - this._pausedTime) / 1000;
             }
         }
     };
@@ -253,7 +253,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             this._recorder = undefined;
             const now = new Date().getTime();
             this._paused && (this._pausedTime += now - this._pauseStart);
-            this.dataDoc[this.fieldKey + '-duration'] = (now - this._recordStart - this._pausedTime) / 1000;
+            this.dataDoc[this.fieldKey + '_duration'] = (now - this._recordStart - this._pausedTime) / 1000;
             this.mediaState = media_state.Paused;
             this._stream?.getAudioTracks()[0].stop();
             const ind = DocUtils.ActiveRecordings.indexOf(this);
@@ -422,11 +422,11 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             if (!this.layoutDoc.dontAutoPlayFollowedLinks) {
                 this.playFrom(this.timeline?.anchorStart(link) || 0, this.timeline?.anchorEnd(link));
             } else {
-                this._ele!.currentTime = this.layoutDoc._currentTimecode = this.timeline?.anchorStart(link) || 0;
+                this._ele!.currentTime = this.layoutDoc._layout_currentTimecode = this.timeline?.anchorStart(link) || 0;
             }
         } else {
             this.links
-                .filter(l => l.anchor1 === link || l.anchor2 === link)
+                .filter(l => l.link_anchor_1 === link || l.link_anchor_2 === link)
                 .forEach(l => {
                     const { la1, la2 } = this.getLinkData(l);
                     const startTime = this.timeline?.anchorStart(la1) || this.timeline?.anchorStart(la2);
@@ -435,7 +435,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         if (!this.layoutDoc.dontAutoPlayFollowedLinks) {
                             this.playFrom(startTime, endTime);
                         } else {
-                            this._ele!.currentTime = this.layoutDoc._currentTimecode = startTime;
+                            this._ele!.currentTime = this.layoutDoc._layout_currentTimecode = startTime;
                         }
                     }
                 });
@@ -447,7 +447,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     timelineScreenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -AudioBox.topControlsHeight);
 
-    setPlayheadTime = (time: number) => (this._ele!.currentTime = this.layoutDoc._currentTimecode = time);
+    setPlayheadTime = (time: number) => (this._ele!.currentTime = this.layoutDoc._layout_currentTimecode = time);
 
     playing = () => this.mediaState === media_state.Playing;
 
@@ -547,7 +547,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         <div className="record-button" onPointerDown={this._paused ? this.recordPlay : this.recordPause}>
                             <FontAwesomeIcon size="2x" icon={this._paused ? 'play' : 'pause'} />
                         </div>
-                        <div className="record-timecode">{formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode)))}</div>
+                        <div className="record-timecode">{formatTime(Math.round(NumCast(this.layoutDoc._layout_currentTimecode)))}</div>
                     </div>
                 ) : (
                     <div className="audiobox-start-record" onPointerDown={this.Record}>
@@ -623,7 +623,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 {this.audio}
 
                 <div className="audiobox-timecodes">
-                    <div className="timecode-current">{this.timeline && formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this.timeline.clipStart)))}</div>
+                    <div className="timecode-current">{this.timeline && formatTime(Math.round(NumCast(this.layoutDoc._layout_currentTimecode) - NumCast(this.timeline.clipStart)))}</div>
                     {this.miniPlayer ? (
                         <div>/</div>
                     ) : (
@@ -656,6 +656,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 ref={action((r: any) => (this._stackedTimeline = r))}
                 {...this.props}
                 CollectionFreeFormDocumentView={undefined}
+                dataFieldKey={this.fieldKey}
                 fieldKey={this.annotationKey}
                 dictationKey={this.fieldKey + '-dictation'}
                 mediaPath={this.path}
@@ -689,7 +690,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             <audio
                 ref={this.setRef}
                 className={`audiobox-control${this.props.isContentActive() ? '-interactive' : ''}`}
-                onLoadedData={action(e => this._ele?.duration && this._ele?.duration !== Infinity && (this.dataDoc[this.fieldKey + '-duration'] = this._ele.duration))}>
+                onLoadedData={action(e => this._ele?.duration && this._ele?.duration !== Infinity && (this.dataDoc[this.fieldKey + '_duration'] = this._ele.duration))}>
                 <source src={this.path} type="audio/mpeg" />
                 Not supported.
             </audio>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 862d0da8c..6710cee63 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -36,13 +36,13 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         { key: 'x' },
         { key: 'y' },
         { key: '_rotation', val: 0 },
-        { key: '_scrollTop' },
+        { key: '_layout_scrollTop' },
         { key: 'opacity', val: 1 },
         { key: '_currentFrame' },
-        { key: 'viewScale', val: 1 },
-        { key: 'viewScale', val: 1 },
-        { key: 'panX' },
-        { key: 'panY' },
+        { key: 'freeform_scale', val: 1 },
+        { key: 'freeform_scale', val: 1 },
+        { key: 'freeform_panX' },
+        { key: 'freeform_panY' },
     ]; // fields that are configured to be animatable using animation frames
     public static animStringFields = ['backgroundColor', 'color', 'fillColor']; // fields that are configured to be animatable using animation frames
     public static animDataFields = (doc: Doc) => (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames
@@ -154,8 +154,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             CollectionFreeFormDocumentView.animStringFields.forEach(val => (doc[val] = ComputedField.MakeInterpolatedString(val, 'activeFrame', doc, currTimecode)));
             CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => (doc[val] = ComputedField.MakeInterpolatedDataField(val, 'activeFrame', doc, currTimecode)));
             const targetDoc = doc; // data fields, like rtf 'text' exist on the data doc, so
-            //doc !== targetDoc && (targetDoc.context = doc.context); // the computed fields don't see the layout doc -- need to copy the context to the data doc (HACK!!!) and set the activeFrame on the data doc (HACK!!!)
-            targetDoc.activeFrame = ComputedField.MakeFunction('self.context?._currentFrame||0');
+            //doc !== targetDoc && (targetDoc.embedContainer = doc.embedContainer); // the computed fields don't see the layout doc -- need to copy the embedContainer to the data doc (HACK!!!) and set the activeFrame on the data doc (HACK!!!)
+            targetDoc.activeFrame = ComputedField.MakeFunction('self.embedContainer?._currentFrame||0');
             targetDoc.dataTransition = 'inherit';
         });
     }
@@ -202,7 +202,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             PanelWidth: this.panelWidth,
             PanelHeight: this.panelHeight,
         };
-        const isInk = StrCast(this.layoutDoc.layout).includes(InkingStroke.name) && !this.props.LayoutTemplateString && !this.layoutDoc._isInkMask;
+        const isInk = StrCast(this.layoutDoc.layout).includes(InkingStroke.name) && !this.props.LayoutTemplateString && !this.layoutDoc._stroke_isInkMask;
         return (
             <div
                 className="collectionFreeFormDocumentView-container"
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index 70ba7e182..330cc3971 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -48,7 +48,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps>() {
     }
 
     render() {
-        const scaling = Math.min(this.layoutDoc.fitWidth ? 10000 : this.props.PanelHeight() / this.rootDoc[HeightSym](), this.props.PanelWidth() / this.rootDoc[WidthSym]());
+        const scaling = Math.min(this.layoutDoc.layout_fitWidth ? 10000 : this.props.PanelHeight() / this.rootDoc[HeightSym](), this.props.PanelWidth() / this.rootDoc[WidthSym]());
         return (
             <div
                 className={`colorBox-container${this.props.isContentActive() ? '-interactive' : ''}`}
@@ -72,7 +72,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             SetActiveInkWidth(e.target.value);
                             SelectionManager.Views()
                                 .filter(i => StrCast(i.rootDoc.type) === DocumentType.INK)
-                                .map(i => (i.rootDoc.strokeWidth = Number(e.target.value)));
+                                .map(i => (i.rootDoc.stroke_width = Number(e.target.value)));
                         }}
                     />
                 </div>
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index ace388c57..3be2d9a77 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, observable } from 'mobx';
+import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc, Opt } from '../../../fields/Doc';
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
@@ -26,6 +26,13 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
 
     @observable _animating = '';
 
+    @computed get clipWidth() {
+        return NumCast(this.layoutDoc[this.clipWidthKey], 50);
+    }
+    get clipWidthKey() {
+        return '_' + this.props.fieldKey + '_clipWidth';
+    }
+
     componentDidMount() {
         this.props.setContentView?.(this);
     }
@@ -59,7 +66,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                 action(() => {
                     // on click, animate slider movement to the targetWidth
                     this._animating = 'all 200ms';
-                    this.layoutDoc._clipWidth = (targetWidth * 100) / this.props.PanelWidth();
+                    this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this.props.PanelWidth();
                     setTimeout(
                         action(() => (this._animating = '')),
                         200
@@ -71,9 +78,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
 
     @action
     private onPointerMove = ({ movementX }: PointerEvent) => {
-        const width = movementX * this.props.ScreenToLocalTransform().Scale + (NumCast(this.layoutDoc._clipWidth) / 100) * this.props.PanelWidth();
+        const width = movementX * this.props.ScreenToLocalTransform().Scale + (this.clipWidth / 100) * this.props.PanelWidth();
         if (width && width > 5 && width < this.props.PanelWidth()) {
-            this.layoutDoc._clipWidth = (width * 100) / this.props.PanelWidth();
+            this.layoutDoc[this.clipWidthKey] = (width * 100) / this.props.PanelWidth();
         }
         return false;
     };
@@ -101,7 +108,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
     };
 
     render() {
-        const clipWidth = NumCast(this.layoutDoc._clipWidth) + '%';
         const clearButton = (which: string) => {
             return (
                 <div
@@ -143,7 +149,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         };
         const displayBox = (which: string, index: number, cover: number) => {
             return (
-                <div className={`${which}Box-cont`} key={which} style={{ width: this.props.PanelWidth() }} onPointerDown={e => this.registerSliding(e, cover)} ref={ele => this.createDropTarget(ele, which, index)}>
+                <div className={`${index === 0 ? 'before' : 'after'}Box-cont`} key={which} style={{ width: this.props.PanelWidth() }} onPointerDown={e => this.registerSliding(e, cover)} ref={ele => this.createDropTarget(ele, which, index)}>
                     {displayDoc(which)}
                 </div>
             );
@@ -151,16 +157,16 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
 
         return (
             <div className={`comparisonBox${this.props.isContentActive() || SnappingManager.GetIsDragging() ? '-interactive' : ''}` /* change className to easily disable/enable pointer events in CSS */}>
-                {displayBox(this.fieldKey === 'data' ? 'compareBox-after' : `${this.fieldKey}2`, 1, this.props.PanelWidth() - 3)}
-                <div className="clip-div" style={{ width: clipWidth, transition: this._animating, background: StrCast(this.layoutDoc._backgroundColor, 'gray') }}>
-                    {displayBox(this.fieldKey === 'data' ? 'compareBox-before' : `${this.fieldKey}1`, 0, 0)}
+                {displayBox(`${this.fieldKey}_2`, 1, this.props.PanelWidth() - 3)}
+                <div className="clip-div" style={{ width: this.clipWidth + '%', transition: this._animating, background: StrCast(this.layoutDoc._backgroundColor, 'gray') }}>
+                    {displayBox(`${this.fieldKey}_1`, 0, 0)}
                 </div>
 
                 <div
                     className="slide-bar"
                     style={{
-                        left: `calc(${clipWidth} - 0.5px)`,
-                        cursor: NumCast(this.layoutDoc._clipWidth) < 5 ? 'e-resize' : NumCast(this.layoutDoc._clipWidth) / 100 > (this.props.PanelWidth() - 5) / this.props.PanelWidth() ? 'w-resize' : undefined,
+                        left: `calc(${this.clipWidth + '%'} - 0.5px)`,
+                        cursor: this.clipWidth < 5 ? 'e-resize' : this.clipWidth / 100 > (this.props.PanelWidth() - 5) / this.props.PanelWidth() ? 'w-resize' : undefined,
                     }}
                     onPointerDown={e => this.registerSliding(e, this.props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */
                 >
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index eb25d3264..5876efb01 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -3,7 +3,7 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, StrListCast } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
-import { Cast, NumCast, StrCast } from '../../../../fields/Types';
+import { Cast, CsvCast, NumCast, StrCast } from '../../../../fields/Types';
 import { CsvField } from '../../../../fields/URLField';
 import { Docs } from '../../../documents/Documents';
 import { ViewBoxAnnotatableComponent } from '../../DocComponent';
@@ -29,7 +29,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     // @observable private pairs: { [key: string]: FieldResult }[] = [];
     static pairSet = new ObservableMap<string, { [key: string]: string }[]>();
     @computed.struct get pairs() {
-        return DataVizBox.pairSet.get(StrCast(this.rootDoc.fileUpload));
+        return DataVizBox.pairSet.get(CsvCast(this.rootDoc[this.fieldKey]).url.href);
     }
     private _chartRenderer: LineChart | undefined;
     // // another way would be store a schema that defines the type of data we are expecting from an imported doc
@@ -61,7 +61,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     @action
     restoreView = (data: Doc) => {
         const changedView = this.dataVizView !== data.presDataVizView && (this.layoutDoc._dataVizView = data.presDataVizView);
-        const changedAxes = this.axes.join('') !== StrListCast(data.presDataVizAxes).join('') && (this.layoutDoc._dataVizAxes = new List<string>(StrListCast(data.presDataVizAxes)));
+        const changedAxes = this.axes.join('') !== StrListCast(data.presDataVizAxes).join('') && (this.layoutDoc._data_vizAxes = new List<string>(StrListCast(data.presDataVizAxes)));
         const func = () => this._chartRenderer?.restoreView(data);
         if (changedView || changedAxes) {
             setTimeout(func, 100);
@@ -88,14 +88,14 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     };
 
     @computed.struct get axes() {
-        return StrListCast(this.layoutDoc.dataVizAxes);
+        return StrListCast(this.layoutDoc.data_vizAxes);
     }
-    selectAxes = (axes: string[]) => (this.layoutDoc.dataVizAxes = new List<string>(axes));
+    selectAxes = (axes: string[]) => (this.layoutDoc.data_vizAxes = new List<string>(axes));
 
     @computed get selectView() {
         const width = this.props.PanelWidth() * 0.9;
         const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9;
-        const margin = { top: 10, right: 25, bottom: 50, left:25};
+        const margin = { top: 10, right: 25, bottom: 50, left: 25 };
         if (!this.pairs) return 'no data';
         // prettier-ignore
         switch (this.dataVizView) {
@@ -113,10 +113,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     }
 
     fetchData() {
-        if (DataVizBox.pairSet.has(StrCast(this.rootDoc.fileUpload))) return;
-        DataVizBox.pairSet.set(StrCast(this.rootDoc.fileUpload), []);
+        if (DataVizBox.pairSet.has(CsvCast(this.rootDoc[this.fieldKey]).url.href)) return;
+        DataVizBox.pairSet.set(CsvCast(this.rootDoc[this.fieldKey]).url.href, []);
         fetch('/csvData?uri=' + this.dataUrl?.url.href) //
-            .then(res => res.json().then(action(res => !res.errno && DataVizBox.pairSet.set(StrCast(this.rootDoc.fileUpload), res))));
+            .then(res => res.json().then(action(res => !res.errno && DataVizBox.pairSet.set(CsvCast(this.rootDoc[this.fieldKey]).url.href, res))));
     }
 
     // handle changing the view using a button
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 777bf2f66..11f62a61f 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -56,8 +56,8 @@ export class LineChart extends React.Component<LineChartProps> {
     }
     @computed get incomingLinks() {
         return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
-            .filter(link => link.anchor1 !== this.props.rootDoc) // get links where this chart doc is the target of the link
-            .map(link => DocCast(link.anchor1)); // then return the source of the link
+            .filter(link => link.link_anchor_1 !== this.props.rootDoc) // get links where this chart doc is the target of the link
+            .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
     }
     @computed get incomingSelected() {
         return this.incomingLinks // all links that are pointing to this node
@@ -87,7 +87,7 @@ export class LineChart extends React.Component<LineChartProps> {
             { fireImmediately: true }
         );
         this._disposers.annos = reaction(
-            () => DocListCast(this.props.dataDoc[this.props.fieldKey + '-annotations']),
+            () => DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']),
             annotations => {
                 // modify how d3 renders so that anything in this annotations list would be potentially highlighted in some way
                 // could be blue colored to make it look like anchor
@@ -123,7 +123,7 @@ export class LineChart extends React.Component<LineChartProps> {
             element.classList.remove('selected');
         }
     };
-    // gets called whenever the "data-annotations" fields gets updated
+    // gets called whenever the "data_annotations" fields gets updated
     drawAnnotations = (dataX: number, dataY: number, selected?: boolean) => {
         // TODO: nda - can optimize this by having some sort of mapping of the x and y values to the individual circle elements
         // loop through all html elements with class .circle-d1 and find the one that has "data-x" and "data-y" attributes that match the dataX and dataY
@@ -228,15 +228,15 @@ export class LineChart extends React.Component<LineChartProps> {
 
         // creating the x and y scales
         const xScale = scaleCreatorNumerical(xMin, xMax, 0, width);
-        const yScale = scaleCreatorNumerical(0, yMax,height, 0);
+        const yScale = scaleCreatorNumerical(0, yMax, height, 0);
 
         // adding svg
         const margin = this.props.margin;
         const svg = (this._lineChartSvg = d3
             .select(this._lineChartRef.current)
             .append('svg')
-            .attr('width', `${width +margin.left + margin.right}`)
-            .attr('height', `${height + margin.top + margin.bottom }`)
+            .attr('width', `${width + margin.left + margin.right}`)
+            .attr('height', `${height + margin.top + margin.bottom}`)
             .append('g')
             .attr('transform', `translate(${margin.left}, ${margin.top})`));
 
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 0d69ac890..3816bddfa 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -47,17 +47,17 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                     e => {
                                                         const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!;
                                                         const targetCreator = (annotationOn: Doc | undefined) => {
-                                                            const alias = Doc.MakeAlias(this.props.docView?.()!.rootDoc!);
-                                                            alias._dataVizView = DataVizView.LINECHART;
-                                                            alias._dataVizAxes = new List<string>([col, col]);
-                                                            alias.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!;
-                                                            return alias;
+                                                            const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!);
+                                                            embedding._dataVizView = DataVizView.LINECHART;
+                                                            embedding._data_vizAxes = new List<string>([col, col]);
+                                                            embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!;
+                                                            return embedding;
                                                         };
                                                         if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) {
                                                             DragManager.StartAnchorAnnoDrag([header.current!], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, {
                                                                 dragComplete: e => {
                                                                     if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
-                                                                        e.linkDocument.linkDisplay = true;
+                                                                        e.linkDocument.layout_linkDisplay = true;
                                                                         // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc;
                                                                         // e.annoDragData.linkSourceDoc.followLinkZoom = false;
                                                                     }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 76a5ce7b3..348ef910a 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -120,15 +120,15 @@ export class DocumentContentsView extends React.Component<
         select: (ctrl: boolean) => void;
         NativeDimScaling?: () => number;
         setHeight?: (height: number) => void;
-        layoutKey: string;
+        layout_fieldKey: string;
     }
 > {
     @computed get layout(): string {
         TraceMobx();
         if (this.props.LayoutTemplateString) return this.props.LayoutTemplateString;
         if (!this.layoutDoc) return '<p>awaiting layout</p>';
-        if (this.props.layoutKey === 'layout_keyValue') return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString());
-        const layout = Cast(this.layoutDoc[this.layoutDoc === this.props.Document && this.props.layoutKey ? this.props.layoutKey : StrCast(this.layoutDoc.layoutKey, 'layout')], 'string');
+        if (this.props.layout_fieldKey === 'layout_keyValue') return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString());
+        const layout = Cast(this.layoutDoc[this.layoutDoc === this.props.Document && this.props.layout_fieldKey ? this.props.layout_fieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string');
         if (layout === undefined) return this.props.Document.data ? "<FieldView {...props} fieldKey='data' />" : KeyValueBox.LayoutString();
         if (typeof layout === 'string') return layout;
         return '<p>Loading layout</p>';
@@ -140,12 +140,12 @@ export class DocumentContentsView extends React.Component<
     }
     get layoutDoc() {
         // bcz: replaced this with below : is it correct?  change was made to accommodate passing fieldKey's from a layout script
-        // const template: Doc = this.props.LayoutTemplate?.() || Doc.Layout(this.props.Document, this.props.layoutKey ? Cast(this.props.Document[this.props.layoutKey], Doc, null) : undefined);
+        // const template: Doc = this.props.LayoutTemplate?.() || Doc.Layout(this.props.Document, this.props.layout_fieldKey ? Cast(this.props.Document[this.props.layout_fieldKey], Doc, null) : undefined);
         const template: Doc =
             this.props.LayoutTemplate?.() ||
             (this.props.LayoutTemplateString && this.props.Document) ||
-            (this.props.layoutKey && StrCast(this.props.Document[this.props.layoutKey]) && this.props.Document) ||
-            Doc.Layout(this.props.Document, this.props.layoutKey ? Cast(this.props.Document[this.props.layoutKey], Doc, null) : undefined);
+            (this.props.layout_fieldKey && StrCast(this.props.Document[this.props.layout_fieldKey]) && this.props.Document) ||
+            Doc.Layout(this.props.Document, this.props.layout_fieldKey ? Cast(this.props.Document[this.props.layout_fieldKey], Doc, null) : undefined);
         return Doc.expandTemplateLayout(template, this.props.Document);
     }
 
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 47705d53d..d5ca30957 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -52,7 +52,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                         dragComplete: dropEv => {
                             if (this.props.View && dropEv.linkDocument) {
                                 // dropEv.linkDocument equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop
-                                !dropEv.linkDocument.linkRelationship && (Doc.GetProto(dropEv.linkDocument).linkRelationship = 'hyperlink');
+                                !dropEv.linkDocument.link_relationship && (Doc.GetProto(dropEv.linkDocument).link_relationship = 'hyperlink');
                             }
                             linkDrag?.end();
                         },
@@ -142,7 +142,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             } else if (startLink !== endLink) {
                 endLink = endLinkView?.docView?._componentView?.getAnchor?.(true, pinProps) || endLink;
                 startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.(true) || startLink;
-                const linkDoc = DocUtils.MakeLink(startLink, endLink, { linkRelationship: DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined });
+                const linkDoc = DocUtils.MakeLink(startLink, endLink, { link_relationship: DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined });
 
                 LinkManager.currentLink = linkDoc;
 
@@ -197,7 +197,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
         const results = [] as Doc[];
         const filters = this.props.View.props.docFilters();
         Array.from(new Set<Doc>(this.props.View.allLinks)).forEach(link => {
-            if (DocUtils.FilterDocs([link], filters, []).length || DocUtils.FilterDocs([link.anchor2 as Doc], filters, []).length || DocUtils.FilterDocs([link.anchor1 as Doc], filters, []).length) {
+            if (DocUtils.FilterDocs([link], filters, []).length || DocUtils.FilterDocs([link.link_anchor_2 as Doc], filters, []).length || DocUtils.FilterDocs([link.link_anchor_1 as Doc], filters, []).length) {
                 results.push(link);
             }
         });
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ffbde18ca..d8494e58e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -131,7 +131,7 @@ export interface DocComponentView {
     setData?: (data: Field | Promise<RefField | undefined>) => boolean;
     componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null;
     incrementalRendering?: () => void;
-    fitWidth?: () => boolean; // whether the component always fits width (eg, KeyValueBox)
+    layout_fitWidth?: () => boolean; // whether the component always fits width (eg, KeyValueBox)
     overridePointerEvents?: () => 'all' | 'none' | undefined; // if the conmponent overrides the pointer events for the document
     fieldKey?: string;
     annotationKey?: string;
@@ -150,7 +150,7 @@ export interface DocumentViewSharedProps {
     Document: Doc;
     DataDoc?: Doc;
     contentBounds?: () => undefined | { x: number; y: number; r: number; b: number };
-    fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitContentsToBox property on a Document
+    fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document
     suppressSetHeight?: boolean;
     thumbShown?: () => boolean;
     setContentView?: (view: DocComponentView) => any;
@@ -164,11 +164,11 @@ export interface DocumentViewSharedProps {
     styleProvider: Opt<StyleProviderFunc>;
     setTitleFocus?: () => void;
     focus: DocFocusFunc;
-    fitWidth?: (doc: Doc) => boolean | undefined;
+    layout_fitWidth?: (doc: Doc) => boolean | undefined;
     docFilters: () => string[];
     docRangeFilters: () => string[];
     searchFilterDocs: () => Doc[];
-    showTitle?: () => string;
+    layout_showTitle?: () => string;
     whenChildContentsActiveChanged: (isActive: boolean) => void;
     rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected
     addDocTab: (doc: Doc, where: OpenWhere) => boolean;
@@ -275,8 +275,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     public get LayoutFieldKey() {
         return Doc.LayoutFieldKey(this.layoutDoc);
     }
-    @computed get ShowTitle() {
-        return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.ShowTitle) as Opt<string>;
+    @computed get layout_showTitle() {
+        return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.layout_showTitle) as Opt<string>;
     }
     @computed get NativeDimScaling() {
         return this.props.NativeDimScaling?.() || 1;
@@ -305,8 +305,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @computed get headerMargin() {
         return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0;
     }
-    @computed get showCaption() {
-        return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.ShowCaption) || 0;
+    @computed get layout_showCaption() {
+        return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.showCaption) || 0;
     }
     @computed get titleHeight() {
         return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.TitleHeight) || 0;
@@ -315,7 +315,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         return this.props.styleProvider?.(this.Document, this.props, StyleProp.PointerEvents + (this.props.isSelected() ? ':selected' : ''));
     }
     @computed get finalLayoutKey() {
-        return StrCast(this.Document.layoutKey, 'layout');
+        return StrCast(this.Document.layout_fieldKey, 'layout');
     }
     @computed get nativeWidth() {
         return this.props.NativeWidth();
@@ -410,7 +410,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     // switches text input focus to the title bar of the document (and displays the title bar if it hadn't been)
     setTitleFocus = () => {
-        if (!StrCast(this.layoutDoc._showTitle)) this.layoutDoc._showTitle = 'title';
+        if (!StrCast(this.layoutDoc._layout_showTitle)) this.layoutDoc._layout_showTitle = 'title';
         setTimeout(() => this._titleRef.current?.setIsFocused(true)); // use timeout in case title wasn't shown to allow re-render so that titleref will be defined
     };
 
@@ -539,7 +539,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
         if (!Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) {
             this.cleanupPointerEvents();
-            this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'alias') || ((this.Document.dropAction || this.props.dropAction || undefined) as dropActionType));
+            this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'embed') || ((this.Document.dropAction || this.props.dropAction || undefined) as dropActionType));
         }
     };
 
@@ -589,7 +589,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @undoBatch deleteClicked = () => this.props.removeDocument?.(this.props.Document);
     @undoBatch setToggleDetail = () =>
         (this.Document.onClick = ScriptField.MakeScript(
-            `toggleDetail(documentView, "${StrCast(this.Document.layoutKey)
+            `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey)
                 .replace('layout_', '')
                 .replace(/^layout$/, 'detail')}")`,
             { documentView: 'any' }
@@ -611,7 +611,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 if (de.complete.annoDragData && !de.complete.annoDragData.dropDocument) {
                     de.complete.annoDragData.dropDocument = de.complete.annoDragData.dropDocCreator(undefined);
                 }
-                if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.context) {
+                if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.embedContainer) {
                     const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.rootDoc;
                     de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
                 }
@@ -622,12 +622,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @undoBatch
     @action
     makeIntoPortal = () => {
-        const portalLink = this.allLinks.find(d => d.anchor1 === this.props.Document && d.linkRelationship === 'portal to:portal from');
+        const portalLink = this.allLinks.find(d => d.link_anchor_1 === this.props.Document && d.link_relationship === 'portal to:portal from');
         if (!portalLink) {
             DocUtils.MakeLink(
                 this.props.Document,
-                Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), _isLightbox: true, _fitWidth: true, title: StrCast(this.props.Document.title) + ' [Portal]' }),
-                { linkRelationship: 'portal to:portal from' }
+                Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), _isLightbox: true, _layout_fitWidth: true, title: StrCast(this.props.Document.title) + ' [Portal]' }),
+                { link_relationship: 'portal to:portal from' }
             );
         }
         this.Document.followLinkLocation = OpenWhere.lightbox;
@@ -699,7 +699,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             .forEach(item => item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: item.icon as IconProp }));
 
         if (!this.props.Document.isFolder) {
-            const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null);
+            const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layout_fieldKey)], Doc, null);
             const appearance = cm.findByDescription('UI Controls...');
             const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : [];
             !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template   ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' });
@@ -742,7 +742,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
             const funcs: ContextMenuProps[] = [];
             if (!Doc.noviceMode && this.layoutDoc.onDragStart) {
-                funcs.push({ description: 'Drag an Alias', icon: 'edit', event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) });
+                funcs.push({ description: 'Drag an Embedding', icon: 'edit', event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getEmbedding(this.dragFactory)')) });
                 funcs.push({ description: 'Drag a Copy', icon: 'edit', event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)')) });
                 funcs.push({ description: 'Drag Document', icon: 'edit', event: () => (this.layoutDoc.onDragStart = undefined) });
                 cm.addItem({ description: 'OnDrag...', noexpand: true, subitems: funcs, icon: 'asterisk' });
@@ -910,7 +910,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     onClick={this.onClickFunc}
                     focus={this.props.focus}
                     setTitleFocus={this.setTitleFocus}
-                    layoutKey={this.finalLayoutKey}
+                    layout_fieldKey={this.finalLayoutKey}
                 />
                 {this.layoutDoc.hideAllLinks ? null : this.allLinkEndpoints}
             </div>
@@ -922,7 +922,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
         // prettier-ignore
         switch (property.split(':')[0]) {
-            case StyleProp.ShowTitle:     return '';
+            case StyleProp.layout_showTitle:     return '';
             case StyleProp.PointerEvents: return 'none';
             case StyleProp.Highlighting:  return undefined;
         }
@@ -938,22 +938,22 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         TraceMobx();
         return LinkManager.Instance.getAllRelatedLinks(this.rootDoc).filter(
             link =>
-                Doc.AreProtosEqual(link.anchor1 as Doc, this.rootDoc) ||
-                Doc.AreProtosEqual(link.anchor2 as Doc, this.rootDoc) ||
-                ((link.anchor1 as Doc)?.unrendered && Doc.AreProtosEqual((link.anchor1 as Doc)?.annotationOn as Doc, this.rootDoc)) ||
-                ((link.anchor2 as Doc)?.unrendered && Doc.AreProtosEqual((link.anchor2 as Doc)?.annotationOn as Doc, this.rootDoc))
+                Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.rootDoc) ||
+                Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.rootDoc) ||
+                ((link.link_anchor_1 as Doc)?.unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.rootDoc)) ||
+                ((link.link_anchor_2 as Doc)?.unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.rootDoc))
         );
     }
     @computed get allLinks() {
         TraceMobx();
         return LinkManager.Instance.getAllRelatedLinks(this.rootDoc);
     }
-    hideLink = computedFn((link: Doc) => () => (link.linkDisplay = false));
+    hideLink = computedFn((link: Doc) => () => (link.layout_linkDisplay = false));
     @computed get allLinkEndpoints() {
         // the small blue dots that mark the endpoints of links
         TraceMobx();
-        if (this.props.hideLinkAnchors || this.layoutDoc.hideLinkAnchors || this.props.dontRegisterView || this.layoutDoc.unrendered) return null;
-        const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => d.linkDisplay);
+        if (this.props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this.props.dontRegisterView || this.layoutDoc.unrendered) return null;
+        const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => d.layout_linkDisplay);
         return filtered.map(link => (
             <div className="documentView-anchorCont" key={link[Id]}>
                 <DocumentView
@@ -964,14 +964,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     PanelWidth={this.anchorPanelWidth}
                     PanelHeight={this.anchorPanelHeight}
                     dontRegisterView={false}
-                    showTitle={returnEmptyString}
+                    layout_showTitle={returnEmptyString}
                     hideCaptions={true}
                     hideLinkAnchors={true}
-                    fitWidth={returnTrue}
+                    layout_fitWidth={returnTrue}
                     removeDocument={this.hideLink(link)}
                     styleProvider={this.anchorStyleProvider}
                     LayoutTemplate={undefined}
-                    LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(link, this.rootDoc)}`)}
+                    LayoutTemplateString={LinkAnchorBox.LayoutString(`link_anchor_${Doc.LinkEndpoint(link, this.rootDoc)}`)}
                 />
             </div>
         ));
@@ -1046,9 +1046,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @computed get innards() {
         TraceMobx();
         const ffscale = () => this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1;
-        const showTitle = this.ShowTitle?.split(':')[0];
-        const showTitleHover = this.ShowTitle?.includes(':hover');
-        const captionView = !this.showCaption ? null : (
+        const layout_showTitle = this.layout_showTitle?.split(':')[0];
+        const layout_showTitleHover = this.layout_showTitle?.includes(':hover');
+        const captionView = !this.layout_showCaption ? null : (
             <div
                 className="documentView-captionWrapper"
                 style={{
@@ -1060,7 +1060,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     {...this.props}
                     yPadding={10}
                     xPadding={10}
-                    fieldKey={this.showCaption}
+                    fieldKey={this.layout_showCaption}
                     fontSize={12 * Math.max(1, (2 * ffscale()) / 3)}
                     styleProvider={this.captionStyleProvider}
                     dontRegisterView={true}
@@ -1071,27 +1071,27 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 />
             </div>
         );
-        const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc;
+        const targetDoc = layout_showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc;
         const background = StrCast(
             SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.sharingDoc.userColor,
-            Doc.UserDoc().showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : 'rgba(0,0,0,0.4)'
+            Doc.UserDoc().layout_showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : 'rgba(0,0,0,0.4)'
         );
-        const sidebarWidthPercent = +StrCast(this.layoutDoc.sidebarWidthPercent).replace('%', '');
-        const titleView = !showTitle ? null : (
+        const layout_sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', '');
+        const titleView = !layout_showTitle ? null : (
             <div
-                className={`documentView-titleWrapper${showTitleHover ? '-hover' : ''}`}
+                className={`documentView-titleWrapper${layout_showTitleHover ? '-hover' : ''}`}
                 key="title"
                 style={{
                     position: this.headerMargin ? 'relative' : 'absolute',
                     height: this.titleHeight,
-                    width: !this.headerMargin ? `calc(${sidebarWidthPercent || 100}% - 18px)` : (sidebarWidthPercent || 100) + '%', // leave room for annotation button
+                    width: !this.headerMargin ? `calc(${layout_sidebarWidthPercent || 100}% - 18px)` : (layout_sidebarWidthPercent || 100) + '%', // leave room for annotation button
                     color: lightOrDark(background),
                     background,
                     pointerEvents: (!this.disableClickScriptFunc && this.onClickHandler) || this.Document.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
                 }}>
                 <EditableView
                     ref={this._titleRef}
-                    contents={showTitle
+                    contents={layout_showTitle
                         .split(';')
                         .map(field => field.trim())
                         .map(field => targetDoc[field]?.toString())
@@ -1100,27 +1100,27 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     fontSize={10}
                     GetValue={() => {
                         this.props.select(false);
-                        return showTitle.split(';').length === 1 ? showTitle + '=' + Field.toString(targetDoc[showTitle.split(';')[0]] as any as Field) : '#' + showTitle;
+                        return layout_showTitle.split(';').length === 1 ? layout_showTitle + '=' + Field.toString(targetDoc[layout_showTitle.split(';')[0]] as any as Field) : '#' + layout_showTitle;
                     }}
                     SetValue={undoBatch((input: string) => {
                         if (input?.startsWith('#')) {
-                            if (this.props.showTitle) {
-                                this.rootDoc._showTitle = input?.substring(1) ? input.substring(1) : undefined;
+                            if (this.props.layout_showTitle) {
+                                this.rootDoc._layout_showTitle = input?.substring(1) ? input.substring(1) : undefined;
                             } else {
-                                Doc.UserDoc().showTitle = input?.substring(1) ? input.substring(1) : 'creationDate';
+                                Doc.UserDoc().layout_showTitle = input?.substring(1) ? input.substring(1) : 'creationDate';
                             }
                         } else {
-                            var value = input.replace(new RegExp(showTitle + '='), '') as string | number;
-                            if (showTitle !== 'title' && Number(value).toString() === value) value = Number(value);
-                            if (showTitle.includes('Date') || showTitle === 'author') return true;
-                            Doc.SetInPlace(targetDoc, showTitle, value, true);
+                            var value = input.replace(new RegExp(layout_showTitle + '='), '') as string | number;
+                            if (layout_showTitle !== 'title' && Number(value).toString() === value) value = Number(value);
+                            if (layout_showTitle.includes('Date') || layout_showTitle === 'author') return true;
+                            Doc.SetInPlace(targetDoc, layout_showTitle, value, true);
                         }
                         return true;
                     })}
                 />
             </div>
         );
-        return this.props.hideTitle || (!showTitle && !this.showCaption) ? (
+        return this.props.hideTitle || (!layout_showTitle && !this.layout_showCaption) ? (
             this.contents
         ) : (
             <div className="documentView-styleWrapper">
@@ -1319,11 +1319,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     get LayoutFieldKey() {
         return this.docView?.LayoutFieldKey || 'layout';
     }
-    @computed get fitWidth() {
-        return this.docView?._componentView?.fitWidth?.() ?? this.props.fitWidth?.(this.rootDoc) ?? this.layoutDoc?.fitWidth;
+    @computed get layout_fitWidth() {
+        return this.docView?._componentView?.layout_fitWidth?.() ?? this.props.layout_fitWidth?.(this.rootDoc) ?? this.layoutDoc?.layout_fitWidth;
     }
     @computed get anchorViewDoc() {
-        return this.props.LayoutTemplateString?.includes('anchor2') ? DocCast(this.rootDoc['anchor2']) : this.props.LayoutTemplateString?.includes('anchor1') ? DocCast(this.rootDoc['anchor1']) : undefined;
+        return this.props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.rootDoc['link_anchor_2']) : this.props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.rootDoc['link_anchor_1']) : undefined;
     }
     @computed get hideLinkButton() {
         return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkButton + (this.isSelected() ? ':selected' : ''));
@@ -1339,13 +1339,13 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         return Doc.Layout(this.Document, this.props.LayoutTemplate?.());
     }
     @computed get nativeWidth() {
-        return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, !this.fitWidth));
+        return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, !this.layout_fitWidth));
     }
     @computed get nativeHeight() {
-        return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, !this.fitWidth));
+        return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, !this.layout_fitWidth));
     }
     @computed get shouldNotScale() {
-        return (this.fitWidth && !this.nativeWidth) || [CollectionViewType.Docking].includes(this.Document._viewType as any);
+        return (this.layout_fitWidth && !this.nativeWidth) || [CollectionViewType.Docking].includes(this.Document._viewType as any);
     }
     @computed get effectiveNativeWidth() {
         return this.shouldNotScale ? 0 : this.nativeWidth || NumCast(this.layoutDoc.width);
@@ -1356,8 +1356,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     @computed get nativeScaling() {
         if (this.shouldNotScale) return 1;
         const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0;
-        if (this.fitWidth || this.props.PanelHeight() / (this.effectiveNativeHeight || 1) > this.props.PanelWidth() / (this.effectiveNativeWidth || 1)) {
-            return Math.max(minTextScale, this.props.PanelWidth() / (this.effectiveNativeWidth || 1)); // width-limited or fitWidth
+        if (this.layout_fitWidth || this.props.PanelHeight() / (this.effectiveNativeHeight || 1) > this.props.PanelWidth() / (this.effectiveNativeWidth || 1)) {
+            return Math.max(minTextScale, this.props.PanelWidth() / (this.effectiveNativeWidth || 1)); // width-limited or layout_fitWidth
         }
         return Math.max(minTextScale, this.props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled
     }
@@ -1365,7 +1365,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth();
     }
     @computed get panelHeight() {
-        if (this.effectiveNativeHeight && (!this.fitWidth || !this.layoutDoc.nativeHeightUnfrozen)) {
+        if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.nativeHeightUnfrozen)) {
             return Math.min(this.props.PanelHeight(), this.effectiveNativeHeight * this.nativeScaling);
         }
         return this.props.PanelHeight();
@@ -1374,7 +1374,10 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         return this.effectiveNativeWidth ? Math.max(0, (this.props.PanelWidth() - this.effectiveNativeWidth * this.nativeScaling) / 2) : 0;
     }
     @computed get Yshift() {
-        return this.effectiveNativeWidth && this.effectiveNativeHeight && Math.abs(this.Xshift) < 0.001 && (!this.layoutDoc.nativeHeightUnfrozen || (!this.fitWidth && this.effectiveNativeHeight * this.nativeScaling <= this.props.PanelHeight()))
+        return this.effectiveNativeWidth &&
+            this.effectiveNativeHeight &&
+            Math.abs(this.Xshift) < 0.001 &&
+            (!this.layoutDoc.nativeHeightUnfrozen || (!this.layout_fitWidth && this.effectiveNativeHeight * this.nativeScaling <= this.props.PanelHeight()))
             ? Math.max(0, (this.props.PanelHeight() - this.effectiveNativeHeight * this.nativeScaling) / 2)
             : 0;
     }
@@ -1410,10 +1413,10 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             finished?.();
             this.docView && (this.docView._animateScaleTime = animTime);
         });
-        const layoutKey = Cast(this.Document.layoutKey, 'string', null);
-        if (layoutKey !== 'layout_icon') {
+        const layout_fieldKey = Cast(this.Document.layout_fieldKey, 'string', null);
+        if (layout_fieldKey !== 'layout_icon') {
             this.switchViews(true, 'icon', finalFinished);
-            if (layoutKey && layoutKey !== 'layout' && layoutKey !== 'layout_icon') this.Document.deiconifyLayout = layoutKey.replace('layout_', '');
+            if (layout_fieldKey && layout_fieldKey !== 'layout' && layout_fieldKey !== 'layout_icon') this.Document.deiconifyLayout = layout_fieldKey.replace('layout_', '');
         } else {
             const deiconifyLayout = Cast(this.Document.deiconifyLayout, 'string', null);
             this.switchViews(deiconifyLayout ? true : false, deiconifyLayout, finalFinished);
@@ -1433,7 +1436,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         setTimeout(
             action(() => {
                 if (useExistingLayout && custom && this.rootDoc['layout_' + view]) {
-                    this.rootDoc.layoutKey = 'layout_' + view;
+                    this.rootDoc.layout_fieldKey = 'layout_' + view;
                 } else {
                     this.setCustomView(custom, view);
                 }
@@ -1520,7 +1523,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                             width: xshift ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`,
                             height: this.props.forceAutoHeight
                                 ? undefined
-                                : yshift ?? (this.fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`),
+                                : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`),
                         }}>
                         <DocumentViewInternal
                             {...this.props}
@@ -1558,7 +1561,7 @@ ScriptingGlobals.add(function deiconifyViewToLightbox(documentView: DocumentView
 });
 
 ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string) {
-    if (dv.Document.layoutKey === 'layout_' + detailLayoutKeySuffix) dv.switchViews(false, 'layout');
+    if (dv.Document.layout_fieldKey === 'layout_' + detailLayoutKeySuffix) dv.switchViews(false, 'layout');
     else dv.switchViews(true, detailLayoutKeySuffix, undefined, true);
 });
 
@@ -1571,12 +1574,12 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc) {
         const other = LinkManager.getOppositeAnchor(link, linkSource);
         const otherdoc = !other ? undefined : other.annotationOn ? Cast(other.annotationOn, Doc, null) : other;
         if (otherdoc && !collectedLinks?.some(d => Doc.AreProtosEqual(d, otherdoc))) {
-            const alias = Doc.MakeAlias(otherdoc);
-            alias.x = wid;
-            alias.y = 0;
-            alias._lockedPosition = false;
+            const embedding = Doc.MakeEmbedding(otherdoc);
+            embedding.x = wid;
+            embedding.y = 0;
+            embedding._lockedPosition = false;
             wid += otherdoc[WidthSym]();
-            Doc.AddDocToList(Doc.GetProto(linkCollection), 'data', alias);
+            Doc.AddDocToList(Doc.GetProto(linkCollection), 'data', embedding);
         }
     });
     return links;
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index 163c5a9ed..f17ab06e7 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -90,7 +90,7 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
     };
     render() {
         TraceMobx();
-        const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
+        const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
         return (
             <div
                 ref={r => this.updateSize()}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 7eae4e938..85dd779fc 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -50,7 +50,7 @@ export class FieldView extends React.Component<FieldViewProps> {
 
     @computed
     get field(): FieldResult {
-        const { Document, fieldKey } = this.props;
+        const { Document, fieldKey: fieldKey } = this.props;
         return Document[fieldKey];
     }
     render() {
diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx
index b43e359ff..db72209ab 100644
--- a/src/client/views/nodes/FunctionPlotBox.tsx
+++ b/src/client/views/nodes/FunctionPlotBox.tsx
@@ -90,7 +90,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>
         if (ele) {
             this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc);
         }
-        // if (this.autoHeight) this.tryUpdateScrollHeight();
+        // if (this.layout_autoHeight) this.tryUpdateScrollHeight();
     };
     @computed get theGraph() {
         return <div id={`${this._plotId}`} ref={r => r && this.createGraph(r)} style={{ position: 'absolute', width: '100%', height: '100%' }} onPointerDown={e => e.stopPropagation()} />;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index c9be10d3a..7d1d50cc7 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -79,9 +79,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             this._getAnchor?.(this._savedAnnotations, false) ?? // use marquee anchor, otherwise, save zoom/pan as anchor
             Docs.Create.ImageanchorDocument({
                 title: 'ImgAnchor:' + this.rootDoc.title,
-                presPanX: NumCast(this.layoutDoc._panX),
-                presPanY: NumCast(this.layoutDoc._panY),
-                presViewScale: Cast(this.layoutDoc._viewScale, 'number', null),
+                presPanX: NumCast(this.layoutDoc._freeform_panX),
+                presPanY: NumCast(this.layoutDoc._freeform_panY),
+                presViewScale: Cast(this.layoutDoc._freeform_scale, 'number', null),
                 presTransition: 1000,
                 unrendered: true,
                 annotationOn: this.rootDoc,
@@ -99,7 +99,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         this._disposers.sizer = reaction(
             () => ({
                 forceFull: this.props.renderDepth < 1 || this.layoutDoc._showFullRes,
-                scrSize: (this.props.ScreenToLocalTransform().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.rootDoc._viewScale, 1),
+                scrSize: (this.props.ScreenToLocalTransform().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.rootDoc._freeform_scale, 1),
                 selected: this.props.isSelected(),
             }),
             ({ forceFull, scrSize, selected }) => (this._curSuffix = selected ? '_o' : this.fieldKey === 'icon' ? '_m' : forceFull ? '_o' : scrSize < 0.25 ? '_s' : scrSize < 0.5 ? '_m' : scrSize < 0.8 ? '_l' : '_o'),
@@ -116,7 +116,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             { fireImmediately: true }
         );
         this._disposers.scroll = reaction(
-            () => this.layoutDoc._scrollTop,
+            () => this.layoutDoc.layout_scrollTop,
             s_top => {
                 this._forcedScroll = true;
                 !this._ignoreScroll && this._mainCont.current && (this._mainCont.current.scrollTop = NumCast(s_top));
@@ -144,7 +144,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 de.complete.docDragData.droppedDocuments.forEach(
                     action((drop: Doc) => {
                         Doc.AddDocToList(this.dataDoc, this.fieldKey + '-alternates', drop);
-                        this.rootDoc[this.fieldKey + '-usePath'] = 'alternate:hover';
+                        this.rootDoc[this.fieldKey + '_usePath'] = 'alternate:hover';
                         e.stopPropagation();
                     })
                 );
@@ -167,28 +167,28 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     @undoBatch
     setNativeSize = action(() => {
-        const scaling = (this.props.DocumentView?.().props.ScreenToLocalTransform().Scale || 1) / NumCast(this.rootDoc._viewScale, 1);
+        const scaling = (this.props.DocumentView?.().props.ScreenToLocalTransform().Scale || 1) / NumCast(this.rootDoc._freeform_scale, 1);
         const nscale = NumCast(this.props.PanelWidth()) / scaling;
-        const nh = nscale / NumCast(this.dataDoc[this.fieldKey + '-nativeHeight']);
-        const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '-nativeWidth']);
-        this.dataDoc[this.fieldKey + '-nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '-nativeHeight']) * nh;
-        this.dataDoc[this.fieldKey + '-nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '-nativeWidth']) * nh;
-        this.rootDoc._panX = nh * NumCast(this.rootDoc._panX);
-        this.rootDoc._panY = nh * NumCast(this.rootDoc._panY);
-        this.dataDoc._panXMax = this.dataDoc._panXMax ? nh * NumCast(this.dataDoc._panXMax) : undefined;
-        this.dataDoc._panXMin = this.dataDoc._panXMin ? nh * NumCast(this.dataDoc._panXMin) : undefined;
-        this.dataDoc._panYMax = this.dataDoc._panYMax ? nw * NumCast(this.dataDoc._panYMax) : undefined;
-        this.dataDoc._panYMin = this.dataDoc._panYMin ? nw * NumCast(this.dataDoc._panYMin) : undefined;
+        const nh = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']);
+        const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
+        this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nh;
+        this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nh;
+        this.rootDoc._freeform_panX = nh * NumCast(this.rootDoc._freeform_panX);
+        this.rootDoc._freeform_panY = nh * NumCast(this.rootDoc._freeform_panY);
+        this.dataDoc._freeform_panXMax = this.dataDoc._freeform_panXMax ? nh * NumCast(this.dataDoc._freeform_panXMax) : undefined;
+        this.dataDoc._freeform_panXMin = this.dataDoc._freeform_panXMin ? nh * NumCast(this.dataDoc._freeform_panXMin) : undefined;
+        this.dataDoc._freeform_panYMax = this.dataDoc._freeform_panYMax ? nw * NumCast(this.dataDoc._freeform_panYMax) : undefined;
+        this.dataDoc._freeform_panYMin = this.dataDoc._freeform_panYMin ? nw * NumCast(this.dataDoc._freeform_panYMin) : undefined;
     });
     @undoBatch
     rotate = action(() => {
-        const nw = NumCast(this.dataDoc[this.fieldKey + '-nativeWidth']);
-        const nh = NumCast(this.dataDoc[this.fieldKey + '-nativeHeight']);
+        const nw = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
+        const nh = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']);
         const w = this.layoutDoc._width;
         const h = this.layoutDoc._height;
         this.dataDoc[this.fieldKey + '-rotation'] = (NumCast(this.dataDoc[this.fieldKey + '-rotation']) + 90) % 360;
-        this.dataDoc[this.fieldKey + '-nativeWidth'] = nh;
-        this.dataDoc[this.fieldKey + '-nativeHeight'] = nw;
+        this.dataDoc[this.fieldKey + '_nativeWidth'] = nh;
+        this.dataDoc[this.fieldKey + '_nativeHeight'] = nw;
         this.layoutDoc._width = h;
         this.layoutDoc._height = w;
     });
@@ -204,7 +204,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const anchy = NumCast(cropping.y);
         const anchw = NumCast(cropping._width);
         const anchh = NumCast(cropping._height);
-        const viewScale = NumCast(this.rootDoc[this.fieldKey + '-nativeWidth']) / anchw;
+        const viewScale = NumCast(this.rootDoc[this.fieldKey + '_nativeWidth']) / anchw;
         cropping.title = 'crop: ' + this.rootDoc.title;
         cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
         cropping.y = NumCast(this.rootDoc.y);
@@ -213,24 +213,24 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         cropping.onClick = undefined;
         const croppingProto = Doc.GetProto(cropping);
         croppingProto.annotationOn = undefined;
-        croppingProto.isPrototype = true;
+        croppingProto.isDataDoc = true;
         croppingProto.backgroundColor = undefined;
         croppingProto.proto = Cast(this.rootDoc.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
         croppingProto.type = DocumentType.IMG;
         croppingProto.layout = ImageBox.LayoutString('data');
         croppingProto.data = ObjectField.MakeCopy(this.rootDoc[this.fieldKey] as ObjectField);
-        croppingProto['data-nativeWidth'] = anchw;
-        croppingProto['data-nativeHeight'] = anchh;
-        croppingProto.viewScale = viewScale;
-        croppingProto.viewScaleMin = viewScale;
-        croppingProto.panX = anchx / viewScale;
-        croppingProto.panY = anchy / viewScale;
-        croppingProto.panXMin = anchx / viewScale;
-        croppingProto.panXMax = anchw / viewScale;
-        croppingProto.panYMin = anchy / viewScale;
-        croppingProto.panYMax = anchh / viewScale;
+        croppingProto['data_nativeWidth'] = anchw;
+        croppingProto['data_nativeHeight'] = anchh;
+        croppingProto.freeform_scale = viewScale;
+        croppingProto.freeform_scaleMin = viewScale;
+        croppingProto.freeform_panX = anchx / viewScale;
+        croppingProto.freeform_panY = anchy / viewScale;
+        croppingProto.freeform_panXMin = anchx / viewScale;
+        croppingProto.freeform_panXMax = anchw / viewScale;
+        croppingProto.freeform_panYMin = anchy / viewScale;
+        croppingProto.freeform_panYMax = anchh / viewScale;
         if (addCrop) {
-            DocUtils.MakeLink(region, cropping, { linkRelationship: 'cropped image' });
+            DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
             cropping.x = NumCast(this.rootDoc.x) + this.rootDoc[WidthSym]();
             cropping.y = NumCast(this.rootDoc.y);
             this.props.addDocTab(cropping, OpenWhere.inParent);
@@ -312,7 +312,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         return !tags ? null : <img id={'google-tags'} src={'/assets/google_tags.png'} />;
     };
 
-    getScrollHeight = () => (this.props.fitWidth?.(this.rootDoc) !== false && NumCast(this.rootDoc._viewScale, 1) === NumCast(this.rootDoc._viewScaleMin, 1) ? this.nativeSize.nativeHeight : undefined);
+    getScrollHeight = () => (this.props.layout_fitWidth?.(this.rootDoc) !== false && NumCast(this.rootDoc._freeform_scale, 1) === NumCast(this.rootDoc._freeform_scaleMin, 1) ? this.nativeSize.nativeHeight : undefined);
 
     @computed
     private get considerDownloadIcon() {
@@ -358,13 +358,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     @computed get nativeSize() {
         TraceMobx();
-        const nativeWidth = NumCast(this.dataDoc[this.fieldKey + '-nativeWidth'], NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth'], 500));
-        const nativeHeight = NumCast(this.dataDoc[this.fieldKey + '-nativeHeight'], NumCast(this.layoutDoc[this.fieldKey + '-nativeHeight'], 500));
+        const nativeWidth = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth'], 500));
+        const nativeHeight = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc[this.fieldKey + '_nativeHeight'], 500));
         const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + '-nativeOrientation'], 1);
         return { nativeWidth, nativeHeight, nativeOrientation };
     }
     @computed get overlayImageIcon() {
-        const usePath = this.rootDoc[`_${this.fieldKey}-usePath`];
+        const usePath = this.rootDoc[`_${this.fieldKey}_usePath`];
         return (
             <Tooltip
                 title={
@@ -385,7 +385,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 <div
                     className="imageBox-alternateDropTarget"
                     ref={this._overlayIconRef}
-                    onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, e => (this.rootDoc[`_${this.fieldKey}-usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined))}
+                    onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, e => (this.rootDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined))}
                     style={{
                         display: (SnappingManager.GetIsDragging() && DragManager.DocDragData?.canEmbed) || DocListCast(this.dataDoc[this.fieldKey + '-alternates']).length ? 'block' : 'none',
                         width: 'min(10%, 25px)',
@@ -431,7 +431,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             transformOrigin = 'right top';
             transform = `translate(-100%, 0%) rotate(${rotation}deg) scale(${aspect})`;
         }
-        const usePath = this.rootDoc[`_${this.fieldKey}-usePath`];
+        const usePath = this.rootDoc[`_${this.fieldKey}_usePath`];
 
         return (
             <div className="imageBox-cont" onPointerEnter={action(() => (this._isHovering = true))} onPointerLeave={action(() => (this._isHovering = false))} key={this.layoutDoc[Id]} ref={this.createDropTarget} onPointerDown={this.marqueeDown}>
@@ -459,9 +459,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         TraceMobx();
         return <div className="imageBox-annotationLayer" style={{ height: this.props.PanelHeight() }} ref={this._annotationLayer} />;
     }
-    screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop) * this.props.ScreenToLocalTransform().Scale);
+    screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this.props.ScreenToLocalTransform().Scale);
     marqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && NumCast(this.rootDoc._viewScale, 1) <= NumCast(this.rootDoc.viewScaleMin, 1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+        if (!e.altKey && e.button === 0 && NumCast(this.rootDoc._freeform_scale, 1) <= NumCast(this.rootDoc.freeform_scaleMin, 1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
             setupMoveUpEvents(
                 this,
                 e,
@@ -497,9 +497,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 ref={this._mainCont}
                 onScroll={action(e => {
                     if (!this._forcedScroll) {
-                        if (this.layoutDoc._scrollTop || this._mainCont.current?.scrollTop) {
+                        if (this.layoutDoc._layout_scrollTop || this._mainCont.current?.scrollTop) {
                             this._ignoreScroll = true;
-                            this.layoutDoc._scrollTop = this._mainCont.current?.scrollTop;
+                            this.layoutDoc._layout_scrollTop = this._mainCont.current?.scrollTop;
                             this._ignoreScroll = false;
                         }
                     }
@@ -510,7 +510,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     height: this.props.PanelWidth() ? undefined : `100%`,
                     pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined,
                     borderRadius,
-                    overflow: this.layoutDoc.fitWidth || this.props.fitWidth?.(this.rootDoc) ? 'auto' : undefined,
+                    overflow: this.layoutDoc.layout_fitWidth || this.props.layout_fitWidth?.(this.rootDoc) ? 'auto' : undefined,
                 }}>
                 <CollectionFreeFormView
                     ref={this._ffref}
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index f3c8ba62d..88a82e8e6 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -46,15 +46,13 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
     }
     reverseNativeScaling = returnTrue;
     able = returnAlways;
-    fitWidth = returnTrue;
+    layout_fitWidth = returnTrue;
     overridePointerEvents = returnAll;
     onClickScriptDisable = returnAlways;
 
     @observable private rows: KeyValuePair[] = [];
+    @observable _splitPercentage = 50;
 
-    @computed get splitPercentage() {
-        return NumCast(this.props.Document.schemaSplitPercentage, 50);
-    }
     get fieldDocToLayout() {
         return this.props.fieldKey ? DocCast(this.props.Document[this.props.fieldKey], DocCast(this.props.Document)) : this.props.Document;
     }
@@ -147,7 +145,9 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
         const rows: JSX.Element[] = [];
         let i = 0;
         const self = this;
-        for (const key of Object.keys(ids).slice().sort()) {
+        const keys = Object.keys(ids).slice();
+        //for (const key of [...keys.filter(id => id !== 'layout' && !id.includes('_')).sort(), ...keys.filter(id => id === 'layout' || id.includes('_')).sort()]) {
+        for (const key of keys.sort()) {
             rows.push(
                 <KeyValuePair
                     doc={realDoc}
@@ -162,7 +162,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
                             if (el) self.rows.push(el);
                         };
                     })()}
-                    keyWidth={100 - this.splitPercentage}
+                    keyWidth={100 - this._splitPercentage}
                     rowStyle={'keyValueBox-' + (i++ % 2 ? 'oddRow' : 'evenRow')}
                     key={key}
                     keyName={key}
@@ -180,7 +180,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
                         this._keyInput.current!.select();
                         e.stopPropagation();
                     }}
-                    style={{ width: `${100 - this.splitPercentage}%` }}>
+                    style={{ width: `${100 - this._splitPercentage}%` }}>
                     <input style={{ width: '100%' }} ref={this._keyInput} type="text" placeholder="Key" />
                 </td>
                 <td
@@ -189,7 +189,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
                         this._valInput.current!.select();
                         e.stopPropagation();
                     }}
-                    style={{ width: `${this.splitPercentage}%` }}>
+                    style={{ width: `${this._splitPercentage}%` }}>
                     <input style={{ width: '100%' }} ref={this._valInput} type="text" placeholder="Value" onKeyDown={this.onEnterKey} />
                 </td>
             </tr>
@@ -199,7 +199,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
     @action
     onDividerMove = (e: PointerEvent): void => {
         const nativeWidth = this._mainCont.current!.getBoundingClientRect();
-        this.props.Document.schemaSplitPercentage = Math.max(0, 100 - Math.round(((e.clientX - nativeWidth.left) / nativeWidth.width) * 100));
+        this._splitPercentage = Math.max(0, 100 - Math.round(((e.clientX - nativeWidth.left) / nativeWidth.width) * 100));
     };
     @action
     onDividerUp = (e: PointerEvent): void => {
@@ -216,7 +216,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
     getFieldView = async () => {
         const rows = this.rows.filter(row => row.isChecked);
         if (rows.length > 1) {
-            const parent = Docs.Create.StackingDocument([], { _autoHeight: true, _width: 300, title: `field views for ${DocCast(this.props.Document.data).title}`, _chromeHidden: true });
+            const parent = Docs.Create.StackingDocument([], { _layout_autoHeight: true, _width: 300, title: `field views for ${DocCast(this.props.Document.data).title}`, _chromeHidden: true });
             for (const row of rows) {
                 const field = this.createFieldView(DocCast(this.props.Document.data), row);
                 field && Doc.AddDocToList(parent, 'data', field);
@@ -229,9 +229,9 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
 
     createFieldView = (templateDoc: Doc, row: KeyValuePair) => {
         const metaKey = row.props.keyName;
-        const fieldTemplate = Doc.IsDelegateField(templateDoc, metaKey) ? Doc.MakeDelegate(templateDoc) : Doc.MakeAlias(templateDoc);
+        const fieldTemplate = Doc.IsDelegateField(templateDoc, metaKey) ? Doc.MakeDelegate(templateDoc) : Doc.MakeEmbedding(templateDoc);
         fieldTemplate.title = metaKey;
-        fieldTemplate.fitWidth = true;
+        fieldTemplate.layout_fitWidth = true;
         fieldTemplate._xMargin = 10;
         fieldTemplate._yMargin = 10;
         fieldTemplate._width = 100;
@@ -284,8 +284,8 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
 
     render() {
         const dividerDragger =
-            this.splitPercentage === 0 ? null : (
-                <div className="keyValueBox-dividerDragger" style={{ transform: `translate(calc(${100 - this.splitPercentage}% - 5px), 0px)` }}>
+            this._splitPercentage === 0 ? null : (
+                <div className="keyValueBox-dividerDragger" style={{ transform: `translate(calc(${100 - this._splitPercentage}% - 5px), 0px)` }}>
                     <div className="keyValueBox-dividerDraggerThumb" onPointerDown={this.onDividerDown} />
                 </div>
             );
@@ -295,10 +295,10 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
                 <table className="keyValueBox-table">
                     <tbody className="keyValueBox-tbody">
                         <tr className="keyValueBox-header">
-                            <th className="keyValueBox-key" style={{ width: `${100 - this.splitPercentage}%` }} ref={this._keyHeader} onPointerDown={SetupDrag(this._keyHeader, this.getFieldView)}>
+                            <th className="keyValueBox-key" style={{ width: `${100 - this._splitPercentage}%` }} ref={this._keyHeader} onPointerDown={SetupDrag(this._keyHeader, this.getFieldView)}>
                                 Key
                             </th>
-                            <th className="keyValueBox-fields" style={{ width: `${this.splitPercentage}%` }}>
+                            <th className="keyValueBox-fields" style={{ width: `${this._splitPercentage}%` }}>
                                 Fields
                             </th>
                         </tr>
diff --git a/src/client/views/nodes/KeyValuePair.scss b/src/client/views/nodes/KeyValuePair.scss
index 57d36932e..2b4867321 100644
--- a/src/client/views/nodes/KeyValuePair.scss
+++ b/src/client/views/nodes/KeyValuePair.scss
@@ -19,6 +19,7 @@
             position: relative;
             margin: 0;
         }
+        .keyValuePair-keyFieldMod,
         .keyValuePair-keyField {
             width: 100%;
             margin-left: 20px;
@@ -27,6 +28,9 @@
             overflow: auto;
             display: inline;
         }
+        .keyValuePair-keyFieldMod {
+            margin-left: 35px;
+        }
     }
 }
 .keyValuePair-td-value {
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 85641124f..509bb667e 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -66,7 +66,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             isSelected: returnFalse,
             setHeight: returnFalse,
             select: emptyFunction,
-            dropAction: 'alias',
+            dropAction: 'embed',
             bringToFront: emptyFunction,
             renderDepth: 1,
             isContentActive: returnFalse,
@@ -108,8 +108,8 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
                             })}>
                             X
                         </button>
-                        <input className={'keyValuePair-td-key-check'} type="checkbox" style={hover} onChange={this.handleCheck} ref={this.checkbox} />
-                        <div className="keyValuePair-keyField" style={{ color: keyStyle }}>
+                        <input className="keyValuePair-td-key-check" type="checkbox" style={hover} onChange={this.handleCheck} ref={this.checkbox} />
+                        <div className={`keyValuePair-keyField${props.fieldKey.includes('_') ? 'Mod' : ''}`} style={{ color: keyStyle }}>
                             {'('.repeat(parenCount)}
                             {props.fieldKey}
                             {')'.repeat(parenCount)}
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 916458dfd..32026ea9c 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -37,7 +37,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
     }
 
     getTitle() {
-        return this.rootDoc['title-custom'] ? StrCast(this.rootDoc.title) : this.props.label ? this.props.label : typeof this.rootDoc[this.fieldKey] === 'string' ? StrCast(this.rootDoc[this.fieldKey]) : StrCast(this.rootDoc.title);
+        return this.rootDoc.title_custom ? StrCast(this.rootDoc.title) : this.props.label ? this.props.label : typeof this.rootDoc[this.fieldKey] === 'string' ? StrCast(this.rootDoc[this.fieldKey]) : StrCast(this.rootDoc.title);
     }
 
     protected createDropTarget = (ele: HTMLDivElement) => {
@@ -82,7 +82,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
         return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
     }
 
-    fitTextToBox = (r: any): any => {
+    fitTextToBox = (r: any) => {
         const singleLine = BoolCast(this.rootDoc._singleLine, true);
         const params = {
             rotateText: null,
@@ -141,9 +141,9 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
                         paddingBottom: NumCast(this.rootDoc._yPadding),
                         width: this.props.PanelWidth(),
                         height: this.props.PanelHeight(),
-                        whiteSpace: boxParams.singleLine ? 'pre' : 'pre-wrap',
+                        whiteSpace: typeof boxParams !== 'number' && boxParams.singleLine ? 'pre' : 'pre-wrap',
                     }}>
-                    <span style={{ width: boxParams.singleLine ? '' : '100%' }} ref={action((r: any) => this.fitTextToBox(r))}>
+                    <span style={{ width: typeof boxParams !== 'number' && boxParams.singleLine ? '' : '100%' }} ref={action((r: any) => this.fitTextToBox(r))}>
                         {label.startsWith('#') ? null : label.replace(/([^a-zA-Z])/g, '$1\u200b')}
                     </span>
                 </div>
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 31f1775e5..f38ef634c 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -46,14 +46,14 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const separation = Math.sqrt((pt[0] - e.clientX) * (pt[0] - e.clientX) + (pt[1] - e.clientY) * (pt[1] - e.clientY));
             if (separation > 100) {
                 const dragData = new DragManager.DocumentDragData([this.rootDoc]);
-                dragData.dropAction = 'alias';
-                dragData.removeDropProperties = ['anchor1_x', 'anchor1_y', 'anchor2_x', 'anchor2_y', 'onClick'];
+                dragData.dropAction = 'embed';
+                dragData.removeDropProperties = ['link_anchor_1_x', 'link_anchor_1_y', 'link_anchor_2_x', 'link_anchor_2_y', 'onClick'];
                 DragManager.StartDocumentDrag([this._ref.current!], dragData, pt[0], pt[1]);
                 return true;
             } else {
                 this.rootDoc[this.fieldKey + '_x'] = ((pt[0] - bounds.left) / bounds.width) * 100;
                 this.rootDoc[this.fieldKey + '_y'] = ((pt[1] - bounds.top) / bounds.height) * 100;
-                this.rootDoc.linkAutoMove = false;
+                this.rootDoc.layout_autoMoveAnchors = false;
             }
         }
         return false;
@@ -67,10 +67,14 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const x = NumCast(this.rootDoc[this.fieldKey + '_x'], 100);
         const y = NumCast(this.rootDoc[this.fieldKey + '_y'], 100);
         const background = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.BackgroundColor + ':anchor');
-        const anchor = this.fieldKey === 'anchor1' ? 'anchor2' : 'anchor1';
-        const anchorScale = !this.dataDoc[this.fieldKey + '-useLinkSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25;
+        const anchor = this.fieldKey === 'link_anchor_1' ? 'link_anchor_2' : 'link_anchor_1';
+        const anchorScale = !this.dataDoc[this.fieldKey + '_useLinkSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25;
         const targetTitle = StrCast((this.dataDoc[anchor] as Doc)?.title);
-        const selView = SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('anchor1') ? 'anchor1' : SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('anchor2') ? 'anchor2' : '';
+        const selView = SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('link_anchor_1')
+            ? 'link_anchor_1'
+            : SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('link_anchor_2')
+            ? 'link_anchor_2'
+            : '';
         return (
             <div
                 ref={this._ref}
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 46ccdecae..710d41471 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -9,7 +9,7 @@ import './LinkBox.scss';
 
 @observer
 export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
-    public static LayoutString(fieldKey: string) {
+    public static LayoutString(fieldKey: string = 'link') {
         return FieldView.LayoutString(LinkBox, fieldKey);
     }
 
@@ -23,7 +23,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
             <div className={`linkBox-container${this.props.isContentActive() ? '-interactive' : ''}`} style={{ background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor) }}>
                 <ComparisonBox
                     {...this.props}
-                    fieldKey="anchor"
+                    fieldKey="link_anchor"
                     setHeight={emptyFunction}
                     dontRegisterView={true}
                     renderDepth={this.props.renderDepth + 1}
diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx
index 91bd505c5..c45045a8a 100644
--- a/src/client/views/nodes/LinkDescriptionPopup.tsx
+++ b/src/client/views/nodes/LinkDescriptionPopup.tsx
@@ -24,7 +24,7 @@ export class LinkDescriptionPopup extends React.Component<{}> {
     onDismiss = (add: boolean) => {
         LinkDescriptionPopup.descriptionPopup = false;
         if (add) {
-            LinkManager.currentLink && (Doc.GetProto(LinkManager.currentLink).description = this.description);
+            LinkManager.currentLink && (Doc.GetProto(LinkManager.currentLink).link_description = this.description);
         }
     };
 
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index c58b5dd8c..c6172ee01 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -58,13 +58,13 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
         var linkTarget = this.props.linkDoc;
         this._linkSrc = this.props.linkSrc;
         this._linkDoc = this.props.linkDoc;
-        const anchor1 = this._linkDoc?.anchor1 as Doc;
-        const anchor2 = this._linkDoc?.anchor2 as Doc;
-        if (anchor1 && anchor2) {
-            linkTarget = Doc.AreProtosEqual(anchor1, this._linkSrc) || Doc.AreProtosEqual(anchor1?.annotationOn as Doc, this._linkSrc) ? anchor2 : anchor1;
+        const link_anchor_1 = this._linkDoc?.link_anchor_1 as Doc;
+        const link_anchor_2 = this._linkDoc?.link_anchor_2 as Doc;
+        if (link_anchor_1 && link_anchor_2) {
+            linkTarget = Doc.AreProtosEqual(link_anchor_1, this._linkSrc) || Doc.AreProtosEqual(link_anchor_1?.annotationOn as Doc, this._linkSrc) ? link_anchor_2 : link_anchor_1;
         }
         if (linkTarget?.annotationOn && linkTarget?.type !== DocumentType.RTF) {
-            // want to show annotation context document if annotation is not text
+            // want to show annotation embedContainer document if annotation is not text
             linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => (this._markerTargetDoc = this._targetDoc = anno)));
         } else {
             this._markerTargetDoc = this._targetDoc = linkTarget;
@@ -111,7 +111,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                     action(anchor => {
                         if (anchor instanceof Doc && LinkManager.Links(anchor).length) {
                             this._linkDoc = this._linkDoc ?? LinkManager.Links(anchor)[0];
-                            const automaticLink = this._linkDoc.linkRelationship === LinkManager.AutoKeywords;
+                            const automaticLink = this._linkDoc.link_relationship === LinkManager.AutoKeywords;
                             if (automaticLink) {
                                 // automatic links specify the target in the link info, not the source
                                 const linkTarget = anchor;
@@ -175,7 +175,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
         } else if (this.props.hrefs?.length) {
             const webDoc =
                 Array.from(SearchBox.staticSearchCollection(Doc.MyFilesystem, this.props.hrefs[0]).keys()).lastElement() ??
-                Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, useCors: true });
+                Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, data_useCors: true });
             this.props.docProps?.addDocTab(webDoc, OpenWhere.lightbox);
         }
     };
@@ -208,7 +208,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                 </div>
                 <div className="linkDocPreview-title" style={{ pointerEvents: 'all' }}>
                     {StrCast(this._markerTargetDoc.title).length > 16 ? StrCast(this._markerTargetDoc.title).substr(0, 16) + '...' : StrCast(this._markerTargetDoc.title)}
-                    <p className="linkDocPreview-description"> {StrCast(this._linkDoc.description)}</p>
+                    <p className="linkDocPreview-description"> {StrCast(this._linkDoc.link_description)}</p>
                 </div>
                 <div className="linkDocPreview-buttonBar" style={{ float: 'right' }}>
                     <Tooltip title={<div className="dash-tooltip">Next Link</div>} placement="top">
@@ -263,7 +263,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             isDocumentActive={returnFalse}
                             isContentActive={returnFalse}
                             addDocument={returnFalse}
-                            showTitle={returnEmptyString}
+                            layout_showTitle={returnEmptyString}
                             removeDocument={returnFalse}
                             addDocTab={returnFalse}
                             pinToPres={returnFalse}
@@ -278,7 +278,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             pointerEvents={returnNone}
                             focus={emptyFunction}
                             whenChildContentsActiveChanged={returnFalse}
-                            ignoreAutoHeight={true} // need to ignore autoHeight otherwise autoHeight text boxes will expand beyond the preview panel size.
+                            ignoreAutoHeight={true} // need to ignore layout_autoHeight otherwise layout_autoHeight text boxes will expand beyond the preview panel size.
                             bringToFront={returnFalse}
                             NativeWidth={Doc.NativeWidth(this._targetDoc) ? () => Doc.NativeWidth(this._targetDoc) : undefined}
                             NativeHeight={Doc.NativeHeight(this._targetDoc) ? () => Doc.NativeHeight(this._targetDoc) : undefined}
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 36be7d257..9b0fddce4 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -98,7 +98,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return FieldView.LayoutString(MapBox, fieldKey);
     }
     public get SidebarKey() {
-        return this.fieldKey + '-sidebar';
+        return this.fieldKey + '_sidebar';
     }
     private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void);
     @computed get inlineTextAnnotations() {
@@ -126,7 +126,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     @observable _showSidebar = false;
     @computed get SidebarShown() {
-        return this._showSidebar || this.layoutDoc._showSidebar ? true : false;
+        return this._showSidebar || this.layoutDoc._layout_showSidebar ? true : false;
     }
 
     static _canAnnotate = true;
@@ -267,7 +267,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         setTimeout(() => {
             if (this._loadPending && this._map.getBounds()) {
                 this._loadPending = false;
-                this.layoutDoc.fitContentsToBox && this.fitBounds(this._map);
+                this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
             }
         }, 250);
         // listener to addmarker event
@@ -282,7 +282,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     centered = () => {
         if (this._loadPending && this._map.getBounds()) {
             this._loadPending = false;
-            this.layoutDoc.fitContentsToBox && this.fitBounds(this._map);
+            this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
         }
         this.dataDoc.mapLat = this._map.getCenter()?.lat();
         this.dataDoc.mapLng = this._map.getCenter()?.lng();
@@ -292,7 +292,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     zoomChanged = () => {
         if (this._loadPending && this._map.getBounds()) {
             this._loadPending = false;
-            this.layoutDoc.fitContentsToBox && this.fitBounds(this._map);
+            this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
         }
         this.dataDoc.mapZoom = this._map.getZoom();
     };
@@ -327,7 +327,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      */
     sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
         console.log('print all sidebar Docs');
-        if (!this.layoutDoc._showSidebar) this.toggleSidebar();
+        if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
         const docs = doc instanceof Doc ? [doc] : doc;
         docs.forEach(doc => {
             if (doc.lat !== undefined && doc.lng !== undefined) {
@@ -351,7 +351,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      * @returns
      */
     sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
-        if (this.layoutDoc._showSidebar) this.toggleSidebar();
+        if (this.layoutDoc._layout_showSidebar) this.toggleSidebar();
         const docs = doc instanceof Doc ? [doc] : doc;
         return this.removeDocument(doc, sidebarKey);
     };
@@ -375,11 +375,11 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     if (this.sidebarWidth() + localDelta[0] > 0) {
                         this._showSidebar = true;
                         this.layoutDoc._width = fullWidth + localDelta[0];
-                        this.layoutDoc._sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
+                        this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
                     } else {
                         this._showSidebar = false;
                         this.layoutDoc._width = mapWidth;
-                        this.layoutDoc._sidebarWidthPercent = '0%';
+                        this.layoutDoc._layout_sidebarWidthPercent = '0%';
                     }
                     return false;
                 }),
@@ -388,12 +388,12 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         );
     };
 
-    sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
-    @computed get sidebarWidthPercent() {
-        return StrCast(this.layoutDoc._sidebarWidthPercent, '0%');
+    sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
+    @computed get layout_sidebarWidthPercent() {
+        return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '-backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
 
     /**
@@ -453,7 +453,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 title="Toggle Sidebar"
                 style={{
                     display: !this.props.isContentActive() ? 'none' : undefined,
-                    top: StrCast(this.rootDoc._showTitle) === 'title' ? 20 : 5,
+                    top: StrCast(this.rootDoc._layout_showTitle) === 'title' ? 20 : 5,
                     backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
                 }}
                 onPointerDown={this.sidebarBtnDown}>
@@ -467,8 +467,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     toggleSidebar = () => {
         //1.2 * w * ? = .2 * w      .2/1.2
         const prevWidth = this.sidebarWidth();
-        this.layoutDoc._showSidebar = (this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%';
-        this.layoutDoc._width = this.layoutDoc._showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
+        this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%';
+        this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
     };
 
     sidebarDown = (e: React.PointerEvent) => {
@@ -476,8 +476,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
     sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => {
         const bounds = this._ref.current!.getBoundingClientRect();
-        this.layoutDoc._sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%';
-        this.layoutDoc._showSidebar = this.layoutDoc._sidebarWidthPercent !== '0%';
+        this.layoutDoc._layout_sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%';
+        this.layoutDoc._layout_showSidebar = this.layoutDoc._layout_sidebarWidthPercent !== '0%';
         e.preventDefault();
         return false;
     };
@@ -548,7 +548,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
-    scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop));
+    scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
     transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
     opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
     infoWidth = () => this.props.PanelWidth() / 5;
@@ -616,7 +616,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         //     zoom: 15,
                         // });
                     }}
-                    style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
+                    style={{ width: `calc(100% - ${this.layout_sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
                     <div style={{ mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div>
                     {renderAnnotations(this.opaqueFilter)}
                     {SnappingManager.GetIsDragging() ? null : renderAnnotations()}
@@ -667,7 +667,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     )}
                 </div>
                 {/* </LoadScript > */}
-                <div className="mapBox-sidebar" style={{ position: 'absolute', right: 0, height: '100%', width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+                <div className="mapBox-sidebar" style={{ position: 'absolute', right: 0, height: '100%', width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
                     <SidebarAnnos
                         ref={this._sidebarRef}
                         {...this.props}
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index 37f9bad9e..9354f9639 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -95,7 +95,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return FieldView.LayoutString(MapBox2, fieldKey);
     }
     public get SidebarKey() {
-        return this.fieldKey + '-sidebar';
+        return this.fieldKey + '_sidebar';
     }
     private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void);
     @computed get inlineTextAnnotations() {
@@ -123,7 +123,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     @observable _showSidebar = false;
     @computed get SidebarShown() {
-        return this._showSidebar || this.layoutDoc._showSidebar ? true : false;
+        return this._showSidebar || this.layoutDoc._layout_showSidebar ? true : false;
     }
 
     static _canAnnotate = true;
@@ -264,7 +264,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         setTimeout(() => {
             if (this._loadPending && this._map.getBounds()) {
                 this._loadPending = false;
-                this.layoutDoc.fitContentsToBox && this.fitBounds(this._map);
+                this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
             }
         }, 250);
         // listener to addmarker event
@@ -279,7 +279,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     centered = () => {
         if (this._loadPending && this._map.getBounds()) {
             this._loadPending = false;
-            this.layoutDoc.fitContentsToBox && this.fitBounds(this._map);
+            this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
         }
         this.dataDoc.mapLat = this._map.getCenter()?.lat();
         this.dataDoc.mapLng = this._map.getCenter()?.lng();
@@ -289,7 +289,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     zoomChanged = () => {
         if (this._loadPending && this._map.getBounds()) {
             this._loadPending = false;
-            this.layoutDoc.fitContentsToBox && this.fitBounds(this._map);
+            this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
         }
         this.dataDoc.mapZoom = this._map.getZoom();
     };
@@ -324,7 +324,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      */
     sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
         console.log('print all sidebar Docs');
-        if (!this.layoutDoc._showSidebar) this.toggleSidebar();
+        if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
         const docs = doc instanceof Doc ? [doc] : doc;
         docs.forEach(doc => {
             if (doc.lat !== undefined && doc.lng !== undefined) {
@@ -348,7 +348,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
      * @returns
      */
     sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
-        if (this.layoutDoc._showSidebar) this.toggleSidebar();
+        if (this.layoutDoc._layout_showSidebar) this.toggleSidebar();
         const docs = doc instanceof Doc ? [doc] : doc;
         return this.removeDocument(doc, sidebarKey);
     };
@@ -372,11 +372,11 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     if (this.sidebarWidth() + localDelta[0] > 0) {
                         this._showSidebar = true;
                         this.layoutDoc._width = fullWidth + localDelta[0];
-                        this.layoutDoc._sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
+                        this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
                     } else {
                         this._showSidebar = false;
                         this.layoutDoc._width = mapWidth;
-                        this.layoutDoc._sidebarWidthPercent = '0%';
+                        this.layoutDoc._layout_sidebarWidthPercent = '0%';
                     }
                     return false;
                 }),
@@ -385,12 +385,12 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         );
     };
 
-    sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
-    @computed get sidebarWidthPercent() {
-        return StrCast(this.layoutDoc._sidebarWidthPercent, '0%');
+    sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
+    @computed get layout_sidebarWidthPercent() {
+        return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '-backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
 
     /**
@@ -450,7 +450,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 title="Toggle Sidebar"
                 style={{
                     display: !this.props.isContentActive() ? 'none' : undefined,
-                    top: StrCast(this.rootDoc._showTitle) === 'title' ? 20 : 5,
+                    top: StrCast(this.rootDoc._layout_showTitle) === 'title' ? 20 : 5,
                     backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
                 }}
                 onPointerDown={this.sidebarBtnDown}>
@@ -464,8 +464,8 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     toggleSidebar = () => {
         //1.2 * w * ? = .2 * w      .2/1.2
         const prevWidth = this.sidebarWidth();
-        this.layoutDoc._showSidebar = (this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%';
-        this.layoutDoc._width = this.layoutDoc._showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
+        this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%';
+        this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
     };
 
     sidebarDown = (e: React.PointerEvent) => {
@@ -473,8 +473,8 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
     sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => {
         const bounds = this._ref.current!.getBoundingClientRect();
-        this.layoutDoc._sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%';
-        this.layoutDoc._showSidebar = this.layoutDoc._sidebarWidthPercent !== '0%';
+        this.layoutDoc._layout_sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%';
+        this.layoutDoc._layout_showSidebar = this.layoutDoc._layout_sidebarWidthPercent !== '0%';
         e.preventDefault();
         return false;
     };
@@ -545,7 +545,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
-    scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop));
+    scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
     transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
     opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
     infoWidth = () => this.props.PanelWidth() / 5;
@@ -566,7 +566,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     onPointerDown={async e => {
                         e.button === 0 && !e.ctrlKey && e.stopPropagation();
                     }}
-                    style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
+                    style={{ width: `calc(100% - ${this.layout_sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
                     <div style={{ mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div>
                     {renderAnnotations(this.opaqueFilter)}
                     {SnappingManager.GetIsDragging() ? null : renderAnnotations()}
@@ -616,7 +616,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     )}
                 </div>
                 {/* </LoadScript > */}
-                <div className="MapBox2-sidebar" style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+                <div className="MapBox2-sidebar" style={{ width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
                     <SidebarAnnos
                         ref={this._sidebarRef}
                         {...this.props}
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index 7b437c7de..bc57148dc 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -32,7 +32,7 @@ export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & Vi
 
     addNoteClick = (e: React.PointerEvent) => {
         setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => {
-            const newBox = Docs.Create.TextDocument('Note', { _autoHeight: true });
+            const newBox = Docs.Create.TextDocument('Note', { _layout_autoHeight: true });
             FormattedTextBox.SelectOnLoad = newBox[Id]; // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
             Doc.AddDocToList(this.props.place, 'data', newBox);
             this._stack?.scrollToBottom();
@@ -42,7 +42,7 @@ export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & Vi
     };
 
     _stack: CollectionStackingView | CollectionNoteTakingView | null | undefined;
-    childFitWidth = (doc: Doc) => doc.type === DocumentType.RTF;
+    childLayoutFitWidth = (doc: Doc) => doc.type === DocumentType.RTF;
     addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.AddDocToList(this.props.place, 'data', d), true as boolean);
     removeDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.RemoveDocFromList(this.props.place, 'data', d), true as boolean);
     render() {
@@ -69,7 +69,7 @@ export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & Vi
                             rootSelected={returnFalse}
                             childHideResizeHandles={returnTrue}
                             childHideDecorationTitle={returnTrue}
-                            childFitWidth={this.childFitWidth}
+                            childLayoutFitWidth={this.childLayoutFitWidth}
                             // childDocumentsActive={returnFalse}
                             removeDocument={this.removeDoc}
                             addDocument={this.addDoc}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 6aa04e356..edeaba322 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -63,7 +63,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         super(props);
         const nw = Doc.NativeWidth(this.Document, this.dataDoc) || 927;
         const nh = Doc.NativeHeight(this.Document, this.dataDoc) || 1200;
-        !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
+        !this.Document._layout_fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
         if (this.pdfUrl) {
             if (PDFBox.pdfcache.get(this.pdfUrl.url.href)) runInAction(() => (this._pdf = PDFBox.pdfcache.get(this.pdfUrl!.url.href)));
             else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(action((pdf: any) => (this._pdf = pdf)));
@@ -122,15 +122,15 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         cropping.onClick = undefined;
         const croppingProto = Doc.GetProto(cropping);
         croppingProto.annotationOn = undefined;
-        croppingProto.isPrototype = true;
+        croppingProto.isDataDoc = true;
         croppingProto.proto = Cast(this.rootDoc.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
         croppingProto.type = DocumentType.IMG;
         croppingProto.layout = ImageBox.LayoutString('data');
         croppingProto.data = new ImageField(Utils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png'));
-        croppingProto['data-nativeWidth'] = anchw;
-        croppingProto['data-nativeHeight'] = anchh;
+        croppingProto['data_nativeWidth'] = anchw;
+        croppingProto['data_nativeHeight'] = anchh;
         if (addCrop) {
-            DocUtils.MakeLink(region, cropping, { linkRelationship: 'cropped image' });
+            DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
         }
         this.props.bringToFront(cropping);
 
@@ -140,8 +140,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             htmlString,
             anchw,
             anchh,
-            (NumCast(region.y) * this.props.PanelWidth()) / NumCast(this.rootDoc[this.fieldKey + '-nativeWidth']),
-            (NumCast(region.x) * this.props.PanelWidth()) / NumCast(this.rootDoc[this.fieldKey + '-nativeWidth']),
+            (NumCast(region.y) * this.props.PanelWidth()) / NumCast(this.rootDoc[this.fieldKey + '_nativeWidth']),
+            (NumCast(region.x) * this.props.PanelWidth()) / NumCast(this.rootDoc[this.fieldKey + '_nativeWidth']),
             4
         )
             .then((data_url: any) => {
@@ -173,15 +173,15 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 this.layoutDoc[HeightSym](),
                 this.props.PanelWidth(),
                 this.props.PanelHeight(),
-                NumCast(this.layoutDoc._scrollTop),
-                NumCast(this.rootDoc[this.fieldKey + '-nativeHeight'], 1),
+                NumCast(this.layoutDoc._layout_scrollTop),
+                NumCast(this.rootDoc[this.fieldKey + '_nativeHeight'], 1),
                 true,
                 this.layoutDoc[Id] + '-icon',
                 (iconFile: string, nativeWidth: number, nativeHeight: number) => {
                     setTimeout(() => {
                         this.dataDoc.icon = new ImageField(iconFile);
-                        this.dataDoc['icon-nativeWidth'] = nativeWidth;
-                        this.dataDoc['icon-nativeHeight'] = nativeHeight;
+                        this.dataDoc['icon_nativeWidth'] = nativeWidth;
+                        this.dataDoc['icon_nativeHeight'] = nativeHeight;
                     }, 500);
                 }
             );
@@ -201,13 +201,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             { fireImmediately: true }
         );
         this._disposers.scroll = reaction(
-            () => this.rootDoc.scrollTop,
+            () => this.rootDoc.layout_scrollTop,
             () => {
-                if (!(ComputedField.WithoutComputed(() => FieldValue(this.props.Document[this.SidebarKey + '-panY'])) instanceof ComputedField)) {
-                    this.props.Document[this.SidebarKey + '-panY'] = ComputedField.MakeFunction('this.scrollTop');
+                if (!(ComputedField.WithoutComputed(() => FieldValue(this.props.Document[this.SidebarKey + '_panY'])) instanceof ComputedField)) {
+                    this.props.Document[this.SidebarKey + '_panY'] = ComputedField.MakeFunction('this.layout_scrollTop');
                 }
-                this.props.Document[this.SidebarKey + '-viewScale'] = 1;
-                this.props.Document[this.SidebarKey + '-panX'] = 0;
+                this.props.Document[this.SidebarKey + '_freeform_scale'] = 1;
+                this.props.Document[this.SidebarKey + '_freeform_panX'] = 0;
             }
         );
     }
@@ -215,7 +215,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._pdfViewer?.brushView(view);
 
     sidebarAddDocTab = (doc: Doc, where: OpenWhere) => {
-        if (DocListCast(this.props.Document[this.props.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) {
+        if (DocListCast(this.props.Document[this.props.fieldKey + '_sidebar']).includes(doc) && !this.SidebarShown) {
             this.toggleSidebar(false);
             return true;
         }
@@ -239,7 +239,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         }
         const docAnchor = () => {
             const anchor = Docs.Create.TextanchorDocument({
-                title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._scrollTop)?.toFixed(0)),
+                title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._layout_scrollTop)?.toFixed(0)),
                 unrendered: true,
                 annotationOn: this.rootDoc,
             });
@@ -258,11 +258,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     @action
     loaded = (nw: number, nh: number, np: number) => {
-        this.dataDoc[this.props.fieldKey + '-numPages'] = np;
+        this.dataDoc[this.props.fieldKey + '_numPages'] = np;
         Doc.SetNativeWidth(this.dataDoc, Math.max(Doc.NativeWidth(this.dataDoc), (nw * 96) / 72));
         Doc.SetNativeHeight(this.dataDoc, (nh * 96) / 72);
         this.layoutDoc._height = this.layoutDoc[WidthSym]() / (Doc.NativeAspect(this.dataDoc) || 1);
-        !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
+        !this.Document._layout_fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
     };
 
     public search = action((searchString: string, bwd?: boolean, clear: boolean = false) => {
@@ -279,14 +279,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     public prevAnnotation = () => this._pdfViewer?.prevAnnotation();
     public nextAnnotation = () => this._pdfViewer?.nextAnnotation();
     public backPage = () => {
-        this.Document._curPage = Math.max(1, (NumCast(this.Document._curPage) || 1) - 1);
+        this.Document._layout_curPage = Math.max(1, (NumCast(this.Document._layout_curPage) || 1) - 1);
         return true;
     };
     public forwardPage = () => {
-        this.Document._curPage = Math.min(NumCast(this.dataDoc[this.props.fieldKey + '-numPages']), (NumCast(this.Document._curPage) || 1) + 1);
+        this.Document._layout_curPage = Math.min(NumCast(this.dataDoc[this.props.fieldKey + '_numPages']), (NumCast(this.Document._layout_curPage) || 1) + 1);
         return true;
     };
-    public gotoPage = (p: number) => (this.Document._curPage = p);
+    public gotoPage = (p: number) => (this.Document._layout_curPage = p);
 
     @undoBatch
     onKeyDown = action((e: KeyboardEvent) => {
@@ -316,9 +316,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     searchStringChanged = (e: React.ChangeEvent<HTMLInputElement>) => (this._searchString = e.currentTarget.value);
 
     // adding external documents; to sidebar key
-    // if (doc.Geolocation) this.addDocument(doc, this.fieldkey+"-annotation")
+    // if (doc.Geolocation) this.addDocument(doc, this.fieldkey+"_annotation")
     sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => {
-        if (!this.layoutDoc._showSidebar) this.toggleSidebar();
+        if (!this.layoutDoc._show_sidebar) this.toggleSidebar();
         return this.addDocument(doc, sidebarKey);
     };
     sidebarBtnDown = (e: React.PointerEvent, onButton: boolean) => {
@@ -332,13 +332,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     .ScreenToLocalTransform()
                     .scale(this.props.NativeDimScaling?.() || 1)
                     .transformDirection(delta[0], delta[1]);
-                const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']);
+                const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
                 const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
                 const ratio = (curNativeWidth + ((onButton ? 1 : -1) * localDelta[0]) / (this.props.NativeDimScaling?.() || 1)) / nativeWidth;
                 if (ratio >= 1) {
                     this.layoutDoc.nativeWidth = nativeWidth * ratio;
                     onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]);
-                    this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
+                    this.layoutDoc._show_sidebar = nativeWidth !== this.layoutDoc._nativeWidth;
                 }
                 return false;
             },
@@ -352,7 +352,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @observable _previewNativeWidth: Opt<number> = undefined;
     @observable _previewWidth: Opt<number> = undefined;
     toggleSidebar = action((preview: boolean = false) => {
-        const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']);
+        const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
         const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth;
         const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth + PDFBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth;
         const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
@@ -363,7 +363,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         } else {
             this.layoutDoc.nativeWidth = nativeWidth * pdfratio;
             this.layoutDoc._width = (this.layoutDoc[WidthSym]() * nativeWidth * pdfratio) / curNativeWidth;
-            this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
+            this.layoutDoc._show_sidebar = nativeWidth !== this.layoutDoc._nativeWidth;
         }
     });
     settingsPanel() {
@@ -378,7 +378,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             </>
         );
         const searchTitle = `${!this._searching ? 'Open' : 'Close'} Search Bar`;
-        const curPage = NumCast(this.Document._curPage) || 1;
+        const curPage = NumCast(this.Document._layout_curPage) || 1;
         return !this.props.isContentActive() || this._pdfViewer?.isAnnotating ? null : (
             <div
                 className="pdfBox-ui"
@@ -424,7 +424,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     <input
                         value={curPage}
                         style={{ width: `${curPage > 99 ? 4 : 3}ch`, pointerEvents: 'all' }}
-                        onChange={e => (this.Document._curPage = Number(e.currentTarget.value))}
+                        onChange={e => (this.Document._layout_curPage = Number(e.currentTarget.value))}
                         onKeyDown={e => e.stopPropagation()}
                         onClick={action(() => (this._pageControls = !this._pageControls))}
                     />
@@ -470,7 +470,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
     @observable _showSidebar = false;
     @computed get SidebarShown() {
-        return this._showSidebar || this.layoutDoc._showSidebar ? true : false;
+        return this._showSidebar || this.layoutDoc._show_sidebar ? true : false;
     }
     @computed get sidebarHandle() {
         return (
@@ -480,7 +480,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 title="Toggle Sidebar"
                 style={{
                     display: !this.props.isContentActive() ? 'none' : undefined,
-                    top: StrCast(this.rootDoc._showTitle) === 'title' ? 20 : 5,
+                    top: StrCast(this.rootDoc._layout_showTitle) === 'title' ? 20 : 5,
                     backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
                 }}
                 onPointerDown={e => this.sidebarBtnDown(e, true)}>
@@ -490,10 +490,10 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     }
 
     public get SidebarKey() {
-        return this.fieldKey + '-sidebar';
+        return this.fieldKey + '_sidebar';
     }
     @computed get pdfScale() {
-        const pdfNativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']);
+        const pdfNativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
         const nativeWidth = NumCast(this.layoutDoc.nativeWidth, pdfNativeWidth);
         const pdfRatio = pdfNativeWidth / nativeWidth;
         return (pdfRatio * this.props.PanelWidth()) / pdfNativeWidth;
@@ -572,7 +572,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 onContextMenu={this.specificContextMenu}
                 style={{
                     display: this.props.thumbShown?.() ? 'none' : undefined,
-                    height: this.props.Document._scrollTop && !this.Document._fitWidth && window.screen.width > 600 ? (NumCast(this.Document._height) * this.props.PanelWidth()) / NumCast(this.Document._width) : undefined,
+                    height: this.props.Document._layout_scrollTop && !this.Document._layout_fitWidth && window.screen.width > 600 ? (NumCast(this.Document._height) * this.props.PanelWidth()) / NumCast(this.Document._width) : undefined,
                 }}>
                 <div className="pdfBox-background" onPointerDown={e => this.sidebarBtnDown(e, false)} />
                 <div
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index f406ffbea..80b12b96e 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -41,7 +41,7 @@ export class RecordingBox extends ViewBoxBaseComponent() {
     setResult = (info: Upload.AccessPathInfo, presentation?: Presentation) => {
         this.result = info;
         this.dataDoc.type = DocumentType.VID;
-        this.dataDoc[this.fieldKey + '-duration'] = this.videoDuration;
+        this.dataDoc[this.fieldKey + '_duration'] = this.videoDuration;
 
         this.dataDoc.layout = VideoBox.LayoutString(this.fieldKey);
         this.dataDoc[this.props.fieldKey] = new VideoField(this.result.accessPaths.client);
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 75e61bbeb..7bf765042 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -129,7 +129,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
         }
     }
     getAnchor = (addAsAnnotation: boolean) => {
-        const startTime = Cast(this.layoutDoc._currentTimecode, 'number', null) || (this._videoRec ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined);
+        const startTime = Cast(this.layoutDoc._layout_currentTimecode, 'number', null) || (this._videoRec ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined);
         return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, startTime, startTime === undefined ? undefined : startTime + 3, undefined, addAsAnnotation) || this.rootDoc;
     };
 
@@ -236,13 +236,13 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                 console.log('screenshotbox: upload');
                 const file = new File(vid_chunks, `${this.rootDoc[Id]}.mkv`, { type: vid_chunks[0].type, lastModified: Date.now() });
                 const [{ result }] = await Networking.UploadFilesToServer(file);
-                this.dataDoc[this.fieldKey + '-duration'] = (new Date().getTime() - this.recordingStart!) / 1000;
+                this.dataDoc[this.fieldKey + '_duration'] = (new Date().getTime() - this.recordingStart!) / 1000;
                 if (!(result instanceof Error)) {
                     // convert this screenshotBox into normal videoBox
                     this.dataDoc.type = DocumentType.VID;
                     this.layoutDoc.layout = VideoBox.LayoutString(this.fieldKey);
                     this.dataDoc.nativeWidth = this.dataDoc.nativeHeight = undefined;
-                    this.layoutDoc._fitWidth = undefined;
+                    this.layoutDoc._layout_fitWidth = undefined;
                     this.dataDoc[this.props.fieldKey] = new VideoField(result.accessPaths.agnostic.client);
                 } else alert('video conversion failed');
             };
@@ -270,14 +270,14 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
     setupDictation = () => {
         if (this.dataDoc[this.fieldKey + '-dictation']) return;
         const dictationText = DocUtils.GetNewTextDoc('dictation', NumCast(this.rootDoc.x), NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height));
-        dictationText._autoHeight = false;
+        dictationText._layout_autoHeight = false;
         const dictationTextProto = Doc.GetProto(dictationText);
         dictationTextProto.recordingSource = this.dataDoc;
         dictationTextProto.recordingStart = ComputedField.MakeFunction(`self.recordingSource["${this.props.fieldKey}-recordingStart"]`);
         dictationTextProto.mediaState = ComputedField.MakeFunction('self.recordingSource.mediaState');
         this.dataDoc[this.fieldKey + '-dictation'] = dictationText;
     };
-    videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '-nativeHeight'], this.layoutDoc[HeightSym]()) / NumCast(this.dataDoc[this.fieldKey + '-nativeWidth'], this.layoutDoc[WidthSym]())) * this.props.PanelWidth();
+    videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], this.layoutDoc[HeightSym]()) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], this.layoutDoc[WidthSym]())) * this.props.PanelWidth();
     formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight());
     render() {
         TraceMobx();
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index f09962b22..37fda14fc 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -167,7 +167,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     // only included in buttons, transforms scripting UI to a button
     @action
     onFinish = () => {
-        this.rootDoc.layoutKey = 'layout';
+        this.rootDoc.layout_fieldKey = 'layout';
     };
 
     // displays error message
@@ -702,7 +702,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
 
     // toolbar (with compile and apply buttons) for scripting UI
     renderScriptingTools() {
-        const buttonStyle = 'scriptingBox-button' + (StrCast(this.rootDoc.layoutKey).startsWith('layout_on') ? '-finish' : '');
+        const buttonStyle = 'scriptingBox-button' + (StrCast(this.rootDoc.layout_fieldKey).startsWith('layout_on') ? '-finish' : '');
         return (
             <div className="scriptingBox-toolbar">
                 <button
@@ -730,7 +730,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                     Save
                 </button>
 
-                {!StrCast(this.rootDoc.layoutKey).startsWith('layout_on') ? null : ( // onClick, onChecked, etc need a Finish button to return to their default layout
+                {!StrCast(this.rootDoc.layout_fieldKey).startsWith('layout_on') ? null : ( // onClick, onChecked, etc need a Finish button to return to their default layout
                     <button
                         className={buttonStyle}
                         onPointerDown={e => {
@@ -776,7 +776,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
 
     // toolbar (with edit and run buttons and error message) for params UI
     renderTools(toolSet: string, func: () => void) {
-        const buttonStyle = 'scriptingBox-button' + (StrCast(this.rootDoc.layoutKey).startsWith('layout_on') ? '-finish' : '');
+        const buttonStyle = 'scriptingBox-button' + (StrCast(this.rootDoc.layout_fieldKey).startsWith('layout_on') ? '-finish' : '');
         return (
             <div className="scriptingBox-toolbar">
                 <button
@@ -795,7 +795,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
                     }}>
                     {toolSet}
                 </button>
-                {!StrCast(this.rootDoc.layoutKey).startsWith('layout_on') ? null : (
+                {!StrCast(this.rootDoc.layout_fieldKey).startsWith('layout_on') ? null : (
                     <button
                         className={buttonStyle}
                         onPointerDown={e => {
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 7a7d4fe37..e00cb8618 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx';
 import { observer } from 'mobx-react';
 import { basename } from 'path';
-import { Doc, HeightSym, WidthSym } from '../../../fields/Doc';
+import { Doc, HeightSym, StrListCast, WidthSym } from '../../../fields/Doc';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
 import { ObjectField } from '../../../fields/ObjectField';
@@ -91,9 +91,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         return LinkManager.Links(this.dataDoc);
     }
     @computed get heightPercent() {
-        return NumCast(this.layoutDoc._timelineHeightPercent, 100);
+        return NumCast(this.layoutDoc._layout_timelineHeightPercent, 100);
     } // current percent of video relative to VideoBox height
-    // @computed get rawDuration() { return NumCast(this.dataDoc[this.fieldKey + "-duration"]); }
+    // @computed get rawDuration() { return NumCast(this.dataDoc[this.fieldKey + "_duration"]); }
     @observable rawDuration: number = 0;
 
     @computed get youtubeVideoId() {
@@ -325,14 +325,14 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 y: NumCast(this.layoutDoc.y, 1),
                 _width: 150,
                 _height: 50,
-                title: (this.layoutDoc._currentTimecode || 0).toString(),
+                title: (this.layoutDoc._layout_currentTimecode || 0).toString(),
                 onClick: FollowLinkScript(),
             });
             this.props.addDocument?.(b);
-            DocUtils.MakeLink(b, this.rootDoc, { linkRelationship: 'video snapshot' });
+            DocUtils.MakeLink(b, this.rootDoc, { link_relationship: 'video snapshot' });
             Networking.PostToServer('/youtubeScreenshot', {
                 id: this.youtubeVideoId,
-                timecode: this.layoutDoc._currentTimecode,
+                timecode: this.layoutDoc._layout_currentTimecode,
             }).then(response => {
                 const resolved = response?.accessPaths?.agnostic?.client;
                 if (resolved) {
@@ -345,7 +345,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             const dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png'
             // if you want to preview the captured image,
             const retitled = StrCast(this.rootDoc.title).replace(/[ -\.:]/g, '');
-            const encodedFilename = encodeURIComponent('snapshot' + retitled + '_' + (this.layoutDoc._currentTimecode || 0).toString().replace(/\./, '_'));
+            const encodedFilename = encodeURIComponent('snapshot' + retitled + '_' + (this.layoutDoc._layout_currentTimecode || 0).toString().replace(/\./, '_'));
             const filename = basename(encodedFilename);
             Utils.convertDataUri(dataUrl, filename).then((returnedFilename: string) => returnedFilename && (cb ?? this.createSnapshotLink)(returnedFilename, downX, downY));
         }
@@ -354,8 +354,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     updateIcon = () => {
         const makeIcon = (returnedfilename: string) => {
             this.dataDoc.icon = new ImageField(returnedfilename);
-            this.dataDoc['icon-nativeWidth'] = this.layoutDoc[WidthSym]();
-            this.dataDoc['icon-nativeHeight'] = this.layoutDoc[HeightSym]();
+            this.dataDoc.icon_nativeWidth = this.layoutDoc[WidthSym]();
+            this.dataDoc.icon_nativeHeight = this.layoutDoc[HeightSym]();
         };
         this.Snapshot(undefined, undefined, makeIcon);
     };
@@ -373,18 +373,18 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             onClick: FollowLinkScript(),
             _width: 150,
             _height: (height / width) * 150,
-            title: '--snapshot' + NumCast(this.layoutDoc._currentTimecode) + ' image-',
+            title: '--snapshot' + NumCast(this.layoutDoc._layout_currentTimecode) + ' image-',
         });
         Doc.SetNativeWidth(Doc.GetProto(imageSnapshot), Doc.NativeWidth(this.layoutDoc));
         Doc.SetNativeHeight(Doc.GetProto(imageSnapshot), Doc.NativeHeight(this.layoutDoc));
         this.props.addDocument?.(imageSnapshot);
-        const link = DocUtils.MakeLink(imageSnapshot, this.getAnchor(true), { linkRelationship: 'video snapshot' });
-        link && (Doc.GetProto(link.anchor2 as Doc).timecodeToHide = NumCast((link.anchor2 as Doc).timecodeToShow) + 3);
+        const link = DocUtils.MakeLink(imageSnapshot, this.getAnchor(true), { link_relationship: 'video snapshot' });
+        link && (Doc.GetProto(link.link_anchor_2 as Doc).timecodeToHide = NumCast((link.link_anchor_2 as Doc).timecodeToShow) + 3);
         setTimeout(() => downX !== undefined && downY !== undefined && DocumentManager.Instance.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, 'move', true));
     };
 
     getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
-        const timecode = Cast(this.layoutDoc._currentTimecode, 'number', null);
+        const timecode = Cast(this.layoutDoc._layout_currentTimecode, 'number', null);
         const marquee = AnchorMenu.Instance.GetAnchor?.(undefined, addAsAnnotation);
         if (!addAsAnnotation && marquee) marquee.backgroundColor = 'transparent';
         const anchor = CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, timecode ? timecode : undefined, undefined, marquee, addAsAnnotation) || this.rootDoc;
@@ -402,16 +402,16 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         }
         if (Number.isFinite(this.player!.duration)) {
             this.rawDuration = this.player!.duration;
-            this.dataDoc[this.fieldKey + '-duration'] = this.rawDuration;
-        } else this.rawDuration = NumCast(this.dataDoc[this.fieldKey + '-duration']);
+            this.dataDoc[this.fieldKey + '_duration'] = this.rawDuration;
+        } else this.rawDuration = NumCast(this.dataDoc[this.fieldKey + '_duration']);
     });
 
     // updates video time
     @action
     updateTimecode = () => {
-        this.player && (this.layoutDoc._currentTimecode = this.player.currentTime);
+        this.player && (this.layoutDoc._layout_currentTimecode = this.player.currentTime);
         try {
-            this._youtubePlayer && (this.layoutDoc._currentTimecode = this._youtubePlayer.getCurrentTime?.());
+            this._youtubePlayer && (this.layoutDoc._layout_currentTimecode = this._youtubePlayer.getCurrentTime?.());
         } catch (e) {
             console.log('Video Timecode Exception:', e);
         }
@@ -423,8 +423,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     // extracts video thumbnails and saves them as field of doc
     getVideoThumbnails = () => {
-        if (this.dataDoc.thumbnails !== undefined) return;
-        this.dataDoc.thumbnails = new List<string>();
+        if (this.dataDoc[this.fieldKey + '_thumbnails'] !== undefined) return;
+        this.dataDoc[this.fieldKey + '_thumbnails'] = new List<string>();
         const thumbnailPromises: Promise<any>[] = [];
         const video = document.createElement('video');
 
@@ -442,7 +442,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             if (newTime < video.duration) {
                 video.currentTime = newTime;
             } else {
-                Promise.all(thumbnailPromises).then(thumbnails => (this.dataDoc.thumbnails = new List<string>(thumbnails)));
+                Promise.all(thumbnailPromises).then(thumbnails => (this.dataDoc[this.fieldKey + '_thumbnails'] = new List<string>(thumbnails)));
             }
         };
 
@@ -460,12 +460,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             // vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen);
             this._disposers.reactionDisposer?.();
             this._disposers.reactionDisposer = reaction(
-                () => NumCast(this.layoutDoc._currentTimecode),
+                () => NumCast(this.layoutDoc._layout_currentTimecode),
                 time => !this._playing && (vref.currentTime = time),
                 { fireImmediately: true }
             );
 
-            (!this.dataDoc.thumbnails || this.dataDoc.thumbnails.length != VideoBox.numThumbnails) && this.getVideoThumbnails();
+            (!this.dataDoc[this.fieldKey + '_thumbnails'] || this.dataDoc[this.fieldKey + '_thumbnails'].length != VideoBox.numThumbnails) && this.getVideoThumbnails();
         }
     };
 
@@ -531,7 +531,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         this.dataDoc.layout = RecordingBox.LayoutString(this.fieldKey);
                         // delete assoicated video data
                         this.dataDoc[this.props.fieldKey] = '';
-                        this.dataDoc[this.fieldKey + '-duration'] = '';
+                        this.dataDoc[this.fieldKey + '_duration'] = '';
                         // delete assoicated presentation data
                         this.dataDoc[this.fieldKey + '-presentation'] = '';
                     },
@@ -573,7 +573,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         key="video"
                         autoPlay={this._screenCapture}
                         ref={this.setVideoRef}
-                        style={this._fullScreen ? this.fullScreenSize() : this.isCropped ? { width: 'max-content', height: 'max-content', transform: `scale(${1 / NumCast(this.rootDoc._viewScale)})`, transformOrigin: 'top left' } : {}}
+                        style={this._fullScreen ? this.fullScreenSize() : this.isCropped ? { width: 'max-content', height: 'max-content', transform: `scale(${1 / NumCast(this.rootDoc._freeform_scale)})`, transformOrigin: 'top left' } : {}}
                         onCanPlay={this.videoLoad}
                         controls={VideoBox._nativeControls}
                         onPlay={() => this.Play()}
@@ -620,8 +620,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             this._disposers.reactionDisposer?.();
             this._disposers.youtubeReactionDisposer?.();
             this._disposers.reactionDisposer = reaction(
-                () => this.layoutDoc._currentTimecode,
-                () => !this._playing && this.Seek(NumCast(this.layoutDoc._currentTimecode))
+                () => this.layoutDoc._layout_currentTimecode,
+                () => !this._playing && this.Seek(NumCast(this.layoutDoc._layout_currentTimecode))
             );
             this._disposers.youtubeReactionDisposer = reaction(
                 () => Doc.ActiveTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting,
@@ -677,15 +677,15 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 this._clicking = false;
                 if (this.props.isContentActive()) {
                     // const local = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformPoint(e.clientX, e.clientY);
-                    // this.layoutDoc._timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this.props.PanelHeight() * 100));
+                    // this.layoutDoc._layout_timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this.props.PanelHeight() * 100));
 
-                    this.layoutDoc._timelineHeightPercent = 80;
+                    this.layoutDoc._layout_timelineHeightPercent = 80;
                 }
                 return false;
             }),
             emptyFunction,
             () => {
-                this.layoutDoc._timelineHeightPercent = this.heightPercent !== 100 ? 100 : VideoBox.heightPercent;
+                this.layoutDoc._layout_timelineHeightPercent = this.heightPercent !== 100 ? 100 : VideoBox.heightPercent;
                 setTimeout(
                     action(() => (this._clicking = false)),
                     500
@@ -721,7 +721,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         this._youtubeIframeId = VideoBox._youtubeIframeCounter++;
         this._youtubeContentCreated = this._forceCreateYouTubeIFrame ? true : true;
         const classname = 'videoBox-content-YouTube' + (this._fullScreen ? '-fullScreen' : '');
-        const start = untracked(() => Math.round(NumCast(this.layoutDoc._currentTimecode)));
+        const start = untracked(() => Math.round(NumCast(this.layoutDoc._layout_currentTimecode)));
         return (
             <iframe
                 key={this._youtubeIframeId}
@@ -740,7 +740,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     @action.bound
     addDocWithTimecode(doc: Doc | Doc[]): boolean {
         const docs = doc instanceof Doc ? [doc] : doc;
-        const curTime = NumCast(this.layoutDoc._currentTimecode);
+        const curTime = NumCast(this.layoutDoc._layout_currentTimecode);
         docs.forEach(doc => (doc._timecodeToHide = (doc._timecodeToShow = curTime) + 1));
         return this.addDocument(doc);
     }
@@ -859,7 +859,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     // starts marquee selection
     marqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._viewScale, 1) === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) {
+        if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) {
             setupMoveUpEvents(
                 this,
                 e,
@@ -890,7 +890,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             .scale(this.scaling())
             .translate(0, (-this.heightPercent / 100) * this.props.PanelHeight());
 
-    setPlayheadTime = (time: number) => (this.player!.currentTime = this.layoutDoc._currentTimecode = time);
+    setPlayheadTime = (time: number) => (this.player!.currentTime = this.layoutDoc._layout_currentTimecode = time);
 
     timelineHeight = () => (this.props.PanelHeight() * (100 - this.heightPercent)) / 100;
 
@@ -899,7 +899,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     scaling = () => this.props.NativeDimScaling?.() || 1;
 
     panelWidth = () => (this.props.PanelWidth() * this.heightPercent) / 100;
-    panelHeight = () => (this.layoutDoc._fitWidth ? this.panelWidth() / (Doc.NativeAspect(this.rootDoc) || 1) : (this.props.PanelHeight() * this.heightPercent) / 100);
+    panelHeight = () => (this.layoutDoc._layout_fitWidth ? this.panelWidth() / (Doc.NativeAspect(this.rootDoc) || 1) : (this.props.PanelHeight() * this.heightPercent) / 100);
 
     screenToLocalTransform = () => {
         const offset = (this.props.PanelWidth() - this.panelWidth()) / 2 / this.scaling();
@@ -956,9 +956,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 <CollectionStackedTimeline
                     ref={action((r: any) => (this._stackedTimeline = r))}
                     {...this.props}
+                    dataFieldKey={this.fieldKey}
                     fieldKey={this.annotationKey}
                     dictationKey={this.fieldKey + '-dictation'}
                     mediaPath={this.audiopath}
+                    thumbnails={() => StrListCast(this.dataDoc[this.fieldKey + '_thumbnails'])}
                     renderDepth={this.props.renderDepth + 1}
                     startTag={'_timecodeToShow' /* videoStart */}
                     endTag={'_timecodeToHide' /* videoEnd */}
@@ -1003,7 +1005,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const anchy = NumCast(cropping.y);
         const anchw = NumCast(cropping._width);
         const anchh = NumCast(cropping._height);
-        const viewScale = NumCast(this.rootDoc[this.fieldKey + '-nativeWidth']) / anchw;
+        const viewScale = NumCast(this.rootDoc[this.fieldKey + '_nativeWidth']) / anchw;
         cropping.title = 'crop: ' + this.rootDoc.title;
         cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
         cropping.y = NumCast(this.rootDoc.y);
@@ -1014,25 +1016,25 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         cropping.onClick = undefined;
         const croppingProto = Doc.GetProto(cropping);
         croppingProto.annotationOn = undefined;
-        croppingProto.isPrototype = true;
+        croppingProto.isDataDoc = true;
         croppingProto.proto = Cast(this.rootDoc.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
         croppingProto.type = DocumentType.VID;
         croppingProto.layout = VideoBox.LayoutString('data');
         croppingProto.data = ObjectField.MakeCopy(this.rootDoc[this.fieldKey] as ObjectField);
-        croppingProto['data-nativeWidth'] = anchw;
-        croppingProto['data-nativeHeight'] = anchh;
+        croppingProto['data_nativeWidth'] = anchw;
+        croppingProto['data_nativeHeight'] = anchh;
         croppingProto.videoCrop = true;
-        croppingProto.currentTimecode = this.layoutDoc._currentTimecode;
-        croppingProto.viewScale = viewScale;
-        croppingProto.viewScaleMin = viewScale;
-        croppingProto.panX = anchx / viewScale;
-        croppingProto.panY = anchy / viewScale;
-        croppingProto.panXMin = anchx / viewScale;
-        croppingProto.panXMax = anchw / viewScale;
-        croppingProto.panYMin = anchy / viewScale;
-        croppingProto.panYMax = anchh / viewScale;
+        croppingProto.layout_currentTimecode = this.layoutDoc._layout_currentTimecode;
+        croppingProto.freeform_scale = viewScale;
+        croppingProto.freeform_scaleMin = viewScale;
+        croppingProto.freeform_ = anchx / viewScale;
+        croppingProto.freeform_panY = anchy / viewScale;
+        croppingProto.freeform_panXMin = anchx / viewScale;
+        croppingProto.freeform_panXMax = anchw / viewScale;
+        croppingProto.freeform_panYMin = anchy / viewScale;
+        croppingProto.freeform_panYMax = anchh / viewScale;
         if (addCrop) {
-            DocUtils.MakeLink(region, cropping, { linkRelationship: 'cropped image' });
+            DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
         }
         this.props.bringToFront(cropping);
         return cropping;
@@ -1050,7 +1052,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 style={{
                     pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined,
                     borderRadius,
-                    overflow: this.props.docViewPath?.().slice(-1)[0].fitWidth ? 'auto' : undefined,
+                    overflow: this.props.docViewPath?.().slice(-1)[0].layout_fitWidth ? 'auto' : undefined,
                 }}
                 onWheel={e => {
                     e.stopPropagation();
@@ -1116,7 +1118,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     @computed get UIButtons() {
         const bounds = this.props.docViewPath().lastElement().getBounds();
         const width = (bounds?.right || 0) - (bounds?.left || 0);
-        const curTime = NumCast(this.layoutDoc._currentTimecode) - (this.timeline?.clipStart || 0);
+        const curTime = NumCast(this.layoutDoc._layout_currentTimecode) - (this.timeline?.clipStart || 0);
         return (
             <>
                 <div className="videobox-button" title={this._playing ? 'play' : 'pause'} onPointerDown={this.onPlayDown}>
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 82c8e796d..3da5d8f17 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -56,7 +56,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     private _disposers: { [name: string]: IReactionDisposer } = {};
     private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
     private _keyInput = React.createRef<HTMLInputElement>();
-    private _initialScroll: Opt<number> = NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.scrollTop));
+    private _initialScroll: Opt<number> = NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.layout_scrollTop));
     private _sidebarRef = React.createRef<SidebarAnnos>();
     private _searchRef = React.createRef<HTMLInputElement>();
     private _searchString = '';
@@ -101,7 +101,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             ImageCast(
                 this.layoutDoc['thumb-frozen'],
                 ImageCast(
-                    this.layoutDoc.thumbScrollTop === this.layoutDoc._scrollTop && this.layoutDoc.thumbNativeWidth === NumCast(this.layoutDoc.nativeWidth) && this.layoutDoc.thumbNativeHeight === NumCast(this.layoutDoc.nativeHeight)
+                    this.layoutDoc.thumbScrollTop === this.layoutDoc._layout_scrollTop && this.layoutDoc.thumbNativeWidth === NumCast(this.layoutDoc.nativeWidth) && this.layoutDoc.thumbNativeHeight === NumCast(this.layoutDoc.nativeHeight)
                         ? this.layoutDoc.thumb
                         : undefined
                 )
@@ -144,7 +144,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     updateThumb = async () => {
         if (!this._iframe) return;
-        const scrollTop = NumCast(this.layoutDoc._scrollTop);
+        const scrollTop = NumCast(this.layoutDoc._layout_scrollTop);
         const nativeWidth = NumCast(this.layoutDoc.nativeWidth);
         const nativeHeight = (nativeWidth * this.props.PanelHeight()) / this.props.PanelWidth();
         var htmlString = this._iframe.contentDocument && new XMLSerializer().serializeToString(this._iframe.contentDocument);
@@ -181,12 +181,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         this.props.setContentView?.(this); // this tells the DocumentView that this WebBox is the "content" of the document.  this allows the DocumentView to call WebBox relevant methods to configure the UI (eg, show back/forward buttons)
 
         runInAction(() => {
-            this._annotationKeySuffix = () => this._urlHash + '-annotations';
+            this._annotationKeySuffix = () => this._urlHash + '_annotations';
             const reqdFuncs: { [key: string]: string } = {};
-            // bcz: need to make sure that doc.data-annotations points to the currently active web page's annotations (this could/should be when the doc is created)
-            reqdFuncs[this.fieldKey + '-annotations'] = `copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"])`;
-            reqdFuncs[this.fieldKey + '-annotations-setter'] = `this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"] = value`;
-            reqdFuncs[this.fieldKey + '-sidebar'] = `copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"])`;
+            // bcz: need to make sure that doc.data_annotations points to the currently active web page's annotations (this could/should be when the doc is created)
+            reqdFuncs[this.fieldKey + '_annotations'] = `copyField(this["${this.fieldKey}_"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"_annotations"])`;
+            reqdFuncs[this.fieldKey + '_annotations-setter'] = `this["${this.fieldKey}_"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"_annotations"] = value`;
+            reqdFuncs[this.fieldKey + '_sidebar'] = `copyField(this["${this.fieldKey}_"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"_sidebar"])`;
             DocUtils.AssignScripts(this.dataDoc, {}, reqdFuncs);
         });
         this._disposers.urlchange = reaction(
@@ -196,12 +196,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             }
         );
 
-        this._disposers.autoHeight = reaction(
-            () => this.layoutDoc._autoHeight,
-            autoHeight => {
-                if (autoHeight) {
-                    this.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']);
-                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.NativeDimScaling?.() || 1));
+        this._disposers.layout_autoHeight = reaction(
+            () => this.layoutDoc._layout_autoHeight,
+            layout_autoHeight => {
+                if (layout_autoHeight) {
+                    this.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + '_nativeHeight']);
+                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '_nativeHeight']) * (this.props.NativeDimScaling?.() || 1));
                 }
             }
         );
@@ -225,7 +225,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         }
 
         this._disposers.scrollReaction = reaction(
-            () => NumCast(this.layoutDoc._scrollTop),
+            () => NumCast(this.layoutDoc._layout_scrollTop),
             scrollTop => {
                 const viewTrans = StrCast(this.Document._viewTransition);
                 const durationMiliStr = viewTrans.match(/([0-9]*)ms/);
@@ -281,7 +281,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     focus = (anchor: Doc, options: DocFocusOptions) => {
         if (anchor !== this.rootDoc && this._outerRef.current) {
             const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
-            const scrollTo = Utils.scrollIntoView(NumCast(anchor.y), anchor[HeightSym](), NumCast(this.layoutDoc._scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(anchor.y) + anchor[HeightSym](), this._scrollHeight));
+            const scrollTo = Utils.scrollIntoView(NumCast(anchor.y), anchor[HeightSym](), NumCast(this.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(anchor.y) + anchor[HeightSym](), this._scrollHeight));
             if (scrollTo !== undefined) {
                 if (this._initialScroll === undefined) {
                     const focusTime = options.zoomTime ?? 500;
@@ -296,14 +296,14 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     @action
     getView = (doc: Doc) => {
-        if (this.rootDoc.layoutKey === 'layout_icon') this.props.DocumentView?.().iconify();
+        if (this.rootDoc.layout_fieldKey === 'layout_icon') this.props.DocumentView?.().iconify();
         if (this._url && WebCast(doc.presData).url.href !== this._url) this.setData(WebCast(doc.presData).url.href);
         if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(false);
         return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
     };
 
     sidebarAddDocTab = (doc: Doc, where: OpenWhere) => {
-        if (DocListCast(this.props.Document[this.props.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) {
+        if (DocListCast(this.props.Document[this.props.fieldKey + '_sidebar']).includes(doc) && !this.SidebarShown) {
             this.toggleSidebar(false);
             return true;
         }
@@ -321,8 +321,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const anchor =
             this._getAnchor(this._savedAnnotations, false) ??
             Docs.Create.WebanchorDocument({
-                title: StrCast(this.rootDoc.title + ' ' + this.layoutDoc._scrollTop),
-                y: NumCast(this.layoutDoc._scrollTop),
+                title: StrCast(this.rootDoc.title + ' ' + this.layoutDoc._layout_scrollTop),
+                y: NumCast(this.layoutDoc._layout_scrollTop),
                 unrendered: true,
                 annotationOn: this.rootDoc,
             });
@@ -349,9 +349,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 this._selectionText = sel.toString();
                 AnchorMenu.Instance.setSelectedText(sel.toString());
                 this._textAnnotationCreator = () => this.createTextAnnotation(sel, !sel.isCollapsed ? sel.getRangeAt(0) : undefined);
-                AnchorMenu.Instance.jumpTo(e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._scrollTop) * scale);
+                AnchorMenu.Instance.jumpTo(e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._layout_scrollTop) * scale);
                 // Changing which document to add the annotation to (the currently selected WebBox)
-                GPTPopup.Instance.setSidebarId(`${this.props.fieldKey}-${this._urlHash}-sidebar`);
+                GPTPopup.Instance.setSidebarId(`${this.props.fieldKey}_${this._urlHash}_sidebar`);
                 GPTPopup.Instance.addDoc = this.sidebarAddDocument;
             }
         }
@@ -364,7 +364,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const word = getWordAtPoint(e.target, e.clientX, e.clientY);
         this._setPreviewCursor?.(e.clientX, e.clientY, false, true);
         MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
-        e.button !== 2 && (this._marqueeing = [e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._scrollTop) * scale]);
+        e.button !== 2 && (this._marqueeing = [e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._layout_scrollTop) * scale]);
         if (word || ((e.target as any) || '').className.includes('rangeslider') || (e.target as any)?.onclick || (e.target as any)?.parentNode?.onclick) {
             setTimeout(
                 action(() => (this._marqueeing = undefined)),
@@ -485,7 +485,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                                 batch.end();
                             });
                             if (this._outerRef.current) {
-                                this._outerRef.current.scrollTop = NumCast(this.layoutDoc._scrollTop);
+                                this._outerRef.current.scrollTop = NumCast(this.layoutDoc._layout_scrollTop);
                                 this._outerRef.current.scrollLeft = 0;
                             }
                         }
@@ -508,8 +508,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (e.ctrlKey) {
             if (this._innerCollectionView) {
                 this._innerCollectionView.zoom(e.screenX, e.screenY, e.deltaY);
-                const offset = e.clientY - NumCast(this.layoutDoc._scrollTop);
-                this.layoutDoc.panY = offset - offset / NumCast(this.layoutDoc._viewScale) + NumCast(this.layoutDoc._scrollTop) - NumCast(this.layoutDoc._scrollTop) / NumCast(this.layoutDoc._viewScale);
+                const offset = e.clientY - NumCast(this.layoutDoc._layout_scrollTop);
+                this.layoutDoc.panY = offset - offset / NumCast(this.layoutDoc._freeform_scale) + NumCast(this.layoutDoc._layout_scrollTop) - NumCast(this.layoutDoc._layout_scrollTop) / NumCast(this.layoutDoc._freeform_scale);
             }
             e.preventDefault();
         }
@@ -532,7 +532,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 this.layoutDoc.thumbScrollTop = undefined;
                 this.layoutDoc.thumbNativeWidth = undefined;
                 this.layoutDoc.thumbNativeHeight = undefined;
-                this.layoutDoc.scrollTop = this._outerRef.current.scrollTop = newScrollTop;
+                this.layoutDoc.layout_scrollTop = this._outerRef.current.scrollTop = newScrollTop;
             } else if (this._outerRef.current) this._outerRef.current.scrollTop = newScrollTop;
         }, timeout);
     };
@@ -550,13 +550,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
 
     forward = (checkAvailable?: boolean) => {
-        const future = Cast(this.rootDoc[this.fieldKey + '-future'], listSpec('string'), []);
-        const history = Cast(this.rootDoc[this.fieldKey + '-history'], listSpec('string'), []);
+        const future = Cast(this.rootDoc[this.fieldKey + '_future'], listSpec('string'), []);
+        const history = Cast(this.rootDoc[this.fieldKey + '_history'], listSpec('string'), []);
         if (checkAvailable) return future.length;
         runInAction(() => {
             if (future.length) {
                 const curUrl = this._url;
-                this.dataDoc[this.fieldKey + '-history'] = new List<string>([...history, this._url]);
+                this.dataDoc[this.fieldKey + '_history'] = new List<string>([...history, this._url]);
                 this.dataDoc[this.fieldKey] = new WebField(new URL(future.pop()!));
                 this._scrollHeight = 0;
                 if (this._webUrl === this._url) {
@@ -572,14 +572,14 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
 
     back = (checkAvailable?: boolean) => {
-        const future = Cast(this.rootDoc[this.fieldKey + '-future'], listSpec('string'));
-        const history = Cast(this.rootDoc[this.fieldKey + '-history'], listSpec('string'), []);
+        const future = Cast(this.rootDoc[this.fieldKey + '_future'], listSpec('string'));
+        const history = Cast(this.rootDoc[this.fieldKey + '_history'], listSpec('string'), []);
         if (checkAvailable) return history.length;
         runInAction(() => {
             if (history.length) {
                 const curUrl = this._url;
-                if (future === undefined) this.dataDoc[this.fieldKey + '-future'] = new List<string>([this._url]);
-                else this.dataDoc[this.fieldKey + '-future'] = new List<string>([...future, this._url]);
+                if (future === undefined) this.dataDoc[this.fieldKey + '_future'] = new List<string>([this._url]);
+                else this.dataDoc[this.fieldKey + '_future'] = new List<string>([...future, this._url]);
                 this.dataDoc[this.fieldKey] = new WebField(new URL(history.pop()!));
                 this._scrollHeight = 0;
                 if (this._webUrl === this._url) {
@@ -643,10 +643,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         if (Field.toString(data) === this._url) return false;
         this._scrollHeight = 0;
         const oldUrl = this._url;
-        const history = Cast(this.rootDoc[this.fieldKey + '-history'], listSpec('string'), []);
+        const history = Cast(this.rootDoc[this.fieldKey + '_history'], listSpec('string'), []);
         const weburl = new WebField(Field.toString(data));
-        this.dataDoc[this.fieldKey + '-future'] = new List<string>([]);
-        this.dataDoc[this.fieldKey + '-history'] = new List<string>([...(history || []), oldUrl]);
+        this.dataDoc[this.fieldKey + '_future'] = new List<string>([]);
+        this.dataDoc[this.fieldKey + '_history'] = new List<string>([...(history || []), oldUrl]);
         this.dataDoc[this.fieldKey] = weburl;
         return true;
     };
@@ -659,7 +659,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const cm = ContextMenu.Instance;
         const funcs: ContextMenuProps[] = [];
         if (!cm.findByDescription('Options...')) {
-            !Doc.noviceMode && funcs.push({ description: (this.layoutDoc.useCors ? "Don't Use" : 'Use') + ' Cors', event: () => (this.layoutDoc.useCors = !this.layoutDoc.useCors), icon: 'snowflake' });
+            !Doc.noviceMode &&
+                funcs.push({ description: (this.layoutDoc[this.fieldKey + '_useCors'] ? "Don't Use" : 'Use') + ' Cors', event: () => (this.layoutDoc[this.fieldKey + '_useCors'] = !this.layoutDoc[this.fieldKey + '_useCors']), icon: 'snowflake' });
             funcs.push({
                 description: (this.layoutDoc.allowScripts ? 'Prevent' : 'Allow') + ' Scripts',
                 event: () => {
@@ -672,12 +673,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 icon: 'snowflake',
             });
             funcs.push({
-                description: (!this.layoutDoc.forceReflow ? 'Force' : 'Prevent') + ' Reflow',
+                description: (!this.layoutDoc.layout_forceReflow ? 'Force' : 'Prevent') + ' Reflow',
                 event: () => {
-                    const nw = !this.layoutDoc.forceReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.NativeDimScaling?.() || 1);
-                    this.layoutDoc.forceReflow = !nw;
+                    const nw = !this.layoutDoc.layout_forceReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.NativeDimScaling?.() || 1);
+                    this.layoutDoc.layout_forceReflow = !nw;
                     if (nw) {
-                        Doc.SetInPlace(this.layoutDoc, this.fieldKey + '-nativeWidth', nw, true);
+                        Doc.SetInPlace(this.layoutDoc, this.fieldKey + '_nativeWidth', nw, true);
                     }
                 },
                 icon: 'snowflake',
@@ -726,7 +727,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         setTimeout(
             action(() => {
                 if (this._initialScroll === undefined && !this._webPageHasBeenRendered) {
-                    this.setScrollPos(NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.scrollTop)));
+                    this.setScrollPos(NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.layout_scrollTop)));
                 }
                 this._webPageHasBeenRendered = true;
             })
@@ -736,7 +737,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             return <span className="webBox-htmlSpan" contentEditable onPointerDown={e => e.stopPropagation()} dangerouslySetInnerHTML={{ __html: field.html }} />;
         }
         if (field instanceof WebField) {
-            const url = this.layoutDoc.useCors ? Utils.CorsProxy(this._webUrl) : this._webUrl;
+            const url = this.layoutDoc[this.fieldKey + '_useCors'] ? Utils.CorsProxy(this._webUrl) : this._webUrl;
             return (
                 <iframe
                     className="webBox-iframe"
@@ -758,7 +759,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
 
     sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
-        if (!this.layoutDoc._showSidebar) this.toggleSidebar();
+        if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
         return this.addDocumentWrapper(doc, sidebarKey);
     };
     @observable _draggingSidebar = false;
@@ -774,15 +775,15 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                     .ScreenToLocalTransform()
                     .scale(this.props.NativeDimScaling?.() || 1)
                     .transformDirection(delta[0], delta[1]);
-                const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']);
-                const nativeHeight = NumCast(this.layoutDoc[this.fieldKey + '-nativeHeight']);
+                const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
+                const nativeHeight = NumCast(this.layoutDoc[this.fieldKey + '_nativeHeight']);
                 const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
                 const ratio = (curNativeWidth + ((onButton ? 1 : -1) * localDelta[0]) / (this.props.NativeDimScaling?.() || 1)) / nativeWidth;
                 if (ratio >= 1) {
                     this.layoutDoc.nativeWidth = nativeWidth * ratio;
                     this.layoutDoc.nativeHeight = nativeHeight * (1 + ratio);
                     onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]);
-                    this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
+                    this.layoutDoc._layout_showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
                 }
                 return false;
             }),
@@ -804,7 +805,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 title="Toggle Sidebar"
                 style={{
                     display: !this.props.isContentActive() ? 'none' : undefined,
-                    top: StrCast(this.layoutDoc._showTitle) === 'title' ? 20 : 5,
+                    top: StrCast(this.layoutDoc._layout_showTitle) === 'title' ? 20 : 5,
                     backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
                 }}
                 onPointerDown={e => this.sidebarBtnDown(e, true)}>
@@ -815,12 +816,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @observable _previewNativeWidth: Opt<number> = undefined;
     @observable _previewWidth: Opt<number> = undefined;
     toggleSidebar = action((preview: boolean = false) => {
-        var nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']);
+        var nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
         if (!nativeWidth) {
             const defaultNativeWidth = this.rootDoc[this.fieldKey] instanceof WebField ? 850 : this.Document[WidthSym]();
             Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || defaultNativeWidth);
             Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || (this.Document[HeightSym]() / this.Document[WidthSym]()) * defaultNativeWidth);
-            nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']);
+            nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
         }
         const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth;
         const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth + WebBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth;
@@ -830,10 +831,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             this._previewWidth = (this.layoutDoc[WidthSym]() * nativeWidth * sideratio) / curNativeWidth;
             this._showSidebar = true;
         } else {
-            this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar;
+            this.layoutDoc._layout_showSidebar = !this.layoutDoc._layout_showSidebar;
             this.layoutDoc._width = (this.layoutDoc[WidthSym]() * nativeWidth * pdfratio) / curNativeWidth;
-            if (!this.layoutDoc._showSidebar && !(this.dataDoc[this.fieldKey] instanceof WebField)) {
-                this.layoutDoc.nativeWidth = this.dataDoc[this.fieldKey + '-nativeWidth'] = undefined;
+            if (!this.layoutDoc._layout_showSidebar && !(this.dataDoc[this.fieldKey] instanceof WebField)) {
+                this.layoutDoc.nativeWidth = this.dataDoc[this.fieldKey + '_nativeWidth'] = undefined;
             } else {
                 this.layoutDoc.nativeWidth = nativeWidth * pdfratio;
             }
@@ -862,8 +863,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 className={'webBox-cont' + (interactive ? '-interactive' : '')}
                 onKeyDown={e => e.stopPropagation()}
                 style={{
-                    width: !this.layoutDoc.forceReflow ? NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']) || `100%` : '100%',
-                    transform: `scale(${this.zoomScaling()})  translate(${-NumCast(this.layoutDoc.panX)}px, ${-NumCast(this.layoutDoc.panY)}px)`,
+                    width: !this.layoutDoc.layout_forceReflow ? NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']) || `100%` : '100%',
+                    transform: `scale(${this.zoomScaling()})  translate(${-NumCast(this.layoutDoc.freeform_panX)}px, ${-NumCast(this.layoutDoc.freeform_panY)}px)`,
                 }}>
                 {this._hackHide || (this.webThumb && !this._webPageHasBeenRendered && LightboxView.LightboxDoc !== this.rootDoc) ? null : this.urlContent}
             </div>
@@ -876,7 +877,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             <div
                 className="webBox-annotationLayer"
                 style={{
-                    transform: `scale(${this.zoomScaling()})  translate(${-NumCast(this.layoutDoc.panX)}px, ${-NumCast(this.layoutDoc.panY)}px)`,
+                    transform: `scale(${this.zoomScaling()})  translate(${-NumCast(this.layoutDoc.freeform_panX)}px, ${-NumCast(this.layoutDoc.freeform_panY)}px)`,
                     height: Doc.NativeHeight(this.Document) || undefined,
                 }}
                 ref={this._annotationLayer}>
@@ -889,7 +890,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         );
     }
     @computed get SidebarShown() {
-        return this._showSidebar || this.layoutDoc._showSidebar ? true : false;
+        return this._showSidebar || this.layoutDoc._layout_showSidebar ? true : false;
     }
 
     @computed get webpage() {
@@ -914,7 +915,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 ScreenToLocalTransform={this.scrollXf}
                 NativeDimScaling={returnOne}
                 focus={this.focus}
-                dropAction={'alias'}
+                dropAction="embed"
                 docFilters={docFilters}
                 select={emptyFunction}
                 isAnyChildContentActive={returnFalse}
@@ -989,7 +990,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func);
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth() + WebBox.sidebarResizerWidth;
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
-    scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop));
+    scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
     transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
     opaqueFilter = () => [...this.props.docFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
@@ -1055,7 +1056,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         ref={this._sidebarRef}
                         {...this.props}
                         whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
-                        fieldKey={this.fieldKey + '-' + this._urlHash}
+                        fieldKey={this.fieldKey + '_' + this._urlHash}
                         rootDoc={this.rootDoc}
                         layoutDoc={this.layoutDoc}
                         dataDoc={this.dataDoc}
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index a4968dcd0..5e615f2c1 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -44,16 +44,12 @@ export enum ButtonType {
     ToggleButton = 'tglBtn',
     ColorButton = 'colorBtn',
     ToolButton = 'toolBtn',
-    NumberButton = 'numBtn',
+    NumberSliderButton = 'numSliderBtn',
+    NumberDropdownButton = 'numDropdownBtn',
+    NumberInlineButton = 'numInlineBtn',
     EditableText = 'editableText',
 }
 
-export enum NumButtonType {
-    Slider = 'slider',
-    DropdownOptions = 'list',
-    Inline = 'inline',
-}
-
 export interface ButtonProps extends FieldViewProps {
     type?: ButtonType;
 }
@@ -132,8 +128,52 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
     /**
      * Number button
      */
-    @computed get numberButton() {
-        const numBtnType: string = StrCast(this.rootDoc.numBtnType);
+    @computed get numberSliderButton() {
+        const numScript = ScriptCast(this.rootDoc.script);
+        const setValue = (value: number) => UndoManager.RunInBatch(() => numScript?.script.run({ self: this.rootDoc, value, _readOnly_: false }), 'set num value');
+
+        // Script for checking the outcome of the toggle
+        const checkResult = Number(numScript?.script.run({ self: this.rootDoc, value: 0, _readOnly_: true }).result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3));
+
+        const label = !FontIconBox.GetShowLabels() ? null : <div className="fontIconBox-label">{this.label}</div>;
+
+        const dropdown = (
+            <div className="menuButton-dropdownBox" onPointerDown={e => e.stopPropagation()}>
+                <input
+                    type="range"
+                    step="1"
+                    min={NumCast(this.rootDoc.numBtnMin, 0)}
+                    max={NumCast(this.rootDoc.numBtnMax, 100)}
+                    value={checkResult}
+                    className="menu-slider"
+                    onPointerDown={() => (this._batch = UndoManager.StartBatch('presDuration'))}
+                    onPointerUp={() => this._batch?.end()}
+                    onChange={e => {
+                        e.stopPropagation();
+                        setValue(Number(e.target.value));
+                    }}
+                />
+            </div>
+        );
+        return (
+            <div
+                className="menuButton numBtn slider"
+                onPointerDown={e => e.stopPropagation()}
+                onClick={action(() => {
+                    this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen;
+                    this.noTooltip = this.rootDoc.dropDownOpen;
+                    Doc.UnBrushAllDocs();
+                })}>
+                {checkResult}
+                {label}
+                {this.rootDoc.dropDownOpen ? dropdown : null}
+            </div>
+        );
+    }
+    /**
+     * Number button
+     */
+    @computed get numberDropdownButton() {
         const numScript = ScriptCast(this.rootDoc.script);
         const setValue = (value: number) => UndoManager.RunInBatch(() => numScript?.script.run({ self: this.rootDoc, value, _readOnly_: false }), 'set num value');
 
@@ -142,102 +182,71 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
 
         const label = !FontIconBox.GetShowLabels() ? null : <div className="fontIconBox-label">{this.label}</div>;
 
-        if (numBtnType === NumButtonType.Slider) {
-            const dropdown = (
-                <div className="menuButton-dropdownBox" onPointerDown={e => e.stopPropagation()}>
-                    <input
-                        type="range"
-                        step="1"
-                        min={NumCast(this.rootDoc.numBtnMin, 0)}
-                        max={NumCast(this.rootDoc.numBtnMax, 100)}
-                        value={checkResult}
-                        className="menu-slider"
-                        onPointerDown={() => (this._batch = UndoManager.StartBatch('presDuration'))}
-                        onPointerUp={() => this._batch?.end()}
-                        onChange={e => {
-                            e.stopPropagation();
-                            setValue(Number(e.target.value));
-                        }}
-                    />
+        const items: number[] = [];
+        for (let i = 0; i < 100; i++) {
+            if (i % 2 === 0) {
+                items.push(i);
+            }
+        }
+        const list = items.map(value => {
+            return (
+                <div
+                    className="list-item"
+                    key={`${value}`}
+                    style={{
+                        backgroundColor: value.toString() === checkResult ? Colors.LIGHT_BLUE : undefined,
+                    }}
+                    onClick={() => setValue(value)}>
+                    {value}
                 </div>
             );
-            return (
+        });
+        return (
+            <div className="menuButton numBtn list">
+                <div className="button" onClick={action(e => setValue(Number(checkResult) - 1))}>
+                    <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'minus'} />
+                </div>
                 <div
-                    className={`menuButton ${this.type} ${numBtnType}`}
-                    onPointerDown={e => e.stopPropagation()}
+                    className={`button ${'number'}`}
+                    onPointerDown={e => {
+                        e.stopPropagation();
+                        e.preventDefault();
+                    }}
                     onClick={action(() => {
                         this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen;
                         this.noTooltip = this.rootDoc.dropDownOpen;
                         Doc.UnBrushAllDocs();
                     })}>
-                    {checkResult}
-                    {label}
-                    {this.rootDoc.dropDownOpen ? dropdown : null}
+                    <input style={{ width: 30 }} className="button-input" type="number" value={checkResult} onChange={undoBatch(action(e => setValue(Number(e.target.value))))} />
+                </div>
+                <div className={`button`} onClick={action(e => setValue(Number(checkResult) + 1))}>
+                    <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'plus'} />
                 </div>
-            );
-        } else if (numBtnType === NumButtonType.DropdownOptions) {
-            const items: number[] = [];
-            for (let i = 0; i < 100; i++) {
-                if (i % 2 === 0) {
-                    items.push(i);
-                }
-            }
-            const list = items.map(value => {
-                return (
-                    <div
-                        className="list-item"
-                        key={`${value}`}
-                        style={{
-                            backgroundColor: value.toString() === checkResult ? Colors.LIGHT_BLUE : undefined,
-                        }}
-                        onClick={() => setValue(value)}>
-                        {value}
-                    </div>
-                );
-            });
-            return (
-                <div className={`menuButton ${this.type} ${numBtnType}`}>
-                    <div className={`button`} onClick={action(e => setValue(Number(checkResult) - 1))}>
-                        <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'minus'} />
-                    </div>
-                    <div
-                        className={`button ${'number'}`}
-                        onPointerDown={e => {
-                            e.stopPropagation();
-                            e.preventDefault();
-                        }}
-                        onClick={action(() => {
-                            this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen;
-                            this.noTooltip = this.rootDoc.dropDownOpen;
-                            Doc.UnBrushAllDocs();
-                        })}>
-                        <input style={{ width: 30 }} className="button-input" type="number" value={checkResult} onChange={undoBatch(action(e => setValue(Number(e.target.value))))} />
-                    </div>
-                    <div className={`button`} onClick={action(e => setValue(Number(checkResult) + 1))}>
-                        <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'plus'} />
-                    </div>
 
-                    {this.rootDoc.dropDownOpen ? (
-                        <div>
-                            <div className="menuButton-dropdownList" style={{ left: '25%' }}>
-                                {list}
-                            </div>
-                            <div
-                                className="dropbox-background"
-                                onClick={action(e => {
-                                    e.stopPropagation();
-                                    this.rootDoc.dropDownOpen = false;
-                                    this.noTooltip = false;
-                                    Doc.UnBrushAllDocs();
-                                })}
-                            />
+                {this.rootDoc.dropDownOpen ? (
+                    <div>
+                        <div className="menuButton-dropdownList" style={{ left: '25%' }}>
+                            {list}
                         </div>
-                    ) : null}
-                </div>
-            );
-        } else {
-            return <div />;
-        }
+                        <div
+                            className="dropbox-background"
+                            onClick={action(e => {
+                                e.stopPropagation();
+                                this.rootDoc.dropDownOpen = false;
+                                this.noTooltip = false;
+                                Doc.UnBrushAllDocs();
+                            })}
+                        />
+                    </div>
+                ) : null}
+            </div>
+        );
+    }
+    /**
+     * Number button
+     */
+    @computed get numberInlineButton() {
+        return <div />;
     }
 
     /**
@@ -528,7 +537,9 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
             case ButtonType.EditableText: return this.editableText;
             case ButtonType.DropdownList: button = this.dropdownListButton; break;
             case ButtonType.ColorButton: button = this.colorButton; break;
-            case ButtonType.NumberButton: button = this.numberButton; break;
+            case ButtonType.NumberDropdownButton: button = this.numberDropdownButton; break;
+            case ButtonType.NumberInlineButton: button = this.numberInlineButton; break;
+            case ButtonType.NumberSliderButton: button = this.numberSliderButton; break;
             case ButtonType.DropdownButton: button = this.dropdownButton; break;
             case ButtonType.ToggleButton: button = this.toggleButton; break;
             case ButtonType.TextButton: 
@@ -613,7 +624,7 @@ ScriptingGlobals.add(function setHeaderColor(color?: string, checkResult?: boole
     }
     Doc.SharingDoc().userColor = undefined;
     Doc.GetProto(Doc.SharingDoc()).userColor = color;
-    Doc.UserDoc().showTitle = color === 'transparent' ? undefined : StrCast(Doc.UserDoc().showTitle, 'creationDate');
+    Doc.UserDoc().layout_showTitle = color === 'transparent' ? undefined : StrCast(Doc.UserDoc().layout_showTitle, 'creationDate');
 });
 
 // toggle: Set overlay status of selected document
@@ -626,29 +637,29 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) {
     selected ? selected.props.CollectionFreeFormDocumentView?.().float() : console.log('[FontIconBox.tsx] toggleOverlay failed');
 });
 
-ScriptingGlobals.add(function showFreeform(attr: 'grid' | 'snapline' | 'clusters' | 'arrange' | 'viewAll', checkResult?: boolean) {
+ScriptingGlobals.add(function showFreeform(attr: 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll', checkResult?: boolean) {
     const selected = SelectionManager.Docs().lastElement();
     // prettier-ignore
-    const map: Map<'grid' | 'snapline' | 'clusters' | 'arrange'| 'viewAll', { undo: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc) => void;}> = new Map([
+    const map: Map<'grid' | 'snaplines' | 'clusters' | 'arrange'| 'viewAll', { undo: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc) => void;}> = new Map([
         ['grid', {
             undo: false,
-            checkResult: (doc:Doc) => doc._backgroundGridShow,
-            setDoc: (doc:Doc) => doc._backgroundGridShow = !doc._backgroundGridShow,
+            checkResult: (doc:Doc) => doc._freeform_backgroundGrid,
+            setDoc: (doc:Doc) => doc._freeform_backgroundGrid = !doc._freeform_backgroundGrid,
         }],
-        ['snapline', {
+        ['snaplines', {
             undo: false,
-            checkResult: (doc:Doc) => doc.showSnapLines,
-            setDoc: (doc:Doc) => doc._showSnapLines = !doc._showSnapLines,
+            checkResult: (doc:Doc) => doc._freeform_snapLines,
+            setDoc: (doc:Doc) => doc._freeform_snapLines = !doc._freeform_snapLines,
         }],
         ['viewAll', {
             undo: false,
-            checkResult: (doc:Doc) => doc._fitContentsToBox,
-            setDoc: (doc:Doc) => doc._fitContentsToBox = !doc._fitContentsToBox,
+            checkResult: (doc:Doc) => doc._freeform_fitContentsToBox,
+            setDoc: (doc:Doc) => doc._freeform_fitContentsToBox = !doc._freeform_fitContentsToBox,
         }],
         ['clusters', {
             undo: false,
-            checkResult: (doc:Doc) => doc._useClusters,
-            setDoc: (doc:Doc) => doc._useClusters = !doc._useClusters,
+            checkResult: (doc:Doc) => doc._freeform_useClusters,
+            setDoc: (doc:Doc) => doc._freeform_useClusters = !doc._freeform_useClusters,
         }],
         ['arrange', {
             undo: true,
@@ -850,8 +861,8 @@ ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'fillColor' | '
     // prettier-ignore
     const map: Map<'inkMask' | 'fillColor' | 'strokeWidth' | 'strokeColor', { checkResult: () => any; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([
         ['inkMask', {
-            checkResult: () => ((selected?.type === DocumentType.INK ? BoolCast(selected.isInkMask) : ActiveIsInkMask()) ? Colors.MEDIUM_BLUE : 'transparent'),
-            setInk: (doc: Doc) => (doc.isInkMask = !doc.isInkMask),
+            checkResult: () => ((selected?.type === DocumentType.INK ? BoolCast(selected.stroke_isInkMask) : ActiveIsInkMask()) ? Colors.MEDIUM_BLUE : 'transparent'),
+            setInk: (doc: Doc) => (doc.stroke_isInkMask = !doc.stroke_isInkMask),
             setMode: () => selected?.type !== DocumentType.INK && SetActiveIsInkMask(!ActiveIsInkMask()),
         }],
         ['fillColor', {
@@ -860,8 +871,8 @@ ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'fillColor' | '
             setMode: () => SetActiveFillColor(StrCast(value)),
         }],
         [ 'strokeWidth', {
-            checkResult: () => (selected?.type === DocumentType.INK ? NumCast(selected.strokeWidth) : ActiveInkWidth()),
-            setInk: (doc: Doc) => (doc.strokeWidth = NumCast(value)),
+            checkResult: () => (selected?.type === DocumentType.INK ? NumCast(selected.stroke_width) : ActiveInkWidth()),
+            setInk: (doc: Doc) => (doc.stroke_width = NumCast(value)),
             setMode: () => SetActiveInkWidth(value.toString()),
         }],
         ['strokeColor', {
@@ -914,24 +925,24 @@ ScriptingGlobals.add(function webBack(checkResult?: boolean) {
 ScriptingGlobals.add(function toggleSchemaPreview(checkResult?: boolean) {
     const selected = SelectionManager.Docs().lastElement();
     if (checkResult && selected) {
-        const result: boolean = NumCast(selected.schemaPreviewWidth) > 0;
+        const result: boolean = NumCast(selected.schema_previewWidth) > 0;
         if (result) return Colors.MEDIUM_BLUE;
         else return 'transparent';
     } else if (selected) {
-        if (NumCast(selected.schemaPreviewWidth) > 0) {
-            selected.schemaPreviewWidth = 0;
+        if (NumCast(selected.schema_previewWidth) > 0) {
+            selected.schema_previewWidth = 0;
         } else {
-            selected.schemaPreviewWidth = 200;
+            selected.schema_previewWidth = 200;
         }
     }
 });
 ScriptingGlobals.add(function toggleSingleLineSchema(checkResult?: boolean) {
     const selected = SelectionManager.Docs().lastElement();
     if (checkResult && selected) {
-        return NumCast(selected._singleLine) > 0 ? Colors.MEDIUM_BLUE : 'transparent';
+        return NumCast(selected._schema_singleLine) > 0 ? Colors.MEDIUM_BLUE : 'transparent';
     }
     if (selected) {
-        selected._singleLine = !selected._singleLine;
+        selected._schema_singleLine = !selected._schema_singleLine;
     }
 });
 
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index c05a30d1a..c929b7ff3 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -41,18 +41,33 @@ export class DashDocView {
 
         this.root = ReactDOM.createRoot(this.dom);
         this.root.render(
-            <DashDocViewInternal docId={node.attrs.docId} alias={node.attrs.alias} width={node.attrs.width} height={node.attrs.height} hidden={node.attrs.hidden} fieldKey={node.attrs.fieldKey} tbox={tbox} view={view} node={node} getPos={getPos} />
+            <DashDocViewInternal
+                docId={node.attrs.docId}
+                embedding={node.attrs.embedding}
+                width={node.attrs.width}
+                height={node.attrs.height}
+                hidden={node.attrs.hidden}
+                fieldKey={node.attrs.fieldKey}
+                tbox={tbox}
+                view={view}
+                node={node}
+                getPos={getPos}
+            />
         );
     }
     destroy() {
-        setTimeout(this.root.unmount);
+        setTimeout(() => {
+            try {
+                this.root.unmount();
+            } catch {}
+        });
     }
     selectNode() {}
 }
 
 interface IDashDocViewInternal {
     docId: string;
-    alias: string;
+    embedding: string;
     tbox: FormattedTextBox;
     width: string;
     height: string;
@@ -69,25 +84,18 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
     _textBox: FormattedTextBox;
     @observable _dashDoc: Doc | undefined;
     @observable _finalLayout: any;
-    @observable _resolvedDataDoc: any;
     @observable _width: number = 0;
     @observable _height: number = 0;
 
     updateDoc = action((dashDoc: Doc) => {
         this._dashDoc = dashDoc;
-        this._finalLayout = this.props.docId ? dashDoc : Doc.expandTemplateLayout(Doc.Layout(dashDoc), dashDoc);
+        this._finalLayout = dashDoc;
 
-        if (this._finalLayout) {
-            if (!Doc.AreProtosEqual(this._finalLayout, dashDoc)) {
-                this._finalLayout.rootDocument = dashDoc.aliasOf;
-            }
-            this._resolvedDataDoc = Cast(this._finalLayout.resolvedDataDoc, Doc, null);
-        }
         if (this.props.width !== (this._dashDoc?._width ?? '') + 'px' || this.props.height !== (this._dashDoc?._height ?? '') + 'px') {
             try {
                 this._width = NumCast(this._dashDoc?._width);
                 this._height = NumCast(this._dashDoc?._height);
-                // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made
+                // bcz: an exception will be thrown if two embeddings are open at the same time when a doc view comment is made
                 this.props.view.dispatch(
                     this.props.view.state.tr.setNodeMarkup(this.props.getPos(), null, {
                         ...this.props.node.attrs,
@@ -105,15 +113,15 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
         super(props);
         this._textBox = this.props.tbox;
 
-        DocServer.GetRefField(this.props.docId + this.props.alias).then(async dashDoc => {
+        DocServer.GetRefField(this.props.docId + this.props.embedding).then(async dashDoc => {
             if (!(dashDoc instanceof Doc)) {
-                this.props.alias &&
+                this.props.embedding &&
                     DocServer.GetRefField(this.props.docId).then(async dashDocBase => {
                         if (dashDocBase instanceof Doc) {
-                            const aliasedDoc = Doc.MakeAlias(dashDocBase, this.props.docId + this.props.alias);
-                            aliasedDoc.layoutKey = 'layout';
-                            this.props.fieldKey && DocUtils.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, this.props.fieldKey, undefined);
-                            this.updateDoc(aliasedDoc);
+                            const embedding = Doc.MakeEmbedding(dashDocBase, this.props.docId + this.props.embedding);
+                            embedding.layout_fieldKey = 'layout';
+                            this.props.fieldKey && DocUtils.makeCustomViewClicked(embedding, Docs.Create.StackingDocument, this.props.fieldKey, undefined);
+                            this.updateDoc(embedding);
                         }
                     });
             } else {
@@ -191,7 +199,6 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                 onWheel={e => e.preventDefault()}>
                 <DocumentView
                     Document={this._finalLayout}
-                    DataDoc={this._resolvedDataDoc}
                     addDocument={returnFalse}
                     rootSelected={returnFalse} //{this._textBox.props.isSelected}
                     removeDocument={this.removeDoc}
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index a9e59ab1c..6c61f6709 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -143,16 +143,17 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     createPivotForField = (e: React.MouseEvent) => {
         let container = this.props.tbox.props.DocumentView?.().props.docViewPath().lastElement();
         if (container) {
-            const alias = Doc.MakeAlias(container.props.Document);
-            alias._viewType = CollectionViewType.Time;
-            let list = Cast(alias._columnHeaders, listSpec(SchemaHeaderField));
+            const embedding = Doc.MakeEmbedding(container.rootDoc);
+            embedding._viewType = CollectionViewType.Time;
+            const colHdrKey = '_' + container.LayoutFieldKey + '_columnHeaders';
+            let list = Cast(embedding[colHdrKey], listSpec(SchemaHeaderField));
             if (!list) {
-                alias._columnHeaders = list = new List<SchemaHeaderField>();
+                embedding[colHdrKey] = list = new List<SchemaHeaderField>();
             }
             list.map(c => c.heading).indexOf(this._fieldKey) === -1 && list.push(new SchemaHeaderField(this._fieldKey, '#f1efeb'));
             list.map(c => c.heading).indexOf('text') === -1 && list.push(new SchemaHeaderField('text', '#f1efeb'));
-            alias._pivotField = this._fieldKey.startsWith('#') ? 'tags' : this._fieldKey;
-            this.props.tbox.props.addDocTab(alias, OpenWhere.addRight);
+            embedding._pivotField = this._fieldKey.startsWith('#') ? 'tags' : this._fieldKey;
+            this.props.tbox.props.addDocTab(embedding, OpenWhere.addRight);
         }
     };
 
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 88adba1e7..023814a9d 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -118,38 +118,38 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         return this._editorView;
     }
     public get SidebarKey() {
-        return this.fieldKey + '-sidebar';
+        return this.fieldKey + '_sidebar';
     }
     @computed get allSidebarDocs() {
         return DocListCast(this.dataDoc[this.SidebarKey]);
     }
 
     @computed get noSidebar() {
-        return this.props.docViewPath().lastElement()?.props.hideDecorationTitle || this.props.noSidebar || this.Document._noSidebar;
+        return this.props.docViewPath().lastElement()?.props.hideDecorationTitle || this.props.noSidebar || this.Document._layout_noSidebar;
     }
-    @computed get sidebarWidthPercent() {
-        return this._showSidebar ? '20%' : StrCast(this.layoutDoc._sidebarWidthPercent, '0%');
+    @computed get layout_sidebarWidthPercent() {
+        return this._showSidebar ? '20%' : StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.fieldKey + '-backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
-    @computed get autoHeight() {
-        return (this.props.forceAutoHeight || this.layoutDoc._autoHeight) && !this.props.ignoreAutoHeight;
+    @computed get layout_autoHeight() {
+        return (this.props.forceAutoHeight || this.layoutDoc._layout_autoHeight) && !this.props.ignoreAutoHeight;
     }
     @computed get textHeight() {
-        return NumCast(this.rootDoc[this.fieldKey + '-height']);
+        return NumCast(this.rootDoc[this.fieldKey + '_height']);
     }
     @computed get scrollHeight() {
-        return NumCast(this.rootDoc[this.fieldKey + '-scrollHeight']);
+        return NumCast(this.rootDoc[this.fieldKey + '_scrollHeight']);
     }
     @computed get sidebarHeight() {
-        return !this.sidebarWidth() ? 0 : NumCast(this.rootDoc[this.SidebarKey + '-height']);
+        return !this.sidebarWidth() ? 0 : NumCast(this.rootDoc[this.SidebarKey + '_height']);
     }
     @computed get titleHeight() {
         return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0;
     }
-    @computed get autoHeightMargins() {
-        return this.titleHeight + NumCast(this.layoutDoc._autoHeightMargins);
+    @computed get layout_autoHeightMargins() {
+        return this.titleHeight + NumCast(this.layoutDoc._layout_autoHeightMargins);
     }
     @computed get _recording() {
         return this.dataDoc?.mediaState === 'recording';
@@ -213,8 +213,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     public RemoveLinkFromDoc(linkDoc?: Doc) {
         this.unhighlightSearchTerms();
         const state = this._editorView?.state;
-        const a1 = linkDoc?.anchor1 as Doc;
-        const a2 = linkDoc?.anchor2 as Doc;
+        const a1 = linkDoc?.link_anchor_1 as Doc;
+        const a2 = linkDoc?.link_anchor_2 as Doc;
         if (state && a1 && a2 && this._editorView) {
             this.removeDocument(a1);
             this.removeDocument(a2);
@@ -255,18 +255,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         AnchorMenu.Instance.Status = 'marquee';
 
         AnchorMenu.Instance.OnClick = (e: PointerEvent) => {
-            !this.layoutDoc.showSidebar && this.toggleSidebar();
+            !this.layoutDoc.layout_showSidebar && this.toggleSidebar();
             setTimeout(() => this._sidebarRef.current?.anchorMenuClick(this.makeLinkAnchor(undefined, OpenWhere.addRight, undefined, 'Anchored Selection', true))); // give time for sidebarRef to be created
         };
         AnchorMenu.Instance.OnAudio = (e: PointerEvent) => {
-            !this.layoutDoc.showSidebar && this.toggleSidebar();
+            !this.layoutDoc.layout_showSidebar && this.toggleSidebar();
             const anchor = this.makeLinkAnchor(undefined, OpenWhere.addRight, undefined, 'Anchored Selection', true, true);
             setTimeout(() => {
                 const target = this._sidebarRef.current?.anchorMenuClick(anchor);
                 if (target) {
                     anchor.followLinkAudio = true;
                     DocumentViewInternal.recordAudioAnnotation(Doc.GetProto(target), Doc.LayoutFieldKey(target));
-                    target.title = ComputedField.MakeFunction(`self["text-audioAnnotations-text"].lastElement()`);
+                    target.title = ComputedField.MakeFunction(`self["text_audioAnnotations_text"].lastElement()`);
                 }
             });
         };
@@ -323,7 +323,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 if (this._applyingChange !== this.fieldKey && removeSelection(json) !== removeSelection(curProto?.Data)) {
                     this._applyingChange = this.fieldKey;
                     const textChange = curText !== Cast(dataDoc[this.fieldKey], RichTextField)?.Text;
-                    textChange && (dataDoc[this.fieldKey + '-lastModified'] = new DateField(new Date(Date.now())));
+                    textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
                     if ((!curTemp && !curProto) || curText || json.includes('dash')) {
                         // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
                         if (removeSelection(json) !== removeSelection(curLayout?.Data)) {
@@ -333,7 +333,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                             } else {
                                 dataDoc[this.fieldKey] = new RichTextField(json, curText);
                             }
-                            dataDoc[this.fieldKey + '-noTemplate'] = true; //(curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited
+                            dataDoc[this.fieldKey + '_noTemplate'] = true; //(curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited
                             textChange && ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: curText });
                             unchanged = false;
                         }
@@ -341,7 +341,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         // if we've deleted all the text in a note driven by a template, then restore the template data
                         dataDoc[this.fieldKey] = undefined;
                         this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((curProto || curTemp).Data)));
-                        dataDoc[this.fieldKey + '-noTemplate'] = undefined; // mark the data field as not being split from any template it might have
+                        dataDoc[this.fieldKey + '_noTemplate'] = undefined; // mark the data field as not being split from any template it might have
                         ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: curText });
                         unchanged = false;
                     }
@@ -371,7 +371,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         let linkAnchor;
         let link;
         LinkManager.Links(this.dataDoc).forEach((l, i) => {
-            const anchor = (l.anchor1 as Doc).annotationOn ? (l.anchor1 as Doc) : (l.anchor2 as Doc).annotationOn ? (l.anchor2 as Doc) : undefined;
+            const anchor = (l.link_anchor_1 as Doc).annotationOn ? (l.link_anchor_1 as Doc) : (l.link_anchor_2 as Doc).annotationOn ? (l.link_anchor_2 as Doc) : undefined;
             if (anchor && (anchor.annotationOn as Doc).mediaState === 'recording') {
                 linkTime = NumCast(anchor._timecodeToShow /* audioStart */);
                 linkAnchor = anchor;
@@ -407,7 +407,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
 
     autoLink = () => {
         const newAutoLinks = new Set<Doc>();
-        const oldAutoLinks = LinkManager.Links(this.props.Document).filter(link => link.linkRelationship === LinkManager.AutoKeywords);
+        const oldAutoLinks = LinkManager.Links(this.props.Document).filter(link => link.link_relationship === LinkManager.AutoKeywords);
         if (this._editorView?.state.doc.textContent) {
             const isNodeSel = this._editorView.state.selection instanceof NodeSelection;
             const f = this._editorView.state.selection.from;
@@ -419,7 +419,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             tr = tr.setSelection(isNodeSel && false ? new NodeSelection(tr.doc.resolve(f)) : new TextSelection(tr.doc.resolve(f), tr.doc.resolve(t)));
             this._editorView?.dispatch(tr);
         }
-        oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.anchor2 !== this.rootDoc).forEach(LinkManager.Instance.deleteLink);
+        oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.link_anchor_2 !== this.rootDoc).forEach(LinkManager.Instance.deleteLink);
     };
 
     updateTitle = () => {
@@ -428,7 +428,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             !this.props.dontRegisterView && // (this.props.Document.isTemplateForField === "text" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing
             (title.startsWith('-') || title.startsWith('@')) &&
             this._editorView &&
-            !this.dataDoc['title-custom'] &&
+            !this.dataDoc.title_custom &&
             (Doc.LayoutFieldKey(this.rootDoc) === this.fieldKey || this.fieldKey === 'text')
         ) {
             let node = this._editorView.state.doc;
@@ -460,8 +460,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
                             alink =
                                 alink ??
-                                (LinkManager.Links(this.Document).find(link => Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), this.rootDoc) && Doc.AreProtosEqual(Cast(link.anchor2, Doc, null), target)) ||
-                                    DocUtils.MakeLink(this.props.Document, target, { linkRelationship: LinkManager.AutoKeywords })!);
+                                (LinkManager.Links(this.Document).find(link => Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), this.rootDoc) && Doc.AreProtosEqual(Cast(link.link_anchor_2, Doc, null), target)) ||
+                                    DocUtils.MakeLink(this.props.Document, target, { link_relationship: LinkManager.AutoKeywords })!);
                             newAutoLinks.add(alink);
                             const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this.props.Document[Id] }];
                             allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? []));
@@ -528,7 +528,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             this.setupEditor(this.config, this.fieldKey);
             this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc);
         }
-        // if (this.autoHeight) this.tryUpdateScrollHeight();
+        // if (this.layout_autoHeight) this.tryUpdateScrollHeight();
     };
 
     @undoBatch
@@ -554,11 +554,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     docId: target[Id],
                     float: 'unset',
                 });
-                if (!['alias', 'copy'].includes((dragData.dropAction ?? '') as any)) {
+                if (!['embed', 'copy'].includes((dragData.dropAction ?? '') as any)) {
                     dragData.removeDocument?.(dragData.draggedDocuments[0]);
                 }
-                target._fitContentsToBox = true;
-                target.context = this.rootDoc;
+                target._freeform_fitContentsToBox = true;
+                target.embedContainer = this.rootDoc;
                 const view = this._editorView!;
                 view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
                 e.stopPropagation();
@@ -655,14 +655,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
 
     @observable _showSidebar = false;
     @computed get SidebarShown() {
-        return this._showSidebar || this.layoutDoc._showSidebar ? true : false;
+        return this._showSidebar || this.layoutDoc._layout_showSidebar ? true : false;
     }
 
     @action
     toggleSidebar = (preview: boolean = false) => {
         const prevWidth = 1 - this.sidebarWidth() / Number(getComputedStyle(this._ref.current!).width.replace('px', ''));
         if (preview) this._showSidebar = true;
-        else this.layoutDoc._showSidebar = (this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, '0%') === '0%' ? '50%' : '0%') !== '0%';
+        else this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? '50%' : '0%') !== '0%';
 
         this.layoutDoc._width = !preview && this.SidebarShown ? NumCast(this.layoutDoc._width) * 2 : Math.max(20, NumCast(this.layoutDoc._width) * prevWidth);
     };
@@ -685,11 +685,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             .ScreenToLocalTransform()
             .scale(this.props.NativeDimScaling?.() || 1)
             .transformDirection(delta[0], delta[1]);
-        const sidebarWidth = (NumCast(this.layoutDoc._width) * Number(this.sidebarWidthPercent.replace('%', ''))) / 100;
+        const sidebarWidth = (NumCast(this.layoutDoc._width) * Number(this.layout_sidebarWidthPercent.replace('%', ''))) / 100;
         const width = this.layoutDoc[WidthSym]() + localDelta[0];
-        this.layoutDoc._sidebarWidthPercent = Math.max(0, (sidebarWidth + localDelta[0]) / width) * 100 + '%';
+        this.layoutDoc._layout_sidebarWidthPercent = Math.max(0, (sidebarWidth + localDelta[0]) / width) * 100 + '%';
         this.layoutDoc.width = width;
-        this.layoutDoc._showSidebar = this.layoutDoc._sidebarWidthPercent !== '0%';
+        this.layoutDoc._layout_showSidebar = this.layoutDoc._layout_sidebarWidthPercent !== '0%';
         e.preventDefault();
         return false;
     };
@@ -757,7 +757,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             description: 'plain',
             event: undoBatch(() => {
                 Doc.setNativeView(this.rootDoc);
-                this.layoutDoc.autoHeightMargins = undefined;
+                this.layoutDoc.layout_autoHeightMargins = undefined;
             }),
             icon: 'eye',
         });
@@ -765,18 +765,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             description: 'metadata',
             event: undoBatch(() => {
                 this.dataDoc.layout_meta = Cast(Doc.UserDoc().emptyHeader, Doc, null)?.layout;
-                this.rootDoc.layoutKey = 'layout_meta';
-                setTimeout(() => (this.rootDoc._headerHeight = this.rootDoc._autoHeightMargins = 50), 50);
+                this.rootDoc.layout_fieldKey = 'layout_meta';
+                setTimeout(() => (this.rootDoc._headerHeight = this.rootDoc._layout_autoHeightMargins = 50), 50);
             }),
             icon: 'eye',
         });
-        const noteTypesDoc = Cast(Doc.UserDoc()['template-notes'], Doc, null);
+        const noteTypesDoc = Cast(Doc.UserDoc().template_notes, Doc, null);
         DocListCast(noteTypesDoc?.data).forEach(note => {
             const icon: IconProp = StrCast(note.icon) as IconProp;
             changeItems.push({
                 description: StrCast(note.title),
                 event: undoBatch(() => {
-                    this.layoutDoc.autoHeightMargins = undefined;
+                    this.layoutDoc.layout_autoHeightMargins = undefined;
                     Doc.setNativeView(this.rootDoc);
                     DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note);
                 }),
@@ -802,11 +802,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         );
 
         const uicontrols: ContextMenuProps[] = [];
-        uicontrols.push({ description: !this.Document._noSidebar ? 'Hide Sidebar Handle' : 'Show Sidebar Handle', event: () => (this.layoutDoc._noSidebar = !this.layoutDoc._noSidebar), icon: !this.Document._noSidebar ? 'eye-slash' : 'eye' });
         uicontrols.push({
-            description: (this.Document._showAltContentUI ? 'Hide' : 'Show') + ' Alt Content UI',
-            event: () => (this.layoutDoc._showAltContentUI = !this.layoutDoc._showAltContentUI),
-            icon: !this.Document._showAltContentUI ? 'eye-slash' : 'eye',
+            description: !this.Document._layout_noSidebar ? 'Hide Sidebar Handle' : 'Show Sidebar Handle',
+            event: () => (this.layoutDoc._layout_noSidebar = !this.layoutDoc._layout_noSidebar),
+            icon: !this.Document._layout_noSidebar ? 'eye-slash' : 'eye',
+        });
+        uicontrols.push({
+            description: (this.Document._layout_altContentUI ? 'Hide' : 'Show') + ' Alt Content UI',
+            event: () => (this.layoutDoc._layout_altContentUI = !this.layoutDoc._layout_altContentUI),
+            icon: !this.Document._layout_altContentUI ? 'eye-slash' : 'eye',
         });
         uicontrols.push({ description: 'Show Highlights...', noexpand: true, subitems: highlighting, icon: 'hand-point-right' });
         !Doc.noviceMode &&
@@ -837,10 +841,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         this.rootDoc.title = this.layoutDoc.isTemplateForField as string;
                         this.rootDoc.isTemplateDoc = false;
                         this.rootDoc.isTemplateForField = '';
-                        this.rootDoc.layoutKey = 'layout';
+                        this.rootDoc.layout_fieldKey = 'layout';
                         MakeTemplate(this.rootDoc, true, title);
                         setTimeout(() => {
-                            this.rootDoc._autoHeight = this.layoutDoc._autoHeight; // autoHeight, width and height
+                            this.rootDoc._layout_autoHeight = this.layoutDoc._layout_autoHeight; // layout_autoHeight, width and height
                             this.rootDoc._width = this.layoutDoc._width || 300; // are stored on the template, since we're getting rid of the old template
                             this.rootDoc._height = this.layoutDoc._height || 200; // we need to copy them over to the root.  This should probably apply to all '_' fields
                             this.rootDoc._backgroundColor = Cast(this.layoutDoc._backgroundColor, 'string', null);
@@ -848,7 +852,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         }, 10);
                     }
                     Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc);
-                    Doc.AddDocToList(Cast(Doc.UserDoc()['template-notes'], Doc, null), 'data', this.rootDoc);
+                    Doc.AddDocToList(Cast(Doc.UserDoc().template_notes, Doc, null), 'data', this.rootDoc);
                 },
                 icon: 'eye',
             });
@@ -859,11 +863,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         optionItems.push({ description: `Generate Dall-E Image`, event: () => this.generateImage(), icon: 'star' });
         optionItems.push({ description: `Ask GPT-3`, event: () => this.askGPT(), icon: 'lightbulb' });
         optionItems.push({
-            description: !this.Document._singleLine ? 'Create New Doc on Carriage Return' : 'Allow Carriage Returns',
-            event: () => (this.layoutDoc._singleLine = !this.layoutDoc._singleLine),
-            icon: !this.Document._singleLine ? 'grip-lines' : 'bars',
+            description: !this.Document._createDocOnCR ? 'Create New Doc on Carriage Return' : 'Allow Carriage Returns',
+            event: () => (this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR),
+            icon: !this.Document._createDocOnCR ? 'grip-lines' : 'bars',
         });
-        !Doc.noviceMode && optionItems.push({ description: `${this.Document._autoHeight ? 'Lock' : 'Auto'} Height`, event: () => (this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight), icon: this.Document._autoHeight ? 'lock' : 'unlock' });
+        !Doc.noviceMode &&
+            optionItems.push({
+                description: `${this.Document._layout_autoHeight ? 'Lock' : 'Auto'} Height`,
+                event: () => (this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight),
+                icon: this.Document._layout_autoHeight ? 'lock' : 'unlock',
+            });
         optionItems.push({ description: `show markdown options`, event: RTFMarkup.Instance.open, icon: 'text' });
         !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' });
         this._downX = this._downY = Number.NaN;
@@ -903,8 +912,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     y: NumCast(this.rootDoc.y),
                     _height: 200,
                     _width: 200,
-                    'data-nativeWidth': result.nativeWidth,
-                    'data-nativeHeight': result.nativeHeight,
+                    data_nativeWidth: result.nativeWidth,
+                    data_nativeHeight: result.nativeHeight,
                 });
                 if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.rootDoc)) {
                     newDoc.overlayX = this.rootDoc.x;
@@ -914,7 +923,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     this.props.addDocument?.(newDoc);
                 }
                 // Create link between prompt and image
-                DocUtils.MakeLink(this.rootDoc, newDoc, { linkRelationship: 'Image Prompt' });
+                DocUtils.MakeLink(this.rootDoc, newDoc, { link_relationship: 'Image Prompt' });
             }
         } catch (err) {
             console.log(err);
@@ -957,8 +966,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 const link = DocUtils.MakeLinkToActiveAudio(textanchorFunc, false).lastElement();
                 if (link) {
                     Doc.GetProto(link).isDictation = true;
-                    const audioanchor = Cast(link.anchor2, Doc, null);
-                    const textanchor = Cast(link.anchor1, Doc, null);
+                    const audioanchor = Cast(link.link_anchor_2, Doc, null);
+                    const textanchor = Cast(link.link_anchor_1, Doc, null);
                     if (audioanchor) {
                         audioanchor.backgroundColor = 'tan';
                         const audiotag = this._editorView.state.schema.nodes.audiotag.create({
@@ -1082,11 +1091,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         }
     };
 
-    // if the scroll height has changed and we're in autoHeight mode, then we need to update the textHeight component of the doc.
+    // if the scroll height has changed and we're in layout_autoHeight mode, then we need to update the textHeight component of the doc.
     // Since we also monitor all component height changes, this will update the document's height.
     resetNativeHeight = (scrollHeight: number) => {
         const nh = this.layoutDoc.isTemplateForField ? 0 : NumCast(this.layoutDoc._nativeHeight);
-        this.rootDoc[this.fieldKey + '-height'] = scrollHeight;
+        this.rootDoc[this.fieldKey + '_height'] = scrollHeight;
         if (nh) this.layoutDoc._nativeHeight = scrollHeight;
     };
 
@@ -1097,9 +1106,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         !this.props.dontSelectOnLoad && this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document.  this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
         this._cachedLinks = LinkManager.Links(this.Document);
         this._disposers.breakupDictation = reaction(() => DocumentManager.Instance.RecordingEvent, this.breakupDictation);
-        this._disposers.autoHeight = reaction(
-            () => this.autoHeight,
-            autoHeight => autoHeight && this.tryUpdateScrollHeight()
+        this._disposers.layout_autoHeight = reaction(
+            () => this.layout_autoHeight,
+            layout_autoHeight => layout_autoHeight && this.tryUpdateScrollHeight()
         );
         this._disposers.highlights = reaction(
             () => Array.from(FormattedTextBox._globalHighlights).slice(),
@@ -1111,16 +1120,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             width => this.tryUpdateScrollHeight()
         );
         this._disposers.scrollHeight = reaction(
-            () => ({ scrollHeight: this.scrollHeight, autoHeight: this.autoHeight, width: NumCast(this.layoutDoc._width) }),
-            ({ width, scrollHeight, autoHeight }) => width && autoHeight && this.resetNativeHeight(scrollHeight),
+            () => ({ scrollHeight: this.scrollHeight, layout_autoHeight: this.layout_autoHeight, width: NumCast(this.layoutDoc._width) }),
+            ({ width, scrollHeight, layout_autoHeight }) => width && layout_autoHeight && this.resetNativeHeight(scrollHeight),
             { fireImmediately: true }
         );
         this._disposers.componentHeights = reaction(
-            // set the document height when one of the component heights changes and autoHeight is on
-            () => ({ sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, autoHeight: this.autoHeight, marginsHeight: this.autoHeightMargins }),
-            ({ sidebarHeight, textHeight, autoHeight, marginsHeight }) => {
+            // set the document height when one of the component heights changes and layout_autoHeight is on
+            () => ({ sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, layout_autoHeight: this.layout_autoHeight, marginsHeight: this.layout_autoHeightMargins }),
+            ({ sidebarHeight, textHeight, layout_autoHeight, marginsHeight }) => {
                 const newHeight = this.contentScaling * (marginsHeight + Math.max(sidebarHeight, textHeight));
-                if (autoHeight && newHeight && newHeight !== this.rootDoc.height && !this.props.dontRegisterView) {
+                if (layout_autoHeight && newHeight && newHeight !== this.rootDoc.height && !this.props.dontRegisterView) {
                     this.props.setHeight?.(newHeight);
                 }
             },
@@ -1145,7 +1154,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         this._disposers.editorState = reaction(
             () => {
                 const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc?.proto), this.fieldKey) ? DocCast(this.layoutDoc?.proto) : this?.dataDoc;
-                const whichDoc = !this.dataDoc || !this.layoutDoc ? undefined : dataDoc?.[this.fieldKey + '-noTemplate'] || !this.layoutDoc[this.fieldKey] ? dataDoc : this.layoutDoc;
+                const whichDoc = !this.dataDoc || !this.layoutDoc ? undefined : dataDoc?.[this.fieldKey + '_noTemplate'] || !this.layoutDoc[this.fieldKey] ? dataDoc : this.layoutDoc;
                 return !whichDoc ? undefined : { data: Cast(whichDoc[this.fieldKey], RichTextField, null), str: Field.toString(whichDoc[this.fieldKey]) };
             },
             incomingValue => {
@@ -1223,7 +1232,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         }
         var quickScroll: string | undefined = '';
         this._disposers.scroll = reaction(
-            () => NumCast(this.layoutDoc._scrollTop),
+            () => NumCast(this.layoutDoc._layout_scrollTop),
             pos => {
                 if (!this._ignoreScroll && this._scrollRef.current && !this.props.dontSelectOnLoad) {
                     const viewTrans = quickScroll ?? StrCast(this.Document._viewTransition);
@@ -1300,7 +1309,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 }
             }, 0);
             dataDoc.title = exportState.title;
-            this.dataDoc['title-custom'] = true;
+            this.dataDoc.title_custom = true;
             dataDoc.googleDocUnchanged = true;
         } else {
             delete dataDoc[GoogleRef];
@@ -1357,7 +1366,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                             view.state.schema.marks.linkAnchor.create({
                                 allAnchors: [{ href: `/doc/${this.rootDoc[Id]}`, title: this.rootDoc.title, anchorId: `${this.rootDoc[Id]}` }],
                                 location: 'add:right',
-                                title: `from: ${DocCast(pdfAnchor.context).title}`,
+                                title: `from: ${DocCast(pdfAnchor.embedContainer).title}`,
                                 noPreview: true,
                                 docref: false,
                             }),
@@ -1366,7 +1375,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         ]),
                     ]);
 
-                    const link = DocUtils.MakeLink(pdfAnchor, this.rootDoc, { linkRelationship: 'PDF pasted' });
+                    const link = DocUtils.MakeLink(pdfAnchor, this.rootDoc, { link_relationship: 'PDF pasted' });
                     if (link) {
                         view.dispatch(view.state.tr.replaceSelectionWith(dashField, false).scrollIntoView().setMeta('paste', true).setMeta('uiEvent', 'paste'));
                     }
@@ -1454,7 +1463,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 if (startupText) {
                     dispatch(state.tr.insertText(startupText));
                 }
-                const textAlign = StrCast(this.dataDoc['text-align'], StrCast(Doc.UserDoc().textAlign, 'left'));
+                const textAlign = StrCast(this.dataDoc.text_align, StrCast(Doc.UserDoc().textAlign, 'left'));
                 if (textAlign !== 'left') {
                     selectAll(this._editorView.state, tr => {
                         this._editorView!.dispatch(tr.replaceSelectionWith(state.schema.nodes.paragraph.create({ align: textAlign })));
@@ -1527,7 +1536,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         } else (e.nativeEvent as any).handledByInnerReactInstance = true;
 
         if (this.Document.forceActive) e.stopPropagation();
-        this.tryUpdateScrollHeight(); // if a doc a fitWidth doc is being viewed in different context (eg freeform & lightbox), then it will have conflicting heights.  so when the doc is clicked on, we want to make sure it has the appropriate height for the selected view.
+        this.tryUpdateScrollHeight(); // if a doc a fitWidth doc is being viewed in different embedContainer (eg freeform & lightbox), then it will have conflicting heights.  so when the doc is clicked on, we want to make sure it has the appropriate height for the selected view.
         if ((e.target as any).tagName === 'AUDIOTAG') {
             e.preventDefault();
             e.stopPropagation();
@@ -1730,7 +1739,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     setTimeout(
                         () =>
                             translateGoogleApi(result1[0], { from: 'es', to: 'en' }).then((result: any) => {
-                                this.dataDoc[this.fieldKey + '-translation'] = result1 + '\r\n\r\n' + result[0];
+                                this.dataDoc[this.fieldKey + '_translation'] = result1 + '\r\n\r\n' + result[0];
                             }),
                         1000
                     );
@@ -1740,10 +1749,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             }
             this._lastText = curText;
         }
-        if (StrCast(this.rootDoc.title).startsWith('@') && !this.dataDoc['title-custom']) {
+        if (StrCast(this.rootDoc.title).startsWith('@') && !this.dataDoc.title_custom) {
             UndoManager.RunInBatch(() => {
-                this.dataDoc['title-custom'] = true;
-                this.dataDoc.showTitle = 'title';
+                this.dataDoc.title_custom = true;
+                this.dataDoc.layout_showTitle = 'title';
                 const tr = this._editorView!.state.tr;
                 this._editorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(0), tr.doc.resolve(StrCast(this.rootDoc.title).length + 2))).deleteSelection());
             }, 'titler');
@@ -1803,7 +1812,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         if (!LinkDocPreview.LinkInfo && this._scrollRef.current) {
             if (!this.props.dontSelectOnLoad) {
                 this._ignoreScroll = true;
-                this.layoutDoc._scrollTop = this._scrollRef.current.scrollTop;
+                this.layoutDoc._layout_scrollTop = this._scrollRef.current.scrollTop;
                 this._ignoreScroll = false;
                 e.stopPropagation();
                 e.preventDefault();
@@ -1823,7 +1832,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
             if (this.props.setHeight && scrollHeight && !this.props.dontRegisterView) {
                 // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
-                const setScrollHeight = () => (this.rootDoc[this.fieldKey + '-scrollHeight'] = scrollHeight);
+                const setScrollHeight = () => (this.rootDoc[this.fieldKey + '_scrollHeight'] = scrollHeight);
                 if (this.rootDoc === this.layoutDoc || this.layoutDoc.resolvedDataDoc) {
                     setScrollHeight();
                 } else {
@@ -1832,21 +1841,21 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             }
         }
     };
-    fitContentsToBox = () => BoolCast(this.props.Document._fitContentsToBox);
-    sidebarContentScaling = () => (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
+    fitContentsToBox = () => BoolCast(this.props.Document._freeform_fitContentsToBox);
+    sidebarContentScaling = () => (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
     sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => {
-        if (!this.layoutDoc._showSidebar) this.toggleSidebar();
+        if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
         return this.addDocument(doc, sidebarKey);
     };
     sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey);
     sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey);
-    setSidebarHeight = (height: number) => (this.rootDoc[this.SidebarKey + '-height'] = height);
-    sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
+    setSidebarHeight = (height: number) => (this.rootDoc[this.SidebarKey + '_height'] = height);
+    sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
     sidebarScreenToLocal = () =>
         this.props
             .ScreenToLocalTransform()
             .translate(-(this.props.PanelWidth() - this.sidebarWidth()) / (this.props.NativeDimScaling?.() || 1), 0)
-            .scale(1 / NumCast(this.layoutDoc._viewScale, 1) / (this.props.NativeDimScaling?.() || 1));
+            .scale(1 / NumCast(this.layoutDoc._freeform_scale, 1) / (this.props.NativeDimScaling?.() || 1));
 
     @computed get audioHandle() {
         return !this._recording ? null : (
@@ -1880,7 +1889,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     color,
                     opacity: annotated ? 1 : undefined,
                 }}>
-                <FontAwesomeIcon icon={'comment-alt'} />
+                <FontAwesomeIcon icon="comment-alt" />
             </div>
         );
     }
@@ -1932,25 +1941,25 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         fitContentsToBox={this.fitContentsToBox}
                         noSidebar={true}
                         treeViewHideTitle={true}
-                        fieldKey={this.layoutDoc.sidebarViewType === 'translation' ? `${this.fieldKey}-translation` : `${this.fieldKey}-sidebar`}
+                        fieldKey={this.layoutDoc.sidebarViewType === 'translation' ? `${this.fieldKey}_translation` : `${this.fieldKey}_sidebar`}
                     />
                 </div>
             );
         };
         return (
-            <div className={'formattedTextBox-sidebar' + (Doc.ActiveTool !== InkTool.None ? '-inking' : '')} style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+            <div className={'formattedTextBox-sidebar' + (Doc.ActiveTool !== InkTool.None ? '-inking' : '')} style={{ width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
                 {renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
             </div>
         );
     }
     cycleAlternateText = () => {
-        if (this.layoutDoc._showAltContentUI) {
-            const usePath = this.rootDoc[`${this.props.fieldKey}-usePath`];
-            this.rootDoc[`_${this.props.fieldKey}-usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
+        if (this.layoutDoc._layout_altContentUI) {
+            const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`];
+            this.rootDoc[`_${this.props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
         }
     };
     @computed get overlayAlternateIcon() {
-        const usePath = this.rootDoc[`${this.props.fieldKey}-usePath`];
+        const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`];
         return (
             <Tooltip
                 title={
@@ -1982,23 +1991,23 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         );
     }
     @computed get fieldKey() {
-        const usePath = StrCast(this.rootDoc[`${this.props.fieldKey}-usePath`]);
-        return this.props.fieldKey + (usePath && (!usePath.includes(':hover') || this._isHovering) ? `-${usePath.replace(':hover', '')}` : '');
+        const usePath = StrCast(this.rootDoc[`${this.props.fieldKey}_usePath`]);
+        return this.props.fieldKey + (usePath && (!usePath.includes(':hover') || this._isHovering) ? `_${usePath.replace(':hover', '')}` : '');
     }
     @observable _isHovering = false;
     render() {
         TraceMobx();
         const active = this.props.isContentActive() || this.props.isSelected();
         const selected = active;
-        const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
+        const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === '100%' ? '-rounded' : '';
         const interactive = (Doc.ActiveTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition);
         if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
         const minimal = this.props.ignoreAutoHeight;
         const paddingX = NumCast(this.layoutDoc._xMargin, this.props.xPadding || 0);
         const paddingY = NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
-        const selPad = (selected && !this.layoutDoc._singleLine) || minimal ? Math.min(paddingY, Math.min(paddingX, 10)) : 0;
-        const selPaddingClass = selected && !this.layoutDoc._singleLine && paddingY >= 10 ? '-selected' : '';
+        const selPad = (selected && !this.layoutDoc._createDocOnCR) || minimal ? Math.min(paddingY, Math.min(paddingX, 10)) : 0;
+        const selPaddingClass = selected && !this.layoutDoc._createDocOnCR && paddingY >= 10 ? '-selected' : '';
         const styleFromLayoutString = Doc.styleFromLayoutString(this.rootDoc, this.layoutDoc, this.props, scale); // this converts any expressions in the format string to style props.  e.g., <FormattedTextBox height='{this._headerHeight}px' >
         return styleFromLayoutString?.height === '0px' ? null : (
             <div
@@ -2010,7 +2019,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
                         (e: WheelEvent) => {
                             if (this.props.isContentActive() && !this.props.allowScroll) {
-                                if (!NumCast(this.layoutDoc._scrollTop) && e.deltaY <= 0) e.preventDefault();
+                                if (!NumCast(this.layoutDoc._layout_scrollTop) && e.deltaY <= 0) e.preventDefault();
                                 e.stopPropagation();
                             }
                         },
@@ -2028,7 +2037,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                           }),
                     display: !SnappingManager.GetIsDragging() && this.props.thumbShown?.() ? 'none' : undefined,
                     transition: 'inherit',
-                    // overflowY: this.layoutDoc._autoHeight ? "hidden" : undefined,
+                    // overflowY: this.layoutDoc._layout_autoHeight ? "hidden" : undefined,
                     color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
                     fontSize: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontSize),
                     fontFamily: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontFamily),
@@ -2039,8 +2048,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     className="formattedTextBox-cont"
                     ref={this._ref}
                     style={{
-                        overflow: this.autoHeight && this.props.CollectionFreeFormDocumentView?.() ? 'hidden' : undefined, //x this breaks viewing an autoHeight doc in its own tab, or in the lightbox
-                        height: this.props.height || (this.autoHeight && this.props.renderDepth && !this.props.suppressSetHeight ? 'max-content' : undefined),
+                        overflow: this.layout_autoHeight && this.props.CollectionFreeFormDocumentView?.() ? 'hidden' : undefined, //x this breaks viewing an layout_autoHeight doc in its own tab, or in the lightbox
+                        height: this.props.height || (this.layout_autoHeight && this.props.renderDepth && !this.props.suppressSetHeight ? 'max-content' : undefined),
                         pointerEvents: interactive ? undefined : 'none',
                     }}
                     onContextMenu={this.specificContextMenu}
@@ -2056,9 +2065,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         className={`formattedTextBox-outer${selected ? '-selected' : ''}`}
                         ref={this._scrollRef}
                         style={{
-                            width: this.props.dontSelectOnLoad ? '100%' : `calc(100% - ${this.sidebarWidthPercent})`,
+                            width: this.props.dontSelectOnLoad ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`,
                             pointerEvents: !active && !SnappingManager.GetIsDragging() ? 'none' : undefined,
-                            overflow: this.layoutDoc._singleLine ? 'hidden' : this.layoutDoc._autoHeight ? 'visible' : undefined,
+                            overflow: this.layoutDoc._createDocOnCR ? 'hidden' : this.layoutDoc._layout_autoHeight ? 'visible' : undefined,
                         }}
                         onScroll={this.onScroll}
                         onDrop={this.ondrop}>
@@ -2075,10 +2084,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                             }}
                         />
                     </div>
-                    {this.noSidebar || this.props.dontSelectOnLoad || !this.SidebarShown || this.sidebarWidthPercent === '0%' ? null : this.sidebarCollection}
-                    {this.noSidebar || this.Document._noSidebar || this.props.dontSelectOnLoad || this.Document._singleLine ? null : this.sidebarHandle}
+                    {this.noSidebar || this.props.dontSelectOnLoad || !this.SidebarShown || this.layout_sidebarWidthPercent === '0%' ? null : this.sidebarCollection}
+                    {this.noSidebar || this.Document._layout_noSidebar || this.props.dontSelectOnLoad || this.Document._createDocOnCR ? null : this.sidebarHandle}
                     {this.audioHandle}
-                    {this.layoutDoc._showAltContentUI ? this.overlayAlternateIcon : null}
+                    {this.layoutDoc._layout_altContentUI ? this.overlayAlternateIcon : null}
                 </div>
             </div>
         );
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index f0caa1f4f..5e0041b84 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -623,15 +623,15 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
                     if (linkclicked) {
                         const linkDoc = await DocServer.GetRefField(linkclicked);
                         if (linkDoc instanceof Doc) {
-                            const anchor1 = await Cast(linkDoc.anchor1, Doc);
-                            const anchor2 = await Cast(linkDoc.anchor2, Doc);
+                            const link_anchor_1 = await Cast(linkDoc.link_anchor_1, Doc);
+                            const link_anchor_2 = await Cast(linkDoc.link_anchor_2, Doc);
                             const currentDoc = SelectionManager.Docs().lastElement();
-                            if (currentDoc && anchor1 && anchor2) {
-                                if (Doc.AreProtosEqual(currentDoc, anchor1)) {
-                                    return StrCast(anchor2.title);
+                            if (currentDoc && link_anchor_1 && link_anchor_2) {
+                                if (Doc.AreProtosEqual(currentDoc, link_anchor_1)) {
+                                    return StrCast(link_anchor_2.title);
                                 }
-                                if (Doc.AreProtosEqual(currentDoc, anchor2)) {
-                                    return StrCast(anchor1.title);
+                                if (Doc.AreProtosEqual(currentDoc, link_anchor_2)) {
+                                    return StrCast(link_anchor_1.title);
                                 }
                             }
                         }
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index cad56b14b..104aed058 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -81,9 +81,9 @@ export class RichTextRules {
                 textDoc.inlineTextCount = numInlines + 1;
                 const inlineFieldKey = 'inline' + numInlines; // which field on the text document this annotation will write to
                 const inlineLayoutKey = 'layout_' + inlineFieldKey; // the field holding the layout string that will render the inline annotation
-                const textDocInline = Docs.Create.TextDocument('', { _layoutKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: textDoc, _fitWidth: true, _autoHeight: true, _fontSize: '9px', title: 'inline comment' });
+                const textDocInline = Docs.Create.TextDocument('', { _layout_fieldKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: textDoc, _layout_fitWidth: true, _layout_autoHeight: true, _fontSize: '9px', title: 'inline comment' });
                 textDocInline.title = inlineFieldKey; // give the annotation its own title
-                textDocInline['title-custom'] = true; // And make sure that it's 'custom' so that editing text doesn't change the title of the containing doc
+                textDocInline.title_custom = true; // And make sure that it's 'custom' so that editing text doesn't change the title of the containing doc
                 textDocInline.isTemplateForField = inlineFieldKey; // this is needed in case the containing text doc is converted to a template at some point
                 textDocInline.proto = textDoc; // make the annotation inherit from the outer text doc so that it can resolve any nested field references, e.g., [[field]]
                 textDocInline._textContext = ComputedField.MakeFunction(`copyField(self.${inlineFieldKey})`);
@@ -249,7 +249,7 @@ export class RichTextRules {
                         this.TextBox.EditorView?.dispatch(rstate.tr.setSelection(new TextSelection(rstate.doc.resolve(start), rstate.doc.resolve(end - 3))));
                     }
 
-                    DocUtils.MakeLink(this.TextBox.getAnchor(true), target, { linkRelationship: 'portal to:portal from' });
+                    DocUtils.MakeLink(this.TextBox.getAnchor(true), target, { link_relationship: 'portal to:portal from' });
 
                     const fstate = this.TextBox.EditorView?.state;
                     if (fstate && selection) {
@@ -299,28 +299,6 @@ export class RichTextRules {
                 return tr.setSelection(new NodeSelection(tr.doc.resolve(tr.selection.$from.pos - 1)));
             }),
 
-            // create an inline view of a document {{ <layoutKey> : <Doc> }}
-            // {{:Doc}} => show default view of document
-            // {{<layout>}} => show layout for this doc
-            // {{<layout> : Doc}} => show layout for another doc
-            new InputRule(new RegExp(/\{\{([a-zA-Z_ \-0-9]*)(\([a-zA-Z0-9…._/\-]*\))?(:[a-zA-Z_@\.\? \-0-9]+)?\}\}$/), (state, match, start, end) => {
-                const fieldKey = match[1] || '';
-                const fieldParam = match[2]?.replace('…', '...') || '';
-                const rawdocid = match[3]?.substring(1);
-                const docId = rawdocid ? (!rawdocid.includes('@') ? normalizeEmail(Doc.CurrentUserEmail) + '@' + rawdocid : rawdocid) : undefined;
-                if (!fieldKey && !docId) return state.tr;
-                docId &&
-                    DocServer.GetRefField(docId).then(docx => {
-                        if (!(docx instanceof Doc && docx)) {
-                            Docs.Create.FreeformDocument([], { title: rawdocid, _width: 500, _height: 500 }, docId);
-                        }
-                    });
-                const node = (state.doc.resolve(start) as any).nodeAfter;
-                const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 75, title: 'dashDoc', docId, fieldKey: fieldKey + fieldParam, float: 'unset', alias: Utils.GenerateGuid() });
-                const sm = state.storedMarks || undefined;
-                return node ? state.tr.replaceRangeWith(start, end, dashDoc).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr;
-            }),
-
             // create an inline view of a tag stored under the '#' field
             new InputRule(new RegExp(/#([a-zA-Z_\-]+[a-zA-Z_\-0-9]*)\s$/), (state, match, start, end) => {
                 const tag = match[1];
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index 6c9d5d31a..f27fb18e2 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -247,7 +247,7 @@ export const nodes: { [index: string]: NodeSpec } = {
             hidden: { default: false }, // whether dashComment node has toggle the dashDoc's display off
             fieldKey: { default: '' },
             docId: { default: '' },
-            alias: { default: '' },
+            embedding: { default: '' },
         },
         group: 'inline',
         draggable: false,
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index c22107c03..858d83b7a 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -273,7 +273,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     progressivizedItems = (doc: Doc) => {
         const targetList = PresBox.targetRenderedDoc(doc);
         if (doc.presIndexed !== undefined && targetList) {
-            const listItems = (Cast(targetList[Doc.LayoutFieldKey(targetList)], listSpec(Doc), null)?.filter(d => d instanceof Doc) as Doc[]) ?? DocListCast(targetList[Doc.LayoutFieldKey(targetList) + '-annotations']);
+            const listItems = (Cast(targetList[Doc.LayoutFieldKey(targetList)], listSpec(Doc), null)?.filter(d => d instanceof Doc) as Doc[]) ?? DocListCast(targetList[Doc.LayoutFieldKey(targetList) + '_annotations']);
             return listItems.filter(doc => !doc.unrendered);
         }
     };
@@ -419,7 +419,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const activeFrame = activeItem.presActiveFrame ?? activeItem.presCurrentFrame;
         if (activeFrame !== undefined) {
             const transTime = NumCast(activeItem.presTransition, 500);
-            const acontext = activeItem.presActiveFrame !== undefined ? DocCast(DocCast(activeItem.presentationTargetDoc).context) : DocCast(activeItem.presentationTargetDoc);
+            const acontext = activeItem.presActiveFrame !== undefined ? DocCast(DocCast(activeItem.presentationTargetDoc).embedContainer) : DocCast(activeItem.presentationTargetDoc);
             const context = DocCast(acontext)?.annotationOn ? DocCast(DocCast(acontext).annotationOn) : acontext;
             if (context) {
                 const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
@@ -435,7 +435,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const setData = bestTargetView?.ComponentView?.setData;
             if (setData) setData(activeItem.presData);
             else Doc.GetProto(bestTarget)[fkey] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
-            bestTarget[fkey + '-usePath'] = activeItem.presUsePath;
+            bestTarget[fkey + '_usePath'] = activeItem.presUsePath;
             setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10);
         }
         if (pinDataTypes?.datarange || (!pinDataTypes && activeItem.presXRange !== undefined)) {
@@ -449,14 +449,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             }
         }
         if (pinDataTypes?.clippable || (!pinDataTypes && activeItem.presClipWidth !== undefined)) {
-            if (bestTarget._clipWidth !== activeItem.presClipWidth) {
-                bestTarget._clipWidth = activeItem.presClipWidth;
+            const fkey = '_' + Doc.LayoutFieldKey(bestTarget);
+            if (bestTarget[fkey + '_clipWidth'] !== activeItem.presClipWidth) {
+                bestTarget[fkey + '_clipWidth'] = activeItem.presClipWidth;
                 changed = true;
             }
         }
         if (pinDataTypes?.temporal || (!pinDataTypes && activeItem.presStartTime !== undefined)) {
-            if (bestTarget._currentTimecode !== activeItem.presStartTime) {
-                bestTarget._currentTimecode = activeItem.presStartTime;
+            if (bestTarget._layout_currentTimecode !== activeItem.presStartTime) {
+                bestTarget._layout_currentTimecode = activeItem.presStartTime;
                 changed = true;
             }
         }
@@ -504,8 +505,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         }
 
         if (pinDataTypes?.scrollable || (!pinDataTypes && activeItem.presViewScroll !== undefined)) {
-            if (bestTarget._scrollTop !== activeItem.presViewScroll) {
-                bestTarget._scrollTop = activeItem.presViewScroll;
+            if (bestTarget._layout_scrollTop !== activeItem.presViewScroll) {
+                bestTarget._layout_scrollTop = activeItem.presViewScroll;
                 changed = true;
                 const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number'));
                 if (contentBounds) {
@@ -516,19 +517,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         }
         if (pinDataTypes?.dataannos || (!pinDataTypes && activeItem.presAnnotations !== undefined)) {
             const fkey = Doc.LayoutFieldKey(bestTarget);
-            const oldItems = DocListCast(bestTarget[fkey + '-annotations']).filter(doc => doc.unrendered);
+            const oldItems = DocListCast(bestTarget[fkey + '_annotations']).filter(doc => doc.unrendered);
             const newItems = DocListCast(activeItem.presAnnotations).map(doc => {
                 doc.hidden = false;
                 return doc;
             });
-            const hiddenItems = DocListCast(bestTarget[fkey + '-annotations'])
+            const hiddenItems = DocListCast(bestTarget[fkey + '_annotations'])
                 .filter(doc => !doc.unrendered && !newItems.includes(doc))
                 .map(doc => {
                     doc.hidden = true;
                     return doc;
                 });
             const newList = new List<Doc>([...oldItems, ...hiddenItems, ...newItems]);
-            Doc.GetProto(bestTarget)[fkey + '-annotations'] = newList;
+            Doc.GetProto(bestTarget)[fkey + '_annotations'] = newList;
         }
         if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.presPinLayoutData !== undefined)) {
             changed = true;
@@ -560,20 +561,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number'));
             if (contentBounds) {
                 const viewport = { panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] };
-                bestTarget._panX = viewport.panX;
-                bestTarget._panY = viewport.panY;
+                bestTarget._freeform_panX = viewport.panX;
+                bestTarget._freeform_panY = viewport.panY;
                 const dv = DocumentManager.Instance.getDocumentView(bestTarget);
                 if (dv) {
                     changed = true;
                     const computedScale = NumCast(activeItem.presZoom, 1) * Math.min(dv.props.PanelWidth() / viewport.width, dv.props.PanelHeight() / viewport.height);
-                    activeItem.presMovement === PresMovement.Zoom && (bestTarget._viewScale = computedScale);
+                    activeItem.presMovement === PresMovement.Zoom && (bestTarget._freeform_scale = computedScale);
                     dv.ComponentView?.brushView?.(viewport);
                 }
             } else {
-                if (bestTarget._panX !== activeItem.presPanX || bestTarget._panY !== activeItem.presPanY || bestTarget._viewScale !== activeItem.presViewScale) {
-                    bestTarget._panX = activeItem.presPanX ?? bestTarget._panX;
-                    bestTarget._panY = activeItem.presPanY ?? bestTarget._panY;
-                    bestTarget._viewScale = activeItem.presViewScale ?? bestTarget._viewScale;
+                if (bestTarget._freeform_panX !== activeItem.presPanX || bestTarget._freeform_panY !== activeItem.presPanY || bestTarget._freeform_scale !== activeItem.presViewScale) {
+                    bestTarget._freeform_panX = activeItem.presPanX ?? bestTarget._freeform_panX;
+                    bestTarget._freeform_panY = activeItem.presPanY ?? bestTarget._freeform_panY;
+                    bestTarget._freeform_scale = activeItem.presViewScale ?? bestTarget._freeform_scale;
                     changed = true;
                 }
             }
@@ -610,12 +611,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 pinProps?.activeFrame !== undefined;
             const fkey = Doc.LayoutFieldKey(targetDoc);
             if (pinProps.pinData.dataview) {
-                pinDoc.presUsePath = targetDoc[fkey + '-usePath'];
+                pinDoc.presUsePath = targetDoc[fkey + '_usePath'];
                 pinDoc.presData = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data;
             }
             if (pinProps.pinData.dataannos) {
                 const fkey = Doc.LayoutFieldKey(targetDoc);
-                pinDoc.presAnnotations = new List<Doc>(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations']).filter(doc => !doc.unrendered));
+                pinDoc.presAnnotations = new List<Doc>(DocListCast(Doc.GetProto(targetDoc)[fkey + '_annotations']).filter(doc => !doc.unrendered));
             }
             if (pinProps.pinData.inkable) {
                 pinDoc.presFillColor = targetDoc.fillColor;
@@ -623,8 +624,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 pinDoc.presWidth = targetDoc._width;
                 pinDoc.presHeight = targetDoc._height;
             }
-            if (pinProps.pinData.scrollable) pinDoc.presViewScroll = targetDoc._scrollTop;
-            if (pinProps.pinData.clippable) pinDoc.presClipWidth = targetDoc._clipWidth;
+            if (pinProps.pinData.scrollable) pinDoc.presViewScroll = targetDoc._layout_scrollTop;
+            if (pinProps.pinData.clippable) {
+                const fkey = Doc.LayoutFieldKey(targetDoc);
+                pinDoc.presClipWidth = targetDoc[fkey + '_clipWidth'];
+            }
             if (pinProps.pinData.datarange) {
                 pinDoc.presXRange = undefined; //targetDoc?.xrange;
                 pinDoc.presYRange = undefined; //targetDoc?.yrange;
@@ -649,13 +653,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             if (pinProps.pinData.filters) pinDoc.presDocFilters = ObjectField.MakeCopy(targetDoc.docFilters as ObjectField);
             if (pinProps.pinData.pivot) pinDoc.presPivotField = targetDoc._pivotField;
             if (pinProps.pinData.pannable) {
-                pinDoc.presPanX = NumCast(targetDoc._panX);
-                pinDoc.presPanY = NumCast(targetDoc._panY);
-                pinDoc.presViewScale = NumCast(targetDoc._viewScale, 1);
+                pinDoc.presPanX = NumCast(targetDoc._freeform_panX);
+                pinDoc.presPanY = NumCast(targetDoc._freeform_panY);
+                pinDoc.presViewScale = NumCast(targetDoc._freeform_scale, 1);
             }
             if (pinProps.pinData.temporal) {
-                pinDoc.presStartTime = targetDoc._currentTimecode;
-                const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], NumCast(targetDoc.presStartTime) + 0.1);
+                pinDoc.presStartTime = targetDoc._layout_currentTimecode;
+                const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], NumCast(targetDoc.presStartTime) + 0.1);
                 pinDoc.presEndTime = NumCast(targetDoc.clipEnd, duration);
             }
         }
@@ -663,7 +667,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             // If pinWithView option set then update scale and x / y props of slide
             const bounds = pinProps.pinViewport;
             pinDoc.presPinView = true;
-            pinDoc.presViewScale = NumCast(targetDoc._viewScale, 1);
+            pinDoc.presViewScale = NumCast(targetDoc._freeform_scale, 1);
             pinDoc.presPanX = bounds.left + bounds.width / 2;
             pinDoc.presPanY = bounds.top + bounds.height / 2;
             pinDoc.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
@@ -793,7 +797,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const savedStates = docs.map(doc => {
             switch (doc.type) {
                 case DocumentType.COL:
-                    if (doc._viewType === CollectionViewType.Freeform) return { type: CollectionViewType.Freeform, doc, x: NumCast(doc.panX), y: NumCast(doc.panY), s: NumCast(doc.viewScale) };
+                    if (doc._viewType === CollectionViewType.Freeform) return { type: CollectionViewType.Freeform, doc, x: NumCast(doc.freeform_panX), y: NumCast(doc.freeform_panY), s: NumCast(doc.freeform_scale) };
                     break;
                 case DocumentType.INK:
                     if (doc.data instanceof InkField) {
@@ -813,7 +817,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                 const { x, y, s, doc } = savedState!;
                                 doc._panX = x;
                                 doc._panY = y;
-                                doc._viewScale = s;
+                                doc._freeform_scale = s;
                             }
                             break;
                         case DocumentType.INK:
@@ -1008,17 +1012,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     return false;
                 }
             } else {
-                if (!doc.aliasOf) {
-                    const original = Doc.MakeAlias(doc);
-                    TabDocView.PinDoc(original, {});
-                    setTimeout(() => this.removeDocument(doc), 0);
-                    return false;
-                } else {
-                    if (!doc.presentationTargetDoc) doc.title = doc.title + ' - Slide';
-                    doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf);
-                    doc.presMovement = PresMovement.Zoom;
-                    if (this._expandBoolean) doc.presExpandInlineButton = true;
-                }
+                if (!doc.presentationTargetDoc) doc.title = doc.title + ' - Slide';
+                doc.presentationTargetDoc = doc.createdFrom; // dropped document will be a new embedding of an embedded document somewhere else.
+                doc.presMovement = PresMovement.Zoom;
+                if (this._expandBoolean) doc.presExpandInlineButton = true;
             }
         });
         return true;
@@ -1086,7 +1083,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 this.rootDoc._itemIndex = index;
             }
         } else this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
-        this.updateCurrentPresentation(DocCast(doc.context));
+        this.updateCurrentPresentation(DocCast(doc.embedContainer));
     };
 
     //Command click
@@ -1240,7 +1237,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             .filter(doc => Cast(doc.presentationTargetDoc, Doc, null))
             .forEach((doc, index) => {
                 const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
-                const srcContext = Cast(tagDoc.context, Doc, null);
+                const srcContext = Cast(tagDoc.embedContainer, Doc, null);
                 const width = NumCast(tagDoc._width) / 10;
                 const height = Math.max(NumCast(tagDoc._height) / 10, 15);
                 const edge = Math.max(width, height);
@@ -1300,7 +1297,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     /**
      * Method called for viewing paths which adds a single line with
      * points at the center of each document added.
-     * Design choice: When this is called it sets _fitContentsToBox as true so the
+     * Design choice: When this is called it sets _freeform_fitContentsToBox as true so the
      * user can have an overview of all of the documents in the collection.
      * (Design needed for when documents in presentation trail are in another
      * collection)
@@ -1553,7 +1550,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                 // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized.
                                 // to avoid creating a new slide to correspond to each of the target's data list, we create a computedField to refernce the target's data list.
                                 let dataField = Doc.LayoutFieldKey(tagDoc);
-                                if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '-annotations';
+                                if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '_annotations';
 
                                 if (DocCast(activeItem.presentationTargetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc.annotationOn["${dataField}"]`);
                                 else activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc["${dataField}"]`);
@@ -1743,7 +1740,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const activeItem = this.activeItem;
         if (activeItem && this.targetDoc) {
             const clipStart = NumCast(activeItem.clipStart);
-            const clipEnd = NumCast(activeItem.clipEnd, NumCast(activeItem[Doc.LayoutFieldKey(activeItem) + '-duration']));
+            const clipEnd = NumCast(activeItem.clipEnd, NumCast(activeItem[Doc.LayoutFieldKey(activeItem) + '_duration']));
             return (
                 <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                     <div>
@@ -2077,10 +2074,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         // prettier-ignore
         switch (layout) {
             case 'blank': return Docs.Create.FreeformDocument([], { title: input ? input : 'Blank slide', _width: 400, _height: 225, x, y });
-            case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input ? input : 'Title slide', _width: 400, _height: 225, _fitContentsToBox: true, x, y });
-            case 'header': return Docs.Create.FreeformDocument([header()], { title: input ? input : 'Section header', _width: 400, _height: 225, _fitContentsToBox: true, x, y });
-            case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input ? input : 'Title and content', _width: 400, _height: 225, _fitContentsToBox: true, x, y });
-            case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _fitContentsToBox: true, x, y })
+            case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input ? input : 'Title slide', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
+            case 'header': return Docs.Create.FreeformDocument([header()], { title: input ? input : 'Section header', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
+            case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input ? input : 'Title and content', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
+            case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y })
         }
     };
 
@@ -2458,7 +2455,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                 childIgnoreNativeSize={true}
                                 moveDocument={returnFalse}
                                 ignoreUnrendered={true}
-                                //childFitWidth={returnTrue}
+                                //childLayoutFitWidth={returnTrue}
                                 childOpacity={returnOne}
                                 //childLayoutString={PresElementBox.LayoutString('data')}
                                 childClickScript={PresBox.navigateToDocScript}
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 62e5314c3..e48d2d674 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -61,7 +61,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     }
 
     componentDidMount() {
-        this.layoutDoc.hideLinkButton = true;
+        this.layoutDoc.layout_hideLinkButton = true;
         this._heightDisposer = reaction(
             () => ({ expand: this.rootDoc.presExpandInlineButton, height: this.collapsedHeight }),
             ({ expand, height }) => (this.layoutDoc._height = height + (expand ? this.expandViewHeight : 0)),
@@ -319,7 +319,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     // a previously recorded video will have timecode defined
     static videoIsRecorded = (activeItem: Opt<Doc>) => {
         const casted = Cast(activeItem?.recording, Doc, null);
-        return casted && 'currentTimecode' in casted;
+        return casted && 'layout_currentTimecode' in casted;
     };
 
     removeAllRecordingInOverlay = () => {
@@ -380,10 +380,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 _width: 384,
                 _height: 216,
                 hideDocumentButtonBar: true,
-                hideDecorationTitle: true,
+                layout_hideDecorationTitle: true,
                 hideOpenButton: true,
                 // hideDeleteButton: true,
-                cloneFieldFilter: new List<string>(['system']),
+                cloneFieldFilter: new List<string>(['isSystem']),
             });
 
             // attach the recording to the slide, and attach the slide to the recording
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index cc0072a94..8bd060d4f 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -51,8 +51,8 @@ export class GPTPopup extends React.Component<GPTPopupProps> {
         const newDoc = Docs.Create.TextDocument(this.props.text.trim(), {
             _width: 200,
             _height: 50,
-            _fitWidth: true,
-            _autoHeight: true,
+            _layout_fitWidth: true,
+            _layout_autoHeight: true,
         });
         this.addDoc(newDoc, this.sidebarId);
     };
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index ea709a859..40b745cc4 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -90,7 +90,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
     @observable isAnnotating = false;
     // key where data is stored
     @computed get allAnnotations() {
-        return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '-annotations']), this.props.docFilters(), this.props.docRangeFilters());
+        return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), this.props.docFilters(), this.props.docRangeFilters());
     }
     @computed get inlineTextAnnotations() {
         return this.allAnnotations.filter(a => a.textInlineAnnotations);
@@ -101,12 +101,12 @@ export class PDFViewer extends React.Component<IViewerProps> {
         this.setupPdfJsViewer();
         this._mainCont.current?.addEventListener('scroll', e => ((e.target as any).scrollLeft = 0));
 
-        this._disposers.autoHeight = reaction(
-            () => this.props.layoutDoc._autoHeight,
-            autoHeight => {
-                if (autoHeight) {
-                    this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']);
-                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.NativeDimScaling?.() || 1));
+        this._disposers.layout_autoHeight = reaction(
+            () => this.props.layoutDoc._layout_autoHeight,
+            layout_autoHeight => {
+                if (layout_autoHeight) {
+                    this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + '_nativeHeight']);
+                    this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '_nativeHeight']) * (this.props.NativeDimScaling?.() || 1));
                 }
             }
         );
@@ -123,7 +123,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
             { fireImmediately: true }
         );
         this._disposers.curPage = reaction(
-            () => Cast(this.props.Document._curPage, 'number', null),
+            () => Cast(this.props.Document._layout_curPage, 'number', null),
             page => page !== undefined && page !== this._pdfViewer?.currentPageNumber && this.gotoPage(page),
             { fireImmediately: true }
         );
@@ -181,14 +181,14 @@ export class PDFViewer extends React.Component<IViewerProps> {
         let focusSpeed: Opt<number>;
         if (doc !== this.props.rootDoc && mainCont) {
             const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
-            const scrollTo = Utils.scrollIntoView(scrollTop, doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, windowHeight * 0.1, this._scrollHeight);
-            if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) {
+            const scrollTo = Utils.scrollIntoView(scrollTop, doc[HeightSym](), NumCast(this.props.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, this._scrollHeight);
+            if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._layout_scrollTop) {
                 if (!this._pdfViewer) this._initialScroll = { loc: scrollTo, easeFunc: options.easeFunc };
                 else if (!options.instant) this._scrollStopper = smoothScroll((focusSpeed = options.zoomTime ?? 500), mainCont, scrollTo, options.easeFunc, this._scrollStopper);
                 else this._mainCont.current?.scrollTo({ top: Math.abs(scrollTo || 0) });
             }
         } else {
-            this._initialScroll = { loc: NumCast(this.props.layoutDoc._scrollTop), easeFunc: options.easeFunc };
+            this._initialScroll = { loc: NumCast(this.props.layoutDoc._layout_scrollTop), easeFunc: options.easeFunc };
         }
         return focusSpeed;
     };
@@ -208,18 +208,18 @@ export class PDFViewer extends React.Component<IViewerProps> {
 
     pagesinit = () => {
         if (this._pdfViewer._setDocumentViewerElement?.offsetParent) {
-            runInAction(() => (this._pdfViewer.currentScaleValue = this.props.layoutDoc._viewScale = 1));
-            this.gotoPage(NumCast(this.props.Document._curPage, 1));
+            runInAction(() => (this._pdfViewer.currentScaleValue = this.props.layoutDoc._freeform_scale = 1));
+            this.gotoPage(NumCast(this.props.Document._layout_curPage, 1));
         }
         document.removeEventListener('pagesinit', this.pagesinit);
         var quickScroll: { loc?: string; easeFunc?: 'ease' | 'linear' } | undefined = { loc: this._initialScroll ? this._initialScroll.loc?.toString() : '', easeFunc: this._initialScroll ? this._initialScroll.easeFunc : undefined };
         this._disposers.scale = reaction(
-            () => NumCast(this.props.layoutDoc._viewScale, 1),
+            () => NumCast(this.props.layoutDoc._freeform_scale, 1),
             scale => (this._pdfViewer.currentScaleValue = scale),
             { fireImmediately: true }
         );
         this._disposers.scroll = reaction(
-            () => Math.abs(NumCast(this.props.Document._scrollTop)),
+            () => Math.abs(NumCast(this.props.Document._layout_scrollTop)),
             pos => {
                 if (!this._ignoreScroll) {
                     this._showWaiting && this.setupPdfJsViewer();
@@ -316,7 +316,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         if (this._mainCont.current && !this._forcedScroll) {
             this._ignoreScroll = true; // the pdf scrolled, so we need to tell the Doc to scroll but we don't want the doc to then try to set the PDF scroll pos (which would interfere with the smooth scroll animation)
             if (!LinkDocPreview.LinkInfo) {
-                this.props.layoutDoc._scrollTop = this._mainCont.current.scrollTop;
+                this.props.layoutDoc._layout_scrollTop = this._mainCont.current.scrollTop;
             }
             this._ignoreScroll = false;
             if (this._scrollTimer) clearTimeout(this._scrollTimer); // wait until a scrolling pause, then create an anchor to audio
@@ -371,7 +371,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         // if alt+left click, drag and annotate
         this._downX = e.clientX;
         this._downY = e.clientY;
-        if ((this.props.Document._viewScale || 1) !== 1) return;
+        if ((this.props.Document._freeform_scale || 1) !== 1) return;
         if ((e.button !== 0 || e.altKey) && this.props.isContentActive(true)) {
             this._setPreviewCursor?.(e.clientX, e.clientY, true, false);
         }
@@ -421,7 +421,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         }
 
         // Changing which document to add the annotation to (the currently selected PDF)
-        GPTPopup.Instance.setSidebarId('data-sidebar');
+        GPTPopup.Instance.setSidebarId('data_sidebar');
         GPTPopup.Instance.addDoc = this.props.sidebarAddDoc;
     };
 
@@ -434,7 +434,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 const rect = clientRects.item(i);
                 if (rect?.width && rect.width < this._mainCont.current.clientWidth / this.props.ScreenToLocalTransform().Scale) {
                     const scaleX = this._mainCont.current.offsetWidth / boundingRect.width;
-                    const pdfScale = NumCast(this.props.layoutDoc._viewScale, 1);
+                    const pdfScale = NumCast(this.props.layoutDoc._freeform_scale, 1);
                     const annoBox = document.createElement('div');
                     annoBox.className = 'marqueeAnnotator-annotationBox';
                     // transforms the positions from screen onto the pdf div
@@ -477,7 +477,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
             if (e.ctrlKey) {
                 const curScale = Number(this._pdfViewer.currentScaleValue);
                 this._pdfViewer.currentScaleValue = Math.max(1, Math.min(10, curScale - (curScale * e.deltaY) / 1000));
-                this.props.layoutDoc._viewScale = Number(this._pdfViewer.currentScaleValue);
+                this.props.layoutDoc._freeform_scale = Number(this._pdfViewer.currentScaleValue);
             }
         }
     };
@@ -485,12 +485,12 @@ export class PDFViewer extends React.Component<IViewerProps> {
     pointerEvents = () => (this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none');
     @computed get annotationLayer() {
         return (
-            <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.props.Document), transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})` }} ref={this._annotationLayer}>
+            <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.props.Document), transform: `scale(${NumCast(this.props.layoutDoc._freeform_scale, 1)})` }} ref={this._annotationLayer}>
                 {this.inlineTextAnnotations
                     .sort((a, b) => NumCast(a.y) - NumCast(b.y))
                     .filter(anno => !anno.hidden)
                     .map(anno => (
-                        <Annotation {...this.props} fieldKey={this.props.fieldKey + '-annotations'} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.props.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />
+                        <Annotation {...this.props} fieldKey={this.props.fieldKey + '_annotations'} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.props.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />
                     ))}
             </div>
         );
@@ -508,8 +508,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
 
     getScrollHeight = () => this._scrollHeight;
     showInfo = action((anno: Opt<Doc>) => (this._overlayAnnoInfo = anno));
-    scrollXf = () => (this._mainCont.current ? this.props.ScreenToLocalTransform().translate(0, NumCast(this.props.layoutDoc._scrollTop)) : this.props.ScreenToLocalTransform());
-    overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._viewScale, 1));
+    scrollXf = () => (this._mainCont.current ? this.props.ScreenToLocalTransform().translate(0, NumCast(this.props.layoutDoc._layout_scrollTop)) : this.props.ScreenToLocalTransform());
+    overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._freeform_scale, 1));
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1);
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
@@ -539,7 +539,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 childPointerEvents="all" // but freeform children need to get events to allow text editing, etc
                 renderDepth={this.props.renderDepth + 1}
                 isAnnotationOverlay={true}
-                fieldKey={this.props.fieldKey + '-annotations'}
+                fieldKey={this.props.fieldKey + '_annotations'}
                 getScrollHeight={this.getScrollHeight}
                 setPreviewCursor={this.setPreviewCursor}
                 setBrushViewer={this.setBrushViewer}
@@ -548,7 +548,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 ScreenToLocalTransform={this.overlayTransform}
                 isAnyChildContentActive={returnFalse}
                 isAnnotationOverlayScrollable={true}
-                dropAction={'alias'}
+                dropAction="embed"
                 docFilters={docFilters}
                 select={emptyFunction}
                 bringToFront={emptyFunction}
@@ -586,8 +586,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
                     onPointerDown={this.onPointerDown}
                     onClick={this.onClick}
                     style={{
-                        overflowX: NumCast(this.props.layoutDoc._viewScale, 1) !== 1 ? 'scroll' : undefined,
-                        height: !this.props.Document._fitWidth && window.screen.width > 600 ? Doc.NativeHeight(this.props.Document) : `100%`,
+                        overflowX: NumCast(this.props.layoutDoc._freeform_scale, 1) !== 1 ? 'scroll' : undefined,
+                        height: !this.props.Document._layout_fitWidth && window.screen.width > 600 ? Doc.NativeHeight(this.props.Document) : `100%`,
                     }}>
                     {this.pdfViewerDiv}
                     {this.annotationLayer}
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 32b661bb6..536ec7c75 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -47,7 +47,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     @observable _linkedDocsIn: Map<Doc, Set<Doc>> = new Map<Doc, Set<Doc>>();
     @observable _selectedResult: Doc | undefined = undefined;
     @observable _deletedDocsStatus: boolean = false;
-    @observable _onlyAliases: boolean = true;
+    @observable _onlyEmbeddings: boolean = true;
 
     /**
      * This is the constructor for the SearchBox class.
@@ -139,7 +139,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                 visited.push(d);
                 const fieldKey = Doc.LayoutFieldKey(d);
                 const annos = !Field.toString(Doc.LayoutField(d) as Field).includes('CollectionView');
-                const data = d[annos ? fieldKey + '-annotations' : fieldKey];
+                const data = d[annos ? fieldKey + '_annotations' : fieldKey];
                 data && newarray.push(...DocListCast(data));
                 func(depth, d);
             });
@@ -166,7 +166,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                     .map(async d => {
                         const fieldKey = Doc.LayoutFieldKey(d);
                         const annos = !Field.toString(Doc.LayoutField(d) as Field).includes('CollectionView');
-                        const data = d[annos ? fieldKey + '-annotations' : fieldKey];
+                        const data = d[annos ? fieldKey + '_annotations' : fieldKey];
                         const docs = await DocListCastAsync(data);
                         docs && newarray.push(...docs);
                         func(depth, d);
@@ -217,34 +217,34 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
             'y',
             'proto',
             'width',
-            'autoHeight',
+            'layout_autoHeight',
             'acl-Override',
             'acl-Public',
-            'context',
+            'embedContainer',
             'zIndex',
             'height',
-            'text-scrollHeight',
-            'text-height',
+            'text_scrollHeight',
+            'text_height',
             'cloneFieldFilter',
-            'isPrototype',
-            'text-annotations',
-            'dragFactory-count',
-            'text-noTemplate',
-            'aliases',
-            'system',
-            'layoutKey',
-            'baseProto',
+            'isDataDoc',
+            'text_annotations',
+            'dragFactory_count',
+            'text_noTemplate',
+            'proto_embeddings',
+            'isSystem',
+            'layout_fieldKey',
+            'isBaseProto',
             'xMargin',
             'yMargin',
             'links',
             'layout',
             'layout_keyValue',
-            'fitWidth',
+            'layout_fitWidth',
             'viewType',
-            'title-custom',
-            'panX',
-            'panY',
-            'viewScale',
+            'title_custom',
+            'freeform_panX',
+            'freeform_panY',
+            'freeform_scale',
         ];
         query = query.toLowerCase();
 
@@ -300,8 +300,8 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                 const linkedDocSet = new Set<Doc>();
 
                 Doc.GetProto(doc)[DirectLinksSym].forEach(link => {
-                    const d1 = link?.anchor1 as Doc;
-                    const d2 = link?.anchor2 as Doc;
+                    const d1 = link?.link_anchor_1 as Doc;
+                    const d2 = link?.link_anchor_2 as Doc;
                     if (doc === d1 && this._results.has(d2)) {
                         linkedDocSet.add(d2);
                         this._linkedDocsIn.get(d2)?.add(doc);
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 5e3e27a7c..deda4c876 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -236,7 +236,7 @@ export class Doc extends RefField {
         if (
             doc &&
             Doc.MyFileOrphans instanceof Doc &&
-            Doc.IsPrototype(doc) &&
+            Doc.IsDocDataProto(doc) &&
             !Doc.IsSystem(doc) &&
             ![DocumentType.MARKER, DocumentType.KVP, DocumentType.LINK, DocumentType.LINKANCHOR].includes(doc.type as any) &&
             !doc.isFolder &&
@@ -381,7 +381,7 @@ export class Doc extends RefField {
         const templateLayoutDoc = Cast(Doc.LayoutField(this[SelfProxy]), Doc, null);
         if (templateLayoutDoc) {
             let renderFieldKey: any;
-            const layoutField = templateLayoutDoc[StrCast(templateLayoutDoc.layoutKey, 'layout')];
+            const layoutField = templateLayoutDoc[StrCast(templateLayoutDoc.layout_fieldKey, 'layout')];
             if (typeof layoutField === 'string') {
                 renderFieldKey = layoutField.split("fieldKey={'")[1].split("'")[0]; //layoutField.split("'")[1];
             } else {
@@ -510,14 +510,14 @@ export namespace Doc {
     export function GetT<T extends Field>(doc: Doc, key: string, ctor: ToConstructor<T>, ignoreProto: boolean = false): FieldResult<T> {
         return Cast(Get(doc, key, ignoreProto), ctor) as FieldResult<T>;
     }
-    export function IsPrototype(doc: Doc) {
-        return GetT(doc, 'isPrototype', 'boolean', true);
+    export function IsDocDataProto(doc: Doc) {
+        return GetT(doc, 'isDataDoc', 'boolean', true);
     }
     export function IsBaseProto(doc: Doc) {
-        return GetT(doc, 'baseProto', 'boolean', true);
+        return GetT(doc, 'isBaseProto', 'boolean', true);
     }
     export function IsSystem(doc: Doc) {
-        return GetT(doc, 'system', 'boolean', true);
+        return GetT(doc, 'isSystem', 'boolean', true);
     }
     export function IsDelegateField(doc: Doc, fieldKey: string) {
         return doc && Get(doc, fieldKey, true) !== undefined;
@@ -574,9 +574,9 @@ export namespace Doc {
 
     // Gets the data document for the document.  Note: this is mis-named -- it does not specifically
     // return the doc's proto, but rather recursively searches through the proto inheritance chain
-    // and returns the document who's proto is undefined or whose proto is marked as a base prototype ('isPrototype').
+    // and returns the document who's proto is undefined or whose proto is marked as a data doc ('isDataDoc').
     export function GetProto(doc: Doc): Doc {
-        const proto = doc && (Doc.GetT(doc, 'isPrototype', 'boolean', true) ? doc : doc.proto || doc);
+        const proto = doc && (Doc.GetT(doc, 'isDataDoc', 'boolean', true) ? doc : doc.proto || doc);
         return proto === doc ? proto : Doc.GetProto(proto);
     }
     export function GetDataDoc(doc: Doc): Doc {
@@ -680,25 +680,25 @@ export namespace Doc {
         return bounds;
     }
 
-    export function MakeAlias(doc: Doc, id?: string) {
-        const alias = !GetT(doc, 'isPrototype', 'boolean', true) && doc.proto ? Doc.MakeCopy(doc, undefined, id) : Doc.MakeDelegate(doc, id);
-        const layout = Doc.LayoutField(alias);
-        if (layout instanceof Doc && layout !== alias && layout === Doc.Layout(alias)) {
-            Doc.SetLayout(alias, Doc.MakeAlias(layout));
+    export function MakeEmbedding(doc: Doc, id?: string) {
+        const embedding = !GetT(doc, 'isDataDoc', 'boolean', true) && doc.proto ? Doc.MakeCopy(doc, undefined, id) : Doc.MakeDelegate(doc, id);
+        const layout = Doc.LayoutField(embedding);
+        if (layout instanceof Doc && layout !== embedding && layout === Doc.Layout(embedding)) {
+            Doc.SetLayout(embedding, Doc.MakeEmbedding(layout));
         }
-        alias.aliasOf = doc;
-        alias.aliasNumber = Doc.GetProto(doc).aliasNumber = NumCast(Doc.GetProto(doc).aliasNumber) + 1;
-        alias.title = ComputedField.MakeFunction(`renameAlias(this)`);
-        alias.author = Doc.CurrentUserEmail;
+        embedding.createdFrom = doc;
+        embedding.proto_embeddingId = Doc.GetProto(doc).proto_embeddingId = NumCast(Doc.GetProto(doc).proto_embeddingId) + 1;
+        embedding.title = ComputedField.MakeFunction(`renameEmbedding(this)`);
+        embedding.author = Doc.CurrentUserEmail;
 
-        Doc.AddDocToList(Doc.GetProto(doc)[DataSym], 'aliases', alias);
+        Doc.AddDocToList(Doc.GetProto(doc)[DataSym], 'proto_embeddings', embedding);
 
-        return alias;
+        return embedding;
     }
 
-    export function BestAlias(doc: Doc) {
-        const bestAlias = Doc.GetProto(doc) ? DocListCast(doc.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail) : doc;
-        return bestAlias ?? Doc.MakeAlias(doc);
+    export function BestEmbedding(doc: Doc) {
+        const bestEmbedding = Doc.GetProto(doc) ? DocListCast(doc.proto_embeddings).find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail) : doc;
+        return bestEmbedding ?? Doc.MakeEmbedding(doc);
     }
 
     // this lists out all the tag ids that can be  in a RichTextField that might contain document ids.
@@ -745,7 +745,7 @@ export namespace Doc {
                 if (docAtKey instanceof Doc) {
                     if (pruneDocs.includes(docAtKey)) {
                         // prune doc and do nothing
-                    } else if (!Doc.IsSystem(docAtKey) && (key.startsWith('layout') || ['context', 'annotationOn', 'proto'].includes(key) || ((key === 'anchor1' || key === 'anchor2') && doc.author === Doc.CurrentUserEmail))) {
+                    } else if (!Doc.IsSystem(docAtKey) && (key.startsWith('layout') || ['embedContainer', 'annotationOn', 'proto'].includes(key) || ((key === 'link_anchor_1' || key === 'link_anchor_2') && doc.author === Doc.CurrentUserEmail))) {
                         assignKey(await Doc.makeClone(docAtKey, cloneMap, linkMap, rtfs, exclusions, pruneDocs, cloneLinks));
                     } else {
                         assignKey(docAtKey);
@@ -766,7 +766,8 @@ export namespace Doc {
         Array.from(doc[DirectLinksSym]).forEach(async link => {
             if (
                 cloneLinks ||
-                ((cloneMap.has(DocCast(link.anchor1)?.[Id]) || cloneMap.has(DocCast(DocCast(link.anchor1)?.annotationOn)?.[Id])) && (cloneMap.has(DocCast(link.anchor2)?.[Id]) || cloneMap.has(DocCast(DocCast(link.anchor2)?.annotationOn)?.[Id])))
+                ((cloneMap.has(DocCast(link.link_anchor_1)?.[Id]) || cloneMap.has(DocCast(DocCast(link.link_anchor_1)?.annotationOn)?.[Id])) &&
+                    (cloneMap.has(DocCast(link.link_anchor_2)?.[Id]) || cloneMap.has(DocCast(DocCast(link.link_anchor_2)?.annotationOn)?.[Id])))
             ) {
                 linkMap.set(link[Id], await Doc.makeClone(link, cloneMap, linkMap, rtfs, exclusions, pruneDocs, cloneLinks));
             }
@@ -804,7 +805,7 @@ export namespace Doc {
     export async function MakeClone(doc: Doc, cloneLinks = true, cloneMap: Map<string, Doc> = new Map()) {
         const linkMap = new Map<string, Doc>();
         const rtfMap: { copy: Doc; key: string; field: RichTextField }[] = [];
-        const copy = await Doc.makeClone(doc, cloneMap, linkMap, rtfMap, ['cloneOf'], doc.context ? [DocCast(doc.context)] : [], cloneLinks);
+        const copy = await Doc.makeClone(doc, cloneMap, linkMap, rtfMap, ['cloneOf'], doc.embedContainer ? [DocCast(doc.embedContainer)] : [], cloneLinks);
         const repaired = new Set<Doc>();
         const linkedDocs = Array.from(linkMap.values());
         linkedDocs.map((link: Doc) => LinkManager.Instance.addLink(link, true));
@@ -980,7 +981,7 @@ export namespace Doc {
     export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string, retitle = false): Doc {
         const copy = new Doc(copyProtoId, true);
         updateCachedAcls(copy);
-        const exclude = Cast(doc.cloneFieldFilter, listSpec('string'), []);
+        const exclude = [...Cast(doc.cloneFieldFilter, listSpec('string'), []), 'dragFactory_count', 'cloneFieldFilter'];
         Object.keys(doc).forEach(key => {
             if (exclude.includes(key)) return;
             const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
@@ -1009,12 +1010,12 @@ export namespace Doc {
             }
         });
         if (copyProto) {
-            Doc.GetProto(copy).context = undefined;
-            Doc.GetProto(copy).aliases = new List<Doc>([copy]);
+            Doc.GetProto(copy).embedContainer = undefined;
+            Doc.GetProto(copy).proto_embeddings = new List<Doc>([copy]);
         } else {
-            Doc.AddDocToList(Doc.GetProto(copy)[DataSym], 'aliases', copy);
+            Doc.AddDocToList(Doc.GetProto(copy)[DataSym], 'proto_embeddings', copy);
         }
-        copy.context = undefined;
+        copy.embedContainer = undefined;
         Doc.defaultAclPrivate && (copy['acl-Public'] = 'Not Shared');
         if (retitle) {
             copy.title = incrementTitleCopy(StrCast(copy.title));
@@ -1035,7 +1036,7 @@ export namespace Doc {
             Object.keys(doc)
                 .filter(key => key.startsWith('acl'))
                 .forEach(key => (delegate[key] = doc[key]));
-            if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DataSym], 'aliases', delegate);
+            if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DataSym], 'proto_embeddings', delegate);
             title && (delegate.title = title);
             delegate[Initializing] = false;
             Doc.AddFileOrphan(delegate);
@@ -1053,13 +1054,13 @@ export namespace Doc {
         delegateProto[Initializing] = true;
         delegateProto.proto = doc;
         delegateProto.author = Doc.CurrentUserEmail;
-        delegateProto.isPrototype = true;
+        delegateProto.isDataDoc = true;
         title && (delegateProto.title = title);
         const delegate = new Doc(id, true);
         delegate[Initializing] = true;
         delegate.proto = delegateProto;
         delegate.author = Doc.CurrentUserEmail;
-        Doc.AddDocToList(delegateProto[DataSym], 'aliases', delegate);
+        Doc.AddDocToList(delegateProto[DataSym], 'proto_embeddings', delegate);
         delegate[Initializing] = false;
         delegateProto[Initializing] = false;
         return delegate;
@@ -1071,9 +1072,9 @@ export namespace Doc {
             const proto = new Doc();
             proto.author = Doc.CurrentUserEmail;
             const target = Doc.MakeDelegate(proto);
-            const targetKey = StrCast(templateDoc.layoutKey, 'layout');
+            const targetKey = StrCast(templateDoc.layout_fieldKey, 'layout');
             const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + '(...' + _applyCount++ + ')');
-            target.layoutKey = targetKey;
+            target.layout_fieldKey = targetKey;
             applied && (Doc.GetProto(applied).type = templateDoc.type);
             Doc.defaultAclPrivate && (applied['acl-Public'] = 'Not Shared');
             return applied;
@@ -1176,31 +1177,31 @@ export namespace Doc {
         return overrideLayout || doc[LayoutSym] || doc;
     }
     export function SetLayout(doc: Doc, layout: Doc | string) {
-        doc[StrCast(doc.layoutKey, 'layout')] = layout;
+        doc[StrCast(doc.layout_fieldKey, 'layout')] = layout;
     }
     export function LayoutField(doc: Doc) {
-        return doc[StrCast(doc.layoutKey, 'layout')];
+        return doc[StrCast(doc.layout_fieldKey, 'layout')];
     }
     export function LayoutFieldKey(doc: Doc): string {
-        return StrCast(Doc.Layout(doc).layout).split("'")[1]; // bcz: TODO check on this .  used to always reference 'layout', now it uses the layout speicfied by the current layoutKey
+        return StrCast(Doc.Layout(doc).layout).split("'")[1]; // bcz: TODO check on this .  used to always reference 'layout', now it uses the layout speicfied by the current layout_fieldKey
     }
     export function NativeAspect(doc: Doc, dataDoc?: Doc, useDim?: boolean) {
         return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1);
     }
     export function NativeWidth(doc?: Doc, dataDoc?: Doc, useWidth?: boolean) {
-        return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '-nativeWidth'], useWidth ? doc[WidthSym]() : 0));
+        return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeWidth'], useWidth ? doc[WidthSym]() : 0));
     }
     export function NativeHeight(doc?: Doc, dataDoc?: Doc, useHeight?: boolean) {
         if (!doc) return 0;
         const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[HeightSym]()) / doc[WidthSym]();
-        const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '-nativeHeight'], useHeight ? doc[HeightSym]() : 0);
+        const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeHeight'], useHeight ? doc[HeightSym]() : 0);
         return NumCast(doc._nativeHeight, nheight || dheight);
     }
     export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) {
-        doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '-nativeWidth'] = width;
+        doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '_nativeWidth'] = width;
     }
     export function SetNativeHeight(doc: Doc, height: number | undefined, fieldKey?: string) {
-        doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '-nativeHeight'] = height;
+        doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '_nativeHeight'] = height;
     }
 
     const manager = new DocData();
@@ -1271,8 +1272,8 @@ export namespace Doc {
             const lastBrushed = Array.from(brushManager.BrushedDoc.keys()).lastElement();
             if (lastBrushed) {
                 for (const link of LinkManager.Instance.getAllDirectLinks(lastBrushed)) {
-                    const a1 = Cast(link.anchor1, Doc, null);
-                    const a2 = Cast(link.anchor2, Doc, null);
+                    const a1 = Cast(link.link_anchor_1, Doc, null);
+                    const a2 = Cast(link.link_anchor_2, Doc, null);
                     if (Doc.AreProtosEqual(a1, doc) || Doc.AreProtosEqual(a2, doc) || Doc.AreProtosEqual(Cast(a1.annotationOn, Doc, null), doc) || Doc.AreProtosEqual(Cast(a2.annotationOn, Doc, null), doc)) {
                         return DocBrushStatus.linkHighlighted;
                     }
@@ -1304,8 +1305,8 @@ export namespace Doc {
     }
 
     export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) {
-        if (linkDoc.anchor2 === anchorDoc || (linkDoc.anchor2 as Doc).annotationOn) return '2';
-        return Doc.AreProtosEqual(anchorDoc, (linkDoc.anchor1 as Doc).annotationOn as Doc) || Doc.AreProtosEqual(anchorDoc, linkDoc.anchor1 as Doc) ? '1' : '2';
+        if (linkDoc.link_anchor_2 === anchorDoc || (linkDoc.link_anchor_2 as Doc).annotationOn) return '2';
+        return Doc.AreProtosEqual(anchorDoc, (linkDoc.link_anchor_1 as Doc).annotationOn as Doc) || Doc.AreProtosEqual(anchorDoc, linkDoc.link_anchor_1 as Doc) ? '1' : '2';
     }
 
     export function linkFollowUnhighlight() {
@@ -1400,14 +1401,14 @@ export namespace Doc {
     }
 
     export function deiconifyView(doc: Doc) {
-        StrCast(doc.layoutKey).split('_')[1] === 'icon' && setNativeView(doc);
+        StrCast(doc.layout_fieldKey).split('_')[1] === 'icon' && setNativeView(doc);
     }
 
     export function setNativeView(doc: any) {
-        const prevLayout = StrCast(doc.layoutKey).split('_')[1];
+        const prevLayout = StrCast(doc.layout_fieldKey).split('_')[1];
         const deiconify = prevLayout === 'icon' && StrCast(doc.deiconifyLayout) ? 'layout_' + StrCast(doc.deiconifyLayout) : '';
         prevLayout === 'icon' && (doc.deiconifyLayout = undefined);
-        doc.layoutKey = deiconify || 'layout';
+        doc.layout_fieldKey = deiconify || 'layout';
     }
     export function setDocRangeFilter(container: Opt<Doc>, key: string, range?: number[]) {
         if (!container) return;
@@ -1431,7 +1432,7 @@ export namespace Doc {
     // based on the modifiers :"check", "x", undefined
     export function setDocFilter(container: Opt<Doc>, key: string, value: any, modifiers: 'remove' | 'match' | 'check' | 'x' | 'exists' | 'unset', toggle?: boolean, fieldPrefix?: string, append: boolean = true) {
         if (!container) return;
-        const filterField = '_' + (fieldPrefix ? fieldPrefix + '-' : '') + 'docFilters';
+        const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'docFilters';
         const docFilters = Cast(container[filterField], listSpec('string'), []);
         runInAction(() => {
             for (let i = 0; i < docFilters.length; i++) {
@@ -1471,18 +1472,18 @@ export namespace Doc {
     export function toggleNativeDimensions(layoutDoc: Doc, contentScale: number, panelWidth: number, panelHeight: number) {
         runInAction(() => {
             if (Doc.NativeWidth(layoutDoc) || Doc.NativeHeight(layoutDoc)) {
-                layoutDoc._viewScale = NumCast(layoutDoc._viewScale, 1) * contentScale;
+                layoutDoc._freeform_scale = NumCast(layoutDoc._freeform_scale, 1) * contentScale;
                 layoutDoc._nativeWidth = undefined;
                 layoutDoc._nativeHeight = undefined;
-                layoutDoc._forceReflow = undefined;
+                layoutDoc._layout_forceReflow = undefined;
                 layoutDoc._nativeHeightUnfrozen = undefined;
                 layoutDoc._nativeDimModifiable = undefined;
             } else {
-                layoutDoc._autoHeight = false;
+                layoutDoc._layout_autoHeight = false;
                 if (!Doc.NativeWidth(layoutDoc)) {
                     layoutDoc._nativeWidth = NumCast(layoutDoc._width, panelWidth);
                     layoutDoc._nativeHeight = NumCast(layoutDoc._height, panelHeight);
-                    layoutDoc._forceReflow = true;
+                    layoutDoc._layout_forceReflow = true;
                     layoutDoc._nativeHeightUnfrozen = true;
                     layoutDoc._nativeDimModifiable = true;
                 }
@@ -1710,8 +1711,8 @@ export function IdToDoc(id: string) {
 ScriptingGlobals.add(function idToDoc(id: string): any {
     return IdToDoc(id);
 });
-ScriptingGlobals.add(function renameAlias(doc: any) {
-    return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, '') + `(${doc.aliasNumber})`;
+ScriptingGlobals.add(function renameEmbedding(doc: any) {
+    return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`;
 });
 ScriptingGlobals.add(function getProto(doc: any) {
     return Doc.GetProto(doc);
@@ -1719,8 +1720,8 @@ ScriptingGlobals.add(function getProto(doc: any) {
 ScriptingGlobals.add(function getDocTemplate(doc?: any) {
     return Doc.getDocTemplate(doc);
 });
-ScriptingGlobals.add(function getAlias(doc: any) {
-    return Doc.MakeAlias(doc);
+ScriptingGlobals.add(function getEmbedding(doc: any) {
+    return Doc.MakeEmbedding(doc);
 });
 ScriptingGlobals.add(function getCopy(doc: any, copyProto: any) {
     return doc.isTemplateDoc ? Doc.ApplyTemplate(doc) : Doc.MakeCopy(doc, copyProto);
diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts
index 239b59e83..24cd078f2 100644
--- a/src/fields/RichTextUtils.ts
+++ b/src/fields/RichTextUtils.ts
@@ -395,11 +395,11 @@ export namespace RichTextUtils {
                             if (new RegExp(window.location.origin + delimiter).test(url) && !url.endsWith(alreadyShared)) {
                                 const linkDoc = await DocServer.GetRefField(url.split(delimiter)[1]);
                                 if (linkDoc instanceof Doc) {
-                                    let exported = (await Cast(linkDoc.anchor2, Doc))!;
+                                    let exported = (await Cast(linkDoc.link_anchor_2, Doc))!;
                                     if (!exported.customLayout) {
-                                        exported = Doc.MakeAlias(exported);
+                                        exported = Doc.MakeEmbedding(exported);
                                         DocUtils.makeCustomViewClicked(exported, Docs.Create.FreeformDocument);
-                                        linkDoc.anchor2 = exported;
+                                        linkDoc.link_anchor_2 = exported;
                                     }
                                     url = Utils.shareUrl(exported[Id]);
                                 }
diff --git a/src/fields/Types.ts b/src/fields/Types.ts
index 4cf286a32..251b1149d 100644
--- a/src/fields/Types.ts
+++ b/src/fields/Types.ts
@@ -3,7 +3,7 @@ import { List } from './List';
 import { RefField } from './RefField';
 import { DateField } from './DateField';
 import { ScriptField } from './ScriptField';
-import { URLField, WebField, ImageField } from './URLField';
+import { URLField, WebField, ImageField, CsvField } from './URLField';
 import { TextField } from '@material-ui/core';
 import { RichTextField } from './RichTextField';
 
@@ -104,6 +104,9 @@ export function RTFCast(field: FieldResult) {
 export function ScriptCast(field: FieldResult, defaultVal: ScriptField | null = null) {
     return Cast(field, ScriptField, defaultVal);
 }
+export function CsvCast(field: FieldResult, defaultVal: CsvField | null = null) {
+    return Cast(field, CsvField, defaultVal);
+}
 export function WebCast(field: FieldResult, defaultVal: WebField | null = null) {
     return Cast(field, WebField, defaultVal);
 }
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index b7fd06973..7b2fd74d0 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -13,11 +13,11 @@ export const documentSchema = createSchema({
     links: listSpec(Doc), // computed (readonly) list of links associated with this document
 
     // "Location" properties in a very general sense
-    _curPage: 'number', // current page of a page based document
+    _layout_curPage: 'number', // current page of a page based document
     _currentFrame: 'number', // current frame of a frame based collection (e.g., a progressive slide)
     lastFrame: 'number', // last frame of a frame based collection (e.g., a progressive slide)
     activeFrame: 'number', // the active frame of a frame based animated document
-    _currentTimecode: 'number', // current play back time of a temporal document (video / audio)
+    _layout_currentTimecode: 'number', // current play back time of a temporal document (video / audio)
     _timecodeToShow: 'number', // the time that a document should be displayed (e.g., time an annotation should be displayed on a video)
     _timecodeToHIde: 'number', // the time that a document should be hidden
     markers: listSpec(Doc), // list of markers for audio / video
@@ -25,52 +25,52 @@ export const documentSchema = createSchema({
     y: 'number', // y coordinate when in a freeform view
     z: 'number', // z "coordinate" - non-zero specifies the overlay layer of a freeformview
     zIndex: 'number', // zIndex of a document in a freeform view
-    _scrollTop: 'number', // scroll position of a scrollable document (pdf, text, web)
+    _layout_scrollTop: 'number', // scroll position of a scrollable document (pdf, text, web)
     lat: 'number',
     lng: 'number',
 
     // appearance properties on the layout
     '_backgroundGrid-spacing': 'number', // the size of the grid for collection views
-    _autoHeight: 'boolean', // whether the height of the document should be computed automatically based on its contents
+    _layout_autoHeight: 'boolean', // whether the height of the document should be computed automatically based on its contents
     _nativeWidth: 'number', // native width of document which determines how much document contents are scaled when the document's width is set
     _nativeHeight: 'number', // "
     _width: 'number', // width of document in its container's coordinate system
     _height: 'number', // "
-    _xPadding: 'number', // pixels of padding on left/right of collectionfreeformview contents when fitContentsToBox is set
-    _yPadding: 'number', // pixels of padding on top/bottom of collectionfreeformview contents when fitContentsToBox is set
+    _xPadding: 'number', // pixels of padding on left/right of collectionfreeformview contents when freeform_fitContentsToBox is set
+    _yPadding: 'number', // pixels of padding on top/bottom of collectionfreeformview contents when freeform_fitContentsToBox is set
     _xMargin: 'number', // margin added on left/right of most documents to add separation from their container
     _yMargin: 'number', // margin added on top/bottom of most documents to add separation from their container
     _overflow: 'string', // sets overflow behvavior for CollectionFreeForm views
-    _showCaption: 'string', // whether editable caption text is overlayed at the bottom of the document
-    _showTitle: 'string', // the fieldkey(s) whose contents should be displayed at the top of the document. separate multiple keys with ";".  Use :hover suffix to indicate title should be shown on hover
+    _layout_showCaption: 'string', // whether editable caption text is overlayed at the bottom of the document
+    _layout_showTitle: 'string', // the fieldkey(s) whose contents should be displayed at the top of the document. separate multiple keys with ";".  Use :hover suffix to indicate title should be shown on hover
     _pivotField: 'string', // specifies which field key should be used as the timeline/pivot axis
     _columnsFill: 'boolean', // whether documents in a stacking view column should be sized to fill the column
     _columnsSort: 'string', // how a document should be sorted "ascending", "descending", undefined (none)
     _columnsHideIfEmpty: 'boolean', // whether empty stacking view column headings should be hidden
-    _columnHeaders: listSpec(SchemaHeaderField), // header descriptions for stacking/masonry
-    _schemaHeaders: listSpec(SchemaHeaderField), // header descriptions for schema views
+    // _columnHeaders: listSpec(SchemaHeaderField), // header descriptions for stacking/masonry
+    // _schemaHeaders: listSpec(SchemaHeaderField), // header descriptions for schema views
     _fontSize: 'string',
     _fontFamily: 'string',
-    _sidebarWidthPercent: 'string', // percent of text window width taken up by sidebar
+    _layout_sidebarWidthPercent: 'string', // percent of text window width taken up by sidebar
 
     // appearance properties on the data document
     backgroundColor: 'string', // background color of document
     borderRounding: 'string', // border radius rounding of document
     boxShadow: 'string', // the amount of shadow around the perimeter of a document
     color: 'string', // foreground color of document
-    fitContentsToBox: 'boolean', // whether freeform view contents should be zoomed/panned to fill the area of the document view box
+    freeform_fitContentsToBox: 'boolean', // whether freeform view contents should be zoomed/panned to fill the area of the document view box
     fontSize: 'string',
     hidden: 'boolean', // whether a document should not be displayed
-    isInkMask: 'boolean', // is the document a mask (ie, sits on top of other documents, has an unbounded width/height that is dark, and content uses 'hard-light' mix-blend-mode to let other documents pop through)
-    layout: 'string', // this is the native layout string for the document.  templates can be added using other fields and setting layoutKey below
-    layoutKey: 'string', // holds the field key for the field that actually holds the current lyoat
+    stroke_isInkMask: 'boolean', // is the document a mask (ie, sits on top of other documents, has an unbounded width/height that is dark, and content uses 'hard-light' mix-blend-mode to let other documents pop through)
+    layout: 'string', // this is the native layout string for the document.  templates can be added using other fields and setting layout_fieldKey below
+    layout_fieldKey: 'string', // holds the field key for the field that actually holds the current lyoat
     letterSpacing: 'string',
     opacity: 'number', // opacity of document
-    strokeWidth: 'number',
-    strokeBezier: 'number',
-    strokeStartMarker: 'string',
-    strokeEndMarker: 'string',
-    strokeDash: 'string',
+    stroke_width: 'number',
+    stroke_bezier: 'number',
+    stroke_startMarker: 'string',
+    stroke_endMarker: 'string',
+    stroke_dash: 'string',
     textTransform: 'string',
     treeViewOpen: 'boolean', //  flag denoting whether the documents sub-tree (contents) is visible or hidden
     treeViewExpandedView: 'string', // name of field whose contents are being displayed as the document's subtree
@@ -87,20 +87,20 @@ export const documentSchema = createSchema({
     followLinkLocation: 'string', // flag for where to place content when following a click interaction (e.g., add:right, lightbox, default, )
     hideLinkButton: 'boolean', // whether the blue link counter button should be hidden
     hideAllLinks: 'boolean', // whether all individual blue anchor dots should be hidden
-    linkDisplay: 'boolean', // whether a link connection should be shown between link anchor endpoints.
+    layout_linkDisplay: 'boolean', // whether a link connection should be shown between link anchor endpoints.
     isLightbox: 'boolean', // whether the marked object will display addDocTab() calls that target "lightbox" destinations
     layers: listSpec('string'), // which layers the document is part of
     _lockedPosition: 'boolean', // whether the document can be moved (dragged)
     _lockedTransform: 'boolean', // whether a freeformview can pan/zoom
-    linkDisplayArrow: 'boolean', // toggles directed arrows
+    layout_linkDisplayArrow: 'boolean', // toggles directed arrows
 
     // drag drop properties
     _stayInCollection: 'boolean', // whether document can be dropped into a different collection
     dragFactory: Doc, // the document that serves as the "template" for the onDragStart script.  ie, to drag out copies of the dragFactory document.
-    dropAction: 'string', // override specifying what should happen when this document is dropped (can be "alias", "copy", "move")
-    targetDropAction: 'string', // allows the target of a drop event to specify the dropAction ("alias", "copy", "move") NOTE: if the document is dropped within the same collection, the dropAction is coerced to 'move'
-    childDropAction: 'string', // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy")
-    removeDropProperties: listSpec('string'), // properties that should be removed from the alias/copy/etc of this document when it is dropped
+    dropAction: 'string', // override specifying what should happen when this document is dropped (can be "embed", "copy", "move")
+    targetDropAction: 'string', // allows the target of a drop event to specify the dropAction ("embed", "copy", "move") NOTE: if the document is dropped within the same collection, the dropAction is coerced to 'move'
+    childDropAction: 'string', // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "embed" or "copy")
+    removeDropProperties: listSpec('string'), // properties that should be removed from the embed/copy/etc of this document when it is dropped
 });
 
 export const collectionSchema = createSchema({
diff --git a/src/fields/util.ts b/src/fields/util.ts
index d5b55867e..2a6caaaa3 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -289,7 +289,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
         });
 
         // maps over the annotations of the document
-        DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + '-annotations']).forEach(d => {
+        DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + '_annotations']).forEach(d => {
             distributeAcls(key, acl, d, inheritingFromCollection, visited);
             distributeAcls(key, acl, d[DataSym], inheritingFromCollection, visited);
         });
@@ -377,7 +377,7 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
             diff?.op === '$addToSet'
                 ? { $addToSet: { ['fields.' + prop]: SerializationHelper.Serialize(new List<Doc>(diff.items)) } }
                 : diff?.op === '$remFromSet'
-                ? { $remFromSet: { ['fields.' + prop]: SerializationHelper.Serialize(new List<Doc>(diff.items)), hint : diff.hint } }
+                ? { $remFromSet: { ['fields.' + prop]: SerializationHelper.Serialize(new List<Doc>(diff.items)), hint: diff.hint } }
                 : { $set: { ['fields.' + prop]: SerializationHelper.Serialize(value) } };
         !op.$set && ((op as any).length = diff.length);
         const prevValue = ObjectField.MakeCopy(lastValue as List<any>);
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index a0b437354..c3423e2a5 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -21,7 +21,13 @@ import React = require('react');
 export class AudioUpload extends React.Component {
     @observable public _audioCol: Doc = FieldValue(
         Cast(
-            Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: 'mobile audio', _width: 500, _height: 100 }), Doc) as Doc], { title: 'mobile audio', _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: '0 0' }),
+            Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: 'mobile audio', _width: 500, _height: 100 }), Doc) as Doc], {
+                title: 'mobile audio',
+                _width: 300,
+                _height: 300,
+                _layoutFitContentsToBox: true,
+                boxShadow: '0 0',
+            }),
             Doc
         )
     ) as Doc;
@@ -48,7 +54,7 @@ export class AudioUpload extends React.Component {
                             Doc
                         ) as Doc,
                     ],
-                    { title: 'mobile audio', _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: '0 0' }
+                    { title: 'mobile audio', _width: 300, _height: 300, _layoutFitContentsToBox: true, boxShadow: '0 0' }
                 ),
                 Doc
             )
diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts
index a74e13a62..186f0bcd3 100644
--- a/src/server/ApiManagers/SearchManager.ts
+++ b/src/server/ApiManagers/SearchManager.ts
@@ -1,94 +1,89 @@
-import { exec } from "child_process";
-import { cyan, green, red, yellow } from "colors";
+import { exec } from 'child_process';
+import { cyan, green, red, yellow } from 'colors';
 import * as path from 'path';
-import { log_execution } from "../ActionUtilities";
-import { Database } from "../database";
-import { Method } from "../RouteManager";
-import RouteSubscriber from "../RouteSubscriber";
-import { Search } from "../Search";
-import ApiManager, { Registration } from "./ApiManager";
-import { Directory, pathToDirectory } from "./UploadManager";
+import { log_execution } from '../ActionUtilities';
+import { Database } from '../database';
+import { Method } from '../RouteManager';
+import RouteSubscriber from '../RouteSubscriber';
+import { Search } from '../Search';
+import ApiManager, { Registration } from './ApiManager';
+import { Directory, pathToDirectory } from './UploadManager';
 const findInFiles = require('find-in-files');
 
 export class SearchManager extends ApiManager {
-
     protected initialize(register: Registration): void {
-
         register({
             method: Method.GET,
-            subscription: new RouteSubscriber("solr").add("action"),
+            subscription: new RouteSubscriber('solr').add('action'),
             secureHandler: async ({ req, res }) => {
                 const { action } = req.params;
                 switch (action) {
-                    case "start":
-                    case "stop":
-                        const status = req.params.action === "start";
+                    case 'start':
+                    case 'stop':
+                        const status = req.params.action === 'start';
                         SolrManager.SetRunning(status);
                         break;
-                    case "update":
+                    case 'update':
                         await SolrManager.update();
                         break;
                     default:
                         console.log(yellow(`${action} is an unknown solr operation.`));
                 }
-                res.redirect("/home");
-            }
+                res.redirect('/home');
+            },
         });
 
         register({
             method: Method.GET,
-            subscription: "/textsearch",
+            subscription: '/textsearch',
             secureHandler: async ({ req, res }) => {
                 const q = req.query.q;
                 if (q === undefined) {
                     res.send([]);
                     return;
                 }
-                const resObj: { ids: string[], numFound: number, lines: string[] } = { ids: [], numFound: 0, lines: [] };
+                const resObj: { ids: string[]; numFound: number; lines: string[] } = { ids: [], numFound: 0, lines: [] };
                 let results: any;
                 const dir = pathToDirectory(Directory.text);
                 try {
                     const regex = new RegExp(q.toString());
-                    results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, dir, ".txt$");
+                    results = await findInFiles.find({ term: q, flags: 'ig' }, dir, '.txt$');
                     for (const result in results) {
-                        resObj.ids.push(path.basename(result, ".txt").replace(/upload_/, ""));
+                        resObj.ids.push(path.basename(result, '.txt').replace(/upload_/, ''));
                         resObj.lines.push(results[result].line);
                         resObj.numFound++;
                     }
                     res.send(resObj);
                 } catch (e) {
-                    console.log(red("textsearch:bad RegExp" + q.toString()));
+                    console.log(red('textsearch:bad RegExp' + q.toString()));
                     res.send([]);
                     return;
                 }
-            }
+            },
         });
 
         register({
             method: Method.GET,
-            subscription: "/dashsearch",
+            subscription: '/dashsearch',
             secureHandler: async ({ req, res }) => {
                 const solrQuery: any = {};
-                ["q", "fq", "start", "rows", "sort", "hl.maxAnalyzedChars", "hl", "hl.fl"].forEach(key => solrQuery[key] = req.query[key]);
+                ['q', 'fq', 'start', 'rows', 'sort', 'hl.maxAnalyzedChars', 'hl', 'hl.fl'].forEach(key => (solrQuery[key] = req.query[key]));
                 if (solrQuery.q === undefined) {
                     res.send([]);
                     return;
                 }
                 const results = await Search.search(solrQuery);
                 res.send(results);
-            }
+            },
         });
-
     }
-
 }
 
 export namespace SolrManager {
-
     export function SetRunning(status: boolean) {
-        const args = status ? "start" : "stop -p 8983";
+        const args = status ? 'start' : 'stop -p 8983';
         console.log(`solr management: trying to ${args}`);
-        exec(`solr ${args}`, { cwd: "./solr-8.3.1/bin" }, (error, stdout, stderr) => {
+        exec(`solr ${args}`, { cwd: './solr-8.3.1/bin' }, (error, stdout, stderr) => {
             if (error) {
                 console.log(red(`solr management error: unable to ${args} server`));
                 console.log(red(error.message));
@@ -97,39 +92,39 @@ export namespace SolrManager {
             console.log(yellow(stderr));
         });
         if (status) {
-            console.log(cyan("Start script is executing: please allow 15 seconds for solr to start on port 8983."));
+            console.log(cyan('Start script is executing: please allow 15 seconds for solr to start on port 8983.'));
         }
     }
 
     export async function update() {
-        console.log(green("Beginning update..."));
+        console.log(green('Beginning update...'));
         await log_execution<void>({
-            startMessage: "Clearing existing Solr information...",
-            endMessage: "Solr information successfully cleared",
+            startMessage: 'Clearing existing Solr information...',
+            endMessage: 'Solr information successfully cleared',
             action: Search.clear,
-            color: cyan
+            color: cyan,
         });
         const cursor = await log_execution({
-            startMessage: "Connecting to and querying for all documents from database...",
+            startMessage: 'Connecting to and querying for all documents from database...',
             endMessage: ({ result, error }) => {
                 const success = error === null && result !== undefined;
                 if (!success) {
-                    console.log(red("Unable to connect to the database."));
+                    console.log(red('Unable to connect to the database.'));
                     process.exit(0);
                 }
-                return "Connection successful and query complete";
+                return 'Connection successful and query complete';
             },
             action: () => Database.Instance.query({}),
-            color: yellow
+            color: yellow,
         });
         const updates: any[] = [];
         let numDocs = 0;
         function updateDoc(doc: any) {
             numDocs++;
-            if ((numDocs % 50) === 0) {
+            if (numDocs % 50 === 0) {
                 console.log(`Batch of 50 complete, total of ${numDocs}`);
             }
-            if (doc.__type !== "Doc") {
+            if (doc.__type !== 'Doc') {
                 return;
             }
             const fields = doc.fields;
@@ -143,8 +138,8 @@ export namespace SolrManager {
                 const term = ToSearchTerm(value);
                 if (term !== undefined) {
                     const { suffix, value } = term;
-                    if (key.endsWith('lastModified')) {
-                        update["lastModified" + suffix] = value;
+                    if (key.endsWith('modificationDate')) {
+                        update['modificationDate' + suffix] = value;
                     }
                     update[key + suffix] = value;
                     dynfield = true;
@@ -157,51 +152,54 @@ export namespace SolrManager {
         await cursor?.forEach(updateDoc);
         const result = await log_execution({
             startMessage: `Dispatching updates for ${updates.length} documents`,
-            endMessage: "Dispatched updates complete",
+            endMessage: 'Dispatched updates complete',
             action: () => Search.updateDocuments(updates),
-            color: cyan
+            color: cyan,
         });
         try {
             if (result) {
                 const { status } = JSON.parse(result).responseHeader;
-                console.log(status ? red(`Failed with status code (${status})`) : green("Success!"));
+                console.log(status ? red(`Failed with status code (${status})`) : green('Success!'));
             } else {
-                console.log(red("Solr is likely not running!"));
+                console.log(red('Solr is likely not running!'));
             }
         } catch (e) {
-            console.log(red("Error:"));
+            console.log(red('Error:'));
             console.log(e);
-            console.log("\n");
+            console.log('\n');
         }
         await cursor?.close();
     }
 
-    const suffixMap: { [type: string]: (string | [string, string | ((json: any) => any)]) } = {
-        "number": "_n",
-        "string": "_t",
-        "boolean": "_b",
-        "image": ["_t", "url"],
-        "video": ["_t", "url"],
-        "pdf": ["_t", "url"],
-        "audio": ["_t", "url"],
-        "web": ["_t", "url"],
-        "map": ["_t", "url"],
-        "date": ["_d", value => new Date(value.date).toISOString()],
-        "proxy": ["_i", "fieldId"],
-        "prefetch_proxy": ["_i", "fieldId"],
-        "list": ["_l", list => {
-            const results = [];
-            for (const value of list.fields) {
-                const term = ToSearchTerm(value);
-                if (term) {
-                    results.push(term.value);
+    const suffixMap: { [type: string]: string | [string, string | ((json: any) => any)] } = {
+        number: '_n',
+        string: '_t',
+        boolean: '_b',
+        image: ['_t', 'url'],
+        video: ['_t', 'url'],
+        pdf: ['_t', 'url'],
+        audio: ['_t', 'url'],
+        web: ['_t', 'url'],
+        map: ['_t', 'url'],
+        date: ['_d', value => new Date(value.date).toISOString()],
+        proxy: ['_i', 'fieldId'],
+        prefetch_proxy: ['_i', 'fieldId'],
+        list: [
+            '_l',
+            list => {
+                const results = [];
+                for (const value of list.fields) {
+                    const term = ToSearchTerm(value);
+                    if (term) {
+                        results.push(term.value);
+                    }
                 }
-            }
-            return results.length ? results : null;
-        }]
+                return results.length ? results : null;
+            },
+        ],
     };
 
-    function ToSearchTerm(val: any): { suffix: string, value: any } | undefined {
+    function ToSearchTerm(val: any): { suffix: string; value: any } | undefined {
         if (val === null || val === undefined) {
             return;
         }
@@ -213,7 +211,7 @@ export namespace SolrManager {
 
         if (Array.isArray(suffix)) {
             const accessor = suffix[1];
-            if (typeof accessor === "function") {
+            if (typeof accessor === 'function') {
                 val = accessor(val);
             } else {
                 val = val[accessor];
@@ -223,5 +221,4 @@ export namespace SolrManager {
 
         return { suffix, value: val };
     }
-
-}
\ No newline at end of file
+}
diff --git a/src/server/updateProtos.ts b/src/server/updateProtos.ts
index c5552f6bf..2f3772a77 100644
--- a/src/server/updateProtos.ts
+++ b/src/server/updateProtos.ts
@@ -1,14 +1,22 @@
-import { Database } from "./database";
+import { Database } from './database';
 
-const protos =
-    ["text", "image", "web", "collection", "kvp", "video", "audio", "pdf", "icon", "import", "linkdoc", "map"];
+const protos = ['text', 'image', 'web', 'collection', 'kvp', 'video', 'audio', 'pdf', 'icon', 'import', 'linkdoc', 'map'];
 
 (async function () {
     await Promise.all(
-        protos.map(protoId => new Promise(res => Database.Instance.update(protoId, {
-            $set: { "fields.baseProto": true }
-        }, res)))
+        protos.map(
+            protoId =>
+                new Promise(res =>
+                    Database.Instance.update(
+                        protoId,
+                        {
+                            $set: { 'fields.isBaseProto': true },
+                        },
+                        res
+                    )
+                )
+        )
     );
 
-    console.log("done");
-})();
\ No newline at end of file
+    console.log('done');
+})();
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index f131927f7..be5cdb202 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -476,8 +476,8 @@ export namespace WebSocket {
                 if (term !== undefined) {
                     const { suffix, value } = term;
                     update[key + suffix] = { set: value };
-                    if (key.endsWith('lastModified')) {
-                        update['lastModified' + suffix] = value;
+                    if (key.endsWith('modificationDate')) {
+                        update['modificationDate' + suffix] = value;
                     }
                 }
             }
-- 
cgit v1.2.3-70-g09d2


From 46cf6c823ca8ab628cd8c5bd7fdfe8945344a014 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 16 May 2023 14:50:29 -0400
Subject: fixed bugs with goldenlayout dragging and undoing.  fixed searching
 for filter values in sidebars.  Stopped creating empty list for collections
 when datafield() is accessed because it messes up undo of a collection. fixed
 tab title editing.  from marquee.  Added UndoStack UI and additional naming
 support in code.

---
 src/client/documents/Documents.ts                  | 12 ++--
 src/client/goldenLayout.js                         |  2 +-
 src/client/util/CurrentUserUtils.ts                | 44 +++++++-------
 src/client/util/DragManager.ts                     |  6 +-
 src/client/util/LinkFollower.ts                    |  2 +-
 src/client/util/SelectionManager.ts                |  2 +-
 src/client/util/UndoManager.ts                     | 53 ++++++++++++-----
 src/client/views/ContextMenuItem.tsx               |  5 +-
 src/client/views/DocumentDecorations.tsx           | 46 +++++----------
 src/client/views/EditableView.tsx                  |  2 +
 src/client/views/FilterPanel.tsx                   |  9 ++-
 src/client/views/GlobalKeyHandler.ts               | 10 ++--
 src/client/views/MainView.tsx                      |  8 +--
 src/client/views/PropertiesButtons.tsx             |  6 +-
 .../views/PropertiesDocBacklinksSelector.tsx       |  2 +-
 src/client/views/PropertiesDocContextSelector.tsx  |  2 +-
 src/client/views/PropertiesView.tsx                | 32 +++++-----
 src/client/views/SidebarAnnos.scss                 | 14 +++--
 src/client/views/SidebarAnnos.tsx                  | 15 ++++-
 src/client/views/UndoStack.tsx                     | 30 ++++++++++
 .../views/collections/CollectionDockingView.tsx    | 63 ++++++++++----------
 .../collections/CollectionNoteTakingViewColumn.tsx |  5 +-
 .../collections/CollectionStackedTimeline.tsx      |  3 +-
 .../CollectionStackingViewFieldColumn.tsx          |  4 +-
 src/client/views/collections/CollectionSubView.tsx | 13 ++--
 src/client/views/collections/TabDocView.tsx        | 21 ++++---
 src/client/views/collections/TreeView.tsx          |  4 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 -
 .../collections/collectionFreeForm/MarqueeView.tsx | 26 +++-----
 .../collectionSchema/CollectionSchemaView.tsx      | 32 +++++-----
 .../collectionSchema/SchemaColumnHeader.tsx        |  2 -
 .../collections/collectionSchema/SchemaRowBox.tsx  | 10 ++--
 .../collectionSchema/SchemaTableCell.tsx           |  2 +-
 src/client/views/linking/LinkMenu.tsx              |  2 +-
 src/client/views/nodes/AudioBox.tsx                |  2 +-
 src/client/views/nodes/DocumentLinksButton.tsx     | 20 +++----
 src/client/views/nodes/DocumentView.tsx            | 57 ++++++++++--------
 src/client/views/nodes/LinkDocPreview.tsx          |  3 +-
 src/client/views/nodes/button/FontIconBox.tsx      | 60 ++++++++-----------
 .../views/nodes/formattedText/FormattedTextBox.tsx | 69 +++++++++++-----------
 src/client/views/nodes/trails/PresBox.tsx          |  9 ++-
 src/client/views/nodes/trails/PresElementBox.tsx   | 13 ++--
 src/client/views/pdf/AnchorMenu.tsx                | 11 ++--
 src/client/views/search/SearchBox.tsx              |  2 +
 src/fields/Doc.ts                                  | 18 ++++--
 src/fields/util.ts                                 | 38 +++++++-----
 46 files changed, 421 insertions(+), 372 deletions(-)
 create mode 100644 src/client/views/UndoStack.tsx

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 2151d0ec7..795d60b48 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -24,7 +24,7 @@ import { DirectoryImportBox } from '../util/Import & Export/DirectoryImportBox';
 import { FollowLinkScript } from '../util/LinkFollower';
 import { LinkManager } from '../util/LinkManager';
 import { ScriptingGlobals } from '../util/ScriptingGlobals';
-import { undoBatch, UndoManager } from '../util/UndoManager';
+import { undoable, undoBatch, UndoManager } from '../util/UndoManager';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
 import { DimUnit } from '../views/collections/collectionMulticolumn/CollectionMulticolumnView';
 import { CollectionView } from '../views/collections/CollectionView';
@@ -249,7 +249,7 @@ export class DocumentOptions {
     contextMenuIcons?: List<string>;
     defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or deafult (undefined) means open document full screen
     waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire.  'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
-    dontUndo?: boolean; // whether button clicks should be undoable (this is set to true for Undo/Redo/and sidebar buttons that open the siebar panel)
+    dontUndo?: boolean; // whether button clicks should be undoable ( true for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)
     layout?: string | Doc; // default layout string for a document
     contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
     childLimitHeight?: number; // whether to limit the height of collection children.  0 - means  height can be no bigger than width
@@ -1532,7 +1532,7 @@ export namespace DocUtils {
                 description: 'Quick Notes',
                 subitems: DocListCast((Doc.UserDoc()['template-notes'] as Doc).data).map((note, i) => ({
                     description: ':' + StrCast(note.title),
-                    event: undoBatch((args: { x: number; y: number }) => {
+                    event: undoable((args: { x: number; y: number }) => {
                         const textDoc = Docs.Create.TextDocument('', {
                             _width: 200,
                             x,
@@ -1546,7 +1546,7 @@ export namespace DocUtils {
                             textDoc[pivotField] = pivotValue;
                         }
                         docTextAdder(textDoc);
-                    }),
+                    }, 'create quick note'),
                     icon: StrCast(note.icon) as IconProp,
                 })) as ContextMenuProps[],
                 icon: 'sticky-note',
@@ -1557,7 +1557,7 @@ export namespace DocUtils {
             .filter(doc => doc && doc !== Doc.UserDoc().emptyTrail && doc !== Doc.UserDoc().emptyDataViz)
             .map((dragDoc, i) => ({
                 description: ':' + StrCast(dragDoc.title).replace('Untitled ', ''),
-                event: undoBatch((args: { x: number; y: number }) => {
+                event: undoable((args: { x: number; y: number }) => {
                     const newDoc = DocUtils.copyDragFactory(dragDoc);
                     if (newDoc) {
                         newDoc.author = Doc.CurrentUserEmail;
@@ -1570,7 +1570,7 @@ export namespace DocUtils {
                         }
                         docAdder?.(newDoc);
                     }
-                }),
+                }, StrCast(dragDoc.title)),
                 icon: Doc.toIcon(dragDoc),
             })) as ContextMenuProps[];
         ContextMenu.Instance.addItem({
diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js
index 9cb20d834..843b8bb5f 100644
--- a/src/client/goldenLayout.js
+++ b/src/client/goldenLayout.js
@@ -4740,7 +4740,7 @@
                         newstack._$init();
                         newstack.addChild(this.contentItems[0]);
                     }
-                    correctRowOrCol.addChild(newstack,  insertBefore ? 0 : undefined, true);
+                    correctRowOrCol.addChild(newstack,  !insertBefore ? 0 : undefined, true);
                     newstack.config[dimension] = 50;
                     contentItem.config[dimension] = 50;
                     correctRowOrCol.callDownwards('setSize');
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 26fe8f440..b0a2c7d60 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -363,7 +363,7 @@ export class CurrentUserUtils {
         const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, scripts, funcs }) => {
             const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
             const reqdBtnOpts:DocumentOptions = {
-                title, icon, target, btnType: ButtonType.MenuButton, isSystem: true, dontUndo: true,  dontRegisterView: true,
+                title, icon, target, btnType: ButtonType.MenuButton, isSystem: true, dontUndo: true, dontRegisterView: true,
                 _width: 60, _height: 60,  _stayInCollection: true, _hideContextMenu: true,
                 _removeDropProperties: new List<string>(["_stayInCollection"]),
             };
@@ -598,12 +598,12 @@ export class CurrentUserUtils {
                             CurrentUserUtils.createToolButton(opts), scripts, funcs);
         
         const btnDescs = [// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet
-            { scripts: { onClick: "undo()"}, opts: { title: "undo", icon: "undo-alt", toolTip: "Click to undo" }},
-            { scripts: { onClick: "redo()"}, opts: { title: "redo", icon: "redo-alt", toolTip: "Click to redo" }},
-            { scripts: { },                  opts: { title: "linker", icon: "linkui", toolTip: "link started"}},
-            { scripts: { },                  opts: { title: "currently playing", icon: "currentlyplayingui", toolTip: "currently playing media"}},
+            { scripts: { onClick: "undo()"},      opts: { title: "undo", icon: "undo-alt", toolTip: "Click to undo" }},
+            { scripts: { onClick: "redo()"},      opts: { title: "redo", icon: "redo-alt", toolTip: "Click to redo" }},
+            { scripts: { },                       opts: { title: "linker", icon: "linkui", toolTip: "link started"}},
+            { scripts: { },                       opts: { title: "currently playing", icon: "currentlyplayingui", toolTip: "currently playing media"}},
         ];
-        const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts));
+        const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts));
         const dockBtnsReqdOpts:DocumentOptions = {
             title: "docked buttons", _height: 40, flexGap: 0, boxShadow: "standard", childDropAction: 'embed',
             childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true
@@ -632,21 +632,21 @@ export class CurrentUserUtils {
     }
     static textTools():Button[] {
         return [
-            { title: "Font",    toolTip: "Font", width: 100,     btnType: ButtonType.DropdownList,                      toolType:"font",     ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'},
+            { title: "Font",     toolTip: "Font", width: 100,     btnType: ButtonType.DropdownList,                      toolType:"font",     ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'},
               btnList: new List<string>(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) },
-            { title: "Size",    toolTip: "Font size (%size)",    btnType: ButtonType.NumberDropdownButton, width: 75,           toolType:"fontSize", ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 0 },
-            { title: "Color",   toolTip: "Font color (%color)",  btnType: ButtonType.ColorButton,  icon: "font",        toolType:"fontColor",ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'}},
+            { title: "Font Size",toolTip: "Font size (%size)",    btnType: ButtonType.NumberDropdownButton, width: 75,           toolType:"fontSize", ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 0 },
+            { title: "Color",    toolTip: "Font color (%color)",  btnType: ButtonType.ColorButton,  icon: "font",        toolType:"fontColor",ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'}},
             { title: "Highlight",toolTip:"Font highlight",       btnType: ButtonType.ColorButton,  icon: "highlighter", toolType:"highlight",ignoreClick: true,   scripts: {script:  '{ return setFontAttr(self.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} },
-            { title: "Bold",    toolTip: "Bold (Ctrl+B)",        btnType: ButtonType.ToggleButton, icon: "bold",        toolType:"bold",                          scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
-            { title: "Italic",  toolTip: "Italic (Ctrl+I)",      btnType: ButtonType.ToggleButton, icon: "italic",      toolType:"italics",                       scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
-            { title: "Under",   toolTip: "Underline (Ctrl+U)",   btnType: ButtonType.ToggleButton, icon: "underline",   toolType:"underline",                     scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
-            { title: "Bullets", toolTip: "Bullet List",          btnType: ButtonType.ToggleButton, icon: "list",        toolType:"bullet",                        scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
-            { title: "#",       toolTip: "Number List",          btnType: ButtonType.ToggleButton, icon: "list-ol",     toolType:"decimal",                       scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
-            { title: "Left",    toolTip: "Left align (Cmd-[)",   btnType: ButtonType.ToggleButton, icon: "align-left",  toolType:"left",                          scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }},
-            { title: "Center",  toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",                        scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
-            { title: "Right",   toolTip: "Right align (Cmd-])",  btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right",                         scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
-            { title: "Dictate", toolTip: "Dictate",              btnType: ButtonType.ToggleButton, icon: "microphone",  toolType:"dictation",                     scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}},
-            { title: "NoLink",  toolTip: "Auto Link",            btnType: ButtonType.ToggleButton, icon: "link",        toolType:"noAutoLink", expertMode:true,   scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}},
+            { title: "Bold",     toolTip: "Bold (Ctrl+B)",        btnType: ButtonType.ToggleButton, icon: "bold",        toolType:"bold",                          scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+            { title: "Italic",   toolTip: "Italic (Ctrl+I)",      btnType: ButtonType.ToggleButton, icon: "italic",      toolType:"italics",                       scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+            { title: "Under",    toolTip: "Underline (Ctrl+U)",   btnType: ButtonType.ToggleButton, icon: "underline",   toolType:"underline",                     scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+            { title: "Bullets",  toolTip: "Bullet List",          btnType: ButtonType.ToggleButton, icon: "list",        toolType:"bullet",                        scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+            { title: "#",        toolTip: "Number List",          btnType: ButtonType.ToggleButton, icon: "list-ol",     toolType:"decimal",                       scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+            { title: "Left",     toolTip: "Left align (Cmd-[)",   btnType: ButtonType.ToggleButton, icon: "align-left",  toolType:"left",                          scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }},
+            { title: "Center",   toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",                        scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+            { title: "Right",    toolTip: "Right align (Cmd-])",  btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right",                         scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+            { title: "Dictate",  toolTip: "Dictate",              btnType: ButtonType.ToggleButton, icon: "microphone",  toolType:"dictation",                     scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}},
+            { title: "NoLink",   toolTip: "Auto Link",            btnType: ButtonType.ToggleButton, icon: "link",        toolType:"noAutoLink", expertMode:true,   scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}},
             // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}},
             // { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", scripts: {onClick:: 'toggleSuperscript()'}},
             // { title: "Subscript", tooltip: "Subscript", btnType: ButtonType.ToggleButton, icon: "subscript", scripts: {onClick:: 'toggleSubscript()'}},
@@ -711,7 +711,7 @@ export class CurrentUserUtils {
         const reqdOpts:DocumentOptions = {
             ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit,
             backgroundColor: params.backgroundColor ??"transparent", ///  a bit hacky. if an onClick is specified, then assume a toggle uses onClick to get the backgroundColor (see below).  Otherwise, assume a transparent background
-            color: Colors.WHITE, isSystem: true, dontUndo: true, 
+            color: Colors.WHITE, isSystem: true, //dontUndo: true, 
             _nativeWidth: params.width ?? 30, _width: params.width ?? 30,
             _height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth,
             toolType: params.toolType, expertMode: params.expertMode,
@@ -727,14 +727,14 @@ export class CurrentUserUtils {
 
     /// Initializes all the default buttons for the top bar context menu
     static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") {
-        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", flexGap: 0, childDropAction: 'embed', childDontRegisterViews: true,  linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 };
+        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", dontUndo:true, flexGap: 0, childDropAction: 'embed', childDontRegisterViews: true,  linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 };
         const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined);
         const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => {
             const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title);
             if (!params.subMenu) {
                 return this.setupContextMenuButton(params, menuBtnDoc);
             } else {
-                const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit,
+                const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, dontUndo: true,
                     childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: params.scripts?.onClick ? false : true,
                     linearViewSubMenu: true, linearViewExpandable: true, };
                 const items = params.subMenu?.map(sub =>
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 070e0f918..e3798233e 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -263,7 +263,7 @@ export namespace DragManager {
 
     // drags a column from a schema view
     export function StartColumnDrag(ele: HTMLElement[], dragData: ColumnDragData, downX: number, downY: number, options?: DragOptions) {
-        StartDrag(ele, dragData, downX, downY, options);
+        StartDrag(ele, dragData, downX, downY, options, undefined, 'Drag Column');
     }
 
     export function SetSnapLines(horizLines: number[], vertLines: number[]) {
@@ -325,10 +325,10 @@ export namespace DragManager {
     export let docsBeingDragged: Doc[] = observable([] as Doc[]);
     export let CanEmbed = false;
     export let DocDragData: DocumentDragData | undefined;
-    export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) {
+    export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void, dragUndoName?:string) {
         if (dragData.dropAction === 'none') return;
         DocDragData = dragData as DocumentDragData;
-        const batch = UndoManager.StartBatch('dragging');
+        const batch = UndoManager.StartBatch(dragUndoName ?? 'document drag');
         eles = eles.filter(e => e);
         CanEmbed = dragData.canEmbed || false;
         if (!dragDiv) {
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts
index 2812d6c88..f74409e42 100644
--- a/src/client/util/LinkFollower.ts
+++ b/src/client/util/LinkFollower.ts
@@ -28,7 +28,7 @@ export class LinkFollower {
     // if the target isn't onscreen, then it will open up the target in the lightbox, or in place
     // depending on the followLinkLocation property of the source (or the link itself as a fallback);
     public static FollowLink = (linkDoc: Opt<Doc>, sourceDoc: Doc, altKey: boolean) => {
-        const batch = UndoManager.StartBatch('follow link click');
+        const batch = UndoManager.StartBatch('Follow Link');
         runInAction(() => (LinkFollower.IsFollowing = true)); // turn off decoration bounds while following links since animations may occur, and DocDecorations is based on screenToLocal which is not always an observable value
         LinkFollower.traverseLink(
             linkDoc,
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index fba0a4f76..0125331ec 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -118,6 +118,6 @@ ScriptingGlobals.add(function SelectionManager_selectedDocType(type: string, exp
     if (type === 'tab') {
         return SelectionManager.Views().lastElement()?.props.renderDepth === 0;
     }
-    let selected = (sel => (checkContext ? DocCast(sel?.context) : sel))(SelectionManager.SelectedSchemaDoc() ?? SelectionManager.Docs().lastElement());
+    let selected = (sel => (checkContext ? DocCast(sel?.embedContainer) : sel))(SelectionManager.SelectedSchemaDoc() ?? SelectionManager.Docs().lastElement());
     return selected?.type === type || selected?.type_collection === type || !type;
 });
diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts
index d0aec45a6..6fef9d660 100644
--- a/src/client/util/UndoManager.ts
+++ b/src/client/util/UndoManager.ts
@@ -3,7 +3,7 @@ import { Without } from '../../Utils';
 
 function getBatchName(target: any, key: string | symbol): string {
     const keyName = key.toString();
-    if (target && target.constructor && target.constructor.name) {
+    if (target?.constructor?.name) {
         return `${target.constructor.name}.${keyName}`;
     }
     return keyName;
@@ -34,6 +34,17 @@ function propertyDecorator(target: any, key: string | symbol) {
     });
 }
 
+export function undoable(fn: (...args: any[]) => any, batchName: string): (...args: any[]) => any {
+    return function () {
+        const batch = UndoManager.StartBatch(batchName);
+        try {
+            return fn.apply(undefined, arguments as any);
+        } finally {
+            batch.end();
+        }
+    };
+}
+
 export function undoBatch(target: any, key: string | symbol, descriptor?: TypedPropertyDescriptor<any>): any;
 export function undoBatch(fn: (...args: any[]) => any): (...args: any[]) => any;
 export function undoBatch(target: any, key?: string | symbol, descriptor?: TypedPropertyDescriptor<any>): any {
@@ -73,15 +84,18 @@ export namespace UndoManager {
     }
     type UndoBatch = UndoEvent[];
 
+    export let undoStackNames: string[] = observable([]);
+    export let redoStackNames: string[] = observable([]);
     export let undoStack: UndoBatch[] = observable([]);
     export let redoStack: UndoBatch[] = observable([]);
     let currentBatch: UndoBatch | undefined;
-    export let batchCounter = 0;
+    export let batchCounter = observable.box(0);
     let undoing = false;
     let tempEvents: UndoEvent[] | undefined = undefined;
 
-    export function AddEvent(event: UndoEvent): void {
-        if (currentBatch && batchCounter && !undoing) {
+    export function AddEvent(event: UndoEvent, value?: any): void {
+        if (currentBatch && batchCounter.get() && !undoing) {
+            console.log('                         '.slice(0, batchCounter.get()) + 'UndoEvent : ' + event.prop + ' = ' + value);
             currentBatch.push(event);
             tempEvents?.push(event);
         }
@@ -135,11 +149,13 @@ export namespace UndoManager {
 
         private dispose = (cancel: boolean) => {
             if (this.disposed) {
-                throw new Error('Cannot dispose an already disposed batch');
+                console.log('WARNING: undo batch already disposed');
+                return false;
+            } else {
+                this.disposed = true;
+                openBatches.splice(openBatches.indexOf(this));
+                return EndBatch(this.batchName, cancel);
             }
-            this.disposed = true;
-            openBatches.splice(openBatches.indexOf(this));
-            return EndBatch(cancel);
         };
 
         end = () => this.dispose(false);
@@ -147,22 +163,23 @@ export namespace UndoManager {
     }
 
     export function StartBatch(batchName: string): Batch {
-        // console.log("Start " + batchCounter + " " + batchName);
-        batchCounter++;
-        if (batchCounter > 0 && currentBatch === undefined) {
+        console.log('                          '.slice(0, batchCounter.get()) + 'Start ' + batchCounter + ' ' + batchName);
+        runInAction(() => batchCounter.set(batchCounter.get() + 1));
+        if (currentBatch === undefined) {
             currentBatch = [];
         }
         return new Batch(batchName);
     }
 
-    const EndBatch = action((cancel: boolean = false) => {
-        batchCounter--;
-        // console.log("End " + batchCounter);
-        if (batchCounter === 0 && currentBatch?.length) {
-            // console.log("------ended----")
+    const EndBatch = action((batchName: string, cancel: boolean = false) => {
+        runInAction(() => batchCounter.set(batchCounter.get() - 1));
+        console.log('                          '.slice(0, batchCounter.get()) + 'End ' + batchName + ' (' + currentBatch?.length + ')');
+        if (batchCounter.get() === 0 && currentBatch?.length) {
             if (!cancel) {
                 undoStack.push(currentBatch);
+                undoStackNames.push(batchName ?? '???');
             }
+            redoStackNames.length = 0;
             redoStack.length = 0;
             currentBatch = undefined;
             return true;
@@ -204,6 +221,7 @@ export namespace UndoManager {
             return;
         }
 
+        const names = undoStackNames.pop();
         const commands = undoStack.pop();
         if (!commands) {
             return;
@@ -215,6 +233,7 @@ export namespace UndoManager {
         }
         undoing = false;
 
+        redoStackNames.push(names ?? '???');
         redoStack.push(commands);
     });
 
@@ -223,6 +242,7 @@ export namespace UndoManager {
             return;
         }
 
+        const names = redoStackNames.pop();
         const commands = redoStack.pop();
         if (!commands) {
             return;
@@ -234,6 +254,7 @@ export namespace UndoManager {
         }
         undoing = false;
 
+        undoStackNames.push(names ?? '???');
         undoStack.push(commands);
     });
 }
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index e87d2046b..33f250986 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -40,10 +40,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
     handleEvent = async (e: React.MouseEvent<HTMLDivElement>) => {
         if ('event' in this.props) {
             this.props.closeMenu?.();
-            let batch: UndoManager.Batch | undefined;
-            if (this.props.undoable !== false) {
-                batch = UndoManager.StartBatch(`Context menu event: ${this.props.description}`);
-            }
+            const batch = this.props.undoable !== false ? UndoManager.StartBatch(`Click Menu item: ${this.props.description}`) : undefined;
             await this.props.event({ x: e.clientX, y: e.clientY });
             batch?.end();
         }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 39073d763..8077b9af1 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -2,23 +2,25 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@material-ui/core';
 import { IconButton } from 'browndash-components';
-import { action, computed, observable, reaction, runInAction } from 'mobx';
+import { action, computed, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import { FaUndo } from 'react-icons/fa';
 import { DateField } from '../../fields/DateField';
 import { AclAdmin, AclEdit, DataSym, Doc, DocListCast, Field, HeightSym, WidthSym } from '../../fields/Doc';
-import { Document } from '../../fields/documentSchemas';
 import { InkField } from '../../fields/InkField';
+import { RichTextField } from '../../fields/RichTextField';
 import { ScriptField } from '../../fields/ScriptField';
 import { Cast, NumCast, StrCast } from '../../fields/Types';
 import { GetEffectiveAcl } from '../../fields/util';
 import { aggregateBounds, emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils';
 import { Docs } from '../documents/Documents';
 import { DocumentType } from '../documents/DocumentTypes';
+import { DocumentManager } from '../util/DocumentManager';
 import { DragManager } from '../util/DragManager';
+import { LinkFollower } from '../util/LinkFollower';
 import { SelectionManager } from '../util/SelectionManager';
 import { SnappingManager } from '../util/SnappingManager';
-import { undoBatch, UndoManager } from '../util/UndoManager';
+import { UndoManager } from '../util/UndoManager';
 import { CollectionDockingView } from './collections/CollectionDockingView';
 import { CollectionFreeFormView } from './collections/collectionFreeForm';
 import { DocumentButtonBar } from './DocumentButtonBar';
@@ -27,15 +29,11 @@ import { Colors } from './global/globalEnums';
 import { InkingStroke } from './InkingStroke';
 import { InkStrokeProperties } from './InkStrokeProperties';
 import { LightboxView } from './LightboxView';
-import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView';
+import { DocumentView, OpenWhereMod } from './nodes/DocumentView';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { ImageBox } from './nodes/ImageBox';
 import React = require('react');
-import { RichTextField } from '../../fields/RichTextField';
-import { LinkFollower } from '../util/LinkFollower';
 import _ = require('lodash');
-import { DocumentManager } from '../util/DocumentManager';
-import { isUndefined } from 'lodash';
 
 @observer
 export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> {
@@ -150,7 +148,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                             Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true);
                         }
                     }),
-                'title blur'
+                'edit title'
             );
         }
     };
@@ -227,11 +225,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             .filter(v => v && v.props.renderDepth > 0);
         if (forceDeleteOrIconify === false && this._iconifyBatch) return;
         this._deleteAfterIconify = forceDeleteOrIconify || this._iconifyBatch ? true : false;
-        if (!this._iconifyBatch) {
-            this._iconifyBatch = UndoManager.StartBatch('iconifying');
-        } else {
-            forceDeleteOrIconify = false; // can't force immediate close in the middle of iconifying -- have to wait until iconifying completes
-        }
         var iconifyingCount = views.length;
         const finished = action((force?: boolean) => {
             if ((force || --iconifyingCount === 0) && this._iconifyBatch) {
@@ -250,6 +243,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                 this._iconifyBatch = undefined;
             }
         });
+        if (!this._iconifyBatch) {
+            this._iconifyBatch = UndoManager.StartBatch(forceDeleteOrIconify ? 'delete selected docs' : 'iconifying');
+        } else {
+            forceDeleteOrIconify = false; // can't force immediate close in the middle of iconifying -- have to wait until iconifying completes
+        }
+
         if (forceDeleteOrIconify) finished(forceDeleteOrIconify);
         else if (!this._deleteAfterIconify) views.forEach(dv => dv.iconify(finished));
     };
@@ -397,7 +396,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
     onRotateDown = (e: React.PointerEvent): void => {
         this._isRotating = true;
         const rcScreen = { X: this.rotCenter[0], Y: this.rotCenter[1] };
-        const rotateUndo = UndoManager.StartBatch('rotatedown');
+        const rotateUndo = UndoManager.StartBatch('drag rotation');
         const selectedInk = SelectionManager.Views().filter(i => i.ComponentView instanceof InkingStroke);
         const centerPoint = this.rotCenter.slice();
         const infos = new Map<Doc, { unrotatedDocPos: { x: number; y: number }; startRotCtr: { x: number; y: number }; accumRot: number }>();
@@ -465,7 +464,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         const bounds = e.currentTarget.getBoundingClientRect();
         this._offX = this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX;
         this._offY = this._resizeHdlId.toLowerCase().includes('top') ? bounds.bottom - e.clientY : bounds.top - e.clientY;
-        this._resizeUndo = UndoManager.StartBatch('DocDecs resize');
+        this._resizeUndo = UndoManager.StartBatch('drag resizing');
         this._snapX = e.pageX;
         this._snapY = e.pageY;
         const ffviewSet = new Set<CollectionFreeFormView>();
@@ -770,20 +769,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
 
         const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
             <Tooltip key={key} title={<div className="dash-tooltip">{title}</div>} placement="top">
-                <div
-                    className={`documentDecorations-${key}Button`}
-                    onContextMenu={e => e.preventDefault()}
-                    onPointerDown={
-                        pointerDown ??
-                        (e =>
-                            setupMoveUpEvents(
-                                this,
-                                e,
-                                returnFalse,
-                                emptyFunction,
-                                undoBatch(e => click!(e))
-                            ))
-                    }>
+                <div className={`documentDecorations-${key}Button`} onContextMenu={e => e.preventDefault()} onPointerDown={pointerDown ?? (e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => click!(e)))}>
                     <FontAwesomeIcon icon={icon as any} />
                 </div>
             </Tooltip>
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 6b4132814..7043edcee 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -156,12 +156,14 @@ export class EditableView extends React.Component<EditableProps> {
                 break;
             case ':':
                 if (this.props.menuCallback) {
+                    e.stopPropagation();
                     this.props.menuCallback(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y);
                     break;
                 }
 
             default:
                 if (this.props.textCallback?.(e.key)) {
+                    e.stopPropagation();
                     this._editing = false;
                     this.props.isEditingCallback?.(false);
                 }
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 75e0e7c4c..53c1f1018 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -10,6 +10,7 @@ import { UserOptions } from '../util/GroupManager';
 import './FilterPanel.scss';
 import { FieldView } from './nodes/FieldView';
 import { SearchBox } from './search/SearchBox';
+import { undoable } from '../util/UndoManager';
 
 interface filterProps {
     rootDoc: Doc;
@@ -31,7 +32,7 @@ export class FilterPanel extends React.Component<filterProps> {
         return targetView?.ComponentView?.annotationKey ?? targetView?.ComponentView?.fieldKey ?? 'data';
     }
     @computed get targetDocChildren() {
-        return DocListCast(this.targetDoc?.[this.targetDocChildKey] || Doc.ActiveDashboard?.data);
+        return [...DocListCast(this.targetDoc?.[this.targetDocChildKey] || Doc.ActiveDashboard?.data), ...DocListCast(this.targetDoc[Doc.LayoutFieldKey(this.targetDoc) + '_sidebar'])];
     }
 
     @computed get allDocs() {
@@ -89,6 +90,7 @@ export class FilterPanel extends React.Component<filterProps> {
                     const fieldKey = Doc.LayoutFieldKey(t);
                     const annos = !Field.toString(Doc.LayoutField(t) as Field).includes('CollectionView');
                     DocListCast(t[annos ? fieldKey + '_annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc));
+                    annos && DocListCast(t[fieldKey + '_sidebar']).forEach(newdoc => newarray.push(newdoc));
                 });
                 subDocs = newarray;
             }
@@ -204,7 +206,8 @@ export class FilterPanel extends React.Component<filterProps> {
                                 .find(filter => filter.split(':')[0] === facetHeader)
                                 ?.split(':')[1] ?? '-empty-'
                         }
-                        onKeyDown={e => e.key === 'Enter' && Doc.setDocFilter(this.targetDoc, facetHeader, e.currentTarget.value, !e.currentTarget.value ? 'remove' : 'match')}
+                        onBlur={undoable(e => Doc.setDocFilter(this.targetDoc, facetHeader, e.currentTarget.value, !e.currentTarget.value ? 'remove' : 'match'), 'set text filter')}
+                        onKeyDown={e => e.key === 'Enter' && undoable(e => Doc.setDocFilter(this.targetDoc, facetHeader, e.currentTarget.value, !e.currentTarget.value ? 'remove' : 'match'), 'set text filter')(e)}
                     />
                 );
             case 'checkbox':
@@ -220,7 +223,7 @@ export class FilterPanel extends React.Component<filterProps> {
                                         ?.split(':')[2] === 'check'
                                 }
                                 type={type}
-                                onChange={e => Doc.setDocFilter(this.targetDoc, facetHeader, fval, e.target.checked ? 'check' : 'remove')}
+                                onChange={undoable(e => Doc.setDocFilter(this.targetDoc, facetHeader, fval, e.target.checked ? 'check' : 'remove'), 'set filter')}
                             />
                             {facetValue}
                         </div>
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index b9b92dd2b..625bc760d 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -161,12 +161,10 @@ export class KeyManager {
             case 'delete':
             case 'backspace':
                 if (document.activeElement?.tagName !== 'INPUT' && document.activeElement?.tagName !== 'TEXTAREA') {
-                    UndoManager.RunInBatch(() => {
-                        if (LightboxView.LightboxDoc) {
-                            LightboxView.SetLightboxDoc(undefined);
-                            SelectionManager.DeselectAll();
-                        } else DocumentDecorations.Instance.onCloseClick(true);
-                    }, 'backspace');
+                    if (LightboxView.LightboxDoc) {
+                        LightboxView.SetLightboxDoc(undefined);
+                        SelectionManager.DeselectAll();
+                    } else DocumentDecorations.Instance.onCloseClick(true);
                     return { stopPropagation: true, preventDefault: true };
                 }
                 break;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 853f9cace..50f451c0a 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -915,11 +915,11 @@ export class MainView extends React.Component {
         return !SelectionManager.Views().some(dv => dv.rootDoc.freeform_snapLines) ? null : (
             <div className="mainView-snapLines">
                 <svg style={{ width: '100%', height: '100%' }}>
-                    {SnappingManager.horizSnapLines().map(l => (
-                        <line x1="0" y1={l} x2="2000" y2={l} stroke="black" opacity={0.3} strokeWidth={0.5} strokeDasharray={'1 1'} />
+                    {SnappingManager.horizSnapLines().map((l, i) => (
+                        <line key={i} x1="0" y1={l} x2="2000" y2={l} stroke="black" opacity={0.3} strokeWidth={0.5} strokeDasharray={'1 1'} />
                     ))}
-                    {SnappingManager.vertSnapLines().map(l => (
-                        <line y1="0" x1={l} y2="2000" x2={l} stroke="black" opacity={0.3} strokeWidth={0.5} strokeDasharray={'1 1'} />
+                    {SnappingManager.vertSnapLines().map((l, i) => (
+                        <line key={i} y1="0" x1={l} y2="2000" x2={l} stroke="black" opacity={0.3} strokeWidth={0.5} strokeDasharray={'1 1'} />
                     ))}
                 </svg>
             </div>
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index a37447505..a5c58c9d2 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -14,7 +14,7 @@ import { DocUtils } from '../documents/Documents';
 import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
 import { LinkManager } from '../util/LinkManager';
 import { SelectionManager } from '../util/SelectionManager';
-import { undoBatch } from '../util/UndoManager';
+import { undoable, undoBatch } from '../util/UndoManager';
 import { Colors } from './global/globalEnums';
 import { InkingStroke } from './InkingStroke';
 import { DocumentView, OpenWhere } from './nodes/DocumentView';
@@ -51,11 +51,11 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                     <div
                         className={`propertiesButtons-linkButton-empty toggle-${StrCast(targetDoc[property]).includes(':hover') ? 'hover' : targetDoc[property] ? 'on' : 'off'}`}
                         onPointerDown={e => e.stopPropagation()}
-                        onClick={undoBatch(() => {
+                        onClick={undoable(() => {
                             if (SelectionManager.Views().length > 1) {
                                 SelectionManager.Views().forEach(dv => (onClick ?? onPropToggle)(dv, dv.rootDoc, property));
                             } else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property);
-                        })}>
+                        }, property)}>
                         <FontAwesomeIcon className="documentdecorations-icon" size="lg" icon={icon(BoolCast(targetDoc?.[property])) as any} />
                     </div>
                     <div className="propertiesButtons-title">{label}</div>
diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx
index 46e6fd188..7b21629da 100644
--- a/src/client/views/PropertiesDocBacklinksSelector.tsx
+++ b/src/client/views/PropertiesDocBacklinksSelector.tsx
@@ -25,7 +25,7 @@ export class PropertiesDocBacklinksSelector extends React.Component<PropertiesDo
 
         if (otherdoc) {
             otherdoc.hidden = false;
-            this.props.addDocTab(Doc.IsDocDataProto(otherdoc) ? Doc.MakeDelegate(otherdoc) : otherdoc, OpenWhere.toggleRight);
+            this.props.addDocTab(Doc.IsDataProto(otherdoc) ? Doc.MakeDelegate(otherdoc) : otherdoc, OpenWhere.toggleRight);
         }
     };
 
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index 12a09196e..e1279c9a7 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -48,7 +48,7 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
 
     getOnClick = (col: Doc, target: Doc) => {
         if (!this.props.DocView) return;
-        col = Doc.IsDocDataProto(col) ? Doc.MakeDelegate(col) : col;
+        col = Doc.IsDataProto(col) ? Doc.MakeDelegate(col) : col;
         DocFocusOrOpen(Doc.GetProto(this.props.DocView.props.Document), undefined, col);
     };
 
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 19c138a21..297820e37 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -21,7 +21,7 @@ import { LinkManager } from '../util/LinkManager';
 import { SelectionManager } from '../util/SelectionManager';
 import { SharingManager } from '../util/SharingManager';
 import { Transform } from '../util/Transform';
-import { undoBatch, UndoManager } from '../util/UndoManager';
+import { undoable, undoBatch, UndoManager } from '../util/UndoManager';
 import { EditableView } from './EditableView';
 import { FilterPanel } from './FilterPanel';
 import { Colors } from './global/globalEnums';
@@ -538,6 +538,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     className="inputBox-input"
                     type="text"
                     value={value}
+                    readOnly={true}
                     onChange={e => {
                         setter(e.target.value);
                     }}
@@ -656,21 +657,21 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return this.inputBoxDuo(
             'hgt',
             this.shapeHgt,
-            (val: string) => {
+            undoable((val: string) => {
                 if (!isNaN(Number(val))) {
                     this.shapeHgt = val;
                 }
                 return true;
-            },
+            }, 'set height'),
             'H:',
             'wid',
             this.shapeWid,
-            (val: string) => {
+            undoable((val: string) => {
                 if (!isNaN(Number(val))) {
                     this.shapeWid = val;
                 }
                 return true;
-            },
+            }, 'set width'),
             'W:'
         );
     }
@@ -678,21 +679,21 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         return this.inputBoxDuo(
             'Xps',
             this.shapeXps,
-            (val: string) => {
+            undoable((val: string) => {
                 if (val !== '0' && !isNaN(Number(val))) {
                     this.shapeXps = val;
                 }
                 return true;
-            },
+            }, 'set x coord'),
             'X:',
             'Yps',
             this.shapeYps,
-            (val: string) => {
+            undoable((val: string) => {
                 if (val !== '0' && !isNaN(Number(val))) {
                     this.shapeYps = val;
                 }
                 return true;
-            },
+            }, 'set y coord'),
             'Y:'
         );
     }
@@ -867,7 +868,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     regInput = (key: string, value: any, setter: (val: string) => {}) => {
         return (
             <div className="inputBox">
-                <input className="inputBox-input" type="text" value={value} onChange={e => setter(e.target.value)} />
+                <input className="inputBox-input" type="text" readOnly={true} value={value} onChange={e => setter(e.target.value)} />
                 <div className="inputBox-button">
                     <div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}>
                         <FontAwesomeIcon icon="caret-up" color="white" size="sm" />
@@ -1228,8 +1229,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         }
     });
 
-    @undoBatch
-    changeFollowBehavior = action((follow: Opt<string>) => this.sourceAnchor && (this.sourceAnchor.followLinkLocation = follow));
+    changeFollowBehavior = undoable((loc: Opt<string>) => this.sourceAnchor && (this.sourceAnchor.followLinkLocation = loc), 'change follow behavior');
 
     @undoBatch
     changeAnimationBehavior = action((behavior: string) => this.sourceAnchor && (this.sourceAnchor.followLinkAnimEffect = behavior));
@@ -1315,6 +1315,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 autoComplete={'off'}
                 id="link_relationship_input"
                 value={StrCast(LinkManager.currentLink?.link_relationship)}
+                readOnly={true}
                 onKeyDown={this.onRelationshipKey}
                 onBlur={this.onSelectOutRelationship}
                 onChange={e => this.handlelinkRelationshipChange(e.currentTarget.value)}
@@ -1332,6 +1333,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 style={{ textAlign: 'left' }}
                 id="link_description_input"
                 value={Field.toString(LinkManager.currentLink?.link_description as any as Field)}
+                readOnly={true}
                 onKeyDown={this.onDescriptionKey}
                 onBlur={this.onSelectOutDesc}
                 onChange={e => this.handleDescriptionChange(e.currentTarget.value)}
@@ -1457,7 +1459,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                             <select style={{ width: '100%', gridColumn: 2 }} onChange={e => this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}>
                                                 <option value="default">Default</option>
                                                 {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
-                                                    <option value={effect.toString()}>{effect.toString()}</option>
+                                                    <option key={effect.toString()} value={effect.toString()}>
+                                                        {effect.toString()}
+                                                    </option>
                                                 ))}
                                             </select>
                                             <div className="effectDirection" style={{ marginLeft: '10px', display: 'grid', width: 40, height: 36, gridColumn: 3, gridTemplateRows: '12px 12px 12px' }}>
@@ -1567,7 +1571,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                         <div className="propertiesView-input inline" style={{ display: 'grid', gridTemplateColumns: '78px calc(100% - 108px) 50px' }}>
                                             <p>Zoom %</p>
                                             <div className="ribbon-property" style={{ display: !targZoom ? 'none' : 'inline-flex' }}>
-                                                <input className="presBox-input" style={{ width: '100%' }} type="number" value={zoom} />
+                                                <input className="presBox-input" style={{ width: '100%' }} readOnly={true} type="number" value={zoom} />
                                                 <div className="ribbon-propertyUpDown" style={{ display: 'flex', flexDirection: 'column' }}>
                                                     <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
                                                         <FontAwesomeIcon icon={'caret-up'} />
diff --git a/src/client/views/SidebarAnnos.scss b/src/client/views/SidebarAnnos.scss
index a0506cb3a..d7de2b641 100644
--- a/src/client/views/SidebarAnnos.scss
+++ b/src/client/views/SidebarAnnos.scss
@@ -4,22 +4,26 @@
     overflow: auto;
     flex-flow: row;
     flex-wrap: wrap;
-    .sidebarAnnos-filterTag, .sidebarAnnos-filterTag-active,
-    .sidebarAnnos-filterUser, .sidebarAnnos-filterUser-active {
+    .sidebarAnnos-filterTag,
+    .sidebarAnnos-filterTag-active,
+    .sidebarAnnos-filterUser,
+    .sidebarAnnos-filterUser-active {
         font-weight: bold;
         font-size: 10px;
         padding-left: 5;
         padding-right: 5;
         box-shadow: black 1px 1px 3px;
         border-radius: 5;
-        margin: 2; 
+        margin: 2;
         height: 15;
         background-color: lightgrey;
     }
-    .sidebarAnnos-filterUser, .sidebarAnnos-filterUser-active {
+    .sidebarAnnos-filterUser,
+    .sidebarAnnos-filterUser-active {
         border-radius: 15px;
     }
+    .sidebarAnnos-filterUser-active,
     .sidebarAnnos-filterTag-active {
         background-color: white;
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index e12621f35..c9e52a1db 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -49,13 +49,21 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         );
         return keys;
     }
+    @computed get allHashtags() {
+        const keys = new Set<string>();
+        DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc => StrListCast(doc.tags).forEach(tag => keys.add(tag)));
+        return Array.from(keys.keys())
+            .filter(key => key[0])
+            .filter(key => !key.startsWith('_') && (key[0] === '#' || key[0] === key[0].toUpperCase()))
+            .sort();
+    }
     @computed get allUsers() {
         const keys = new Set<string>();
         DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc => keys.add(StrCast(doc.author)));
         return Array.from(keys.keys()).sort();
     }
     get filtersKey() {
-        return '_' + this.sidebarKey + '-docFilters';
+        return '_' + this.sidebarKey + '_docFilters';
     }
 
     anchorMenuClick = (anchor: Doc) => {
@@ -179,9 +187,9 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     };
     render() {
         const renderTag = (tag: string) => {
-            const active = StrListCast(this.props.rootDoc[this.filtersKey]).includes(`${tag}:${tag}:check`);
+            const active = StrListCast(this.props.rootDoc[this.filtersKey]).includes(`tags:${tag}:check`);
             return (
-                <div key={tag} className={`sidebarAnnos-filterTag${active ? '-active' : ''}`} onClick={e => Doc.setDocFilter(this.props.rootDoc, tag, tag, 'check', true, this.sidebarKey, e.shiftKey)}>
+                <div key={tag} className={`sidebarAnnos-filterTag${active ? '-active' : ''}`} onClick={e => Doc.setDocFilter(this.props.rootDoc, 'tags', tag, 'check', true, this.sidebarKey, e.shiftKey)}>
                     {tag}
                 </div>
             );
@@ -216,6 +224,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                 }}>
                 <div className="sidebarAnnos-tagList" style={{ height: this.filtersHeight() }} onWheel={e => e.stopPropagation()}>
                     {this.allUsers.map(renderUsers)}
+                    {this.allHashtags.map(renderTag)}
                     {Array.from(this.allMetadata.keys())
                         .sort()
                         .map(key => renderMeta(key, this.allMetadata.get(key)))}
diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx
new file mode 100644
index 000000000..01e184d6b
--- /dev/null
+++ b/src/client/views/UndoStack.tsx
@@ -0,0 +1,30 @@
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { UndoManager } from '../util/UndoManager';
+import './ScriptingRepl.scss';
+
+@observer
+export class UndoStack extends React.Component {
+    render() {
+        return (
+            <div className="scriptingRepl-outerContainer">
+                <div className="scriptingRepl-commandsContainer" ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })} style={{ background: UndoManager.batchCounter.get() ? 'yellow' : undefined }}>
+                    {UndoManager.undoStackNames.map((name, i) => (
+                        <div className="scriptingRepl-resultContainer" key={i}>
+                            <div className="scriptingRepl-commandString">{name.replace(/[^\.]*\./, '')}</div>
+                        </div>
+                    ))}
+                    {Array.from(UndoManager.redoStackNames)
+                        .reverse()
+                        .map((name, i) => (
+                            <div className="scriptingRepl-resultContainer" key={i}>
+                                <div className="scriptingRepl-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
+                                    {name.replace(/[^\.]*\./, '')}
+                                </div>
+                            </div>
+                        ))}
+                </div>
+            </div>
+        );
+    }
+}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index cce21a3aa..4ae24af60 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -6,7 +6,7 @@ import { Doc, DocListCast, Opt } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
-import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types';
+import { ImageCast, NumCast, StrCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { inheritParentAcls } from '../../../fields/util';
 import { emptyFunction, incrementTitleCopy } from '../../../Utils';
@@ -20,14 +20,14 @@ import { SelectionManager } from '../../util/SelectionManager';
 import { undoBatch, UndoManager } from '../../util/UndoManager';
 import { DashboardView } from '../DashboardView';
 import { LightboxView } from '../LightboxView';
+import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
+import { OverlayView } from '../OverlayView';
+import { ScriptingRepl } from '../ScriptingRepl';
 import './CollectionDockingView.scss';
 import { CollectionFreeFormView } from './collectionFreeForm';
 import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
 import { TabDocView } from './TabDocView';
 import React = require('react');
-import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
-import { OverlayView } from '../OverlayView';
-import { ScriptingRepl } from '../ScriptingRepl';
 const _global = (window /* browser */ || global) /* node */ as any;
 
 @observer
@@ -85,6 +85,7 @@ export class CollectionDockingView extends CollectionSubView() {
 
     tabItemDropped = () => DragManager.CompleteWindowDrag?.(false);
     tabDragStart = (proxy: any, finishDrag?: (aborted: boolean) => void) => {
+        this._flush = this._flush ?? UndoManager.StartBatch('tab move');
         const dashDoc = proxy?._contentItem?.tab?.DashDoc as Doc;
         dashDoc && (DragManager.DocDragData = new DragManager.DocumentDragData([proxy._contentItem.tab.DashDoc]));
         DragManager.CompleteWindowDrag = (aborted: boolean) => {
@@ -92,12 +93,12 @@ export class CollectionDockingView extends CollectionSubView() {
                 proxy._dragListener.AbortDrag();
                 if (this._flush) {
                     this._flush.cancel(); // cancel the undo change being logged
-                    this._flush = undefined;
                     this.setupGoldenLayout(); // restore golden layout to where it was before the drag (this is a no-op when using StartOtherDrag because the proxy dragged item was never in the golden layout)
                 }
                 DragManager.CompleteWindowDrag = undefined;
             }
             finishDrag?.(aborted);
+            setTimeout(this.endUndoBatch, 100);
         };
     };
     @undoBatch
@@ -180,7 +181,6 @@ export class CollectionDockingView extends CollectionSubView() {
     //
     //  Creates a split on any side of the docking view based on the passed input pullSide and then adds the Document to the requested side
     //
-    @undoBatch
     @action
     public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) {
         if (document?._type_collection === CollectionViewType.Docking) return DashboardView.openDashboard(document);
@@ -195,6 +195,8 @@ export class CollectionDockingView extends CollectionSubView() {
         if (!instance) return false;
         const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName, undefined, keyValue);
 
+        CollectionDockingView.Instance._flush = CollectionDockingView.Instance._flush ?? UndoManager.StartBatch('Add Split');
+        setTimeout(CollectionDockingView.Instance.endUndoBatch, 100);
         if (!pullSide && stack) {
             stack.addChild(docContentConfig, undefined);
             setTimeout(() => stack.setActiveContentItem(stack.contentItems[stack.contentItems.length - 1]));
@@ -370,16 +372,30 @@ export class CollectionDockingView extends CollectionSubView() {
         !LightboxView.LightboxDoc && cur && this._goldenLayout?.updateSize(cur.getBoundingClientRect().width, cur.getBoundingClientRect().height);
     };
 
+    endUndoBatch = () => {
+        const json = JSON.stringify(this._goldenLayout.toConfig());
+        const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g);
+        const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', ''));
+        const docs = !docids
+            ? []
+            : docids
+                  .map(id => DocServer.GetCachedRefField(id))
+                  .filter(f => f)
+                  .map(f => f as Doc);
+        const changesMade = this.props.Document.dockingConfig !== json;
+        if (changesMade) {
+            this.props.Document.dockingConfig = json;
+            this.props.Document.data = new List<Doc>(docs);
+        }
+        this._flush?.end();
+        this._flush = undefined;
+    };
+
     @action
     onPointerUp = (e: MouseEvent): void => {
         window.removeEventListener('pointerup', this.onPointerUp);
-        const flush = this._flush;
-        this._flush = undefined;
-        if (flush) {
-            DragManager.CompleteWindowDrag = undefined;
-            if (!this.stateChanged()) flush.cancel();
-            else flush.end();
-        }
+        DragManager.CompleteWindowDrag = undefined;
+        setTimeout(this.endUndoBatch, 100);
     };
 
     @action
@@ -393,10 +409,8 @@ export class CollectionDockingView extends CollectionSubView() {
             window.addEventListener('mouseup', this.onPointerUp);
             if (!htmlTarget.closest('*.lm_content') && (htmlTarget.closest('*.lm_tab') || htmlTarget.closest('*.lm_stack'))) {
                 const className = typeof htmlTarget.className === 'string' ? htmlTarget.className : '';
-                if (!className.includes('lm_close') && !className.includes('lm_maximise')) {
-                    this._flush = UndoManager.StartBatch('golden layout edit');
-                    DocServer.UPDATE_SERVER_CACHE();
-                }
+                if (className.includes('lm_maximise')) this._flush = UndoManager.StartBatch('tab maximize');
+                else if (!className.includes('lm_close')) DocServer.UPDATE_SERVER_CACHE();
             }
         }
         if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
@@ -452,25 +466,12 @@ export class CollectionDockingView extends CollectionSubView() {
     stateChanged = () => {
         this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig());
         const json = JSON.stringify(this._goldenLayout.toConfig());
-        const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g);
-        const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', ''));
-        const docs = !docids
-            ? []
-            : docids
-                  .map(id => DocServer.GetCachedRefField(id))
-                  .filter(f => f)
-                  .map(f => f as Doc);
         const changesMade = this.props.Document.dockingConfig !== json;
-        if (changesMade && !this._flush) {
-            UndoManager.RunInBatch(() => {
-                this.props.Document.dockingConfig = json;
-                this.props.Document.data = new List<Doc>(docs);
-            }, 'state changed');
-        }
         return changesMade;
     };
 
     tabDestroyed = (tab: any) => {
+        this._flush = this._flush ?? UndoManager.StartBatch('tab movement');
         if (tab.DashDoc && ![DocumentType.KVP, DocumentType.PRES].includes(tab.DashDoc?.type)) {
             Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc);
             Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index 63becac1e..2f28ecd00 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -121,7 +121,8 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
 
     @action pointerEntered = () => SnappingManager.GetIsDragging() && (this._background = '#b4b4b4');
     @action pointerLeave = () => (this._background = 'inherit');
-    textCallback = (char: string) => this.addNewTextDoc('-typed text-', false, true);
+    @undoBatch
+    addTextNote = (char: string) => this.addNewTextDoc('-typed text-', false, true);
 
     // addNewTextDoc is called when a user starts typing in a column to create a new node
     @action
@@ -272,7 +273,7 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
                         {!this.props.chromeHidden ? (
                             <div className="collectionNoteTakingView-DocumentButtons" style={{ marginBottom: 10 }}>
                                 <div key={`${heading}-add-document`} className="collectionNoteTakingView-addDocumentButton">
-                                    <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} textCallback={this.textCallback} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
+                                    <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} textCallback={this.addTextNote} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
                                 </div>
                                 <div key={`${this.props.Document[Id]}-addGroup`} className="collectionNoteTakingView-addDocumentButton">
                                     <EditableView {...this.props.editableViewProps()} />
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 6b4c8a3e9..b131d38d8 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -119,7 +119,8 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
         // onClick play scripts
         CollectionStackedTimeline.RangeScript =
             CollectionStackedTimeline.RangeScript ||
-            ScriptField.MakeFunction(`scriptContext.clickAnchor(this, clientX)`, {
+            ScriptField.MakeFunction(`setTimeout(() => scriptContext.clickAnchor(this, clientX))`, {
+                // setTimeout is a hack to run script in its own properly named undo group (instead of being part of the generic onClick)
                 self: Doc.name,
                 scriptContext: 'any',
                 clientX: 'number',
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 243550c0b..6be9cb72d 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -128,7 +128,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
 
     @action pointerEntered = () => SnappingManager.GetIsDragging() && (this._background = '#b4b4b4');
     @action pointerLeave = () => (this._background = 'inherit');
-    textCallback = (char: string) => this.addNewTextDoc('-typed text-', false, true);
+    @undoBatch typedNote = (char: string) => this.addNewTextDoc('-typed text-', false, true);
 
     @action
     addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
@@ -363,7 +363,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                                 <EditableView
                                     GetValue={returnEmptyString}
                                     SetValue={this.addNewTextDoc}
-                                    textCallback={this.textCallback}
+                                    textCallback={this.typedNote}
                                     placeholder={"Type ':' for commands"}
                                     contents={<FontAwesomeIcon icon={'plus'} />}
                                     menuCallback={this.menuCallback}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index bcda13c8b..cfe78afa1 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -5,7 +5,6 @@ import { AclPrivate, Doc, DocListCast, Field, Opt, StrListCast } from '../../../
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
-import { ScriptField } from '../../../fields/ScriptField';
 import { Cast, ScriptCast, StrCast } from '../../../fields/Types';
 import { WebField } from '../../../fields/URLField';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
@@ -65,11 +64,7 @@ export function CollectionSubView<X>(moreProps?: X) {
         // to its children which may be templates.
         // If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey'
         @computed get dataField() {
-            if (this.layoutDoc[this.props.fieldKey]) return this.layoutDoc[this.props.fieldKey];
-            // sets the dataDoc's data field to an empty list if the data field is undefined - prevents issues with addonly
-            // setTimeout changes it outside of the @computed section
-            !this.dataDoc[this.props.fieldKey] && setTimeout(() => !this.dataDoc[this.props.fieldKey] && (this.dataDoc[this.props.fieldKey] = new List<Doc>()));
-            return this.dataDoc[this.props.fieldKey];
+            return this.layoutDoc[this.props.fieldKey];
         }
 
         get childLayoutPairs(): { layout: Doc; data: Doc }[] {
@@ -130,8 +125,9 @@ export function CollectionSubView<X>(moreProps?: X) {
                     const fieldKey = Doc.LayoutFieldKey(d);
                     const annos = !Field.toString(Doc.LayoutField(d) as Field).includes(CollectionView.name);
                     const data = d[annos ? fieldKey + '_annotations' : fieldKey];
-                    if (data !== undefined) {
-                        let subDocs = DocListCast(data);
+                    const side = annos && d[fieldKey + '_sidebar'];
+                    if (data !== undefined || side !== undefined) {
+                        let subDocs = [...DocListCast(data), ...DocListCast(side)];
                         if (subDocs.length > 0) {
                             let newarray: Doc[] = [];
                             notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, childDocFilters, docRangeFilters, d).length);
@@ -142,6 +138,7 @@ export function CollectionSubView<X>(moreProps?: X) {
                                     const annos = !Field.toString(Doc.LayoutField(t) as Field).includes(CollectionView.name);
                                     notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], childDocFilters, docRangeFilters, d).length));
                                     DocListCast(t[annos ? fieldKey + '_annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc));
+                                    annos && DocListCast(t[fieldKey + '_sidebar']).forEach(newdoc => newarray.push(newdoc));
                                 });
                                 subDocs = newarray;
                             }
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 7e88959a4..33fa434e1 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -13,14 +13,13 @@ import { listSpec } from '../../../fields/Schema';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
 import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../../Utils';
 import { DocServer } from '../../DocServer';
-import { DocUtils } from '../../documents/Documents';
 import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager, dropActionType } from '../../util/DragManager';
 import { SelectionManager } from '../../util/SelectionManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
-import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { undoable, UndoManager } from '../../util/UndoManager';
 import { DashboardView } from '../DashboardView';
 import { Colors, Shadows } from '../global/globalEnums';
 import { LightboxView } from '../LightboxView';
@@ -116,15 +115,13 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
             titleEle.size = StrCast(doc.title).length + 3;
             titleEle.value = doc.title;
-            titleEle.onkeydown = (e: KeyboardEvent) => {
-                e.stopPropagation();
-            };
-            titleEle.onchange = undoBatch(
-                action((e: any) => {
+            titleEle.onkeydown = (e: KeyboardEvent) => e.stopPropagation();
+            titleEle.onchange = (e: any) => {
+                undoable(() => {
                     titleEle.size = e.currentTarget.value.length + 3;
                     Doc.GetProto(doc).title = e.currentTarget.value;
-                })
-            );
+                }, 'edit tab title')();
+            };
 
             if (tab.element[0].children[1].children.length === 1) {
                 iconWrap.className = 'lm_iconWrap lm_moreInfo';
@@ -198,7 +195,9 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 action(selected => {
                     if (selected) this._activated = true;
                     const toggle = tab.element[0].children[2].children[0] as HTMLInputElement;
-                    selected && tab.contentItem !== tab.header.parent.getActiveContentItem() && UndoManager.RunInBatch(() => tab.header.parent.setActiveContentItem(tab.contentItem), 'tab switch');
+                    if (selected && tab.contentItem !== tab.header.parent.getActiveContentItem()) {
+                        undoable(() => tab.header.parent.setActiveContentItem(tab.contentItem), 'tab switch')();
+                    }
                     toggle.style.fontWeight = selected ? 'bold' : '';
                     // toggle.style.textTransform = selected ? "uppercase" : "";
                 }),
@@ -234,7 +233,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     public static PinDoc(docs: Doc | Doc[], pinProps: PinProps) {
         const docList = docs instanceof Doc ? [docs] : docs;
 
-        const batch = UndoManager.StartBatch('pinning doc');
+        const batch = UndoManager.StartBatch('Pin doc to pres trail');
         const curPres = Doc.ActivePresentation ?? Doc.MakeCopy(Doc.UserDoc().emptyTrail as Doc, true);
 
         if (!Doc.ActivePresentation) {
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 037148bb9..f56eaee07 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -102,7 +102,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     private _treedropDisposer?: DragManager.DragDropDisposer;
 
     get treeViewOpenIsTransient() {
-        return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsDocDataProto(this.doc);
+        return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsDataProto(this.doc);
     }
     set treeViewOpen(c: boolean) {
         if (this.treeViewOpenIsTransient) this._transientOpenState = c;
@@ -221,7 +221,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         } else {
             // choose an appropriate embedding or make one. --- choose the first embedding that (1) user owns,  (2) has no context field ... otherwise make a new embedding
             const bestEmbedding =
-                docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsDocDataProto(docView.props.Document)
+                docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsDataProto(docView.props.Document)
                     ? docView.props.Document
                     : DocListCast(this.props.document.proto_embeddings).find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail);
             const nextBestEmbedding = DocListCast(this.props.document.proto_embeddings).find(doc => doc.author === Doc.CurrentUserEmail);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 5ac444147..95046661e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -483,7 +483,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         return false;
     }
 
-    @undoBatch
     @action
     updateClusters(_freeform_useClusters: boolean) {
         this.props.Document._freeform_useClusters = _freeform_useClusters;
@@ -534,7 +533,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         }
     }
 
-    @undoBatch
     @action
     updateCluster(doc: Doc) {
         const childLayouts = this.childLayoutPairs.map(pair => pair.layout);
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 47d7801e6..641088675 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -102,7 +102,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         this._lassoPts = [];
     };
 
-    @undoBatch
     @action
     onKeyPress = (e: KeyboardEvent) => {
         //make textbox and add it to this collection
@@ -111,7 +110,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         const [x, y] = this.Transform.transformPoint(this._downX, this._downY);
         if (e.key === '?') {
             cm.setDefaultItem('?', (str: string) => this.props.addDocTab(Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: 'bing', data_useCors: true }), OpenWhere.addRight));
-
             cm.displayMenu(this._downX, this._downY, undefined, true);
             e.stopPropagation();
         } else if (e.key === 'u' && this.props.ungroup) {
@@ -173,7 +171,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             e.stopPropagation();
         } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
             FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this.props.childLayoutString ? e.key : '';
-            FormattedTextBox.LiveTextUndo = UndoManager.StartBatch('live text batch');
+            FormattedTextBox.LiveTextUndo = UndoManager.StartBatch('type new note');
             this.props.addLiveTextDocument(DocUtils.GetNewTextDoc('-typed text-', x, y, 200, 100, this.props.xPadding === 0));
             e.stopPropagation();
         }
@@ -396,6 +394,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         return newCollection;
     });
 
+    @undoBatch
     @action
     pileup = (e: KeyboardEvent | React.PointerEvent | undefined) => {
         const selected = this.marqueeSelect(false);
@@ -508,8 +507,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
     };
 
     @undoBatch
-    @action
-    summary = (e: KeyboardEvent | React.PointerEvent | undefined) => {
+    summary = action((e: KeyboardEvent | React.PointerEvent | undefined) => {
         const selected = this.marqueeSelect(false).map(d => {
             this.props.removeDocument?.(d);
             d.x = NumCast(d.x) - this.Bounds.left;
@@ -534,19 +532,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         this.props.addDocument?.(portal);
         this.props.addLiveTextDocument(summary);
         MarqueeOptionsMenu.Instance.fadeOut(true);
-    };
+    });
 
     @action
-    background = (e: KeyboardEvent | React.PointerEvent | undefined) => {
-        const newCollection = this.getCollection([], undefined, undefined);
-        this.props.addDocument?.(newCollection);
-        MarqueeOptionsMenu.Instance.fadeOut(true);
-        this.hideMarquee();
-        setTimeout(() => this.props.selectDocuments([newCollection]));
-    };
-
-    @undoBatch
-    marqueeCommand = action((e: KeyboardEvent) => {
+    marqueeCommand = (e: KeyboardEvent) => {
         if (this._commandExecuted || (e as any).propagationIsStopped) {
             return;
         }
@@ -557,7 +546,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             this.delete(e, e.key === 'h');
             e.stopPropagation();
         }
-        if ('cbtsSpg'.indexOf(e.key) !== -1) {
+        if ('ctsSpg'.indexOf(e.key) !== -1) {
             this._commandExecuted = true;
             e.stopPropagation();
             e.preventDefault();
@@ -565,7 +554,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             if (e.key === 'g') this.collection(e, true);
             if (e.key === 'c' || e.key === 't') this.collection(e);
             if (e.key === 's' || e.key === 'S') this.summary(e);
-            if (e.key === 'b') this.background(e);
             if (e.key === 'p') this.pileup(e);
             this.cleanupInteractions(false);
         }
@@ -575,7 +563,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             e.preventDefault();
             this._lassoFreehand = !this._lassoFreehand;
         }
-    });
+    };
 
     touchesLine(r1: { left: number; top: number; width: number; height: number }) {
         for (const lassoPt of this._lassoPts) {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index bcc2ca129..2a68f9b58 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -13,7 +13,7 @@ import { Docs, DocumentOptions, DocUtils, FInfo } from '../../../documents/Docum
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
-import { undoBatch } from '../../../util/UndoManager';
+import { undoable, undoBatch } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
 import { EditableView } from '../../EditableView';
 import { Colors } from '../../global/globalEnums';
@@ -25,6 +25,8 @@ import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
+import { faHeartPulse } from '@fortawesome/free-solid-svg-icons';
+import { faGalacticSenate } from '@fortawesome/free-brands-svg-icons';
 
 export enum ColumnType {
     Number,
@@ -224,7 +226,7 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @undoBatch
     @action
-    setSort = (field: string | undefined, desc: boolean = false) => {
+    setColumnSort = (field: string | undefined, desc: boolean = false) => {
         this.layoutDoc.sortField = field;
         this.layoutDoc.sortDesc = desc;
     };
@@ -484,24 +486,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         return false;
     };
 
-    @action
-    addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
-        if (!value && !forceEmptyNote) return false;
-        const newDoc = Docs.Create.TextDocument(value, { title: value, _layout_autoHeight: true });
-        FormattedTextBox.SelectOnLoad = newDoc[Id];
-        FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' ';
-        return this.addRow(newDoc) || false;
-    };
-
     menuCallback = (x: number, y: number) => {
         ContextMenu.Instance.clearItems();
 
-        DocUtils.addDocumentCreatorMenuItems(doc => this.addRow(doc), this.addRow, x, y, true);
+        DocUtils.addDocumentCreatorMenuItems(this.addRow, this.addRow, x, y, true);
 
-        ContextMenu.Instance.setDefaultItem('::', (name: string): void => {
-            Doc.GetProto(this.props.Document)[name] = '';
-            this.addRow(Docs.Create.TextDocument('', { title: name, _layout_autoHeight: true }));
-        });
         ContextMenu.Instance.displayMenu(x, y, undefined, true);
     };
 
@@ -866,7 +855,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 columnWidths={this.displayColumnWidths}
                                 sortField={this.sortField}
                                 sortDesc={this.sortDesc}
-                                setSort={this.setSort}
+                                setSort={this.setColumnSort}
                                 rowHeight={this.rowHeightFunc}
                                 removeColumn={this.removeColumn}
                                 resizeColumn={this.startResize}
@@ -879,7 +868,14 @@ export class CollectionSchemaView extends CollectionSubView() {
                     {this._columnMenuIndex !== undefined && this.renderColumnMenu}
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
                     <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} rowHeight={this.rowHeightFunc} setRef={(ref: HTMLDivElement | null) => (this._tableContentRef = ref)} />
-                    <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} height={CollectionSchemaView._newNodeInputHeight} />
+                    <EditableView
+                        GetValue={returnEmptyString}
+                        SetValue={undoable(value => (value ? this.addRow(Docs.Create.TextDocument(value, { title: value, _layout_autoHeight: true })) : false), 'add text doc')}
+                        placeholder={"Type ':' for commands"}
+                        contents={'+ New Node'}
+                        menuCallback={this.menuCallback}
+                        height={CollectionSchemaView._newNodeInputHeight}
+                    />
                 </div>
                 {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
                 {this.previewWidth > 0 && (
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 7da3c042c..46c2f622b 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -5,8 +5,6 @@ import { observer } from 'mobx-react';
 import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
 import { Colors } from '../../global/globalEnums';
 import './CollectionSchemaView.scss';
-import { SnappingManager } from '../../../util/SnappingManager';
-import { DragManager } from '../../../util/DragManager';
 
 export interface SchemaColumnHeaderProps {
     columnKeys: string[];
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 45bfe4f77..978b65053 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -7,7 +7,7 @@ import { Doc } from '../../../../fields/Doc';
 import { BoolCast } from '../../../../fields/Types';
 import { DragManager } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
-import { undoBatch } from '../../../util/UndoManager';
+import { undoable, undoBatch } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
 import { OpenWhere } from '../../nodes/DocumentView';
@@ -111,18 +111,18 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     }}>
                     <div
                         className="schema-row-button"
-                        onPointerDown={undoBatch(e => {
+                        onPointerDown={undoable(e => {
                             e.stopPropagation();
                             this.props.removeDocument?.(this.rootDoc);
-                        })}>
+                        }, 'Delete Row')}>
                         <FontAwesomeIcon icon="times" />
                     </div>
                     <div
                         className="schema-row-button"
-                        onPointerDown={e => {
+                        onPointerDown={undoable(e => {
                             e.stopPropagation();
                             this.props.addDocTab(this.rootDoc, OpenWhere.addRight);
-                        }}>
+                        }, 'Open Doc on Right')}>
                         <FontAwesomeIcon icon="external-link-alt" />
                     </div>
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 42bf32475..6d5ef9df6 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -122,7 +122,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                         const ret = KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
                         this.props.finishEdit?.();
                         return ret;
-                    })}
+                    }, 'edit schema cell')}
                 />
             </div>
         );
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index 3f6369898..65d13a6c3 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -49,7 +49,7 @@ export class LinkMenu extends React.Component<Props> {
             <LinkMenuGroup key={group[0]} itemHandler={this.props.itemHandler} docView={this.props.docView} sourceDoc={this.props.docView.props.Document} group={group[1]} groupType={group[0]} clearLinkEditor={this.clear} />
         ));
 
-        return linkItems.length ? linkItems : this.props.style ? [<></>] : [<p key="">No links have been created yet. Drag the linking button onto another document to create a link.</p>];
+        return linkItems.length ? linkItems : this.props.style ? [] : [<p key="none">No links have been created yet. Drag the linking button onto another document to create a link.</p>];
     };
 
     render() {
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 8e83cf121..410e0bbdc 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -447,7 +447,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     timelineScreenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -AudioBox.topControlsHeight);
 
-    setPlayheadTime = (time: number) => (this._ele!.currentTime = this.layoutDoc._layout_currentTimecode = time);
+    setPlayheadTime = (time: number) => (this._ele!.currentTime /*= this.layoutDoc._layout_currentTimecode*/ = time);
 
     playing = () => this.mediaState === media_state.Playing;
 
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index d5ca30957..bd1952ecb 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -9,7 +9,7 @@ import { DocUtils } from '../../documents/Documents';
 import { DragManager } from '../../util/DragManager';
 import { Hypothesis } from '../../util/HypothesisUtils';
 import { LinkManager } from '../../util/LinkManager';
-import { undoBatch, UndoManager } from '../../util/UndoManager';
+import { undoable, undoBatch, UndoManager } from '../../util/UndoManager';
 import './DocumentLinksButton.scss';
 import { DocumentView } from './DocumentView';
 import { LinkDescriptionPopup } from './LinkDescriptionPopup';
@@ -78,7 +78,6 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
         );
     };
 
-    @undoBatch
     onLinkButtonDown = (e: React.PointerEvent): void => {
         setupMoveUpEvents(
             this,
@@ -123,17 +122,14 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             e,
             returnFalse,
             emptyFunction,
-            undoBatch(
-                action(e => {
-                    DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.props.View.props.Document, true, this.props.View);
-                })
-            )
+            action(e => DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.props.View.props.Document, true, this.props.View))
         );
     };
 
-    public static finishLinkClick = undoBatch(
-        action((screenX: number, screenY: number, startLink: Doc, endLink: Doc, startIsAnnotation: boolean, endLinkView?: DocumentView, pinProps?: PinProps) => {
-            if (startLink === endLink) {
+    @undoBatch
+    public static finishLinkClick(screenX: number, screenY: number, startLink: Doc | undefined, endLink: Doc, startIsAnnotation: boolean, endLinkView?: DocumentView, pinProps?: PinProps) {
+        runInAction(() => {
+            if (startLink === endLink || !startLink) {
                 DocumentLinksButton.StartLink = undefined;
                 DocumentLinksButton.StartLinkView = undefined;
                 DocumentLinksButton.AnnotationId = undefined;
@@ -185,8 +181,8 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
                     );
                 }
             }
-        })
-    );
+        });
+    }
 
     @action clearLinks() {
         DocumentLinksButton.StartLink = undefined;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 359b72352..52eee84ac 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -7,6 +7,7 @@ import { AclPrivate, AnimationSym, DataSym, Doc, DocListCast, Field, Opt, StrLis
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
+import { RefField } from '../../../fields/RefField';
 import { listSpec } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
@@ -35,8 +36,11 @@ import { ContextMenuProps } from '../ContextMenuItem';
 import { DocComponent } from '../DocComponent';
 import { EditableView } from '../EditableView';
 import { GestureOverlay } from '../GestureOverlay';
+import { InkingStroke } from '../InkingStroke';
 import { LightboxView } from '../LightboxView';
+import { OverlayView } from '../OverlayView';
 import { StyleProp } from '../StyleProvider';
+import { UndoStack } from '../UndoStack';
 import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView';
 import { DocumentContentsView, ObserverJsxParser } from './DocumentContentsView';
 import { DocumentLinksButton } from './DocumentLinksButton';
@@ -47,8 +51,6 @@ import { LinkAnchorBox } from './LinkAnchorBox';
 import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
 import React = require('react');
-import { InkingStroke } from '../InkingStroke';
-import { RefField } from '../../../fields/RefField';
 const { Howl } = require('howler');
 
 interface Window {
@@ -456,27 +458,26 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                         // instead of in the global lightbox
                         const oldFunc = DocumentViewInternal.addDocTabFunc;
                         DocumentViewInternal.addDocTabFunc = this.props.addDocTab;
-                        const res =
-                            this.onClickHandler?.script.run(
-                                {
-                                    this: this.layoutDoc,
-                                    self: this.rootDoc,
-                                    _readOnly_: false,
-                                    scriptContext: this.props.scriptContext,
-                                    documentView: this.props.DocumentView(),
-                                    clientX,
-                                    clientY,
-                                    shiftKey,
-                                    altKey,
-                                    metaKey,
-                                },
-                                console.log
-                            ).result?.select === true
-                                ? this.props.select(false)
-                                : '';
+                        this.onClickHandler?.script.run(
+                            {
+                                this: this.layoutDoc,
+                                self: this.rootDoc,
+                                _readOnly_: false,
+                                scriptContext: this.props.scriptContext,
+                                documentView: this.props.DocumentView(),
+                                clientX,
+                                clientY,
+                                shiftKey,
+                                altKey,
+                                metaKey,
+                            },
+                            console.log
+                        ).result?.select === true
+                            ? this.props.select(false)
+                            : '';
                         DocumentViewInternal.addDocTabFunc = oldFunc;
                     };
-                    clickFunc = () => (this.props.Document.dontUndo ? func() : UndoManager.RunInBatch(func, 'on click'));
+                    clickFunc = () => (this.props.Document.dontUndo ? func() : UndoManager.RunInBatch(func, 'click ' + this.rootDoc.title));
                 } else {
                     // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
                     if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) {
@@ -490,7 +491,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 if ((clickFunc && waitFordblclick !== 'never') || waitFordblclick === 'always') {
                     this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout);
                     this._doubleClickTimeout = setTimeout(this._singleClickFunc, 300);
-                } else {
+                } else if (!DocumentView.LongPress) {
                     this._singleClickFunc();
                     this._singleClickFunc = undefined;
                 }
@@ -502,7 +503,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     @action
     onPointerDown = (e: React.PointerEvent): void => {
-        this._longPressSelector = setTimeout(() => DocumentView.LongPress && this.props.select(false), 1000);
+        this._longPressSelector = setTimeout(() => {
+            if (DocumentView.LongPress) {
+                if (this.rootDoc.dontUndo) {
+                    OverlayView.Instance.addWindow(<UndoStack />, { x: 300, y: 100, width: 200, height: 200, title: 'Undo Stack' });
+                } else {
+                    this.props.select(false);
+                }
+            }
+        }, 1000);
         if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this.props.DocumentView();
 
         this._downX = e.clientX;
@@ -557,7 +566,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         if (this.onPointerUpHandler?.script) {
             this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log);
         } else if (e.button === 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
-            this._doubleTap = Date.now() - this._lastTap < Utils.CLICK_TIME;
+            this._doubleTap = this.rootDoc.defaultDoubleClick !== 'ignore' && Date.now() - this._lastTap < Utils.CLICK_TIME;
             if (!this.props.isSelected(true)) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected
         }
         if (DocumentView.LongPress) e.preventDefault();
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index c6172ee01..450176a49 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -123,7 +123,6 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                                 this._markerTargetDoc = linkTarget;
                                 this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget;
                             }
-                            this._toolTipText = 'link to ' + this._targetDoc?.title;
                             if (LinkDocPreview.LinkInfo?.noPreview || this._linkSrc?.followLinkToggle || this._markerTargetDoc?.type === DocumentType.PRES) this.followLink();
                         }
                     })
@@ -296,7 +295,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                 className="linkDocPreview"
                 ref={this._linkDocRef}
                 onPointerDown={this.followLinkPointerDown}
-                style={{ display: !this._toolTipText ? 'none' : undefined, left: this.props.location[0], top: this.props.location[1], width: this.width() + borders, height: this.height() + borders + (this.props.showHeader ? 37 : 0) }}>
+                style={{ left: this.props.location[0], top: this.props.location[1], width: this.width() + borders, height: this.height() + borders + (this.props.showHeader ? 37 : 0) }}>
                 {this.docPreview}
             </div>
         );
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 57aa852ac..b07cf7e00 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -16,7 +16,7 @@ import { CollectionViewType, DocumentType } from '../../../documents/DocumentTyp
 import { LinkManager } from '../../../util/LinkManager';
 import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
 import { SelectionManager } from '../../../util/SelectionManager';
-import { undoBatch, UndoManager } from '../../../util/UndoManager';
+import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager';
 import { CollectionFreeFormView } from '../../collections/collectionFreeForm';
 import { ContextMenu } from '../../ContextMenu';
 import { DocComponent } from '../../DocComponent';
@@ -129,29 +129,27 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
      * Number button
      */
     @computed get numberSliderButton() {
-        const numScript = ScriptCast(this.rootDoc.script);
-        const setValue = (value: number) => UndoManager.RunInBatch(() => numScript?.script.run({ self: this.rootDoc, value, _readOnly_: false }), 'set num value');
-
+        const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ self: this.rootDoc, value, _readOnly_: value === undefined });
         // Script for checking the outcome of the toggle
-        const checkResult = Number(numScript?.script.run({ self: this.rootDoc, value: 0, _readOnly_: true }).result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3));
-
+        const checkResult = Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3));
         const label = !FontIconBox.GetShowLabels() ? null : <div className="fontIconBox-label">{this.label}</div>;
 
         const dropdown = (
             <div className="menuButton-dropdownBox" onPointerDown={e => e.stopPropagation()}>
                 <input
+                    className="menu-slider"
                     type="range"
                     step="1"
                     min={NumCast(this.rootDoc.numBtnMin, 0)}
                     max={NumCast(this.rootDoc.numBtnMax, 100)}
+                    //readOnly={true}
                     value={checkResult}
-                    className="menu-slider"
-                    onPointerDown={() => (this._batch = UndoManager.StartBatch('presDuration'))}
+                    onPointerDown={() => (this._batch = UndoManager.StartBatch('num slider changing'))}
                     onPointerUp={() => this._batch?.end()}
-                    onChange={e => {
+                    onChange={undoable(e => {
                         e.stopPropagation();
-                        setValue(Number(e.target.value));
-                    }}
+                        numScript(Number(e.target.value));
+                    }, 'set num value')}
                 />
             </div>
         );
@@ -174,20 +172,13 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
      * Number button
      */
     @computed get numberDropdownButton() {
-        const numScript = ScriptCast(this.rootDoc.script);
-        const setValue = (value: number) => UndoManager.RunInBatch(() => numScript?.script.run({ self: this.rootDoc, value, _readOnly_: false }), 'set num value');
-
-        // Script for checking the outcome of the toggle
-        const checkResult = Number(numScript?.script.run({ self: this.rootDoc, value: 0, _readOnly_: true }).result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3));
+        const numScript = (value?: number) => ScriptCast(this.rootDoc.script)?.script.run({ self: this.rootDoc, value, _readOnly_: value === undefined });
 
-        const label = !FontIconBox.GetShowLabels() ? null : <div className="fontIconBox-label">{this.label}</div>;
+        const checkResult = Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3));
 
         const items: number[] = [];
-        for (let i = 0; i < 100; i++) {
-            if (i % 2 === 0) {
-                items.push(i);
-            }
-        }
+        for (let i = 0; i < 100; i += 2) items.push(i);
+
         const list = items.map(value => {
             return (
                 <div
@@ -196,15 +187,15 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                     style={{
                         backgroundColor: value.toString() === checkResult ? Colors.LIGHT_BLUE : undefined,
                     }}
-                    onClick={() => setValue(value)}>
+                    onClick={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)}>
                     {value}
                 </div>
             );
         });
         return (
             <div className="menuButton numBtn list">
-                <div className="button" onClick={action(e => setValue(Number(checkResult) - 1))}>
-                    <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'minus'} />
+                <div className="button" onClick={undoable(e => numScript(Number(checkResult) - 1), `${this.rootDoc.title} decrement value`)}>
+                    <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon="minus" />
                 </div>
                 <div
                     className={`button ${'number'}`}
@@ -217,9 +208,9 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
                         this.noTooltip = this.rootDoc.dropDownOpen;
                         Doc.UnBrushAllDocs();
                     })}>
-                    <input style={{ width: 30 }} className="button-input" type="number" value={checkResult} onChange={undoBatch(action(e => setValue(Number(e.target.value))))} />
+                    <input style={{ width: 30 }} className="button-input" type="number" value={checkResult} readOnly={true} onChange={undoable(e => numScript(Number(e.target.value)), `${this.rootDoc.title} button set value`)} />
                 </div>
-                <div className={`button`} onClick={action(e => setValue(Number(checkResult) + 1))}>
+                <div className={`button`} onClick={undoable(e => numScript(Number(checkResult) + 1), `${this.rootDoc.title} increment value`)}>
                     <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'plus'} />
                 </div>
 
@@ -322,12 +313,12 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
             .map(value => (
                 <div
                     className="list-item"
-                    key={`${value}`}
+                    key={value}
                     style={{
                         fontFamily: script.script.originalScript.startsWith('{ return setFont') ? value : undefined,
                         backgroundColor: value === text ? Colors.LIGHT_BLUE : undefined,
                     }}
-                    onClick={undoBatch(() => script.script.run({ self: this.rootDoc, value }))}>
+                    onClick={undoable(() => script.script.run({ self: this.rootDoc, value }), value)}>
                     {value[0].toUpperCase() + value.slice(1)}
                 </div>
             ));
@@ -640,29 +631,26 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) {
 ScriptingGlobals.add(function showFreeform(attr: 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll', checkResult?: boolean) {
     const selected = SelectionManager.Docs().lastElement();
     // prettier-ignore
-    const map: Map<'grid' | 'snaplines' | 'clusters' | 'arrange'| 'viewAll', { undo: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc) => void;}> = new Map([
+    const map: Map<'grid' | 'snaplines' | 'clusters' | 'arrange'| 'viewAll', { waitForRender?: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc) => void;}> = new Map([
         ['grid', {
-            undo: false,
             checkResult: (doc:Doc) => doc._freeform_backgroundGrid,
             setDoc: (doc:Doc) => doc._freeform_backgroundGrid = !doc._freeform_backgroundGrid,
         }],
         ['snaplines', {
-            undo: false,
             checkResult: (doc:Doc) => doc._freeform_snapLines,
             setDoc: (doc:Doc) => doc._freeform_snapLines = !doc._freeform_snapLines,
         }],
         ['viewAll', {
-            undo: false,
             checkResult: (doc:Doc) => doc._freeform_fitContentsToBox,
             setDoc: (doc:Doc) => doc._freeform_fitContentsToBox = !doc._freeform_fitContentsToBox,
         }],
         ['clusters', {
-            undo: false,
+            waitForRender: true, // flags that undo batch should terminate after a re-render giving the script the chance to fire
             checkResult: (doc:Doc) => doc._freeform_useClusters,
             setDoc: (doc:Doc) => doc._freeform_useClusters = !doc._freeform_useClusters,
         }],
         ['arrange', {
-            undo: true,
+            waitForRender: true, // flags that undo batch should terminate after a re-render giving the script the chance to fire
             checkResult: (doc:Doc) => doc._autoArrange,
             setDoc: (doc:Doc) => doc._autoArrange = !doc._autoArrange,
         }],
@@ -671,7 +659,7 @@ ScriptingGlobals.add(function showFreeform(attr: 'grid' | 'snaplines' | 'cluster
     if (checkResult) {
         return map.get(attr)?.checkResult(selected) ? Colors.MEDIUM_BLUE : 'transparent';
     }
-    const batch = map.get(attr)?.undo ? UndoManager.StartBatch('set feature') : { end: () => {} };
+    const batch = map.get(attr)?.waitForRender ? UndoManager.StartBatch('set freeform attribute') : { end: () => {} };
     SelectionManager.Docs().map(dv => map.get(attr)?.setDoc(dv));
     setTimeout(() => batch.end(), 100);
 });
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 9c06aa7d8..e85835002 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -301,11 +301,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             this._editorView.updateState(state);
 
             const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc;
-            const curText = state.doc.textBetween(0, state.doc.content.size, ' \n');
-            const curTemp = this.layoutDoc.resolvedDataDoc ? Cast(this.layoutDoc[this.fieldKey], RichTextField) : undefined; // the actual text in the text box
-            const curProto = Cast(Cast(dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); // the default text inherited from a prototype
-            const curLayout = this.rootDoc !== this.layoutDoc ? Cast(this.layoutDoc[this.fieldKey], RichTextField, null) : undefined; // the default text stored in a layout template
-            const json = JSON.stringify(state.toJSON());
+            const newText = state.doc.textBetween(0, state.doc.content.size, ' \n');
+            const newJson = JSON.stringify(state.toJSON());
+            const prevData = Cast(this.layoutDoc[this.fieldKey], RichTextField, null); // the actual text in the text box
+            const prevLayoutData = this.rootDoc !== this.layoutDoc ? Cast(this.layoutDoc[this.fieldKey], RichTextField, null) : undefined; // the default text stored in a layout template
+            const protoData = Cast(Cast(dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); // the default text inherited from a prototype
             const effectiveAcl = GetEffectiveAcl(dataDoc);
 
             const removeSelection = (json: string | undefined) => (json?.indexOf('"storedMarks"') === -1 ? json?.replace(/"selection":.*/, '') : json?.replace(/"selection":"\"storedMarks\""/, '"storedMarks"'));
@@ -320,29 +320,25 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 dataDoc.tags = accumTags.length ? new List<string>(Array.from(new Set<string>(accumTags))) : undefined;
 
                 let unchanged = true;
-                if (this._applyingChange !== this.fieldKey && removeSelection(json) !== removeSelection(curProto?.Data)) {
+                if (this._applyingChange !== this.fieldKey && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
                     this._applyingChange = this.fieldKey;
-                    const textChange = curText !== Cast(dataDoc[this.fieldKey], RichTextField)?.Text;
+                    const textChange = newText !== prevData?.Text;
                     textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
-                    if ((!curTemp && !curProto) || curText || json.includes('dash')) {
+                    if ((!prevData && !protoData) || newText || (!newText && !protoData)) {
                         // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
-                        if (removeSelection(json) !== removeSelection(curLayout?.Data)) {
+                        if (removeSelection(newJson) !== removeSelection(prevLayoutData?.Data)) {
                             const numstring = NumCast(dataDoc[this.fieldKey], null);
-                            if (numstring !== undefined) {
-                                dataDoc[this.fieldKey] = Number(curText);
-                            } else {
-                                dataDoc[this.fieldKey] = new RichTextField(json, curText);
-                            }
+                            dataDoc[this.fieldKey] = numstring !== undefined ? Number(newText) : new RichTextField(newJson, newText);
                             dataDoc[this.fieldKey + '_noTemplate'] = true; //(curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited
-                            textChange && ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: curText });
+                            textChange && ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: newText });
                             unchanged = false;
                         }
                     } else {
                         // if we've deleted all the text in a note driven by a template, then restore the template data
                         dataDoc[this.fieldKey] = undefined;
-                        this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((curProto || curTemp).Data)));
+                        this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((protoData || prevData).Data)));
                         dataDoc[this.fieldKey + '_noTemplate'] = undefined; // mark the data field as not being split from any template it might have
-                        ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: curText });
+                        ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: newText });
                         unchanged = false;
                     }
                     this._applyingChange = '';
@@ -667,7 +663,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         this.layoutDoc._width = !preview && this.SidebarShown ? NumCast(this.layoutDoc._width) * 2 : Math.max(20, NumCast(this.layoutDoc._width) * prevWidth);
     };
     sidebarDown = (e: React.PointerEvent) => {
-        const batch = UndoManager.StartBatch('sidebar');
+        const batch = UndoManager.StartBatch('toggle sidebar');
         setupMoveUpEvents(
             this,
             e,
@@ -694,13 +690,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         return false;
     };
 
-    @undoBatch
     deleteAnnotation = (anchor: Doc) => {
+        const batch = UndoManager.StartBatch('delete link');
         LinkManager.Instance.deleteLink(LinkManager.Links(anchor)[0]);
         // const docAnnotations = DocListCast(this.props.dataDoc[this.fieldKey]);
         // this.props.dataDoc[this.fieldKey] = new List<Doc>(docAnnotations.filter(a => a !== this.annoTextRegion));
         // AnchorMenu.Instance.fadeOut(true);
         this.props.select(false);
+        setTimeout(batch.end); // wait for reaction to remove link from document
     };
 
     @undoBatch
@@ -733,17 +730,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 .split(' ')
                 .filter(h => h);
             const anchorDoc = Array.from(hrefs).lastElement().replace(Doc.localServerPath(), '').split('?')[0];
+            const deleteMarkups = undoBatch(() => {
+                const sel = editor.state.selection;
+                editor.dispatch(editor.state.tr.removeMark(sel.from, sel.to, editor.state.schema.marks.linkAnchor));
+            });
             e.persist();
             anchorDoc &&
                 DocServer.GetRefField(anchorDoc).then(
                     action(anchor => {
+                        anchor && SelectionManager.SelectSchemaViewDoc(anchor as Doc);
                         AnchorMenu.Instance.Status = 'annotation';
-                        AnchorMenu.Instance.Delete = () => this.deleteAnnotation(anchor as Doc);
+                        AnchorMenu.Instance.Delete = !anchor && editor.state.selection.empty ? returnFalse : !anchor ? deleteMarkups : () => this.deleteAnnotation(anchor as Doc);
                         AnchorMenu.Instance.Pinned = false;
-                        AnchorMenu.Instance.PinToPres = () => this.pinToPres(anchor as Doc);
-                        AnchorMenu.Instance.MakeTargetToggle = () => this.makeTargetToggle(anchor as Doc);
-                        AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(anchor as Doc);
-                        AnchorMenu.Instance.IsTargetToggler = () => this.isTargetToggler(anchor as Doc);
+                        AnchorMenu.Instance.PinToPres = !anchor ? returnFalse : () => this.pinToPres(anchor as Doc);
+                        AnchorMenu.Instance.MakeTargetToggle = !anchor ? returnFalse : () => this.makeTargetToggle(anchor as Doc);
+                        AnchorMenu.Instance.ShowTargetTrail = !anchor ? returnFalse : () => this.showTargetTrail(anchor as Doc);
+                        AnchorMenu.Instance.IsTargetToggler = !anchor ? returnFalse : () => this.isTargetToggler(anchor as Doc);
                         AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true);
                     })
                 );
@@ -1002,7 +1004,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     anchorDoc ??
                     Docs.Create.TextConfigDocument({
                         //
-                        title: '#' + this._editorView?.state.doc.textBetween(sel.from, sel.to),
+                        title: 'text(' + this._editorView?.state.doc.textBetween(sel.from, sel.to) + ')',
                         annotationOn: this.dataDoc,
                     });
                 const href = targetHref ?? Doc.localServerPath(anchor);
@@ -1480,11 +1482,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         }
 
         const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()));
-        if (selectOnLoad && !this.props.dontRegisterView && !this.props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
+        if (this._editorView && selectOnLoad && !this.props.dontRegisterView && !this.props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
             const selLoadChar = FormattedTextBox.SelectOnLoadChar;
             FormattedTextBox.SelectOnLoad = '';
             this.props.select(false);
-            if (selLoadChar && this._editorView) {
+            if (selLoadChar) {
                 const $from = this._editorView.state.selection.anchor ? this._editorView.state.doc.resolve(this._editorView.state.selection.anchor - 1) : undefined;
                 const mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) });
                 const curMarks = this._editorView.state.storedMarks ?? $from?.marksAcross(this._editorView.state.selection.$head) ?? [];
@@ -1494,10 +1496,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     .insertText(FormattedTextBox.SelectOnLoadChar, this._editorView.state.doc.content.size - 1, this._editorView.state.doc.content.size)
                     .setStoredMarks(storedMarks);
                 this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
-            } else if (this._editorView && curText && !FormattedTextBox.DontSelectInitialText) {
+            } else if (curText && !FormattedTextBox.DontSelectInitialText) {
                 selectAll(this._editorView.state, this._editorView?.dispatch);
-                this.startUndoTypingBatch();
-            } else if (this._editorView) {
+            } else {
                 this._editorView.dispatch(this._editorView.state.tr.addStoredMark(schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })));
             }
         }
@@ -1506,7 +1507,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         if (this._editorView) {
             const tr = this._editorView.state.tr;
             const { from, to } = tr.selection;
-            // for some reason, the selection is sometimes lost in the sidebar view when prosemirror syncs the seledtion with the dom, so reset the selectoin after the document has ben fully instantiated.
+            // for some reason, the selection is sometimes lost in the sidebar view when prosemirror syncs the seledtion with the dom, so reset the selection after the document has ben fully instantiated.
             if (FormattedTextBox.DontSelectInitialText) setTimeout(() => this._editorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(from), tr.doc.resolve(to)))), 250);
             this._editorView.state.storedMarks = [
                 ...(this._editorView.state.storedMarks ?? []),
@@ -1630,7 +1631,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     onFocused = (e: React.FocusEvent): void => {
         //applyDevTools.applyDevTools(this._editorView);
         this.ProseRef?.children[0] === e.nativeEvent.target && this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props);
-        this.startUndoTypingBatch();
+        e.stopPropagation();
     };
 
     onClick = (e: React.MouseEvent): void => {
@@ -1705,13 +1706,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         }
     }
     startUndoTypingBatch() {
-        !this._undoTyping && (this._undoTyping = UndoManager.StartBatch('undoTyping'));
+        !this._undoTyping && (this._undoTyping = UndoManager.StartBatch('text edits on ' + this.rootDoc.title));
     }
     public endUndoTypingBatch() {
-        const wasUndoing = this._undoTyping;
         this._undoTyping?.end();
         this._undoTyping = undefined;
-        return wasUndoing;
     }
 
     @action
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 3d1d11141..3eadc3047 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -1428,6 +1428,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 min={min}
                 max={max}
                 value={value}
+                readOnly={true}
                 style={{ marginLeft: hmargin, marginRight: hmargin, width: `calc(100% - ${2 * (hmargin ?? 0)}px)` }}
                 className={`toolbar-slider ${active ? '' : 'none'}`}
                 onPointerDown={e => {
@@ -1501,7 +1502,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             <div className="ribbon-doubleButton">
                                 <div className="presBox-subheading">Slide Duration</div>
                                 <div className="ribbon-property">
-                                    <input className="presBox-input" type="number" value={duration} onKeyDown={e => e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s
+                                    <input className="presBox-input" type="number" readOnly={true} value={duration} onKeyDown={e => e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s
                                 </div>
                                 <div className="ribbon-propertyUpDown">
                                     <div className="ribbon-propertyUpDownItem" onClick={() => this.updateDurationTime(String(duration), 1000)}>
@@ -1654,7 +1655,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Zoom ? 'inline-flex' : 'none' }}>
                             <div className="presBox-subheading">Zoom (% screen filled)</div>
                             <div className="ribbon-property">
-                                <input className="presBox-input" type="number" value={zoom} onChange={e => this.updateZoom(e.target.value)} />%
+                                <input className="presBox-input" type="number" readOnly={true} value={zoom} onChange={e => this.updateZoom(e.target.value)} />%
                             </div>
                             <div className="ribbon-propertyUpDown">
                                 <div className="ribbon-propertyUpDownItem" onClick={() => this.updateZoom(String(zoom), 0.1)}>
@@ -1669,7 +1670,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
                             <div className="presBox-subheading">Transition Time</div>
                             <div className="ribbon-property">
-                                <input className="presBox-input" type="number" value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s
+                                <input className="presBox-input" type="number" readOnly={true} value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s
                             </div>
                             <div className="ribbon-propertyUpDown">
                                 <div className="ribbon-propertyUpDownItem" onClick={() => this.updateTransitionTime(String(transitionSpeed), 1000)}>
@@ -1756,6 +1757,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                             className="presBox-input"
                                             style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }}
                                             type="number"
+                                            readOnly={true}
                                             value={NumCast(activeItem.presStartTime).toFixed(2)}
                                             onKeyDown={e => e.stopPropagation()}
                                             onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
@@ -1782,6 +1784,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                             onKeyDown={e => e.stopPropagation()}
                                             style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }}
                                             type="number"
+                                            readOnly={true}
                                             value={NumCast(activeItem.presEndTime).toFixed(2)}
                                             onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
                                                 activeItem.presEndTime = Number(e.target.value);
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 4eb6aee25..2279ffe84 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -1,6 +1,6 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@material-ui/core';
-import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
@@ -13,7 +13,7 @@ import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
 import { SettingsManager } from '../../../util/SettingsManager';
 import { Transform } from '../../../util/Transform';
-import { undoBatch } from '../../../util/UndoManager';
+import { undoable, undoBatch } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
 import { EditableView } from '../../EditableView';
 import { Colors } from '../../global/globalEnums';
@@ -263,16 +263,15 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         }
     };
 
-    @undoBatch
-    removeItem = action((e: React.MouseEvent) => {
+    removePresentationItem = undoable((e: React.MouseEvent) => {
         e.stopPropagation();
         if (this.presBox && this.indexInPres < (this.presBoxView?.itemIndex || 0)) {
-            this.presBox.itemIndex = (this.presBoxView?.itemIndex || 0) - 1;
+            runInAction(() => (this.presBox!.itemIndex = (this.presBoxView?.itemIndex || 0) - 1));
         }
         this.props.removeDocument?.(this.rootDoc);
         this.presBoxView?.removeFromSelectedArray(this.rootDoc);
         this.removeAllRecordingInOverlay();
-    });
+    }, 'Remove doc from pres trail');
 
     // set the value/title of the individual pres element
     @undoBatch
@@ -476,7 +475,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         );
         items.push(
             <Tooltip key="trash" title={<div className="dash-tooltip">Remove from presentation</div>}>
-                <div className={'slideButton'} onClick={this.removeItem}>
+                <div className={'slideButton'} onClick={this.removePresentationItem}>
                     <FontAwesomeIcon icon={'trash'} onPointerDown={e => e.stopPropagation()} />
                 </div>
             </Tooltip>
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index d6dddf71a..5480600b0 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -395,22 +395,25 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
             ) : (
                 <>
                     <Tooltip key="trash" title={<div className="dash-tooltip">Remove Link Anchor</div>}>
-                        <button className="antimodeMenu-button" onPointerDown={this.Delete}>
+                        <button className="antimodeMenu-button" style={{ display: this.Delete === returnFalse ? 'none' : undefined }} onPointerDown={this.Delete}>
                             <FontAwesomeIcon icon="trash-alt" size="lg" />
                         </button>
                     </Tooltip>
                     <Tooltip key="Pin" title={<div className="dash-tooltip">Pin to Presentation</div>}>
-                        <button className="antimodeMenu-button" onPointerDown={this.PinToPres}>
+                        <button className="antimodeMenu-button" style={{ display: this.PinToPres === returnFalse ? 'none' : undefined }} onPointerDown={this.PinToPres}>
                             <FontAwesomeIcon icon="map-pin" size="lg" />
                         </button>
                     </Tooltip>
                     <Tooltip key="trail" title={<div className="dash-tooltip">Show Linked Trail</div>}>
-                        <button className="antimodeMenu-button" onPointerDown={this.ShowTargetTrail}>
+                        <button className="antimodeMenu-button" style={{ display: this.ShowTargetTrail === returnFalse ? 'none' : undefined }} onPointerDown={this.ShowTargetTrail}>
                             <FontAwesomeIcon icon="taxi" size="lg" />
                         </button>
                     </Tooltip>
                     <Tooltip key="toggle" title={<div className="dash-tooltip">make target visibility toggle on click</div>}>
-                        <button className="antimodeMenu-button" style={{ color: this.IsTargetToggler() ? 'black' : 'white', backgroundColor: this.IsTargetToggler() ? 'white' : 'black' }} onPointerDown={this.MakeTargetToggle}>
+                        <button
+                            className="antimodeMenu-button"
+                            style={{ display: this.IsTargetToggler === returnFalse ? 'none' : undefined, color: this.IsTargetToggler() ? 'black' : 'white', backgroundColor: this.IsTargetToggler() ? 'white' : 'black' }}
+                            onPointerDown={this.MakeTargetToggle}>
                             <FontAwesomeIcon icon="thumbtack" size="lg" />
                         </button>
                     </Tooltip>
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 1c1b41f73..3479cd20f 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -141,6 +141,8 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
                 const annos = !Field.toString(Doc.LayoutField(d) as Field).includes('CollectionView');
                 const data = d[annos ? fieldKey + '_annotations' : fieldKey];
                 data && newarray.push(...DocListCast(data));
+                const sidebar = d[fieldKey + '_sidebar'];
+                sidebar && newarray.push(...DocListCast(sidebar));
                 func(depth, d);
             });
             docs = newarray;
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 5312da009..d8447deb6 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -236,7 +236,7 @@ export class Doc extends RefField {
         if (
             doc &&
             Doc.MyFileOrphans instanceof Doc &&
-            Doc.IsDocDataProto(doc) &&
+            Doc.IsDataProto(doc) &&
             !Doc.IsSystem(doc) &&
             ![DocumentType.CONFIG, DocumentType.KVP, DocumentType.LINK, DocumentType.LINKANCHOR].includes(doc.type as any) &&
             !doc.isFolder &&
@@ -510,7 +510,7 @@ export namespace Doc {
     export function GetT<T extends Field>(doc: Doc, key: string, ctor: ToConstructor<T>, ignoreProto: boolean = false): FieldResult<T> {
         return Cast(Get(doc, key, ignoreProto), ctor) as FieldResult<T>;
     }
-    export function IsDocDataProto(doc: Doc) {
+    export function IsDataProto(doc: Doc) {
         return GetT(doc, 'isDataDoc', 'boolean', true);
     }
     export function IsBaseProto(doc: Doc) {
@@ -981,7 +981,7 @@ export namespace Doc {
     export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string, retitle = false): Doc {
         const copy = new Doc(copyProtoId, true);
         updateCachedAcls(copy);
-        const exclude = [...Cast(doc.cloneFieldFilter, listSpec('string'), []), 'dragFactory_count', 'cloneFieldFilter'];
+        const exclude = [...StrListCast(doc.cloneFieldFilter), 'dragFactory_count', 'cloneFieldFilter'];
         Object.keys(doc).forEach(key => {
             if (exclude.includes(key)) return;
             const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
@@ -1433,7 +1433,7 @@ export namespace Doc {
     export function setDocFilter(container: Opt<Doc>, key: string, value: any, modifiers: 'remove' | 'match' | 'check' | 'x' | 'exists' | 'unset', toggle?: boolean, fieldPrefix?: string, append: boolean = true) {
         if (!container) return;
         const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'docFilters';
-        const docFilters = Cast(container[filterField], listSpec('string'), []);
+        const docFilters = StrListCast(container[filterField]);
         runInAction(() => {
             for (let i = 0; i < docFilters.length; i++) {
                 const fields = docFilters[i].split(':'); // split key:value:modifier
@@ -1745,6 +1745,16 @@ ScriptingGlobals.add(function undo() {
     SelectionManager.DeselectAll();
     return UndoManager.Undo();
 });
+
+export function ShowUndoStack() {
+    SelectionManager.DeselectAll();
+    var buffer = '';
+    UndoManager.undoStack.forEach((batch, i) => {
+        buffer += 'Batch => ' + UndoManager.undoStackNames[i] + '\n';
+        ///batch.forEach(undo => (buffer += '   ' + undo.prop + '\n'));
+    });
+    alert(buffer);
+}
 ScriptingGlobals.add(function redo() {
     SelectionManager.DeselectAll();
     return UndoManager.Redo();
diff --git a/src/fields/util.ts b/src/fields/util.ts
index f4fd3200c..a2b445d6c 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -65,6 +65,7 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
     if (value instanceof RefField) {
         value = new ProxyField(value);
     }
+
     if (value instanceof ObjectField) {
         if (value[Parent] && value[Parent] !== receiver && !(value instanceof PrefetchProxy)) {
             throw new Error("Can't put the same object in multiple documents at the same time");
@@ -102,20 +103,24 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
             DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue);
         }
         !receiver[Initializing] &&
+            !receiver.dontUndo &&
             (!receiver[UpdatingFromServer] || receiver[ForceServerWrite]) &&
-            UndoManager.AddEvent({
-                redo: () => (receiver[prop] = value),
-                undo: () => {
-                    const wasUpdate = receiver[UpdatingFromServer];
-                    const wasForce = receiver[ForceServerWrite];
-                    receiver[ForceServerWrite] = true; // needed since writes aren't propagated to server if UpdatingFromServerIsSet
-                    receiver[UpdatingFromServer] = true; // needed if the event caused ACL's to change such that the doc is otherwise no longer editable.
-                    receiver[prop] = curValue;
-                    receiver[ForceServerWrite] = wasForce;
-                    receiver[UpdatingFromServer] = wasUpdate;
+            UndoManager.AddEvent(
+                {
+                    redo: () => (receiver[prop] = value),
+                    undo: () => {
+                        const wasUpdate = receiver[UpdatingFromServer];
+                        const wasForce = receiver[ForceServerWrite];
+                        receiver[ForceServerWrite] = true; // needed since writes aren't propagated to server if UpdatingFromServerIsSet
+                        receiver[UpdatingFromServer] = true; // needed if the event caused ACL's to change such that the doc is otherwise no longer editable.
+                        receiver[prop] = curValue;
+                        receiver[ForceServerWrite] = wasForce;
+                        receiver[UpdatingFromServer] = wasUpdate;
+                    },
+                    prop: prop?.toString(),
                 },
-                prop: prop?.toString(),
-            });
+                value
+            );
         return true;
     }
     return false;
@@ -390,6 +395,7 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
                     diff?.op === '$addToSet'
                         ? {
                               redo: () => {
+                                  console.log('redo $add: ' + prop, diff.items); // bcz: uncomment to log undo
                                   receiver[prop].push(...diff.items.map((item: any) => item.value ?? item));
                                   lastValue = ObjectField.MakeCopy(receiver[prop]);
                               },
@@ -406,11 +412,12 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
                                   });
                                   lastValue = ObjectField.MakeCopy(receiver[prop]);
                               }),
-                              prop: '',
+                              prop: 'add ' + diff.items.length + ' items to list',
                           }
                         : diff?.op === '$remFromSet'
                         ? {
                               redo: action(() => {
+                                  console.log('redo $rem: ' + prop, diff.items); // bcz: uncomment to log undo
                                   diff.items.forEach((item: any) => {
                                       const ind = item instanceof SchemaHeaderField ? receiver[prop].findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading) : receiver[prop].indexOf(item.value ?? item);
                                       ind !== -1 && receiver[prop].splice(ind, 1);
@@ -430,10 +437,11 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
                                   });
                                   lastValue = ObjectField.MakeCopy(receiver[prop]);
                               },
-                              prop: '',
+                              prop: 'remove ' + diff.items.length + ' items from list',
                           }
                         : {
                               redo: () => {
+                                  console.log('redo list: ' + prop, receiver[prop]); // bcz: uncomment to log undo
                                   receiver[prop] = ObjectField.MakeCopy(newValue as List<any>);
                                   lastValue = ObjectField.MakeCopy(receiver[prop]);
                               },
@@ -442,7 +450,7 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
                                   receiver[prop] = ObjectField.MakeCopy(prevValue as List<any>);
                                   lastValue = ObjectField.MakeCopy(receiver[prop]);
                               },
-                              prop: '',
+                              prop: 'assign list',
                           }
                 );
         }
-- 
cgit v1.2.3-70-g09d2


From bf16eca7a84adfdf1c5970e7e4793568ee70325d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 13 Jun 2023 22:14:29 -0400
Subject: fixed updating cached docs when opening a backlinks collection. 
 added some FieldInfo types and added 'enumeration' field display in schema
 view.  fixed bug in schema view column sizing.   updated a bunch of standard
 field names to be more consistent.

---
 src/client/documents/Documents.ts                  | 471 +++++++++++----------
 src/client/util/CurrentUserUtils.ts                | 115 ++---
 src/client/util/DocumentManager.ts                 |   2 +-
 src/client/util/DragManager.ts                     |   2 +-
 src/client/util/LinkManager.ts                     |   2 +-
 src/client/util/TrackMovements.ts                  |   3 +-
 src/client/views/DashboardView.tsx                 |   9 +-
 src/client/views/DocComponent.tsx                  |   2 -
 src/client/views/DocumentButtonBar.tsx             |   2 +-
 src/client/views/DocumentDecorations.tsx           |  16 +-
 src/client/views/FilterPanel.tsx                   |  12 +-
 src/client/views/GestureOverlay.tsx                |   8 +-
 src/client/views/LightboxView.tsx                  |  12 +-
 src/client/views/MainView.tsx                      |  20 +-
 src/client/views/MarqueeAnnotator.tsx              |   2 +-
 src/client/views/OverlayView.tsx                   |   4 +-
 src/client/views/Palette.tsx                       |   4 +-
 src/client/views/PropertiesButtons.tsx             |   4 +-
 .../views/PropertiesDocBacklinksSelector.tsx       |   4 +-
 src/client/views/PropertiesView.tsx                |  44 +-
 src/client/views/SidebarAnnos.tsx                  |  12 +-
 src/client/views/StyleProvider.tsx                 |  23 +-
 src/client/views/TemplateMenu.tsx                  |   4 +-
 src/client/views/collections/CollectionMenu.tsx    |  10 +-
 .../views/collections/CollectionNoteTakingView.tsx | 104 ++---
 .../views/collections/CollectionPileView.tsx       |  21 +-
 .../collections/CollectionStackedTimeline.tsx      |  14 +-
 .../views/collections/CollectionStackingView.tsx   |  12 +-
 src/client/views/collections/CollectionSubView.tsx |  29 +-
 .../views/collections/CollectionTimeView.tsx       |  18 +-
 .../views/collections/CollectionTreeView.tsx       |  12 +-
 src/client/views/collections/TabDocView.tsx        |   8 +-
 src/client/views/collections/TreeView.tsx          |  24 +-
 .../CollectionFreeFormLinkView.tsx                 |  16 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  14 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |   2 +-
 .../collectionLinear/CollectionLinearView.tsx      |  18 +-
 .../CollectionMulticolumnView.tsx                  |   4 +-
 .../CollectionMultirowView.tsx                     |   4 +-
 .../collectionSchema/CollectionSchemaView.scss     |   2 +-
 .../collectionSchema/CollectionSchemaView.tsx      |  56 +--
 .../collectionSchema/SchemaColumnHeader.tsx        |   3 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |  10 +-
 .../collectionSchema/SchemaTableCell.tsx           |  55 ++-
 src/client/views/linking/LinkMenuGroup.tsx         |   2 +-
 src/client/views/linking/LinkPopup.tsx             |   4 +-
 .../views/nodes/DataVizBox/components/TableBox.tsx |   2 +-
 src/client/views/nodes/DocumentLinksButton.tsx     |   6 +-
 src/client/views/nodes/DocumentView.tsx            |  43 +-
 src/client/views/nodes/KeyValuePair.tsx            |   4 +-
 src/client/views/nodes/LabelBox.tsx                |   4 +-
 src/client/views/nodes/LinkAnchorBox.tsx           |   4 +-
 src/client/views/nodes/LinkDocPreview.tsx          |   4 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |   8 +-
 src/client/views/nodes/MapBox/MapBox2.tsx          |   8 +-
 src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx |   2 +-
 src/client/views/nodes/PDFBox.tsx                  |   4 +-
 src/client/views/nodes/QueryBox.scss               |   5 -
 src/client/views/nodes/QueryBox.tsx                |  38 --
 src/client/views/nodes/VideoBox.tsx                |   4 +-
 src/client/views/nodes/WebBox.tsx                  |   8 +-
 src/client/views/nodes/button/FontIconBox.tsx      |   2 +-
 .../views/nodes/formattedText/DashDocView.tsx      |   4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  22 +-
 src/client/views/nodes/trails/PresBox.tsx          |  14 +-
 src/client/views/nodes/trails/PresElementBox.tsx   |  10 +-
 src/client/views/pdf/PDFViewer.tsx                 |  10 +-
 src/fields/Doc.ts                                  |  44 +-
 src/fields/documentSchemas.ts                      |  10 +-
 src/fields/util.ts                                 |   8 +-
 src/mobile/AudioUpload.tsx                         |  10 +-
 src/mobile/MobileInterface.tsx                     |   4 +-
 72 files changed, 740 insertions(+), 761 deletions(-)
 delete mode 100644 src/client/views/nodes/QueryBox.scss
 delete mode 100644 src/client/views/nodes/QueryBox.tsx

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index c1abd6e71..a91d5806c 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -110,18 +110,28 @@ class DocInfo extends FInfo {
     }
 }
 class DimInfo extends FInfo {
-    fieldType? = 'DimUnit';
+    fieldType? = 'enumeration';
     values? = [DimUnit.Pixel, DimUnit.Ratio];
-    readOnly = true;
+    readOnly = false;
 }
 class PEInfo extends FInfo {
-    fieldType? = 'pointerEvents';
+    fieldType? = 'enumeration';
     values? = ['all', 'none'];
-    readOnly = true;
+    readOnly = false;
 }
 class DAInfo extends FInfo {
-    fieldType? = 'dropActionType';
+    fieldType? = 'enumeration';
     values? = ['embed', 'copy', 'move', 'same', 'proto', 'none'];
+    readOnly = false;
+}
+class CTypeInfo extends FInfo {
+    fieldType? = 'enumeration';
+    values? = Array.from(Object.keys(CollectionViewType));
+    readOnly = false;
+}
+class DTypeInfo extends FInfo {
+    fieldType? = 'enumeration';
+    values? = Array.from(Object.keys(DocumentType));
     readOnly = true;
 }
 class DateInfo extends FInfo {
@@ -134,272 +144,267 @@ type STRt = StrInfo | string;
 type DOCt = DocInfo | Doc;
 type DIMt = DimInfo | typeof DimUnit.Pixel | typeof DimUnit.Ratio;
 type PEVt = PEInfo | 'none' | 'all';
+type COLLt = CTypeInfo | CollectionViewType;
 type DROPt = DAInfo | dropActionType;
 type DATEt = DateInfo | number;
+type DTYPEt = DTypeInfo | string;
 export class DocumentOptions {
+    // coordinate and dimensions depending on view
     x?: NUMt = new NumInfo('x coordinate of document in a freeform view');
     y?: NUMt = new NumInfo('y coordinage of document in a freeform view');
     z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, [1, 0]);
-    isSystem?: BOOLt = new BoolInfo('is this a system created/owned doc', true);
-    type?: STRt = new StrInfo('type of document', true, Array.from(Object.keys(DocumentType)));
-    title?: string;
-    author_date?: DATEt = new DateInfo('date the document was created', true);
-    _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
-    allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?', true);
-    childDropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto a child of a collection ");
-    targetDropAction?: DROPt = new DAInfo('what should happen to the source document when ??? ');
-    userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
-    color?: STRt = new StrInfo('foreground color data doc');
-    backgroundColor?: STRt = new StrInfo('background color for data doc');
-    _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
-    _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title');
-    _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes');
-    _headerPointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume');
-    _freeform_panX?: NUMt = new NumInfo('horizontal pan location of a freeform view');
-    _freeform_panY?: NUMt = new NumInfo('vertical pan location of a freeform view');
+    _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height");
+    _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
+    lat?: NUMt = new NumInfo('latitude coordinate for map views');
+    lng?: NUMt = new NumInfo('longitude coordinate for map views');
+    _timecodeToShow?: NUMt = new NumInfo('the time that a document should be displayed (e.g., when an annotation shows up as a video plays)');
+    _timecodeToHide?: NUMt = new NumInfo('the time that a document should be hidden');
     _width?: NUMt = new NumInfo('displayed width of a document');
     _height?: NUMt = new NumInfo('displayed height of document');
     data_nativeWidth?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)');
     data_nativeHeight?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)');
+    linearBtnWidth?: NUMt = new NumInfo('unexpanded width of a linear menu button (button "width" changes when it expands)');
     _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)');
     _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)');
     _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers');
     _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers');
-    _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height");
-    _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
+
+    'acl-Public'?: string; // public permissions
+    '_acl-Public'?: string; // public permissions
+    type?: DTYPEt = new DTypeInfo('type of document', true);
+    _type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection
+    title?: STRt = new StrInfo('title of document');
+    caption?: RichTextField;
+    author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable
+    author_date?: DATEt = new DateInfo('date the document was created', true);
+    annotationOn?: DOCt = new DocInfo('document annotated by this document');
+    color?: STRt = new StrInfo('foreground color data doc');
+    hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection');
+    backgroundColor?: STRt = new StrInfo('background color for data doc');
+    opacity?: NUMt = new NumInfo('document opacity');
+    viewTransitionTime?: NUMt = new NumInfo('transition duration for view parameters');
+    dontRegisterView?: BOOLt = new BoolInfo('are views of this document registered so that they can be found when following links, etc');
+    dontUndo?: BOOLt = new BoolInfo('whether button clicks should be undoable (true for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)');
+    _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title');
+    _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes');
+    _headerPointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume');
+    _lockedPosition?: BOOLt = new BoolInfo("lock the x,y coordinates of the document so that it can't be dragged");
+    _lockedTransform?: BOOLt = new BoolInfo('lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed');
+
+    layout?: string | Doc; // default layout string or template document
+    layout_keyValue?: STRt = new StrInfo('layout definition for showing keyValue view of document');
+    layout_explainer?: STRt = new StrInfo('explanation displayed at top of a collection to describe its purpose');
+    layout_headerButton?: DOCt = new DocInfo('the (button) Doc to display at the top of a collection.');
+    layout_disableBrushing?: BOOLt = new BoolInfo('whether to suppress border highlighting');
+    layout_unrendered?: BOOLt = new BoolInfo('denotes an annotation that is not rendered with a DocumentView (e.g, rtf/pdf text selections and links to scroll locations in web/pdf)');
+    layout_hideOpenButton?: BOOLt = new BoolInfo('whether to hide the open full screen button when selected');
+    layout_hideDocumentButtonBar?: BOOLt = new BoolInfo('whether to hide the document decorations lower button bar when selected');
+    layout_hideLinkAnchors?: BOOLt = new BoolInfo('suppresses link anchor dots from being displayed');
+    layout_hideAllLinks?: BOOLt = new BoolInfo('whether all individual blue anchor dots should be hidden');
+    layout_hideResizeHandles?: BOOLt = new BoolInfo('whether to hide the resize handles when selected');
+    layout_hideLinkButton?: BOOLt = new BoolInfo('whether the blue link counter button should be hidden');
+    layout_hideDecorationTitle?: BOOLt = new BoolInfo('whether to suppress the document decortations title when selected');
+    layout_borderRounding?: string;
+    layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow
+    layout_maxAutoHeight?: NUMt = new NumInfo('maximum height for newly created (eg, from pasting) text documents');
+    _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
+    _layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document');
+    _layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video)  value is in seconds');
+    _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
     _layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)');
-    _layoutFitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
-    _contentBounds?: List<number>; // the (forced) bounds of the document to display. format is: [left, top, right, bottom]
-    _lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged
-    _lockedTransform?: boolean; // lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed
-    _followLinkToggle?: boolean; // whether document, when clicked, toggles display of its link target
+    _layout_fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
+    _layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition');
+    _layout_enableAltContentUI?: BOOLt = new BoolInfo('whether to show alternate content button');
     _layout_showTitle?: string; // field name to display in header (:hover is an optional suffix)
-    _layout_altContentUI?: boolean; // whether to show alternate content button
-    _isLightbox?: boolean; // whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target
+    _layout_showSidebar?: BOOLt = new BoolInfo('whether an annotationsidebar should be displayed for text docuemnts');
     _layout_showCaption?: string; // which field to display in the caption area.  leave empty to have no caption
-    _layoutScrollTop?: number; // scroll location for pdfs
-    _noAutoscroll?: boolean; // whether collections autoscroll when this item is dragged
-    _chromeHidden?: boolean; // whether the editing chrome for a document is hidden
-    _searchDoc?: boolean; // is this a search document (used to change UI for search results in schema view)
-    _forceActive?: boolean; // flag to handle pointer events when not selected (or otherwise active)
-    enableDragWhenActive?: boolean; // allow dragging even if document contentts are active (e.g., tree, groups)
-    _stayInCollection?: boolean; // whether the document should remain in its collection when someone tries to drag and drop it elsewhere
-    _raiseWhenDragged?: boolean; // whether a document is brought to front when dragged.
-    _hideContextMenu?: boolean; // whether the context menu can be shown
-    _type_collection?: string; // sub type of a collection
-    type_collection?: string; // sub type of a collection
-    _gridGap?: number; // gap between items in masonry view
-    freeform?: string; // placeholder just so that the key value pane has a divider to render for freeform view data
-    _freeform_scale?: number; // how much a freeform view has been scaled (zoomed)
-    _overflow?: string; // set overflow behavior
-    _xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts
-    _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts
-    _xPadding?: number;
-    _yPadding?: number;
-    _carousel_index?: number; // which item index the carousel viewer is showing
-    _layout_showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts
+
+    _chromeHidden?: BOOLt = new BoolInfo('whether the editing chrome for a document is hidden');
+    _gridGap?: NUMt = new NumInfo('gap between items in masonry view');
+    _xMargin?: NUMt = new NumInfo('gap between left edge of document and start of masonry/stacking layouts');
+    _yMargin?: NUMt = new NumInfo('gap between top edge of dcoument and start of masonry/stacking layouts');
+    _xPadding?: NUMt = new NumInfo('x padding');
+    _yPadding?: NUMt = new NumInfo('y padding');
     _singleLine?: boolean; // whether label box is restricted to one line of text
     _createDocOnCR?: boolean; // whether carriage returns and tabs create new text documents
-    _minFontSize?: number; // minimum font size for labelBoxes
-    _maxFontSize?: number; // maximum font size for labelBoxes
-    _columnWidth?: number;
-    _columnsHideIfEmpty?: boolean; // whether stacking view column headings should be hidden
-    _text_fontSize?: string;
-    _text_fontFamily?: string;
-    _text_fontWeight?: string;
-    _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
-    _layout_curPage?: number; // current page of a PDF or other? paginated document
-    _layout_currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video)  value is in seconds
-    _currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide)
-    _timecodeToShow?: number; // the time that a document should be displayed (e.g., when an annotation shows up as a video plays)
-    _timecodeToHide?: number; // the time that a document should be hidden
-    _timelineLabel?: boolean; // whether the document exists on a timeline
+    _columnWidth?: NUMt = new NumInfo('width of table column');
+    _columnsHideIfEmpty?: BOOLt = new BoolInfo('whether stacking view column headings should be hidden');
     _caption_xMargin?: NUMt = new NumInfo('x margin of caption inside of a carousel collection', true);
     _caption_yMargin?: NUMt = new NumInfo('y margin of caption inside of a carousel collection', true);
     icon_nativeWidth?: NUMt = new NumInfo('native width of icon view', true);
     icon_nativeHeight?: NUMt = new NumInfo('native height of icon view', true);
-    dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
-    openFactoryLocation?: string; // an OpenWhere value to place the factory created document
-    openFactoryAsDelegate?: boolean; //
-    lat?: number;
-    lng?: number;
-    infoWindowOpen?: boolean;
-    author?: string;
-    _layout_fieldKey?: string;
-    fieldValues?: List<any>; // possible field values used by fieldInfos
-    fieldType?: string; // type of afield used by fieldInfos
-    layout_unrendered?: boolean; // denotes an annotation that is not rendered with a DocumentView (e.g, rtf/pdf text selections and links to scroll locations in web/pdf)
-    'acl-Public'?: string; // public permissions
-    '_acl-Public'?: string; // public permissions
-    version?: string; // version identifier for a document
-    label?: string;
-    hidden?: boolean;
-    _hidden?: boolean;
-    pointerEvents?: string; // pointer events that the documentview should have
-    mediaState?: string; // status of audio/video media document: "pendingRecording", "recording", "paused", "playing"
-    recording?: boolean; // whether WebCam is recording or not
-    autoPlayAnchors?: boolean; // whether to play audio/video when an anchor is clicked in a stackedTimeline.
-    dontPlayLinkOnSelect?: boolean; // whether an audio/video should start playing when a link is followed to it.
-    linkSource?: Doc; // the source document for a collection of backlinks
+    _text_fontSize?: string;
+    _text_fontFamily?: string;
+    _text_fontWeight?: string;
+    _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
+
+    infoWindowOpen?: BOOLt = new BoolInfo('whether info window corresponding to pin is open (on MapDocuments)');
+    _carousel_index?: NUMt = new NumInfo('which item index the carousel viewer is showing');
+    _label_minFontSize?: NUMt = new NumInfo('minimum font size for labelBoxes');
+    _label_maxFontSize?: NUMt = new NumInfo('maximum font size for labelBoxes');
+    stroke_width?: NUMt = new NumInfo('width of an ink stroke');
+    icon_label?: STRt = new StrInfo('label to use for a fontIcon doc (otherwise, the title is used)');
+    mediaState?: STRt = new StrInfo('status of audio/video media document: "pendingRecording", "recording", "paused", "playing"');
+    recording?: BOOLt = new BoolInfo('whether WebCam is recording or not');
+    autoPlayAnchors?: BOOLt = new BoolInfo('whether to play audio/video when an anchor is clicked in a stackedTimeline.');
+    dontPlayLinkOnSelect?: BOOLt = new BoolInfo('whether an audio/video should start playing when a link is followed to it.');
     updateContentsScript?: ScriptField; // reactive script invoked when viewing a document that can update contents of a collection (or do anything)
     toolTip?: string; // tooltip to display on hover
     toolType?: string; // type of pen tool
-    expertMode?: boolean; // something available only in expert (not novice) mode
+    expertMode?: BOOLt = new BoolInfo('something available only in expert (not novice) mode');
+
+    contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
     contextMenuFilters?: List<ScriptField>;
     contextMenuScripts?: List<ScriptField>;
     contextMenuLabels?: List<string>;
     contextMenuIcons?: List<string>;
-    defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or deafult (undefined) means open document full screen
-    waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire.  'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
-    dontUndo?: boolean; // whether button clicks should be undoable ( true for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)
-    layout?: string | Doc; // default layout string for a document
-    contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
-    childLimitHeight?: number; // whether to limit the height of collection children.  0 - means  height can be no bigger than width
+    childFilters_boolean?: string;
+    childFilters?: List<string>;
+    childLimitHeight?: NUMt = new NumInfo('whether to limit the height of collection children.  0 - means  height can be no bigger than width');
     childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox layout in tree view)
     childLayoutString?: string; // template string for collection to use to render its children
-    childDocumentsActive?: boolean; // whether child documents are active when parent is document active
-    childDontRegisterViews?: boolean;
-    childHideLinkButton?: boolean; // hide link buttons on all children
+    childDocumentsActive?: BOOLt = new BoolInfo('whether child documents are active when parent is document active');
+    childDontRegisterViews?: BOOLt = new BoolInfo('whether child document views should be registered so that they can be found when following links, etc');
+    childHideLinkButton?: BOOLt = new BoolInfo('hide link buttons on all children');
     childContextMenuFilters?: List<ScriptField>;
     childContextMenuScripts?: List<ScriptField>;
     childContextMenuLabels?: List<string>;
     childContextMenuIcons?: List<string>;
-    followLinkZoom?: boolean; // whether to zoom to the target of a link
-    layout_hideLinkButton?: boolean; // whether the blue link counter button should be hidden
-    disableDocBrushing?: boolean; // whether to suppress border highlighting
-    layout_hideDecorationTitle?: boolean;
-    hideOpenButton?: boolean;
-    layout_hideResizeHandles?: boolean;
-    hideDocumentButtonBar?: boolean;
-    hideAllLinks?: boolean; // whether all individual blue anchor dots should be hidden
-    isTemplateForField?: string; // the field key for which the containing document is a rendering template
-    isTemplateDoc?: boolean;
     targetScriptKey?: string; // where to write a template script (used by collections with click templates which need to target onClick, onDoubleClick, etc)
-    templates?: List<string>;
-    hero?: ImageField; // primary image that best represents a compound document (e.g., for a buxton device document that has multiple images)
-    caption?: RichTextField;
-    opacity?: number;
-    defaultBackgroundColor?: string;
-    _layout_autoMoveAnchors?: boolean; // whether link endpoint should move around the edges of a document to make shortest path to other link endpoint
-    layout_hideLinkAnchors?: boolean; // suppresses link anchor dots from being displayed
-    isFolder?: boolean;
-    lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide)
-    activeFrame?: number; // the active frame of a document in a frame base collection
-    appearFrame?: number; // the frame in which the document appears
-    viewTransitionTime?: number; // transition duration for view parameters
-    presPanX?: number; // panX saved as a view spec
-    presPanY?: number; // panY saved as a view spec
-    presViewScale?: number; // viewScale saved as a view Spec
-    presTransition?: number; //the time taken for the transition TO a document
-    presDuration?: number; //the duration of the slide in presentation view
-    presZoomText?: boolean; // whether text anchors should shown in a larger box when following links to make them stand out
-    borderRounding?: string;
-    boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow
+
+    lastFrame?: NUMt = new NumInfo('the last frame of a frame-based collection (e.g., progressive slide)');
+    activeFrame?: NUMt = new NumInfo('the active frame of a document in a frame base collection');
+    appearFrame?: NUMt = new NumInfo('the frame in which the document appears');
+    _currentFrame?: NUMt = new NumInfo('the current frame of a frame-based collection (e.g., progressive slide)');
+
+    isSystem?: BOOLt = new BoolInfo('is this a system created/owned doc', true);
+    isBaseProto?: BOOLt = new BoolInfo('is doc a base level prototype for data documents as opposed to data documents which are prototypes for layout documents.  base protos are not cloned during a deep');
+    isTemplateForField?: string; // the field key for which the containing document is a rendering template
+    isTemplateDoc?: BOOLt = new BoolInfo('is the document a template for creating other documents');
+    isGroup?: BOOLt = new BoolInfo('should collection use a grouping UI behavior');
+    isFolder?: BOOLt = new BoolInfo('is document a tree view folder');
+    _isTimelineLabel?: BOOLt = new BoolInfo('is document a timeline label');
+    _isLightbox?: BOOLt = new BoolInfo('whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target');
+
+    presPanX?: NUMt = new NumInfo('panX saved as a view spec');
+    presPanY?: NUMt = new NumInfo('panY saved as a view spec');
+    presViewScale?: NUMt = new NumInfo('viewScale saved as a view Spec');
+    presTransition?: NUMt = new NumInfo('the time taken for the transition TO a document');
+    presDuration?: NUMt = new NumInfo('the duration of the slide in presentation view');
+    presZoomText?: BOOLt = new BoolInfo('whether text anchors should shown in a larger box when following links to make them stand out');
+
     data?: any;
-    isBaseProto?: boolean; // this Doc is base level prototype for data documents as opposed to data documents which are prototypes for layout documents.  base protos are not cloned during a deep
-    dontRegisterView?: boolean;
-    lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document.  see PresBox.
+    data_useCors?: BOOLt = new BoolInfo('whether CORS protocol should be used for web page');
     columnHeaders?: List<SchemaHeaderField>; // headers for stacking views
     schemaHeaders?: List<SchemaHeaderField>; // headers for schema view
-    dockingConfig?: string;
-    annotationOn?: Doc;
-    followLinkToggle?: boolean;
-    isGroup?: boolean; // whether a collection should use a grouping UI behavior
-    _removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped.  e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
+    dockingConfig?: STRt = new StrInfo('configuration of golden layout windows (applies only if doc is rendered as a CollectionDockingView)');
+    icon?: string; // icon used by fonticonbox to render button
     noteType?: string;
-    // BACKGROUND GRID
+
+    // freeform properties
     _freeform_backgroundGrid?: boolean;
+    _freeform_scale?: NUMt = new NumInfo('how much a freeform view has been scaled (zoomed)');
+    _freeform_panX?: NUMt = new NumInfo('horizontal pan location of a freeform view');
+    _freeform_panY?: NUMt = new NumInfo('vertical pan location of a freeform view');
+    _freeform_noAutoPan?: BOOLt = new BoolInfo('disables autopanning when this item is dragged');
+    _freeform_noZoom?: BOOLt = new BoolInfo('disables zooming');
 
     //BUTTONS
     buttonText?: string;
-    iconShape?: string; // shapes of the fonticon border
     btnType?: string;
     btnList?: List<string>;
     docColorBtn?: string;
     userColorBtn?: string;
-    canClick?: string;
     script?: ScriptField;
-    numBtnMax?: number;
-    numBtnMin?: number;
+    numBtnMax?: NUMt = new NumInfo('maximum value of a number button');
+    numBtnMin?: NUMt = new NumInfo('minimum value of a number button');
     switchToggle?: boolean;
     badgeValue?: ScriptField;
 
     //LINEAR VIEW
-    linearViewIsExpanded?: boolean; // is linear view expanded
-    linearViewExpandable?: boolean; // can linear view be expanded
-    linearViewToggleButton?: string; // button to open close linear view group
-    linearViewSubMenu?: boolean;
-    linearBtnWidth?: number;
-    flexGap?: number; // Linear view flex gap
+    linearView_IsExpanded?: BOOLt = new BoolInfo('is linear view expanded');
+    linearView_Expandable?: BOOLt = new BoolInfo('can linear view be expanded');
+    linearView_SubMenu?: BOOLt = new BoolInfo('is doc a sub menu of more linear views');
+    flexGap?: NUMt = new NumInfo('Linear view flex gap');
     flexDirection?: 'unset' | 'row' | 'column' | 'row-reverse' | 'column-reverse';
 
-    layout_linkView?: Doc; // view template for a link document
-    layout_keyValue?: string; // view tempalte for key value docs
     link_description?: string; // added for links
     link_relationship?: string; // type of relatinoship a link represents
-    layout_linkDisplay?: boolean; // whether a link line should be dipslayed between the two link anchors
-    layout_linkDisplayArrow?: boolean; // whether to display link's directional arrowhead
+    link_displayLine?: BOOLt = new BoolInfo('whether a link line should be dipslayed between the two link anchors');
+    link_displayArrow?: BOOLt = new BoolInfo("whether to display link's directional arrowhead");
     link_anchor_1?: Doc;
     link_anchor_2?: Doc;
-    link_anchor_1_useLinkSmallAnchor?: boolean; // whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
-    link_anchor_2_useLinkSmallAnchor?: boolean; // whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
-    ignoreClick?: boolean;
+    link_autoMoveAnchors?: BOOLt = new BoolInfo('whether link endpoint should move around the edges of a document to make shortest path to other link endpoint');
+    link_anchor_1_useSmallAnchor?: BOOLt = new BoolInfo('whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)');
+    link_anchor_2_useSmallAnchor?: BOOLt = new BoolInfo('whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)');
+    link_relationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor)
+    link_relationshipSizes?: List<number>; //stores number of links contained in each relationship
+    link_colorList?: List<string>; // colors of links corresponding to specific link relationships
+    followLinkZoom?: BOOLt = new BoolInfo('whether to zoom to the target of a link');
+    followLinkToggle?: BOOLt = new BoolInfo('whether target of link should be toggled on and off when following a link to it');
+    followLinkLocation?: STRt = new StrInfo('where to open link target when following link');
+    followLinkAnimEffect?: STRt = new StrInfo('animation effect triggered on target of link');
+    followLinkAnimDirection?: STRt = new StrInfo('direction modifier for animation effect');
+
+    ignoreClick?: BOOLt = new BoolInfo('whether clicks on document should be ignored');
     onClick?: ScriptField;
     onDoubleClick?: ScriptField;
     onChildClick?: ScriptField; // script given to children of a collection to execute when they are clicked
     onChildDoubleClick?: ScriptField; // script given to children of a collection to execute when they are double clicked
+    defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or deafult (undefined) means open document full screen
+    waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire.  'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
+    dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
+    openFactoryLocation?: string; // an OpenWhere value to place the factory created document
+    openFactoryAsDelegate?: BOOLt = new BoolInfo('create a delegate of the factory');
+    _forceActive?: BOOLt = new BoolInfo('flag to handle pointer events when not selected (or otherwise active)');
+    enableDragWhenActive?: BOOLt = new BoolInfo('allow dragging even if document contentts are active (e.g., tree, groups)');
+    _stayInCollection?: BOOLt = new BoolInfo('whether the document should remain in its collection when someone tries to drag and drop it elsewhere');
+    _raiseWhenDragged?: BOOLt = new BoolInfo('whether a document is brought to front when dragged.');
+    allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?', true);
+    childDropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto a child of a collection ");
+    targetDropAction?: DROPt = new DAInfo('what should happen to the source document when ??? ');
+    _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
+    _removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped.  e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
+    cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
     dropConverter?: ScriptField; // script to run when documents are dropped on this Document.
     dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script
     clickFactory?: Doc; // document to create when clicking on a button with a suitable onClick script
     onDragStart?: ScriptField; //script to execute at start of drag operation --  e.g., when a "creator" button is dragged this script generates a different document to drop
-    cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
-    filterBoolean?: string;
-    data_useCors?: boolean;
-    icon?: string; // icon used by fonticonbox to render button
-    target?: Doc; // available for use in scripts as the primary target document
-    sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script
-    targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script
-    searchFileTypes?: List<string>; // file types allowed in a search query
-    stroke_width?: number;
-    freezeChildren?: string; // whether children are now allowed to be added and or removed from a collection
-    treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view
-    treeViewHideUnrendered?: boolean; // tells tree view not to display documents that have an 'layout_unrendered' tag unless they also have a treeViewFieldKey tag (presBox)
-    treeViewHideHeaderIfTemplate?: boolean; // whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)
-    treeViewHideHeader?: boolean; // whether to hide the header for a document in a tree view
-    treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items.
+    target?: Doc; // available for use in scripts.  used to provide a document parameter to the script (Note, this is a convenience entry since any field could be used for parameterizing a script)
+
+    treeViewHideTitle?: BOOLt = new BoolInfo('whether to hide the top document title of a tree view');
+    treeViewHideUnrendered?: BOOLt = new BoolInfo("tells tree view not to display documents that have an 'layout_unrendered' tag unless they also have a treeViewFieldKey tag (presBox)");
+    treeViewHideHeaderIfTemplate?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)');
+    treeViewHideHeader?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view');
+    treeViewHideHeaderFields?: BOOLt = new BoolInfo('whether to hide the drop down options for tree view items.');
     treeViewChildDoubleClick?: ScriptField; //
-    // Action Button
-    buttonMenu?: boolean; // whether a action button should be displayed
-    buttonMenuDoc?: Doc;
-    explainer?: string;
-
-    treeViewOpenIsTransient?: boolean; // ignores the treeViewOpen Doc flag, allowing a treeViewItem's expand/collapse state to be independent of other views of the same document in the same or any other tree view
-    _treeViewOpen?: boolean; // whether this document is expanded in a tree view  (note: need _ and regular versions since this can be specified for both proto and layout docs)
-    treeViewOpen?: boolean; // whether this document is expanded in a tree view
+    treeViewOpenIsTransient?: BOOLt = new BoolInfo("ignores the treeViewOpen Doc flag, allowing a treeViewItem's expand/collapse state to be independent of other views of the same document in the same or any other tree view");
+    treeViewOpen?: BOOLt = new BoolInfo('whether this document is expanded in a tree view');
     treeViewExpandedView?: string; // which field/thing is displayed when this item is opened in tree view
-    treeViewExpandedViewLock?: boolean; // whether the expanded view can be changed
+    treeViewExpandedViewLock?: BOOLt = new BoolInfo('whether the expanded view can be changed');
     treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked
-    treeViewTruncateTitleWidth?: number;
-    treeViewHasOverlay?: boolean; // whether the treeview has an overlay for freeform annotations
+    treeViewTruncateTitleWidth?: NUMt = new NumInfo('maximum width of a treew view title before truncation');
+    treeViewHasOverlay?: BOOLt = new BoolInfo('whether the treeview has an overlay for freeform annotations');
     treeViewType?: string; // whether treeview is a Slide, file system, or (default) collection hierarchy
-    sidebarColor?: string; // background color of text sidebar
-    sidebarViewType?: string; // collection type of text sidebar
-    docMaxAutoHeight?: number; // maximum height for newly created (eg, from pasting) text documents
+    treeViewFreezeChildren?: STRt = new StrInfo('set (add, remove, add|remove) to disable adding, removing or both from collection');
+
+    sidebar_color?: string; // background color of text sidebar
+    sidebar_collectionType?: string; // collection type of text sidebar
+
     text?: string;
-    textTransform?: string; // is linear view expanded
-    letterSpacing?: string; // is linear view expanded
+    textTransform?: string;
+    letterSpacing?: string;
     iconTemplate?: string; // name of icon template style
-    selectedIndex?: number; // which item in a linear view has been selected using the "thumb doc" ui
+    selectedIndex?: NUMt = new NumInfo("which item in a linear view has been selected using the 'thumb doc' ui");
+
+    fieldValues?: List<any>; // possible values a field can have (used by FieldInfo's only)
+    fieldType?: string; // display type of a field, e.g. string, number, enumeration (used by FieldInfo's only)
+
     clipboard?: Doc;
-    searchQuery?: string; // for quersyBox
-    useLinkSmallAnchor?: boolean; // whether links to this document should use a miniature linkAnchorBox
-    border?: string; //for searchbox
     hoverBackgroundColor?: string; // background color of a label when hovered
-    link_relationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor)
-    link_relationshipSizes?: List<number>; //stores number of links contained in each relationship
-    linkColorList?: List<string>; // colors of links corresponding to specific link relationships
+    userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
 }
 export namespace Docs {
     export let newAccount: boolean = false;
@@ -986,7 +991,7 @@ export namespace Docs {
             I.layout = InkingStroke.LayoutString('stroke');
             I.layout_fitWidth = true;
             I.layout_hideDecorationTitle = true; // don't show title when selected
-            // I.hideOpenButton = true; // don't show open full screen button when selected
+            // I.layout_hideOpenButton = true; // don't show open full screen button when selected
             I.color = color;
             I.fillColor = fillColor;
             I.stroke = new InkField(points);
@@ -1088,7 +1093,12 @@ export namespace Docs {
         }
 
         export function PileDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
-            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _overflow: 'visible', enableDragWhenActive: true, _forceActive: true, _noAutoscroll: true, ...options, _type_collection: CollectionViewType.Pile }, id);
+            return InstanceFromProto(
+                Prototypes.get(DocumentType.COL),
+                new List(documents),
+                { enableDragWhenActive: true, _forceActive: true, _freeform_noZoom: true, _freeform_noAutoPan: true, ...options, _type_collection: CollectionViewType.Pile },
+                id
+            );
         }
 
         export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
@@ -1177,12 +1187,7 @@ export namespace Docs {
         }
 
         export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
-            return InstanceFromProto(
-                Prototypes.get(DocumentType.COL),
-                new List(documents),
-                { freezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, _type_collection: CollectionViewType.Docking, dockingConfig: config },
-                id
-            );
+            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewFreezeChildren: 'remove|add', ...options, _type_collection: CollectionViewType.Docking, dockingConfig: config }, id);
         }
 
         export function DirectoryImportDocument(options: DocumentOptions = {}) {
@@ -1227,18 +1232,18 @@ export namespace Docs {
 export namespace DocUtils {
     /**
      * @param docs
-     * @param docFilters
-     * @param docRangeFilters
+     * @param childFilters
+     * @param childFiltersByRanges
      * @param parentCollection
-     * Given a list of docs and docFilters, @returns the list of Docs that match those filters
+     * Given a list of docs and childFilters, @returns the list of Docs that match those filters
      */
-    export function FilterDocs(childDocs: Doc[], docFilters: string[], docRangeFilters: string[], parentCollection?: Doc) {
-        if (!docFilters?.length && !docRangeFilters?.length) {
+    export function FilterDocs(childDocs: Doc[], childFilters: string[], childFiltersByRanges: string[], parentCollection?: Doc) {
+        if (!childFilters?.length && !childFiltersByRanges?.length) {
             return childDocs.filter(d => !d.cookies); // remove documents that need a cookie if there are no filters to provide one
         }
 
         const filterFacets: { [key: string]: { [value: string]: string } } = {}; // maps each filter key to an object with value=>modifier fields
-        docFilters.forEach(filter => {
+        childFilters.forEach(filter => {
             const fields = filter.split(':');
             const key = fields[0];
             const value = fields[1];
@@ -1249,7 +1254,7 @@ export namespace DocUtils {
             filterFacets[key][value] = modifiers;
         });
 
-        const filteredDocs = docFilters.length
+        const filteredDocs = childFilters.length
             ? childDocs.filter(d => {
                   if (d.z) return true;
                   // if the document needs a cookie but no filter provides the cookie, then the document does not pass the filter
@@ -1293,7 +1298,7 @@ export namespace DocUtils {
                                 return Field.toString(d[facetKey] as Field).includes(value);
                             });
                       // if we're ORing them together, the default return is false, and we return true for a doc if it satisfies any one set of criteria
-                      if (parentCollection?.filterBoolean === 'OR') {
+                      if (parentCollection?.childFilters_boolean === 'OR') {
                           if (satisfiesUnsetsFacets && satisfiesExistsFacets && satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true;
                       }
                       // if we're ANDing them together, the default return is true, and we return false for a doc if it doesn't satisfy any set of criteria
@@ -1301,14 +1306,14 @@ export namespace DocUtils {
                           if (!satisfiesUnsetsFacets || !satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false;
                       }
                   }
-                  return (parentCollection?.currentFilter as Doc)?.filterBoolean === 'OR' ? false : true;
+                  return (parentCollection?.currentFilter as Doc)?.childFilters_boolean === 'OR' ? false : true;
               })
             : childDocs;
         const rangeFilteredDocs = filteredDocs.filter(d => {
-            for (let i = 0; i < docRangeFilters.length; i += 3) {
-                const key = docRangeFilters[i];
-                const min = Number(docRangeFilters[i + 1]);
-                const max = Number(docRangeFilters[i + 2]);
+            for (let i = 0; i < childFiltersByRanges.length; i += 3) {
+                const key = childFiltersByRanges[i];
+                const min = Number(childFiltersByRanges[i + 1]);
+                const max = Number(childFiltersByRanges[i + 2]);
                 const val = typeof d[key] === 'string' ? (Number(StrCast(d[key])).toString() === StrCast(d[key]) ? Number(StrCast(d[key])) : undefined) : Cast(d[key], 'number', null);
                 if (val === undefined) {
                     //console.log("Should 'undefined' pass range filter or not?")
@@ -1325,11 +1330,11 @@ export namespace DocUtils {
         broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1));
         return DocUtils.ActiveRecordings.map(audio => {
             const sourceDoc = getSourceDoc();
-            return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { layout_linkDisplay: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' });
+            return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { link_displayLine: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' });
         });
     }
 
-    export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string; layout_linkDisplay?: boolean }, id?: string, showPopup?: number[]) {
+    export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string; link_displayLine?: boolean }, id?: string, showPopup?: number[]) {
         if (!linkSettings.link_relationship) linkSettings.link_relationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link';
         const sv = DocumentManager.Instance.getDocumentView(source);
         if (target.doc === Doc.UserDoc()) return undefined;
@@ -1370,15 +1375,15 @@ export namespace DocUtils {
                 source,
                 target,
                 {
-                    title: ComputedField.MakeFunction('generateLinkTitle(self)') as any,
-                    link_anchor_1_useLinkSmallAnchor: source.useLinkSmallAnchor ? true : undefined,
-                    link_anchor_2_useLinkSmallAnchor: target.useLinkSmallAnchor ? true : undefined,
                     'acl-Public': SharingPermissions.Augment,
                     '_acl-Public': SharingPermissions.Augment,
-                    layout_linkDisplay: linkSettings.layout_linkDisplay,
+                    title: ComputedField.MakeFunction('generateLinkTitle(self)') as any,
+                    link_anchor_1_useSmallAnchor: source.useSmallAnchor ? true : undefined,
+                    link_anchor_2_useSmallAnchor: target.useSmallAnchor ? true : undefined,
+                    link_displayLine: linkSettings.link_displayLine,
                     link_relationship: linkSettings.link_relationship,
                     link_description: linkSettings.link_description,
-                    _layout_autoMoveAnchors: true,
+                    link_autoMoveAnchors: true,
                     _layout_showCaption: 'link_description',
                     _layout_showTitle: 'link_relationship',
                 },
@@ -1706,14 +1711,14 @@ export namespace DocUtils {
         if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) {
             const pushpin = Docs.Create.FontIconDocument({
                 title: 'pushpin',
-                label: '',
+                icon_label: '',
                 annotationOn: Cast(doc.annotationOn, Doc, null),
                 followLinkToggle: true,
                 icon: 'map-pin',
                 x: Cast(doc.x, 'number', null),
                 y: Cast(doc.y, 'number', null),
                 backgroundColor: '#ACCEF7',
-                hideAllLinks: true,
+                layout_hideAllLinks: true,
                 _width: 15,
                 _height: 15,
                 _xPadding: 0,
@@ -1804,7 +1809,7 @@ export namespace DocUtils {
             _xMargin: noMargins ? 0 : undefined,
             _yMargin: noMargins ? 0 : undefined,
             annotationOn,
-            docMaxAutoHeight: maxHeight,
+            layout_maxAutoHeight: maxHeight,
             backgroundColor,
             _width: width || 200,
             _height: 35,
@@ -1812,7 +1817,7 @@ export namespace DocUtils {
             y: y,
             _layout_fitWidth: true,
             _layout_autoHeight: true,
-            _layout_altContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards),
+            _layout_enableAltContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards),
             title,
         });
         const template = Doc.UserDoc().defaultTextLayout;
@@ -1842,18 +1847,18 @@ export namespace DocUtils {
     }
 
     /**
-     * uploadFilesToDocs will take in an array of Files, and creates documents for the 
-     * new files. 
-     * 
+     * uploadFilesToDocs will take in an array of Files, and creates documents for the
+     * new files.
+     *
      * @param files an array of files that will be uploaded
      * @param options options to use while uploading
-     * @returns 
+     * @returns
      */
     export async function uploadFilesToDocs(files: File[], options: DocumentOptions) {
         const generatedDocuments: Doc[] = [];
 
-        // These files do not have overwriteDocs, so we do not set the guid and let the client generate one. 
-        const fileNoGuidPairs: Networking.FileGuidPair[] = files.map(file => ({file}));
+        // These files do not have overwriteDocs, so we do not set the guid and let the client generate one.
+        const fileNoGuidPairs: Networking.FileGuidPair[] = files.map(file => ({ file }));
 
         const upfiles = await Networking.UploadFilesToServer(fileNoGuidPairs);
         for (const {
@@ -1867,8 +1872,8 @@ export namespace DocUtils {
 
     export function uploadFileToDoc(file: File, options: DocumentOptions, overwriteDoc: Doc) {
         const generatedDocuments: Doc[] = [];
-        // Since this file has an overwriteDoc, we can set the client tracking guid to the overwriteDoc's guid. 
-        Networking.UploadFilesToServer([{file, guid: overwriteDoc[Id]}]).then(upfiles => {
+        // Since this file has an overwriteDoc, we can set the client tracking guid to the overwriteDoc's guid.
+        Networking.UploadFilesToServer([{ file, guid: overwriteDoc[Id] }]).then(upfiles => {
             const {
                 source: { name, type },
                 result,
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 6f6ac2d4a..59041862f 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -23,7 +23,7 @@ import { MainView } from "../views/MainView";
 import { ButtonType } from "../views/nodes/button/FontIconBox";
 import { OpenWhere } from "../views/nodes/DocumentView";
 import { OverlayView } from "../views/OverlayView";
-import { DragManager } from "./DragManager";
+import { DragManager, dropActionType } from "./DragManager";
 import { MakeTemplate } from "./DropConverter";
 import { FollowLinkScript } from "./LinkFollower";
 import { LinkManager } from "./LinkManager";
@@ -97,7 +97,7 @@ export class CurrentUserUtils {
 
         const reqdOpts:DocumentOptions = {
             title: "Experimental Tools", _xMargin: 0, _layout_showTitle: "title", _chromeHidden: true,
-            _stayInCollection: true, _hideContextMenu: true, _forceActive: true, isSystem: true,
+            _stayInCollection: true, _layout_hideContextMenu: true, _forceActive: true, isSystem: true,
             _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
         };
         const reqdScripts = { dropConverter : "convertToButtons(dragData)" };
@@ -136,7 +136,7 @@ export class CurrentUserUtils {
         const reqdClickList = reqdTempOpts.map(opts => {
             const allOpts = {...reqdClickOpts, ...opts.opts};
             const clickDoc = tempClicks ? DocListCast(tempClicks.data).find(doc => doc.title === opts.opts.title): undefined;
-            return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name}), allOpts), true, opts.opts.title);
+            return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name}), allOpts), true, opts.opts.title?.toString());
         });
 
         const reqdOpts:DocumentOptions = {title: "click editor templates", _height:75, isSystem: true};
@@ -192,7 +192,7 @@ export class CurrentUserUtils {
                 {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", });
         };
         const labelBox = (opts: DocumentOptions, data?:string) => Docs.Create.LabelDocument({
-            textTransform: "unset", letterSpacing: "unset", _singleLine: false, _minFontSize: 14, _maxFontSize: 24, borderRounding: "5px",  _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
+            textTransform: "unset", letterSpacing: "unset", _singleLine: false, _label_minFontSize: 14, _label_maxFontSize: 24, layout_borderRounding: "5px",  _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
         });
         const imageBox = (opts: DocumentOptions, url?:string) => Docs.Create.ImageDocument(url ?? "http://www.cs.brown.edu/~bcz/noImage.png", { "icon_nativeWidth": 360 / 4, "icon_nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG,  _width: 360 / 4, _height: 270 / 4,  _layout_showTitle: "title", ...opts });
         const fontBox = (opts:DocumentOptions, data?:string) => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts  });
@@ -260,10 +260,11 @@ export class CurrentUserUtils {
         const emptyThings:{key:string,  // the field name where the empty thing will be stored
                           opts:DocumentOptions,   // the document options that are required for the empty thing
                           funcs?:{[key:string]: any},  // computed fields that are rquired for the empth thing
+                          scripts?:{[key:string]: any},
                           creator:(opts:DocumentOptions)=> any // how to create the empty thing if it doesn't exist
               }[] = [
             {key: "Note",       creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _layout_autoHeight: true }},
-            {key: "Flashcard",  creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _layout_autoHeight: true, _layout_altContentUI: true}},
+            {key: "Flashcard",  creator: opts => Docs.Create.TextDocument("", opts),        opts: { _width: 200, _layout_autoHeight: true, _layout_enableAltContentUI: true}},
             {key: "Equation",   creator: opts => Docs.Create.EquationDocument(opts),        opts: { _width: 300, _height: 35, }},
             {key: "Noteboard",  creator: opts => Docs.Create.NoteTakingDocument([], opts),  opts: { _width: 250, _height: 200, _layout_fitWidth: true}},
             {key: "Simulation", creator: opts => Docs.Create.SimulationDocument(opts),      opts: { _width: 300, _height: 300, }},
@@ -274,11 +275,11 @@ export class CurrentUserUtils {
             {key: "Map",        creator: opts => Docs.Create.MapDocument([], opts),         opts: { _width: 800, _height: 600, _layout_fitWidth: true, _layout_showSidebar: true,  }},
             {key: "Screengrab", creator: Docs.Create.ScreenshotDocument,                    opts: { _width: 400, _height: 200 }},
             {key: "WebCam",     creator: opts => Docs.Create.WebCamDocument("", opts),      opts: { _width: 400, _height: 200, recording:true, isSystem: true, cloneFieldFilter: new List<string>(["isSystem"]) }},
-            {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, onClick: FollowLinkScript()}},
+            {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}},
             {key: "Script",     creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }},
             {key: "DataViz",    creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts),   opts: { _width: 300, _height: 300 }},
             {key: "Header",     creator: headerTemplate,                                    opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeViewHideUnrendered: true}},
-            {key: "Trail",      creator: Docs.Create.PresDocument,                          opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, targetDropAction: "embed" as any, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, boxShadow: "0 0" }},
+            {key: "Trail",      creator: Docs.Create.PresDocument,                          opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, targetDropAction: "embed" as dropActionType, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, layout_boxShadow: "0 0" }},
             {key: "Tab",        creator: opts => Docs.Create.FreeformDocument([], opts),    opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }},
             {key: "Slide",      creator: opts => Docs.Create.TreeDocument([], opts),        opts: { _width: 300, _height: 200, _type_collection: CollectionViewType.Tree, 
                                                                                                 treeViewHasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, 
@@ -287,7 +288,7 @@ export class CurrentUserUtils {
                                                                                             }, funcs: {title: 'self.text?.Text'}},
             ];
 
-        emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, undefined, thing.funcs));
+        emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs));
         
         return [
             { toolTip: "Tap or drag to create a note",            title: "Note", icon: "sticky-note",   dragFactory: doc.emptyNote as Doc,       clickFactory: DocCast(doc.emptyNote)},
@@ -321,7 +322,7 @@ export class CurrentUserUtils {
         const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).map((reqdOpts) => {
             const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined;
             const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["funcs", "scripts", "backgroundColor"]).omit, 
-                _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, 
+                _width: 35, _height: 35, _layout_hideContextMenu: true, _stayInCollection: true, 
                 btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, isSystem: true,
                 _removeDropProperties: new List<string>(["_stayInCollection"]),
                 };
@@ -329,7 +330,7 @@ export class CurrentUserUtils {
         });
 
         const reqdOpts:DocumentOptions = {
-            title: "Basic Item Creators", _layout_showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, isSystem: true,
+            title: "Basic Item Creators", _layout_showTitle: "title", _xMargin: 0, _stayInCollection: true, _layout_hideContextMenu: true, _chromeHidden: true, isSystem: true,
             _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true,
              childDropAction: 'embed' 
         };
@@ -367,14 +368,14 @@ export class CurrentUserUtils {
             const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
             const reqdBtnOpts:DocumentOptions = {
                 title, icon, target, btnType: ButtonType.MenuButton, isSystem: true, dontUndo: true, dontRegisterView: true,
-                _width: 60, _height: 60,  _stayInCollection: true, _hideContextMenu: true,
+                _width: 60, _height: 60,  _stayInCollection: true, _layout_hideContextMenu: true,
                 _removeDropProperties: new List<string>(["_stayInCollection"]),
             };
             return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs);
         });
 
         const reqdStackOpts:DocumentOptions ={
-            title: "menuItemPanel", childDropAction: "same", backgroundColor: Colors.DARK_GRAY, boxShadow: "rgba(0,0,0,0)",  dontRegisterView: true, ignoreClick: true,
+            title: "menuItemPanel", childDropAction: "same", backgroundColor: Colors.DARK_GRAY, layout_boxShadow: "rgba(0,0,0,0)",  dontRegisterView: true, ignoreClick: true,
             _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _layout_autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, isSystem: true,
         };
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdStackOpts, menuBtns, { dropConverter: "convertToButtons(dragData)" });
@@ -413,14 +414,14 @@ export class CurrentUserUtils {
     static mobileButton = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MulticolumnDocument(docs, {
         ...opts,
          _nativeWidth: 900, _nativeHeight: 250, _width: 900, _height: 250, _yMargin: 15,
-        borderRounding: "5px", boxShadow: "0 0", isSystem: true
+        layout_borderRounding: "5px", layout_boxShadow: "0 0", isSystem: true
     }) as any as Doc
 
     // sets up the text container for the information contained within the mobile button
     static mobileTextContainer = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MultirowDocument(docs, {
         ...opts,
         _nativeWidth: 450, _nativeHeight: 250, _width: 450, _height: 250, _yMargin: 25,
-        backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", ignoreClick: true, isSystem: true
+        backgroundColor: "rgba(0,0,0,0)", layout_borderRounding: "0", layout_boxShadow: "0 0", ignoreClick: true, isSystem: true
     }) as any as Doc
 
     // Sets up the title of the button
@@ -458,7 +459,7 @@ export class CurrentUserUtils {
     static setupSearcher(doc: Doc, field:string) {
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.SearchDocument(opts), {
                 dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", isSystem: true, childDropAction: "embed", 
-                _lockedPosition: true, _type_collection: CollectionViewType.Schema, _searchDoc: true,  });
+                _lockedPosition: true, _type_collection: CollectionViewType.Schema  });
     }
 
     /// Initializes the panel of draggable tools that is opened from the left sidebar.
@@ -467,8 +468,8 @@ export class CurrentUserUtils {
         const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, DocListCast(myTools?.data)?.length ? DocListCast(myTools.data)[0]:undefined);
         const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc,DocListCast(myTools?.data)?.length > 1 ? DocListCast(myTools.data)[1]:undefined);
         const reqdToolOps:DocumentOptions = {
-            title: "My Tools", isSystem: true, ignoreClick: true, boxShadow: "0 0",
-            _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, 
+            title: "My Tools", isSystem: true, ignoreClick: true, layout_boxShadow: "0 0",
+            _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, _chromeHidden: true, 
         };
         return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdToolOps, [creatorBtns, templateBtns]);
     }
@@ -480,10 +481,10 @@ export class CurrentUserUtils {
         const toggleDarkTheme = `this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`;
         const newDashboard = `createNewDashboard()`;
 
-        const reqdBtnOpts:DocumentOptions = { _forceActive: true,  _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true,
+        const reqdBtnOpts:DocumentOptions = { _forceActive: true,  _width: 30, _height: 30, _stayInCollection: true, _layout_hideContextMenu: true,
              title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", isSystem: true };
         const reqdBtnScript = {onClick: newDashboard,}
-        const newDashboardButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myDashboards?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
+        const newDashboardButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myDashboards?.layout_headerButton), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
        
         const contextMenuScripts = [/*newDashboard*/] as string[];
         const contextMenuLabels = [/*"Create New Dashboard"*/]  as string[];
@@ -493,15 +494,15 @@ export class CurrentUserUtils {
         const childContextMenuLabels =  ["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard", "Reset Dashboard"];// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters
         const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters
         const reqdOpts:DocumentOptions = {
-            title: "My Dashboards", childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, boxShadow: "0 0", childDontRegisterViews: true,
+            title: "My Dashboards", childHideLinkButton: true, treeViewFreezeChildren: "remove|add", treeViewHideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true,
             targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true,  treeViewTruncateTitleWidth: 350, ignoreClick: true, 
-            buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "embed",
+            layout_headerButton: newDashboardButton, childDropAction: "embed",
             _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
             contextMenuLabels:new List<string>(contextMenuLabels),
             contextMenuIcons:new List<string>(contextMenuIcons),
             childContextMenuLabels:new List<string>(childContextMenuLabels),
             childContextMenuIcons:new List<string>(childContextMenuIcons),
-            explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files."
+            layout_explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files."
         };
         myDashboards = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), reqdOpts);
         if (Cast(myDashboards.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) {
@@ -523,19 +524,19 @@ export class CurrentUserUtils {
         
         const newFolder = `TreeView_addNewFolder()`;
         const newFolderOpts: DocumentOptions = {
-            _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _width: 30, _height: 30,
+            _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, _width: 30, _height: 30,
             title: "New folder", btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true
         };
         const newFolderScript = { onClick: newFolder};
-        const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.buttonMenuDoc), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
+        const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
         
         const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, 
-            title: "My Documents", buttonMenu: true, buttonMenuDoc: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", isSystem: true,
-            isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, boxShadow: "0 0", childDontRegisterViews: true, 
+            title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", isSystem: true,
+            isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, 
             treeViewTruncateTitleWidth: 350, ignoreClick: true, childDropAction: "embed",
             childContextMenuLabels: new List<string>(["Create new folder"]),
             childContextMenuIcons: new List<string>(["plus"]),
-            explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
+            layout_explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
         };
         myFilesystem = DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, [myFileOrphans]);
         const childContextMenuScripts = [newFolder];
@@ -548,21 +549,21 @@ export class CurrentUserUtils {
     /// initializes the panel displaying docs that have been recently closed
     static setupRecentlyClosed(doc: Doc, field:string) {
         const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, 
-            title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "embed", isSystem: true,
-            treeViewTruncateTitleWidth: 350, ignoreClick: true,  boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same",
+            title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "embed", isSystem: true,
+            treeViewTruncateTitleWidth: 350, ignoreClick: true,  layout_boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same",
             contextMenuLabels: new List<string>(["Empty recently closed"]),
             contextMenuIcons:new List<string>(["trash"]),
-            explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list."
+            layout_explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list."
         };
         const recentlyClosed = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), reqdOpts);
 
         const clearAll = (target:string) => `getProto(${target}).data = new List([])`;
-        const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, 
+        const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _stayInCollection: true, _layout_hideContextMenu: true, 
             title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton,  buttonText: "Empty", icon: "trash", isSystem: true,
             toolTip: "Empty recently closed",};
-        const clearDocsButton = DocUtils.AssignDocField(recentlyClosed, "clearDocsBtn", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
+        DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
 
-        if (recentlyClosed.buttonMenuDoc !== clearDocsButton) Doc.GetProto(recentlyClosed).buttonMenuDoc = clearDocsButton;
+        //if (recentlyClosed.layout_headerButton !== clearDocsButton) Doc.GetProto(recentlyClosed).layout_headerButton = clearDocsButton;
         
         if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) {
             recentlyClosed.contextMenuScripts = new List<ScriptField>([ScriptField.MakeScript(clearAll("self"))!])
@@ -574,7 +575,7 @@ export class CurrentUserUtils {
     static setupUserDocView(doc: Doc, field:string) {
         const reqdOpts:DocumentOptions = {
             _lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view",
-            boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, isSystem: true,
+            layout_boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, isSystem: true,
             treeViewHideTitle: true, treeViewTruncateTitleWidth: 350
         };
         if (!doc[field]) DocUtils.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" });
@@ -582,14 +583,14 @@ export class CurrentUserUtils {
     }
 
     static linearButtonList = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.LinearDocument(docs, {
-        ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, boxShadow: "0 0", _forceActive: true,
+        ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, layout_boxShadow: "0 0", _forceActive: true,
         dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
         _lockedPosition: true, isSystem: true, flexDirection: "row"
     })
 
     static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({
-        btnType: ButtonType.ToolButton, _forceActive: true, _hideContextMenu: true, 
-        _removeDropProperties: new List<string>([ "_hideContextMenu", "stayInCollection"]), 
+        btnType: ButtonType.ToolButton, _forceActive: true, _layout_hideContextMenu: true, 
+        _removeDropProperties: new List<string>([ "_layout_hideContextMenu", "stayInCollection"]), 
         _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, isSystem: true, ...opts,
     })
 
@@ -609,8 +610,8 @@ export class CurrentUserUtils {
         ];
         const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts));
         const dockBtnsReqdOpts:DocumentOptions = {
-            title: "docked buttons", _height: 40, flexGap: 0, boxShadow: "standard", childDropAction: 'embed',
-            childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true
+            title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDropAction: 'embed',
+            childDontRegisterViews: true, linearView_IsExpanded: true, linearView_Expandable: true, ignoreClick: true
         };
         reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
         reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "undo")!).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
@@ -701,12 +702,12 @@ export class CurrentUserUtils {
             { title: "Back",    icon: "chevron-left",  toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton,         expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 20,  scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
             { title: "Num", icon:"",toolTip: "Frame Number (click to toggle edit mode)",btnType: ButtonType.TextButton,          expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}},
             { title: "Fwd",     icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton,         expertMode: true,  toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 20,  scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
-            { title: "Text",    icon: "Text",          toolTip: "Text functions",       subMenu: CurrentUserUtils.textTools(),   expertMode: false, toolType:DocumentType.RTF,            funcs: {                                                                             linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "Ink",     icon: "Ink",           toolTip: "Ink functions",        subMenu: CurrentUserUtils.inkTools(),    expertMode: false, toolType:DocumentType.INK,            funcs: {                                                                             linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
-            { title: "Doc",     icon: "Doc",           toolTip: "Freeform Doc tools",   subMenu: CurrentUserUtils.freeTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "View",    icon: "View",          toolTip: "View tools",           subMenu: CurrentUserUtils.viewTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
-            { title: "Web",     icon: "Web",           toolTip: "Web functions",        subMenu: CurrentUserUtils.webTools(),    expertMode: false, toolType:DocumentType.WEB,            funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected
-            { title: "Schema",  icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",    subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema,   funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearViewIsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} } // Only when Schema is selected
+            { title: "Text",    icon: "Text",          toolTip: "Text functions",       subMenu: CurrentUserUtils.textTools(),   expertMode: false, toolType:DocumentType.RTF,            funcs: {                                                                             linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "Ink",     icon: "Ink",           toolTip: "Ink functions",        subMenu: CurrentUserUtils.inkTools(),    expertMode: false, toolType:DocumentType.INK,            funcs: {                                                                             linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
+            { title: "Doc",     icon: "Doc",           toolTip: "Freeform Doc tools",   subMenu: CurrentUserUtils.freeTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "View",    icon: "View",          toolTip: "View tools",           subMenu: CurrentUserUtils.viewTools(),   expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+            { title: "Web",     icon: "Web",           toolTip: "Web functions",        subMenu: CurrentUserUtils.webTools(),    expertMode: false, toolType:DocumentType.WEB,            funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected
+            { title: "Schema",  icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema,   funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} } // Only when Schema is selected
         ];
     }
 
@@ -719,7 +720,7 @@ export class CurrentUserUtils {
             _nativeWidth: params.width ?? 30, _width: params.width ?? 30,
             _height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth,
             toolType: params.toolType, expertMode: params.expertMode,
-            _stayInCollection: true, _hideContextMenu: true, _lockedPosition: true,
+            _stayInCollection: true, _layout_hideContextMenu: true, _lockedPosition: true,
             _removeDropProperties: new List<string>([ "_stayInCollection"]),
         };
         const reqdFuncs:{[key:string]:any} = {
@@ -731,7 +732,7 @@ export class CurrentUserUtils {
 
     /// Initializes all the default buttons for the top bar context menu
     static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") {
-        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", dontUndo:true, flexGap: 0, childDropAction: 'embed', childDontRegisterViews: true,  linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 };
+        const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", dontUndo:true, flexGap: 0, childDropAction: 'embed', childDontRegisterViews: true,  linearView_IsExpanded: true, ignoreClick: true, linearView_Expandable: false, _height: 35 };
         const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined);
         const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => {
             const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title);
@@ -740,7 +741,7 @@ export class CurrentUserUtils {
             } else {
                 const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, dontUndo: true,
                     childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: params.scripts?.onClick ? false : true,
-                    linearViewSubMenu: true, linearViewExpandable: true, };
+                    linearView_SubMenu: true, linearView_Expandable: true, };
                 const items = params.subMenu?.map(sub =>
                     this.setupContextMenuButton(sub, DocListCast(menuBtnDoc?.data).find(doc => doc.title === sub.title))
                 );
@@ -793,8 +794,8 @@ export class CurrentUserUtils {
             "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment,
             childDropAction: "embed", isSystem: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true,
             // NOTE: treeViewHideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar
-            _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, 
-            explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
+            _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, layout_boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, 
+            layout_explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
         };
         
         DocUtils.AssignDocField(doc, "mySharedDocs", opts => Docs.Create.TreeDocument([], opts, sharingDocumentId + "layout", sharingDocumentId), sharedDocOpts, undefined, sharedScripts);
@@ -803,17 +804,17 @@ export class CurrentUserUtils {
     /// Import option on the left side button panel 
     static setupImportSidebar(doc: Doc, field:string) {   
         const reqdOpts:DocumentOptions = {
-            title: "My Imports", _forceActive: true, buttonMenu: true, ignoreClick: true, _layout_showTitle: "title", 
-            _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0,
-            childDropAction: "copy", _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true,
-            dontRegisterView: true, explainer: "This is where documents that are Imported into Dash will go."
+            title: "My Imports", _forceActive: true, ignoreClick: true, _layout_showTitle: "title", 
+            _stayInCollection: true, _layout_hideContextMenu: true, childLimitHeight: 0,
+            childDropAction: "copy", _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, layout_boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true,
+            dontRegisterView: true, layout_explainer: "This is where documents that are Imported into Dash will go."
         };
         const myImports = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.StackingDocument([], opts), reqdOpts);
     
         const reqdBtnOpts:DocumentOptions = { _forceActive: true, toolTip: "Import from computer",
-            _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, 
+            _width: 30, _height: 30, _stayInCollection: true, _layout_hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, 
             buttonText: "Import", icon: "upload", isSystem: true };
-        DocUtils.AssignDocField(myImports, "buttonMenuDoc", (opts) => Docs.Create.FontIconDocument(opts), reqdBtnOpts, undefined, { onClick: "importDocument()" });
+        DocUtils.AssignDocField(myImports, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), reqdBtnOpts, undefined, { onClick: "importDocument()" });
         return myImports;
     }
     /// Updates the UserDoc to have all required fields, docs, etc.  No changes should need to be
@@ -850,7 +851,7 @@ export class CurrentUserUtils {
         doc.defaultAclPrivate ?? (doc.defaultAclPrivate = false);
         doc.savedFilters ?? (doc.savedFilters = new List<Doc>());
         doc.filterDocCount = 0;
-        doc.freezeChildren = "remove|add";
+        doc.treeViewFreezeChildren = "remove|add";
         this.setupLinkDocs(doc, linkDatabaseId);
         this.setupSharedDocs(doc, sharingDocumentId);  // sets up the right sidebar collection for mobile upload documents and sharing
         this.setupDefaultIconTemplates(doc);  // creates a set of icon templates triggered by the document deoration icon
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 7a88ca991..612f16ce9 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -189,7 +189,7 @@ export class DocumentManager {
         while (
             containerDocContext.length &&
             containerDocContext[0]?.embedContainer &&
-            DocCast(containerDocContext[0].embedContainer)?.type_collection !== CollectionViewType.Docking &&
+            DocCast(containerDocContext[0].embedContainer)?._type_collection !== CollectionViewType.Docking &&
             (includeExistingViews || !DocumentManager.Instance.getDocumentView(containerDocContext[0]))
         ) {
             containerDocContext = [Cast(containerDocContext[0].embedContainer, Doc, null), ...containerDocContext];
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index fb4a8985c..668de5408 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -517,7 +517,7 @@ export namespace DragManager {
 
             const target = document.elementFromPoint(e.x, e.y);
 
-            if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._noAutoscroll)) {
+            if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._freeform_noAutoPan)) {
                 const autoScrollHandler = () => {
                     target.dispatchEvent(
                         new CustomEvent<React.DragEvent>('dashDragAutoScroll', {
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 41c2fa889..dbb05917e 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -134,7 +134,7 @@ export class LinkManager {
     public createlink_relationshipLists = () => {
         //create new lists for link relations and their associated colors if the lists don't already exist
         !Doc.UserDoc().link_relationshipList && (Doc.UserDoc().link_relationshipList = new List<string>());
-        !Doc.UserDoc().linkColorList && (Doc.UserDoc().linkColorList = new List<string>());
+        !Doc.UserDoc().link_ColorList && (Doc.UserDoc().link_ColorList = new List<string>());
         !Doc.UserDoc().link_relationshipSizes && (Doc.UserDoc().link_relationshipSizes = new List<number>());
     };
 
diff --git a/src/client/util/TrackMovements.ts b/src/client/util/TrackMovements.ts
index f83b6af0e..0e56ee1bc 100644
--- a/src/client/util/TrackMovements.ts
+++ b/src/client/util/TrackMovements.ts
@@ -3,6 +3,7 @@ import { NumCast } from '../../fields/Types';
 import { Doc, DocListCast } from '../../fields/Doc';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
 import { Id } from '../../fields/FieldSymbols';
+import { CollectionViewType } from '../documents/DocumentTypes';
 
 export type Movement = {
     time: number;
@@ -89,7 +90,7 @@ export class TrackMovements {
         if (this.recordingFFViews === null) return;
 
         // so that the size comparisons are correct, we must filter to only the FFViews
-        const isFFView = (doc: Doc) => doc && 'type_collection' in doc && doc.type_collection === 'freeform';
+        const isFFView = (doc: Doc) => doc && doc._type_collection === CollectionViewType.Freeform;
         const tabbedFFViews = new Set<Doc>();
         for (const DashDoc of tabbedDocs) {
             if (isFFView(DashDoc)) tabbedFFViews.add(DashDoc);
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 94dd010c3..50cf2226e 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -390,7 +390,7 @@ export class DashboardView extends React.Component {
             _width: 30,
             _height: 30,
             _stayInCollection: true,
-            _hideContextMenu: true,
+            _layout_hideContextMenu: true,
             title: 'New trail',
             toolTip: 'Create new trail',
             btnType: ButtonType.ClickButton,
@@ -415,16 +415,15 @@ export class DashboardView extends React.Component {
             childDropAction: 'embed',
             treeViewTruncateTitleWidth: 150,
             ignoreClick: true,
-            buttonMenu: true,
-            buttonMenuDoc: myTrailsBtn,
+            layout_headerButton: myTrailsBtn,
             contextMenuIcons: new List<string>(['plus']),
             contextMenuLabels: new List<string>(['Create New Trail']),
             _lockedPosition: true,
-            boxShadow: '0 0',
+            layout_boxShadow: '0 0',
             childDontRegisterViews: true,
             targetDropAction: 'same',
             isSystem: true,
-            explainer: 'All of the trails that you have created will appear here.',
+            layout_explainer: 'All of the trails that you have created will appear here.',
         };
         const myTrails = DocUtils.AssignScripts(Docs.Create.TreeDocument([], reqdOpts), { treeViewChildDoubleClick: 'openPresentation(documentView.rootDoc)' });
         dashboardDoc.myTrails = new PrefetchProxy(myTrails);
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 6fab4430d..db24229dc 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -128,8 +128,6 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
 
         isAnyChildContentActive = () => this._isAnyChildContentActive;
 
-        lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result;
-
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
         @computed public get annotationKey() {
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 547d844ca..35b0b22a8 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -589,7 +589,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                         <LinkPopup
                             key="popup"
                             showPopup={this._showLinkPopup}
-                            linkCreated={link => (link.layout_linkDisplay = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
+                            linkCreated={link => (link.link_displayLine = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
                             linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)}
                             linkFrom={() => this.props.views().lastElement()?.rootDoc}
                         />
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e4d50b143..528b82e3e 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -332,7 +332,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                         const docMax = Math.min(NumCast(doc.width) / 2, NumCast(doc.height) / 2);
                         const ratio = dist / maxDist;
                         const radius = Math.min(1, ratio) * docMax;
-                        doc.borderRounding = `${radius}px`;
+                        doc.layout_borderRounding = `${radius}px`;
                     });
                 return false;
             }, // moveEvent
@@ -588,7 +588,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                     let dW = docwidth * (dWin / refWidth);
                     let dH = docheight * (dHin / refHeight);
                     const scale = docView.props.ScreenToLocalTransform().Scale;
-                    const modifyNativeDim = (e.ctrlKey || doc.layout_forceReflow) && doc.nativeDimModifiable && ((!dragBottom && !dragTop) || e.ctrlKey || doc.nativeHeightUnfrozen);
+                    const modifyNativeDim = (e.ctrlKey && doc.nativeDimModifiable) || (doc.layout_forceReflow && !dragBottom && !dragTop) || (doc.nativeHeightUnfrozen && (dragBottom || dragTop || e.ctrlKey));
                     if (nwidth && nheight) {
                         if (nwidth / nheight !== docwidth / docheight && !dragBottom && !dragTop) {
                             docheight = (nheight / nwidth) * docwidth;
@@ -636,7 +636,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                 }
                             }
                             if (!modifyNativeDim) {
-                                actualdH = Math.min((nheight / nwidth) * docwidth, actualdH);
+                                actualdH = (nheight / nwidth) * docwidth; //, actualdH);
                             }
                             doc._height = actualdH;
                         }
@@ -750,13 +750,13 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         const hideDecorations = seldocview.props.hideDecorations || seldocview.rootDoc.hideDecorations;
         const hideResizers = hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating;
         const hideTitle = hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.layout_hideDecorationTitle || this._isRounding || this._isRotating;
-        const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.hideDocumentButtonBar || this._isRounding || this._isRotating;
+        const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.layout_hideDocumentButtonBar || this._isRounding || this._isRotating;
         // if multiple documents have been opened at the same time, then don't show open button
         const hideOpenButton =
             hideDecorations ||
             seldocview.props.hideOpenButton ||
-            seldocview.rootDoc.hideOpenButton ||
-            SelectionManager.Views().some(docView => docView.props.Document._stayInCollection || docView.props.Document.isGroup || docView.props.Document.hideOpenButton) ||
+            seldocview.rootDoc.layout_hideOpenButton ||
+            SelectionManager.Views().some(docView => docView.rootDoc._stayInCollection || docView.rootDoc.isGroup || docView.rootDoc.layout_hideOpenButton) ||
             this._isRounding ||
             this._isRotating;
         const hideDeleteButton =
@@ -767,7 +767,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             seldocview.rootDoc.hideDeleteButton ||
             SelectionManager.Views().some(docView => {
                 const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DocData]) : AclEdit;
-                return (docView.rootDoc.stayInCollection && !docView.rootDoc.timelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
+                return (docView.rootDoc.stayInCollection && !docView.rootDoc._isTimelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
             });
 
         const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
@@ -796,7 +796,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
 
         // Radius constants
         const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView;
-        const borderRadius = numberValue(StrCast(seldocview.rootDoc.borderRounding));
+        const borderRadius = numberValue(StrCast(seldocview.rootDoc.layout_borderRounding));
         const docMax = Math.min(NumCast(seldocview.rootDoc.width) / 2, NumCast(seldocview.rootDoc.height) / 2);
         const maxDist = Math.min((this.Bounds.r - this.Bounds.x) / 2, (this.Bounds.b - this.Bounds.y) / 2);
         const radiusHandle = (borderRadius / docMax) * maxDist;
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 53c1f1018..fe42628cd 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -64,7 +64,7 @@ export class FilterPanel extends React.Component<filterProps> {
      * The current attributes selected to filter based on
      */
     @computed get activeFilters() {
-        return StrListCast(this.targetDoc?._docFilters);
+        return StrListCast(this.targetDoc?._childFilters);
     }
 
     /**
@@ -108,8 +108,8 @@ export class FilterPanel extends React.Component<filterProps> {
     @observable _chosenFacets = new ObservableMap<string, 'text' | 'checkbox' | 'slider' | 'range'>();
     @computed get activeFacets() {
         const facets = new Map<string, 'text' | 'checkbox' | 'slider' | 'range'>(this._chosenFacets);
-        StrListCast(this.targetDoc?._docFilters).map(filter => facets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'));
-        setTimeout(() => StrListCast(this.targetDoc?._docFilters).map(action(filter => this._chosenFacets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'))));
+        StrListCast(this.targetDoc?._childFilters).map(filter => facets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'));
+        setTimeout(() => StrListCast(this.targetDoc?._childFilters).map(action(filter => this._chosenFacets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'))));
         return facets;
     }
     /**
@@ -174,7 +174,7 @@ export class FilterPanel extends React.Component<filterProps> {
                         <Select placeholder="Add a filter..." options={options} isMulti={false} onChange={val => this.facetClick((val as UserOptions).value)} onKeyDown={e => e.stopPropagation()} value={null} closeMenuOnSelect={true} />
                     </div>
                     <div className="filterBox-select-bool">
-                        <select className="filterBox-selection" onChange={action(e => this.targetDoc && (this.targetDoc._filterBoolean = (e.target as any).value))} defaultValue={StrCast(this.targetDoc?.filterBoolean)}>
+                        <select className="filterBox-selection" onChange={action(e => this.targetDoc && (this.targetDoc._childFilters_boolean = (e.target as any).value))} defaultValue={StrCast(this.targetDoc?.childFilters_boolean)}>
                             {['AND', 'OR'].map(bool => (
                                 <option value={bool} key={bool}>
                                     {bool}
@@ -202,7 +202,7 @@ export class FilterPanel extends React.Component<filterProps> {
                 return (
                     <input
                         placeholder={
-                            StrListCast(this.targetDoc._docFilters)
+                            StrListCast(this.targetDoc._childFilters)
                                 .find(filter => filter.split(':')[0] === facetHeader)
                                 ?.split(':')[1] ?? '-empty-'
                         }
@@ -218,7 +218,7 @@ export class FilterPanel extends React.Component<filterProps> {
                             <input
                                 style={{ width: 20, marginLeft: 20 }}
                                 checked={
-                                    StrListCast(this.targetDoc._docFilters)
+                                    StrListCast(this.targetDoc._childFilters)
                                         .find(filter => filter.split(':')[0] === facetHeader && filter.split(':')[1] == facetValue)
                                         ?.split(':')[2] === 'check'
                                 }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 141e99c66..0951bff22 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -140,7 +140,7 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 title: 'buttons',
                 _layout_autoHeight: true,
                 _yMargin: 5,
-                linearViewIsExpanded: true,
+                linearView_IsExpanded: true,
                 backgroundColor: 'white',
                 isSystem: true,
             });
@@ -148,7 +148,7 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 _width: 300,
                 _height: 25,
                 _layout_autoHeight: true,
-                linearViewIsExpanded: true,
+                linearView_IsExpanded: true,
                 flexDirection: 'column',
                 isSystem: true,
             });
@@ -1013,8 +1013,8 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 focus={emptyFunction}
                 whenChildContentsActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
-                docRangeFilters={returnEmptyFilter}
-                docFilters={returnEmptyFilter}
+                childFiltersByRanges={returnEmptyFilter}
+                childFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
             />
         );
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 1b309a6be..286d39943 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -43,7 +43,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
     @observable private static _layoutTemplateString: Opt<string>;
     @observable private static _doc: Opt<Doc>;
     @observable private static _docTarget: Opt<Doc>;
-    @observable private static _docFilters: string[] = []; // filters
+    @observable private static _childFilters: string[] = []; // filters
     private static _savedState: Opt<LightboxSavedState>;
     private static _history: Opt<{ doc: Doc; target?: Doc }[]> = [];
     @observable private static _future: Opt<Doc[]> = [];
@@ -58,7 +58,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
             this.LightboxDoc.layout_fieldKey = this._savedState.layout_fieldKey;
         }
         if (!doc) {
-            this._docFilters && (this._docFilters.length = 0);
+            this._childFilters && (this._childFilters.length = 0);
             this._future = this._history = [];
             Doc.ActiveTool = InkTool.None;
             MainView.Instance._exploreMode = false;
@@ -134,7 +134,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
     @action
     public static SetCookie(cookie: string) {
         if (this.LightboxDoc && cookie) {
-            this._docFilters = (f => (this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f]))(`cookies:${cookie}:provide`);
+            this._childFilters = (f => (this._childFilters ? [this._childFilters.push(f) as any, this._childFilters][1] : [f]))(`cookies:${cookie}:provide`);
         }
     }
     public static AddDocTab = (doc: Doc, location: OpenWhere, layoutTemplate?: Doc | string) => {
@@ -148,7 +148,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
             layoutTemplate
         );
     };
-    docFilters = () => LightboxView._docFilters || [];
+    childFilters = () => LightboxView._childFilters || [];
     addDocTab = LightboxView.AddDocTab;
     @action public static Next() {
         const doc = LightboxView._doc!;
@@ -261,8 +261,8 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                             renderDepth={0}
                             rootSelected={returnTrue}
                             docViewPath={returnEmptyDoclist}
-                            docFilters={this.docFilters}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={this.childFilters}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                             addDocument={undefined}
                             removeDocument={undefined}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8e112dddb..b0e992cb6 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -608,8 +608,8 @@ export class MainView extends React.Component {
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
             </div>
@@ -637,8 +637,8 @@ export class MainView extends React.Component {
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     suppressSetHeight={true}
                     renderDepth={this._hideUI ? 0 : -1}
@@ -736,8 +736,8 @@ export class MainView extends React.Component {
                         focus={emptyFunction}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                     />
                 </div>
@@ -767,8 +767,8 @@ export class MainView extends React.Component {
                     isContentActive={returnTrue}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     scriptContext={this}
                 />
@@ -903,8 +903,8 @@ export class MainView extends React.Component {
                     renderDepth={0}
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
                 {['watching', 'recording'].includes(String(this.userDoc?.presentationMode) ?? '') ? <div style={{ border: '.5rem solid green', padding: '5px' }}>{StrCast(this.userDoc?.presentationMode)}</div> : <></>}
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 6c36d39b9..a4a2c1df9 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -126,7 +126,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
                           if (!e.aborted && e.linkDocument) {
                               Doc.GetProto(e.linkDocument).link_relationship = 'cropped image';
                               Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.docView.rootDoc.title;
-                              Doc.GetProto(e.linkDocument).layout_linkDisplay = false;
+                              Doc.GetProto(e.linkDocument).link_displayLine = false;
                           }
                       },
                   });
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 59865cba3..339507f65 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -228,8 +228,8 @@ export class OverlayView extends React.Component {
                             docViewPath={returnEmptyDoclist}
                             addDocTab={DocumentViewInternal.addDocTabFunc}
                             pinToPres={emptyFunction}
-                            docFilters={returnEmptyFilter}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                         />
                     </div>
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 3ad28c418..749eb08a2 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -56,8 +56,8 @@ export default class Palette extends React.Component<PaletteProps> {
                             styleProvider={returnEmptyString}
                             whenChildContentsActiveChanged={emptyFunction}
                             bringToFront={emptyFunction}
-                            docFilters={returnEmptyFilter}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                         />
                         <div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div>
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 76828a576..11b89fd69 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -133,14 +133,14 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                     const containerDoc = dv.rootDoc;
                     //containerDoc.followAllLinks =
                     // containerDoc.noShadow =
-                    // containerDoc.disableDocBrushing =
+                    // containerDoc.layout_disableBrushing =
                     // containerDoc._forceActive =
                     //containerDoc._freeform_fitContentsToBox =
                     containerDoc._isLightbox = !containerDoc._isLightbox;
                     //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined;
                     const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]);
                     //dv.rootDoc.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' });
-                    containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.layout_linkDisplay = false)));
+                    containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.link_displayLine = false)));
                 });
             }
         );
diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx
index 7b21629da..3e69bcba6 100644
--- a/src/client/views/PropertiesDocBacklinksSelector.tsx
+++ b/src/client/views/PropertiesDocBacklinksSelector.tsx
@@ -19,8 +19,8 @@ type PropertiesDocBacklinksSelectorProps = {
 @observer
 export class PropertiesDocBacklinksSelector extends React.Component<PropertiesDocBacklinksSelectorProps> {
     getOnClick = (link: Doc) => {
-        const linkSource = this.props.Document;
-        const other = LinkManager.getOppositeAnchor(link, linkSource);
+        const linkAnchor = this.props.Document;
+        const other = LinkManager.getOppositeAnchor(link, linkAnchor);
         const otherdoc = !other ? undefined : other.annotationOn && other.type !== DocumentType.RTF ? Cast(other.annotationOn, Doc, null) : other;
 
         if (otherdoc) {
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 00e077f96..1f2e21dd5 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -276,8 +276,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         PanelHeight={panelHeight}
                         focus={emptyFunction}
                         ScreenToLocalTransform={this.getTransform}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                         addDocument={returnFalse}
                         moveDocument={undefined}
@@ -941,26 +941,26 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     /**
-     * Updates this.filterDoc's currentFilter and saves the docFilters on the currentFilter
+     * Updates this.filterDoc's currentFilter and saves the childFilters on the currentFilter
      */
     updateFilterDoc = (doc: Doc) => {
         if (this.selectedDoc) {
             if (doc === this.selectedDoc.currentFilter) return; // causes problems if you try to reapply the same doc
-            const savedDocFilters = doc._docFiltersList;
-            const currentDocFilters = this.selectedDoc._docFilters;
-            this.selectedDoc._docFilters = new List<string>();
-            (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters;
+            const savedDocFilters = doc._childFiltersList;
+            const currentDocFilters = this.selectedDoc._childFilters;
+            this.selectedDoc._childFilters = new List<string>();
+            (this.selectedDoc.currentFilter as Doc)._childFiltersList = currentDocFilters;
             this.selectedDoc.currentFilter = doc;
-            doc._docFiltersList = new List<string>();
-            this.selectedDoc._docFilters = savedDocFilters;
+            doc._childFiltersList = new List<string>();
+            this.selectedDoc._childFilters = savedDocFilters;
 
-            const savedDocRangeFilters = doc._docRangeFiltersList;
-            const currentDocRangeFilters = this.selectedDoc._docRangeFilters;
-            this.selectedDoc._docRangeFilters = new List<string>();
-            (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters;
+            const savedDocRangeFilters = doc._childFiltersByRangesList;
+            const currentDocRangeFilters = this.selectedDoc._childFiltersByRanges;
+            this.selectedDoc._childFiltersByRanges = new List<string>();
+            (this.selectedDoc.currentFilter as Doc)._childFiltersByRangesList = currentDocRangeFilters;
             this.selectedDoc.currentFilter = doc;
-            doc._docRangeFiltersList = new List<string>();
-            this.selectedDoc._docRangeFilters = savedDocRangeFilters;
+            doc._childFiltersByRangesList = new List<string>();
+            this.selectedDoc._childFiltersByRanges = savedDocRangeFilters;
         }
     };
 
@@ -1117,7 +1117,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             Doc.GetProto(LinkManager.currentLink).link_relationship = value;
             const linkRelationshipList = StrListCast(Doc.UserDoc().link_relationshipList);
             const linkRelationshipSizes = NumListCast(Doc.UserDoc().link_relationshipSizes);
-            const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
+            const linkColorList = StrListCast(Doc.UserDoc().link_ColorList);
 
             // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color
             if (!linkRelationshipList?.includes(value)) {
@@ -1328,8 +1328,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline">
                                         <p>Show link</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.layout_linkDisplay ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_linkDisplay')}
+                                            style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
@@ -1338,8 +1338,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
                                         <p>Auto-move anchors</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.layout_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_autoMoveAnchors')}
+                                            style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
@@ -1348,8 +1348,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                                     <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
                                         <p>Display arrow</p>
                                         <button
-                                            style={{ background: !LinkManager.currentLink?.layout_linkDisplayArrow ? '' : '#4476f7', borderRadius: 3 }}
-                                            onPointerDown={e => this.toggleLinkProp(e, 'layout_linkDisplayArrow')}
+                                            style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
+                                            onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
                                             onClick={e => e.stopPropagation()}
                                             className="propertiesButton">
                                             <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 498e2ccba..db273cc88 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -63,11 +63,11 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         return Array.from(keys.keys()).sort();
     }
     get filtersKey() {
-        return '_' + this.sidebarKey + '_docFilters';
+        return '_' + this.sidebarKey + '_childFilters';
     }
 
     anchorMenuClick = (anchor: Doc) => {
-        const startup = StrListCast(this.props.rootDoc.docFilters)
+        const startup = StrListCast(this.props.rootDoc.childFilters)
             .map(filter => filter.split(':')[0])
             .join(' ');
         const target = Docs.Create.TextDocument(startup, {
@@ -83,9 +83,9 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         FormattedTextBox.SelectOnLoad = target[Id];
         FormattedTextBox.DontSelectInitialText = true;
         const link = DocUtils.MakeLink(anchor, target, { link_relationship: 'inline comment:comment on' });
-        link && (link.layout_linkDisplay = false);
+        link && (link.link_displayLine = false);
 
-        const taggedContent = this.docFilters()
+        const taggedContent = this.childFilters()
             .filter(data => data.split(':')[0])
             .map(data => {
                 const key = data.split(':')[0];
@@ -177,7 +177,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
     addDocument = (doc: Doc | Doc[]) => this.props.sidebarAddDocument(doc, this.sidebarKey);
     moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(doc, targetCollection, addDocument, this.sidebarKey);
     removeDocument = (doc: Doc | Doc[]) => this.props.removeDocument(doc, this.sidebarKey);
-    docFilters = () => [...StrListCast(this.props.layoutDoc._docFilters), ...StrListCast(this.props.layoutDoc[this.filtersKey])];
+    childFilters = () => [...StrListCast(this.props.layoutDoc._childFilters), ...StrListCast(this.props.layoutDoc[this.filtersKey])];
     layout_showTitle = () => 'title';
     setHeightCallback = (height: number) => this.props.setHeight?.(height + this.filtersHeight());
     sortByLinkAnchorY = (a: Doc, b: Doc) => {
@@ -238,7 +238,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                         ref={this._stackRef}
                         PanelHeight={this.panelHeight}
                         PanelWidth={this.panelWidth}
-                        docFilters={this.docFilters}
+                        childFilters={this.childFilters}
                         sortFunc={this.sortByLinkAnchorY}
                         setHeight={this.setHeightCallback}
                         isAnnotationOverlay={false}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index cf0177f4b..9199bf931 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -115,7 +115,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             allSorts[TreeSort.None] = { color: 'darkgray', label: '\u00A0\u00A0\u00A0' };
             return allSorts;
         case StyleProp.Highlighting:
-            if (doc && !doc.disableDocBrushing && !props?.disableDocBrushing) {
+            if (doc && !doc.layout_disableBrushing && !props?.disableBrushing) {
                 const selected = SelectionManager.Views().some(dv => dv.rootDoc === doc);
                 const highlightIndex = Doc.isBrushedHighlightedDegree(doc) || (selected ? Doc.DocBrushStatus.selfBrushed : 0);
                 const highlightColor = ['transparent', 'rgb(68, 118, 247)', selected ? 'black' : 'rgb(68, 118, 247)', 'orange', 'lightBlue'][highlightIndex];
@@ -166,7 +166,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             if (!backColor) return undefined;
             return lightOrDark(backColor);
         case StyleProp.BorderRounding:
-            return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : ''));
+            return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.layout_borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : ''));
         case StyleProp.BorderPath:
             const borderPath = Doc.IsComicStyle(doc) &&
                 props?.renderDepth &&
@@ -235,38 +235,37 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         }
         case StyleProp.BoxShadow: {
             if (!doc || opacity() === 0 || doc.noShadow) return undefined; // if it's not visible, then no shadow)
-            if (doc.boxShadow === 'standard') return Shadows.STANDARD_SHADOW;
+            if (doc.layout_boxShadow === 'standard') return Shadows.STANDARD_SHADOW;
             if (IsFollowLinkScript(doc?.onClick) && LinkManager.Links(doc).length && ![DocumentType.LINK, DocumentType.INK].includes(doc.type as any)) return StrCast(doc?._linkButtonShadow, 'lightblue 0em 0em 1em');
             switch (doc?.type) {
                 case DocumentType.COL:
                     return StrCast(
-                        doc?.boxShadow,
+                        doc?.layout_borderRounding,
                         doc?._type_collection === CollectionViewType.Pile
                             ? '4px 4px 10px 2px'
                             : lockedPosition() || doc?._isGroup || docProps?.LayoutTemplateString
                             ? undefined // groups have no drop shadow -- they're supposed to be "invisible".  LayoutString's imply collection is being rendered as something else (e.g., title of a Slide)
-                            : `${darkScheme() ? Colors.DARK_GRAY : Colors.MEDIUM_GRAY} ${StrCast(doc.boxShadow, '0.2vw 0.2vw 0.8vw')}`
+                            : `${darkScheme() ? Colors.DARK_GRAY : Colors.MEDIUM_GRAY} ${StrCast(doc.layout_borderRounding, '0.2vw 0.2vw 0.8vw')}`
                     );
 
                 case DocumentType.LABEL:
                     if (doc?.annotationOn !== undefined) return 'black 2px 2px 1px';
                 default:
                     return doc.z
-                        ? `#9c9396  ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
+                        ? `#9c9396  ${StrCast(doc?.layout_boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
                         : props?.docViewPath().lastElement()?.rootDoc._freeform_useClusters
-                        ? `${backgroundCol()} ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                        ? `${backgroundCol()} ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : NumCast(doc.group, -1) !== -1
-                        ? `gray ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                        ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : lockedPosition()
                         ? undefined // if it's a background & has a cluster color, make the shadow spread really big
-                        : StrCast(doc.boxShadow, '');
+                        : StrCast(doc.layout_boxShadow, '');
             }
         }
         case StyleProp.PointerEvents:
             const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name) && !props?.LayoutTemplateString;
             if (docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.() !== undefined) return docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.();
             if (MainView.Instance._exploreMode || doc?.layout_unrendered) return isInk ? 'visiblePainted' : 'all';
-            if (doc?.pointerEvents) return StrCast(doc.pointerEvents);
             if (props?.contentPointerEvents) return StrCast(props.contentPointerEvents);
             if (props?.pointerEvents?.() === 'none') return 'none';
             if (opacity() === 0) return 'none';
@@ -284,9 +283,9 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             };
             const filter = () => {
                 const showFilterIcon =
-                    StrListCast(doc?._docFilters).length || StrListCast(doc?._docRangeFilters).length
+                    StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length
                         ? '#18c718bd' //'hasFilter'
-                        : docProps?.docFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragsDocFilter).length || docProps?.docRangeFilters().length
+                        : docProps?.childFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragsDocFilter).length || docProps?.childFiltersByRanges().length
                         ? 'orange' //'inheritsFilter'
                         : undefined;
                 return !showFilterIcon ? null : (
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 814a95ab8..62f47ba71 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -116,8 +116,8 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                     styleProvider={DefaultStyleProvider}
                     setHeight={returnFalse}
                     docViewPath={returnEmptyDoclist}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     rootSelected={returnFalse}
                     onCheckedClick={this.scriptField}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index dc430667b..fc3f713ce 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -130,8 +130,8 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
                     renderDepth={0}
                     focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
             </div>
@@ -277,16 +277,16 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
     _saveFilterCommand = {
         params: ['target'],
         title: 'save filter',
-        script: `self.target._docFilters = compareLists(self['target-docFilters'],self.target._docFilters) ? undefined : copyField(self['target-docFilters']); 
+        script: `self.target._childFilters = compareLists(self['target-childFilters'],self.target._childFilters) ? undefined : copyField(self['target-childFilters']); 
                  self.target._searchFilterDocs = compareLists(self['target-searchFilterDocs'],self.target._searchFilterDocs) ? undefined: copyField(self['target-searchFilterDocs']);`,
         immediate: undoBatch((source: Doc[]) => {
-            this.target._docFilters = undefined;
+            this.target._childFilters = undefined;
             this.target._searchFilterDocs = undefined;
         }),
         initialize: (button: Doc) => {
             const activeDash = Doc.ActiveDashboard;
             if (activeDash) {
-                button['target-docFilters'] = (Doc.MySearcher._docFilters || activeDash._docFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher._docFilters || activeDash._docFilters) as any as ObjectField) : undefined;
+                button['target-childFilters'] = (Doc.MySearcher._childFilters || activeDash._childFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher._childFilters || activeDash._childFilters) as any as ObjectField) : undefined;
                 button['target-searchFilterDocs'] = activeDash._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(activeDash._searchFilterDocs as any as ObjectField) : undefined;
             }
         },
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index fc265e2b9..675f23970 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -201,13 +201,17 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     };
 
     styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => {
-        if (property === StyleProp.BoxShadow && doc && DragManager.docsBeingDragged.includes(doc)) {
-            return `#9c9396  ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}`;
-        }
-        if (property === StyleProp.Opacity && doc) {
-            if (this.props.childOpacity) {
-                return this.props.childOpacity();
-            }
+        switch (property) {
+            case StyleProp.BoxShadow:
+                if (doc && DragManager.docsBeingDragged.includes(doc)) {
+                    return `#9c9396 ${StrCast(doc?.layout_boxShadow, '10px 10px 0.9vw')}`;
+                }
+                break;
+            case StyleProp.Opacity:
+                if (doc && this.props.childOpacity) {
+                    return this.props.childOpacity();
+                }
+                break;
         }
         return this.props.styleProvider?.(doc, props, property);
     };
@@ -251,11 +255,11 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 onDoubleClick={this.onChildDoubleClickHandler}
                 ScreenToLocalTransform={noteTakingDocTransform}
                 focus={this.focusDocument}
-                docFilters={this.childDocFilters}
+                childFilters={this.childDocFilters}
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 hideResizeHandles={this.props.childHideResizeHandles?.()}
                 hideTitle={this.props.childHideTitle?.()}
-                docRangeFilters={this.childDocRangeFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
@@ -603,42 +607,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         return eles;
     }
 
-    @computed get buttonMenu() {
-        const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
-        if (menuDoc) {
-            const width = NumCast(menuDoc._width, 30);
-            const height = NumCast(menuDoc._height, 30);
-            return (
-                <div className="buttonMenu-docBtn" style={{ width, height }}>
-                    <DocumentView
-                        Document={menuDoc}
-                        DataDoc={menuDoc}
-                        isContentActive={this.props.isContentActive}
-                        isDocumentActive={returnTrue}
-                        addDocument={this.props.addDocument}
-                        moveDocument={this.props.moveDocument}
-                        addDocTab={this.props.addDocTab}
-                        pinToPres={emptyFunction}
-                        rootSelected={this.props.isSelected}
-                        removeDocument={this.props.removeDocument}
-                        ScreenToLocalTransform={Transform.Identity}
-                        PanelWidth={() => 35}
-                        PanelHeight={() => 35}
-                        renderDepth={this.props.renderDepth}
-                        focus={emptyFunction}
-                        styleProvider={this.props.styleProvider}
-                        docViewPath={returnEmptyDoclist}
-                        whenChildContentsActiveChanged={emptyFunction}
-                        bringToFront={emptyFunction}
-                        docFilters={this.props.docFilters}
-                        docRangeFilters={this.props.docRangeFilters}
-                        searchFilterDocs={this.props.searchFilterDocs}
-                    />
-                </div>
-            );
-        }
-    }
-
     @computed get nativeWidth() {
         return Doc.NativeWidth(this.layoutDoc);
     }
@@ -658,35 +626,25 @@ export class CollectionNoteTakingView extends CollectionSubView() {
 
     render() {
         TraceMobx();
-        const buttonMenu = this.rootDoc.buttonMenu;
-        const noviceExplainer = StrCast(this.rootDoc.explainer);
         return (
-            <>
-                {buttonMenu || noviceExplainer ? (
-                    <div className="documentButtonMenu" key="buttons">
-                        {buttonMenu ? this.buttonMenu : null}
-                        {Doc.UserDoc().noviceMode && noviceExplainer ? <div className="documentExplanation">{noviceExplainer}</div> : null}
-                    </div>
-                ) : null}
-                <div
-                    className="collectionNoteTakingView"
-                    ref={this.createRef}
-                    key="notes"
-                    style={{
-                        overflowY: this.props.isContentActive() ? 'auto' : 'hidden',
-                        background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
-                        pointerEvents: this.backgroundEvents ? 'all' : undefined,
-                    }}
-                    onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
-                    onPointerLeave={action(e => (this.docsDraggedRowCol.length = 0))}
-                    onPointerMove={e => e.buttons && this.onPointerMove(false, e.clientX, e.clientY)}
-                    onDragOver={e => this.onPointerMove(true, e.clientX, e.clientY)}
-                    onDrop={this.onExternalDrop.bind(this)}
-                    onContextMenu={this.onContextMenu}
-                    onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}>
-                    {this.renderedSections}
-                </div>
-            </>
+            <div
+                className="collectionNoteTakingView"
+                ref={this.createRef}
+                key="notes"
+                style={{
+                    overflowY: this.props.isContentActive() ? 'auto' : 'hidden',
+                    background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor),
+                    pointerEvents: this.backgroundEvents ? 'all' : undefined,
+                }}
+                onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))}
+                onPointerLeave={action(e => (this.docsDraggedRowCol.length = 0))}
+                onPointerMove={e => e.buttons && this.onPointerMove(false, e.clientX, e.clientY)}
+                onDragOver={e => this.onPointerMove(true, e.clientX, e.clientY)}
+                onDrop={this.onExternalDrop.bind(this)}
+                onContextMenu={this.onContextMenu}
+                onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}>
+                {this.renderedSections}
+            </div>
         );
     }
 }
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index bbc91aa6e..57d9bbb49 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -23,7 +23,7 @@ export class CollectionPileView extends CollectionSubView() {
 
     componentDidMount() {
         if (this.layoutEngine() !== computePassLayout.name && this.layoutEngine() !== computeStarburstLayout.name) {
-            this.Document._pileLayoutEngine = computePassLayout.name;
+            this.Document._freeform_pileEngine = computePassLayout.name;
         }
         this._originalChrome = this.layoutDoc._chromeHidden;
         this.layoutDoc._chromeHidden = true;
@@ -33,7 +33,7 @@ export class CollectionPileView extends CollectionSubView() {
         Object.values(this._disposers).forEach(disposer => disposer?.());
     }
 
-    layoutEngine = () => StrCast(this.Document._pileLayoutEngine);
+    layoutEngine = () => StrCast(this.Document._freeform_pileEngine);
 
     @undoBatch
     addPileDoc = (doc: Doc | Doc[]) => {
@@ -73,28 +73,29 @@ export class CollectionPileView extends CollectionSubView() {
 
     // toggles the pileup between starburst to compact
     toggleStarburst = action(() => {
+        this.layoutDoc._freeform_scale = undefined;
         if (this.layoutEngine() === computeStarburstLayout.name) {
             if (this.rootDoc[Width]() !== NumCast(this.rootDoc._starburstDiameter, 500)) {
                 this.rootDoc._starburstDiameter = this.rootDoc[Width]();
             }
             const defaultSize = 110;
-            this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2;
-            this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2;
-            this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize);
-            this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize);
+            this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - NumCast(this.layoutDoc._freeform_pileWidth, defaultSize) / 2;
+            this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - NumCast(this.layoutDoc._freeform_pileHeight, defaultSize) / 2;
+            this.layoutDoc._width = NumCast(this.layoutDoc._freeform_pileWidth, defaultSize);
+            this.layoutDoc._height = NumCast(this.layoutDoc._freeform_pileHeight, defaultSize);
             DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false);
             this.layoutDoc._freeform_panX = 0;
             this.layoutDoc._freeform_panY = -10;
-            this.props.Document._pileLayoutEngine = computePassLayout.name;
+            this.props.Document._freeform_pileEngine = computePassLayout.name;
         } else {
             const defaultSize = NumCast(this.rootDoc._starburstDiameter, 500);
             this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - defaultSize / 2;
             this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - defaultSize / 2;
-            this.layoutDoc._starburstPileWidth = this.layoutDoc[Width]();
-            this.layoutDoc._starburstPileHeight = this.layoutDoc[Height]();
+            this.layoutDoc._freeform_pileWidth = this.layoutDoc[Width]();
+            this.layoutDoc._freeform_pileHeight = this.layoutDoc[Height]();
             this.layoutDoc._freeform_panX = this.layoutDoc._freeform_panY = 0;
             this.layoutDoc._width = this.layoutDoc._height = defaultSize;
-            this.props.Document._pileLayoutEngine = computeStarburstLayout.name;
+            this.props.Document._freeform_pileEngine = computeStarburstLayout.name;
         }
     });
 
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index b131d38d8..9d5cb257a 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -404,15 +404,15 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
             docAnchor ??
             Docs.Create.LabelDocument({
                 title: ComputedField.MakeFunction(`self["${endTag}"] ? "#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"]) : "#" + formatToTime(self["${startTag}"])`) as any,
-                _minFontSize: 12,
-                _maxFontSize: 24,
+                _label_minFontSize: 12,
+                _label_maxFontSize: 24,
                 _stayInCollection: true,
                 backgroundColor: 'rgba(128, 128, 128, 0.5)',
                 layout_hideLinkButton: true,
                 onClick: FollowLinkScript(),
                 annotationOn: rootDoc,
-                _timelineLabel: true,
-                borderRounding: anchorEndTime === undefined ? '100%' : undefined,
+                _isTimelineLabel: true,
+                layout_borderRounding: anchorEndTime === undefined ? '100%' : undefined,
             });
         Doc.GetProto(anchor)[startTag] = anchorStartTime;
         Doc.GetProto(anchor)[endTag] = anchorEndTime;
@@ -752,7 +752,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
             if (timelineOnly) {
                 if (!left && time !== undefined && time <= NumCast(anchor[this.props.startTag])) time = undefined;
                 Doc.SetInPlace(anchor, left ? this.props.startTag : this.props.endTag, time, true);
-                if (!left) Doc.SetInPlace(anchor, 'borderRounding', time !== undefined ? undefined : '100%', true);
+                if (!left) Doc.SetInPlace(anchor, 'layout_borderRounding', time !== undefined ? undefined : '100%', true);
             } else {
                 anchor[left ? '_timecodeToShow' : '_timecodeToHide'] = time;
             }
@@ -820,8 +820,8 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                     focus={focusFunc}
                     isContentActive={returnFalse}
                     searchFilterDocs={returnEmptyDoclist}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     rootSelected={returnFalse}
                     onClick={script}
                     onDoubleClick={this.props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 56f53afe6..3c0d8cbc3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -346,11 +346,11 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 onDoubleClick={this.onChildDoubleClickHandler}
                 ScreenToLocalTransform={stackedDocTransform}
                 focus={this.focusDocument}
-                docFilters={this.childDocFilters}
+                childFilters={this.childDocFilters}
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 hideResizeHandles={this.props.childHideResizeHandles?.()}
                 hideTitle={this.props.childHideTitle?.()}
-                docRangeFilters={this.childDocRangeFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 xPadding={NumCast(this.layoutDoc._childXPadding, this.props.childXPadding)}
                 yPadding={NumCast(this.layoutDoc._childYPadding, this.props.childYPadding)}
@@ -650,7 +650,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
 
     return35 = () => 35;
     @computed get buttonMenu() {
-        const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
+        const menuDoc: Doc = Cast(this.rootDoc.layout_headerButton, Doc, null);
         // TODO:glr Allow support for multiple buttons
         if (menuDoc) {
             const width: number = NumCast(menuDoc._width, 30);
@@ -679,8 +679,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        docFilters={this.props.docFilters}
-                        docRangeFilters={this.props.docRangeFilters}
+                        childFilters={this.props.childFilters}
+                        childFiltersByRanges={this.props.childFiltersByRanges}
                         searchFilterDocs={this.props.searchFilterDocs}
                     />
                 </div>
@@ -711,7 +711,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             contents: '+ ADD A GROUP',
         };
         const buttonMenu = this.rootDoc.buttonMenu;
-        const noviceExplainer = this.rootDoc.explainer;
+        const noviceExplainer = this.rootDoc.layout_explainer;
         return (
             <>
                 {buttonMenu || noviceExplainer ? (
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 967d1d40e..d1b7f6ff6 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -28,8 +28,8 @@ export function CollectionSubView<X>(moreProps?: X) {
         private gestureDisposer?: GestureUtils.GestureEventDisposer;
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
         protected _mainCont?: HTMLDivElement;
-        @observable _focusFilters: Opt<string[]>; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it
-        @observable _focusRangeFilters: Opt<string[]>; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it
+        @observable _focusFilters: Opt<string[]>; // childFilters that are overridden when previewing a link to an anchor which has childFilters set on it
+        @observable _focusRangeFilters: Opt<string[]>; // childFiltersByRanges that are overridden when previewing a link to an anchor which has childFiltersByRanges set on it
         protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
             //used for stacking and masonry view
             this.dropDisposer?.();
@@ -81,13 +81,13 @@ export function CollectionSubView<X>(moreProps?: X) {
         get childDocList() {
             return Cast(this.dataField, listSpec(Doc));
         }
-        collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._docFilters);
-        collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._docRangeFilters, listSpec('string'), []);
+        collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._childFilters);
+        collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._childFiltersByRanges, listSpec('string'), []);
         // child filters apply to the descendants of the documents in this collection
-        childDocFilters = () => [...(this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
+        childDocFilters = () => [...(this.props.childFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
         // unrecursive filters apply to the documents in the collection, but no their children.  See Utils.noRecursionHack
-        unrecursiveDocFilters = () => [...(this.props.docFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
-        childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()];
+        unrecursiveDocFilters = () => [...(this.props.childFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
+        childDocRangeFilters = () => [...(this.props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()];
         searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
         @computed.struct get childDocs() {
             TraceMobx();
@@ -109,20 +109,20 @@ export function CollectionSubView<X>(moreProps?: X) {
             const childDocs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && (this.props.ignoreUnrendered || !d.layout_unrendered)).map(d => d as Doc);
 
             const childDocFilters = this.childDocFilters();
-            const docRangeFilters = this.childDocRangeFilters();
+            const childFiltersByRanges = this.childDocRangeFilters();
             const searchDocs = this.searchFilterDocs();
-            if (this.props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !docRangeFilters.length && !searchDocs.length)) {
+            if (this.props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) {
                 return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one
             }
 
             const docsforFilter: Doc[] = [];
             childDocs.forEach(d => {
                 // dragging facets
-                const dragged = this.props.docFilters?.().some(f => f.includes(Utils.noDragsDocFilter));
+                const dragged = this.props.childFilters?.().some(f => f.includes(Utils.noDragsDocFilter));
                 if (dragged && DragManager.docsBeingDragged.includes(d)) return false;
-                let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), docRangeFilters, this.props.Document).length > 0;
+                let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.props.Document).length > 0;
                 if (notFiltered) {
-                    notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, docRangeFilters, this.props.Document).length > 0;
+                    notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this.props.Document).length > 0;
                     const fieldKey = Doc.LayoutFieldKey(d);
                     const annos = !Field.toString(Doc.LayoutField(d) as Field).includes(CollectionView.name);
                     const data = d[annos ? fieldKey + '_annotations' : fieldKey];
@@ -131,13 +131,14 @@ export function CollectionSubView<X>(moreProps?: X) {
                         let subDocs = [...DocListCast(data), ...DocListCast(side)];
                         if (subDocs.length > 0) {
                             let newarray: Doc[] = [];
-                            notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, childDocFilters, docRangeFilters, d).length);
+                            notFiltered = notFiltered || (!searchDocs.length && DocUtils.FilterDocs(subDocs, childDocFilters, childFiltersByRanges, d).length);
                             while (subDocs.length > 0 && !notFiltered) {
                                 newarray = [];
                                 subDocs.forEach(t => {
                                     const fieldKey = Doc.LayoutFieldKey(t);
                                     const annos = !Field.toString(Doc.LayoutField(t) as Field).includes(CollectionView.name);
-                                    notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], childDocFilters, docRangeFilters, d).length));
+                                    notFiltered =
+                                        notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !childFiltersByRanges.length) || DocUtils.FilterDocs([t], childDocFilters, childFiltersByRanges, d).length));
                                     DocListCast(t[annos ? fieldKey + '_annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc));
                                     annos && DocListCast(t[fieldKey + '_sidebar']).forEach(newdoc => newarray.push(newdoc));
                                 });
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 49a90d828..60e6815e5 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -125,8 +125,8 @@ export class CollectionTimeView extends CollectionSubView() {
 
     goTo = (prevFilterIndex: number) => {
         this.layoutDoc._pivotField = this.layoutDoc['_prevPivotFields' + prevFilterIndex];
-        this.layoutDoc._docFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocFilter' + prevFilterIndex] as ObjectField);
-        this.layoutDoc._docRangeFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocRangeFilters' + prevFilterIndex] as ObjectField);
+        this.layoutDoc._childFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocFilter' + prevFilterIndex] as ObjectField);
+        this.layoutDoc._childFiltersByRanges = ObjectField.MakeCopy(this.layoutDoc['_prevDocRangeFilters' + prevFilterIndex] as ObjectField);
         this.layoutDoc._prevFilterIndex = prevFilterIndex;
     };
 
@@ -136,7 +136,7 @@ export class CollectionTimeView extends CollectionSubView() {
         if (prevFilterIndex > 0) {
             this.goTo(prevFilterIndex - 1);
         } else {
-            this.layoutDoc._docFilters = new List([]);
+            this.layoutDoc._childFilters = new List([]);
         }
     };
 
@@ -145,7 +145,7 @@ export class CollectionTimeView extends CollectionSubView() {
             <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this.props.isContentActive() ? undefined : 'none' }} onClick={this.contentsDown}>
                 <CollectionFreeFormView
                     {...this.props}
-                    engineProps={{ pivotField: this.pivotField, docFilters: this.childDocFilters, docRangeFilters: this.childDocRangeFilters }}
+                    engineProps={{ pivotField: this.pivotField, childFilters: this.childDocFilters, childFiltersByRanges: this.childDocRangeFilters }}
                     fitContentsToBox={returnTrue}
                     childClickScript={this._childClickedScript}
                     viewDefDivClick={this.layoutEngine() === computeTimelineLayout.name ? undefined : this._viewDefDivClick}
@@ -276,12 +276,12 @@ export class CollectionTimeView extends CollectionSubView() {
 ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) {
     const pivotField = StrCast(pivotDoc._pivotField, 'author');
     let prevFilterIndex = NumCast(pivotDoc._prevFilterIndex);
-    const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField));
-    pivotDoc['_prevDocFilter' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField);
-    pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField);
+    const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._childFilters as ObjectField));
+    pivotDoc['_prevDocFilter' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._childFilters as ObjectField);
+    pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._childFiltersByRanges as ObjectField);
     pivotDoc['_prevPivotFields' + prevFilterIndex] = pivotField;
     pivotDoc._prevFilterIndex = ++prevFilterIndex;
-    pivotDoc._docFilters = new List();
+    pivotDoc._childFilters = new List();
     setTimeout(
         action(() => {
             const filterVals = bounds.payload as string[];
@@ -292,7 +292,7 @@ ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBou
                     pivotDoc._pivotField = filterVals[0];
                 }
             }
-            const newFilters = StrListCast(pivotDoc._docFilters);
+            const newFilters = StrListCast(pivotDoc._childFilters);
             if (newFilters.length && originalFilter.length && newFilters.lastElement() === originalFilter.lastElement()) {
                 pivotDoc._prevFilterIndex = --prevFilterIndex;
                 pivotDoc['_prevDocFilter' + prevFilterIndex] = undefined;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 969658238..ed1e0c067 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -240,8 +240,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 PanelHeight={this.documentTitleHeight}
                 NativeDimScaling={returnOne}
                 onKey={this.onKey}
-                docFilters={returnEmptyFilter}
-                docRangeFilters={returnEmptyFilter}
+                childFilters={returnEmptyFilter}
+                childFiltersByRanges={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
                 addDocument={returnFalse}
                 moveDocument={returnFalse}
@@ -314,12 +314,12 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
     }
 
     @computed get noviceExplainer() {
-        return !Doc.noviceMode || !this.rootDoc.explainer ? null : <div className="documentExplanation"> {StrCast(this.rootDoc.explainer)} </div>;
+        return !Doc.noviceMode || !this.rootDoc.layout_explainer ? null : <div className="documentExplanation"> {StrCast(this.rootDoc.layout_explainer)} </div>;
     }
 
     return35 = () => 35;
     @computed get buttonMenu() {
-        const menuDoc = Cast(this.rootDoc.buttonMenuDoc, Doc, null);
+        const menuDoc = Cast(this.rootDoc.layout_headerButton, Doc, null);
         // To create a multibutton menu add a CollectionLinearView
         return !menuDoc ? null : (
             <div className="buttonMenu-docBtn" style={{ width: NumCast(menuDoc._width, 30), height: NumCast(menuDoc._height, 30) }}>
@@ -343,8 +343,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={this.props.docFilters}
-                    docRangeFilters={this.props.docRangeFilters}
+                    childFilters={this.props.childFilters}
+                    childFiltersByRanges={this.props.childFiltersByRanges}
                     searchFilterDocs={this.props.searchFilterDocs}
                 />
             </div>
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 710e33b1c..75e4e8abf 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -432,8 +432,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     PanelWidth={this.PanelWidth}
                     PanelHeight={this.PanelHeight}
                     styleProvider={DefaultStyleProvider}
-                    docFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
-                    docRangeFilters={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
+                    childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
+                    childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
                     searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
                     addDocument={undefined}
                     removeDocument={this.remDocTab}
@@ -602,8 +602,8 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     styleProvider={TabMinimapView.miniStyleProvider}
                     addDocTab={this.props.addDocTab}
                     pinToPres={TabDocView.PinDoc}
-                    docFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
-                    docRangeFilters={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
+                    childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
+                    childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
                     searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
                     fitContentsToBox={returnTrue}
                 />
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index ca9471f6f..9039875c1 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -119,7 +119,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return 'TreeView(' + this.props.document.title + ')';
     } // this makes mobx trace() statements more descriptive
     get defaultExpandedView() {
-        return this.doc.type_collection === CollectionViewType.Docking
+        return this.doc._type_collection === CollectionViewType.Docking
             ? this.fieldKey
             : this.props.treeView.dashboardMode
             ? this.fieldKey
@@ -388,7 +388,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         };
         const addDoc = inside ? localAdd : parentAddDoc;
         const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument;
-        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.freezeChildren).includes('add')) || forceAdd;
+        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeViewFreezeChildren).includes('add')) || forceAdd;
         if (canAdd) {
             this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true);
             const res = UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false));
@@ -714,7 +714,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const data = () => (this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : '');
         const embeddings = () => (this.props.treeView.dashboardMode ? '' : 'embeddings');
         const fields = () => (Doc.noviceMode ? '' : 'fields');
-        const layout = Doc.noviceMode || this.doc.type_collection === CollectionViewType.Docking ? [] : ['layout'];
+        const layout = Doc.noviceMode || this.doc._type_collection === CollectionViewType.Docking ? [] : ['layout'];
         return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [embeddings(), links(), annos()] : []), fields()].filter(m => m);
     }
     @action
@@ -732,7 +732,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : (
             <>
                 {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */}
-                {this.doc.hideContextMenu ? null : (
+                {this.doc._layout_hideContextMenu ? null : (
                     <FontAwesomeIcon
                         title="context menu"
                         key="bars"
@@ -772,7 +772,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 ? []
                 : this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc)
                 ? [openEmbedding, makeFolder]
-                : this.doc.type_collection === CollectionViewType.Docking
+                : this.doc._type_collection === CollectionViewType.Docking
                 ? []
                 : [deleteItem, openEmbedding, focusDoc]),
         ];
@@ -930,13 +930,13 @@ export class TreeView extends React.Component<TreeViewProps> {
                 focus={this.refocus}
                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                 bringToFront={emptyFunction}
-                disableDocBrushing={this.props.treeView.props.disableDocBrushing}
+                disableBrushing={this.props.treeView.props.disableBrushing}
                 hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)}
                 dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)}
                 xPadding={NumCast(this.props.treeView.props.Document.childXPadding, this.props.treeView.props.childXPadding)}
                 yPadding={NumCast(this.props.treeView.props.Document.childYPadding, this.props.treeView.props.childYPadding)}
-                docFilters={returnEmptyFilter}
-                docRangeFilters={returnEmptyFilter}
+                childFilters={returnEmptyFilter}
+                childFiltersByRanges={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
             />
         );
@@ -1010,8 +1010,8 @@ export class TreeView extends React.Component<TreeViewProps> {
                     treeViewDoc={this.props.treeView?.props.Document}
                     rootSelected={returnTrue}
                     docViewPath={this.props.treeView.props.docViewPath}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     addDocument={this.props.addDocument}
                     moveDocument={this.move}
@@ -1021,7 +1021,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     yPadding={NumCast(this.props.treeView.props.Document.childYPadding, this.props.treeView.props.childYPadding)}
                     addDocTab={this.props.addDocTab}
                     pinToPres={this.props.treeView.props.pinToPres}
-                    disableDocBrushing={this.props.treeView.props.disableDocBrushing}
+                    disableBrushing={this.props.treeView.props.disableBrushing}
                     bringToFront={returnFalse}
                     scriptContext={this}
                 />
@@ -1211,7 +1211,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         onCheckedClick={onCheckedClick}
                         onChildClick={onChildClick}
                         renderDepth={renderDepth}
-                        removeDoc={StrCast(treeViewParent.freezeChildren).includes('remove') ? undefined : remove}
+                        removeDoc={StrCast(treeViewParent.treeViewFreezeChildren).includes('remove') ? undefined : remove}
                         addDocument={addDocument}
                         styleProvider={styleProvider}
                         panelWidth={rowWidth}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 6202dcacc..f1d98d22a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -59,7 +59,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             0
         ); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render()
         setTimeout(
-            action(() => (!LinkDocs.length || !linkDoc.layout_linkDisplay) && (this._opacity = 0.05)),
+            action(() => (!LinkDocs.length || !linkDoc.link_displayLine) && (this._opacity = 0.05)),
             750
         ); // this will unhighlight the link line.
         const a = A.ContentDiv.getBoundingClientRect();
@@ -77,7 +77,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const targetBhyperlink = Array.from(window.document.getElementsByClassName((linkDoc.link_anchor_2 as Doc)[Id])).lastElement();
         if ((!targetAhyperlink && !a.width) || (!targetBhyperlink && !b.width)) return;
         if (!targetAhyperlink) {
-            if (linkDoc.layout_autoMoveAnchors) {
+            if (linkDoc.link_autoMoveAnchors) {
                 linkDoc.link_anchor_1_x = ((apt.point.x - aleft) / awidth) * 100;
                 linkDoc.link_anchor_1_y = ((apt.point.y - atop) / aheight) * 100;
             }
@@ -92,7 +92,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             else linkDoc.opacity = 1;
         }
         if (!targetBhyperlink) {
-            if (linkDoc.layout_autoMoveAnchors) {
+            if (linkDoc.link_autoMoveAnchors) {
                 linkDoc.link_anchor_2_x = ((bpt.point.x - bleft) / bwidth) * 100;
                 linkDoc.link_anchor_2_y = ((bpt.point.y - btop) / bheight) * 100;
             }
@@ -247,7 +247,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData;
         const linkRelationship = Field.toString(link?.link_relationship as any as Field); //get string representing relationship
         const linkRelationshipList = Doc.UserDoc().link_relationshipList as List<string>;
-        const linkColorList = Doc.UserDoc().linkColorList as List<string>;
+        const linkColorList = Doc.UserDoc().link_ColorList as List<string>;
         const linkRelationshipSizes = Doc.UserDoc().link_relationshipSizes as List<number>;
         const currRelationshipIndex = linkRelationshipList.indexOf(linkRelationship);
         const linkDescription = Field.toString(link.link_description as any as Field);
@@ -262,11 +262,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         //thickness varies linearly from 3px to 12px for increasing link count
         const strokeWidth = linkSize === -1 ? '3px' : Math.floor(2 + 10 * (linkSize / Math.max(...linkRelationshipSizes))) + 'px';
 
-        if (link.layout_linkDisplayArrow === undefined) {
-            link.layout_linkDisplayArrow = false;
+        if (link.link_displayArrow === undefined) {
+            link.link_displayArrow = false;
         }
 
-        return link.opacity === 0 || !a.width || !b.width || (!link.layout_linkDisplay && !aActive && !bActive) ? null : (
+        return link.opacity === 0 || !a.width || !b.width || (!link.link_displayLine && !aActive && !bActive) ? null : (
             <>
                 <defs>
                     <marker id={`${link[Id] + 'arrowhead'}`} markerWidth="4" markerHeight="3" refX="0" refY="1.5" orient="auto">
@@ -295,7 +295,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
                     style={{ pointerEvents: 'visibleStroke', opacity: this._opacity, stroke, strokeWidth }}
                     onClick={this.onClickLine}
                     d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`}
-                    markerEnd={link.layout_linkDisplayArrow ? `url(#${link[Id] + 'arrowhead'})` : ''}
+                    markerEnd={link.link_displayArrow ? `url(#${link[Id] + 'arrowhead'})` : ''}
                 />
                 {textX === undefined || !linkDescription ? null : (
                     <text filter={`url(#${link[Id] + 'background'})`} className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown}>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 811a77fa8..11151e74e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1021,7 +1021,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     zoom = (pointX: number, pointY: number, deltaY: number): void => {
-        if (this.Document._isGroup) return;
+        if (this.Document._isGroup || this.Document._freeform_noZoom) return;
         let deltaScale = deltaY > 0 ? 1 / 1.05 : 1.05;
         if (deltaScale < 0) deltaScale = -deltaScale;
         const [x, y] = this.getTransform().transformPoint(pointX, pointY);
@@ -1294,8 +1294,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 ScreenToLocalTransform={childLayout.z ? this.getContainerTransform : this.getTransform}
                 PanelWidth={childLayout[Width]}
                 PanelHeight={childLayout[Height]}
-                docFilters={this.childDocFilters}
-                docRangeFilters={this.childDocRangeFilters}
+                childFilters={this.childDocFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
                 isContentActive={this.props.childContentsActive ?? emptyFunction}
@@ -1317,7 +1317,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 dontRegisterView={this.props.dontRenderDocuments || this.props.dontRegisterView}
                 pointerEvents={this.pointerEvents}
                 //rotation={this.props.styleProvider?.(childLayout, this.props, StyleProp.JitterRotation) || 0}
-                //fitContentsToBox={this.props.fitContentsToBox || BoolCast(this.props.freezeChildDimensions)} // bcz: check this
+                //fitContentsToBox={this.props.fitContentsToBox || BoolCast(this.props.treeViewFreezeChildDimensions)} // bcz: check this
             />
         );
     }
@@ -1692,7 +1692,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if ((e as any).handlePan || this.props.isAnnotationOverlay) return;
         (e as any).handlePan = true;
 
-        if (!this.layoutDoc._noAutoscroll && !this.props.renderDepth && this._marqueeRef) {
+        if (!this.layoutDoc._freeform_noAutoPan && !this.props.renderDepth && this._marqueeRef) {
             const dragX = e.detail.clientX;
             const dragY = e.detail.clientY;
             const bounds = this._marqueeRef?.getBoundingClientRect();
@@ -2007,8 +2007,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                             onKey={this.onKeyDown}
                             onDoubleClick={this.onChildDoubleClickHandler}
                             onBrowseClick={this.onBrowseClickHandler}
-                            docFilters={this.childDocFilters}
-                            docRangeFilters={this.childDocRangeFilters}
+                            childFilters={this.childDocFilters}
+                            childFiltersByRanges={this.childDocRangeFilters}
                             searchFilterDocs={this.searchFilterDocs}
                             isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
                             isContentActive={this.props.childContentsActive ?? emptyFunction}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index d50c8d2c4..534275610 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -522,7 +522,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             followLinkToggle: true,
             _width: 200,
             _height: 200,
-            _layoutFitContentsToBox: true,
+            _layout_fitContentsToBox: true,
             _layout_showSidebar: true,
             title: 'overview',
         });
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index ca6b8705d..65578f214 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -24,7 +24,7 @@ import './CollectionLinearView.scss';
 /**
  * CollectionLinearView is the class for rendering the horizontal collection
  * of documents, it useful for horizontal menus. It can either be expandable
- * or not using the linearViewExpandable field.
+ * or not using the linearView_Expandable field.
  * It is used in the following locations:
  * - It is used in the popup menu on the bottom left (see docButtons() in MainView.tsx)
  * - It is used for the context sensitive toolbar at the top (see contMenuButtons() in CollectionMenu.tsx)
@@ -46,7 +46,7 @@ export class CollectionLinearView extends CollectionSubView() {
 
     componentDidMount() {
         this._widthDisposer = reaction(
-            () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[Width]() || this.dimension()) + tot + 4, 0) : 0),
+            () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsExpanded ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[Width]() || this.dimension()) + tot + 4, 0) : 0),
             width => this.childDocs.length && (this.layoutDoc._width = width),
             { fireImmediately: true }
         );
@@ -214,8 +214,8 @@ export class CollectionLinearView extends CollectionSubView() {
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={this.props.docFilters}
-                    docRangeFilters={this.props.docRangeFilters}
+                    childFilters={this.props.childFilters}
+                    childFiltersByRanges={this.props.childFiltersByRanges}
                     searchFilterDocs={this.props.searchFilterDocs}
                     hideResizeHandles={true}
                 />
@@ -226,7 +226,7 @@ export class CollectionLinearView extends CollectionSubView() {
     render() {
         const flexDir = StrCast(this.Document.flexDirection); // Specify direction of linear view content
         const flexGap = NumCast(this.Document.flexGap); // Specify the gap between linear view content
-        const isExpanded = BoolCast(this.layoutDoc.linearViewIsExpanded);
+        const isExpanded = BoolCast(this.layoutDoc.linearView_IsExpanded);
 
         const menuOpener = (
             <label
@@ -239,9 +239,9 @@ export class CollectionLinearView extends CollectionSubView() {
         );
 
         return (
-            <div className={`collectionLinearView-outer ${this.layoutDoc.linearViewSubMenu}`} style={{ backgroundColor: this.layoutDoc.linearViewIsExpanded ? undefined : 'transparent' }}>
+            <div className={`collectionLinearView-outer ${this.layoutDoc.linearView_SubMenu}`} style={{ backgroundColor: this.layoutDoc.linearView_IsExpanded ? undefined : 'transparent' }}>
                 <div className="collectionLinearView" ref={this.createDashEventsTarget} onContextMenu={this.myContextMenu} style={{ minHeight: this.dimension() }}>
-                    {!this.props.Document.linearViewExpandable ? null : (
+                    {!this.props.Document.linearView_Expandable ? null : (
                         <Tooltip title={<div className="dash-tooltip">{isExpanded ? 'Close' : 'Open'}</div>} placement="top">
                             {menuOpener}
                         </Tooltip>
@@ -259,11 +259,11 @@ export class CollectionLinearView extends CollectionSubView() {
                                 scriptContext: this.props.scriptContext,
                                 documentView: this.props.DocumentView?.(),
                             });
-                            this.layoutDoc.linearViewIsExpanded = this.addMenuToggle.current!.checked;
+                            this.layoutDoc.linearView_IsExpanded = this.addMenuToggle.current!.checked;
                         })}
                     />
 
-                    {!this.layoutDoc.linearViewIsExpanded ? null : (
+                    {!this.layoutDoc.linearView_IsExpanded ? null : (
                         <div
                             className="collectionLinearView-content"
                             style={{
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 78d3d1b6e..34fa0343d 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -259,8 +259,8 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 fitContentsToBox={this.props.fitContentsToBox}
                 focus={this.props.focus}
-                docFilters={this.childDocFilters}
-                docRangeFilters={this.childDocRangeFilters}
+                childFilters={this.childDocFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 4d61dc272..bab77ed48 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -258,8 +258,8 @@ export class CollectionMultirowView extends CollectionSubView() {
                 hideDecorationTitle={this.props.childHideDecorationTitle?.()}
                 fitContentsToBox={this.props.fitContentsToBox}
                 focus={this.props.focus}
-                docFilters={this.childDocFilters}
-                docRangeFilters={this.childDocRangeFilters}
+                childFilters={this.childDocFilters}
+                childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 3a0c2c85c..52ebb7763 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -104,7 +104,7 @@
 
 .schema-header-row {
     cursor: grab;
-    justify-content: flex-end;
+    //justify-content: flex-end;
 
     .row-menu {
         display: flex;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 36abad87e..15424de98 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -32,6 +32,7 @@ export enum ColumnType {
     Date,
     Image,
     RTF,
+    Enumeration,
     Any,
 }
 
@@ -42,6 +43,7 @@ export const FInfotoColType: { [key: string]: ColumnType } = {
     date: ColumnType.Date,
     image: ColumnType.Image,
     rtf: ColumnType.RTF,
+    enumeration: ColumnType.Enumeration,
 };
 
 const defaultColumnKeys: string[] = ['title', 'type', 'author', 'author_date', 'text'];
@@ -54,6 +56,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _makeNewColumn: boolean = false;
     private _documentOptions: DocumentOptions = new DocumentOptions();
     private _tableContentRef: HTMLDivElement | null = null;
+    private _menuTarget = React.createRef<HTMLDivElement>();
 
     static _rowHeight: number = 50;
     static _rowSingleLineHeight: number = 32;
@@ -77,6 +80,11 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _filterSearchValue: string = '';
     @observable _selectedCell: [Doc, number] | undefined;
 
+    // target HTMLelement portal for showing a popup menu to edit cell values.
+    public get MenuTarget() {
+        return this._menuTarget.current;
+    }
+
     @computed get _selectedDocs() {
         return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.rootDoc));
     }
@@ -336,9 +344,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     dragColumn = (e: PointerEvent, index: number) => {
         const dragData = new DragManager.ColumnDragData(index);
         const dragEles = [this._colEles[index]];
-        this.childDocs.forEach(doc => {
-            dragEles.push(this._rowEles.get(doc).children[1].children[index]);
-        });
+        this.childDocs.forEach(doc => dragEles.push(this._rowEles.get(doc).children[1].children[index]));
         DragManager.StartColumnDrag(dragEles, dragData, e.x, e.y);
 
         document.removeEventListener('pointermove', this.highlightDropColumn);
@@ -352,24 +358,28 @@ export class CollectionSchemaView extends CollectionSubView() {
         return true;
     };
 
-    @action
-    highlightDropColumn = (e: PointerEvent) => {
-        e.stopPropagation();
-        const mouseX = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0];
+    findDropIndex = (mouseX: number) => {
         let index: number | undefined;
         this.displayColumnWidths.reduce((total, curr, i) => {
             if (total <= mouseX && total + curr >= mouseX) {
-                if (mouseX <= total + curr / 2) index = i;
+                if (mouseX <= total + curr) index = i;
                 else index = i + 1;
             }
             return total + curr;
         }, CollectionSchemaView._rowMenuWidth);
+        return index;
+    };
 
+    @action
+    highlightDropColumn = (e: PointerEvent) => {
+        e.stopPropagation();
+        const mouseX = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0];
+        const index = this.findDropIndex(mouseX);
         this._colEles.forEach((colRef, i) => {
             let leftStyle = '';
             let rightStyle = '';
-            if (i + 1 === index) rightStyle = `solid 2px ${Colors.MEDIUM_BLUE}`;
-            if (i === index && i === 0) leftStyle = `solid 2px ${Colors.MEDIUM_BLUE}`;
+            if (i + 1 === index) rightStyle = `solid 12px ${Colors.MEDIUM_BLUE}`;
+            if (i === index && i === 0) leftStyle = `solid 12px ${Colors.MEDIUM_BLUE}`;
             colRef.style.borderLeft = leftStyle;
             colRef.style.borderRight = rightStyle;
             this.childDocs.forEach(doc => {
@@ -426,15 +436,8 @@ export class CollectionSchemaView extends CollectionSubView() {
         if (de.complete.columnDragData) {
             e.stopPropagation();
             const mouseX = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0];
-            let index = de.complete.columnDragData.colIndex;
-            this.displayColumnWidths.reduce((total, curr, i) => {
-                if (total <= mouseX && total + curr >= mouseX) {
-                    if (mouseX <= total + curr / 2) index = i;
-                    else index = i + 1;
-                }
-                return total + curr;
-            }, CollectionSchemaView._rowMenuWidth);
-            this.moveColumn(de.complete.columnDragData.colIndex, index);
+            const index = this.findDropIndex(mouseX);
+            this.moveColumn(de.complete.columnDragData.colIndex, index ?? de.complete.columnDragData.colIndex);
 
             this._colEles.forEach((colRef, i) => {
                 colRef.style.borderLeft = '';
@@ -607,7 +610,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._menuKeys = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
-    getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
+    getFieldFilters = (field: string) => StrListCast(this.Document._childFilters).filter(filter => filter.split(':')[0] == field);
 
     removeFieldFilters = (field: string) => {
         this.getFieldFilters(field).forEach(filter => Doc.setDocFilter(this.Document, field, filter.split(':')[1], 'remove'));
@@ -760,7 +763,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             }
         });
 
-        const filters = StrListCast(this.Document._docFilters);
+        const filters = StrListCast(this.Document._childFilters);
         return keyOptions.map(key => {
             let bool = false;
             if (filters !== undefined) {
@@ -832,6 +835,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     render() {
         return (
             <div className="collectionSchemaView" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} onDrop={this.onExternalDrop.bind(this)}>
+                <div ref={this._menuTarget} style={{ background: 'red', top: 0, left: 0, position: 'absolute', zIndex: 10000 }}></div>
                 <div
                     className="schema-table"
                     onWheel={e => this.props.isContentActive() && e.stopPropagation()}
@@ -860,6 +864,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 openContextMenu={this.openContextMenu}
                                 dragColumn={this.dragColumn}
                                 setColRef={this.setColRef}
+                                isContentActive={this.props.isContentActive}
                             />
                         ))}
                     </div>
@@ -894,8 +899,8 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 isContentActive={returnTrue}
                                 isDocumentActive={returnFalse}
                                 ScreenToLocalTransform={this.screenToLocal}
-                                docFilters={this.childDocFilters}
-                                docRangeFilters={this.childDocRangeFilters}
+                                childFilters={this.childDocFilters}
+                                childFiltersByRanges={this.childDocRangeFilters}
                                 searchFilterDocs={this.searchFilterDocs}
                                 styleProvider={DefaultStyleProvider}
                                 docViewPath={returnEmptyDoclist}
@@ -940,6 +945,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 LayoutTemplateString={SchemaRowBox.LayoutString(this.props.schema.props.fieldKey)}
                                 Document={doc}
                                 DataDoc={dataDoc}
+                                yPadding={index}
                                 renderDepth={this.props.schema.props.renderDepth + 1}
                                 PanelWidth={this.tableWidthFunc}
                                 PanelHeight={this.props.rowHeight}
@@ -949,8 +955,8 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 enableDragWhenActive={true}
                                 onClickScriptDisable="always"
                                 focus={this.props.schema.focusDocument}
-                                docFilters={this.props.schema.childDocFilters}
-                                docRangeFilters={this.props.schema.childDocRangeFilters}
+                                childFilters={this.props.schema.childDocFilters}
+                                childFiltersByRanges={this.props.schema.childDocRangeFilters}
                                 searchFilterDocs={this.props.schema.searchFilterDocs}
                                 rootSelected={this.props.schema.rootSelected}
                                 ScreenToLocalTransform={this.childScreenToLocal(index)}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 46c2f622b..65e47f441 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -12,6 +12,7 @@ export interface SchemaColumnHeaderProps {
     columnIndex: number;
     sortField: string;
     sortDesc: boolean;
+    isContentActive: (outsideReaction?: boolean | undefined) => boolean | undefined;
     setSort: (field: string | undefined, desc?: boolean) => void;
     removeColumn: (index: number) => void;
     rowHeight: () => number;
@@ -44,7 +45,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
 
     @action
     onPointerDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction, false);
+        this.props.isContentActive(true) && setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction, false);
     };
 
     render() {
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 978b65053..4f3503751 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -7,7 +7,7 @@ import { Doc } from '../../../../fields/Doc';
 import { BoolCast } from '../../../../fields/Types';
 import { DragManager } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
-import { undoable, undoBatch } from '../../../util/UndoManager';
+import { undoable } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
 import { OpenWhere } from '../../nodes/DocumentView';
@@ -15,6 +15,7 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
+import { Transform } from '../../../util/Transform';
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -143,6 +144,13 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             selectedCell={this.selectedCell}
                             setColumnValues={this.setColumnValues}
                             oneLine={BoolCast(this.schemaDoc?._singleLine)}
+                            menuTarget={this.schemaView.MenuTarget}
+                            transform={() => {
+                                const ind = index === this.schemaView.columnKeys.length - 1 ? this.schemaView.columnKeys.length - 3 : index;
+                                const x = this.schemaView?.displayColumnWidths.reduce((p, c, i) => (i <= ind ? p + c : p), 0);
+                                const y = (this.props.yPadding ?? 0) * this.props.PanelHeight();
+                                return new Transform(x + CollectionSchemaView._rowMenuWidth, y, 1);
+                            }}
                         />
                     ))}
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 876693474..97264508c 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,4 +1,5 @@
-import React = require('react');
+import * as React from 'react';
+import Select, { MenuPlacement } from 'react-select';
 import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { extname } from 'path';
@@ -6,12 +7,11 @@ import DatePicker from 'react-datepicker';
 import { DateField } from '../../../../fields/DateField';
 import { Doc, DocListCast, Field } from '../../../../fields/Doc';
 import { RichTextField } from '../../../../fields/RichTextField';
-import { BoolCast, Cast, DateCast, DocCast, FieldValue } from '../../../../fields/Types';
+import { BoolCast, Cast, DateCast, DocCast, FieldValue, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
 import { FInfo } from '../../../documents/Documents';
 import { DocFocusOrOpen } from '../../../util/DocumentManager';
-import { dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoable, undoBatch } from '../../../util/UndoManager';
 import { EditableView } from '../../EditableView';
@@ -21,7 +21,7 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
-import { ColumnType, FInfotoColType } from './CollectionSchemaView';
+import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 
 export interface SchemaTableCellProps {
@@ -41,6 +41,9 @@ export interface SchemaTableCellProps {
     oneLine?: boolean; // whether all input should fit on one line vs allowing textare multiline inputs
     allowCRs?: boolean; // allow carriage returns in text input (othewrise CR ends the edit)
     finishEdit?: () => void; // notify container that edit is over (eg. to hide view in DashFieldView)
+    options?: string[];
+    menuTarget: HTMLDivElement | null;
+    transform: () => Transform;
 }
 
 @observer
@@ -64,8 +67,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         const color = protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue';
         const textDecoration = color !== 'black' && parenCount ? 'underline' : '';
         const fieldProps: FieldViewProps = {
-            docFilters: returnEmptyFilter,
-            docRangeFilters: returnEmptyFilter,
+            childFilters: returnEmptyFilter,
+            childFiltersByRanges: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
@@ -129,15 +132,15 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     }
 
     get getCellType() {
+        const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
         const cellValue = this.props.Document[this.props.fieldKey];
         if (cellValue instanceof ImageField) return ColumnType.Image;
         if (cellValue instanceof DateField) return ColumnType.Date;
         if (cellValue instanceof RichTextField) return ColumnType.RTF;
         if (typeof cellValue === 'number') return ColumnType.Any;
-        if (typeof cellValue === 'string') return ColumnType.Any;
+        if (typeof cellValue === 'string' && columnTypeStr !== 'enumeration') return ColumnType.Any;
         if (typeof cellValue === 'boolean') return ColumnType.Boolean;
 
-        const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
         if (columnTypeStr && columnTypeStr in FInfotoColType) {
             return FInfotoColType[columnTypeStr];
         }
@@ -152,6 +155,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             case ColumnType.Image: return <SchemaImageCell {...this.props} />;
             case ColumnType.Boolean: return <SchemaBoolCell {...this.props} />;
             case ColumnType.RTF: return <SchemaRTFCell {...this.props} />;
+            case ColumnType.Enumeration: return <SchemaEnumerationCell {...this.props} options={this.props.getFinfo(this.props.fieldKey)?.values?.map(val => val.toString())} />;
             case ColumnType.Date: // return <SchemaDateCell {...this.props} />;
             default:  return this.defaultCellContent;
         }
@@ -311,3 +315,38 @@ export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
         );
     }
 }
+@observer
+export class SchemaEnumerationCell extends React.Component<SchemaTableCellProps> {
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
+        return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+    }
+    render() {
+        const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this.props);
+        const options = this.props.options?.map(facet => ({ value: facet, label: facet }));
+        return (
+            <div className="schemaSelectionCell" style={{ display: 'flex', color, textDecoration, cursor, pointerEvents }}>
+                <div style={{ width: '100%' }}>
+                    <Select
+                        styles={{
+                            menuPortal: base => ({
+                                ...base,
+                                left: 0,
+                                top: 0,
+                                transform: `translate(${this.props.transform().TranslateX}px, ${this.props.transform().TranslateY}px)`,
+                                width: Number(base.width) * this.props.transform().Scale,
+                                zIndex: 9999,
+                            }),
+                        }}
+                        menuPortalTarget={this.props.menuTarget}
+                        menuPosition={'absolute'}
+                        placeholder={StrCast(this.props.Document[this.props.fieldKey], 'select...')}
+                        options={options}
+                        isMulti={false}
+                        onChange={val => KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), `"${val?.value ?? ''}"`)}
+                    />
+                </div>
+            </div>
+        );
+    }
+}
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index b9d56541a..8324a97d9 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -25,7 +25,7 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
 
     getBackgroundColor = (): string => {
         const link_relationshipList = StrListCast(Doc.UserDoc().link_relationshipList);
-        const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
+        const linkColorList = StrListCast(Doc.UserDoc().link_ColorList);
         let color = 'white';
         // if this link's relationship property is not default "link", set its color
         if (link_relationshipList) {
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 5f2d4a7b6..664a0fa4f 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -89,8 +89,8 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                     />
                 </div>
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 60480ac33..d84e34d52 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -57,7 +57,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                             DragManager.StartAnchorAnnoDrag([header.current!], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, {
                                                                 dragComplete: e => {
                                                                     if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
-                                                                        e.linkDocument.layout_linkDisplay = true;
+                                                                        e.linkDocument.link_displayLine = true;
                                                                         // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc;
                                                                         // e.annoDragData.linkSourceDoc.followLinkZoom = false;
                                                                     }
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index bd1952ecb..7723a088d 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -71,7 +71,9 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             e,
             this.onLinkButtonMoved,
             emptyFunction,
-            action((e, doubleTap) => doubleTap && DocumentView.showBackLinks(this.props.View.rootDoc)),
+            action((e, doubleTap) => {
+                doubleTap && DocumentView.showBackLinks(this.props.View.rootDoc);
+            }),
             undefined,
             undefined,
             action(() => (DocumentLinksButton.LinkEditorDocView = this.props.View))
@@ -191,7 +193,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
 
     @computed get filteredLinks() {
         const results = [] as Doc[];
-        const filters = this.props.View.props.docFilters();
+        const filters = this.props.View.props.childFilters();
         Array.from(new Set<Doc>(this.props.View.allLinks)).forEach(link => {
             if (DocUtils.FilterDocs([link], filters, []).length || DocUtils.FilterDocs([link.link_anchor_2 as Doc], filters, []).length || DocUtils.FilterDocs([link.link_anchor_1 as Doc], filters, []).length) {
                 results.push(link);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 687683e6e..461066b1b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -168,8 +168,8 @@ export interface DocumentViewSharedProps {
     setTitleFocus?: () => void;
     focus: DocFocusFunc;
     layout_fitWidth?: (doc: Doc) => boolean | undefined;
-    docFilters: () => string[];
-    docRangeFilters: () => string[];
+    childFilters: () => string[];
+    childFiltersByRanges: () => string[];
     searchFilterDocs: () => Doc[];
     layout_showTitle?: () => string;
     whenChildContentsActiveChanged: (isActive: boolean) => void;
@@ -192,7 +192,7 @@ export interface DocumentViewSharedProps {
     hideCaptions?: boolean;
     ignoreAutoHeight?: boolean;
     forceAutoHeight?: boolean;
-    disableDocBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
+    disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
     onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected
     enableDragWhenActive?: boolean;
     waitForDoubleClickToClick?: () => 'never' | 'always' | undefined;
@@ -664,7 +664,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     @action
     onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => {
-        if (e && this.rootDoc._hideContextMenu && Doc.noviceMode) {
+        if (e && this.rootDoc._layout_hideContextMenu && Doc.noviceMode) {
             e.preventDefault();
             e.stopPropagation();
             //!this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false);
@@ -880,7 +880,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             ? true
             : false;
     };
-    docFilters = () => [...this.props.docFilters(), ...StrListCast(this.layoutDoc.docFilters)];
+    childFilters = () => [...this.props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)];
     contentPointerEvents = () => (!this.disableClickScriptFunc && this.onClickHandler ? 'none' : this.pointerEvents);
     @computed get contents() {
         TraceMobx();
@@ -912,7 +912,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     docViewPath={this.props.viewPath}
                     thumbShown={this.thumbShown}
                     setContentView={this.setContentView}
-                    docFilters={this.docFilters}
+                    childFilters={this.childFilters}
                     NativeDimScaling={this.props.NativeDimScaling}
                     PanelHeight={this.panelHeight}
                     setHeight={!this.props.suppressSetHeight ? this.setHeight : undefined}
@@ -924,7 +924,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     setTitleFocus={this.setTitleFocus}
                     layout_fieldKey={this.finalLayoutKey}
                 />
-                {this.layoutDoc.hideAllLinks ? null : this.allLinkEndpoints}
+                {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints}
             </div>
         );
     }
@@ -960,12 +960,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         TraceMobx();
         return LinkManager.Instance.getAllRelatedLinks(this.rootDoc);
     }
-    hideLink = computedFn((link: Doc) => () => (link.layout_linkDisplay = false));
+    hideLink = computedFn((link: Doc) => () => (link.link_displayLine = false));
     @computed get allLinkEndpoints() {
         // the small blue dots that mark the endpoints of links
         TraceMobx();
         if (this.props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this.props.dontRegisterView || this.layoutDoc.layout_unrendered) return null;
-        const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => d.layout_linkDisplay);
+        const filtered = DocUtils.FilterDocs(this.directLinks, this.props.childFilters?.() ?? [], []).filter(d => d.link_displayLine);
         return filtered.map(link => (
             <div className="documentView-anchorCont" key={link[Id]}>
                 <DocumentView
@@ -1013,7 +1013,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 gumStream = stream;
                 recorder = new MediaRecorder(stream);
                 recorder.ondataavailable = async (e: any) => {
-                    const [{ result }] = await Networking.UploadFilesToServer({file: e.data});
+                    const [{ result }] = await Networking.UploadFilesToServer({ file: e.data });
                     if (!(result instanceof Error)) {
                         const audioField = new AudioField(result.accessPaths.agnostic.client);
                         const audioAnnos = Cast(dataDoc[field + '-audioAnnotations'], listSpec(AudioField), null);
@@ -1296,13 +1296,13 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     }
 
     // shows a stacking view collection (by default, but the user can change) of all documents linked to the source
-    public static showBackLinks(linkSource: Doc) {
-        const docId = Doc.CurrentUserEmail + Doc.GetProto(linkSource)[Id] + '-pivotish';
+    public static showBackLinks(linkAnchor: Doc) {
+        const docId = Doc.CurrentUserEmail + Doc.GetProto(linkAnchor)[Id] + '-pivotish';
         // prettier-ignore
-        DocServer.GetRefField(docId).then(docx => docx instanceof Doc &&
+        DocServer.GetRefField(docId).then(docx =>
             LightboxView.SetLightboxDoc(
-                docx || // reuse existing pivot view of documents, or else create a new collection
-                Docs.Create.StackingDocument([], { title: linkSource.title + '-pivot', _width: 500, _height: 500, linkSource, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(self)') }, docId)
+                (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection
+                Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(self, self.target)') }, docId)
             )
         );
     }
@@ -1490,8 +1490,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             // increase max auto height if document has been resized to be greater than current max
             () => NumCast(this.layoutDoc._height),
             action(height => {
-                const docMax = NumCast(this.layoutDoc.docMaxAutoHeight);
-                if (docMax && docMax < height) this.layoutDoc.docMaxAutoHeight = height;
+                const docMax = NumCast(this.layoutDoc.layout_maxAutoHeight);
+                if (docMax && docMax < height) this.layoutDoc.layout_maxAutoHeight = height;
             })
         );
         !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.AddView(this);
@@ -1577,16 +1577,16 @@ ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuff
     else dv.switchViews(true, detailLayoutKeySuffix, undefined, true);
 });
 
-ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc) {
-    const linkSource = Cast(linkCollection.linkSource, Doc, null);
+ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSource: Doc) {
     const collectedLinks = DocListCast(Doc.GetProto(linkCollection).data);
     let wid = linkSource[Width]();
+    let embedding:Doc|undefined;
     const links = LinkManager.Links(linkSource);
     links.forEach(link => {
         const other = LinkManager.getOppositeAnchor(link, linkSource);
-        const otherdoc = !other ? undefined : other.annotationOn ? Cast(other.annotationOn, Doc, null) : other;
+        const otherdoc = DocCast(other?.annotationOn ?? other);
         if (otherdoc && !collectedLinks?.some(d => Doc.AreProtosEqual(d, otherdoc))) {
-            const embedding = Doc.MakeEmbedding(otherdoc);
+            embedding = Doc.MakeEmbedding(otherdoc);
             embedding.x = wid;
             embedding.y = 0;
             embedding._lockedPosition = false;
@@ -1594,5 +1594,6 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc) {
             Doc.AddDocToList(Doc.GetProto(linkCollection), 'data', embedding);
         }
     });
+    embedding && DocServer.UPDATE_SERVER_CACHE();// if a new embedding was made, update the client's server cache so that it will not come back as a promise
     return links;
 });
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 4e348c67c..64f25cb22 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -57,8 +57,8 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
         const props: FieldViewProps = {
             Document: this.props.doc,
             DataDoc: this.props.doc,
-            docFilters: returnEmptyFilter,
-            docRangeFilters: returnEmptyFilter,
+            childFilters: returnEmptyFilter,
+            childFiltersByRanges: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 73823041c..52f3575cb 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -87,8 +87,8 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
         const params = {
             rotateText: null,
             fontSizeFactor: 1,
-            minimumFontSize: NumCast(this.rootDoc._minFontSize, 8),
-            maximumFontSize: NumCast(this.rootDoc._maxFontSize, 1000),
+            minimumFontSize: NumCast(this.rootDoc._label_minFontSize, 8),
+            maximumFontSize: NumCast(this.rootDoc._label_maxFontSize, 1000),
             limitingDimension: 'both',
             horizontalAlign: 'center',
             verticalAlign: 'center',
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index f38ef634c..e86b881a8 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -53,7 +53,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
             } else {
                 this.rootDoc[this.fieldKey + '_x'] = ((pt[0] - bounds.left) / bounds.width) * 100;
                 this.rootDoc[this.fieldKey + '_y'] = ((pt[1] - bounds.top) / bounds.height) * 100;
-                this.rootDoc.layout_autoMoveAnchors = false;
+                this.rootDoc.link_autoMoveAnchors = false;
             }
         }
         return false;
@@ -68,7 +68,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const y = NumCast(this.rootDoc[this.fieldKey + '_y'], 100);
         const background = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.BackgroundColor + ':anchor');
         const anchor = this.fieldKey === 'link_anchor_1' ? 'link_anchor_2' : 'link_anchor_1';
-        const anchorScale = !this.dataDoc[this.fieldKey + '_useLinkSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25;
+        const anchorScale = !this.dataDoc[this.fieldKey + '_useSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25;
         const targetTitle = StrCast((this.dataDoc[anchor] as Doc)?.title);
         const selView = SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('link_anchor_1')
             ? 'link_anchor_1'
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 079e1b56d..86191de63 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -268,8 +268,8 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             addDocTab={returnFalse}
                             pinToPres={returnFalse}
                             dontRegisterView={true}
-                            docFilters={returnEmptyFilter}
-                            docRangeFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
+                            childFiltersByRanges={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                             renderDepth={0}
                             suppressSetHeight={true}
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index f03954789..93e54ffb7 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -394,7 +394,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
 
     /**
@@ -550,8 +550,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.IsOpaqueFilter()];
     infoWidth = () => this.props.PanelWidth() / 5;
     infoHeight = () => this.props.PanelHeight() / 5;
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
@@ -601,7 +601,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     };
     bingMapReady = (map: any) => (this._bingMap = map.map);
     render() {
-        const renderAnnotations = (docFilters?: () => string[]) => null;
+        const renderAnnotations = (childFilters?: () => string[]) => null;
         return (
             <div className="mapBox" ref={this._ref}>
                 <div
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index 18fcc951a..72f37b62c 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -391,7 +391,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
 
     /**
@@ -547,8 +547,8 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.IsOpaqueFilter()];
     infoWidth = () => this.props.PanelWidth() / 5;
     infoHeight = () => this.props.PanelHeight() / 5;
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
@@ -558,7 +558,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return (window as any).Microsoft.Maps;
     }
     render() {
-        const renderAnnotations = (docFilters?: () => string[]) => null;
+        const renderAnnotations = (childFilters?: () => string[]) => null;
         return (
             <div className="MapBox2" ref={this._ref}>
                 <div
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index 6b26f494b..577101445 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -59,7 +59,7 @@ export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & Vi
                             fieldKey="data"
                             NativeWidth={returnZero}
                             NativeHeight={returnZero}
-                            docFilters={returnEmptyFilter}
+                            childFilters={returnEmptyFilter}
                             setHeight={emptyFunction}
                             isAnnotationOverlay={false}
                             select={emptyFunction}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 6ee1b67f2..c210176b0 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -441,7 +441,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return PDFBox.sidebarResizerWidth + nativeDiff * (this.props.NativeDimScaling?.() || 1);
     };
     @undoBatch
-    toggleSidebarType = () => (this.rootDoc.sidebarViewType = this.rootDoc.sidebarViewType === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform);
+    toggleSidebarType = () => (this.rootDoc.sidebar_collectionType = this.rootDoc.sidebar_collectionType === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform);
     specificContextMenu = (e: React.MouseEvent): void => {
         const cm = ContextMenu.Instance;
         const options = cm.findByDescription('Options...');
@@ -557,7 +557,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         };
         return (
             <div className={'formattedTextBox-sidebar' + (Doc.ActiveTool !== InkTool.None ? '-inking' : '')} style={{ width: '100%', right: 0, backgroundColor: `white` }}>
-                {renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
+                {renderComponent(StrCast(this.layoutDoc.sidebar_collectionType))}
             </div>
         );
     }
diff --git a/src/client/views/nodes/QueryBox.scss b/src/client/views/nodes/QueryBox.scss
deleted file mode 100644
index b5f90aa1e..000000000
--- a/src/client/views/nodes/QueryBox.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-.queryBox, .queryBox-dragging {
-    width: 100%;
-    height: 100%; 
-    position: absolute;
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/QueryBox.tsx b/src/client/views/nodes/QueryBox.tsx
deleted file mode 100644
index 1b6056be6..000000000
--- a/src/client/views/nodes/QueryBox.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-// import React = require("react");
-// import { IReactionDisposer } from "mobx";
-// import { observer } from "mobx-react";
-// import { documentSchema } from "../../../new_fields/documentSchemas";
-// import { Id } from '../../../new_fields/FieldSymbols';
-// import { makeInterface, listSpec } from "../../../new_fields/Schema";
-// import { StrCast, Cast } from "../../../new_fields/Types";
-// import { ViewBoxAnnotatableComponent } from '../DocComponent';
-// import { SearchBox } from "../search/SearchBox";
-// import { FieldView, FieldViewProps } from './FieldView';
-// import "./QueryBox.scss";
-// import { List } from "../../../new_fields/List";
-// import { SnappingManager } from "../../util/SnappingManager";
-
-// type QueryDocument = makeInterface<[typeof documentSchema]>;
-// const QueryDocument = makeInterface(documentSchema);
-
-// @observer
-// export class QueryBox extends ViewBoxAnnotatableComponent<FieldViewProps, QueryDocument>(QueryDocument) {
-//     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(QueryBox, fieldKey); }
-//     _docListChangedReaction: IReactionDisposer | undefined;
-//     componentDidMount() {
-//     }
-
-//     componentWillUnmount() {
-//         this._docListChangedReaction?.();
-//     }
-
-//     render() {
-//         const dragging = !SnappingManager.GetIsDragging() ? "" : "-dragging";
-//         return <div className={`queryBox${dragging}`} onWheel={(e) => e.stopPropagation()} >
-            
-//             <SearchBox  Document={this.props.Document}  />
-//         </div >;
-//     }
-// }
-
-// //<SearchBox id={this.props.Document[Id]} sideBar={side} Document={this.props.Document} searchQuery={StrCast(this.dataDoc.searchQuery)} filterQuery={this.dataDoc.filterQuery} />
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 34dcde23b..1f52c2d92 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -913,7 +913,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     marqueeFitScaling = () => ((this.props.NativeDimScaling?.() || 1) * this.heightPercent) / 100;
     marqueeOffset = () => [((this.panelWidth() / 2) * (1 - this.heightPercent / 100)) / (this.heightPercent / 100), 0];
 
-    timelineDocFilter = () => [`_timelineLabel:true,${Utils.noRecursionHack}:x`];
+    timelineDocFilter = () => [`_isTimelineLabel:true,${Utils.noRecursionHack}:x`];
 
     // renders video controls
     componentUI = (boundsLeft: number, boundsTop: number) => {
@@ -1082,7 +1082,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                             PanelHeight={this.panelHeight}
                             isAnyChildContentActive={returnFalse}
                             ScreenToLocalTransform={this.screenToLocalTransform}
-                            docFilters={this.timelineDocFilter}
+                            childFilters={this.timelineDocFilter}
                             select={emptyFunction}
                             focus={emptyFunction}
                             NativeDimScaling={returnOne}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 48f77469f..2ff0245d2 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -900,7 +900,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
         const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any);
         const scale = previewScale * (this.props.NativeDimScaling?.() || 1);
-        const renderAnnotations = (docFilters: () => string[]) => (
+        const renderAnnotations = (childFilters: () => string[]) => (
             <CollectionFreeFormView
                 {...this.props}
                 setContentView={this.setInnerContent}
@@ -919,7 +919,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 NativeDimScaling={returnOne}
                 focus={this.focus}
                 dropAction="embed"
-                docFilters={docFilters}
+                childFilters={childFilters}
                 select={emptyFunction}
                 isAnyChildContentActive={returnFalse}
                 bringToFront={emptyFunction}
@@ -995,8 +995,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
     childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
         if (doc instanceof Doc && property === StyleProp.PointerEvents) {
             if (this.inlineTextAnnotations.includes(doc)) return 'none';
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 601759dbb..5bba51ec8 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -95,7 +95,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
 
     // Determining UI Specs
     @computed get label() {
-        return StrCast(this.rootDoc.label, StrCast(this.rootDoc.title));
+        return StrCast(this.rootDoc.icon_label, StrCast(this.rootDoc.title));
     }
     Icon = (color: string) => {
         const icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as any;
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 1d41eb379..48f4c2afd 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -217,8 +217,8 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                     whenChildContentsActiveChanged={returnFalse}
                     bringToFront={emptyFunction}
                     dontRegisterView={false}
-                    docFilters={this.props.tbox?.props.docFilters}
-                    docRangeFilters={this.props.tbox?.props.docRangeFilters}
+                    childFilters={this.props.tbox?.props.childFilters}
+                    childFiltersByRanges={this.props.tbox?.props.childFiltersByRanges}
                     searchFilterDocs={this.props.tbox?.props.searchFilterDocs}
                 />
             </div>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 105fb9003..115777c18 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -132,7 +132,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         return this._showSidebar ? '20%' : StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
     }
     @computed get sidebarColor() {
-        return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.fieldKey + '_backgroundColor'], '#e4e4e4'));
+        return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.fieldKey + '_backgroundColor'], '#e4e4e4'));
     }
     @computed get layout_autoHeight() {
         return (this.props.forceAutoHeight || this.layoutDoc._layout_autoHeight) && !this.props.ignoreAutoHeight;
@@ -811,9 +811,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             icon: !this.Document._layout_noSidebar ? 'eye-slash' : 'eye',
         });
         uicontrols.push({
-            description: (this.Document._layout_altContentUI ? 'Hide' : 'Show') + ' Alt Content UI',
-            event: () => (this.layoutDoc._layout_altContentUI = !this.layoutDoc._layout_altContentUI),
-            icon: !this.Document._layout_altContentUI ? 'eye-slash' : 'eye',
+            description: (this.Document._layout_enableAltContentUI ? 'Hide' : 'Show') + ' Alt Content UI',
+            event: () => (this.layoutDoc._layout_enableAltContentUI = !this.layoutDoc._layout_enableAltContentUI),
+            icon: !this.Document._layout_enableAltContentUI ? 'eye-slash' : 'eye',
         });
         uicontrols.push({ description: 'Show Highlights...', noexpand: true, subitems: highlighting, icon: 'hand-point-right' });
         !Doc.noviceMode &&
@@ -1741,7 +1741,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
 
         const state = this._editorView!.state;
         const curText = state.doc.textBetween(0, state.doc.content.size, ' \n');
-        if (this.layoutDoc.sidebarViewType === 'translation' && !this.fieldKey.includes('translation') && curText.endsWith(' ') && curText !== this._lastText) {
+        if (this.layoutDoc.sidebar_collectionType === 'translation' && !this.fieldKey.includes('translation') && curText.endsWith(' ') && curText !== this._lastText) {
             try {
                 translateGoogleApi(curText, { from: 'en', to: 'es' }).then((result1: any) => {
                     setTimeout(
@@ -1837,7 +1837,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 return toNum(height) + Math.max(0, toNum(marginTop)) + Math.max(0, toNum(marginBottom));
             };
             const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + toHgt(child), margins);
-            const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
+            const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.layout_maxAutoHeight, proseHeight), proseHeight);
             if (this.props.setHeight && scrollHeight && !this.props.dontRegisterView) {
                 // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
                 const setScrollHeight = () => (this.rootDoc[this.fieldKey + '_scrollHeight'] = scrollHeight);
@@ -1949,19 +1949,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                         fitContentsToBox={this.fitContentsToBox}
                         noSidebar={true}
                         treeViewHideTitle={true}
-                        fieldKey={this.layoutDoc.sidebarViewType === 'translation' ? `${this.fieldKey}_translation` : `${this.fieldKey}_sidebar`}
+                        fieldKey={this.layoutDoc.sidebar_collectionType === 'translation' ? `${this.fieldKey}_translation` : `${this.fieldKey}_sidebar`}
                     />
                 </div>
             );
         };
         return (
             <div className={'formattedTextBox-sidebar' + (Doc.ActiveTool !== InkTool.None ? '-inking' : '')} style={{ width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
-                {renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
+                {renderComponent(StrCast(this.layoutDoc.sidebar_collectionType))}
             </div>
         );
     }
     cycleAlternateText = () => {
-        if (this.layoutDoc._layout_altContentUI) {
+        if (this.layoutDoc._layout_enableAltContentUI) {
             const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`];
             this.rootDoc[`_${this.props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
         }
@@ -2016,7 +2016,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         const active = this.props.isContentActive() || this.props.isSelected();
         const selected = active;
         const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
-        const rounded = StrCast(this.layoutDoc.borderRounding) === '100%' ? '-rounded' : '';
+        const rounded = StrCast(this.layoutDoc.layout_borderRounding) === '100%' ? '-rounded' : '';
         const interactive = (Doc.ActiveTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition);
         if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
         const minimal = this.props.ignoreAutoHeight;
@@ -2096,7 +2096,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     {this.noSidebar || this.props.dontSelectOnLoad || !this.SidebarShown || this.layout_sidebarWidthPercent === '0%' ? null : this.sidebarCollection}
                     {this.noSidebar || this.Document._layout_noSidebar || this.props.dontSelectOnLoad || this.Document._createDocOnCR ? null : this.sidebarHandle}
                     {this.audioHandle}
-                    {this.layoutDoc._layout_altContentUI ? this.overlayAlternateIcon : null}
+                    {this.layoutDoc._layout_enableAltContentUI ? this.overlayAlternateIcon : null}
                 </div>
             </div>
         );
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 884811317..ac20126f1 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -488,8 +488,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         }
 
         if ((pinDataTypes?.filters && activeItem.presDocFilters !== undefined) || (!pinDataTypes && activeItem.presDocFilters !== undefined)) {
-            if (bestTarget.docFilters !== activeItem.presDocFilters) {
-                bestTarget.docFilters = ObjectField.MakeCopy(activeItem.presDocFilters as ObjectField) || new List<string>([]);
+            if (bestTarget.childFilters !== activeItem.presDocFilters) {
+                bestTarget.childFilters = ObjectField.MakeCopy(activeItem.presDocFilters as ObjectField) || new List<string>([]);
                 changed = true;
             }
         }
@@ -651,7 +651,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     )
                 );
             if (pinProps.pinData.type_collection) pinDoc.presViewType = targetDoc._type_collection;
-            if (pinProps.pinData.filters) pinDoc.presDocFilters = ObjectField.MakeCopy(targetDoc.docFilters as ObjectField);
+            if (pinProps.pinData.filters) pinDoc.presDocFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField);
             if (pinProps.pinData.pivot) pinDoc.presPivotField = targetDoc._pivotField;
             if (pinProps.pinData.pannable) {
                 pinDoc.presPanX = NumCast(targetDoc._freeform_panX);
@@ -2078,10 +2078,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         // prettier-ignore
         switch (layout) {
             case 'blank': return Docs.Create.FreeformDocument([], { title: input ? input : 'Blank slide', _width: 400, _height: 225, x, y });
-            case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input ? input : 'Title slide', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
-            case 'header': return Docs.Create.FreeformDocument([header()], { title: input ? input : 'Section header', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
-            case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input ? input : 'Title and content', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y });
-            case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _layoutFitContentsToBox: true, x, y })
+            case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input ? input : 'Title slide', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y });
+            case 'header': return Docs.Create.FreeformDocument([header()], { title: input ? input : 'Section header', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y });
+            case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input ? input : 'Title and content', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y });
+            case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _layout_fitContentsToBox: true, x, y })
         }
     };
 
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 154c879a0..34e069046 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -107,8 +107,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     ScreenToLocalTransform={Transform.Identity}
                     renderDepth={this.props.renderDepth + 1}
                     docViewPath={returnEmptyDoclist}
-                    docFilters={this.props.docFilters}
-                    docRangeFilters={this.props.docRangeFilters}
+                    childFilters={this.props.childFilters}
+                    childFiltersByRanges={this.props.childFiltersByRanges}
                     searchFilterDocs={this.props.searchFilterDocs}
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
@@ -377,9 +377,9 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const recording = Docs.Create.WebCamDocument('', {
                 _width: 384,
                 _height: 216,
-                hideDocumentButtonBar: true,
+                layout_hideDocumentButtonBar: true,
                 layout_hideDecorationTitle: true,
-                hideOpenButton: true,
+                layout_hideOpenButton: true,
                 // hideDeleteButton: true,
                 cloneFieldFilter: new List<string>(['isSystem']),
             });
@@ -522,7 +522,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         style={{
                             display: 'infline-block',
                             backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
-                            //boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined,
+                            //layout_boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined,
                             border: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? presBoxColor + ' solid 2.5px' : undefined) : undefined,
                         }}>
                         <div
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index bc0cad636..dd202418b 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -91,7 +91,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
     @observable isAnnotating = false;
     // key where data is stored
     @computed get allAnnotations() {
-        return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), this.props.docFilters(), this.props.docRangeFilters());
+        return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), this.props.childFilters(), this.props.childFiltersByRanges());
     }
     @computed get inlineTextAnnotations() {
         return this.allAnnotations.filter(a => a.textInlineAnnotations);
@@ -513,8 +513,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
     overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._freeform_scale, 1));
     panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1);
     panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
+    transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
+    opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(DragManager.docsBeingDragged.length ? [] : [Utils.IsOpaqueFilter()])];
     childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
         if (doc instanceof Doc && property === StyleProp.PointerEvents) {
             if (this.inlineTextAnnotations.includes(doc)) return 'none';
@@ -523,7 +523,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         return this.props.styleProvider?.(doc, props, property);
     };
 
-    renderAnnotations = (docFilters: () => string[], mixBlendMode?: any, display?: string) => (
+    renderAnnotations = (childFilters: () => string[], mixBlendMode?: any, display?: string) => (
         <div
             className="pdfViewerDash-overlay"
             style={{
@@ -550,7 +550,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 isAnyChildContentActive={returnFalse}
                 isAnnotationOverlayScrollable={true}
                 dropAction="embed"
-                docFilters={docFilters}
+                childFilters={childFilters}
                 select={emptyFunction}
                 bringToFront={emptyFunction}
                 styleProvider={this.childStyleProvider}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 72eeedcff..92ae64567 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1415,18 +1415,18 @@ export namespace Doc {
     }
     export function setDocRangeFilter(container: Opt<Doc>, key: string, range?: number[]) {
         if (!container) return;
-        const docRangeFilters = Cast(container._docRangeFilters, listSpec('string'), []);
-        for (let i = 0; i < docRangeFilters.length; i += 3) {
-            if (docRangeFilters[i] === key) {
-                docRangeFilters.splice(i, 3);
+        const childFiltersByRanges = Cast(container._childFiltersByRanges, listSpec('string'), []);
+        for (let i = 0; i < childFiltersByRanges.length; i += 3) {
+            if (childFiltersByRanges[i] === key) {
+                childFiltersByRanges.splice(i, 3);
                 break;
             }
         }
         if (range !== undefined) {
-            docRangeFilters.push(key);
-            docRangeFilters.push(range[0].toString());
-            docRangeFilters.push(range[1].toString());
-            container._docRangeFilters = new List<string>(docRangeFilters);
+            childFiltersByRanges.push(key);
+            childFiltersByRanges.push(range[0].toString());
+            childFiltersByRanges.push(range[1].toString());
+            container._childFiltersByRanges = new List<string>(childFiltersByRanges);
         }
     }
 
@@ -1435,35 +1435,35 @@ export namespace Doc {
     // based on the modifiers :"check", "x", undefined
     export function setDocFilter(container: Opt<Doc>, key: string, value: any, modifiers: 'remove' | 'match' | 'check' | 'x' | 'exists' | 'unset', toggle?: boolean, fieldPrefix?: string, append: boolean = true) {
         if (!container) return;
-        const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'docFilters';
-        const docFilters = StrListCast(container[filterField]);
+        const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'childFilters';
+        const childFilters = StrListCast(container[filterField]);
         runInAction(() => {
-            for (let i = 0; i < docFilters.length; i++) {
-                const fields = docFilters[i].split(':'); // split key:value:modifier
+            for (let i = 0; i < childFilters.length; i++) {
+                const fields = childFilters[i].split(':'); // split key:value:modifier
                 if (fields[0] === key && (fields[1] === value || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
                     if (fields[2] === modifiers && modifiers && fields[1] === value) {
                         if (toggle) modifiers = 'remove';
                         else return;
                     }
-                    docFilters.splice(i, 1);
-                    container[filterField] = new List<string>(docFilters);
+                    childFilters.splice(i, 1);
+                    container[filterField] = new List<string>(childFilters);
                     break;
                 }
             }
-            if (!docFilters.length && modifiers === 'match' && value === undefined) {
+            if (!childFilters.length && modifiers === 'match' && value === undefined) {
                 container[filterField] = undefined;
             } else if (modifiers !== 'remove') {
-                !append && (docFilters.length = 0);
-                docFilters.push(key + ':' + value + ':' + modifiers);
-                container[filterField] = new List<string>(docFilters);
+                !append && (childFilters.length = 0);
+                childFilters.push(key + ':' + value + ':' + modifiers);
+                container[filterField] = new List<string>(childFilters);
             }
         });
     }
     export function readDocRangeFilter(doc: Doc, key: string) {
-        const docRangeFilters = Cast(doc._docRangeFilters, listSpec('string'), []);
-        for (let i = 0; i < docRangeFilters.length; i += 3) {
-            if (docRangeFilters[i] === key) {
-                return [Number(docRangeFilters[i + 1]), Number(docRangeFilters[i + 2])];
+        const childFiltersByRanges = Cast(doc._childFiltersByRanges, listSpec('string'), []);
+        for (let i = 0; i < childFiltersByRanges.length; i += 3) {
+            if (childFiltersByRanges[i] === key) {
+                return [Number(childFiltersByRanges[i + 1]), Number(childFiltersByRanges[i + 2])];
             }
         }
     }
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index 7a0a18929..757d507be 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -55,8 +55,8 @@ export const documentSchema = createSchema({
 
     // appearance properties on the data document
     backgroundColor: 'string', // background color of document
-    borderRounding: 'string', // border radius rounding of document
-    boxShadow: 'string', // the amount of shadow around the perimeter of a document
+    layout_borderRounding: 'string', // border radius rounding of document
+    layout_boxShadow: 'string', // the amount of shadow around the perimeter of a document
     color: 'string', // foreground color of document
     freeform_fitContentsToBox: 'boolean', // whether freeform view contents should be zoomed/panned to fill the area of the document view box
     fontSize: 'string',
@@ -86,13 +86,13 @@ export const documentSchema = createSchema({
     onDragStart: ScriptField, // script to run when document is dragged (without being selected).  the script should return the Doc to be dropped.
     followLinkLocation: 'string', // flag for where to place content when following a click interaction (e.g., add:right, lightbox, default, )
     hideLinkButton: 'boolean', // whether the blue link counter button should be hidden
-    hideAllLinks: 'boolean', // whether all individual blue anchor dots should be hidden
-    layout_linkDisplay: 'boolean', // whether a link connection should be shown between link anchor endpoints.
+    layout_hideAllLinks: 'boolean', // whether all individual blue anchor dots should be hidden
+    link_displayLine: 'boolean', // whether a link connection should be shown between link anchor endpoints.
     isLightbox: 'boolean', // whether the marked object will display addDocTab() calls that target "lightbox" destinations
     layers: listSpec('string'), // which layers the document is part of
     _lockedPosition: 'boolean', // whether the document can be moved (dragged)
     _lockedTransform: 'boolean', // whether a freeformview can pan/zoom
-    layout_linkDisplayArrow: 'boolean', // toggles directed arrows
+    link_displayArrow: 'boolean', // toggles directed arrows
 
     // drag drop properties
     _stayInCollection: 'boolean', // whether document can be dropped into a different collection
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 62f27c7d2..f365adf4b 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -16,7 +16,7 @@ import { PrefetchProxy, ProxyField } from './Proxy';
 import { RefField } from './RefField';
 import { RichTextField } from './RichTextField';
 import { SchemaHeaderField } from './SchemaHeaderField';
-import { ComputedField } from './ScriptField';
+import { ComputedField, ScriptField } from './ScriptField';
 import { ScriptCast, StrCast } from './Types';
 
 function _readOnlySetter(): never {
@@ -69,10 +69,12 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
 
     if (writeToDoc) {
         if (value === undefined) {
-            delete target[FieldKeys][prop];
+            target[FieldKeys] && delete target[FieldKeys][prop]; // Lists don't have a FieldKeys field
             delete target.__fieldTuples[prop];
         } else {
-            target[FieldKeys][prop] = true;
+            // bcz: uncomment to see if server is being updated
+            // console.log(prop + ' = ' + value + '(' + curValue + ')');
+            target[FieldKeys] && (target[FieldKeys][prop] = true); // Lists don't have a FieldKeys field
             target.__fieldTuples[prop] = value;
         }
 
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index c3423e2a5..7a1dde9fb 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -25,8 +25,8 @@ export class AudioUpload extends React.Component {
                 title: 'mobile audio',
                 _width: 300,
                 _height: 300,
-                _layoutFitContentsToBox: true,
-                boxShadow: '0 0',
+                _layout_fitContentsToBox: true,
+                layout_boxShadow: '0 0',
             }),
             Doc
         )
@@ -54,7 +54,7 @@ export class AudioUpload extends React.Component {
                             Doc
                         ) as Doc,
                     ],
-                    { title: 'mobile audio', _width: 300, _height: 300, _layoutFitContentsToBox: true, boxShadow: '0 0' }
+                    { title: 'mobile audio', _width: 300, _height: 300, _layout_fitContentsToBox: true, layout_boxShadow: '0 0' }
                 ),
                 Doc
             )
@@ -110,8 +110,8 @@ export class AudioUpload extends React.Component {
                         pinToPres={emptyFunction}
                         rootSelected={returnTrue}
                         removeDocument={undefined}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                         ScreenToLocalTransform={Transform.Identity}
                         PanelWidth={() => 600}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 471dc568b..584a7b432 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -402,8 +402,8 @@ export class MobileInterface extends React.Component {
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-                    docFilters={returnEmptyFilter}
-                    docRangeFilters={returnEmptyFilter}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
             </div>
-- 
cgit v1.2.3-70-g09d2

