Widget UI protocol#
Use this page when editing widget frontend controls, reviewing a widget PR, or asking an agent to make UI changes. The goal is for every viewer to feel like one scientific tool family, even when the underlying data are very different.
For developer-facing ui_mode, show_*, and control-visibility tables, use
the UI Guide. This maintainer page is the internal protocol
for frontend wording, toolbar layout, export labels, and review checks.
Command text#
Use Title Case for command buttons and toolbar actions:
CopyExportResetAddClearUndoSave BandCenter View
Keep scientific acronyms, detector labels, and file-format names uppercase when the uppercase form is the term users recognize:
FFTROIBF,ABF,ADFHTML,PNG,GIF,MP4,CSV,JSON
Do not use all-caps for ordinary commands such as COPY, EXPORT, CLEAR,
or UNDO.
Compact control labels#
Dense widget toolbars and control rows should not use decorative colons. Use:
ScaleColorAutoSmoothLinkZoomPanContrastROI
Use colons in explanatory prose, tooltips, documentation, and status text when they make the sentence clearer. Avoid them inside compact controls because they waste horizontal space and create inconsistent rhythm.
Control Pairs#
Treat a compact label and the control it names as one UI unit. This applies to labels paired with switches, dropdowns, sliders, icon buttons, and compact text buttons:
Auto+ switchSmooth+ switchColor+ menuScale+ menufps+ slider/valueavg+ menu
On mobile and narrow layouts, the row may wrap, but the pair must stay together. Do not allow a label to remain on one line while its switch or menu wraps to the next line. Use an inline-flex pair wrapper or an equivalent stable layout primitive with small fixed gaps.
Every compact label that names a live control (Scale, Color, Colorbar,
Profile, FFT, Lens, Auto, Smooth, and the Link toggles) must render
inside a pair wrapper, not as a bare sibling of its control. A bare label is the
one that drifts away from its switch or menu when the toolbar wraps. Give these
labels full-strength text (themeColors.text); reserve the muted text color for
status text only (export status, page status, zoom readout), never for a label
that names a control the user can toggle.
Scoped sub-groups. When several toggles share one governing word (for
example Link scoping Zoom, Pan, Contrast, and Denoise), wrap the whole
set in a single bordered sub-group led by that word. Repeating or bordering the
scope keeps it legible when the group wraps; a lone Pan switch that wraps away
from a distant Link label reads as an unscoped control.
Mode-gated knobs get their own row. Occasional sliders that appear only when a mode is on (lens magnification and window size, the denoise method/σ/bin knobs, the underlay blend/stretch knobs) belong on their own conditional row, not appended to an always-visible row. This keeps the everyday rows short and stops a toggled-on tool from forcing the base controls to wrap.
Browser signoff for dense controls must include at least one narrow viewport. For Show2D and Show3D, check the main image controls, FFT controls, playback controls, linked zoom/pan/contrast controls, and any page/column controls that can wrap.
Toolbar order#
When a widget has these actions, prefer this order:
Widget-specific controls and mode switches
CopyExportExport status text
Reset
Keep existing widget-specific exceptions only when the scientific workflow depends on them. If changing the order, compare the result against Show2D, Show3D, Show4DSTEM, and ShowEDS before committing.
Dynamic labels#
Scientific labels can be long and data-dependent: page labels, run names, file names, lambda/RMSE summaries, detector names, export statuses, and frame labels. Do not let that text resize the whole toolbar or shift nearby controls while the user scrubs pages or frames.
For dynamic labels inside dense toolbars:
Give the label a bounded width with
overflow: hidden,text-overflow: ellipsis, andwhite-space: nowrap.Keep the full value in
titleand the relevantaria-label.Use fixed or reserved widths for neighboring sliders and compact controls.
Use tabular numbers for counters such as
2/11,10/11, and4 fps.Put detailed metadata in a tooltip, panel label, report table, or secondary line instead of making the primary toolbar grow with every dataset.
Export labels#
Export menu labels should tell users what will be saved:
Format or mode:
HTML,GIF,MP4,PNGEncoding:
Exact float32,Exact uint16,Quantized uint8Reduction:
Downsample 2x,Binned 4x, or the widget-specific reducerEstimated size or render work when available
Examples:
HTML exact float32 (82 MB)HTML quantized uint8 (21 MB)Binned 4x uint16 (180 MB)GIF medium (1.6 MB work)
Do not hide scientific reductions behind vague words like “small” unless the menu also says what changed.
For animation exports, the GUI may not know the compressed GIF/MP4 size before encoding. In that case, show estimated uncompressed RGB render work and keep the label explicit. Do not imply this estimate is the final file size.
Keep advanced animation controls out of the primary toolbar unless they become
common user actions. The GUI should expose the simple path, usually
GIF low/medium/high and MP4 low/medium/high; Python and maintainer smoke
reports should cover advanced options such as frame labels, background color,
bounce playback, panel gap, and dry-run planning.
Visual testing#
After changing controls, rebuild and drive the widget in a browser. At minimum:
Open the live Jupyter widget or standalone exported HTML.
Toggle the controls touched by the change.
Verify labels wrap cleanly in a narrow viewport.
Check light and dark docs themes when the page is theme-sensitive.
Confirm there are no console errors.
For interaction-sensitive changes, follow Agent signoff and the relevant Storyboard file.