Amends 0127 (a
design-system category;
ui leaves the experience row and brand leaves the cross-cutting row),
0165 (where @stackra/ui
lives and how its entries are split), 0024 (where the
brand NOTICE and the font licences sit), 0084 (the
theming and brand rows) and 0291
(decisions 8 and 9: where the Stackra kit and the token engine go). Each amended page carries a
note.Context
The design tokens live in@stackra/brand (packages/experience/brand), together with Stackra’s own logos, marks, illustrations,
favicons, app icons and email templates. 0127 moves that package to
cross-cutting and keeps ui in experience, beside the packages that consume it. That mixes three things: a framework token
schema that any product themes, the Stackra marks that are all rights reserved (0024
decision 2), and the component layer that 0165 defines as one
contract with an implementation per runtime. A framework user cannot bring their own brand without inheriting ours. Components
also need one place where each one is reviewed with real props, in both colour schemes and both text directions, while Storybook is
rejected (0128, 0227).
The owner decided the split on 2026-10-23 in the lead session, recorded in STA-350.
Decision
- A
design-systempackage category.packages/design-system/holds flat packages, as every category does:tokens(@stackra/tokens),ui(@stackra/ui) and latericons(@stackra/icons). Together they are the Stackra Design System. This amends the category table of 0127 as 0282 did:experiencekeeps experience, navigation, console, panel, builder and collaboration (and the other packages its amendment table lists), and losesui;cross-cuttingno longer holdsbrand. @stackra/tokensis the token schema and the default theme.- The schema covers colour roles for light and dark, typography, spacing, radius, shadow, motion and fonts.
- The default theme is named
stackra. - A theme renders to CSS variables for the web (HeroUI v3) and to the Uniwind theme for native (HeroUI Native).
- The generated CSS is committed, and a test checks that it equals the generator’s output.
- A framework user brings their own brand as a theme, through
defineTheme.
@stackra/uiis one API, under 0165.- The shared props, variants and types live in
src/contracts. ./reactimplements each component on HeroUI v3 for the web;./nativeimplements it on HeroUI Native with Uniwind.- The contract is shared and the component code is not. The not-built-yet row “a shared React component library across web and native” stays Deferred (0227).
- The HeroUI form adapters live here (decision 2 of 0165).
- Free packages never depend on HeroUI Pro (decision 5 of 0165).
- The shared props, variants and types live in
@stackra/brandis retired.packages/experience/brandis removed.- Its colour, type and motion tokens become the
stackratheme in@stackra/tokens. - The theme’s fonts (Geist, Geist Mono and IBM Plex Sans Arabic, under the SIL Open Font License) move with it, with their OFL texts beside the files (0024 decision 3).
- Stackra’s logos, marks, illustrations, patterns, icons, favicons and email templates move to our own docs and apps:
apps/docs/src/assets/brand/, with its all-rights-reservedNOTICE(0024 decision 2). App icons move toapps/mobile.
- Its colour, type and motion tokens become the
apps/playgroundis the component review surface.@figentra/playground,tier:app, is a Vite and React Router app on HeroUI v3.- It has one route folder per component. Each renders every real component with real props and states, in light and dark and in left-to-right and right-to-left.
- Playwright with axe runs against it, in the app’s end-to-end tier (0182,
0183 TS16). The packages come from a new
e2ecatalog, approved by the owner:@playwright/testand@axe-core/playwright. - It is not Storybook, which stays rejected (0128,
0227). There are no
*.stories.*files, no story format, no addon ecosystem and no separate component catalogue build. Its pages are ordinary app routes that import the real public entries of@stackra/ui, and the end-to-end and axe tier is the gate.
Consequences
- A framework user themes Stackra by writing a theme, and ships none of our marks. Our marks stay all rights reserved, in our own apps and docs, not in a published MIT package.
- Every component exists once as a contract and twice as an implementation. A component that one runtime lacks is built there, as 0112 X9 already requires.
tools/scripts/structure.mjs(CATEGORIES), the scaffold,AGENTS.md,.agents/rules/workspace-layout.md, the packages guide and the roadmap list thedesign-systemcategory, dropuifrom experience and dropbrandfrom cross-cutting. Every member that imports@stackra/brandmoves to@stackra/tokens, or to the assets in its own app.- A component change is reviewed in the playground, in four views (two schemes, two directions). The playground is one more app to keep building, and its axe run is one more gate.
pnpm-workspace.yamlgains ane2ecatalog. The owner approved it; the edit is the owner’s file (concurrent sessions).- The Figentra runtime
BrandServicethat 0084 planned to merge into the brand package is not placed by this ADR. Its home is decided when it is ported.
Enforcement
tools/scripts/structure.mjsCATEGORIESlistsdesign-system, andtools/scripts/scaffold.mjsacceptspnpm new package <name> --category design-systemthroughCATEGORY_NAMES.FORBIDDEN_FILESintools/scripts/structure.mjsrefuses*.stories.*anywhere, the playground included, throughcheckTestPlacementintools/scripts/validate-repository.mjs.- planned —
tools/scripts/validate-repository.mjsrejects apackages/<category>folder that is not inCATEGORIES(0127 Enforcement). Nothing checks package categories in the validator today. - planned — the test in
@stackra/tokensthat the committed CSS and Uniwind theme equal the generator’s output. - planned — the playground’s Playwright suite with axe, in
apps/playground’s end-to-end__tests__/folders, failing on critical or serious findings in each component route, in both schemes and both directions. - planned — the
@stackra/uiparity test of 0112: every./reactcomponent has a./nativeexport of the same contract. - planned — a check that
apps/docs/src/assets/brand/NOTICEexists (replaces the brand-package check of 0024).
Alternatives
- Keep
@stackra/brandas its own package. Not chosen: it ties the framework’s token schema to Stackra’s all-rights-reserved marks, so a user cannot theme without shipping them. - Keep
uiinexperience. Not chosen: the tokens and the components are one design system and change together; the experience packages consumeuiand stay where they are. - A shared web and native component implementation. Deferred, per the row in 0227. Only the contract is shared.
- Storybook for component review. Rejected (0128, 0227). The playground is an ordinary app instead.
Supersedes and sources
Supersedes: none. Amends: 0127 (the category table), 0165 (decisions 1 and 2), 0024 (decisions 2 and 3, and the Enforcement path), 0084 (the theming and brand rows) and 0291 (decisions 8 and 9). Related: 0060 (light and dark, logical CSS), 0112 (X9,@stackra/ui parity),
0197 and 0022.
Sources: owner decisions in the lead session, 2026-10-23, recorded in Linear STA-350.