Frame Editors
This document explains CoCalc's frame editor system — the layout tree that lets users view multiple panes (source, preview, terminal, table of contents, etc.) for a single file.
Overview
Every file in CoCalc opens in a frame editor: a container that arranges one or more frames (editor panes) in a resizable layout tree with split nodes and tab containers. Each file type defines its own editor spec — a map of available frame types with their React components, commands, and toolbar buttons.
The layout is a tree: each node is either a leaf (a single frame), a split node that arranges children horizontally ("row") or vertically ("col"), or a tab container. Legacy binary trees are still loaded, but current state is normalized to the newer children/sizes representation.
For the current drag-and-drop behavior and tab/split mutation logic, see docs/frame-editor-dnd.md.
Architecture
Key Components
Frame Tree Structure
Tree operations are in tree-ops.ts:
set(tree, {id, ...})— update a node by IDset_leafs(tree, obj)— update all leaf nodesdelete_node(tree, id)— remove a node (sibling takes parent's place)generate_id(tree)— assign unique IDs to all nodesmigrateToNary(tree)— convert legacy binary trees tochildren/sizes
EditorDescription
Each frame type is defined by an EditorDescription:
EditorType Values
All available frame types (from the EditorType union):
| Type | Description |
|---|---|
"cm" | CodeMirror source editor |
"slate" | Slate rich text editor |
"markdown" / "markdown-rendered" | Rendered markdown view |
"markdown-toc" | Markdown table of contents |
"jupyter" | Jupyter notebook cells |
"jupyter-toc" | Jupyter table of contents |
"terminal" | Terminal emulator |
"latex" / "latex-build" / "latex-output" / "latex-toc" | LaTeX editor frames |
"pdfjs-canvas" | PDF viewer |
"preview-html" | HTML preview |
"search" | Search panel |
"settings" | Editor settings |
"timetravel" | Time travel (version history) |
"errors" | Error display |
"chat" / "chatroom" | Side chat |
"tasks" | Task list |
"whiteboard" | Whiteboard canvas |
"slides" / "slides-slideshow" | Slides editor |
"course-students" / "course-assignments" / etc. | Course management tabs |
Creating an Editor
Each file type creates its editor via createEditor():
Example: Code Editor
Example: Markdown Editor
Registration
Editors register for file extensions via register_file_editor():
Registration supports async loading — editor code is loaded on demand when a file is first opened, with timeout/retry logic for network resilience.
The registration system maintains a reference count per open file. When the count drops to zero, the Redux store and actions for that file are cleaned up.
Editor-Specific Directories
Each file type has its own directory under packages/frontend/frame-editors/:
| Directory | File Types | Frames |
|---|---|---|
code-editor/ | .py, .js, .ts, etc. | cm, terminal, time_travel |
markdown-editor/ | .md | slate, cm, markdown, toc |
latex-editor/ | .tex | cm, pdf, build log, toc, errors |
jupyter-editor/ | .ipynb | jupyter, toc, json, introspect |
html-editor/ | .html | cm, iframe preview |
pdf-editor/ | .pdf | pdfjs-canvas |
terminal-editor/ | .term | terminal |
course-editor/ | .course | students, assignments, handouts, config |
slides-editor/ | .board slides | whiteboard, slideshow |
csv-editor/ | .csv | grid view, cm |
sagews-editor/ | .sagews | sage cells, cm |
rst-editor/ | .rst | cm, html preview |
rmd-editor/ | .rmd | cm, html preview, build |
qmd-editor/ | .qmd | cm, preview, build log |
crm-editor/ | CRM tools | CRM tables, accounts |
chat-editor/ | .sage-chat | chatroom |
time-travel-editor/ | (built-in) | version history viewer |
settings/ | (built-in) | editor settings panel |
EditorComponentProps
Every frame component receives these props:
Commands System
packages/frontend/frame-editors/frame-tree/commands/ defines the command registry. Commands are actions available via menus, keyboard shortcuts, and toolbar buttons.
Each EditorDescription declares which commands are available (commands) and which appear as toolbar buttons (buttons). Commands can be customized per frame type via customizeCommands.
Common commands: save, undo, redo, find, replace, goto_line, increase_font_size, decrease_font_size, time_travel, terminal, chatgpt, format, print, cut, copy, paste.
Actions Base Class
packages/frontend/frame-editors/code-editor/actions.ts provides the base Actions class for frame editors. Key responsibilities:
Frame tree management (split, close, focus, resize, save/load custom layouts)
SyncDoc/SyncString lifecycle
Save/load coordination
Undo/redo
Format (via prettier, etc.)
Terminal management
Time travel initialization
Settings persistence
Each editor type can extend this base class to add file-type-specific behavior.
Key Source Files
| File | Description |
|---|---|
frame-editors/frame-tree/types.ts | FrameTree, EditorDescription, EditorComponentProps |
frame-editors/frame-tree/editor.tsx | FrameTreeEditor component, createEditor() |
frame-editors/frame-tree/frame-tree.tsx | Recursive binary tree renderer |
frame-editors/frame-tree/leaf.tsx | Single frame renderer |
frame-editors/frame-tree/title-bar.tsx | Frame tabs and toolbar |
frame-editors/frame-tree/status-bar.tsx | Bottom status line |
frame-editors/frame-tree/tree-ops.ts | Binary tree manipulation |
frame-editors/frame-tree/register.ts | register_file_editor() |
frame-editors/frame-tree/commands/ | Command definitions |
frame-editors/code-editor/editor.ts | Code editor spec |
frame-editors/code-editor/actions.ts | Base Actions class |
frame-editors/code-editor/codemirror-editor.tsx | CodeMirror component |
frame-editors/markdown-editor/editor.ts | Markdown editor spec |
frame-editors/latex-editor/editor.ts | LaTeX editor spec |
frame-editors/jupyter-editor/editor.ts | Jupyter editor spec |
frame-editors/terminal-editor/editor.ts | Terminal frame definition |
frame-editors/generic/chat.ts | Side chat frame (included in all editors) |
Common Patterns for Agents
Adding a New Frame Type
Define an
EditorDescriptionwith component, commands, buttonsAdd it to the editor spec of the relevant file type
The frame will automatically appear in the title bar dropdown