Verified against Semitexa Ultimate 2026.09.19.1020
UI and SSR Integration
platform-ui is a semitexa-module. semitexa/ssr auto-discovers its assets via src/Application/Static/assets.json (v2 manifest).
Mode A — Static bundle (v1, ships today)
Build
bin/semitexa platform-ui:css:build
Produces two static files:
src/Application/Static/css/full.css— all grammar + primitives + baseline + default skin (~12KB raw, 2.6KB gzipped)src/Application/Static/css/baseline.css— reset + typography + tokens only (~2.6KB raw, 1.1KB gzipped)
Ssr discovers them via manifest; they become available as:
platform-ui:css:full— scope=module, priority=40platform-ui:css:baseline— scope=page, priority=30
Use
In a layout template:
<link rel="stylesheet" href="/assets/platform-ui/css/full.css">
Or via ssr asset pipeline in a handler:
$collector->requireModule('platform-ui');
Regenerate after skin change
bin/semitexa skins:generate balanced "#hex" --name=default --write
bin/semitexa platform-ui:css:build
Mode B — Dynamic per-route (post-hook)
The full pipeline exists in platform-ui but needs a post-Twig-render hook in ssr to produce per-request bundles. See semitexa/semitexa-ssr#51.
When available, the pattern will be:
TwigExtractorscans rendered HTML forsx-*/ui-*usage (per-requestSliceRegistry)BundleCompilerassembles minimal CSS from used slices- Content-hashed for cache-busting
- Registered via new
AssetCollector::inlineCss()API
Expected size: 2–5KB gzipped per route instead of 2.6KB monolithic.
Safelist for dynamic templates
When Twig conditionals produce sx-*/ui-* values that can't be seen by static scans:
$safelist = new Safelist();
$safelist->addGlobalSlice('sx-tone:warning');
$safelist->addRoutePrimitive('/dashboard', 'badge');
$safelist->apply($registry, currentRoute: $path);
Introspection
bin/semitexa platform-ui:css:inspect <template>— scans file, shows grammar slices, primitives, unresolved items, and final bundle size