# Portfolio Foundation Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Bootstrap the allmywork SvelteKit portfolio with a CLAUDE.md, a brutalist design system extracted from the Figma AI prototype, shared/ui components converted from React to Svelte 5, and Storybook stories for each component.
**Architecture:** Tailwind CSS v4 custom properties carry the design tokens (colors, typography, spacing, shadows). All UI primitives live in `src/shared/ui/`, each as a PascalCase folder with `ComponentName.svelte`, `types.ts`, `index.ts`, and `ComponentName.stories.svelte`. The FSD directory structure is already in place; this plan fills in the foundation layer only.
**Tech Stack:** SvelteKit 2 + Svelte 5 (runes), Tailwind CSS v4, Biome (lint/format), Vitest (unit tests), Storybook 10 with `@storybook/addon-svelte-csf`, Bun as package manager and runtime.
---
## Task 0: Write CLAUDE.md for the project
**Files:**
- Modify: `/home/ilia/Documents/Projects/allmywork/CLAUDE.md`
The existing CLAUDE.md covers project purpose and tooling. We need to add the code-style section that mirrors glyphdiff's conventions.
**Step 1: Read the existing CLAUDE.md**
Read `/home/ilia/Documents/Projects/allmywork/CLAUDE.md` in full.
**Step 2: Append the Code Style section**
Add the following section to the end of the existing CLAUDE.md (before any trailing lines):
```markdown
---
## Code Style
### Formatting (Biome)
- Indent: tabs
- Quote style: double quotes for JS/TS, double quotes for Svelte attributes
- Line width: 120 characters
- Semicolons: always
- Trailing commas: all
### TypeScript
- Strict mode: on
- Prefer `interface` over `type` for object shapes
- Always type component props via an `interface Props { ... }` block
- Use `$props()` rune — never `export let`
- Use `$derived()` and `$effect()` — never Svelte 4 `$:` syntax
- Use `$state()` for all reactive primitives
### Component Conventions
- File name: PascalCase (`Button.svelte`, `ProjectCard.svelte`)
- Store files: camelCase with `.svelte.ts` suffix (`sidebarStore.svelte.ts`)
- Story files: `.stories.svelte` suffix (Storybook CSF with Svelte addon)
- Test files: `.test.ts` for unit, `.svelte.test.ts` for component tests
- Each slice exports a public API via `index.ts`
### Svelte 5 Patterns
```svelte
```
### Comments
- Multiline JSDoc (`/** ... */`) for exported functions and component description headers
- Single-line (`//`) for inline logic remarks
- Principle: "less is more" — explain the *why*, not the *what*
### Import Order (Biome organizeImports)
1. Svelte/SvelteKit built-ins (`svelte`, `$app/...`)
2. FSD layer aliases (`$shared/...`, `$entities/...`, etc.)
3. Relative imports (`./`, `../`)
### Commit Messages
Format: `prefix(scope): short description`
Prefixes: `feat`, `fix`, `chore`, `refactor`, `docs`, `style`, `test`, `perf`, `ci`, `build`, `revert`
Example: `feat(shared/ui): add Button component with brutalist variants`
```
**Step 3: Verify the file looks correct**
Read the first and last 20 lines of the updated CLAUDE.md to confirm the edit landed cleanly.
**Step 4: Commit**
```bash
cd /home/ilia/Documents/Projects/allmywork
git add CLAUDE.md
git commit -m "docs(CLAUDE.md): add code style section aligned with glyphdiff conventions"
```
---
## Task 1: Install Storybook and required dev dependencies
The project currently has no Storybook. This task wires it up before any stories are written.
**Files:**
- Modify: `/home/ilia/Documents/Projects/allmywork/package.json` (via bun add)
- Create: `/home/ilia/Documents/Projects/allmywork/.storybook/main.ts`
- Create: `/home/ilia/Documents/Projects/allmywork/.storybook/preview.ts`
**Step 1: Install Storybook and addons**
```bash
cd /home/ilia/Documents/Projects/allmywork
bunx storybook@latest init --skip-install
```
Expected output: Storybook scaffolds `.storybook/` and adds scripts to package.json. Answer "yes" to any prompts.
**Step 2: Verify generated .storybook/main.ts**
Read `/home/ilia/Documents/Projects/allmywork/.storybook/main.ts`.
It should reference `@storybook/svelte-vite` as the framework.
If the `init` command did not produce a valid Svelte-Vite config, write `.storybook/main.ts` manually:
```typescript
import type { StorybookConfig } from '@storybook/svelte-vite';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.svelte'],
addons: [
'@storybook/addon-svelte-csf',
'@storybook/addon-a11y',
'@storybook/addon-docs',
],
framework: {
name: '@storybook/svelte-vite',
options: {},
},
};
export default config;
```
**Step 3: Install missing addons if needed**
```bash
cd /home/ilia/Documents/Projects/allmywork
bun add -D @storybook/addon-svelte-csf @storybook/addon-a11y @storybook/addon-docs
```
**Step 4: Add Storybook scripts to package.json (if not already present)**
Open `/home/ilia/Documents/Projects/allmywork/package.json` and confirm the `scripts` section contains:
```json
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
```
If missing, add them.
**Step 5: Run Storybook to confirm it starts**
```bash
cd /home/ilia/Documents/Projects/allmywork
bun run storybook &
```
Expected: Storybook starts on http://localhost:6006 with no fatal errors.
Kill it after confirming: `kill %1` or `Ctrl+C`.
**Step 6: Commit**
```bash
cd /home/ilia/Documents/Projects/allmywork
git add .storybook package.json
git commit -m "chore(storybook): install and configure Storybook 10 with svelte-vite"
```
---
## Task 2: Set up the design system — CSS custom properties and Tailwind v4 tokens
Extract the design tokens from the Figma prototype's `theme.css` into the project's `app.css` and register them as Tailwind v4 theme values.
**Files:**
- Modify: `/home/ilia/Documents/Projects/allmywork/src/app/styles/app.css`
**Reference:** `/home/ilia/Downloads/High-End Portfolio Design System(1)/src/styles/theme.css` and `fonts.css`
**Step 1: Open app.css and replace its contents**
The file currently only contains `@import "tailwindcss";`. Replace it with the following:
```css
@import "tailwindcss";
/* ============================================================
FONTS
============================================================ */
@import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght,SOFT,WONK@0,9..144,100..900,0..100,0..1;1,9..144,100..900,0..100,0..1&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,100..900;1,100..900&display=swap');
/* ============================================================
DESIGN TOKENS
============================================================ */
:root {
/* Typography scale — Augmented Fourth (×1.414) */
--font-size-base: 16px;
--text-xs: 0.707rem; /* 11.31px */
--text-sm: 0.840rem; /* 13.44px */
--text-base: 1rem; /* 16px */
--text-lg: 1.414rem; /* 22.62px */
--text-xl: 2rem; /* 32px */
--text-2xl: 2.828rem; /* 45.25px */
--text-3xl: 4rem; /* 64px */
--text-4xl: 5.657rem; /* 90.51px */
--text-5xl: 8rem; /* 128px */
/* Font families */
--font-heading: 'Fraunces', serif;
--font-body: 'Public Sans', sans-serif;
/* Font weights */
--font-weight-heading: 900;
--font-weight-body: 600;
--font-weight-normal: 400;
/* Line heights */
--line-height-tight: 1.2;
--line-height-normal: 1.5;
/* Fraunces variable font axes */
--fraunces-wonk: 1;
--fraunces-soft: 0;
/* Palette — Sanzo Wada inspired */
--ochre-clay: #D9B48F;
--slate-indigo: #3B4A59;
--burnt-oxide: #A64B35;
--carbon-black: #121212;
/* Semantic color aliases */
--background: var(--ochre-clay);
--foreground: var(--carbon-black);
--card: var(--ochre-clay);
--card-foreground: var(--carbon-black);
--primary: var(--burnt-oxide);
--primary-foreground: var(--ochre-clay);
--secondary: var(--slate-indigo);
--secondary-foreground: var(--ochre-clay);
--muted: var(--slate-indigo);
--muted-foreground: var(--ochre-clay);
--accent: var(--burnt-oxide);
--accent-foreground: var(--ochre-clay);
--destructive: #d4183d;
--destructive-foreground:#ffffff;
--border: var(--carbon-black);
--ring: var(--carbon-black);
/* Spacing — 8pt linear scale */
--space-1: 0.5rem; /* 8px */
--space-2: 1rem; /* 16px */
--space-3: 1.5rem; /* 24px */
--space-4: 2rem; /* 32px */
--space-5: 2.5rem; /* 40px */
--space-6: 3rem; /* 48px */
--space-8: 4rem; /* 64px */
--space-10: 5rem; /* 80px */
--space-12: 6rem; /* 96px */
--space-16: 8rem; /* 128px */
--space-20: 10rem; /* 160px */
/* Borders */
--border-width: 3px;
--radius: 0px;
/* Brutalist hard shadows */
--shadow-brutal-sm: 4px 4px 0 var(--carbon-black);
--shadow-brutal: 8px 8px 0 var(--carbon-black);
--shadow-brutal-lg: 12px 12px 0 var(--carbon-black);
}
/* ============================================================
TAILWIND v4 THEME REGISTRATION
============================================================ */
@theme inline {
/* Colors */
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-border: var(--border);
--color-ring: var(--ring);
/* Palette direct access */
--color-ochre-clay: var(--ochre-clay);
--color-slate-indigo: var(--slate-indigo);
--color-burnt-oxide: var(--burnt-oxide);
--color-carbon-black: var(--carbon-black);
/* Border radius (zero for brutalist aesthetic) */
--radius-sm: var(--radius);
--radius-md: var(--radius);
--radius-lg: var(--radius);
/* Box shadows */
--shadow-brutal-sm: var(--shadow-brutal-sm);
--shadow-brutal: var(--shadow-brutal);
--shadow-brutal-lg: var(--shadow-brutal-lg);
/* Font families */
--font-heading: var(--font-heading);
--font-body: var(--font-body);
}
/* ============================================================
BASE LAYER — GLOBAL ELEMENT DEFAULTS
============================================================ */
@layer base {
html {
font-size: var(--font-size-base);
}
body {
background-color: var(--background);
color: var(--foreground);
font-family: var(--font-body);
font-weight: var(--font-weight-body);
line-height: var(--line-height-tight);
overflow-x: hidden;
position: relative;
}
/* Paper grain texture overlay */
body::before {
content: '';
position: fixed;
inset: 0;
background-image:
repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,0,0,.02) 2px, rgba(0,0,0,.02) 4px),
repeating-linear-gradient(90deg, transparent, transparent 2px, rgba(0,0,0,.02) 2px, rgba(0,0,0,.02) 4px);
opacity: .4;
pointer-events: none;
z-index: 1;
}
/* Ensure page content renders above texture */
body > * {
position: relative;
z-index: 2;
}
h1, .h1 { font-size: var(--text-4xl); }
h2, .h2 { font-size: var(--text-3xl); }
h3, .h3 { font-size: var(--text-2xl); }
h4, .h4 { font-size: var(--text-xl); }
h5, .h5 { font-size: var(--text-lg); }
h1, h2, h3, h4, h5,
.h1, .h2, .h3, .h4, .h5 {
font-family: var(--font-heading);
font-weight: var(--font-weight-heading);
line-height: var(--line-height-tight);
font-variation-settings: 'WONK' var(--fraunces-wonk), 'SOFT' var(--fraunces-soft);
color: var(--carbon-black);
margin: 0;
}
p {
font-family: var(--font-body);
font-size: var(--text-base);
font-weight: var(--font-weight-body);
line-height: var(--line-height-tight);
color: var(--carbon-black);
margin: 0;
}
label {
font-family: var(--font-body);
font-size: var(--text-sm);
font-weight: var(--font-weight-body);
text-transform: uppercase;
letter-spacing: .05em;
line-height: var(--line-height-tight);
}
button {
font-family: var(--font-body);
font-size: var(--text-base);
font-weight: var(--font-weight-body);
line-height: var(--line-height-tight);
cursor: pointer;
}
input, textarea, select {
font-family: var(--font-body);
font-size: var(--text-base);
font-weight: var(--font-weight-body);
line-height: var(--line-height-tight);
}
blockquote {
font-family: var(--font-heading);
font-size: var(--text-xl);
font-weight: var(--font-weight-heading);
font-variation-settings: 'WONK' var(--fraunces-wonk), 'SOFT' var(--fraunces-soft);
line-height: var(--line-height-tight);
border-left: var(--border-width) solid var(--carbon-black);
padding-left: var(--space-4);
margin: var(--space-6) 0;
}
a {
color: var(--burnt-oxide);
text-decoration: none;
border-bottom: 2px solid var(--carbon-black);
transition: border-bottom-width .15s ease;
}
a:hover {
border-bottom-width: 4px;
}
}
/* ============================================================
BRUTALIST UTILITY CLASSES
============================================================ */
.brutal-border { border: var(--border-width) solid var(--carbon-black); }
.brutal-border-top { border-top: var(--border-width) solid var(--carbon-black); }
.brutal-border-bottom { border-bottom: var(--border-width) solid var(--carbon-black); }
.brutal-border-left { border-left: var(--border-width) solid var(--carbon-black); }
.brutal-border-right { border-right: var(--border-width) solid var(--carbon-black); }
.brutal-shadow { box-shadow: var(--shadow-brutal); }
.brutal-shadow-sm { box-shadow: var(--shadow-brutal-sm); }
.brutal-shadow-lg { box-shadow: var(--shadow-brutal-lg); }
/* ============================================================
GRID UTILITIES
============================================================ */
.grid-muller {
display: grid;
gap: var(--space-3);
grid-template-columns: repeat(4, 1fr);
}
@media (min-width: 1024px) {
.grid-muller {
grid-template-columns: repeat(12, 1fr);
}
}
/* ============================================================
ANIMATION
============================================================ */
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.animate-fade-in-up {
animation: fadeInUp .5s cubic-bezier(.4, 0, .2, 1);
}
```
**Step 2: Verify dev server still compiles**
```bash
cd /home/ilia/Documents/Projects/allmywork
bun run dev &
```
Expected: No CSS errors in the terminal. Visit http://localhost:5173 — the page background should be ochre-clay (#D9B48F).
Kill dev server: `kill %1`
**Step 3: Commit**
```bash
cd /home/ilia/Documents/Projects/allmywork
git add src/app/styles/app.css
git commit -m "feat(design-system): add brutalist design tokens and Tailwind v4 theme from Figma prototype"
```
---
## Task 3: Add the `cn` utility to shared/lib
Many components will use `cn` (clsx + tailwind-merge) to compose class names. This task adds the helper before any component uses it.
**Files:**
- Create: `/home/ilia/Documents/Projects/allmywork/src/shared/lib/cn.ts`
- Modify: `/home/ilia/Documents/Projects/allmywork/src/shared/lib/index.ts`
**Step 1: Install clsx and tailwind-merge**
```bash
cd /home/ilia/Documents/Projects/allmywork
bun add clsx tailwind-merge
```
Expected: Both packages appear in `package.json` under `dependencies`.
**Step 2: Write failing test**
Create `/home/ilia/Documents/Projects/allmywork/src/shared/lib/cn.test.ts`:
```typescript
import { describe, expect, it } from 'vitest';
import { cn } from './cn';
describe('cn', () => {
it('merges class strings', () => {
expect(cn('foo', 'bar')).toBe('foo bar');
});
it('deduplicates conflicting Tailwind classes (last wins)', () => {
expect(cn('p-4', 'p-8')).toBe('p-8');
});
it('ignores falsy values', () => {
expect(cn('foo', false, undefined, null, 'bar')).toBe('foo bar');
});
});
```
**Step 3: Run test to confirm it fails**
```bash
cd /home/ilia/Documents/Projects/allmywork
bun run test src/shared/lib/cn.test.ts
```
Expected: FAIL — `Cannot find module './cn'`
**Step 4: Implement cn.ts**
```typescript
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
/** Merge Tailwind classes without conflicts. Later classes win on collision. */
export function cn(...inputs: ClassValue[]): string {
return twMerge(clsx(inputs));
}
```
**Step 5: Run test to confirm it passes**
```bash
cd /home/ilia/Documents/Projects/allmywork
bun run test src/shared/lib/cn.test.ts
```
Expected: PASS (3 tests)
**Step 6: Export from shared/lib/index.ts**
Open `/home/ilia/Documents/Projects/allmywork/src/shared/lib/index.ts` and add:
```typescript
export { cn } from './cn';
```
**Step 7: Commit**
```bash
cd /home/ilia/Documents/Projects/allmywork
git add src/shared/lib/cn.ts src/shared/lib/cn.test.ts src/shared/lib/index.ts package.json
git commit -m "feat(shared/lib): add cn utility (clsx + tailwind-merge)"
```
---
## Task 4: Implement `Badge` component
**Files:**
- Modify: `/home/ilia/Documents/Projects/allmywork/src/shared/ui/` — replace flat files with folder-per-component layout
- Create: `/home/ilia/Documents/Projects/allmywork/src/shared/ui/Badge/types.ts`
- Create: `/home/ilia/Documents/Projects/allmywork/src/shared/ui/Badge/Badge.svelte`
- Create: `/home/ilia/Documents/Projects/allmywork/src/shared/ui/Badge/index.ts`
- Create: `/home/ilia/Documents/Projects/allmywork/src/shared/ui/Badge/Badge.stories.svelte`
**Reference prototype:** `/home/ilia/Downloads/High-End Portfolio Design System(1)/src/app/components/Badge.tsx`
**Step 1: Create types.ts**
```typescript
export type BadgeVariant = 'default' | 'primary' | 'secondary' | 'outline';
```
**Step 2: Write failing component test**
Create `/home/ilia/Documents/Projects/allmywork/src/shared/ui/Badge/Badge.test.ts`:
```typescript
import { render } from '@testing-library/svelte';
import { describe, expect, it } from 'vitest';
import Badge from './Badge.svelte';
describe('Badge', () => {
it('renders children text', () => {
const { getByText } = render(Badge, { props: { children: () => 'hello' } });
expect(getByText('hello')).toBeTruthy();
});
it('applies default variant class', () => {
const { container } = render(Badge, { props: { variant: 'default' } });
expect(container.querySelector('span')?.className).toContain('bg-carbon-black');
});
});
```
**Step 3: Run test to confirm failure**
```bash
cd /home/ilia/Documents/Projects/allmywork
bun run test src/shared/ui/Badge/Badge.test.ts
```
Expected: FAIL — component file not found.
**Step 4: Implement Badge.svelte**
```svelte
{#if children}
{@render children()}
{/if}
```
**Step 5: Create index.ts**
```typescript
export { default as Badge } from './Badge.svelte';
export type { BadgeVariant } from './types';
```
**Step 6: Run test to confirm it passes**
```bash
cd /home/ilia/Documents/Projects/allmywork
bun run test src/shared/ui/Badge/Badge.test.ts
```
Expected: PASS
**Step 7: Write Badge.stories.svelte**
```svelte
Section content
Section content on slate
Section with brutal top and bottom borders
Portfolio Foundation — Design System Active
Stack
SvelteKit + Bun
Styling
Tailwind CSS v4
Components
Shared UI ready