Tokens, building blocks, voice.
The open reference for Struqo's visual system, from tokens to whole pages. Every value comes live from the code, Figma follows it. Agents read the same building blocks in apps/web/components/styleguide/catalog.ts.
Foundations
The tokens from globals.css and the icon set. They sit before the five stages: Brad Frost counts colours, fonts and icons as atoms, here they stand apart because they are not building blocks.
Semantic colours for surfaces, text, borders, status and selection, in light and dark.
One blue for everything that is selected. The part in the drawing, its row in the panel, the active entry in the picker, the open drawing in the rail and the focus ring all read the same token. Only the edge carries colour, the surface stays neutral.
The layers panel and the material list mirror the selection from the drawing. The left edge carries the blue, the surface keeps the ordinary hover tone.
- Counter batten 6443.9 cm
- Cladding west452.0 cm
- Roof sheathing618.0 cm
Picker, drawings rail and the list in focus mode mark with the same bar. The surface stays the neutral card, so the list stays calm.
- West elevation
- Plan 1
- Section B-B
The focus ring reads the same colour. Keyboard and selection speak one language, with no second blue standing next to it.
Anyone building a new surface that shows a selection uses --color-selection (as the class border-selection or bg-selection) or SELECTION_ECHO_EDGE from lib/editor/selection-echo.ts. The value lives once in globals.css, so three patterns for one statement cannot come back. The filled surface of on-states (2D|3D, icon toggles) is not a selection and stays neutrally inverted.
One selection colour across drawing, panels and lists.
Three families, each with one job: Inter for work in the editor, Manrope for everything Struqo says to the outside, IBM Plex Mono for everything you read off. The last line of each card shows which font the browser actually uses for the sample.
- When
- Everything you read or operate in the editor: panels, menus, dialogs, buttons, drawing titles, free text on the sheet.
- Where
- Editor, project list, sign-in and sign-up.
- When
- Everything Struqo says to the outside: headings, body text, navigation and buttons.
- Where
- Every page with the marketing header and footer: home, subpages, journal, help, account, styleguide. Never in the editor.
- When
- Everything you read off: measurements with units (always tabular-nums), dimensions, axes, rulers, scale bars, eyebrows, captions, token names.
- Where
- Everywhere, the same in editor and communication.
One block, one font. A mono label and a text in Inter or Manrope become two blocks, otherwise the baseline does not fit (§ Register).
Each step carries its line height, a multiple of 4 px. The faint lines run every 4 px, the strong ones mark the end of each line of text, so they always sit on a faint one. On the right: size and line height, measured in the browser. This puts the lines on the grid, the baselines not yet: the type sits in the middle of the line box.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
With baseline-grid the first baseline sits on a 4 px line of its own box, each further one a line height lower. The box keeps the height it has without the class, only the type moves, by 2 px at most. The strong lines mark the baselines, the faint ones run every 4 px. On the right: baseline and line height, measured in the browser.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
Rafters, purlins and battens
keep the same beat.
The same card twice, the grid starts at its outer edge. On the left it has a border, which pushes the content down by 1 px. On the right the frame is an inset-ring on the inside and moves nothing.
Bill of materials
Carport south
Twelve rafters 8/16, spruce KVH, all in line.
12 pcs · 3.20 m
Bill of materials
Carport south
Twelve rafters 8/16, spruce KVH, all in line.
12 pcs · 3.20 m
On marketing and journal pages every baseline sits on a 24 px grid, across all columns. Body text takes a 24 px line. Headings keep their line height and fill whole modules. An image starts at the cap height of the first line next to it and ends on a baseline. The lines run under the baselines.
Example
Draw first. Then cut.
Wood forgives a lot, just not wrong lengths. A plan you drew yourself turns the project into an order of work.
Twelve rafters 8/16, spruce KVH. This column is set smaller and sits on the same lines.
Font sizes, line heights and tracking as tokens, Inter for the editor, Manrope for communication, IBM Plex Mono for measurements.
Spacing on the 8 px grid.
Corner radii, 4 px by default.
Three shadow steps for floating surfaces.
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.
The samples draw 1:1, the way the canvas draws at zoom 1. On the stage, line width scales with the zoom.
Line weights per DIN EN ISO 128-20 for drawings and print.
Durations and curve for transitions.
Maximum content width.
Layers for sticky elements, menus, dialogs and tooltips.
85 icons on a 16 px grid with a 1.25 px stroke, the chevrons for input fields at 10 px. They take the text colour of their surroundings, so they read the same in both themes. Grouped by where they sit.
- ExportIcon
- FocusIcon
- GridIcon
- HatchIcon
- HelpIcon
- KeyboardIcon
- MenuIcon
- PrintIcon
- ProjectsIcon
- RedoIcon
- RulerIcon
- SettingsIcon
- SnapIcon
- ThemeDarkIcon
- ThemeLightIcon
- ThemeSystemIcon
- UndoIcon
- ZoomFitIcon
- ZoomInIcon
- ZoomOutIcon
- AutoDimensionIcon
- BeamIcon
- CircleIcon
- CutIcon
- DetailMarkerIcon
- DimensionIcon
- MassiveWallIcon
- MeasureIcon
- NorthArrowIcon
- PanIcon
- PenIcon
- PolygonIcon
- ScaleBarIcon
- SectionLineIcon
- SelectIcon
- SketchRectIcon
- TextIcon
- TriangleIcon
- WallIcon
- AlignBottomIcon
- AlignCenterXIcon
- AlignCenterYIcon
- AlignLeftIcon
- AlignRightIcon
- AlignTopIcon
- CheckIcon
- ChevronDownIcon
- ChevronLeftIcon
- ChevronRightIcon
- CloseIcon
- CubeIcon
- DeleteIcon
- DistributeHorizontalIcon
- DistributeVerticalIcon
- DownloadIcon
- DuplicateIcon
- FullscreenIcon
- HiddenIcon
- LockedIcon
- MoreHorizontalIcon
- PlusIcon
- RotateIcon
- ShadowIcon
- SurroundingsIcon
- SyncIcon
- UnlockedIcon
- VisibleIcon
- BeamComponentIcon
- BoardIcon
- CladdingIcon
- JoistIcon
- PanelIcon
- PostIcon
- RafterIcon
- RoofingIcon
- ShrubIcon
- StudIcon
- TreeIcon
- WallFrameIcon
- DetailGlyphIcon
- ElevationGlyphIcon
- IsoGlyphIcon
- MemberGlyphIcon
- PlanGlyphIcon
- SectionGlyphIcon
Every icon sits in IconBase, the only approved SVG frame. It becomes operable inside IconButton, which brings the label and tooltip.
Every icon in the editor and app, 16 px grid, 1.25 px stroke, colour from the surroundings.