overlapui ships two products that look related but serve different users:
-
overlapui.fscss— the real module:@defines, selective@import, token helpers, compose only what you need. -
overlapui.css/.min.css— a precompiled drop-in sheet for people who never touch FSCSS: link it, use the utility classes, ship.
That second path raises a fair question: can every other module in the ecosystem do the same?
Short answer: most can ship a plain CSS build; not all should treat it as the primary product. The limit is not “FSCSS can’t compile to CSS” — it always can. The limit is what you lose when you freeze a parameterized module into one fixed stylesheet.
What a “plain CSS version” actually is
It is not a second language implementation. It is:
module.standalone.fscss → (fscss CLI / CI) → module.css
A standalone entry file typically:
-
@imports the full module (or a fixed subset) - calls the root / pack helpers with default selectors
- sets default tokens on
:root
CI or npm run build:css runs the official compiler and publishes module.css + module.min.css next to the .fscss source.
Users who only want CSS:
<link rel="stylesheet" href="…/module.min.css">
Users who want FSCSS keep:
@import((avatar-overlap, ou-root) from overlapui)
@ou-root()
@avatar-overlap(.team)
Same design system, two consumption modes.
When a plain CSS build fits well
Plain CSS shines when the module is already class-and-token shaped:
| Pattern | Why CSS export works |
|---|---|
Fixed utility classes (.avatar-overlap, .circle-overlap) |
Markup contract is stable |
Design tokens on :root (--ou-*, --ai-*) |
Consumers override variables without recompiling |
| Hover/focus motion in pure CSS | No compile-time loop required at use site |
| “Drop in and look right” demos | Docs and frameworks that only allow <link>
|
overlapui, large parts of form, icon-mask, circle-progress (default ring classes), and ai-ui (default .ai-shell / .ai-message shells) are in this family. A default compile gives a useful sheet; tokens still allow theming.
When a plain CSS build is weak or misleading
Some modules are generators, not fixed component packs.
st-core@v2 is the clearest case. Charts are driven by:
-
@arrdata of variable length - compile-time loops that emit
--st-p1…--st-pNandclip-pathpolygons - helpers like
@st-chart-line(.line, myData)where the array name and length are part of the compile
A single st-core.css can only encode one frozen default (e.g. eight points with fixed sample values). That is fine as a preview skin or empty chrome. It is not a replacement for “pass my sales array and get the right polygon.” For real data, you still need FSCSS at build time, or you write the CSS variables from JavaScript after a compile-time shell exists.
Similarly:
| Situation | Plain CSS limitation |
|---|---|
Heavy @arr / rpt / count() expansion |
Defaults only; not your dataset |
Selector parameters (@define x(sel:.foo)) |
Standalone must pick one selector set |
| Selective imports as the main API | Full CSS file is the opposite of tree-shaking |
pattern() libraries |
Matching is compile-time against phrases in your sheet |
So: yes, you can always produce a .css artifact. For generator modules, market it as default theme / demo build, not “full module without FSCSS.”
Should all libraries ship one?
Recommended policy for the ecosystem:
-
Ship
.fscssfirst — source of truth, selective import, parameters. -
Ship
.csswhen the default class API is useful alone (overlap, form chrome, icon masks, AI shell defaults). - Document the gap when the CSS build cannot express the main feature (charts, data-driven loops).
-
Keep CI honest —
standalone.fscss→module.csson every release so CSS does not drift from source.
Not every repo needs npm style fields and jsDelivr min files on day one. Prioritize modules people already try to <link> without a preprocessor.
How to add a plain CSS build (any module)
1. Add module.standalone.fscss
@import((*) from "./module.fscss")
@module-root()
@module-pack() /* or each public helper with default selectors */
Use the same defaults the README teaches for copy-paste HTML.
2. Build in package scripts / GitHub Actions
fscss module.standalone.fscss module.css
# optional minify step → module.min.css
Pin the FSCSS CLI version to the module’s fscss_version / engines field.
3. Publish
-
files: include.fscss,.standalone.fscss,.css,.min.css -
style: point at the main CSS file for tooling that reads package metadata - README: two paths — “With FSCSS” and “CSS only”
4. Tell CSS-only users how to theme
If tokens are on :root, document:
:root {
--mod-accent: #5eead4;
--mod-radius: 12px;
}
That recovers a large part of customization without reintroducing the compiler.
Tradeoffs to state clearly
| FSCSS module | Plain CSS build |
|---|---|
Selective @import
|
Whole default surface (or a chosen subset baked in) |
@define(sel, n, data) |
Fixed selectors / fixed N |
| One source, many call sites | One compiled snapshot |
| Ideal for design systems | Ideal for HTML templates, CodePen, no-build sites |
Neither path is “more correct.” overlapui.css exists so non-FSCSS pages still get the overlap behavior. overlapui.fscss exists so serious apps only emit the rules they call.
Practical answer
Can all modules have a plain CSS version?
Technically yes — compile a standalone entry that invokes defaults.Should all modules present that as equivalent to the FSCSS module?
No. Class/token UI packs ≈ strong CSS builds. Data- and loop-driven modules ≈ CSS demos + FSCSS (or JS-written variables) for the real feature.What should authors or anyone do?
For example: form, icon-mask, circle-progress defaults, ai-ui shells, customizable page chrome: still good to follow the overlapui pattern (standalone file, CI, min.css, dual README). For st-core and similar: ship an optional default CSS for docs, and keep the array/compile path as the real API.
Plain CSS is a distribution channel, not a different product philosophy. FSCSS remains the authoring layer; .css is the frozen export for people who only need the defaults.
Top comments (0)