Design guidelines
Umbra widgets should look like they belong together on one desktop. These rules are what reviewers check.
- True black background (
#000), no transparency. Umbra is built for OLED, where black pixels are off, and the window has DWM-drawn rounded corners and a hairline border. - Use the tokens for every color, radius and font (
var(--text),var(--accent),var(--radius-m)), so themes work. See Styling and tokens. - Segoe UI Variable comes from
umbra.css; don’t ship your own fonts unless the widget is about typography. - Text 11 px or larger. Use
font-variant-numeric: tabular-nums(the.numclass) for numbers that change, so they don’t jitter. - Fit the declared
width×heightexactly. The window doesn’t scroll or reflow; when the user resizes it, Umbra zooms the whole page. Let the page fill its window (height: 100%, flex, grid) so extra room gets used.
Motion
Section titled “Motion”- Calm by default. No constant animation. A short entrance and meaningful transitions are fine.
- Respect
html[data-motion="off"](umbra.cssalready disables CSS animations there) and multiply durations byvar(--motion-scale, 1). - Use
umbra.tweenfor number animations, since it jumps to the end value when motion is off or the window is hidden.
Data and behavior
Section titled “Data and behavior”- No network calls faster than
umbra.everyschedules them. If you run your own timers, stop them whileumbra.settings.pausedis true and useumbra.settings.refreshSecondsas the interval. - Show freshness. Dim stale numbers and put an
<umbra-status>in the footer. See Freshness and offline. - Format for the user’s region with
umbra.locale,umbra.hour12andumbra.fmt, not a hard-coded"en-US". - Save what the widget creates in
umbra.store, never inlocalStorage. - Handle edit mode and locking. Don’t rely on mouse interaction while
umbra.settings.editModeis true; mark buttonsdata-no-dragso clicks stay clicks. - Recompute anything derived from “today” in
umbra.onTimeChanged.
Accessibility
Section titled “Accessibility”- Give controls real labels, and keep contrast readable on your surfaces.
- Don’t rely on color alone for rising or falling values: add the
trend-up/trend-downclasses so Windows contrast themes get ▲ and ▼. - Draw borders with
border/outline, notbox-shadow, so they survive forced-colors mode.
Honest permissions
Section titled “Honest permissions”- Declare only the hosts the widget calls, and only the permissions its purpose needs.
- Prefer designs that work offline.
- If you need a local command, read Running local commands first; it makes review stricter.
Before you open a pull request
Section titled “Before you open a pull request”-
widget.jsonhas a clear one-sentencedescription, aversion, and$schema. - A 2×
preview.pngon a black background (umbractl capture <id> preview.png). - No hard-coded colors; checked at 50 %, 100 % and 200 % size.
- Checked with animations off and with the offline simulation.
-
node scripts/catalog.mjspasses andwidgets/index.jsonis regenerated.
