Design system

Tokens, typography, voice.

A live reference for Struqo's visual system. Every value is read from apps/web/app/globals.css at render time, so this page cannot drift from the code.

Code is the source of truth. The Figma library and this page mirror globals.css, never the other way around.

Surfaces
bg-body
bg-body
bg-elevated
bg-elevated
bg-surface
bg-surface
bg-hover
bg-hover
bg-active
bg-active
bg-selected
bg-selected
Text
text-text
text-text
text-text-2
text-text-2
text-text-3
text-text-3
text-text-disabled
text-text-disabled
text-text-on-selected
text-text-on-selected
text-interactive
text-interactive
text-interactive-hover
text-interactive-hover
Borders
border-border-default
border-border-default
border-border-strong
border-border-strong
Status (UI feedback)
--color-success
text-success
--color-success-subtle
bg-success-subtle
--color-warning
text-warning
--color-warning-subtle
bg-warning-subtle
--color-error
text-error
--color-error-subtle
bg-error-subtle
--color-info
text-info
--color-info-subtle
bg-info-subtle
--color-focus-ring
Canvas object states
--color-state-selected
--color-state-hover
--color-state-locked
--color-state-hidden
--color-state-error
--color-state-warning
--color-state-success
--color-state-info
Wood species
--color-wood-fichte
--color-wood-laerche
--color-wood-douglasie
--color-wood-eiche
--color-wood-stroke
Notices and status

Four conventions, graded by urgency. Warning (red) for blocking errors or data inconsistency. Alert (orange) for non-blocking attention. Hint (blue) for neutral information. Success (green) for confirmations. Color carries the message; the container stays restrained.

Warning

Drawing diverges from cross-section. Width 120 → 100 mm.
Blocking error, data inconsistency, legal disclaimer
<Notice tone="warning">

Alert

Email not confirmed yet. Save reminders are paused.
Attention needed, non-blocking
<Notice tone="alert">

Hint

Dimensions are stored in mm. Display follows your selected unit.
Neutral information, tip, tooltip
<Notice tone="info">

Success

Project saved.
Confirmation after an action
<Notice tone="success">
Loading indicator

The plain statement leads through position, not through brightness. All text stays in the same quiet tone; only the activity signals are loud. Below it an indeterminate bar runs at working pace (1.6s, linear): a determinacy sign that claims no percentage nobody has. The indicator appears from the first millisecond and fades out over 180ms at the end, so it never invents waiting time. Only after 6 seconds do the elapsed counter and the sawing Struqo craftsman join in, where distraction helps rather than slows. Under prefers-reduced-motion the stripe holds still, the text remains.

Loading project “Carport Winni” …
Fills the waiting area (canvas, viewport)
<LoadingIndicator variant="overlay">
Loading project “Carport Winni” …
This is taking longer than usual.
Long case: elapsed time and figure join in
<LoadingIndicator figure hint={…}>
Loading project “Carport Winni” …
Please check your internet connection.
The statement turns into an action
<LoadingIndicator figure hint={…}>
Loading …
Compact in rows and panels
<LoadingIndicator variant="inline">
ProgressBar

The bar on its own, for waits outside the loading indicator. Deliberately without a value prop: as long as no load path measures real progress, a filling bar would be a claim without ground. Silent for screen readers, the surrounding live region carries the statement.

Determinacy without measurable progress
<ProgressBar />
Type scale
Ag 1234
--text-xs
Ag 1234
--text-sm
Ag 1234
--text-base
Ag 1234
--text-lg
Ag 1234
--text-xl
Ag 1234
--text-section-xs
Ag 1234
--text-section-sm
Ag 1234
--text-section
Ag 1234
--text-display-xs
Ag 1234
--text-display-sm
Ag 1234
--text-display
Line height
--leading-display
Used for headlines
--leading-heading
Used for headlines
Letter spacing
--tracking-display
Used for display and mono labels
--tracking-heading
Used for display and mono labels
--tracking-eyebrow
Used for display and mono labels
Eyebrow utility
KNOWS ITS WAY AROUND WOOD.eyebrow
Spacing (8px grid)
--spacing-1
--spacing-2
--spacing-3
--spacing-4
--spacing-6
--spacing-8
--spacing-12
--spacing-16
Corner radius
--radius-sm
--radius-md
--radius-lg
Shadow
--shadow-sm
--shadow-md
--shadow-lg
Line widths (DIN)

Drawing line widths per DIN EN ISO 128-20, line group 1. The standard series steps by a factor of the square root of 2; a line group picks a wide-to-narrow pair at a 2:1 ratio. Whatever the section plane cuts gets the wide solid line, whatever sits behind it gets the narrow one.

--stroke-din-sehr-schmal
Very thin, defined as a step
--stroke-din-schmal
Behind the section plane
--stroke-din-breit
Cut and elevation parts
--stroke-din-extra-breit
Solid and existing walls

The samples draw 1:1, the way the canvas draws at zoom 1. On the stage, line width scales with the zoom.

Motion
--duration-fast
Duration or easing curve
--duration-normal
Duration or easing curve
--duration-work-loop
Duration or easing curve
--ease-standard
Duration or easing curve
Layout
--max-width-container
Container max width
Z-index
--z-index-sticky
Stacking order
--z-index-dropdown
Stacking order
--z-index-modal
Stacking order
--z-index-tooltip
Stacking order
Card

List-item container in three variants: static for passive info, interactive with a hover state, and with an actions menu for secondary operations. The card body is always the primary click target. Secondary actions live in the ⋯ menu in the top-right, never as parallel buttons.

Sample item

Secondary info, kept neutral

Static
<Card>
Sample item

Secondary info, kept neutral

Interactive
<Card interactive>
Sample item

Secondary info, kept neutral

With actions menu
<Card interactive> + <DropdownMenu>
FormField

Label, helper text, error message and the a11y wiring around any control. The error state sets aria-invalid and tints the border. Control-agnostic: input, select or textarea.

We never share it.

helper

Required field.

error · aria-invalid
required
control-agnostic (select)
Picker

One selection list for five instances: project, sheet, type, snap step, unit. The entry in force is marked and stays selectable; disabled is reserved for what does not exist. Click the button to open, Esc closes it and returns focus.

<Picker side="bottom" sections={…} />
Save dot

Saved is the resting state and stays put, saving pulses. Offline and a save error are two situations: amber means it carries on by itself, red means there is something to do. The title beside it keeps its colour in every state.

Nothing to save yet
idle
Saving
saving
Saved
saved
Offline, will catch upWill catch up
offline
Saving failed, Struqo keeps tryingKeep this window open
error
Not savedNot saved
guest
Freshness of derived drawings

The drawings rail shows per view whether the projection still matches its source plan. This is not a save status: it knows nothing about the network or the server, it only compares derivation against source. A closed ring means complete, an open arc means something is missing. One click brings it up to date.

Up to date
Out of date, refresh
Illustration

Tree treatments.

Three answers to "What would Dieter Rams do?" for the wood building block. Same geometry, three dialects. Used on the landing ("Why wood") and the stance page.

Konstruktion

Tree as a wood drawing: hatched post trunk, mono dimension, faceted crown.

Strich

Pure line dialect, the same language as the ValueProps diagrams.

Aicher

Flat pictogram in muted green, the softest and most organic.

Voice and tone

Self-aware, relaxed, with a wink.

Measured: three to five beats per longer page. The product is meant to grow and become big; the posture can already smile at itself today without making itself small.

Pattern
Still X
Do
v0.9 · wooden construction planner · still beta
Avoid
v0.9 · wooden construction planner · in beta
Still signals we know where we are and we are working on it. In just hangs there.
Pattern
Parenthetical hedge
Do
Plan and BOM for (small) wooden projects.
Avoid
Plan and BOM for wooden projects.
The parenthesis smiles at current smallness without closing the door on growth.
Pattern
Competence pivot
Do
More expensive tools exist for that.
Avoid
Better tools exist for that.
More expensive states a fact. Better would be self-deprecation that lowers product value.
Pattern
Honest punchline
Do
One developer, reachable. Mostly.
Avoid
One developer, always here for you.
The second sentence hedges honestly and earns trust.
Known gaps

text-text-3 currently fails WCAG AA contrast, panel inputs suppress the global focus ring, and wood species swatches still live outside the CSS token system. Details in docs/DESIGN_SYSTEM.md under Known gaps.

Design system · Struqo