Rekta Design · a design language · 0.2 · desktop and web
Straight lines, live tiles, sideways motion.
no cards · two independent themes · four status fills · every value a token · no framework
Rekta Design is a platform-neutral design language; the name comes from Latin recta, the straight line. This site is built in it, and every part of it is a live example: you are inside a panorama, the pivot above names its sections in a fixed order, and the app bar below holds the global controls.
Move sideways with the mouse wheel, a trackpad swipe, or ← → once the panorama has focus. On a phone, just scroll down. Ctrl K goes anywhere; ? lists every key.
Inspired by Metro.
Rekta Design is inspired by Microsoft's Metro design language, to us one of the best UX designs ever shipped, from Zune and Windows Phone 7 (2010) to Windows 8 (2012). We find it a pity that no major product uses it today, so Rekta takes up its ideas in its own form: its own tokens, typography and components.
- 2000s
- 2010
- 2012
- todayRekta Design
- content over chromeThe information is the interface. Nothing gets a box just to look tidy.
- authentically digitalNo imitation leather or paper: type, colour and motion that belong to a screen.
- type as structureRooted in the Swiss International Typographic Style and the wayfinding signage of public transport: large, plain, readable at a glance.
Its token values are derived from the source code of the Porsche Design System (Apache-2.0): numbers and colours only, no code, fonts or marks.
sources: Metro (design language) · International Typographic Style · Porsche Design System. Rekta Design is independent and not affiliated with or endorsed by Microsoft or Porsche.
Nothing is decoration.
- content over chromeNo cards, no boxed panels. Information sits on the ground, grouped by hairlines and whitespace.
- motion as guidanceEvery transition answers a question: where am I, which facet, what just happened.
- information-dense live tilesA tile's size follows importance; its fill is its status. It opens something or only informs.
- panorama and pivotOne place, wider than the screen, moved through sideways; its facets in a fixed order.
- refined precisionHairlines, tabular figures, calm large areas, vivid small accents.
Status is a fill, not an accent.
Neutral ground, no brand hue. Four status colours carry meaning and only meaning: large fills use the dampened tile form, small marks the saturated full form. Primary text sits on every fill and must clear AA; the ratios below are measured live, in the theme you are looking at.
activewaitingfaileddoneidle
In running text a status takes a soft tint: the import failed, the review is waiting.
neutral surfaces · light · dark
bgsurfacesurface-2text-primarytext-contrast-hightext-contrast-mediumtext-contrast-lowaccentfocusdisabled
contrast on neutral ground
| pair | needs | now |
|---|---|---|
text-primary on bg | 4.5 : 1 | – |
text-primary on surface | 4.5 : 1 | – |
text-contrast-high on bg | 4.5 : 1 | – |
text-contrast-high on surface | 4.5 : 1 | – |
text-contrast-medium on bg | 3 : 1 | – |
focus on bg | 3 : 1 | – |
on-accent on accent | 4.5 : 1 | – |
One slot is a product's own: the accent, ink until a product sets it. It fills the primary button, checked controls and a selected row; never a tile or a status. Try another in look, or make your own in forms.
Three levels, one bold title.
board · updated 2 min ago
Migrate the nightly import
3 of 5 steps · failed at the schema check · 4 comments
Level 1, a quiet kicker. Level 2, the one semibold title per screen. Level 3, a fact line. Navigation titles, like the pivot above, are large and light: they name a place, not a thing. UI words are lowercase; content keeps its own case. Sizes are in rem, so they follow your text size; large ones grow with the place, not the screen.
scale
- Rekta
xxs - Rekta
xs - Rekta
s - Rekta
m - Rekta
l - Rekta
xl - Rekta
xxl - Rekta
nav-active - Rekta
nav-inactive - Rekta
pivot-active - Rekta
pivot-inactive - Rekta
group - Rekta
title
Body text is Barlow at 15px, self-hosted under the SIL Open Font License; numbers that read as data use weight 500 and tabular figures.
Tiles, not cards.
A tile's whole area is one fill, and the fill is its status. Size follows importance; content follows a few patterns: a stat, a sparkline, progress, the status word. A tile opens something, or it only informs: it never changes data. Press one and it nudges back where you press it. These tiles measure this page, live.
The waiting tile is a button: it opens a sheet. The release notes tile is a link: it turns this place. Finished tiles drop their sparkline: stillness means done. Every chart has a text equivalent.
One place, wider than the screen.
A panorama is one place laid out sideways. One wheel gesture moves one thing: started over a section that can still scroll, it scrolls the section; otherwise it moves the panorama sideways. Horizontal input is left alone; at either end the wheel falls through.
Where the place is narrower than 760px or the window shorter than 480px, everything stacks and the page scrolls. Right now:
- window-size class–
- density–
- theme–
- motion–
A pivot is one place's facets in a fixed order. The active title is large; the strip never reorders. It glides by the title's place in the order, less than the content moves, so the titles before it stay in reach. Facets add nothing to history.
4 open · 2 waiting · 1 failed
- Nightly importfailed
- Release noteswaiting
- Import retried
- Review requested
- Deploy finished
- schema.sql
- import.log
- Retry on failure
- Notify on done
The strip above this site is the same component: move the panorama and watch it follow, a step behind. Use ← → once a facet has focus.
Every transition means one thing.
| transition | timing | means |
|---|---|---|
| place change | 400ms, turnstile 40deg | you are somewhere else |
| press | 100ms in, tilt 8deg | this heard you |
| facet change | 0.75 × 400ms, 24px slide | same place, other facet |
| tiles build in | 400ms, 30ms apart | assembling from live data |
| reorder | 400ms | this moved because of you |
| resize, re-flow | 400ms | this grew; the rest made room |
| arrive, leave | 250ms, leaving faster | this one is new; that one is gone |
| live tile news | 400ms: peek, or flip | a new number; a new status |
| data morph | 600ms | the same thing, measured again |
| sheet, toast | 250ms | a short question; something happened |
| floating list | 150ms | options for this control |
| loading | after 300ms, a line every 1200ms | working on it |
| live drawing | 600ms | updating right now |
reorder
- write the release notes
- check contrast in dark
- tag 0.2
try
Reduced motion zeroes every duration: transitions become instant, never skipped, and live values keep updating. Wall-clock timings, like a toast's undo window, stay.
Rows on hairlines, chosen the Metro way.
A click selects a row and shows it. Ctrl+click adds another and starts the selection mode: then every click adds or removes, and the app bar carries the selection. Shift+click takes a range, Esc ends it. A selected row nudges, takes the accent and a checkmark. Drag a column's edge to size it; double-click a group to edit it; right-click a row for its menu.
–
| status |
|---|
No component matches the search and filters.
Nothing selected.
the same on rows
- Nightly importfailed
- Release noteswaiting
- Contrast checkdone
- Font subsetactive
Nothing selected. A selected failed job still says failed.
Every value of the system in a table, the current one beside it: the tokens. Narrower than 760px, rows stack as “label value”: no sideways scrolling on a phone.
A desktop app, by mouse and by keys.
Rest the pointer on a control: a tooltip. Right-click, long-press or Shift F10 on a file: a context menu. A tree that opens and closes, a list you order by its grip, and ten thousand lines that scroll like ten.
- tokens
- rekta.tokens.json
- src
- css
- rekta.css
- js
- rekta.js
- icons
- back.svg
- search.svg
- css
- docs
- behaviour.md
- collections.md
- colour.md
- forms.md
- navigation.md
- platforms.md
- scripts
- build.mjs
- build-site.mjs
- site
- index.html
- site.css
- site.js
- test
- smoke.mjs
files
Choose a file.
Click a file, or move with the arrow keys: → opens a folder, ← closes it.
order the release, by its grip
- write the release notes
- check contrast in dark
- run the smoke test
- tag the release
- publish the tokens
ten thousand lines
–
Click a line, or focus the list and move with ↑ ↓ PageUp PageDown. Only the lines in view exist.
An event leaves, a state stays.
Something that just happened is a toast: ink, one at a time, with an undo window you can hold by pointing at it. A lasting state of the whole system takes the banner on top: one at a time, the most severe first, its end reported as a toast.
- banner now
- live data
a region loading, empty, failed
Nothing open. Well done.
Could not load: the server is offline.
Nothing shimmers: placeholders stand still, and the line comes only after 300ms, so a fast answer never flickers.
Live, and honest about it.
Live values say how fresh they are, and say so when they stop. Rest the pointer on them and they hold still while you read; updates wait behind a button. Turn the feed off and watch it go stale.
undo history
- Nothing yet. Archive a component, edit a group, or order the release.
Everything you archive, edit or move on this page lands here. Ctrl Z takes the last step back, Ctrl Shift Z does it again; the toast offers the same.
Checked late, corrected early.
Make a product accent. A field is checked when you leave it and corrected as you type; sent with errors, a summary comes first. Name it “plum” and the server says no at the field; send it during maintenance and it says no to the form. Change something and leave: it asks first.
Native where it can be, Rekta where it shows.
Every input here changes something you can see. A select, a number, a date and a time are the platform's own controls in Rekta's frame, so their pickers, keys and screen readers come for free; the rest are Rekta's own.
Toggle switches act at once, so they live outside forms that are sent; a checkbox waits for “save”. Segments are for two to five options you see at a glance; more go in a select.
Data, quiet until it matters.
Charts in ink and grey: one axis, round ticks on hairlines, the accent only where you point. Every chart reads out its values under the pointer or with ← → once it has focus, and shows its numbers as a table. A status colour appears only where a value means that status.
a day
build minutes
meters
progress
Yours to set.
Checked, not assumed.
- keyboard firstEvery pointer action has a key; focus moves to what opens and comes back to what opened it.
- focus on fillsOn a tile the ring is drawn inset in the tile's text colour, so it survives every fill. Tab into the tiles below.
- colour is never aloneEvery status has its word, every chart a text equivalent, the app bar's square its word beside it.
- contrast is measuredThe build fails when a pair drops below its minimum, or when two statuses come too close under colour blindness.
- touch44px targets, no hover-only actions, 16px fields, and dragging never activates.
- forced coloursFills drop; tiles keep an edge, marks and meters keep their shape.
Fifty-one icons on one grid.
20 × 20, a 1.6 stroke, square ends, in the text colour, so they follow every theme. An icon goes beside a word; alone, it has a name and a tooltip. The web takes rekta.icons.svg (a sprite: <use href="#rk-i-search">); other platforms take rekta.icons.json, the same shapes as data.
archivebackbellcalendarcheckchevron-downchevron-leftchevron-rightchevron-upclockclosecopydowndownloadediterrorexternaleyefilefilterfolderforwardgriphomeinfoinstalllinklockmenuminusmoremotionofflinepausepinplayplusredorefreshsearchsortstopthemetrashtuneundoupuploaduserwarningwindow
Rest the pointer on one of the toolbar buttons in “desktop”: an icon alone gets its name as a tooltip, and its accessible name stays.
An app, not a tab.
Install this site and it opens in a window of its own, with Rekta's title bar where the browser's was. It works offline, and a new version waits until you say “reload”. A native shell (Electron, Tauri, a WebView) gets the same title bar by setting data-rk-titlebar.
tokens
Every value, a token.
the same names on every platform
- works offline–
- installed–
- connection–
Offline, the banner says so and the page keeps working from what it saved. A new version is announced by a toast with “reload”; it never replaces the page while you are in it.
Same numbers, different plumbing.
The tokens are platform-neutral; a native app reads rekta.tokens.json: the same values resolved, in logical px, ms, hex and four numbers per curve. Names are the same everywhere: space-m is --rk-space-m on the web and SpaceM in your toolkit.
| concept | web | native desktop |
|---|---|---|
| units | rem for sizes that follow the text size; fluid type as clamp() against the place | logical pixels scaled with the OS text size; the same min, max and share of the pane's width |
| window-size class | container queries on the place, and the viewport height | the pane's width and the window's height, same thresholds |
| density | the pointer: fine without touch is compact | the input devices present; the same two densities |
| wheel | one gesture, one scroller | the native wheel event, same rule; trackpad pans left alone |
| back | history: links, Esc, the browser | the shell's back command, the mouse back button, Alt+← |
| reduced motion | prefers-reduced-motion or data-motion | the OS setting or the same in-app switch |
| theme | prefers-color-scheme or data-theme | the OS appearance or an in-app switch; two independent token sets |
Tokens first, then CSS and script.
- take the tokensrekta.tokens.json for any platform; rekta.tokens.css on the web.
- add the componentsrekta.css, with rekta.fonts.css and the Barlow files.
- add the behaviourrekta.js as a module, or rekta.global.js as a classic script. No framework needed, and any framework can use it.
<link rel="stylesheet" href="rekta.tokens.css">
<link rel="stylesheet" href="rekta.fonts.css">
<link rel="stylesheet" href="rekta.css">
<script type="module">
import * as Rekta from './rekta.js';
Rekta.start();
Rekta.places({ home: 'home' });
Rekta.panorama(document.querySelector('.rk-panorama'),
{ pivot: document.querySelector('.rk-pivot') });
</script>
Code, tokens, CSS and script: MIT. Docs and images: CC BY 4.0. Barlow: SIL Open Font License 1.1. Not affiliated with or endorsed by Microsoft or Porsche.