From 7e4d793eaa7e5b6b564355a11fa02a5611645f20 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 21 Mar 2025 18:58:21 -0400
Subject: trying to improve how data / layout / root and templtae docs are
 accessed.

---
 src/client/views/collections/CollectionDockingView.tsx | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index e51bc18ef..a45b37f43 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -503,9 +503,8 @@ export class CollectionDockingView extends CollectionSubView() {
         });
         const dashboardDoc = Docs.Create.DockDocument(newtabs, json, { title: incrementTitleCopy(StrCast(doc.title)) });
 
-        dashboardDoc.pane_count = 1;
-        dashboardDoc.myOverlayDocs = new List<Doc>();
-        dashboardDoc.myPublishedDocs = new List<Doc>();
+        dashboardDoc.$myOverlayDocs = new List<Doc>();
+        dashboardDoc.$myPublishedDocs = new List<Doc>();
 
         DashboardView.SetupDashboardTrails();
         DashboardView.SetupDashboardCalendars(); // Zaul TODO: needed?
@@ -555,13 +554,13 @@ export class CollectionDockingView extends CollectionSubView() {
         stack.header?.element.on('mousedown', (e: MouseEvent) => {
             const dashboard = Doc.ActiveDashboard;
             if (dashboard && e.target === stack.header?.element[0] && e.button === 2) {
-                dashboard.pane_count = NumCast(dashboard.pane_count) + 1;
+                dashboard.$myPaneCount = NumCast(dashboard.$myPaneCount) + 1;
                 const docToAdd = Docs.Create.FreeformDocument([], {
                     _width: this._props.PanelWidth(),
                     _height: this._props.PanelHeight(),
                     _freeform_backgroundGrid: true,
                     _layout_fitWidth: true,
-                    title: `Untitled Tab ${NumCast(dashboard.pane_count)}`,
+                    title: `Untitled Tab ${NumCast(dashboard.$myPaneCount)}`,
                 });
                 Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd, undefined, undefined, true);
                 inheritParentAcls(this.Document, docToAdd, false);
@@ -572,13 +571,13 @@ export class CollectionDockingView extends CollectionSubView() {
         const addNewDoc = undoable(() => {
             const dashboard = Doc.ActiveDashboard;
             if (dashboard) {
-                dashboard.pane_count = NumCast(dashboard.pane_count) + 1;
+                dashboard.$myPaneCount = NumCast(dashboard.$myPaneCount) + 1;
                 const docToAdd = Docs.Create.FreeformDocument([], {
                     _width: this._props.PanelWidth(),
                     _height: this._props.PanelHeight(),
                     _layout_fitWidth: true,
                     _freeform_backgroundGrid: true,
-                    title: `Untitled Tab ${NumCast(dashboard.pane_count)}`,
+                    title: `Untitled Tab ${NumCast(dashboard.$myPaneCount)}`,
                 });
                 Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd, undefined, undefined, true);
                 inheritParentAcls(this.dataDoc, docToAdd, false);
-- 
cgit v1.2.3-70-g09d2


From d0fccd1050f5d6ccc24c1e4d2b7d1c0ed94fb2a7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 23 Mar 2025 10:27:28 -0400
Subject: updated more [DocData] to .$ things

---
 src/client/util/CalendarManager.tsx                |  5 +--
 src/client/util/LinkManager.ts                     |  6 +--
 src/client/views/DocComponent.tsx                  |  9 ++--
 src/client/views/PropertiesDocContextSelector.tsx  |  2 +-
 src/client/views/PropertiesView.tsx                |  8 +---
 src/client/views/SidebarAnnos.tsx                  |  9 ++--
 src/client/views/StyleProviderQuiz.tsx             |  8 ++--
 src/client/views/TagsView.tsx                      | 33 +++++++--------
 .../views/collections/CollectionDockingView.tsx    |  6 +--
 .../collections/CollectionMasonryViewFieldRow.tsx  |  3 +-
 src/client/views/collections/CollectionMenu.tsx    |  3 +-
 .../views/collections/CollectionNoteTakingView.tsx |  2 +-
 .../collections/CollectionNoteTakingViewColumn.tsx |  2 +-
 .../collections/CollectionStackedTimeline.tsx      |  8 ++--
 .../views/collections/CollectionStackingView.tsx   |  5 +--
 src/client/views/collections/CollectionSubView.tsx | 12 +++++-
 src/client/views/collections/TabDocView.tsx        |  2 +-
 src/client/views/collections/TreeView.tsx          |  5 +--
 .../CollectionFreeFormInfoUI.tsx                   | 11 +++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 25 ++++++-----
 .../collectionFreeForm/FaceCollectionBox.tsx       |  4 +-
 .../collectionFreeForm/ImageLabelBox.tsx           | 19 ++++-----
 .../collections/collectionFreeForm/MarqueeView.tsx | 19 ++++-----
 src/client/views/global/globalScripts.ts           | 49 +++++++++-------------
 src/client/views/nodes/AudioBox.tsx                |  2 +-
 src/client/views/nodes/ComparisonBox.tsx           | 10 ++---
 .../views/nodes/DataVizBox/components/TableBox.tsx |  4 +-
 src/client/views/nodes/DiagramBox.tsx              |  5 +--
 src/client/views/nodes/DocumentView.tsx            | 14 +++----
 src/client/views/nodes/ImageBox.tsx                | 42 +++++++++----------
 src/client/views/nodes/KeyValueBox.tsx             |  2 +-
 src/client/views/nodes/LinkBox.tsx                 |  6 +--
 src/client/views/nodes/LinkDescriptionPopup.tsx    |  3 +-
 src/client/views/nodes/PDFBox.tsx                  | 17 ++++----
 .../views/nodes/RecordingBox/RecordingBox.tsx      |  3 +-
 src/client/views/nodes/VideoBox.tsx                | 48 ++++++++++-----------
 src/client/views/nodes/calendarBox/CalendarBox.tsx |  2 +-
 .../nodes/chatbot/chatboxcomponents/ChatBox.tsx    |  6 +--
 .../views/nodes/formattedText/EquationView.tsx     |  5 +--
 src/client/views/nodes/imageEditor/ImageEditor.tsx |  9 ++--
 src/client/views/nodes/trails/PresBox.tsx          |  9 ++--
 src/client/views/smartdraw/SmartDrawHandler.tsx    | 21 +++++-----
 src/client/views/smartdraw/StickerPalette.tsx      | 28 ++++++-------
 src/fields/Doc.ts                                  | 25 ++++++-----
 src/fields/ScriptField.ts                          |  3 +-
 45 files changed, 243 insertions(+), 276 deletions(-)

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

diff --git a/src/client/util/CalendarManager.tsx b/src/client/util/CalendarManager.tsx
index 3357e5d59..1a5a5f889 100644
--- a/src/client/util/CalendarManager.tsx
+++ b/src/client/util/CalendarManager.tsx
@@ -17,7 +17,6 @@ import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox';
 import './CalendarManager.scss';
 import { SnappingManager } from './SnappingManager';
 import { CalendarDate, DateValue } from '@internationalized/date';
-import { DocData } from '../../fields/DocSymbols';
 // import 'react-date-range/dist/styles.css';
 // import 'react-date-range/dist/theme/default.css';
 
@@ -119,7 +118,7 @@ export class CalendarManager extends ObservableReactComponent<object> {
     // TODO: Make undoable
     private addToCalendar = () => {
         const docs = DocumentView.Selected().length < 2 ? [this.targetDoc] : DocumentView.Selected().map(docView => docView.Document);
-        const targetDoc = docs[0]?.[DocData];
+        const targetDoc = docs[0];
 
         if (targetDoc) {
             let calendar: Doc;
@@ -230,7 +229,7 @@ export class CalendarManager extends ObservableReactComponent<object> {
     @computed
     get calendarInterface() {
         const docs = DocumentView.Selected().length < 2 ? [this.targetDoc] : DocumentView.Selected().map(docView => docView.Document);
-        const targetDoc = docs[0]?.[DocData];
+        const targetDoc = docs[0];
 
         return (
             <div
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index d04d41968..3f98ab3c4 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -156,7 +156,7 @@ export class LinkManager {
     }
     public deleteLink(linkDoc: Doc) {
         const ret = Doc.RemoveDocFromList(Doc.LinkDBDoc(), 'data', linkDoc);
-        linkDoc[DocData].link_anchor_1 = linkDoc[DocData].link_anchor_2 = undefined;
+        linkDoc.$link_anchor_1 = linkDoc.$link_anchor_2 = undefined;
         return ret;
     }
     public deleteAllLinksOnAnchor(anchor: Doc) {
@@ -258,8 +258,8 @@ export function UPDATE_SERVER_CACHE() {
 
     // print out cached docs
     //Doc.MyDockedBtns.linearView_IsOpen && console.log('Set cached docs = ');
-    const isFiltered = filtered.filter(doc => !Doc.IsSystem(doc));
-    const strings = isFiltered.map(doc => StrCast(doc.title) + ' ' + (Doc.IsDataProto(doc) ? '(data)' : '(embedding)'));
+    // const isFiltered = filtered.filter(doc => !Doc.IsSystem(doc));
+    // const strings = isFiltered.map(doc => StrCast(doc.title) + ' ' + (Doc.IsDataProto(doc) ? '(data)' : '(embedding)'));
     //Doc.MyDockedBtns.linearView_IsOpen && strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str));
 
     rp.post(ClientUtils.prepend('/setCacheDocumentIds'), {
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 79a0cc602..a311f6436 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -49,7 +49,7 @@ export function DocComponent<P extends DocComponentProps>() {
          * This is the unique data repository for a dcoument that stores the intrinsic document data
          */
         @computed get dataDoc() {
-            return this.Document[DocData];
+            return this._props.Document[DocData];
         }
     }
     return Component;
@@ -93,7 +93,7 @@ export function ViewBoxBaseComponent<P extends FieldViewProps>() {
          * This is the unique data repository for a dcoument that stores the intrinsic document data
          */
         @computed get dataDoc() {
-            return this.Document.isTemplateForField || this.Document.isTemplateDoc ? (this._props.TemplateDataDocument ?? this.Document[DocData]) : this.Document[DocData];
+            return this._props.Document.isTemplateForField || this._props.Document.isTemplateDoc ? (this._props.TemplateDataDocument ?? this._props.Document[DocData]) : this._props.Document[DocData];
         }
 
         /**
@@ -151,7 +151,7 @@ export function ViewBoxAnnotatableComponent<P extends FieldViewProps>() {
          * This is the unique data repository for a dcoument that stores the intrinsic document data
          */
         @computed get dataDoc() {
-            return this.Document.isTemplateForField || this.Document.isTemplateDoc ? (this._props.TemplateDataDocument ?? this.Document[DocData]) : this.Document[DocData];
+            return this._props.Document.isTemplateForField || this._props.Document.isTemplateDoc ? (this._props.TemplateDataDocument ?? this._props.Document[DocData]) : this._props.Document[DocData];
         }
 
         /**
@@ -225,8 +225,7 @@ export function ViewBoxAnnotatableComponent<P extends FieldViewProps>() {
                 if ([AclAugment, AclEdit, AclAdmin].includes(effectiveAcl)) {
                     added.forEach(adoc => {
                         adoc._dragOnlyWithinContainer = undefined;
-                        if (annotationKey ?? this._annotationKeySuffix()) adoc[DocData].annotationOn = this.Document;
-                        else adoc[DocData].annotationOn = undefined;
+                        adoc.$annotationOn = (annotationKey ?? this._annotationKeySuffix()) ? this.Document : undefined;
                         Doc.SetContainer(adoc, this.Document);
                         inheritParentAcls(targetDataDoc, adoc, true);
                     });
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index f494ff16a..ee6486a9c 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -26,7 +26,7 @@ export class PropertiesDocContextSelector extends ObservableReactComponent<Prope
 
     @computed get _docs() {
         if (!this._props.DocView) return [];
-        const target = this._props.DocView._props.Document;
+        const target = this._props.DocView.Document;
         const targetContext = this._props.DocView.containerViewPath?.().lastElement()?.Document;
         const embeddings = Doc.GetEmbeddings(target);
         const containerProtos = embeddings.filter(embedding => embedding.embedContainer && embedding.embedContainer instanceof Doc).reduce((set, embedding) => set.add(Cast(embedding.embedContainer, Doc, null)), new Set<Doc>());
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index b95553c4e..7e9cd002b 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -181,7 +181,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
     @action
     docHeight = () => {
         const layoutDoc = this.selectedLayoutDoc;
-        if (layoutDoc && this.dataDoc) {
+        if (layoutDoc) {
             return Math.max(
                 70,
                 Math.min(
@@ -308,11 +308,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
     }
 
     @computed get contextCount() {
-        if (this.selectedDocumentView) {
-            const target = this.selectedDocumentView.Document;
-            return Doc.GetEmbeddings(target).length - 1;
-        }
-        return 0;
+        return this.selectedDocumentView ? Doc.GetEmbeddings(this.selectedDocumentView.Document).length - 1 : 0;
     }
 
     @computed get links() {
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 816fc8ed3..b3f3a4478 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -4,7 +4,6 @@ import * as React from 'react';
 import { ClientUtils, returnAll, returnFalse, returnOne, returnZero } from '../../ClientUtils';
 import { emptyFunction } from '../../Utils';
 import { Doc, DocListCast, Field, FieldResult, FieldType, StrListCast } from '../../fields/Doc';
-import { DocData } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
 import { List } from '../../fields/List';
 import { RichTextField } from '../../fields/RichTextField';
@@ -88,9 +87,9 @@ export class SidebarAnnos extends ObservableReactComponent<FieldViewProps & Extr
             .filter(data => data.split(':')[0])
             .filter(data => !filterExlusions?.includes(data.split(':')[0]))
             .map(data => {
-                const key = data.split(':')[0];
+                const key = '$'+data.split(':')[0];
                 const val = Field.Copy(this.allMetadata.get(key));
-                target[DocData][key] = val;
+                target[key] = val;
                 return {
                     type: 'dashField',
                     attrs: { fieldKey: key, docId: '', hideKey: false, hideValue: false, editable: true },
@@ -98,7 +97,7 @@ export class SidebarAnnos extends ObservableReactComponent<FieldViewProps & Extr
                 };
             });
 
-        if (!anchor.text) anchor[DocData].text = '-selection-';
+        if (!anchor.text) anchor.$text = '-selection-';
         const textLines: { type: string; attrs: object; content?: unknown[] }[] = [
             {
                 type: 'paragraph',
@@ -133,7 +132,7 @@ export class SidebarAnnos extends ObservableReactComponent<FieldViewProps & Extr
         };
         if (taggedContent.length) textLines.push(metadatatext);
         if (textLines.length) {
-            target[DocData].text = new RichTextField(
+            target.$text = new RichTextField(
                 JSON.stringify({
                     doc: {
                         type: 'doc',
diff --git a/src/client/views/StyleProviderQuiz.tsx b/src/client/views/StyleProviderQuiz.tsx
index f9ee8d3db..b4a1f53c5 100644
--- a/src/client/views/StyleProviderQuiz.tsx
+++ b/src/client/views/StyleProviderQuiz.tsx
@@ -67,7 +67,7 @@ export namespace styleProviderQuiz {
             newCol.zIndex = 1000;
             newCol.forceActive = true;
             newCol.quiz = text;
-            newCol[DocData][Doc.LayoutFieldKey(newCol) + '_transform'] = 'none';
+            newCol['$' + Doc.LayoutFieldKey(newCol) + '_transform'] = 'none';
             Doc.AddDocToList(img.Document, 'quizBoxes', newCol);
             img.addDocument(newCol);
             //   img._loading = false;
@@ -248,7 +248,7 @@ export namespace styleProviderQuiz {
     function check(img: ImageBox) {
         //this._loading = true;
         imgQuizBoxes(img).forEach(async doc => {
-            const input = StrCast(doc[DocData].title);
+            const input = StrCast(doc.$title);
             if (imgQuizMode(img) == quizMode.SMART && input) {
                 const questionText = 'Question: What was labeled in this image?';
                 const rubricText = ' Rubric: ' + StrCast(doc.quiz);
@@ -275,8 +275,8 @@ export namespace styleProviderQuiz {
 
     function redo(img: ImageBox) {
         imgQuizBoxes(img).forEach(doc => {
-            doc[DocData].title = '';
-            doc.backgroundColor = '#e4e4e4';
+            doc.$title = '';
+            doc.$backgroundColor = '#e4e4e4';
         });
     }
 
diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx
index 93d6fb684..7d2a6be5e 100644
--- a/src/client/views/TagsView.tsx
+++ b/src/client/views/TagsView.tsx
@@ -72,7 +72,7 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
         const newTagCol = new Doc();
         newTagCol.title = tag;
         newTagCol.collections = new List<Doc>();
-        newTagCol[DocData].docs = new List<Doc>();
+        newTagCol.$docs = new List<Doc>();
         Doc.ActiveDashboard && Doc.AddDocToList(Doc.ActiveDashboard, 'myTagCollections', newTagCol);
 
         return newTagCol;
@@ -82,7 +82,7 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
      * @param tag tag string
      * @returns An array of documents that contain the tag.
      */
-    public static allDocsWithTag = (tag: string) => DocListCast(TagItem.findTagCollectionDoc(tag)?.[DocData].docs);
+    public static allDocsWithTag = (tag: string) => DocListCast(TagItem.findTagCollectionDoc(tag)?.$docs);
 
     public static docHasTag = (doc: Doc, tag: string) => StrListCast(doc?.tags).includes(tag);
     /**
@@ -95,11 +95,11 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
 
         // If the document is of type COLLECTION, make it a smart collection, otherwise, add the tag to the document.
         if (doc.type === DocumentType.COL && !doc.annotationOn) {
-            Doc.AddDocToList(tagCollection[DocData], 'collections', doc);
+            Doc.AddDocToList(tagCollection, 'collections', doc);
 
             // Iterate through the tag Doc collections and add a copy of the document to each collection
-            for (const cdoc of DocListCast(tagCollection[DocData].docs)) {
-                if (!DocListCast(doc[DocData].data).find(d => Doc.AreProtosEqual(d, cdoc))) {
+            for (const cdoc of DocListCast(tagCollection.$docs)) {
+                if (!DocListCast(doc.$data).find(d => Doc.AreProtosEqual(d, cdoc))) {
                     const newEmbedding = Doc.MakeEmbedding(cdoc);
                     Doc.AddDocToList(doc[DocData], 'data', newEmbedding);
                     Doc.SetContainer(newEmbedding, doc);
@@ -111,7 +111,7 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
 
             // Iterate through the tag document's collections and add a copy of the document to each collection
             for (const collection of DocListCast(tagCollection.collections)) {
-                if (!DocListCast(collection[DocData].data).find(d => Doc.AreProtosEqual(d, doc))) {
+                if (!DocListCast(collection.$data).find(d => Doc.AreProtosEqual(d, doc))) {
                     const newEmbedding = Doc.MakeEmbedding(doc);
                     Doc.AddDocToList(collection[DocData], 'data', newEmbedding);
                     Doc.SetContainer(newEmbedding, collection);
@@ -119,8 +119,8 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
             }
         }
 
-        if (!doc[DocData].tags) doc[DocData].tags = new List<string>();
-        const tagList = doc[DocData].tags as List<string>;
+        if (!doc.$tags) doc.$tags = new List<string>();
+        const tagList = doc.$tags as List<string>;
         if (!tagList.includes(tag)) tagList.push(tag);
     };
 
@@ -131,22 +131,22 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
      * @param tagDoc doc that collections the Docs with the tag
      */
     public static removeTagFromDoc = (doc: Doc, tag: string, tagDoc?: Doc) => {
-        if (doc[DocData].tags) {
+        if (doc.$tags) {
             if (doc.type === DocumentType.COL) {
                 tagDoc && Doc.RemoveDocFromList(tagDoc[DocData], 'collections', doc);
 
                 for (const cur_doc of TagItem.allDocsWithTag(tag)) {
-                    doc[DocData].data = new List<Doc>(DocListCast(doc[DocData].data).filter(d => !Doc.AreProtosEqual(cur_doc, d)));
+                    doc.$data = new List<Doc>(DocListCast(doc.$data).filter(d => !Doc.AreProtosEqual(cur_doc, d)));
                 }
             } else {
                 tagDoc && Doc.RemoveDocFromList(tagDoc[DocData], 'docs', doc);
 
                 for (const collection of DocListCast(tagDoc?.collections)) {
-                    collection[DocData].data = new List<Doc>(DocListCast(collection[DocData].data).filter(d => !Doc.AreProtosEqual(doc, d)));
+                    collection.$data = new List<Doc>(DocListCast(collection.$data).filter(d => !Doc.AreProtosEqual(doc, d)));
                 }
             }
         }
-        doc[DocData].tags = new List<string>(StrListCast(doc[DocData].tags).filter(label => label !== tag));
+        doc.$tags = new List<string>(StrListCast(doc.$tags).filter(label => label !== tag));
     };
 
     private _ref: React.RefObject<HTMLDivElement>;
@@ -171,11 +171,10 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
 
         // Create a new collection and set up configurations.
         const newCollection = ((doc: Doc) => {
-            const docData = doc[DocData];
-            docData.data = new List<Doc>(newEmbeddings);
-            docData.title = this._props.tag;
-            docData.tags = new List<string>([this._props.tag]);
-            docData.freeform_fitContentsToBox = true;
+            doc.$data = new List<Doc>(newEmbeddings);
+            doc.$title = this._props.tag;
+            doc.$tags = new List<string>([this._props.tag]);
+            doc.$freeform_fitContentsToBox = true;
             doc._freeform_panX = doc._freeform_panY = 0;
             doc._width = 900;
             doc._height = 900;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index a45b37f43..12a131deb 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -5,7 +5,7 @@ import * as ReactDOM from 'react-dom/client';
 import ResizeObserver from 'resize-observer-polyfill';
 import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, DivHeight, DivWidth, incrementTitleCopy, returnTrue, UpdateIcon } from '../../../ClientUtils';
 import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc';
-import { AclAdmin, AclEdit, DocData } from '../../../fields/DocSymbols';
+import { AclAdmin, AclEdit } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
@@ -481,7 +481,7 @@ export class CollectionDockingView extends CollectionSubView() {
             Array.from(cloned.map.entries()).forEach(entry => {
                 json = json.replace(entry[0], entry[1][Id]);
             });
-            cloned.clone[DocData].dockingConfig = json;
+            cloned.clone.$dockingConfig = json;
             return DashboardView.openDashboard(cloned.clone);
         }
         const matches = json.match(/"documentId":"[a-z0-9-]+"/g);
@@ -495,7 +495,7 @@ export class CollectionDockingView extends CollectionSubView() {
             const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true, undefined, true) : Doc.MakeEmbedding(origtab);
             const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeEmbedding(origtabdoc));
             if (newtabdocs.length) {
-                newtab[DocData].data = new List<Doc>(newtabdocs);
+                newtab.$data = new List<Doc>(newtabdocs);
                 newtabdocs.forEach(ntab => Doc.SetContainer(ntab, newtab));
             }
             json = json.replace(origtab[Id], newtab[Id]);
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 996626575..4fe73895e 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -5,7 +5,6 @@ import * as React from 'react';
 import { returnEmptyString, returnFalse, setupMoveUpEvents } from '../../../ClientUtils';
 import { emptyFunction, numberRange } from '../../../Utils';
 import { Doc } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
 import { PastelSchemaPalette, SchemaHeaderField } from '../../../fields/SchemaHeaderField';
 import { ScriptField } from '../../../fields/ScriptField';
 import { Docs } from '../../documents/Documents';
@@ -164,7 +163,7 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVF
         const { pivotField } = this._props;
         const newDoc = Docs.Create.TextDocument(value, { _layout_autoHeight: true, _width: 200, _layout_fitWidth: true, title: value });
         DocumentView.SetSelectOnLoad(newDoc);
-        pivotField && (newDoc[DocData][pivotField] = this.getValue(this._props.heading));
+        pivotField && (newDoc['$' + pivotField] = this.getValue(this._props.heading));
         const docs = this._props.parent.childDocList;
         return docs ? !!docs.splice(0, 0, newDoc) : this._props.parent._props.addDocument?.(newDoc) || false; // should really extend addDocument to specify insertion point (at beginning of list)
     };
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index de999c91a..26aca458c 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -9,7 +9,6 @@ import * as React from 'react';
 import { ClientUtils, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../../ClientUtils';
 import { emptyFunction } from '../../../Utils';
 import { Doc, DocListCast, Opt, returnEmptyDoclist } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
 import { List } from '../../../fields/List';
 import { ObjectField } from '../../../fields/ObjectField';
 import { RichTextField } from '../../../fields/RichTextField';
@@ -213,7 +212,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
         title: 'set content',
         script: 'getProto(this.target).data = copyField(this.source);',
         immediate: undoable((source: Doc[]) => {
-            this.target[DocData].data = new List<Doc>(source);
+            this.target.$data = new List<Doc>(source);
         }, ''),
         initialize: emptyFunction,
     };
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index c499bd288..4650727eb 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -441,7 +441,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         if ((e.ctrlKey || fieldProps.Document._createDocOnCR) && ['Enter'].includes(e.key)) {
             e.stopPropagation?.();
             const newDoc = Doc.MakeCopy(fieldProps.Document, true);
-            newDoc[DocData].text = undefined;
+            newDoc.$text = undefined;
             DocumentView.SetSelectOnLoad(newDoc);
             return this.addDocument?.(newDoc);
         }
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index 40b3f9ef2..df9b5a1eb 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -157,7 +157,7 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
     deleteColumn = () => {
         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[DocData][this._props.pivotField] = undefined));
+            //          this._props.docList.forEach(d => (d['$'+this._props.pivotField] = undefined));
             colHdrData.splice(colHdrData.indexOf(this._props.headingObject), 1);
             this._props.resizeColumns(colHdrData);
         }
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index a7a9f2114..0836cce38 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -432,8 +432,8 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                 _isTimelineLabel: true,
                 layout_borderRounding: anchorEndTime === undefined ? '100%' : undefined,
             });
-        anchor[DocData][startTag] = anchorStartTime;
-        anchor[DocData][endTag] = anchorEndTime;
+        anchor['$' + startTag] = anchorStartTime;
+        anchor['$' + endTag] = anchorEndTime;
         if (addAsAnnotation) {
             if (Cast(dataDoc[fieldKey], listSpec(Doc), null)) {
                 Cast(dataDoc[fieldKey], listSpec(Doc), []).push(anchor);
@@ -804,9 +804,7 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch
     };
 
     resetTitle = () => {
-        this._props.mark[DocData].title = ComputedField.MakeFunction(
-            `["${this._props.endTag}"] ? "#" + formatToTime(this["${this._props.startTag}"]) + "-" + formatToTime(this["${this._props.endTag}"]) : "#" + formatToTime(this["${this._props.startTag}"]`
-        );
+        this._props.mark.$title = ComputedField.MakeFunction(`["${this._props.endTag}"] ? "#" + formatToTime(this["${this._props.startTag}"]) + "-" + formatToTime(this["${this._props.endTag}"]) : "#" + formatToTime(this["${this._props.startTag}"]`);
     };
     // context menu
     contextMenuItems = () => {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 392d85af3..9972fe03d 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -5,7 +5,6 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { ClientUtils, DivHeight, returnNone, returnZero, setupMoveUpEvents, smoothScroll } from '../../../ClientUtils';
 import { Doc, Opt } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
@@ -316,11 +315,11 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             const layoutFieldKey = StrCast(fieldProps.fieldKey);
             const newDoc = Doc.MakeCopy(fieldProps.Document, true);
             const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)];
-            newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
+            newDoc['$' + Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
             if (layoutFieldKey !== 'layout' && fieldProps.Document[layoutFieldKey] instanceof Doc) {
                 newDoc[layoutFieldKey] = fieldProps.Document[layoutFieldKey];
             }
-            newDoc[DocData].text = undefined;
+            newDoc.$text = undefined;
             DocumentView.SetSelectOnLoad(newDoc);
             return this.addDocument?.(newDoc);
         }
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 655894e40..29caead5b 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -9,7 +9,7 @@ import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, DateCast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types';
+import { BoolCast, Cast, DateCast, DocCast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types';
 import { WebField } from '../../../fields/URLField';
 import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
@@ -85,6 +85,9 @@ export function CollectionSubView<X>() {
         constructor(props: X & SubCollectionViewProps) {
             super(props);
             makeObservable(this);
+            console.log(`propsTitle: ${this._props.Document.title} DocTitle: ${this.Document.title} LayoutTitle:${this.layoutDoc.title} DataTitle:${this.dataDoc.title}`);
+            console.log(`tempTitle: ${this._props.TemplateDataDocument?.title} LayouTResolve: ${DocCast(this.layoutDoc.resolvedDataDoc)?.title} propDocResolve: ${DocCast(this._props.Document.resolvedDataDoc)?.title}`);
+            console.log('Children:', this.childDocs, this.childLayoutPairs);
         }
 
         @observable _focusFilters: Opt<string[]> = undefined; // childFilters that are overridden when previewing a link to an anchor which has childFilters set on it
@@ -108,7 +111,12 @@ export function CollectionSubView<X>() {
         }
 
         get dataDoc() {
-            return this._props.TemplateDataDocument instanceof Doc && this.Document.isTemplateForField ? Doc.GetProto(this._props.TemplateDataDocument) : this.Document.resolvedDataDoc ? this.Document : this.Document[DocData]; // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
+            console.log(this._props.Document.title + ' isTemplate: ' + this.layoutDoc.isTemplateForField);
+            return this._props.TemplateDataDocument instanceof Doc && this.layoutDoc.isTemplateForField //
+                ? this._props.TemplateDataDocument[DocData]
+                : this.layoutDoc.resolvedDataDoc
+                  ? this._props.Document
+                  : this.Document[DocData]; // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
         }
 
         get childContainerViewPath() {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index cc56a8ff9..2d2c0fce5 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -347,7 +347,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
                 undoable(() => {
                     const target = e.currentTarget as unknown as { value: string };
                     titleEle.size = target?.value.length + 3;
-                    doc[DocData].title = target?.value ?? '';
+                    doc.$title = target?.value ?? '';
                 }, 'edit tab title')();
             };
 
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 6208905fe..d6a19e88e 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -372,9 +372,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
             _width: 1000,
             _height: 10,
         });
-        const bulletData = bullet[DocData];
-        bulletData.title = ComputedField.MakeFunction('this.text?.Text');
-        bulletData.data = new List<Doc>([]);
+        bullet.$title = ComputedField.MakeFunction('this.text?.Text');
+        bullet.$data = new List<Doc>([]);
         DocumentView.addViewRenderedCb(bullet, dv => dv.ComponentView?.setFocus?.());
 
         return bullet;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx
index 8b9a3e0ec..35c6d30fe 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx
@@ -1,16 +1,15 @@
 import { makeObservable, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { Doc, DocListCast, FieldType, FieldResult } from '../../../../fields/Doc';
+import { Doc, DocListCast, FieldResult, FieldType } from '../../../../fields/Doc';
 import { InkTool } from '../../../../fields/InkField';
 import { StrCast } from '../../../../fields/Types';
 import { ObservableReactComponent } from '../../ObservableReactComponent';
 import { DocButtonState, DocumentLinksButton } from '../../nodes/DocumentLinksButton';
 import { TopBar } from '../../topbar/TopBar';
 import { CollectionFreeFormInfoState, InfoState, StateEntryFunc, infoState } from './CollectionFreeFormInfoState';
-import './CollectionFreeFormView.scss';
-import { DocData } from '../../../../fields/DocSymbols';
 import { CollectionFreeFormView } from './CollectionFreeFormView';
+import './CollectionFreeFormView.scss';
 
 export interface CollectionFreeFormInfoUIProps {
     Document: Doc;
@@ -41,7 +40,7 @@ export class CollectionFreeFormInfoUI extends ObservableReactComponent<Collectio
     set currState(val) { runInAction(() => {this._currState = val;}); } // prettier-ignore
 
     componentWillUnmount(): void {
-        this._props.Document[DocData].backgroundColor = this._originalbackground;
+        this._props.Document.$backgroundColor = this._originalbackground;
     }
 
     setCurrState = (state: infoState) => {
@@ -52,9 +51,9 @@ export class CollectionFreeFormInfoUI extends ObservableReactComponent<Collectio
     };
 
     setupStates = () => {
-        this._originalbackground = StrCast(this._props.Document[DocData].backgroundColor);
+        this._originalbackground = StrCast(this._props.Document.$backgroundColor);
         //  state entry functions
-        // const setBackground = (colour: string) => () => {this._props.Document[DocData].backgroundColor = colour;} // prettier-ignore
+        // const setBackground = (colour: string) => () => {this._props.Document.$backgroundColor = colour;} // prettier-ignore
         // const setOpacity = (opacity: number) => () => {this._props.LayoutDoc.opacity = opacity;} // prettier-ignore
         //  arc transition trigger conditions
         const firstDoc = () => (this._props.childDocs().length ? this._props.childDocs()[0] : undefined);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 89aa53c35..6030e146c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -561,7 +561,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 const { points } = ge;
                 const B = this.screenToFreeformContentsXf.transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height);
                 const inkDoc = this.createInkDoc(points, B);
-                if (Doc.ActiveInk === InkInkTool.Highlight) inkDoc[DocData].backgroundColor = 'transparent';
+                if (Doc.ActiveInk === InkInkTool.Highlight) inkDoc.$backgroundColor = 'transparent';
                 if (Doc.ActiveInk === InkInkTool.Write) {
                     this.unprocessedDocs.push(inkDoc);
                     CollectionFreeFormView.collectionsWithUnprocessedInk.add(this);
@@ -639,7 +639,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                         const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height);
                         const inkDoc = this.createInkDoc(points, B);
                         ['color', 'fillColor', 'stroke_width', 'stroke_dash', 'stroke_bezier'].forEach(field => {
-                            inkDoc[DocData][field] = stroke.dataDoc[field];
+                            inkDoc['$' + field] = stroke.dataDoc[field];
                         });
                         this.addDocument(inkDoc);
                     });
@@ -1260,15 +1260,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
      * Adds the created drawing to the freeform canvas and sets the metadata.
      */
     addDrawing = (doc: Doc, opts: DrawingOptions, gptRes: string, x?: number, y?: number) => {
-        const docData = doc[DocData];
-        docData.title = opts.text;
-        docData._width = opts.size;
-        docData.ai_drawing_input = opts.text;
-        docData.ai_drawing_complexity = opts.complexity;
-        docData.ai_drawing_colored = opts.autoColor;
-        docData.ai_drawing_size = opts.size;
-        docData.ai_drawing_data = gptRes;
-        docData.ai = 'gpt';
+        doc.$title = opts.text;
+        doc.$width = opts.size;
+        doc.$ai_drawing_input = opts.text;
+        doc.$ai_drawing_complexity = opts.complexity;
+        doc.$ai_drawing_colored = opts.autoColor;
+        doc.$ai_drawing_size = opts.size;
+        doc.$ai_drawing_data = gptRes;
+        doc.$ai = 'gpt';
         this._drawingContainer = doc;
         if (x !== undefined && y !== undefined) {
             [doc.x, doc.y] = this.screenToFreeformContentsXf.transformPoint(x, y);
@@ -1493,7 +1492,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     createTextDocCopy = undoable((fieldProps: FieldViewProps, below: boolean) => {
         const textDoc = DocCast(fieldProps.Document.rootDocument, fieldProps.Document);
         const newDoc = Doc.MakeCopy(textDoc, true);
-        newDoc[DocData][Doc.LayoutFieldKey(newDoc, fieldProps.LayoutTemplateString)] = undefined; // the copy should not copy the text contents of it source, just the render style
+        newDoc['$' + Doc.LayoutFieldKey(newDoc, fieldProps.LayoutTemplateString)] = undefined; // the copy should not copy the text contents of it source, just the render style
         newDoc.x = NumCast(textDoc.x) + (below ? 0 : NumCast(textDoc._width) + 10);
         newDoc.y = NumCast(textDoc.y) + (below ? NumCast(textDoc._height) + 10 : 0);
         DocumentView.SetSelectOnLoad(newDoc);
@@ -1686,7 +1685,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
      * since rendering a large collection of documents can be slow, at startup, docs are rendered in batches.
      * each doc's render() method will call the cutoff provider which will let the doc know if it should render itself yet, or wait
      */
-    renderCutoffProvider = computedFn((doc: Doc) => (this.Document.isTemplateDoc || this.Document.isTemplateForField ? false : !this._renderCutoffData.get(doc[Id] + '')));
+    renderCutoffProvider = computedFn((doc: Doc) => (this._props.Document.isTemplateDoc || this._props.Document.isTemplateForField ? false : !this._renderCutoffData.get(doc[Id] + '')));
 
     doEngineLayout(
         poolData: Map<string, PoolData>,
diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
index b9f8b13a7..b40189d76 100644
--- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
@@ -108,7 +108,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     if (faceAnno) {
                         faceAnno.face && FaceRecognitionHandler.UniqueFaceRemoveFaceImage(faceAnno, DocCast(faceAnno.face));
                         FaceRecognitionHandler.UniqueFaceAddFaceImage(faceAnno, this.Document);
-                        faceAnno[DocData].face = this.Document[DocData];
+                        faceAnno.$face = this.Document[DocData];
                     }
                 }
             });
@@ -118,7 +118,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 const imgDoc = faceAnno;
                 faceAnno.face && FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, DocCast(faceAnno.face));
                 FaceRecognitionHandler.UniqueFaceAddFaceImage(faceAnno, this.Document);
-                faceAnno[DocData].face = this.Document[DocData];
+                faceAnno.$face = this.Document[DocData];
             });
         e.stopPropagation();
         return true;
diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx
index a3d9641da..c983d7c26 100644
--- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx
@@ -9,7 +9,6 @@ import React from 'react';
 import { imageUrlToBase64 } from '../../../../ClientUtils';
 import { Utils, numberRange } from '../../../../Utils';
 import { Doc, NumListCast, Opt } from '../../../../fields/Doc';
-import { DocData } from '../../../../fields/DocSymbols';
 import { List } from '../../../../fields/List';
 import { ImageCast } from '../../../../fields/Types';
 import { gptGetEmbedding, gptImageLabel } from '../../../apis/gpt/GPT';
@@ -165,7 +164,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
         // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them.
 
         const imageInfos = this._selectedImages.map(async doc => {
-            if (!doc[DocData].tags_chat) {
+            if (!doc.$tags_chat) {
                 const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.');
                 return imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 =>
                 !hrefBase64 ? undefined : 
@@ -176,7 +175,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
         (await Promise.all(imageInfos)).forEach(imageInfo => {
             if (imageInfo) {
-                imageInfo.doc[DocData].tags_chat = (imageInfo.doc[DocData].tags_chat as List<string>) ?? new List<string>();
+                imageInfo.doc.$tags_chat = (imageInfo.doc.$tags_chat as List<string>) ?? new List<string>();
 
                 const labels = imageInfo.labels.split('\n');
                 labels.forEach(label => {
@@ -186,7 +185,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             .replace(/^\d+\.\s*|-|f\*/, '')
                             .replace(/^#/, '')
                             .trim();
-                    (imageInfo.doc[DocData].tags_chat as List<string>).push(hashLabel);
+                    (imageInfo.doc.$tags_chat as List<string>).push(hashLabel);
                 });
             }
         });
@@ -201,10 +200,10 @@ export class ImageLabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
         this.startLoading();
 
         for (const doc of this._selectedImages) {
-            for (let index = 0; index < (doc[DocData].tags_chat as List<string>).length; index++) {
-                const label = (doc[DocData].tags_chat as List<string>)[index];
+            for (let index = 0; index < (doc.$tags_chat as List<string>).length; index++) {
+                const label = (doc.$tags_chat as List<string>)[index];
                 const embedding = await gptGetEmbedding(label);
-                doc[DocData][`tags_embedding_${index + 1}`] = new List<number>(embedding);
+                doc[`$tags_embedding_${index + 1}`] = new List<number>(embedding);
             }
         }
 
@@ -215,13 +214,13 @@ export class ImageLabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
         // For each image, loop through the labels, and calculate similarity. Associate it with the
         // most similar one.
         this._selectedImages.forEach(doc => {
-            const embedLists = numberRange((doc[DocData].tags_chat as List<string>).length).map(n => Array.from(NumListCast(doc[DocData][`tags_embedding_${n + 1}`])));
+            const embedLists = numberRange((doc.$tags_chat as List<string>).length).map(n => Array.from(NumListCast(doc[`$tags_embedding_${n + 1}`])));
             const bestEmbedScore = (embedding: Opt<number[]>) => Math.max(...embedLists.map(l => (embedding && similarity(Array.from(embedding), l)!) || 0));
             const {label: mostSimilarLabelCollect} = 
                 this._labelGroups.map(label => ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) }))
                            .reduce((prev, cur) => cur.similarityScore < 0.3 || cur.similarityScore <= prev.similarityScore ? prev: cur,
                                    { label: '', similarityScore: 0, }); // prettier-ignore
-            doc[DocData].data_label = mostSimilarLabelCollect; // The label most similar to the image's contents.
+            doc.$data_label = mostSimilarLabelCollect; // The label most similar to the image's contents.
         });
 
         this.endLoading();
@@ -322,7 +321,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                             await DocumentView.showDocument(doc, { willZoomCentered: true });
                                         }}></img>
                                     <div className="image-information-labels" onClick={() => this._props.addDocTab(doc, OpenWhere.addRightKeyvalue)}>
-                                        {(doc[DocData].tags_chat as List<string>).map(label => {
+                                        {(doc.$tags_chat as List<string>).map(label => {
                                             return (
                                                 <div key={Utils.GenerateGuid()} className="image-label" style={{ backgroundColor: SettingsManager.userVariantColor, borderColor: SettingsManager.userColor }}>
                                                     {label}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index ad52db496..e3f4c6605 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -165,7 +165,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
                     error && console.log(error);
                     data &&
                         ClientUtils.convertDataUri(data, this._props.Document[Id] + '_icon_' + new Date().getTime()).then(returnedfilename => {
-                            this._props.Document[DocData].icon = new ImageField(returnedfilename);
+                            this._props.Document.$icon = new ImageField(returnedfilename);
                         });
                 })
             );
@@ -371,10 +371,9 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
         const newCollection = creator
             ? creator(selected, { title: 'nested stack' })
             : ((doc: Doc) => {
-                  const docData = doc[DocData];
-                  docData.data = new List<Doc>(selected);
-                  docData.isGroup = makeGroup;
-                  docData.title = makeGroup ? 'grouping' : 'nested freeform';
+                  doc.$data = new List<Doc>(selected);
+                  doc.$isGroup = makeGroup;
+                  doc.$title = makeGroup ? 'grouping' : 'nested freeform';
                   doc._freeform_panX = doc._freeform_panY = 0;
                   return doc;
               })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
@@ -462,9 +461,9 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
         const newColDim = 900;
         for (const label of labelGroups) {
             const newCollection = MarqueeView.getCollection([], undefined, false, this.Bounds);
-            newCollection[DocData].title = label + ' Collection';
-            newCollection._x = this.Bounds.left + x_offset;
-            newCollection._y = this.Bounds.top + y_offset;
+            newCollection.$title = label + ' Collection';
+            newCollection.x = this.Bounds.left + x_offset;
+            newCollection.y = this.Bounds.top + y_offset;
             newCollection._width = newColDim;
             newCollection._height = newColDim;
             newCollection._freeform_panX = this.Bounds.left + this.Bounds.width / 2;
@@ -481,8 +480,8 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
         }
 
         for (const doc of selectedImages) {
-            if (doc[DocData].data_label) {
-                Doc.AddDocToList(labelToCollection.get(doc[DocData].data_label as string)!, undefined, doc);
+            if (doc.$data_label) {
+                Doc.AddDocToList(labelToCollection.get(doc.$data_label as string)!, undefined, doc);
                 this._props.removeDocument?.(doc);
             }
         }
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 835c28daa..79d0ee88f 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -1,15 +1,12 @@
 /* eslint-disable @typescript-eslint/no-unused-vars */
 import { Colors } from '@dash/components';
 import { runInAction } from 'mobx';
-import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
+import { Doc, Opt, StrListCast } from '../../../fields/Doc';
 import { InkEraserTool, InkInkTool, InkProperty, InkTool } from '../../../fields/InkField';
-import { List } from '../../../fields/List';
 import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
 import { WebField } from '../../../fields/URLField';
 import { Gestures } from '../../../pen-gestures/GestureTypes';
-import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
-import { Docs } from '../../documents/Documents';
+import { DocumentType } from '../../documents/DocumentTypes';
 import { LinkManager } from '../../util/LinkManager';
 import { ScriptingGlobals } from '../../util/ScriptingGlobals';
 import { SnappingManager } from '../../util/SnappingManager';
@@ -17,30 +14,30 @@ import { UndoManager, undoable } from '../../util/UndoManager';
 import { GestureOverlay } from '../GestureOverlay';
 import { InkTranscription } from '../InkTranscription';
 import { PropertiesView } from '../PropertiesView';
+import { docSortings } from '../collections/CollectionSubView';
 import { CollectionFreeFormView } from '../collections/collectionFreeForm';
 import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
 import {
     ActiveEraserWidth,
-    ActiveInkFillColor,
-    ActiveInkColor,
     ActiveHideTextLabels,
+    ActiveInkColor,
+    ActiveInkFillColor,
     ActiveInkWidth,
     ActiveIsInkMask,
     DocumentView,
-    SetActiveInkFillColor,
     SetActiveInkColor,
-    SetactiveHideTextLabels,
+    SetActiveInkFillColor,
     SetActiveInkWidth,
     SetActiveIsInkMask,
     SetEraserWidth,
+    SetactiveHideTextLabels,
 } from '../nodes/DocumentView';
 import { ImageBox } from '../nodes/ImageBox';
+import { OpenWhere } from '../nodes/OpenWhere';
 import { VideoBox } from '../nodes/VideoBox';
 import { WebBox } from '../nodes/WebBox';
 import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
 import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
-import { OpenWhere } from '../nodes/OpenWhere';
-import { docSortings } from '../collections/CollectionSubView';
 
 // eslint-disable-next-line prefer-arrow-callback
 ScriptingGlobals.add(function IsNoneSelected() {
@@ -101,10 +98,7 @@ ScriptingGlobals.add(function setBorderColor(color?: string, checkResult?: boole
             return (selected.lastElement() ?? Doc.UserDoc()).borderColor ?? defaultBorder();
         }
         if (!selected.length) setDefaultBorder(color ?? 'transparent');
-        else
-            selected.forEach(doc => {
-                doc[DocData].borderColor = color;
-            });
+        else selected.forEach(doc => (doc.$borderColor = color));
     }
     return '';
 });
@@ -114,7 +108,7 @@ ScriptingGlobals.add(function setBorderColor(color?: string, checkResult?: boole
 ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: boolean) {
     const selectedViews = DocumentView.Selected();
     const selectedDoc = selectedViews.lastElement()?.Document;
-    const defaultFill = selectedDoc?._layout_isSvg ? () => StrCast(selectedDoc[DocData].fillColor) : !Doc.ActiveTool || Doc.ActiveTool === InkTool.None ? () => StrCast(Doc.UserDoc().textBackgroundColor, 'transparent') : () => ActiveInkFillColor();
+    const defaultFill = selectedDoc?._layout_isSvg ? () => StrCast(selectedDoc.$fillColor) : !Doc.ActiveTool || Doc.ActiveTool === InkTool.None ? () => StrCast(Doc.UserDoc().textBackgroundColor, 'transparent') : () => ActiveInkFillColor();
     const setDefaultFill = !Doc.ActiveTool || Doc.ActiveTool === InkTool.None  ? (c: string) => { Doc.UserDoc().textBackgroundColor = c; }: SetActiveInkFillColor; // prettier-ignore
     if (Doc.ActiveTool !== InkTool.None && !selectedViews.lastElement()?.Document._layout_isSvg) {
         if (checkResult) return defaultFill();
@@ -149,10 +143,7 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
             return selected.lastElement()?._backgroundColor ?? defaultFill();
         }
         if (!selected.length) setDefaultFill(color ?? 'transparent');
-        else
-            selected.forEach(doc => {
-                doc[DocData][doc._layout_isSvg ? 'fillColor' : 'backgroundColor'] = color;
-            });
+        else selected.forEach(doc => (doc[doc._layout_isSvg ? '$fillColor' : '$backgroundColor'] = color));
     }
     return '';
 });
@@ -170,7 +161,7 @@ ScriptingGlobals.add(function setHeaderColor(color?: string, checkResult?: boole
     }
     if (DocumentView.Selected().length) {
         DocumentView.SelectedDocs().forEach(doc => {
-            doc[DocData].layout_headingColor = color === 'transparent' ? undefined : color;
+            doc.$layout_headingColor = color === 'transparent' ? undefined : color;
             doc.layout_showTitle = color === 'transparent' ? undefined : StrCast(doc.layout_showTitle, 'title');
         });
     } else {
@@ -470,23 +461,23 @@ ScriptingGlobals.add(function setInkProperty(option: InkProperty, value: string
     // prettier-ignore
     const map: Map<InkProperty, { checkResult: () => number|boolean|string|undefined; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([
         [InkProperty.Mask, {
-            checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected[DocData].stroke_isInkMask) : ActiveIsInkMask())),
-            setInk: (doc: Doc) => { doc[DocData].stroke_isInkMask = !doc.stroke_isInkMask; },
+            checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected.$stroke_isInkMask) : ActiveIsInkMask())),
+            setInk: (doc: Doc) => { doc.$stroke_isInkMask = !doc.stroke_isInkMask; },
             setMode: () => SetActiveIsInkMask(value ? true : false)
         }],
         [InkProperty.Labels, {
-            checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected[DocData].stroke_showLabel) : !ActiveHideTextLabels())),
-            setInk: (doc: Doc) => { doc[DocData].stroke_showLabel = value; },
+            checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected.$stroke_showLabel) : !ActiveHideTextLabels())),
+            setInk: (doc: Doc) => { doc.$stroke_showLabel = value; },
             setMode: () => SetactiveHideTextLabels(value? false : true),
         }],
         [ InkProperty.StrokeWidth, {
-            checkResult: () => (selected?._layout_isSvg ? NumCast(selected[DocData].stroke_width, 1) : ActiveInkWidth()),
-            setInk: (doc: Doc) => { doc[DocData].stroke_width = NumCast(value); },
+            checkResult: () => (selected?._layout_isSvg ? NumCast(selected.$stroke_width, 1) : ActiveInkWidth()),
+            setInk: (doc: Doc) => { doc.$stroke_width = NumCast(value); },
             setMode: () => SetActiveInkWidth(value.toString()),
         }],
         [InkProperty.StrokeColor, {
-            checkResult: () => (selected?._layout_isSvg? StrCast(selected[DocData].color) : ActiveInkColor()),
-            setInk: (doc: Doc) => { doc[DocData].color = String(value); },
+            checkResult: () => (selected?._layout_isSvg? StrCast(selected.$color) : ActiveInkColor()),
+            setInk: (doc: Doc) => { doc.$color = String(value); },
             setMode: () => SetActiveInkColor(StrCast(value))
         }],
         [ InkProperty.EraserWidth, {
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 25e76e2a6..e0d59cc9d 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -296,7 +296,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 'Content-Type': 'application/json',
             },
         });
-        this.Document[DocData].phoneticTranscription = response.data['transcription'];
+        this.Document.$phoneticTranscription = response.data['transcription'];
     };
 
     // context menu
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index c0c6db4d3..992fbba66 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -80,8 +80,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
             const front = Docs.Create.CenteredTextCreator('question', question, {}, img);
             const back = Docs.Create.CenteredTextCreator('answer', answer, {});
             if (useDoc) {
-                useDoc[DocData][frontKey] = front;
-                useDoc[DocData][backKey] = back;
+                useDoc['$' + frontKey] = front;
+                useDoc['$' + backKey] = back;
                 return useDoc;
             }
             return Docs.Create.FlashcardDocument(title, front, back, { _width: 300, _height: 300 });
@@ -475,7 +475,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         axios
             .post(
                 'http://localhost:105/recognize/', //
-                { file: DocCast(this.Document.audio)[DocData].url },
+                { file: DocCast(this.Document.audio).$url },
                 { headers: { 'Content-Type': 'application/json' } }
             )
             .then(response => {
@@ -520,7 +520,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                   action(resp => {
                       switch (resp && callType) {
                           case GPTCallType.CHATCARD:
-                              DocCast(this.dataDoc[this.backKey])[DocData].text = resp;
+                              DocCast(this.dataDoc[this.backKey]).$text = resp;
                               break;
                           case GPTCallType.QUIZDOC:
                               this._renderSide = this.backKey;
@@ -618,7 +618,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
             const hrefBase64 = await imageUrlToBase64(u);
             const response = await gptImageLabel(hrefBase64, 'Answer the following question as a short flashcard response. Do not include a label.' + (this.dataDoc.text as RichTextField)?.Text);
 
-            DocCast(this.dataDoc[this.backKey])[DocData].text = response;
+            DocCast(this.dataDoc[this.backKey]).$text = response;
         } catch (error) {
             console.log('Error', error);
         }
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 7ef4bca6b..b31a0ec1e 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -160,8 +160,8 @@ export class TableBox extends ObservableReactComponent<TableBoxProps> {
                     DragManager.StartAnchorAnnoDrag(moveEv.target instanceof HTMLElement ? [moveEv.target] : [], new DragManager.AnchorAnnoDragData(this._props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, {
                         dragComplete: completeEv => {
                             if (!completeEv.aborted && completeEv.annoDragData && completeEv.annoDragData.linkSourceDoc && completeEv.annoDragData.dropDocument && completeEv.linkDocument) {
-                                completeEv.linkDocument[DocData].link_matchEmbeddings = true;
-                                completeEv.linkDocument[DocData].stroke_startMarker = true;
+                                completeEv.linkDocument.$link_matchEmbeddings = true;
+                                completeEv.linkDocument.$stroke_startMarker = true;
                                 this._props.docView?.()?._props.addDocument?.(completeEv.linkDocument);
                             }
                         },
diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx
index a49c69be3..3b666bad5 100644
--- a/src/client/views/nodes/DiagramBox.tsx
+++ b/src/client/views/nodes/DiagramBox.tsx
@@ -3,7 +3,6 @@ import { action, computed, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCast } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
 import { RichTextField } from '../../../fields/RichTextField';
 import { Cast, DocCast, NumCast, RTFCast, StrCast } from '../../../fields/Types';
 import { Gestures } from '../../../pen-gestures/GestureTypes';
@@ -46,7 +45,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     @observable _errorMessage = '';
 
     @computed get mermaidcode() {
-        return StrCast(this.Document[DocData].text, RTFCast(this.Document[DocData].text)?.Text);
+        return StrCast(this.Document.$text, RTFCast(this.Document.$text)?.Text);
     }
 
     componentDidMount() {
@@ -89,7 +88,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     };
 
     setMermaidCode = undoable((res: string) => {
-        this.Document[DocData].text = new RichTextField(
+        this.Document.$text = new RichTextField(
             JSON.stringify({
                 doc: {
                     type: 'doc',
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 46bd076d4..e9353b001 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -9,7 +9,7 @@ import { Fade, JackInTheBox } from 'react-awesome-reveal';
 import { ClientUtils, DivWidth, isTargetChildOf as isParentOf, lightOrDark, returnFalse, returnVal, simMouseEvent, simulateMouseClick } from '../../../ClientUtils';
 import { Utils, emptyFunction } from '../../../Utils';
 import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../fields/Doc';
-import { AclAdmin, AclEdit, AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols';
+import { AclAdmin, AclEdit, AclPrivate, Animation, AudioPlay, DocViews } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
@@ -40,6 +40,7 @@ import { FieldsDropdown } from '../FieldsDropdown';
 import { ObserverJsxParser } from '../ObservableReactComponent';
 import { PinProps } from '../PinFuncs';
 import { StyleProp } from '../StyleProp';
+import { TagsView } from '../TagsView';
 import { ViewBoxInterface } from '../ViewBoxInterface';
 import { GroupActive } from './CollectionFreeFormDocumentView';
 import { DocumentContentsView } from './DocumentContentsView';
@@ -52,7 +53,6 @@ import { FormattedTextBox } from './formattedText/FormattedTextBox';
 import { PresEffect, PresEffectDirection } from './trails/PresEnums';
 import SpringAnimation from './trails/SlideEffect';
 import { SpringType, springMappings } from './trails/SpringUtils';
-import { TagsView } from '../TagsView';
 
 export interface DocumentViewProps extends FieldViewSharedProps {
     hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected
@@ -426,7 +426,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
 
     noOnClick = undoable(() => {
         this.Document.ignoreClick = false;
-        this.Document.onClick = this.Document[DocData].onClick = undefined;
+        this.Document.onClick = this.Document.$onClick = undefined;
     }, 'default on click');
 
     deleteClicked = undoable(() => this._props.removeDocument?.(this.Document), 'delete doc');
@@ -758,7 +758,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
                     }}>
                     <DocumentContentsView
                         {...this._props}
-                        layoutFieldKey={StrCast(this.Document.layout_fieldKey, 'layout')}
+                        layoutFieldKey={StrCast(this._props.Document.layout_fieldKey, 'layout')}
                         pointerEvents={this.contentPointerEvents}
                         setContentViewBox={this.setContentView}
                         childFilters={this.childFilters}
@@ -1706,7 +1706,7 @@ ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuff
 
 // eslint-disable-next-line prefer-arrow-callback
 ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSource: Doc) {
-    const collectedLinks = DocListCast(linkCollection[DocData].data);
+    const collectedLinks = DocListCast(linkCollection.$data);
     let wid = NumCast(linkSource._width);
     let embedding: Doc | undefined;
     const links = Doc.Links(linkSource);
@@ -1729,7 +1729,7 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSour
 ScriptingGlobals.add(function updateTagsCollection(collection: Doc) {
     const tag = StrCast(collection.title).split('-->')[1];
     const matchedTags = Array.from(SearchUtil.SearchCollection(Doc.MyFilesystem, tag, false, ['tags']).keys());
-    const collectionDocs = DocListCast(collection[DocData].data).concat(collection);
+    const collectionDocs = DocListCast(collection.$data).concat(collection);
     let wid = 100;
     let created = false;
     const matchedDocs = matchedTags
@@ -1749,6 +1749,6 @@ ScriptingGlobals.add(function updateTagsCollection(collection: Doc) {
             return aset;
         }, new Set<Doc>());
 
-    created && (collection[DocData].data = new List<Doc>(Array.from(matchedDocs)));
+    created && (collection.$data = new List<Doc>(Array.from(matchedDocs)));
     return true;
 });
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 5b06e9fc5..5d9718760 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -284,10 +284,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     crop = (region: Doc | undefined, addCrop?: boolean) => {
         if (!region) return undefined;
         const cropping = Doc.MakeCopy(region, true);
-        const regionData = region[DocData];
-        regionData.lockedPosition = true;
-        regionData.title = 'region:' + this.Document.title;
-        regionData.followLinkToggle = true;
+        region.$lockedPosition = true;
+        region.$title = 'region:' + this.Document.title;
+        region.$followLinkToggle = true;
         this.addDocument(region);
         const anchx = NumCast(cropping.x);
         const anchy = NumCast(cropping.y);
@@ -300,24 +299,23 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         cropping._width = anchw * (this._props.NativeDimScaling?.() || 1);
         cropping._height = anchh * (this._props.NativeDimScaling?.() || 1);
         cropping.onClick = undefined;
-        const croppingProto = cropping[DocData];
-        croppingProto.annotationOn = undefined;
-        croppingProto.isDataDoc = true;
-        croppingProto.backgroundColor = undefined;
-        croppingProto.proto = Cast(this.Document.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.dataDoc[this.fieldKey] as ObjectField);
-        croppingProto.data_nativeWidth = anchw;
-        croppingProto.data_nativeHeight = anchh;
-        croppingProto.freeform_scale = viewScale;
-        croppingProto.freeform_panX = anchx / viewScale;
-        croppingProto.freeform_panY = anchy / viewScale;
-        croppingProto.freeform_scale_min = viewScale;
-        croppingProto.freeform_panX_min = anchx / viewScale;
-        croppingProto.freeform_panX_max = anchw / viewScale;
-        croppingProto.freeform_panY_min = anchy / viewScale;
-        croppingProto.freeform_panY_max = anchh / viewScale;
+        cropping.$annotationOn = undefined;
+        cropping.$isDataDoc = true;
+        cropping.$backgroundColor = undefined;
+        cropping.$proto = Cast(this.Document.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
+        cropping.$type = DocumentType.IMG;
+        cropping.$layout = ImageBox.LayoutString('data');
+        cropping.$data = ObjectField.MakeCopy(this.dataDoc[this.fieldKey] as ObjectField);
+        cropping.$data_nativeWidth = anchw;
+        cropping.$data_nativeHeight = anchh;
+        cropping.$freeform_scale = viewScale;
+        cropping.$reeform_panX = anchx / viewScale;
+        cropping.$freeform_panY = anchy / viewScale;
+        cropping.$freeform_scale_min = viewScale;
+        cropping.$freeform_panX_min = anchx / viewScale;
+        cropping.$freeform_panX_max = anchw / viewScale;
+        cropping.$freeform_panY_min = anchy / viewScale;
+        cropping.$freeform_panY_max = anchh / viewScale;
         if (addCrop) {
             DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
             cropping.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width);
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 9795febbe..32c9efbd9 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -105,7 +105,7 @@ export class KeyValueBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     if (setResult) setResult?.(value);
                     else target[key] = field;
                 };
-                const res = script.run({ this: Doc.Layout(doc), _setCacheResult_ }, console.log);
+                const res = script.run({ this: doc, _setCacheResult_ }, console.log);
                 if (!res.success) {
                     if (key) target[key] = script.originalScript;
                     return false;
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index d5dc256d9..8bf65b637 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -252,7 +252,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                     fontSize={fontSize}
                                     GetValue={() => linkDesc}
                                     SetValue={action(val => {
-                                        this.Document[DocData].link_description = val;
+                                        this.Document.$link_description = val;
                                         return true;
                                     })}
                                 />
@@ -262,8 +262,8 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                     background={color}
                                     color={fontColor || lightOrDark(DashColor(color).fade(0.5).toString())}
                                     type={Type.PRIM}
-                                    val={StrCast(this.Document[DocData].link_description)}
-                                    setVal={action(val => (this.Document[DocData].link_description = val))}
+                                    val={StrCast(this.Document.$link_description)}
+                                    setVal={action(val => (this.Document.$link_description = val))}
                                     fillWidth
                                 /> */}
                             </div>
diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx
index ff95f8547..6bec9c53d 100644
--- a/src/client/views/nodes/LinkDescriptionPopup.tsx
+++ b/src/client/views/nodes/LinkDescriptionPopup.tsx
@@ -1,7 +1,6 @@
 import { action, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { DocData } from '../../../fields/DocSymbols';
 import { StrCast } from '../../../fields/Types';
 import { LinkManager } from '../../util/LinkManager';
 import './LinkDescriptionPopup.scss';
@@ -48,7 +47,7 @@ export class LinkDescriptionPopup extends React.Component<{}> {
     onDismiss = (add: boolean) => {
         this.display = false;
         if (add) {
-            LinkManager.Instance.currentLink && (LinkManager.Instance.currentLink[DocData].link_description = this.description);
+            LinkManager.Instance.currentLink && (LinkManager.Instance.currentLink.$link_description = this.description);
         }
         this.description = '';
     };
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 06b75e243..1f72206fc 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -129,15 +129,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         cropping._width = anchw;
         cropping._height = anchh;
         cropping.onClick = undefined;
-        const croppingProto = cropping[DocData];
-        croppingProto.annotationOn = undefined;
-        croppingProto.isDataDoc = true;
-        croppingProto.proto = Cast(this.Document.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(ClientUtils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png'));
-        croppingProto.data_nativeWidth = anchw;
-        croppingProto.data_nativeHeight = anchh;
+        cropping.$annotationOn = undefined;
+        cropping.$isDataDoc = true;
+        cropping.$proto = Cast(this.Document.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
+        cropping.$type = DocumentType.IMG;
+        cropping.$layout = ImageBox.LayoutString('data');
+        cropping.$data = new ImageField(ClientUtils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png'));
+        cropping.$data_nativeWidth = anchw;
+        cropping.$data_nativeHeight = anchh;
         if (addCrop) {
             DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
         }
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index 7ba313e92..53783e8a3 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -3,7 +3,6 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { DateField } from '../../../../fields/DateField';
 import { Doc, DocListCast } from '../../../../fields/Doc';
-import { DocData } from '../../../../fields/DocSymbols';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { BoolCast, DocCast } from '../../../../fields/Types';
@@ -99,7 +98,7 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
                   });
         screengrabber.overlayX = 70; // was -400
         screengrabber.overlayY = 590; // was 0
-        screengrabber[DocData][Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true;
+        screengrabber['$' + Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true;
         Doc.AddToMyOverlay(screengrabber); // just adds doc to overlay
         DocumentView.addViewRenderedCb(screengrabber, docView => {
             RecordingBox.screengrabber = docView.ComponentView as RecordingBox;
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 9adee53e8..fa099178c 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -331,7 +331,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         Doc.SetNativeHeight(imageSnapshot[DocData], Doc.NativeHeight(this.layoutDoc));
         this._props.addDocument?.(imageSnapshot);
         DocUtils.MakeLink(imageSnapshot, this.getAnchor(true), { link_relationship: 'video snapshot' });
-        // link && (DocCast(link.link_anchor_2)[DocData].timecodeToHide = NumCast(DocCast(link.link_anchor_2).timecodeToShow) + 3);  // do we need to set an end time? should default to +0.1
+        // link && (DocCast(link.link_anchor_2).$timecodeToHide = NumCast(DocCast(link.link_anchor_2).timecodeToShow) + 3);  // do we need to set an end time? should default to +0.1
         setTimeout(() => downX !== undefined && downY !== undefined && DocumentView.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, dropActionType.move, true));
     };
 
@@ -918,11 +918,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     crop = (region: Doc | undefined, addCrop?: boolean) => {
         if (!region) return undefined;
         const cropping = Doc.MakeCopy(region, true);
-        const regionData = region[DocData];
-        regionData.backgroundColor = 'transparent';
-        regionData.lockedPosition = true;
-        regionData.title = 'region:' + this.Document.title;
-        regionData.followLinkToggle = true;
+        region.$backgroundColor = 'transparent';
+        region.$lockedPosition = true;
+        region.$title = 'region:' + this.Document.title;
+        region.$followLinkToggle = true;
         region._timecodeToHide = NumCast(region._timecodeToShow) + 0.0001;
         this.addDocument(region);
         const anchx = NumCast(cropping.x);
@@ -938,25 +937,24 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         cropping.timecodeToHide = undefined;
         cropping.timecodeToShow = undefined;
         cropping.onClick = undefined;
-        const croppingProto = cropping[DocData];
-        croppingProto.annotationOn = undefined;
-        croppingProto.isDataDoc = true;
-        croppingProto.proto = Cast(this.Document.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.dataDoc[this.fieldKey] as ObjectField);
-        croppingProto.data_nativeWidth = anchw;
-        croppingProto.data_nativeHeight = anchh;
-        croppingProto.videoCrop = true;
-        croppingProto.layout_currentTimecode = this.layoutDoc._layout_currentTimecode;
-        croppingProto.freeform_scale = viewScale;
-        croppingProto.freeform_scale_min = viewScale;
-        croppingProto.freeform_ = anchx / viewScale;
-        croppingProto.freeform_panY = anchy / viewScale;
-        croppingProto.freeform_panX_min = anchx / viewScale;
-        croppingProto.freeform_panX_max = anchw / viewScale;
-        croppingProto.freeform_panY_min = anchy / viewScale;
-        croppingProto.freeform_panY_max = anchh / viewScale;
+        cropping.$annotationOn = undefined;
+        cropping.$isDataDoc = true;
+        cropping.$proto = Cast(this.Document.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
+        cropping.$type = DocumentType.VID;
+        cropping.$layout = VideoBox.LayoutString('data');
+        cropping.$data = ObjectField.MakeCopy(this.dataDoc[this.fieldKey] as ObjectField);
+        cropping.$data_nativeWidth = anchw;
+        cropping.$data_nativeHeight = anchh;
+        cropping.$videoCrop = true;
+        cropping.$layout_currentTimecode = this.layoutDoc._layout_currentTimecode;
+        cropping.$freeform_scale = viewScale;
+        cropping.$freeform_scale_min = viewScale;
+        cropping.$freeform_ = anchx / viewScale;
+        cropping.$freeform_panY = anchy / viewScale;
+        cropping.$freeform_panX_min = anchx / viewScale;
+        cropping.$freeform_panX_max = anchw / viewScale;
+        cropping.$freeform_panY_min = anchy / viewScale;
+        cropping.$freeform_panY_max = anchh / viewScale;
         if (addCrop) {
             DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
         }
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index 1cbfd5fba..e3408696b 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -113,7 +113,7 @@ export class CalendarBox extends CollectionSubView() {
         if (!super.onInternalDrop(e, de)) return false;
         de.complete.docDragData?.droppedDocuments.forEach(doc => {
             const today = new Date().toISOString();
-            if (!doc.date_range) doc[DocData].date_range = `${today}|${today}`;
+            if (!doc.date_range) doc.$date_range = `${today}|${today}`;
         });
         return true;
     };
diff --git a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
index 6e9307d37..b023b1de6 100644
--- a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
+++ b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
@@ -733,9 +733,9 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     const x2 = parseFloat(values[2]) * Doc.NativeWidth(doc);
                     const y2 = parseFloat(values[3]) * Doc.NativeHeight(doc) + foundChunk.startPage * Doc.NativeHeight(doc);
 
-                    const annotationKey = Doc.LayoutFieldKey(doc) + '_annotations';
+                    const annotationKey = '$' + Doc.LayoutFieldKey(doc) + '_annotations';
 
-                    const existingDoc = DocListCast(doc[DocData][annotationKey]).find(d => d.citation_id === citation.citation_id);
+                    const existingDoc = DocListCast(doc[annotationKey]).find(d => d.citation_id === citation.citation_id);
                     const highlightDoc = existingDoc ?? this.createImageCitationHighlight(x1, y1, x2, y2, citation, annotationKey, doc);
 
                     DocumentManager.Instance.showDocument(highlightDoc, { willZoomCentered: true }, () => {});
@@ -779,7 +779,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             _height: y2 - y1,
             backgroundColor: 'rgba(255, 255, 0, 0.5)',
         });
-        highlight_doc[DocData].citation_id = citation.citation_id;
+        highlight_doc.$citation_id = citation.citation_id;
         Doc.AddDocToList(pdfDoc[DocData], annotationKey, highlight_doc);
         highlight_doc.annotationOn = pdfDoc;
         Doc.SetContainer(highlight_doc, pdfDoc);
diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx
index e0450b202..827db190a 100644
--- a/src/client/views/nodes/formattedText/EquationView.tsx
+++ b/src/client/views/nodes/formattedText/EquationView.tsx
@@ -6,7 +6,6 @@ import { EditorView } from 'prosemirror-view';
 import * as React from 'react';
 import * as ReactDOM from 'react-dom/client';
 import { Doc } from '../../../../fields/Doc';
-import { DocData } from '../../../../fields/DocSymbols';
 import { StrCast } from '../../../../fields/Types';
 import './DashFieldView.scss';
 import EquationEditor from './EquationEditor';
@@ -63,9 +62,9 @@ export class EquationViewInternal extends React.Component<IEquationViewInternal>
                 }}>
                 <EquationEditor
                     ref={this._ref}
-                    value={StrCast(this._textBoxDoc[DocData][this._fieldKey])}
+                    value={StrCast(this._textBoxDoc['$' + this._fieldKey])}
                     onChange={str => {
-                        this._textBoxDoc[DocData][this._fieldKey] = str;
+                        this._textBoxDoc['$' + this._fieldKey] = str;
                     }}
                     autoCommands="pi theta sqrt sum prod alpha beta gamma rho"
                     autoOperatorNames="sin cos tan"
diff --git a/src/client/views/nodes/imageEditor/ImageEditor.tsx b/src/client/views/nodes/imageEditor/ImageEditor.tsx
index 657e689bb..85bd95d15 100644
--- a/src/client/views/nodes/imageEditor/ImageEditor.tsx
+++ b/src/client/views/nodes/imageEditor/ImageEditor.tsx
@@ -24,8 +24,8 @@ import { PointerHandler } from './imageEditorUtils/PointerHandler';
 import { activeColor, bgColor, brushWidthOffset, canvasSize, eraserColor, freeformRenderSize, newCollectionSize, offsetDistanceY, offsetX } from './imageEditorUtils/imageEditorConstants';
 import { CutMode, CursorData, ImageDimensions, ImageEditTool, ImageToolType, Point } from './imageEditorUtils/imageEditorInterfaces';
 import { DocumentView } from '../DocumentView';
-import { DocData } from '../../../../fields/DocSymbols';
 import { SettingsManager } from '../../../util/SettingsManager';
+import { Upload } from '../../../../server/SharedMediaTypes';
 
 interface GenerativeFillProps {
     imageEditorOpen: boolean;
@@ -397,9 +397,8 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
             const newImgDoc = await createNewImgDoc(finalImg, firstDoc);
             if (newImgDoc) {
                 // set the image to transparent to remove the background / brushstrokes
-                const docData = newImgDoc[DocData];
-                docData.backgroundColor = 'transparent';
-                docData.disableMixBlend = true;
+                newImgDoc.$backgroundColor = 'transparent';
+                newImgDoc.$disableMixBlend = true;
                 if (firstDoc) setIsFirstDoc(false);
                 setEdits([...prevEdits, { url: finalImgURL, saveRes: undefined }]);
             }
@@ -476,7 +475,7 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
     const createNewImgDoc = async (img: HTMLImageElement, firstDoc: boolean /*, parent?: Doc */): Promise<Doc | undefined> => {
         if (!imageRootDoc) return undefined;
         const { src } = img;
-        const [result] = await Networking.PostToServer('/uploadRemoteImage', { sources: [src] });
+        const [result] = (await Networking.PostToServer('/uploadRemoteImage', { sources: [src] })) as Upload.ImageInformation[];
         const source = ClientUtils.prepend(result.accessPaths.agnostic.client);
 
         if (firstDoc) {
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index ec97e067a..23155ebf3 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -532,11 +532,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const setData = bestTargetView?.ComponentView?.setData;
             if (setData) setData(activeItem.config_data);
             else {
-                const bestTargetData = bestTarget[DocData];
-                const current = bestTargetData[fkey];
-                const hash = bestTargetData[fkey] ? stringHash(Field.toString(bestTargetData[fkey] as FieldType)) : undefined;
-                if (hash) bestTargetData[fkey + '_' + hash] = current instanceof ObjectField ? current[Copy]() : current;
-                bestTargetData[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data;
+                const current = bestTarget['$' + fkey];
+                const hash = bestTarget['$' + fkey] ? stringHash(Field.toString(bestTarget['$' + fkey] as FieldType)) : undefined;
+                if (hash) bestTarget['$' + fkey + '_' + hash] = current instanceof ObjectField ? current[Copy]() : current;
+                bestTarget['$' + fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data;
             }
             bestTarget[fkey + '_usePath'] = activeItem.config_usePath;
             setTimeout(() => {
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx
index 1cceabed3..2283ef965 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.tsx
+++ b/src/client/views/smartdraw/SmartDrawHandler.tsx
@@ -10,9 +10,11 @@ import { INode, parse } from 'svgson';
 import { imageUrlToBase64, setupMoveUpEvents } from '../../../ClientUtils';
 import { unimplementedFunction } from '../../../Utils';
 import { Doc, DocListCast } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
 import { InkData, InkField, InkTool } from '../../../fields/InkField';
+import { List } from '../../../fields/List';
 import { BoolCast, ImageCast, NumCast, StrCast } from '../../../fields/Types';
+import { PointData } from '../../../pen-gestures/GestureTypes';
+import { Upload } from '../../../server/SharedMediaTypes';
 import { Networking } from '../../Network';
 import { GPTCallType, gptAPICall, gptDrawingColor } from '../../apis/gpt/GPT';
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -26,9 +28,6 @@ import { MarqueeView } from '../collections/collectionFreeForm';
 import { ActiveInkArrowEnd, ActiveInkArrowStart, ActiveInkBezierApprox, ActiveInkColor, ActiveInkDash, ActiveInkFillColor, ActiveInkWidth, ActiveIsInkMask, DocumentView } from '../nodes/DocumentView';
 import { FireflyDimensionsMap, FireflyImageData, FireflyImageDimensions } from './FireflyConstants';
 import './SmartDrawHandler.scss';
-import { Upload } from '../../../server/SharedMediaTypes';
-import { PointData } from '../../../pen-gestures/GestureTypes';
-import { List } from '../../../fields/List';
 
 export interface DrawingOptions {
     text?: string;
@@ -153,9 +152,9 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
         this._display = false;
         this.ShowRegenerate = true;
         this._showEditBox = false;
-        const docData = this._selectedDocs[0][DocData];
-        this._lastResponse = StrCast(docData.drawingData);
-        this._lastInput = { text: StrCast(docData.ai_drawing_input), complexity: NumCast(docData.ai_drawing_complexity), size: NumCast(docData.ai_drawing_size), autoColor: BoolCast(docData.ai_drawing_colored), x: this._pageX, y: this._pageY };
+        const docData = this._selectedDocs[0];
+        this._lastResponse = StrCast(docData.$drawingData);
+        this._lastInput = { text: StrCast(docData.$ai_drawing_input), complexity: NumCast(docData.$ai_drawing_complexity), size: NumCast(docData.$ai_drawing_size), autoColor: BoolCast(docData.$ai_drawing_colored), x: this._pageX, y: this._pageY };
     };
 
     /**
@@ -404,7 +403,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
         const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`;
         try {
             const hrefBase64 = await imageUrlToBase64(hrefComplete);
-            const strokes = DocListCast(drawing[DocData].data);
+            const strokes = DocListCast(drawing.$data);
             const coords: string[] = [];
             strokes.forEach((stroke, i) => {
                 const inkingStroke = DocumentView.getDocumentView(stroke)?.ComponentView as InkingStroke;
@@ -423,14 +422,14 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
      */
     colorStrokes = undoable((res: string, drawing: Doc) => {
         const colorList = res.match(/\{.*?\}/g);
-        const strokes = DocListCast(drawing[DocData].data);
+        const strokes = DocListCast(drawing.$data);
         colorList?.forEach((colors, index) => {
             const strokeAndFill = colors.match(/#[0-9A-Fa-f]{6}/g);
             if (strokeAndFill && strokeAndFill.length == 2) {
-                strokes[index][DocData].color = strokeAndFill[0];
+                strokes[index].$color = strokeAndFill[0];
                 const inkStroke = DocumentView.getDocumentView(strokes[index])?.ComponentView as InkingStroke;
                 const { inkData } = inkStroke.inkScaledData();
-                InkingStroke.IsClosed(inkData) ? (strokes[index][DocData].fillColor = strokeAndFill[1]) : (strokes[index][DocData].fillColor = undefined);
+                InkingStroke.IsClosed(inkData) ? (strokes[index].$fillColor = strokeAndFill[1]) : (strokes[index].$fillColor = undefined);
             }
         });
     }, 'color strokes');
diff --git a/src/client/views/smartdraw/StickerPalette.tsx b/src/client/views/smartdraw/StickerPalette.tsx
index e3305851a..080a05d42 100644
--- a/src/client/views/smartdraw/StickerPalette.tsx
+++ b/src/client/views/smartdraw/StickerPalette.tsx
@@ -9,7 +9,6 @@ import ReactLoading from 'react-loading';
 import { returnEmptyFilter, returnFalse, returnTrue } from '../../../ClientUtils';
 import { emptyFunction, numberRange } from '../../../Utils';
 import { Doc, DocListCast, returnEmptyDoclist } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
 import { ImageCast, NumCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -133,7 +132,7 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
         this._canInteract = true;
         this._opts = { text: '', complexity: 5, size: 200, autoColor: true, x: 0, y: 0 };
         this._gptRes = [];
-        this._props.Document[DocData].data = undefined;
+        this._props.Document.$data = undefined;
     });
 
     /**
@@ -143,8 +142,8 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
     @undoBatch
     generateDrawings = action(() => {
         this._isLoading = true;
-        const prevDrawings = DocListCast(this._props.Document[DocData].data);
-        this._props.Document[DocData].data = undefined;
+        const prevDrawings = DocListCast(this._props.Document.$data);
+        this._props.Document.$data = undefined;
         SmartDrawHandler.Instance.AddDrawing = this.addDrawing;
         this._canInteract = false;
         Promise.all(
@@ -164,7 +163,7 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
     @action
     addDrawing = (drawing: Doc, opts: DrawingOptions, gptRes: string) => {
         this._gptRes.push(gptRes);
-        drawing[DocData].freeform_fitContentsToBox = true;
+        drawing.$freeform_fitContentsToBox = true;
         Doc.AddDocToList(this._props.Document, 'data', drawing);
     };
 
@@ -176,17 +175,16 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
     saveDrawing = () => {
         const cIndex = NumCast(this._props.Document.carousel_index);
         const focusedDrawing = DocListCast(this._props.Document.data)[cIndex];
-        const docData = focusedDrawing[DocData];
-        docData.title = this._opts.text?.match(/^(.*?)~~~.*$/)?.[1] || this._opts.text;
-        docData.ai_drawing_input = this._opts.text;
-        docData.ai_drawing_complexity = this._opts.complexity;
-        docData.ai_drawing_colored = this._opts.autoColor;
-        docData.ai_drawing_size = this._opts.size;
-        docData.ai_drawing_data = this._gptRes[cIndex];
-        docData.ai = 'gpt';
+        focusedDrawing.$title = this._opts.text?.match(/^(.*?)~~~.*$/)?.[1] || this._opts.text;
+        focusedDrawing.$ai_drawing_input = this._opts.text;
+        focusedDrawing.$ai_drawing_complexity = this._opts.complexity;
+        focusedDrawing.$ai_drawing_colored = this._opts.autoColor;
+        focusedDrawing.$ai_drawing_size = this._opts.size;
+        focusedDrawing.$ai_drawing_data = this._gptRes[cIndex];
+        focusedDrawing.$ai = 'gpt';
         focusedDrawing.width = this._opts.size;
-        docData.x = this._opts.x;
-        docData.y = this._opts.y;
+        focusedDrawing.x = this._opts.x;
+        focusedDrawing.y = this._opts.y;
         StickerPalette.addToPalette(focusedDrawing).then(() => this.resetPalette(true));
     };
 
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index e2f708700..4bf04da5c 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -273,12 +273,12 @@ export class Doc extends RefField {
     public static AddToMyOverlay(doc: Doc)    { return Doc.ActiveDashboard ? Doc.AddDocToList(Doc.ActiveDashboard, 'myOverlayDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore
     public static RemFromMyOverlay(doc: Doc)  { return Doc.ActiveDashboard ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myOverlayDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore
     public static AddToMyPublished(doc: Doc)  {
-        doc[DocData].title_custom = true;
-        doc[DocData].layout_showTitle = 'title'; 
+        doc.$title_custom = true;
+        doc.$layout_showTitle = 'title'; 
         Doc.ActiveDashboard ? Doc.AddDocToList(Doc.ActiveDashboard, 'myPublishedDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore
     public static RemFromMyPublished(doc: Doc){ 
-        doc[DocData].title_custom = false;
-        doc[DocData].layout_showTitle = undefined;
+        doc.$title_custom = false;
+        doc.$layout_showTitle = undefined;
         Doc.ActiveDashboard ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myPublishedDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore
     public static IsComicStyle(doc?: Doc)     { return doc && Doc.ActiveDashboard && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === 'comic' ; } // prettier-ignore
 
@@ -629,7 +629,7 @@ export namespace Doc {
      */
     export function RemoveDocFromList(listDoc: Doc, fieldKey: string | undefined, doc: Doc, ignoreProto = false) {
         const key = fieldKey || Doc.LayoutFieldKey(listDoc);
-        const list = Doc.Get(listDoc, key, ignoreProto) === undefined ? (listDoc[DocData][key] = new List<Doc>()) : Cast(listDoc[key], listSpec(Doc));
+        const list = Doc.Get(listDoc, key, ignoreProto) === undefined ? (listDoc['$' + key] = new List<Doc>()) : Cast(listDoc[key], listSpec(Doc));
         if (list) {
             const ind = list.indexOf(doc);
             if (ind !== -1) {
@@ -646,7 +646,7 @@ export namespace Doc {
      */
     export function AddDocToList(listDoc: Doc, fieldKey: string | undefined, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean, reversed?: boolean, ignoreProto?: boolean) {
         const key = fieldKey || Doc.LayoutFieldKey(listDoc);
-        const list = Doc.Get(listDoc, key, ignoreProto) === undefined ? (listDoc[DocData][key] = new List<Doc>()) : Cast(listDoc[key], listSpec(Doc));
+        const list = Doc.Get(listDoc, key, ignoreProto) === undefined ? (listDoc['$' + key] = new List<Doc>()) : Cast(listDoc[key], listSpec(Doc));
         if (list) {
             if (!allowDuplicates) {
                 const pind = list.findIndex(d => d instanceof Doc && d[Id] === doc[Id]);
@@ -691,7 +691,7 @@ export namespace Doc {
             Doc.SetLayout(embedding, Doc.MakeEmbedding(layout));
         }
         embedding.createdFrom = doc;
-        embedding.proto_embeddingId = doc[DocData].proto_embeddingId = Doc.GetEmbeddings(doc).length - 1;
+        embedding.proto_embeddingId = doc.$proto_embeddingId = Doc.GetEmbeddings(doc).length - 1;
         !Doc.GetT(embedding, 'title', 'string', true) && (embedding.title = ComputedField.MakeFunction(`renameEmbedding(this)`));
         embedding.author = ClientUtils.CurrentUserEmail();
 
@@ -699,9 +699,8 @@ export namespace Doc {
     }
 
     export function BestEmbedding(doc: Doc) {
-        const dataDoc = doc[DocData];
-        const availableEmbeddings = Doc.GetEmbeddings(dataDoc);
-        const bestEmbedding = [...(dataDoc !== doc ? [doc] : []), ...availableEmbeddings].find(d => !d.embedContainer && d.author === ClientUtils.CurrentUserEmail());
+        const availableEmbeddings = Doc.GetEmbeddings(doc);
+        const bestEmbedding = [...(doc[DocData] !== doc ? [doc] : []), ...availableEmbeddings].find(d => !d.embedContainer && d.author === ClientUtils.CurrentUserEmail());
         bestEmbedding && Doc.AddEmbedding(doc, doc);
         return bestEmbedding ?? Doc.MakeEmbedding(doc);
     }
@@ -1475,7 +1474,7 @@ export namespace Doc {
      * @returns
      */
     export function getDescription(doc: Doc) {
-        const curDescription = StrCast(doc[DocData][Doc.LayoutFieldKey(doc) + '_description']);
+        const curDescription = StrCast(doc['$' + Doc.LayoutFieldKey(doc) + '_description']);
         const docText = (async (tdoc:Doc) => {
             switch (tdoc.type) {
                 case DocumentType.PDF: return curDescription || StrCast(tdoc.text).split(/\s+/).slice(0, 50).join(' '); // first 50 words of pdf text
@@ -1484,7 +1483,7 @@ export namespace Doc {
                 case DocumentType.RTF: return RTFCast(tdoc[Doc.LayoutFieldKey(tdoc)]).Text;
                 default:               return StrCast(tdoc.title).startsWith("Untitled") ? "" : StrCast(tdoc.title);
         }}); // prettier-ignore
-        return docText(doc).then(text => (doc[DocData][Doc.LayoutFieldKey(doc) + '_description'] = text));
+        return docText(doc).then(text => (doc['$' + Doc.LayoutFieldKey(doc) + '_description'] = text));
     }
 
     // prettier-ignore
@@ -1737,7 +1736,7 @@ ScriptingGlobals.add(function idToDoc(id: string): Doc {
 });
 // eslint-disable-next-line prefer-arrow-callback
 ScriptingGlobals.add(function renameEmbedding(doc: Doc) {
-    return StrCast(doc[DocData].title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`;
+    return StrCast(doc.$title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`;
 });
 // eslint-disable-next-line prefer-arrow-callback
 ScriptingGlobals.add(function getProto(doc: Doc) {
diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts
index b294ee8c6..6e2d7eb78 100644
--- a/src/fields/ScriptField.ts
+++ b/src/fields/ScriptField.ts
@@ -210,6 +210,7 @@ export class ComputedField extends ScriptField {
         this._lastComputedResult =
             this._cachedResult ??
             computedFn(() =>
+                ((val) => val instanceof Array ? new List<number>(val) : val)(
                 this.script.compiled &&
                 this.script.run(
                     {
@@ -220,7 +221,7 @@ export class ComputedField extends ScriptField {
                         _readOnly_: true,
                     },
                     console.log
-                ).result as FieldResult
+                ).result as FieldResult)
             )(); // prettier-ignore
         return this._lastComputedResult;
     };
-- 
cgit v1.2.3-70-g09d2

