Summary
This issue tracks the community-maintained path for a generic, strongly typed style pipeline that works well with AnalogJS while staying aligned with maintainer feedback in First-class Style Dictionary support analogjs/analog#2227.
The implementation home for this work should be this repo, not Analog core.
Why This Lives Here
In First-class Style Dictionary support analogjs/analog#2227, Brandon Roberts recommended:
- keep
style-dictionary and its dependency tree out of Analog core
- avoid adding a large new public API surface to
@analogjs/platform
- avoid hard-coding library-specific target contracts into Analog
- prefer a community-owned Vite plugin built on Vite's native plugin APIs
- keep Angular runtime theming concerns in userland unless real framework gaps later prove otherwise
That is the right boundary.
This issue keeps the implementation energy, but moves it to the correct ownership model.
Goal
Build a community-owned style pipeline that gives Analog users excellent DX without requiring Analog itself to own:
- Style Dictionary
- Panda CSS
- Tokiforge runtime theming
- PrimeNG / Spartan / daisyUI / MUI / Web Awesome / Zard / other library-specific token schemas
Design Principles
- Vite-native first: use normal Vite plugin hooks wherever possible
- Analog-friendly: work cleanly in Analog apps without requiring a large Analog core API
- Strongly typed config: TypeScript-first authoring with a small ergonomic configuration surface
- Pluggable providers: Style Dictionary, Panda CSS, Tokiforge, and custom providers should all fit the same contract
- Do not reinvent Tailwind: Tailwind should continue to own utility generation, theme semantics, and CSS pipeline behavior it already handles well
- Standard schema aware: support standard token interchange formats where it helps, without forcing JSON-first authoring
- Framework-light, ecosystem-heavy: keep host framework hooks minimal and let providers/adapters own the richer semantics
Proposed Shape
stylePipeline({
providers: [
styleDictionaryProvider({
configFile: 'style-dictionary.config.ts',
}),
pandaProvider({
configFile: 'panda.config.ts',
}),
tokiforgeProvider({
configFile: 'tokiforge.config.ts',
}),
],
})
The important API is the generic pipeline, not a token-engine-specific top-level config.
What This Should Provide
| Capability |
Description |
| Typed config loading |
TypeScript-first provider configuration with strong inference |
| Community-owned build cache |
Generated outputs managed outside Analog core |
| Default CSS injection |
Select outputs can be injected as app-level CSS bundles |
| Virtual CSS modules |
Generated CSS can be exposed as imports where useful |
| Grouped output metadata |
Providers can expose outputs by tags or categories for downstream consumers |
| Stable emitted-file metadata |
Deterministic order, importId, and file metadata for Angular-friendly tooling and SSR integrations |
| Scoped diagnostics |
Pipeline-level debug scopes for generation, invalidation, and output wiring |
Public API Direction
Top-level config
| Surface |
Purpose |
stylePipeline() |
Generic orchestration entrypoint |
defineStylePipelineConfig() |
Typed helper for authoring config files |
Provider layer
| Surface |
Purpose |
styleDictionaryProvider() |
Token transforms and output generation |
pandaProvider() |
Panda coexistence and generated artifact registration |
tokiforgeProvider() |
Angular-friendly theme/runtime integration patterns |
customProvider() |
Escape hatch for community-defined pipelines |
Output model
Providers should converge on a common typed output contract that can represent:
- CSS outputs
- theme outputs
- manifests
- TypeScript metadata/codegen artifacts
And each output should be able to describe:
id
kind
scope
order
absolutePath
rootRelativePath
importId
inject
tags
- provider-specific metadata
Why This Is A Framework-Adjacent Problem
The implementation should live in a community repo, but the problem itself is still closely tied to framework behavior once generated styles participate in dev, build, SSR, and HMR.
| Framework |
Public source |
Relevant snippet / API |
Why it matters here |
| Astro |
Astro CSS Vite plugin |
"This plugin tracks the CSS that should be applied by route." |
Astro treats CSS as framework-managed runtime state, with virtual modules and route-aware tracking. Token outputs create the same class of problem once they participate in dev, SSR, and build. |
| Nuxt |
Nuxt components module |
addTemplate, addPluginTemplate, addTypeTemplate, addVitePlugin |
Nuxt handles first-class framework features through generated artifacts plus framework hooks. That informs the generated manifest and emitted-output direction here. |
| Angular |
Angular language service adapters |
"templates and stylesheets" |
Angular already treats styles as compiler resources with dedicated reading, resolution, and invalidation behavior. The community pipeline should respect that reality rather than treating tokens as a disconnected prebuild script. |
The key distinction is ownership:
- the problem space is real and framework-adjacent
- the implementation home should still be community-maintained unless real usage later proves Analog needs a tiny generic hook
Why This Fits Real Design Systems
The strongest design-system examples still converge on CSS custom properties as the durable runtime contract, even when the authoring and consumption layers above them differ.
| System |
Public source |
Relevant snippet / API |
What it reinforces |
| Web Awesome |
Design Tokens overview and Color tokens |
"These custom properties thread through all of Web Awesome's components" and "CSS custom properties" |
A serious component system wants framework-agnostic CSS variables that can flow through every component and theme surface. The pipeline should make that easy to generate and serve. |
| Zard UI |
LLMs index and Theming guide |
"Using CSS Variables and OKLCH colors for theming." and "CSS variables (recommended)" |
Tailwind-oriented UI systems still center tokens around CSS variables, then map them into Tailwind's theme layer. That supports keeping Tailwind semantics in Tailwind while the pipeline owns generation and delivery. |
| Spartan |
Spartan theming |
"Customize your design system with CSS variables. No theming API required." and @theme inline |
Spartan makes the modern pattern explicit: semantic CSS variables are the source of truth and Tailwind is the mapping layer. |
| PrimeNG styled mode |
PrimeNG styled theming |
"A theme consists of two parts; base and preset." and "primitive, semantic and component" tokens |
PrimeNG already models a token architecture with layered presets, dark mode selectors, CSS variable prefixes, and CSS layers. |
| PrimeNG unstyled and Tailwind integration |
PrimeNG Tailwind integration, Pass Through API, and unstyled theming entry |
"It is designed to work both in styled and unstyled modes." and "Your Components, Not Ours" |
PrimeNG's headless direction shows the same requirement from the opposite side: the pipeline should support token delivery and adapter CSS while libraries own DOM customization and utility semantics. |
Architectural Split
| Layer |
Responsibility |
| Community style pipeline core |
Output lifecycle, virtual module identity, watch/HMR invalidation, typed provider contracts |
| Style Dictionary |
Token transforms, format generation, typed config-driven outputs |
| Panda |
Compiler/codegen authority for Panda-native workflows |
| Tokiforge |
Angular runtime/theme-service patterns on top of generated CSS variables |
| Tailwind |
Utility and theme semantics that Tailwind already handles exceptionally well |
| Design-system packages |
Framework bridge CSS and adapter outputs for daisyUI, Spartan, PrimeNG, MUI, Web Awesome, Zard UI, and similar ecosystems |
| Analog core |
Documentation and, only if later proven necessary, tiny generic style/resource integration hooks |
Example Shapes This Enables
1. Base token bundle injected at app level
:root {
--brand-primary: oklch(0.62 0.18 264);
--brand-primary-foreground: oklch(0.98 0.01 264);
--brand-radius-md: 0.75rem;
}
[data-theme='dark'] {
--brand-primary: oklch(0.78 0.15 264);
--brand-primary-foreground: oklch(0.12 0.01 264);
}
2. Tailwind, Zard, or Spartan-style bridge CSS from the same tokens
@theme inline {
--color-primary: var(--brand-primary);
--color-primary-foreground: var(--brand-primary-foreground);
--radius-md: var(--brand-radius-md);
}
3. Web Awesome-style semantic token bridge from the same source
:root {
--wa-color-brand-fill-loud: var(--brand-primary);
--wa-color-brand-on-loud: var(--brand-primary-foreground);
}
4. PrimeNG styled-mode bridge from the same source
:root {
--p-primary-color: var(--brand-primary);
--p-primary-contrast-color: var(--brand-primary-foreground);
--p-border-radius: var(--brand-radius-md);
}
5. PrimeNG unstyled or headless Tailwind bridge
@theme inline {
--color-primary: var(--brand-primary);
--color-surface-0: var(--brand-surface-0);
--color-surface-900: var(--brand-surface-900);
--radius-border: var(--brand-radius-md);
}
6. Framework-aware consumption in an Analog app
import 'virtual:bdx-style-pipeline.css';
import pipeline from 'virtual:bdx-style-pipeline';
await import('virtual:bdx-style-pipeline/tailwind.css');
await import('virtual:bdx-style-pipeline/web-awesome.css');
await import('virtual:bdx-style-pipeline/primeng-styled.css');
console.log(pipeline.outputs);
console.log(pipeline.getOutputsByTag('primeng'));
Compatibility
This design is intentionally pluggable rather than turning Analog into the owner of every token authoring workflow or framework-specific theming API.
| Tool |
How this design plays nicely with it |
Why the split matters |
| TokiForge Angular |
The pipeline can provide generated global token CSS, emitted file metadata, and framework bridge CSS while a TokiForge-style Angular runtime layer owns theme switching, signals, and app-level theme services. |
TokiForge proves that Angular-native DX often wants a runtime theme service on top of CSS variables. That should be an adapter layer, not Analog core. |
| Tokens Studio for Figma |
Tokens Studio can remain the design-source and sync layer, with tokens stored remotely or in Git, then transformed by Style Dictionary and served by the community pipeline. |
This is the cleanest upstream fit: design tokens flow from Figma to Git/JSON to Style Dictionary to app consumption without requiring a framework-owned token authoring model. |
| Panda CSS for Angular |
Panda can keep its own panda.config.ts, codegen, and PostCSS pipeline while consuming the same token source or emitted CSS-variable bridges from this pipeline. |
Panda is a compiler with its own config/codegen authority. The right integration is coexistence or adapter generation, not replacing Panda from a framework package. |
Example integration shapes
-
Tokens Studio -> Git sync -> Style Dictionary -> style pipeline -> Analog
The pipeline watches exported token files, builds the outputs, injects the default CSS variables, and exposes bridge CSS for PrimeNG, Spartan, Web Awesome, MUI, or Tailwind consumers.
-
TokiForge-style Angular runtime on top of pipeline outputs
The pipeline owns token delivery; an Angular helper layer can own ThemeService, signals, theme persistence, and SSR-safe theme switching while components still consume the generated CSS variables.
-
Panda alongside Analog
Panda can still generate atomic classes and typed style APIs, while the pipeline provides shared token outputs or framework bridges for non-Panda consumers in the same monorepo.
The main design principle is consistent across all three: the pipeline should own token output lifecycle and delivery, while upstream token sources and downstream framework adapters keep ownership of their own semantics.
Initial Scope
Core
- typed provider contract
- typed output manifest contract
- deterministic output ordering
- watch file registration
- virtual CSS/module support where needed
- debug logging for pipeline events and generated outputs
Providers
- Style Dictionary provider for token transforms and output generation
- Panda provider for coexistence with Panda's config/codegen pipeline
- Tokiforge provider for Angular-friendly runtime/theme integration patterns without pushing that into Analog core
Integration
- Vite plugin orchestration layer
- Analog usage examples and docs
- examples for Tailwind-based consumption and framework bridge CSS
Non-Goals
- no large new
@analogjs/platform API
- no
provideDesignTokens() in Analog core
- no Analog-owned
'primeng' | 'spartan' | 'daisyui' | ... target strings
- no attempt to replace Tailwind, Panda, Tokiforge, or design-system-specific runtime APIs
- no assumption that Analog must merge code to support this well
What Analog May Eventually Need
If community usage exposes real gaps, the eventual Analog ask should stay small and generic. Example areas:
- stable stylesheet resource identity hooks
- style pipeline registration/composition hooks
- HMR invalidation helpers for generated style resources
- documentation recipes for community plugins
That should only happen after real usage proves the need.
Package Direction In This Repo
The benevolent-dx ecosystem is the right home for the package family behind this work. Analog-facing packages in this repo should live under benevolent-dx/packages/analog-*.
Likely package direction:
benevolent-dx/packages/analog-style-pipeline-core
benevolent-dx/packages/analog-style-pipeline-vite
benevolent-dx/packages/analog-style-pipeline-style-dictionary-provider
benevolent-dx/packages/analog-style-pipeline-panda-provider
benevolent-dx/packages/analog-style-pipeline-tokiforge-provider
Phased Plan
- Tighten the generic provider/output contract
- Harden the Vite plugin around watch/build/HMR behavior
- Make Style Dictionary the first production-grade provider
- Add Panda coexistence support
- Add Tokiforge-oriented Angular runtime integration examples
- Publish docs and real Analog examples
- Re-evaluate whether Analog core needs any tiny generic extension point
Related Links
Summary
This issue tracks the community-maintained path for a generic, strongly typed style pipeline that works well with AnalogJS while staying aligned with maintainer feedback in First-class Style Dictionary support analogjs/analog#2227.
The implementation home for this work should be this repo, not Analog core.
Why This Lives Here
In First-class Style Dictionary support analogjs/analog#2227, Brandon Roberts recommended:
style-dictionaryand its dependency tree out of Analog core@analogjs/platformThat is the right boundary.
This issue keeps the implementation energy, but moves it to the correct ownership model.
Goal
Build a community-owned style pipeline that gives Analog users excellent DX without requiring Analog itself to own:
Design Principles
Proposed Shape
The important API is the generic pipeline, not a token-engine-specific top-level config.
What This Should Provide
order,importId, and file metadata for Angular-friendly tooling and SSR integrationsPublic API Direction
Top-level config
stylePipeline()defineStylePipelineConfig()Provider layer
styleDictionaryProvider()pandaProvider()tokiforgeProvider()customProvider()Output model
Providers should converge on a common typed output contract that can represent:
And each output should be able to describe:
idkindscopeorderabsolutePathrootRelativePathimportIdinjecttagsWhy This Is A Framework-Adjacent Problem
The implementation should live in a community repo, but the problem itself is still closely tied to framework behavior once generated styles participate in dev, build, SSR, and HMR.
"This plugin tracks the CSS that should be applied by route."addTemplate,addPluginTemplate,addTypeTemplate,addVitePlugin"templates and stylesheets"The key distinction is ownership:
Why This Fits Real Design Systems
The strongest design-system examples still converge on CSS custom properties as the durable runtime contract, even when the authoring and consumption layers above them differ.
"These custom properties thread through all of Web Awesome's components"and"CSS custom properties""Using CSS Variables and OKLCH colors for theming."and"CSS variables (recommended)""Customize your design system with CSS variables. No theming API required."and@theme inline"A theme consists of two parts; base and preset."and"primitive, semantic and component"tokens"It is designed to work both in styled and unstyled modes."and"Your Components, Not Ours"Architectural Split
Example Shapes This Enables
1. Base token bundle injected at app level
2. Tailwind, Zard, or Spartan-style bridge CSS from the same tokens
3. Web Awesome-style semantic token bridge from the same source
4. PrimeNG styled-mode bridge from the same source
5. PrimeNG unstyled or headless Tailwind bridge
6. Framework-aware consumption in an Analog app
Compatibility
This design is intentionally pluggable rather than turning Analog into the owner of every token authoring workflow or framework-specific theming API.
panda.config.ts, codegen, and PostCSS pipeline while consuming the same token source or emitted CSS-variable bridges from this pipeline.Example integration shapes
Tokens Studio -> Git sync -> Style Dictionary -> style pipeline -> Analog
The pipeline watches exported token files, builds the outputs, injects the default CSS variables, and exposes bridge CSS for PrimeNG, Spartan, Web Awesome, MUI, or Tailwind consumers.
TokiForge-style Angular runtime on top of pipeline outputs
The pipeline owns token delivery; an Angular helper layer can own
ThemeService, signals, theme persistence, and SSR-safe theme switching while components still consume the generated CSS variables.Panda alongside Analog
Panda can still generate atomic classes and typed style APIs, while the pipeline provides shared token outputs or framework bridges for non-Panda consumers in the same monorepo.
The main design principle is consistent across all three: the pipeline should own token output lifecycle and delivery, while upstream token sources and downstream framework adapters keep ownership of their own semantics.
Initial Scope
Core
Providers
Integration
Non-Goals
@analogjs/platformAPIprovideDesignTokens()in Analog core'primeng' | 'spartan' | 'daisyui' | ...target stringsWhat Analog May Eventually Need
If community usage exposes real gaps, the eventual Analog ask should stay small and generic. Example areas:
That should only happen after real usage proves the need.
Package Direction In This Repo
The
benevolent-dxecosystem is the right home for the package family behind this work. Analog-facing packages in this repo should live underbenevolent-dx/packages/analog-*.Likely package direction:
benevolent-dx/packages/analog-style-pipeline-corebenevolent-dx/packages/analog-style-pipeline-vitebenevolent-dx/packages/analog-style-pipeline-style-dictionary-providerbenevolent-dx/packages/analog-style-pipeline-panda-providerbenevolent-dx/packages/analog-style-pipeline-tokiforge-providerPhased Plan
Related Links