═══════════════════════════════════════════════════════════════════════ TODO #6 — size-limit budgets in CI ═══════════════════════════════════════════════════════════════════════ Adds .size-limit.cjs with budgets for 6 pilot @bytelyst/* packages, plus a Gitea Actions workflow (.gitea/workflows/size-limit.yml) that fails the build on any regression. Current measurements vs budget (all comfortably under): @bytelyst/api-client 793 B / 8 KB @bytelyst/auth-client 1.97 KB / 8 KB @bytelyst/celebrations 236 B / 6 KB @bytelyst/quick-actions 122 B / 6 KB @bytelyst/react-auth 2.71 KB / 10 KB @bytelyst/dashboard-shell 3.96 KB / 30 KB Scripts: pnpm size — measure + assert against budgets pnpm size:why — explain top contributors Deps: size-limit@^12.1.0, @size-limit/preset-small-lib@^12.1.0. Pilot scope (this commit): 6 packages. Full @bytelyst/* rollout is incremental — each entry added separately. ═══════════════════════════════════════════════════════════════════════ TODO #5 — Storybook canonical pattern ═══════════════════════════════════════════════════════════════════════ Discovery: @bytelyst/ui already has Storybook 8 with the @bytelyst/ addon-a11y addon configured and 5 .stories.tsx files. This commit: - Documents that setup as the canonical template (docs/STORYBOOK_TEMPLATE.md) including the .storybook/main.ts, preview.ts, package.json scripts, and an example story. - Catalogs which of the 8 visual @bytelyst/* packages need Storybook added (1/8 done — @bytelyst/ui). - Per docs/ROADMAP_2026_DECISIONS.md §9, hosting target is self-hosted Gitea Pages (no Chromatic). Full rollout to the other 7 packages stays open as incremental work. ═══════════════════════════════════════════════════════════════════════ TODO #4 — DTCG v3 token migration RFC ═══════════════════════════════════════════════════════════════════════ This is too large to land in a single commit. Drafted RFC instead: docs/rfc/0001-dtcg-v3-token-migration.md The RFC proposes a 4-PR sequence: PR 1 — Add converter + dual-emit (byte-identical assertion) PR 2 — Flip source of truth to DTCG JSON PR 3 — Introduce the component tier PR 4 — Multi-theme via DTCG token sets Estimate: 2 person-weeks total. Backward compatibility: --ml-* and --bl-* names preserved through all 4 PRs. Status: Draft, awaiting reviewers. Refs: learning_ai_uxui_web/docs/ROADMAP_2026.md §10 TODOs #4, #5, #6
6.2 KiB
6.2 KiB
RFC 0001 — Migrate @bytelyst/design-tokens to DTCG v3
| Status | Draft |
|---|---|
| Author | Cascade |
| Created | 2026-05-27 |
| Tracks | ROADMAP TODO #4 |
| Reviewers | to be assigned |
Summary
Migrate packages/design-tokens/tokens/bytelyst.tokens.json from the
current bespoke schema to the W3C Design Tokens Community Group
(DTCG) Format Module v3. Re-emit all generated outputs
(CSS / TS / Kotlin / Swift / per-product CSS) from the new schema with
no observable change to runtime CSS variable names.
Motivation
- Designer tooling. Figma-Tokens (now "Tokens Studio") and Specify both speak DTCG natively. Today designers cannot round-trip tokens with engineering — the JSON schema is bespoke.
- Long-term portability. DTCG is becoming the lingua franca of design systems (Adobe Spectrum, Salesforce Lightning, GitHub Primer are all migrating).
- Three-tier semantics. DTCG
$type+ reference syntax ({path}) gives us a clean way to express the reference → semantic → component layering documented inlearning_ai_uxui_web/docs/ROADMAP_2026.md§3.
Current schema (excerpt)
{
"meta": { "name": "ByteLyst Design Tokens", "version": "1.1.0" },
"color": {
"palette": { "neutral": { "0": "#FFFFFF", "50": "#F6F8FC", ... } },
"semantic": {
"dark": { "bgCanvas": "#06070A", ... },
"light": { "bgCanvas": "#F8F9FC", ... }
}
},
"spacing": { "0": 0, "1": 4, "2": 8, ... },
"radius": { "xs": 4, "sm": 6, ... },
"typography": { "fontSize": { "xs": 12, ... } },
...
}
Proposed DTCG v3 schema (excerpt)
{
"$description": "ByteLyst design tokens — DTCG v3",
"$schema": "https://design-tokens.github.io/community-group/format/",
"color": {
"neutral": {
"0": { "$value": "#FFFFFF", "$type": "color" },
"50": { "$value": "#F6F8FC", "$type": "color" },
"950": { "$value": "#06070A", "$type": "color" }
},
"brand": {
"blue": { "$value": "#5A8CFF", "$type": "color" },
"coral": { "$value": "#FF6E6E", "$type": "color" }
},
"semantic": {
"bgCanvas": {
"$value": "{color.neutral.950}",
"$type": "color",
"$description": "Page background — dark"
}
}
},
"spacing": {
"1": { "$value": "4px", "$type": "dimension" },
"2": { "$value": "8px", "$type": "dimension" }
},
"radius": {
"xs": { "$value": "4px", "$type": "dimension" }
},
"component": {
"button": {
"padding-x": { "$value": "{spacing.4}", "$type": "dimension" },
"bg": { "$value": "{color.semantic.accent}", "$type": "color" }
}
}
}
Key changes
| Aspect | Today | DTCG v3 |
|---|---|---|
| Value wrapper | bare value | { "$value": ..., "$type": ... } |
| Type metadata | inferred from JS path | explicit $type |
| References | manual JS lookup | {path.to.token} syntax |
| Light/dark | parallel sibling objects | DTCG token sets (per-theme files) |
| Documentation | none | $description per token |
| Component tier | doesn't exist | new top-level component group |
Implementation plan
The migration is split into 4 PRs to keep each one reviewable.
PR 1 — Add converter + dual-emit (no behaviour change)
- Add
scripts/convert-legacy-to-dtcg.tsthat reads the bespoke JSON and emitsbytelyst.tokens.dtcg.json. - Modify
scripts/generate.tsto accept either schema and produce byte-identical output. - Add a vitest case asserting the two emitters produce identical CSS byte-for-byte.
PR 2 — Flip source of truth to DTCG JSON
- Delete the legacy JSON.
- Update Figma-Tokens plugin documentation + commit a
.tokens.config.jsonfor round-trip.
PR 3 — Introduce the component tier
- New
component.*group in the DTCG JSON. - Generator emits new
--bl-{component}-{slot}variables. - Audit existing hardcoded values in
@bytelyst/uiand replace with the new component tokens.
PR 4 — Multi-theme via DTCG token sets
- Split the single JSON into:
tokens/global.tokens.json(reference + semantic core)tokens/themes/dark.tokens.json(light/dark overrides)tokens/themes/light.tokens.jsontokens/brands/lysnrai.tokens.json(brand-layer overrides — Wave 7)
- Generator composes per-output set.
Backward compatibility
- All existing
--ml-*and--bl-*CSS variable names are preserved. - All TS/Kotlin/Swift exported identifiers preserved.
- Consumer apps require zero changes through PRs 1–3.
- PR 4 introduces multi-set composition but the default still
produces the same
tokens.css.
Risks
| Risk | Severity | Mitigation |
|---|---|---|
| Generator divergence between schemas during PR 1 | High | Byte-identical assertion test |
| Figma-Tokens plugin version churn | Med | Pin plugin version in docs/THEMING.md |
| Designer learning curve | Med | One-pager + paired migration session |
Reference cycles in DTCG ({a} → {b} → {a}) |
Low | Generator validates DAG before emit |
Alternatives considered
- Style Dictionary — Amazon's tool. Heavier, more opinionated. Rejected: we already have a working generator; switching tools is a larger change than switching schemas.
- Stay on bespoke JSON — Rejected: blocks designer round-trip and locks us out of the ecosystem.
Estimate
~1 person-week for PRs 1–3, +1 pw for PR 4 = 2 pw total.
Open questions
- Do we adopt the DTCG 2024 candidate or wait for the 2026 final? Candidate is stable enough; recommend candidate now, re-verify when final.
- Where do per-product brand layers live — separate packages
(
@bytelyst/brand-lysnrai) or subpaths (@bytelyst/design-tokens/brands/lysnrai)? Recommend subpaths pre-Wave 7, separate packages from Wave 7.