Design Lounge
Install

Nº 097 of 520

Bauhaus design language kit

A full Bauhaus UI dialect on one sheet: red, yellow, blue and ink on paper, circle/square/triangle grammar, Josefin Sans lowercase headlines, hard-shadow controls.

Preview

Open full size
1280 × 800 · 20.4 KB · 250 lines

Use it

Free to use · credit appreciated

1 Once, in your project

npx skills add SusanAcharya/Design-Lounge

2 Then ask

Using the Design Lounge skill, build "Bauhaus design language kit" (piece bauhaus-style) in my stack. Match its brief; restyle it onto my product's theme.

No skill? Paste the brief instead. It carries the numbers, tokens and behaviour.

Brief

211 lines

Build brief for a coding agent. Rebuild this piece in the reader’s stack. If they haven’t said which stack, ask once, then default to semantic HTML + CSS + a little vanilla JS. Match the numbers below; don’t “improve” them.

What it is

A kit sheet for “formhaus”, a fictional Bauhaus-revival furniture brand, that doubles as a style guide you can apply to a whole product. The page is a 12-column grid of paper cells separated by 3px ink rules (the grid’s gap shows the black body behind it). The first row is a live landing hero for “Regal 25” modular shelving, with a red circle, blue square, yellow triangle, ink bar and ink dot composed on the right, next to a type specimen with a 150px “Aa”. The second row holds the palette with roles, buttons in four states, tags, inputs and a product card; the third row states the shape grammar (circle acts, square holds, triangle points, rule divides). The detail worth copying: shape carries meaning. Circles are only ever actions or status, squares are containers, triangles point; nothing is rounded unless it is a circle.

Reference behaviour

  1. Initial state: header bar (56px) with a three-shape mark, “formhaus / design language 01”, four section anchors and “Kit v1.4 · Weimar · Oct 2026”. Below it the sheet; the first 800px show the hero, specimen and the whole component row.
  2. Hover any rectangular button: it lifts translate(-3px, -3px) and gains a hard 3px 3px 0 ink shadow over 120ms. Press: it drops back to 0/0 with no shadow. The “States” strip shows Rest / Hover / Pressed / Disabled statically using forced classes, so the states are readable without interacting.
  3. Click the yellow round button in the hero’s bottom-right corner (“Recompose”): the five shapes move to arrangement 2 over 520ms with expo-out easing (circle shrinks to .62 and drops left, square rotates 90° and grows to 1.3, triangle flips 180°, bar goes horizontal, dot grows). Click again: arrangement 3. Again: back to 1. The copy column never moves.
  4. Focus a text input or the select: a 5px yellow offset block appears behind it, outlined by a 2px ink edge (a “printed” focus shadow). No radius, no glow.
  5. The email field ships in its error state: red 2px border, pale red fill #F6DDD6, 12px red message under it, aria-invalid="true".
  6. Click the checkbox: a 10px red square scales from 0 → 1 in 120ms. Click a radio: a 10px blue disc does the same.
  7. Click the switch: the track fills yellow and the knob slides 24px right and morphs from an ink square to a red circle (240ms expo-out). Off again: back to an ink square.
  8. Hover the product card: it lifts 4px with a 4px hard ink shadow.
  9. Header anchors jump to sections; their hover state is a 2px red underline.

Structure

1280 × 800 first frame (sheet continues to ≈ 1000px; body scrolls)
┌──────────────────────────────────────────────────────────────────────────────┐
│ ●■▲ formhaus / design language 01      TYPE COLOUR CONTROLS GRAMMAR  Kit v1.4│ 56 + 3px rule
├───────────────────────────────────────────────┬──────────────────────────────┤
│ formhaus möbel      Kollektion Werkstatt Journal [Cart 2] │ ● 01 TYPE SPECIMEN│
│ REGAL 25 · MODULAR SHELVING          ●    ( red circle 290 )  │ Aa (150px)  Josefin…│
│ build it                      ━━━━━━━━              │ ─────────────────────│
│ in squares.  (76px)       ■ (150)   ▲ (180×156)     │ Display 76 form follows│
│ body 15px                                        │ H2 26 / H3 18 / Body 15 │
│ [Configure Regal 25 →] [1925 drawings]     (↻) │ Label 11              │
│ From €640 · ships in 3 weeks             cols 1–7 · 424h │ cols 8–12 · 424h   │
├───────────┬───────────┬───────────┬──────────────────────────────────────────┤
│02 PALETTE │03 BUTTONS │04 INPUTS  │05 CARD                                   │
│ 5 swatches│ 3 buttons │ postcode  │ [blue art 118h, yellow circle, NEW tag]  │
│ 46px rows │ 4 states  │ email err │ Stuhl B3 · €1,180 [Add]                  │
│ ratio bar │ 5 tags    │ ☐ ◉ ○ sw  │                                          │
│ cols 1–3  │ cols 4–6  │ cols 7–9  │ cols 10–12                     ≈ 254h    │
├───────────┴───────────┴───────────┴──────────────────────────────────────────┤
│ ● Circle acts │ ■ Square holds │ ▲ Triangle points │ ━ Rule divides  (span 3 each)
│ footer strip: kit summary · "Click the round button to recompose"            │
└──────────────────────────────────────────────────────────────────────────────┘
  • <header class="top">: .mark (three 16px shapes, 4px gap), .brand, <nav aria-label="Kit sections"> with four anchors, .ver.
  • <main class="sheet">: display: grid; grid-template-columns: repeat(12, 1fr); gap: 3px; background: var(--ink). Every child is a .cell with paper background and 20px padding; the gap is the rule.
  • .hero (<section>, cols 1–7, 424px, overflow: hidden, data-comp="1|2|3"): five absolutely positioned .shape divs, a .mini nav, a .copy block (eyebrow, <h1>, <p>, two buttons, meta line) and the round .recomp button.
  • .spec (cols 8–12, 424px): <h2 class="lbl">, .aa row (glyph + two family notes), <ul class="scale"> of five rows (<em> meta + sample).
  • .pal, .ctl, .inp, .crd: span 3 columns each. .gram × 4 span 3 each. .foot spans 12.
  • Section labels are <h2 class="lbl"> with a 9px shape before them; the shape class (c, s, t) picks circle/red, square/blue or triangle/yellow.

Tokens

:root {
  /* colour: paper + ink + three primaries */
  --paper: #f0ebe0;      /* surface, 60 % of any screen */
  --paper-2: #e4dccb;    /* inner list rules, disabled fill */
  --ink: #151412;        /* text, all borders, hard shadows, 20 % */
  --ink-2: #4a463f;      /* secondary text */
  --ink-3: #6e685d;      /* meta labels, disabled text */
  --red: #d52b1e;        /* primary action, circles, errors (8 %) */
  --yellow: #f3b61f;     /* highlight, focus fill, "new" (7 %) */
  --blue: #1d4f9c;       /* info, links, focus ring, secondary action (5 %) */
  --on-color: #f0ebe0;   /* text on red / blue */
  --error-fill: #f6ddd6;

  /* type */
  --display: "Josefin Sans", Futura, "Century Gothic", sans-serif;
  --text: "Work Sans", system-ui, sans-serif;
  --fs-display: 76px; --fs-aa: 150px; --fs-h2: 26px; --fs-h3: 18px; --fs-body: 15px; --fs-ui: 14px; --fs-label: 11px; --fs-meta: 10px;

  /* geometry */
  --rule: 3px;           /* between regions */
  --line: 2px;           /* around controls */
  --pad: 20px;           /* cell padding */
  --ctl: 44px;           /* control height */
  --radius: 0;           /* the only exception is a full circle (50 %) */
  --lift: 3px;           /* button hover lift; cards use 4px */
  --shadow-hard: 3px 3px 0 var(--ink);
  --focus-block: 5px 5px 0 var(--yellow), 5px 5px 0 2px var(--ink);
  --space: 4px 8px 12px 16px 20px 24px 32px;

  /* motion */
  --t-micro: 120ms;
  --t-switch: 240ms;
  --t-shape: 520ms;
  --ease: cubic-bezier(.2, .7, .2, 1);
  --expo: cubic-bezier(.16, 1, .3, 1);
}

Typography

RoleFamilySizeWeightLine-heightTrackingCase
Hero headlineJosefin Sans76px700.88−0.025emlowercase (universal-lowercase nod)
Specimen glyphJosefin Sans150px700.8−0.04em“Aa”
H2Josefin Sans26px7001.1−0.01emsentence
H3 / card titleJosefin Sans18–22px600–7001.1–1.30sentence
BrandJosefin Sans19px700 + 4001−0.01emlowercase
BodyWork Sans15px4001.50sentence, --ink-2
ButtonWork Sans14px6001+0.01emsentence
Section label / eyebrowWork Sans11px6001+0.16emUPPERCASE
Meta / state captionsWork Sans10px5001+0.08–0.1emUPPERCASE
TagWork Sans10px6001+0.14emUPPERCASE

Josefin Sans sits low in its em box; add padding-top: 2–4px to any Josefin text that is vertically centred against a box (brand, card title, price) so it looks optically centred.

Motion

ElementTriggerPropertyFrom → ToDurationEasing
.btnhovertransform, box-shadow0,0 / none → −3px,−3px / 3px 3px 0 ink120ms--ease
.btnactivetransform, box-shadowlifted → 0,0 / none120ms--ease
.cardhovertransform, box-shadow→ −4px,−4px / 4px 4px 0 ink120ms--ease
.shape × 5Recompose clicktransformarrangement n → n+1 (values below)520ms--expo
checkbox/radio markchangetransform: scale0 → 1120ms--expo
switch knobtoggletranslateX, border-radius, bg0 / 0 / ink → 24px / 50 % / red240ms--expo
switch tracktogglebackgroundpaper → yellow120mslinear
input focusfocusbox-shadownone → --focus-block120ms--ease

Arrangement 2: circle translate(-230px,120px) scale(.62), square translate(170px,-200px) rotate(90deg) scale(1.3), triangle translate(-40px,-210px) rotate(180deg), bar rotate(0) translate(40px,150px), dot translate(200px,240px) scale(1.6). Arrangement 3: circle translate(20px,-90px) scale(1.25), square translate(-30px,-30px) rotate(45deg), triangle translate(-200px,0) rotate(-90deg) scale(.8), bar rotate(-90deg) translate(-40px,-40px), dot translate(-40px,190px). Arrangement 1 is the untransformed layout.

Reduced motion: every transition 1ms. Recompose still swaps arrangements, instantly.

States

  • Button rest: 44px tall, 2px ink border, 0 radius. Primary red / on-color text; secondary blue / on-color; neutral paper / ink; round = 44px yellow circle with an ink arrow.
  • Hover: lifted 3px up-left with a 3px hard ink shadow. Pressed: flat, no shadow. Disabled: --paper-2 fill, --ink-3 text and border, no lift, cursor: not-allowed.
  • Focus-visible (everything): outline: 3px solid var(--blue); outline-offset: 3px. Inputs replace this with --focus-block.
  • Input error: border --red, fill --error-fill, message 12px/500 red below, aria-invalid + aria-describedby.
  • Checkbox checked: red 10px square inside the 20px box. Radio checked: blue 10px disc inside a 20px circle.
  • Switch on: yellow track, red circular knob at the right. Off: paper track, ink square knob at the left.
  • Tags: 26px, 2px ink border, 8px leading shape. Yellow “New” (square), red “Sale” (circle), blue “Info” (square), ink “Last 3” (triangle, paper text), plain “Birch”.
  • Nav link hover: 2px red bottom border.

Accessibility

  • Header <nav aria-label="Kit sections">; each kit cell is a <section> labelled by its <h2>; the hero is labelled “Composition: product landing hero”.
  • All decorative shapes (.shape, card art, grammar glyphs, the mark) are aria-hidden="true".
  • The static state specimens are aria-hidden with tabindex="-1" so they don’t add four extra tab stops.
  • Recompose is an icon button with aria-label that reports the arrangement (“arrangement 2 of 3”).
  • The switch is <button role="switch" aria-checked>; checkboxes and radios are native inputs visually hidden, with focus drawn on the replacement <i>.
  • Contrast: ink on paper 16.4:1; ink-2 on paper 8.1:1; paper on red 5.7:1; paper on blue 6.6:1; ink on yellow 10.9:1. Red text on paper (eyebrow, error message) is 4.9:1 and only used at ≥ 11px/600.
  • Hit targets: controls 44px; the switch is 52 × 28 but its whole label is clickable.

Responsive rules

  • ≥ 1280: as drawn; the sheet continues to ≈ 1000px and the body scrolls.
  • 1024–1279: same grid; the hero shapes are pinned to the right edge so they crop instead of colliding with the copy.
  • 700–1100: hero and specimen each span 12 columns; component cells and grammar cells span 6; header anchors hide.
  • < 700: every cell spans 12; hero becomes 520px tall with a 56px headline and the circle pushed below the copy; specimen height becomes auto.
  • Applying the language to a product: keep 3px region rules on any layout, 2px on controls, never introduce a radius between 0 and 50 %.

Acceptance checklist

  • Only five colours appear (paper, ink, red, yellow, blue) plus --paper-2, --ink-2/3 and the error fill.
  • Regions are separated by a 3px ink grid gap, not by borders on each cell.
  • No border-radius anywhere except true circles (round button, radio, switch knob when on, red circle shapes).
  • Hero headline is Josefin Sans 700, 76px, line-height .88, lowercase.
  • Buttons are 44px tall with a 2px ink border and lift 3px with a hard 3px shadow on hover, flatten on press.
  • The States strip shows rest, hover, pressed and disabled at once without interaction.
  • Recompose cycles three shape arrangements over 520ms expo-out; the copy never moves.
  • Input focus draws a 5px yellow offset block with a 2px ink edge; error state uses red border, pale fill and a described message.
  • The switch knob is a square when off and a circle when on, and aria-checked flips.
  • Section labels carry a 9px circle, square or triangle that matches their colour role.
  • Focus is visible on every link, button and input (3px blue, 3px offset).
  • With reduced motion, all state changes still happen instantly.
  • No font other than Josefin Sans and Work Sans is loaded.

Implementation notes

Rules from the grid gap. Paint the grid container ink and let each paper cell sit on it; every region boundary is then exactly 3px and never doubles up:

.sheet { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--rule); background: var(--ink); }
.cell  { background: var(--paper); padding: var(--pad); min-width: 0; }
.hero  { grid-column: 1 / 8; height: 424px; overflow: hidden; padding: 0; }

Square-to-circle switch. The knob morphs geometry as it travels, which is the language’s whole argument in one control:

.sw-t button { width: 52px; height: 28px; border: 2px solid var(--ink); background: var(--paper); position: relative; }
.sw-t button::after { content: ""; position: absolute; left: 3px; top: 3px; width: 18px; height: 18px; background: var(--ink);
  transition: transform var(--t-switch) var(--expo), border-radius var(--t-switch) var(--expo), background var(--t-switch); }
.sw-t button[aria-checked="true"] { background: var(--yellow); }
.sw-t button[aria-checked="true"]::after { transform: translateX(24px); border-radius: 50%; background: var(--red); }

Recompose is data-attribute driven; the shapes have one transition and three transform sets:

let c = 1;
recomp.addEventListener('click', () => {
  c = c % 3 + 1; hero.dataset.comp = c;
  recomp.setAttribute('aria-label', `Recompose shapes, arrangement ${c} of 3`);
});

Triangles are clip-path: polygon(50% 0, 100% 100%, 0 100%) on a div, not SVG, so they share the same transition as the other shapes. Common mistakes: adding an 8px radius “for friendliness” (it destroys the grammar); using soft blurred shadows (only hard, zero-blur offsets exist here); putting red on body text; centring Josefin Sans by line-height alone (it rides high; add 2–4px top padding).

Details

Palette
Type
Josefin Sans · Work Sans
Motion
Subtle motion
Build
One session
Designed bySusan AcharyaKathmandu

Studied

Abel

A control. It studies this site for quiet, not for a show.

All sources