Add spacing objects, typography tokens lessons and update extraction rules

New lessons in Module 11: Spacing as First-Class Objects (lesson 04) and
Typography Tokens (lesson 05). Updated module overview with dual-ID system,
positional IDs, and new lesson links. Tutorial 11 now includes spacing and
typography steps. Module 12 lesson 01 updated with object vs spacing
extraction timing rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Mårten Angner 2026-02-27 02:48:36 +01:00
parent 7e4a8e1a7f
commit 095c2ec92e
5 changed files with 449 additions and 10 deletions

View File

@ -0,0 +1,192 @@
# Module 11: Conceptual Specifications
## Lesson 4: Spacing as First-Class Objects
**The invisible layer that holds everything together**
---
## The Gap Is Not Empty
Look at a well-designed page. Between the header and the hero. Between the cards in a grid. Between a heading and the paragraph below it.
That space is not "nothing." It's a design decision.
In WDS, **spacing is a first-class object** — it has an ID, a type, and a value, just like a button or a card.
---
## Why Spacing Gets an ID
Without IDs, spacing conversations sound like this:
> "Add more space between the trust section and the seasons section"
With IDs, they sound like this:
> "Change `hem-v-space-3xl` to `space-4xl`"
The second version is precise, traceable, and can be found in the design system. The first version requires the developer to figure out which space you mean.
---
## The Naming Convention
```
{page}-{v|h}-{type}-{size}
```
| Part | Meaning | Examples |
|------|---------|---------|
| `{page}` | Which page | `hem`, `nyheter`, `om-oss` |
| `{v\|h}` | Direction | `v` = vertical, `h` = horizontal |
| `{type}` | What kind | `space`, `separator`, `line` |
| `{size}` | Token value | `zero`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `flex` |
**The ID describes WHAT the spacing IS, not what it sits between.**
### Examples
```markdown
#### ↕ `hem-v-space-zero` — header and service menu form one continuous nav unit
#### ↕ `hem-v-separator-2xl` — gray line, space-2xl above and below
#### ↕ `hem-v-space-3xl` — major section boundary between seasons and footer
```
---
## Zero Spacing Is a Decision
When two objects touch with no gap, that's a deliberate design choice:
```markdown
#### ↕ `hem-v-space-zero` — hero sits flush below navigation, background color shift provides visual separation
```
If you don't document this, a future developer might "fix" it by adding spacing. Zero spacing says: "This is intentional. Don't add a gap."
---
## How Spacing Appears in Page Specs
Between each section, an explicit spacing object:
```
┌──────────────────────────┐
│ Site Header │
├──────────────────────────┤
│ ↕ hem-v-space-zero │ ← spacing object
├──────────────────────────┤
│ Service Menu │
├──────────────────────────┤
│ ↕ hem-v-space-zero │ ← spacing object
├──────────────────────────┤
│ Hero Section │
├──────────────────────────┤
│ ↕ hem-v-space-zero │ ← spacing object (bg color shift)
├──────────────────────────┤
│ About Section │
├──────────────────────────┤
│ ↕ hem-v-separator-2xl │ ← gray line with equal spacing
├──────────────────────────┤
│ Trust Cards │
├──────────────────────────┤
│ ↕ hem-v-space-3xl │ ← major boundary
├──────────────────────────┤
│ Season Cards │
└──────────────────────────┘
```
---
## Group-Level vs. Individual Spacing
When all items in a grid share the same spacing, define it **on the container**:
```markdown
| Grid gap | h-space-lg / v-space-lg (24px) |
```
Don't create separate spacing objects between card 1 and card 2, card 2 and card 3. The grid gap handles it.
Individual spacing objects are for **between sections** and **non-uniform gaps**.
---
## Internal Spacing
Spacing inside a component (image-to-heading, heading-to-teaser inside a card) is NOT specified upfront. It's added only when the designer explicitly requests it during visual review.
```markdown
<!-- Internal spacing (image->heading, heading->teaser, content padding)
is NOT specified yet. Add here only when the designer requests it. -->
```
This follows the emergent principle: don't design what hasn't been needed yet.
---
## Spacing in the Design System
Spacing objects go to the design system **immediately on first use** — unlike regular objects which extract on second use.
Why? Because spacing is relational. When you decide that a heading needs `space-xl` above a card grid, that's a universal design principle, not a page-specific detail.
The design system organizes patterns by spacing value:
```markdown
### v-space-3xl
| Above | Below | Why |
|-------|-------|-----|
| `trust-section` | `seasons-section` | Major section boundary |
| `seasons-section` | `site-footer` | Major section boundary |
### v-space-zero
| Above | Below | Why |
|-------|-------|-----|
| `site-header` | `service-menu` | One continuous nav unit |
| `service-menu` | `hero` | Flush below navigation |
```
As more pages are designed, each spacing value accumulates more situations. The pattern table grows from real decisions.
---
## How Many Spacing Objects Per Page?
On a typical homepage with 8 sections:
- **6 spacing objects** between sections
- **4 sections** with internal spacing properties (padding, grid gap)
- **10 total** spacing declarations
That's lean. One or two per section boundary. Not dozens.
---
## The Communication Pattern
Always use token names when discussing spacing:
```
BAD: "Add 48 pixels above the footer"
GOOD: "Change hem-v-space-3xl to space-4xl above the footer"
```
This builds a shared vocabulary. Over time, the designer and developer both think in tokens.
---
## What's Next
In the next module, you'll learn how patterns emerge across pages and when to extract them into reusable components.
---
**[Continue to Lesson 5: Typography Tokens →](lesson-05-typography-tokens.md)**
---
[← Back to Lesson 3](lesson-03-element-state-specifications.md) | [Back to Module Overview](module-11-conceptual-specifications-overview.md)
*Part of Module 11: Conceptual Specifications*

View File

@ -0,0 +1,157 @@
# Module 11: Conceptual Specifications
## Lesson 5: Typography Tokens — Size Is Not Structure
**Decoupling visual size from semantic meaning**
---
## The Problem
Most design systems conflate two things:
- **Visual size** — how big text looks
- **Semantic level** — what the text means (H1, H2, H3, p)
This creates rigid rules like "H1 is always 48px" or "H2 is always 32px." But reality doesn't work that way.
A landing page H1 might be a serif display font at 56px italic.
An admin page H1 might be clean sans-serif at 20px medium.
A sidebar H2 might be 14px.
The semantic level is for accessibility and SEO. The visual token is for hierarchy.
---
## The WDS Approach
Two independent systems:
### Heading Scale (Visual Size)
| Token | Size | Weight | Example Use |
|-------|------|--------|-------------|
| `heading-xxs` | 14px | 700 | Smallest sub-headers |
| `heading-xs` | 16px | 700 | Minor headings, labels |
| `heading-sm` | 18px | 700 | Card sub-headings |
| `heading-md` | 20px | 800 | Card headings |
| `heading-lg` | 24px | 800 | Section sub-headers |
| `heading-xl` | 30px | 900 | Section headers |
| `heading-2xl` | 36px | 900 | Major section headers |
| `heading-3xl` | 44px | 900 | Hero headings (tablet) |
| `heading-4xl` | 56px | 900 | Hero headings (desktop) |
### Semantic Level (Document Structure)
`<h1>`, `<h2>`, `<h3>`, `<p>` — these define the document outline for accessibility and SEO.
### How They Combine
```html
<h2 class="text-heading-lg md:text-heading-xl lg:text-heading-2xl">
Our Services
</h2>
```
This `<h2>` is `heading-lg` on mobile, `heading-xl` on tablet, `heading-2xl` on desktop. The semantic level stays H2 on all devices. The visual size adapts.
---
## The Responsive Scaling Rule
Step up one token size per breakpoint:
```
Mobile: heading-lg (24px)
Tablet: heading-xl (30px)
Desktop: heading-2xl (36px)
```
In code:
```html
<h2 class="text-heading-lg md:text-heading-xl lg:text-heading-2xl">
```
In specifications:
```markdown
| Visual size | heading-lg / heading-xl / heading-2xl |
```
Always use token names — never arbitrary pixel values per breakpoint.
---
## Body Type Scale
The same principle applies to body text:
| Token | Size | Weight | Usage |
|-------|------|--------|-------|
| `text-body` | 16px | 400 | Body text |
| `text-body-small` | 14px | 400 | Captions, metadata |
| `text-body-large` | 18px | 400 | Lead paragraphs |
| `text-label` | 14px | 600 | Labels, badges |
| `text-phone` | 24px | 700 | Phone number CTA |
---
## Why Tokens Beat Pixel Values
### 1. Single Point of Change
Bump `heading-xl` from 30px to 32px and every section header on the site adjusts. No hunting through files.
### 2. Shared Vocabulary
"Change the heading from `heading-lg` to `heading-xl`" is precise. "Make it bigger" is not.
### 3. Consistent Hierarchy
Tokens enforce a scale. You can't accidentally use 31px when the scale goes 30, 36, 44.
### 4. Responsive by Default
Each token has responsive variants built in. No reinventing breakpoint behavior per element.
---
## When Tokens Emerge
Don't create the full type scale before building any pages.
Build pages first. Notice that you keep using the same sizes. Extract the scale from real usage.
On the Kalla project, the heading scale emerged after the homepage was built and refined through browser review. The same heading sizes appeared 3+ times in different sections — that's when they became tokens.
---
## Specifying Typography in Page Specs
```markdown
### Section Heading
**OBJECT ID:** `hem-trust-heading`
**DS TYPE:** `section-heading`
| Property | Value |
|----------|-------|
| Tag | h2 |
| Visual size | heading-xl / heading-xl / heading-2xl |
| Font family | font-headline (Inter) |
| Font weight | 900 |
| Color | text-primary (#141414) |
```
Notice: the semantic tag (`h2`) and the visual size (`heading-xl`) are independent. The same component template can be used for an H2 on one page and an H3 on another.
---
## What's Next
You now understand the three invisible specification layers: spacing objects (Lesson 4), typography tokens (this lesson), and the dual-ID system that connects them to the design system (Module 12).
---
[← Back to Lesson 4](lesson-04-spacing-objects.md) | [Back to Module Overview](module-11-conceptual-specifications-overview.md)
*Part of Module 11: Conceptual Specifications*

View File

@ -99,16 +99,40 @@ Specifications use consistent terminology:
## IDs Are the Key
Every object gets a unique ID:
Every object has two IDs:
1. **Instance ID** — unique on the page: `hem-trust-cards:pos-1`
2. **DS Type** — defined in the design system: `article-card`
The Instance ID tells you WHERE this specific object is. The DS Type tells you WHAT kind of object it is.
```markdown
### Trust Card 1
**OBJECT ID:** `hem-trust-cards:pos-1`
**DS TYPE:** `article-card`
```
### Positional IDs for Lists
When a page has multiple instances of the same component, use positional identifiers:
```
Page: P01-signup-page
Section: P01-S01-hero-section
Widget: P01-S02-W01-signup-form
Card: P01-S03-C01-feature-card
Element: P01-S02-W01-E01-email-field
hem-trust-cards:pos-1
hem-trust-cards:pos-2
hem-trust-cards:pos-3
```
Child elements use colon-separated hierarchy:
```
hem-trust-cards:pos-1:image
hem-trust-cards:pos-1:heading
hem-trust-cards:pos-1:teaser
```
Use positional IDs (`pos-1`, `pos-2`) instead of semantic names when content order can change dynamically.
**Why IDs matter:**
1. **Traceability** — From spec → code → test
@ -117,6 +141,7 @@ Element: P01-S02-W01-E01-email-field
4. **Accessibility** — Reference specific elements for ARIA
5. **Analytics** — Track interactions precisely
6. **Testing** — Target elements for automation
7. **Design System** — Link page instances to reusable types
**Without IDs, specifications are just documentation. With IDs, they're implementation maps.**
@ -410,6 +435,12 @@ Deep dive on specifying sections (placement, responsive behavior) and widgets (r
**Lesson 3: Element & State Specifications**
Complete element specifications with all states, exact content, ARIA attributes, edge cases, and translations
**Lesson 4: Spacing as First-Class Objects**
Every gap between sections gets an ID, a type, and a value — the invisible layer that holds everything together
**Lesson 5: Typography Tokens — Size Is Not Structure**
Decouple visual size from semantic meaning. An H2 can be `heading-xl` on the homepage and `heading-sm` in a sidebar.
**Tutorial: Specify Your Pages**
Hands-on practice with Freya creating complete specifications
@ -440,6 +471,12 @@ Deep dive on Layers 2 & 3 of the hierarchy
### [Lesson 3: Element & State Specifications](lesson-03-element-state-specifications.md)
Deep dive on Layers 4 & 5 — Complete implementation details
### [Lesson 4: Spacing as First-Class Objects](lesson-04-spacing-objects.md)
The invisible layer — every gap gets an ID, a type, and a value
### [Lesson 5: Typography Tokens — Size Is Not Structure](lesson-05-typography-tokens.md)
Decouple visual size from semantic meaning
---
## Tutorial

View File

@ -344,7 +344,44 @@ Summary:
---
## Step 8: Review Complete Specification (5 min)
## Step 8: Add Spacing Objects (5 min)
### Freya guides the invisible layer:
> "Now let's specify the spacing between sections. Every gap needs an ID."
**You work through the page sections:**
```markdown
## Spacing Objects
#### ↕ `signup-v-space-zero` — header sits flush against form section
#### ↕ `signup-v-space-xl` — comfortable gap between form and trust section
#### ↕ `signup-v-space-lg` — standard gap between trust section and footer
```
**Freya reminds:**
> "Zero spacing is a design decision too — document it so nobody 'fixes' it later."
### Typography tokens:
> "Let's also specify the heading sizes using tokens, not pixels."
```markdown
### Headline
| Property | Value |
|----------|-------|
| Tag | h1 |
| Visual size | heading-xl / heading-2xl / heading-3xl |
| Font weight | 900 |
```
**Freya explains:**
> "The semantic tag (h1) and the visual size (heading-xl) are independent. The h1 tells screen readers this is the page title. The token controls how big it looks."
---
## Step 9: Review Complete Specification (5 min)
### Freya presents the full document:
@ -370,7 +407,7 @@ If yes, you're done. If not, identify what's missing.
---
## Step 9: Save and Organize (2 min)
## Step 10: Save and Organize (2 min)
### Save the specification:

View File

@ -48,11 +48,27 @@ Shared vocabulary with developers.
## When to Extract
Not everything should be a component. Look for:
Not everything should be a component. And **objects and spacing have different extraction timing:**
### Objects: Extract on Second Use
The first time a button or card appears, it's a one-off — it stays inline in the page spec. The second time the same pattern appears (same states, same behavior), it's a real pattern. Extract it to the design system.
First use = one-off. Second use = pattern. Extract.
### Spacing: Extract Immediately
Spacing extracts on **first use** — no waiting for a second occurrence.
Why? Because spacing is relational. When you decide that a heading needs `space-xl` above a card grid, that's a universal design principle — not a page-specific detail. It applies everywhere that pair of object types appears.
### The Decision Checklist
For objects, look for:
**Appears more than once**
Once is an instance. Twice or more is a pattern worth considering.
Once is an instance. Twice or more is a pattern worth extracting.
**Consistent behavior**