Blockhaus
Cream paper, black ink, wide geometric headlines. Every section is a ruled block and every action a pill.
- Light by default
- 35 colours · 14 type steps
- Inspired by helloivy.co
The same generated app in every design. Scroll inside the window to see the whole page.
What it is
Blockhaus builds every page from ruled blocks, like a design journal printed on cream paper. The palette is black ink, cream and one slate grey, with white sheets for the product itself. Headlines are set in Unbounded, a wide geometric face, and everything else in Inter. Every section sits in square cells drawn with 1px black rules, every action is a black pill, and nothing casts a shadow. Colour appears only in status and in six risograph inks for charts.
Maintained by @agentic-studio in the open registry.
Best for
Tools for designers, studios and agencies: project management, briefs, reviews, portfolios and creative ops. Also any product that wants to look printed and sure of itself instead of glossy.
Trade-offs
- Unbounded is very wide. A 40 character hero title fills two lines at 72px and a longer one takes three, and long words wrap early on a phone. Keep headlines short.
- Every frame is 1px of black ink. That is the look, but busy screens get heavy fast: rows inside a frame drop to a soft rule, and a framed box never sits inside another.
- There is no brand colour. Links, focus and the accent are black, so a screen that must pull the eye does it with size, an ink block or the black pill. Status and charts are the only colour.
Tokens
Generated from this design’s design.yaml, and shipped as CSS variables plus a Tailwind theme. Templates may use these names and nothing else.
Colours
Every colour token in design.yaml, grouped the way the system documents them. These are the light palette's values. The dark palette uses the same names with its own values, and tokens.css ships both.
Brand and accent
accent
#000000
accent-1
#000000
accent-2
#0078bf
accent-3
#e05a1a
accent-4
#765ba7
accent-5
#008c4c
accent-6
#e6399b
accent-hover
#333333
accent-soft
#efe8dc
primary
#000000
Surface
canvas
#faf6f0
hairline
#000000
surface-card
#ffffff
surface-dark
#000000
surface-dark-elevated
#1f1e1c
surface-soft
#f3ede3
surface-solid
#ffffff
surface-strong
#e4dac9
Text
body
#555555
body-strong
#1f1f1f
ink
#000000
muted
#5e697f
muted-soft
#7d8698
on-accent
#ffffff
on-dark
#faf6f0
on-primary
#ffffff
Semantic
error
#c02a26
success
#1d7a46
warning
#9a5b00
Other
danger
#c02a26
danger-soft
#fbe6e1
error-soft
#fbe6e1
primary-hover
#333333
success-soft
#e6f1e4
warning-soft
#f8ecd6
Type scale
Each token rendered at its real size, weight, line height and tracking. Specimens fall back to this site's typeface when the design's own face is not installed locally, so read the numbers, not the letterforms.
Ship faster
- Token
- display-xl
- Values
- 4.5rem · 72px · 500 · lh 1.1 · ls 0
Ship faster
- Token
- display-lg
- Values
- 3.5rem · 56px · 500 · lh 1.1 · ls 0
Ship faster
- Token
- display-md
- Values
- 2.25rem · 36px · 500 · lh 1.2 · ls 0.005em
Ship faster
- Token
- display-sm
- Values
- 1.875rem · 30px · 500 · lh 1.2 · ls 0.01em
Ship faster
- Token
- title-lg
- Values
- 1.5rem · 24px · 500 · lh 1.3 · ls 0.01em
Ship faster
- Token
- body-lg
- Values
- 1.125rem · 18px · 400 · lh 1.6 · ls -0.02em
Ship faster
- Token
- title-md
- Values
- 1.125rem · 18px · 500 · lh 1.35 · ls 0.01em
Ship faster
- Token
- body-md
- Values
- 1rem · 16px · 400 · lh 1.6 · ls -0.02em
Ship faster
- Token
- title-sm
- Values
- 1rem · 16px · 500 · lh 1.4 · ls 0.01em
Ship faster
- Token
- body-sm
- Values
- 0.875rem · 14px · 400 · lh 1.55 · ls -0.01em
Ship faster
- Token
- button
- Values
- 0.875rem · 14px · 500 · lh 1 · ls -0.01em
Ship faster
- Token
- nav-link
- Values
- 0.875rem · 14px · 500 · lh 1.4 · ls -0.01em
Ship faster
- Token
- caption
- Values
- 0.8125rem · 13px · 500 · lh 1.45 · ls 0
SHIP FASTER
- Token
- caption-uppercase
- Values
- 0.75rem · 12px · 500 · lh 1.3 · ls 0.06em
Typefaces
The families the generated Tailwind theme points at. A licensed face is named here even when the substitute below is what actually renders.
- DisplayUnbounded, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif
- BodyInter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif
- MonoMartian Mono, ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace
Spacing scale
Drawn at true size. These are the only gaps and paddings a generated repo is allowed to use.
- xxs0.25rem · 4px
- xs0.5rem · 8px
- sm0.75rem · 12px
- md1rem · 16px
- lg1.5rem · 24px
- xl2rem · 32px
- xxl3rem · 48px
- section4rem · 64px
Radius scale
Sample shapes at true corner radius. Buttons and inputs sit at the small end of this scale, feature cards at the large end.
- lg0 · 0px
- md0 · 0px
- sm0 · 0px
- xl0 · 0px
- xs0 · 0px
- full9999px
- pill9999px
Elevation
Shadow tokens on a neutral card, at true blur and spread.
- inset0 0 #0000
- lift0 0 #0000
- overlay0 0 #0000
- ring0 0 0 1px #000000
- soft0 0 #0000
- xs0 0 #0000
DESIGN.md
Ships in your repo as DESIGN.md. The designer agent reads it before it may introduce a new visual pattern. This is the briefing, not a page about the briefing.
Blockhaus is a risograph design journal on cream paper: black ink, ruled blocks and one wide geometric headline doing all the talking. Every landing block sits in square cells drawn with 1px ink rules on the same two column lines. Every action is a black pill, product screens are white sheets, and pictures rest on a hatched kraft tray. Nothing casts a shadow, and colour is kept for status and charts.
Read this before you add a screen, a component or a colour. The tokens live in
src/app/globals.css, the faces in src/app/fonts.ts, the kit in
src/components/ui/.
At a glance
| Theme | Light native: black ink on cream paper (#faf6f0). Dark is the carbon print: warm near-black paper (#151412), cream ink and grey rules. |
| Type | Unbounded 500 for every heading, card and dialog title. Inter for everything else, tracked tight. Martian Mono only for code, keys and ids. |
| Colour | Black, cream, kraft and one slate grey (#5e697f) for secondary text. No brand colour: status and six risograph chart inks are the only hues. |
| Shape | Every box is square. Only actions and marks are round: pill buttons, circle icon buttons, switches, radios, avatars and stamps. |
| Depth | None cast. Five of six shadows are empty and the ring thickens a 1px frame to 2px. Depth is paper: cream page, white sheets, kraft trays. |
| Signature | Ruled cells on one column, eyebrows led by a 24 by 6px ink block, tick-ring stamps on the steps and a solid ink closing block. |
Principles
- Every block is a ruled box: 1px ink frames, square corners, shared edges, no gaps.
- Every frame lands on the same two column lines.
- Round means action. Buttons are pills; boxes are square.
- Depth is paper and ink, never a shadow, glow, gradient or blur.
- Black pulls the eye. Colour is only for status and data.
Colour
Palette
| Token | Light | Dark | Role |
|---|---|---|---|
canvas (--background) | #faf6f0 | #151412 | The page floor |
surface-soft | #f3ede3 | #0f0e0c | Section bands, sidebars, table heads |
surface-card (--muted) | #ffffff | #1e1c19 | Tinted fills: inactive tabs, hover rows, code |
surface-strong | #e4dac9 | #2f2c28 | Pressed fills, progress tracks |
surface-solid (--popover) | #ffffff | #211f1c | Menus, selects, toasts: always opaque |
card | #ffffff | #1e1c19 | The card fill |
surface-dark | #000000 | #000000 | The inverted panel |
hairline (--border) | #000000 | #6b6761 | Every border and divider |
ink (--foreground) | #000000 | #f4efe6 | Headings and primary text |
body-strong | #1f1f1f | #e8e2d8 | Emphasised body text |
body | #555555 | #c4bfb6 | Running text |
muted (--muted-foreground) | #5e697f | #9aa3b5 | Secondary text, captions |
muted-soft | #7d8698 | #6f7788 | Placeholders, disabled text, icons at rest |
primary | #000000 | #f4efe6 | The action colour |
accent (--accent-fill) | #000000 | #f4efe6 | The saturated accent: links, the accent badge |
accent-soft | #efe8dc | #2b2824 | The tint an accent label sits on |
danger (--destructive) | #c02a26 | #f0705f | Destructive actions and errors |
success, warning and error each come with a -soft tint for the back of a
badge or an alert: #1d7a46, #9a5b00 and #c02a26 in light, #5cc98a, #e8a33d and
#f0705f in dark.
Blockhaus's own variables, read by the landing hooks and the kit: --rule-soft
(rgb(0 0 0 / 0.16) light, rgb(244 239 230 / 0.14) dark), --hatch (rgb(0 0
0 / 0.1) light, rgb(244 239 230 / 0.07) dark).
How colour is used
- Ink (
--foreground, black, cream in dark) draws headings, actions, rules, the feature icon blocks and the closing block. - Running text is charcoal (
text-body, #555555). Secondary text, eyebrows and labels are slate (text-muted, #5e697f). - Surfaces are paper: the cream canvas, white sheets (
bg-card) for product UI, kraft (bg-secondary,bg-surface-soft) for trays and secondary buttons. - The accent is ink too: links, focus and
text-accentare black. Pull the eye with size, an ink block or the black pill. - Green, amber and red mark status only, as
-softtints with a 1px border in the full status colour.
Charts
accent-1 to accent-6 (also chart-1 to chart-6) are six series colours
ordered so neighbours stay distinguishable. Six risograph inks in order: black,
blue, orange, violet, green, pink (cream leads in dark). A single series is
always black, and colour always pairs with a label or a pattern. Assign them in
order; never let colour be the only way to tell two series apart.
Dark mode
The palette is declared twice in src/app/globals.css: light on :root, dark
under @media (prefers-color-scheme: dark) and again on .dark, where the
class wins in both directions. @theme inline points every utility at those
variables, so bg-canvas is one class that follows the mode.
src/lib/design.ts sets the theme a first visit opens in: light here, because
Blockhaus is drawn in light first. The theme menu in the header offers light,
dark and system and remembers the choice.
Type
Faces
- Unbounded (
font-display): headings and display type. - Inter (
font-body): running text and interface copy. - Martian Mono (
font-mono): code, ids and tabular labels.
Unbounded is wide, geometric and a little quirky: at 72px it carries the whole brand, so the palette can stay quiet. Inter's optical sizes keep running text open and dense, and Martian Mono shares the headline's width, so a key or an id reads as part of the same voice.
Every face loads through next/font/google in src/app/fonts.ts: downloaded at
build time and served from this app. Change a face there and here, together.
Scale
| Token | Size | Line | Tracking | Weight | Use |
|---|---|---|---|---|---|
text-display-xl | 72px | 1.1 | 0 | 500 | The hero headline, desktop |
text-display-lg | 56px | 1.1 | 0 | 500 | The hero headline, tablet |
text-display-md | 36px | 1.2 | 0.005em | 500 | Section headlines, the hero on phones |
text-display-sm | 30px | 1.2 | 0.01em | 500 | Section headlines on phones, big numbers |
text-title-lg | 24px | 1.3 | 0.01em | 500 | Page titles in the app |
text-title-md | 18px | 1.35 | 0.01em | 500 | Card titles |
text-title-sm | 16px | 1.4 | 0.01em | 500 | Small headings, table titles |
text-body-lg | 18px | 1.6 | -0.02em | 400 | Lead paragraphs |
text-body-md | 16px | 1.6 | -0.02em | 400 | Running text |
text-body-sm | 14px | 1.55 | -0.01em | 400 | Interface copy, table cells |
text-caption | 13px | 1.45 | 0 | 500 | Metadata, helper text |
text-caption-uppercase | 12px | 1.3 | 0.06em | 500 | Eyebrows above headings |
text-button | 14px | 1 | -0.01em | 500 | Buttons |
text-nav-link | 14px | 1.4 | -0.01em | 500 | Header and footer links |
Rules: one h1 per page. Display sizes are for marketing pages; the app tops
out at text-title-lg. Headings are Unbounded 500 from 16 to 72px, tracked 0 to
0.01em: never tighter, never in capitals, never under 16px. Inter runs -0.02em
at 16px and up and -0.01em at 14px; labels are 12px capitals at +0.06em. Stat
numbers and prices are Unbounded with tabular figures.
Space and layout
- Spacing tokens:
xxs4px,xs8px,sm12px,md16px,lg24px,xl32px,xxl48px,section64px (the gap between landing sections). - Content sits in
max-w-content(1280px) withpx-mdon phones andpx-lgfromsmup. Reading text stops atmax-w-measure(672px). - Spacing steps are 4, 8, 12, 16, 24, 32 and 48px, with 64px of section padding, so landing blocks sit about 128px apart.
- Cells pad 24 to 32px, controls are 40px tall and elements sit 16px apart.
- Header, hero, grids, showcase rows, FAQ, closing block and footer all share the content column's two edges.
- Space separates sections. There are no bands and no rules between them.
Shape and depth
| Token | Value | Where |
|---|---|---|
rounded-xs | 0 | Not used by the kit |
rounded-sm | 0 | The landing page |
rounded-md | 0 | Toaster, the landing page |
rounded-lg | 0 | The landing page |
rounded-xl | 0 | The landing page |
rounded-pill | 9999px | Button, Switch, Toaster, the landing page |
rounded-full | 9999px | Accordion, Avatar, Dialog, RadioGroup, Sheet, Switch |
Every radius is 0 except pill, which belongs to buttons, switches, radios,
avatars, status dots and stamps. Borders are solid: a 1px ink rule on frames and
fields, a soft rule (ink at 15%) for rows inside a frame, and 3 to 6px ink bars
for emphasis. Shadows are empty; shadow-ring is a 1px ink ring that marks a
selected card or a pressed toggle. Floating layers get an ink frame, not a
shadow.
Components
Every component lives in src/components/ui/ and is written against the tokens
above. Import from there; never restyle a kit component inline to make a
one-off.
| Component | In Blockhaus |
|---|---|
Button | A pill in every variant and size: Inter 14px 500, sentence case, no shadow. Primary is black with a white label, #333333 on hover, and presses down 1px. Secondary is kraft, outline is an ink ring that inverts to ink on hover and on the current page, ghost tints ink at 6%, danger is red. Sizes are 32, 40 and 48px tall; icon buttons are 40px circles. Focus is a second ink frame 2px outside, and disabled drops to 40%. |
Badge | Square, never a pill: a 1px border and a 13px 500 label. Neutral is a stamped ink outline, accent is an ink label with white text, and status badges are soft tints with a full-colour border. |
Card | Square, no shadow. Default is a white sheet in a 1px ink frame; soft is a kraft cell in the same frame, strong is the darker kraft with no border, outline is a bare cream cell and dark is the ink block. Titles are Unbounded 18px 500. |
Input, Textarea, Select | 40px white fields in a 1px ink frame, square, with 14px text, a pale slate placeholder and no hover change. Textareas start at 96px and resize vertically. Focus adds a second ink frame 2px outside; invalid turns the frame red. Select content is a white sheet in an ink frame; the highlighted option is inked with cream text and the chosen one shows a check. |
Checkbox, RadioGroup, Switch | Checkboxes are 16px squares that fill with ink and a white check. Radios are circles with an 8px ink dot. The switch is a pill: white with an ink thumb when off, an ink track with a cream thumb when on. |
Tabs | Default is a segmented ink box: square cells split by ink rules, the active one inked with cream text. Line tabs sit on a 1px ink rule and mark the active tab with a 3px ink bar. |
Accordion | Rows split by ink rules. Triggers are Unbounded 16px, underlined on hover. The chevron sits in a 24px ink ring that fills with ink and turns over when open. |
Dialog, AlertDialog, Sheet | White square panels in a 1px ink frame, no shadow, over a 50% ink overlay with no blur. Titles are Unbounded 24px and left-aligned; actions are an outline pill, then a primary pill. Close is a 32px ghost circle. Sheets are cream with an ink rule on the inner edge and under the title. |
DropdownMenu, Popover, Select content, Tooltip | White sheets in a 1px ink frame, square, no shadow. Highlighted items are inked with cream text, danger items fill red, labels are slate capitals, separators are the soft rule and shortcuts are Martian Mono 11px. Tooltips are small square ink blocks. |
Table | Inter 14px with tabular figures. Heads are 12px slate capitals over a 1px ink rule, rows split by the soft rule, hover kraft, selected rows a kraft tint, and the footer is kraft under an ink rule. Right-align numbers and set ids and keys in font-mono at 12px. |
Alert | Square, a 1px border and 16px of padding. Info is a white sheet in an ink frame; success, warning and danger are soft tints with a full-colour border, title and icon. |
Avatar, Progress, Skeleton, Spinner, Separator, Kbd, Breadcrumb, Pagination, Field, Label, Toaster | Avatars are circles with Unbounded initials on the darker kraft. Progress is an 8px square bar in an ink frame that fills with ink. Skeletons pulse slowly on the darker kraft and spinners are ink. Separators are 1px ink rules, soft inside menus and tables. Kbd is Martian Mono 11px on white with a 2px bottom edge. Breadcrumbs are slate links that underline in ink on hover; the current page is ink. In pagination the current page is an ink disc and the others are ghost circles. Labels are Inter 14px 500 in ink, with 13px slate descriptions and red errors, and fields stack 16px apart. Toasts are white sheets in an ink frame with a small ink pill action and an outline pill cancel. |
The landing page
The landing page is the same in every design; the design decides how it looks.
Its sections carry data-slot hooks (listed at the top of
src/components/marketing/section-heading.tsx) that globals.css may style.
Blockhaus styles these:
site-header: an opaque cream strip with no blur, holding a 72px ruled box on the column lines.site-nav: from 64rem the middle cell, ruled on both sides, with ink links at its right. Hover draws a 1px underline; the current page gets a 3px ink bar.brandandbrand-mark: the name in Unbounded 500; the mark is an ink square with its letter in Unbounded.hero: a ruled box hanging from the masthead box so the two share one rule, with everything left-aligned.hero-backdrop: hidden. The hero is bare paper: no wash, no grid, no glow.hero-title: Unbounded across the full width of the box, 30 to 36px on a phone; a long word breaks instead of clipping.hero-subtitle: a near-black Inter deck that grows to 26px.hero-eyebrow: a white pill with an ink edge; a linked eyebrow inverts to an ink pill on hover.hero-visualandshowcase-visual: a kraft tray with a faint 45 degree hatch. The hero tray is the box's second cell, under an ink rule.product-previewandproduct-preview-bar: a white sheet in an ink frame with no shadow; the cream title bar turns its window dots into an ink circle, square and triangle, and rows inside its cards drop to the soft rule.section: soft sections and the steps lose their bands and rules; space separates blocks.section-heading: left-aligned. From 64rem it splits: eyebrow on its own row, title left (3fr), description right (2fr), bottoms aligned. The FAQ keeps its own two columns.section-eyebrow: slate capitals led by a 24 by 6px ink block, on every section and showcase row.feature-grid,feature-cardandfeature-icon: one ruled block of bare cream cells with no gaps, each led by a 40px ink square with a cream icon.logo-cloudandlogo: one ruled strip of equal cells, two across on a phone, each name centred in Unbounded slate. The strip title goes back to Inter capitals.steps,stepandstep-marker: ruled cells with no connector lines. Each step opens with a stamp: a hollow 52px circle with an Unbounded numeral inside a ring of 24 ink ticks.showcase-rowandshowcase-copy: each row is one box split into a cream copy cell and the hatched tray. Rows share edges, so the three read as one checkerboard block.stat-grid,statandstat-value: a 4px ink bar on top, left-aligned cells and Unbounded numbers up to 64px with tabular figures.testimonial: the quotes become bare ruled cells hanging from the figures, set in 18px Inter in ink.faq: a closed ruled box. Questions are Unbounded 16px, underlined on hover, with the chevron in a 30px ink ring that fills when open.cta-bandandcta-panel: a solid ink block with no wash and no shadow, a cream headline and cream pills, and from 64rem a tick-ring stamp in the top right corner. On a dark page it keeps a grey edge.site-footer: cream paper, not a band. The colophon is the last ruled box on the column lines, with a 24px wordmark and Inter column heads.
Everything else is type, space and the kit.
Signed-in screens
The dashboard is the same paper at work: a kraft sidebar ruled off in ink, Unbounded 24px page titles, white card sheets in ink frames, black pill actions and tables with Inter capital heads over an ink rule.
Sign-in is one narrow white sheet in an ink frame on bare cream, with ink-framed fields, a full-width black pill and outline pills for the providers.
Do and don't
Do
- Put every landing section's content in ruled cells: 1px ink frames, square corners, shared edges, no gaps.
- Line up every framed block on the content column: header, hero, grids, showcase rows, FAQ, closing block and footer.
- Set every heading (h1 to h6, card, dialog and sheet titles, FAQ questions) in Unbounded 500, everything else in Inter, and code in Martian Mono.
- Make every action a pill: the black primary for the one main action, outline or ghost pills for the rest.
- Put product UI on white sheets (
bg-card) and pictures on the hatched kraft tray. - Keep running text in
text-bodyand secondary text intext-muted. Keep black for headings, actions and rules. - Plot data in the chart inks in order: black, blue, orange, violet, green, pink. A single series is always black.
- Check both prints every time, including the black closing block, which gains a grey edge on a dark page.
Don't
- Don't add a shadow, a glow, a gradient or a blur. Depth is paper and ink.
- Don't round a box. Cards, fields, menus, dialogs, tabs, badges and tooltips stay square.
- Don't make anything that is not an action into a pill: not a badge, a label, an input or a section eyebrow.
- Don't put a framed box inside another framed box. Inside a frame, divide with the soft rule.
- Don't add a brand colour: no blue links, no tinted buttons, no coloured bands.
- Don't use the chart inks for text, icons, borders or decoration.
- Don't set Unbounded below 16px, in capitals, in running text or with negative tracking.
- Don't use dashed or dotted lines. The stamp ticks and the tray hatch are the only broken marks.
Working in this design
Pasting from shadcn/ui. The token layer carries shadcn's variable names, so
most snippets render unmodified. Two utility names mean something else here:
bg-muted becomes bg-surface-card, and bg-accent / text-accent-foreground
(a hover surface upstream) become bg-surface-card / text-ink. Here muted
is a text colour and accent is the saturated accent.
Adding a token. Add it to all three palette blocks in globals.css (light,
the dark media query, .dark), map it in @theme inline, and document it in
the palette table above. Check contrast in both modes.
Adding a component. Check the kit first: most needs are a variant of
Button, Card or Badge, or a composition on the page. A new component gets
its own file in src/components/ui/, token classes only, a data-slot, and a
row in the Components table here. The designer subagent owns this.
Build a repo in Blockhaus
The builder opens with Blockhaus picked. Pick your batteries and the design is applied to every template before the zip is built.
