Problem
Audited Maka's frontend against Craft Agents OSS (same stack: Electron + React + Tailwind v4 + shadcn-like). Both projects share --radius: 0rem and 15px base font. The gap is not tech selection; it is governance execution.
Maka already defines many of the right primitives, tokens, and renderer contracts, but the system is still too easy to drift:
- overlapping primitive/component layers still exist in places;
- color tokens have had undefined references and too many ad-hoc derivation styles;
- decorative enter/exit motion still leaks through Base UI primitives;
- radius values were spread across hardcoded CSS, arbitrary Tailwind values, and competing token aliases;
--accent has been overloaded across CTA, control, focus, link, live/status, toast, and navigation roles;- hard
border: declarations are used where shadow-ring recipes should own visual outlines; - Storybook has product regression fixtures, but the CSS/token foundation itself is not yet exposed as a complete governance surface.
This issue tracks the design-system refactor needed to close that governance gap. Each PR below should be independently reviewable and should preserve existing product behavior unless its section explicitly calls out a visual correction.
PR plan
PR1. Dead primitive cleanup
Clean up the remaining shadcn leftovers and zero-usage primitives so future governance applies to one real component layer, not dead branches.
Keep: Maka-specific primitives
chat.tsx, alert.tsx, item.tsx, menu.tsx, empty.tsx, accordion.tsx, choice-card.tsx, settings-segmented.tsx, settings-select.tsx, settings-switch.tsx, input-group.tsx, badge.tsx, tabs.tsx, spinner.tsx, kbd.tsx, toolbar.tsx
Delete or migrate: overlapping shadcn leftovers
| File | Overlaps | Action |
|---|
button.tsx | ui.tsx Button | migrate the remaining consumer to ui.tsx Button, then delete |
input.tsx | ui.tsx Input | delete if still unused |
separator.tsx | ui.tsx Separator | delete if still unused |
sheet.tsx | ui.tsx Sheet* | delete if still unused |
skeleton.tsx | ui.tsx Skeleton | delete if still unused |
textarea.tsx | ui.tsx Textarea | delete if still unused |
tooltip.tsx | ui.tsx TooltipTrigger/Popup | delete if still unused |
Delete: zero-usage primitives
frame.tsx, pagination.tsx, table.tsx, command.tsx, drawer.tsx, preview-card.tsx, sidebar.tsx, group.tsx, plus their barrel exports if still present.
Also remove: dead .maka-button[data-variant="primary"] CSS if it still has no production usage.
Acceptance: production imports resolve through ui.tsx or kept Maka-specific primitives; dead primitive exports are gone; relevant dead-export/primitive contracts pass.
PR2. Color token closure
Close the color token system so every referenced token exists and each derivation style has a clear purpose.
Scope:
- Map every undefined foreground/accent token reference to an existing tier or explicit alpha use.
- Keep foreground tiers intentionally small and documented; do not let every one-off opacity become a named tier.
- Ensure Tailwind
@theme inline exposes the supported renderer tokens. - Keep Storybook
Design System/Tokens useful as a quick visual audit of the supported color roles.
Acceptance: no undefined var(--foreground-*) or var(--accent-*) references remain; contracts catch future undefined token references; Storybook shows the supported semantic color roles and representative foreground tiers.
PR3. Motion governance
Remove decorative mount/unmount motion from primitives and keep only functional motion.
Goal: popovers, dialogs, sheets, menus, and tooltips should appear/disappear without Base UI enter/exit animation. Keep spinner, status pulse, streaming caret, shimmer, and other functional progress/status motion.
Scope:
- Strip
data-starting-style, data-ending-style, @starting-style, and decorative near-duplicate keyframes from non-whitelisted primitives/CSS. - Keep motion tokens (
--duration-*, --ease-*) for feedback/status motion. - Extend the Storybook Animation Catalog so retained motion is visible and named.
Acceptance: contract bans unapproved enter/exit animation patterns; retained functional motion is visible in Storybook; no product flow relies on decorative mount/unmount animation.
PR4. Radius governance
Converge radius to one component-type scale and remove hardcoded pixel drift.
Target scale:
| Component type | Token | Value |
|---|
| button / input / compact chip | --radius-control | 6px |
| card / popover / code block | --radius-surface | 8px |
| modal / composer-scale surface | --radius-modal | 12px |
| badge / pill / dot | --radius-pill | 999px |
| flat panel / full-bleed surface | none / 0 | 0 |
Scope:
- Remove competing radius token aliases where possible.
- Replace hardcoded CSS
border-radius: Npx and TSX arbitrary rounded-[Npx] values with the canonical tokens. - Classify intermediate historical values by component type, not nearest numeric value.
Acceptance: radius contract rejects new bare pixel radius values except intentional exemptions; Storybook Design System/Tokens/Radius reflects the canonical scale; current focused PR: #418.
PR5. Primary/accent semantic split
Split --accent into semantic roles so one green no longer controls unrelated UI meanings.
Rejected direction: flipping --color-primary to var(--foreground) just copies Craft's black/white button look and only fixes one contrast case. It leaves checkbox/switch/radio/progress and other selected states tied to the same low-contrast green.
Target roles:
--action / --action-foreground: solid CTA fills such as primary button, submit, send, apply, done.--control / --control-foreground: selected/on/progress states such as checkbox, radio, switch, progress, tabs underline.- Thin emphasis aliases:
--link, --focus-ring, --status-running, --nav-active, --toast-accent.
Scope:
- Call sites stop writing raw
var(--accent) when the intent is action/control/link/focus/status/nav/toast. - Darken
action and control fills enough for white text to clear the contrast target in light and dark modes. - Keep initial aliases visually close unless a contrast fix is explicitly required.
Acceptance: computed contrast contract protects action/control foreground pairs; semantic-token contract catches raw accent usage in governed contexts; Storybook shows the semantic roles separately even when several currently alias the same value.
PR6. Borders as shadows
Move visual-only hard borders to shadow-ring recipes while preserving layout borders.
Problem: hard border: occupies layout space. Replacing every border blindly can shift geometry by 2px and break tight layouts.
Strategy:
- Migrate visual-only outlines first: cards, popovers, tool cards, toast-like surfaces, code/table wrappers where layout does not depend on border width.
- Keep layout borders where the border is structural: sidebar divider, titlebar divider, modal header/footer dividers, list separators, table rules where spacing depends on the line.
- Use the existing shadow recipes:
--shadow-minimal, --shadow-minimal-flat, --shadow-medium, --shadow-modal.
Acceptance: governed surfaces use shadow-ring recipes; geometry-sensitive layout borders are explicitly retained; contract protects the distinction and catches accidental broad border reintroduction.
PR7. Storybook foundation governance acceptance
Make the design-system foundation visible, reviewable, and lockable in Storybook. This is the acceptance pass for #406, not a new low-level gap.
Scope:
- Add or extend
Design System/* stories for foundation governance, not more Product pages:
- semantic color roles;
- full theme/palette matrix;
- typography / Markdown / code;
- spacing / density / layout;
- elevation / borders / shadow rings;
- motion tokens and retained functional motion;
- layering / z-index / overlay stack;
- interaction states.
- Show primitive token consumers only where they prove foundation rules: buttons/actions, form controls, surfaces/overlays, navigation/feedback/data primitives.
- Use the real renderer Storybook substrate: renderer CSS, light/dark globals, and every palette id from
THEME_PALETTES. - Add a focused Storybook governance contract that locks required story exports, palette toolbar completeness, and token-reference usage. Prefer structure/token assertions over fragile pixel assertions.
- Keep existing Product stories as regression fixtures; do not expand them as part of this governance pass.
Non-goals: no token value changes, no primitive behavior changes, no Storybook addon/docs-site work, no token JSON/style-dictionary export, and no Product surface expansion.
Acceptance: Storybook becomes the visible review surface for PR2-PR6 foundation rules; npm run -w @maka/desktop build-storybook passes; Storybook contracts lock the foundation story structure and palette coverage.
Dependency order
PR1 + PR2 can land early as cleanup/token closure
↓
PR3 motion governance and PR4 radius governance can proceed after dead primitive cleanup
↓
PR5 semantic action/control split depends on color token closure
PR6 borders-as-shadows depends on radius/shadow-ring clarity
↓
PR7 Storybook foundation governance is the final acceptance pass, but pieces may be built earlier when their tokens are ready
Global acceptance
#406 can close when:
- dead/overlapping primitives are removed or migrated;
- color tokens are closed and undefined-token references are contract-protected;
- decorative enter/exit motion is removed from governed primitives;
- radius values converge to the canonical scale;
- action/control/emphasis color semantics are split and contrast-protected;
- visual-only borders use shadow-ring recipes while layout borders remain intentional;
- Storybook exposes the governed CSS/token foundation clearly enough for review without driving the desktop app into product states;
- the relevant desktop/UI contract tests, typecheck, and focused Storybook build pass.
References
Problem
Audited Maka's frontend against Craft Agents OSS (same stack: Electron + React + Tailwind v4 + shadcn-like). Both projects share
--radius: 0remand 15px base font. The gap is not tech selection; it is governance execution.Maka already defines many of the right primitives, tokens, and renderer contracts, but the system is still too easy to drift:
--accenthas been overloaded across CTA, control, focus, link, live/status, toast, and navigation roles;border:declarations are used where shadow-ring recipes should own visual outlines;This issue tracks the design-system refactor needed to close that governance gap. Each PR below should be independently reviewable and should preserve existing product behavior unless its section explicitly calls out a visual correction.
PR plan
PR1. Dead primitive cleanup
Clean up the remaining shadcn leftovers and zero-usage primitives so future governance applies to one real component layer, not dead branches.
Keep: Maka-specific primitives
chat.tsx,alert.tsx,item.tsx,menu.tsx,empty.tsx,accordion.tsx,choice-card.tsx,settings-segmented.tsx,settings-select.tsx,settings-switch.tsx,input-group.tsx,badge.tsx,tabs.tsx,spinner.tsx,kbd.tsx,toolbar.tsxDelete or migrate: overlapping shadcn leftovers
button.tsxui.tsxButtonui.tsxButton, then deleteinput.tsxui.tsxInputseparator.tsxui.tsxSeparatorsheet.tsxui.tsxSheet*skeleton.tsxui.tsxSkeletontextarea.tsxui.tsxTextareatooltip.tsxui.tsxTooltipTrigger/PopupDelete: zero-usage primitives
frame.tsx,pagination.tsx,table.tsx,command.tsx,drawer.tsx,preview-card.tsx,sidebar.tsx,group.tsx, plus their barrel exports if still present.Also remove: dead
.maka-button[data-variant="primary"]CSS if it still has no production usage.Acceptance: production imports resolve through
ui.tsxor kept Maka-specific primitives; dead primitive exports are gone; relevant dead-export/primitive contracts pass.PR2. Color token closure
Close the color token system so every referenced token exists and each derivation style has a clear purpose.
Scope:
@theme inlineexposes the supported renderer tokens.Design System/Tokensuseful as a quick visual audit of the supported color roles.Acceptance: no undefined
var(--foreground-*)orvar(--accent-*)references remain; contracts catch future undefined token references; Storybook shows the supported semantic color roles and representative foreground tiers.PR3. Motion governance
Remove decorative mount/unmount motion from primitives and keep only functional motion.
Goal: popovers, dialogs, sheets, menus, and tooltips should appear/disappear without Base UI enter/exit animation. Keep spinner, status pulse, streaming caret, shimmer, and other functional progress/status motion.
Scope:
data-starting-style,data-ending-style,@starting-style, and decorative near-duplicate keyframes from non-whitelisted primitives/CSS.--duration-*,--ease-*) for feedback/status motion.Acceptance: contract bans unapproved enter/exit animation patterns; retained functional motion is visible in Storybook; no product flow relies on decorative mount/unmount animation.
PR4. Radius governance
Converge radius to one component-type scale and remove hardcoded pixel drift.
Target scale:
--radius-control6px--radius-surface8px--radius-modal12px--radius-pill999px00Scope:
border-radius: Npxand TSX arbitraryrounded-[Npx]values with the canonical tokens.Acceptance: radius contract rejects new bare pixel radius values except intentional exemptions; Storybook
Design System/Tokens/Radiusreflects the canonical scale; current focused PR: #418.PR5. Primary/accent semantic split
Split
--accentinto semantic roles so one green no longer controls unrelated UI meanings.Rejected direction: flipping
--color-primarytovar(--foreground)just copies Craft's black/white button look and only fixes one contrast case. It leaves checkbox/switch/radio/progress and other selected states tied to the same low-contrast green.Target roles:
--action/--action-foreground: solid CTA fills such as primary button, submit, send, apply, done.--control/--control-foreground: selected/on/progress states such as checkbox, radio, switch, progress, tabs underline.--link,--focus-ring,--status-running,--nav-active,--toast-accent.Scope:
var(--accent)when the intent is action/control/link/focus/status/nav/toast.actionandcontrolfills enough for white text to clear the contrast target in light and dark modes.Acceptance: computed contrast contract protects action/control foreground pairs; semantic-token contract catches raw accent usage in governed contexts; Storybook shows the semantic roles separately even when several currently alias the same value.
PR6. Borders as shadows
Move visual-only hard borders to shadow-ring recipes while preserving layout borders.
Problem: hard
border:occupies layout space. Replacing every border blindly can shift geometry by 2px and break tight layouts.Strategy:
--shadow-minimal,--shadow-minimal-flat,--shadow-medium,--shadow-modal.Acceptance: governed surfaces use shadow-ring recipes; geometry-sensitive layout borders are explicitly retained; contract protects the distinction and catches accidental broad border reintroduction.
PR7. Storybook foundation governance acceptance
Make the design-system foundation visible, reviewable, and lockable in Storybook. This is the acceptance pass for #406, not a new low-level gap.
Scope:
Design System/*stories for foundation governance, not more Product pages:THEME_PALETTES.Non-goals: no token value changes, no primitive behavior changes, no Storybook addon/docs-site work, no token JSON/style-dictionary export, and no Product surface expansion.
Acceptance: Storybook becomes the visible review surface for PR2-PR6 foundation rules;
npm run -w @maka/desktop build-storybookpasses; Storybook contracts lock the foundation story structure and palette coverage.Dependency order
Global acceptance
#406 can close when:
References
42e7cd44(deleted 27 dead shadcn primitives),193d7d66(deleted 26 dead ui.tsx exports), feat(ui): govern chat conversation-flow display onto @maka/ui Base UI primitives #332/feat(ui): govern chat bubble/row shell onto @maka/ui chat primitives #334/feat(ui): migrate chat turn markers onto @maka/ui Marker primitive (#332) #337 series (built Maka-specific primitives)