Keyboard Shortcuts
All shortcuts below are suppressed while focus is inside a text input, textarea, select or a
contentEditable element (Monaco counts as one) — except Ctrl/Cmd+S, which still prevents the
browser's own save dialog everywhere, but only actually saves the draft when the shell itself has
focus. Every handler lives in apps/web/src/ui/TableEditModeShell.tsx unless noted.
Transform tools#
| Key | Effect | Handler |
|---|---|---|
Q |
Select tool (no gizmo) | setTransformGizmoMode("select"), global keydown |
W |
Move gizmo | setTransformGizmoMode("move") |
E |
Rotate gizmo | setTransformGizmoMode("rotate") |
R |
Scale gizmo | setTransformGizmoMode("scale") |
F |
Frame selection: re-select the selection and re-attach the gizmo. ⚠ The camera does not move yet — see Frame selection | canvasRef.current?.selectObject(...) |
Pressing any of Q/W/E/R first exits an active Snap Point
tool (exitSnapTool()), so a
snap-authoring gesture and a transform tool are never armed together.
Selection and editing#
| Key | Effect | Handler |
|---|---|---|
Escape |
Context-aware: unwinds an in-progress Snap grid batch, then the Snap sub-tool, then the Snap flyout — only then clears the scene selection | global keydown handler |
Delete / Backspace |
Deletes the selected deletable node (object, seat-zone, seat-group, light, poster). With a multi-selection, deletes every selected entity after one confirmation; children move up to their parents |
separate handler |
Ctrl/Cmd+Z |
Undo | undo() |
Ctrl/Cmd+Shift+Z |
Redo | same handler, event.shiftKey branch |
Ctrl/Cmd+Y |
Redo | redo() |
Ctrl/Cmd+D |
Duplicate the selection — every selected entity, each with its subtree | duplicateObjects([...selection]) |
Ctrl/Cmd+C |
Copy the selection — every selected entity, each with its subtree | copyObjects([...selection]) |
Ctrl/Cmd+V |
Paste everything that was copied | pasteObject() |
F2 |
Focus the Inspector's Name field (rename) | focusInspectorNameField() |
| Arrow Up/Down/Left/Right | Nudge the selection on the table plane (world axes: Up/Down = −/+Z, Left/Right = −/+X), step 0.05, or 0.25 with Shift. A multi-selection moves together; children ride with a selected parent, and locked entities hold still |
nudgeSelectedObject(dx, dz) |
Ctrl/Cmd+click on a Hierarchy row |
Toggle that object in/out of the multi-selection | selectThis — see Multi-select |
Shift+click on a Hierarchy row |
Select the visible range from the last plain-click anchor | same handler |
Ctrl/Cmd+click an entity in the viewport |
Toggle that entity in/out of the selection | TabletopRuntime transform-mode pointer handler |
| Drag on empty space in the viewport | Box-select: replace the selection with every unlocked entity whose centre is inside the box | finalizeBoxSelection |
Ctrl/Cmd+drag on empty space in the viewport |
Box-select, adding to the selection | same, additive |
Every row above that edits or moves "the selection" acts on the whole multi-selection when there is one; see Multi-select.
Saving and projects#
| Key | Effect | Handler |
|---|---|---|
Ctrl/Cmd+S |
Save the draft. Always prevents the browser's save dialog; only actually saves when the shell (not Monaco or a PCUI field) owns focus | saveDraftRef.current() |
Ctrl/Cmd+O |
Open the project picker (File ▸ Open Project…). Always prevents the browser's open-file dialog; does nothing while typing in a field or with a dialog open | setProjectPickerOpen(true) |
Monaco binds its own Ctrl+S inside the Script editor (compile
- save the script); the shell's handler detects
event.defaultPreventedand defers to it rather than double-saving.
Tabs (the item-editor tab strip)#
| Key / action | Effect | Handler |
|---|---|---|
Alt+W |
Close the active item tab (never the Scene tab) | ItemEditorTabs.tsx |
Ctrl/Cmd+Tab |
Cycle Scene → tabs → Scene, forward | cycleTabId(state, 1), ItemEditorTabs.tsx |
Ctrl/Cmd+Shift+Tab |
Cycle backward | same, cycleTabId(state, -1) |
| Middle-click a tab | Close it | onAuxClick, ItemEditorTabs.tsx |
Click the tab's × |
Close it | onRequestClose, ItemEditorTabs.tsx |
⚠ Not Ctrl/Cmd+W — browsers reserve it to close the whole browser tab and ignore
preventDefault, so the shell deliberately doesn't advertise it. See Item editors:
Model for the rest of the tab-strip conventions
(dirty dots, the unsaved-changes guard, mounted-but-hidden inactive tabs).
Asset explorer#
These apply while the item area of an Asset Explorer
pane has focus (click an item or empty space in it first). They are handled by the pane itself
(ExplorerItemsView.tsx, useExplorerSelection.ts, explorerClipboard.ts), and the pane
claims Ctrl/Cmd+C/X/V/D, F2 and Delete, so the scene's own shortcuts for those
keys above do not also fire on the selected entity.
| Key | Effect |
|---|---|
Arrow keys, Home, End |
Move through the items in display order |
Shift+arrow / Home / End |
Extend the selection |
Space |
Select the focused item (Ctrl/Cmd+Space toggles it) |
Ctrl/Cmd+A |
Select every item in the folder |
Escape |
Clear the selection (only when something is selected) |
Enter |
Open the focused folder or item |
Ctrl/Cmd+C |
Copy the selection (the only file command in the read-only Library pane) |
Ctrl/Cmd+X |
Cut the selection (Project pane) |
Ctrl/Cmd+V |
Paste into the current folder: a cut moves, a copy copies |
Ctrl/Cmd+D |
Duplicate the selection in place (Name (2)) |
F2 |
Rename one item in place (Project pane). In the field, Enter renames and Esc cancels. See Renaming in place |
Delete / Cmd+Backspace |
Delete the selection (Project pane), after at most one confirmation. In the dialog, Enter deletes and Esc cancels. See Deleting |
Ctrl/Cmd + mouse wheel |
Step through the views, Large icons ↔ Tiles |
With the mouse: Ctrl/Cmd+click toggles an item, Shift+click selects a range,
Ctrl/Cmd+Shift+click adds a range, dragging on empty space draws a selection box (Ctrl/Cmd
adds to the selection), and Ctrl+drag (Option+drag on macOS) onto a folder copies instead of
moving.
Plain Backspace is never claimed. None of these fire while focus is in a text field, Monaco, a
PCUI input or the viewport canvas.
Photo mode#
Photo mode is not part of the Edit Mode shell. It runs at the table: in the
Preview tab, and on /table for every player.
These bindings are handled by apps/web/src/ui/photo/photoShortcuts.ts and usePhotoMode.ts.
| Key | When | Effect |
|---|---|---|
Shift+P |
At the table, in or out of photo mode | Enter or leave photo mode. Plain P is not bound |
Enter |
Photo mode only | Capture with the panel's current size and format. Ignored while focus is on a button, link or checkbox, where Enter already activates that control |
H |
Photo mode only | Hide or show the Visibility panel |
Esc |
Photo mode only | Leave photo mode. Consumed by photo mode, so it does not also close a table menu underneath |
None of them fire while focus is in a text field, with one exception: while you are typing a
preset name in the panel, Esc belongs to that field and does not leave photo mode. Held-down
repeats and combinations with Ctrl, Cmd or Alt are ignored. While a capture is running, all
four are ignored until it finishes. Photo mode will not start
while a dialog is open. Tabletop Simulator's F11/F12 are not used, because browsers reserve
them.
Common mistakes#
- Expecting a shortcut to fire while typing in a field. Every shortcut above except Ctrl+S is fully suppressed while an input, textarea, select or Monaco has focus — click into the viewport or a Hierarchy row first.
- Pressing F and expecting the camera to move.
Fre-selects and re-attaches the gizmo; it does not frame the camera yet. - Pressing Ctrl+W to close a tab. It closes the browser tab instead — use Alt+W.
