Verified against Semitexa Ultimate 2026.09.19.1020
Skin Algorithms and Knobs
Each algorithm is a Semitexa\PlatformUi\Contract\SkinAlgorithm implementation. The registry at Semitexa\PlatformUi\Skin\SkinAlgorithmRegistry lists all three shipped algorithms; the generate command, the LLM prompt, and the output validator all read from it.
Inspect live:
bin/semitexa skins:generate --describe
balanced
Corporate-readable. Soft drop shadows, conservative radii, smooth transitions. WCAG-AA contrast on brand. The default when prose is ambiguous.
| Knob | Enum | Default | Effect |
|---|---|---|---|
radius_scale |
compact · default · rounded |
default |
How round corners feel — compact=tight, rounded=softer. |
shadow_intensity |
minimal · default · pronounced |
default |
Drop-shadow strength on raised surfaces. |
motion_speed |
fast · default · slow |
default |
Transition-duration character. |
glass
Translucent frosted panels, larger radii, diffuse shadows, emphasized motion. Modern SaaS / mac-style.
| Knob | Enum | Default | Effect |
|---|---|---|---|
blur_amount |
subtle · medium · heavy |
medium |
Backdrop-blur radius on panels (6px / 12px / 20px). |
surface_transparency |
light · medium · heavy |
medium |
How much the backdrop shows through panels. |
shadow_softness |
tight · standard · wide |
standard |
Spread of diffuse drop shadows. |
brutalist
Bold & structural. Zero radius (except pill), hard offset shadows, instant motion, saturated accents. Neo-brutalist / zine.
| Knob | Enum | Default | Effect |
|---|---|---|---|
shadow_offset |
sharp · pronounced · extreme |
sharp |
Pixel offset of hard box-shadow (4 / 8 / 12). |
contrast_boost |
standard · high · extreme |
standard |
How dark text gets + how saturated accent becomes. |
shadow_color_mode |
neutral · brand |
neutral |
Shadow is monochrome (neutral) or pulls from --ui-accent-brand (brand). In dark mode the neutral shadow flips to near-white so it remains visible. |
Passing knobs
CLI (repeatable --knob=name:value):
bin/semitexa skins:generate balanced "#2f6fed" \
--knob=radius_scale:rounded --knob=shadow_intensity:pronounced --write
Via LLM (the model emits a knobs object alongside algorithm + seed); override by passing --knob=… explicitly.
Unknown keys or out-of-enum values fail fast with an InvalidArgumentException. Missing knobs take the schema default — never emit partial knob sets.
Adding a fourth algorithm
-
Implement
SkinAlgorithminsrc/Skin/Algorithm/<Name>Algorithm.php. Four methods:public function id(): string // stable slug, e.g. "editorial" public function description(): string // one-liner shown in CLI + LLM prompt public function knobSchema(): array // ['knob_name' => ['enum' => [...], 'default' => 'x', 'description' => '...']] public function generate(SkinParams $params): SkinPalette // emit all 41 tokens -
Honour
SkinMode.$params->modeisSkinMode::Light | SkinMode::Dark. Both must produce readable palettes with ≥ 4.5:1 brand-accent contrast againstSurfacePage. Reference implementation:BalancedAlgorithm::generateColorTokens(). -
Register. Add the class to the list in
SkinAlgorithmRegistry::__construct(). It's deliberately hardcoded — one file, one line. -
Add 1–2 few-shot examples to
resources/llm/skin-resolve-fewshot.json— concrete examples meaningfully shape LLM performance even though the prompt body is dynamic. -
Validator + prompt pick it up automatically.
OutputValidatoraccepts any registered algorithm;PromptResolverFactoryinjects the new algorithm's{{ALGORITHM_SECTIONS}}block into the system prompt at runtime. No edits toskin-resolve-prompt.md,skin-resolve-schema.json, orOutputValidator.php.
Contract guarantees
- Every algorithm emits all 41 tokens, in both modes. Missing tokens break primitives that rely on
var(--ui-X)— fallbacks exist but are hardcoded aesthetics that won't match your algorithm's character. id()is stable. Referenced fromskin.jsonmanifests and themeskinfields. Renaming an id is a breaking change for every stored skin.knobSchema()is authoritative. CLI parser, LLM validator, refinement resolver, and the--describeoutput all read it. Never validate knobs separately.- Determinism. Given the same
SkinParams,generate()must always return the sameSkinPalette. No clocks, no randomness, no environment.
The @AsSkinAlgorithm attribute
An @AsSkinAlgorithm PHP attribute is defined for future auto-discovery, but v2 uses manual registration via the registry constructor. Tagging an algorithm with the attribute is harmless today and will become the discovery mechanism in a later iteration.