Steel looks like a well-made instrument: a near-white page and pure black ink, type set light, and flat colour that arrives in whole bands, never as gradients or textures. Generous space separates groups; tight space holds a group together. Edges are 0.5px hairlines and 4px corners. Shadows are barely there. Motion is quick and exact. Every rule below comes from the three products that define the brand (the website, the app and the launch videos), so following them makes new work sit next to those products without looking borrowed.
The rules that make it Steel
These are fixed. If a user asks for something that breaks one, say which rule it breaks and why it exists, offer the on-brand alternative, and follow their decision. Don't quietly drift.
- Type depends on the surface.
- Websites and brand work (steel.dev, landing pages, docs, emails, slides, social, OG images, posters, video):
- Schengen A sets everything you read: body, UI and, by default, titles.
- Schengen Line is for display moments at 32px and up only (a hero h1, a title card, a counter, a big statement). It is a lined design that falls apart small.
- Schengen A Mono sets code, IDs, numbers in tables and the controls. Buttons, nav links and arrow links are 12px mono capitals, +0.015em.
- Web applications (the dashboard, consoles, settings, any signed-in product UI):
- Inter sets all UI text: body, controls, table cells, page and dialog titles. It is sentence case, 13px for body and controls.
- Schengen A Mono sets IDs, API keys, session IDs, numbers in tables, timestamps and code.
- No Schengen A or Line inside the app.
- Nothing else on any surface: no Geist, no system-ui as the face, no other Google Fonts face, no substitutes. Write the right family first in every stack, even when the font files aren't present yet.
- Websites and brand work (steel.dev, landing pages, docs, emails, slides, social, OG images, posters, video):
- No eyebrow text, ever. Never put a small label above a title, a section or a logo, whether in capitals or not ("NEW", "FEATURES", "WHY STEEL", "REINTRODUCING"). Let the title stand alone. If something needs a category, date or caption, put it below or after the title as a meta line, or in the title itself.
- Type is light. Websites set every face at weight 400 (arrow links 420). In the app, Inter runs 400 for body and 500 at most for emphasis. Video titles run 360–420. Nothing is bold. Build hierarchy with size, the two-tone title (lead in ink, trail in sand-9) and space. Headings track −0.02em.
- Colour is flat, from the palette and sand only.
- Seven hues in five steps (100 / 300 / 500 / 600 / 900), plus clash pink
#FE89B2and night#141414. - Every grey is a Radix sand step. The ink is pure black (pure white in the dark). The page is
#FDFDFC(pure white is fine). - Colour arrives as full-bleed bands of one hue with that hue's own ink, or as a 100-step pastel behind a picture.
- No gradients of any kind: backgrounds, text, borders, overlays, buttons or "glows". No background patterns or textures: no grids, dots, noise, grain, stripes, diagonals or topographic lines. No glass or blur. No off-palette hexes.
- Seven hues in five steps (100 / 300 / 500 / 600 / 900), plus clash pink
- The grid is 12 / 8 / 4 columns, and the margin equals the gutter. That is 24px at desktop, 20px margins on phones, 16px gutters under 640px, and 32px gutters above 1728px. The content column is 1280px. Prose stops at 30rem.
- Whitespace is structural. Sections sit 100px apart (48px on phones). Coloured bands pad 100px (88px on phones). Blocks within a section sit 144px apart, a section title sits 64px above its first block, and a title sits 16px above its description. Buttons sit 12px apart. The app runs denser (see
product-ui.md). - Corners and edges. 4px for every corner that isn't round, on buttons, cards, windows, fields and pictures (the app uses 6px controls and 8px panels; brand-film prints are square). Round things are drawn as Schengen's O. Every border is 0.5px. Depth comes from tone first, then a hairline, then a shadow in a deeper shade of the thing's own fill, never grey-black.
- Motion. Use
--ease-outcubic-bezier(0.23,1,0.32,1)to enter and exit, and--ease-in-outcubic-bezier(0.77,0,0.175,1)to move on screen. UI stays under 300ms. Neverease-in, nevertransition: all. Animate only transform and opacity, and never enter fromscale(0). Everything pressable scales to 0.97. Video runs on the frame and the beat (seereferences/video.md). - Fonts come from the right place.
- ABC Schengen belongs to Dinamo and is licensed, never bundled. Use the project's licensed files, never download or convert them, and never commit them to a public repo. If they're missing, wire everything to the expected filenames (
ABCSchengenA-Variable.woff2,ABCSchengenLine-Variable.woff2,ABCSchengenAMono-Variable.woff2) and tell the user where to put them. - Inter is open source (SIL OFL). Self-host it from
@fontsource-variable/interrather than a font CDN.
- ABC Schengen belongs to Dinamo and is licensed, never bundled. Use the project's licensed files, never download or convert them, and never commit them to a public repo. If they're missing, wire everything to the expected filenames (
Workflow
-
Identify the surface and medium and read only the references it needs:
Making Read Start from Website page, landing page, docs, email typography.md,color.md,layout.md,components.md,voice.mdassets/steel-tokens.css(+tailwind-theme.css),assets/templates/landing.htmlWeb app: dashboard, console, settings product-ui.md,color.md,typography.mdsteel-tokens.csswithdata-surface="app"on<html>Remotion video / motion graphics video.md,voice.mdassets/remotion/theme.ts,assets/remotion/motion.tsSlides, social, OG image, poster, print layout.md§8,color.md,typography.md,voice.mdassets/tokens.jsonfor values,assets/logo/Figma / design tokens for another tool color.md,typography.mdassets/tokens.jsonWeb or app animation motion.mdthe motion tokens in steel-tokens.cssReviewing or restyling existing UI everything relevant above run scripts/check_brand.pyfirst -
Lay the foundation before any component.
- Copy
assets/steel-tokens.cssinto the project (with Tailwind v4, addassets/tailwind-theme.cssafter it). - Websites: find the Schengen files (
find . -iname "ABCSchengen*") and point the@font-faceurls,next/font/localor RemotionloadFontat them. - Web apps: add
data-surface="app"to<html>, install@fontsource-variable/inter, and keep Schengen A Mono for the mono. - Use the semantic roles (
--bg,--surface,--line-subtle,--text,--text-description,--heading-trail) in components, never raw hexes or raw sand steps.
- Copy
-
Build with the house components.
- On websites (
components.md): mono-capital buttons (primary ink, secondary white with the shade), arrow links, 36px-chrome windows with neutral dots, the install field, feature blocks alternating words and pastel pictures, bands with the envelope shoulder, and agent cursors with name tags. - In apps (
product-ui.md): the rail and floating panel, 36px Inter buttons, zebra tables, round badges. - Write copy to
voice.md: sentence case, short declaratives, imperative button labels, numbers with commas and a plus.
- On websites (
-
Lint. Run
python3 scripts/check_brand.py <path>for websites, andpython3 scripts/check_brand.py <path> --surface=appfor web apps (this skill'sscripts/folder; Python 3.8+, no dependencies).- Fix every ERROR: wrong face for the surface, a hosted font, a gradient, a background pattern,
ease-in,transition: all. - Review every WARN: Line under 32px, bold, an eyebrow class, an off-palette colour (it names the nearest Steel colour).
- Depictions of third-party UI (mock browser pages showing other sites) are exempt: pass
--exclude=<dir>.
- Fix every ERROR: wrong face for the surface, a hosted font, a gradient, a background pattern,
-
Look at it. Render it if you can (browser, screenshot, Remotion still) in light, dark and at phone width, and check it against the list below.
Before you hand it over
- Websites: only Schengen A / Line / Mono, with Line only at 32px+. Apps: Inter for UI and Schengen A Mono for IDs and code.
- No eyebrow text anywhere: nothing small sits above a title, section or logo.
- No gradients, no background patterns or textures, no glass.
- Nothing bold. Headings −0.02em. Website controls in 12px mono capitals.
- Every colour is a palette step, a named Steel colour or sand. Bands use an approved ground/ink pair (
color.md§4). - Content on the 12/8/4 grid within 1280px. Margin = gutter. Prose ≤ 30rem.
- Section gaps 100px, block gaps 144px, title → description 16px (phone values from
layout.md). - 4px corners, 0.5px hairlines, shadows only as the shade recipe.
- Dark mode: ground
#141414, white ink, coloured bands keep their light colours (.keep-light), pictures dimmed to 0.82. - Motion: house curves, under 300ms, no ease-in, no
transition: all, reduced motion respected. - No Schengen files committed; the user knows if licensed files are still needed.
-
check_brand.py(with--surface=appfor apps) reports 0 errors.
The look, in numbers
| Value | |
|---|---|
| Website faces | Schengen A (text) · Schengen Line (display ≥ 32px) · Schengen A Mono (code, controls) |
| App faces | Inter (all UI text) · Schengen A Mono (IDs, keys, numbers, code) |
| Web type | hero 60/1.01 (40 phone) · section 40/1.05 (28) · lead 26/1.3 · claim 24/1.3 · term 20/1.4 · body 16/1.6 at 60% ink · small 14 · controls 12/16 mono capitals |
| App type | Inter 13/20 body and controls · 12 meta · 20–24 page titles · weights 400 / 500 |
| Video type | title cards Line 180.8/162.7 at 420 · headlines A 132/150 at 360 · captions Mono 32 under a figure |
| Ink / ground | #000 on #FDFDFC · #FFF on #141414 |
| Accent hues (500) | purple #793387 · blue #05A5FF · teal #00C6C5 · moss #80AA40 / green #01A300 · yellow #F4DD15 · orange #DF8120 · red #D40000 |
| Pastels (100) | #C799D4 · #D7F0FF · #BFF0EF · #99E099 · #FCF6BF · #F7D6AD · #F5A6A6 |
| Grid | 12/8/4 cols · 24px gutter = margin · 1280px page · 30rem measure |
| Rhythm | 100 between sections · 100 band padding · 144 between blocks · 64 title → block · 16 title → text · 12 between buttons |
| Controls | web buttons 36px (nav 32, phone 40), 12px padding, 4px corners · app buttons 36px, 6px corners · nav 72px · window chrome 36px |
| Edges | 0.5px hairlines · shade = fill mixed 45% toward ink at 12% + 8% |
| Motion | ease-out 0.23,1,0.32,1 · in-out 0.77,0,0.175,1 · 125/160/180/240/380ms · press 0.97 |
Files in this skill
references/typography.md: faces per surface, licensing, loading code (CSS, Next.js, Tailwind, Inter, Remotion, OG), scale, patternscolor.md: palette, sand, roles, approved pairings, dark mode, contrast, chartslayout.md: grid, rhythm, page anatomy, proportions, corners, depth, envelope shoulder, other formatscomponents.md: buttons, arrow links, split button, install field, nav, footer, feature blocks, windows, cards, FAQ, icons, cursors, logoproduct-ui.md: the web app's shell, Inter type, density, controls, tables, badges, overlaysmotion.md: web and app motion tokens, rules, signature detailsvideo.md: Remotion cadence, beats, transitions, title type, colour, recipesvoice.md: headlines, buttons, announcements, words to avoid
assets/steel-tokens.css,tailwind-theme.css,tokens.jsonremotion/theme.ts,remotion/motion.tstemplates/landing.html(open it over a local server with the fonts inassets/fonts/)logo/(lockup, wordmark and mark, incurrentColor)
scripts/check_brand.py: the brand linter (--surface=appfor web apps)