Centuria Theme Factory
Theme generation and mass production for ML training diversity
The Centuria Factory is a set of tools for generating new themes via LLM and producing large numbers of theme variations for training data diversity.
Overview
Trinity ships with 14 built-in themes. The Centuria Factory allows generating additional themes in two ways:
- Single theme generation via the
trinity theme-genCLI command - Mass theme generation via
scripts/mass_theme_generator.py
Both approaches require a running LLM endpoint.
Architecture
Text-to-Theme Engine
Converts a natural language style description to a Tailwind CSS configuration via LLM:
from trinity.components.brain import ContentEngine
brain = ContentEngine()
theme_config = brain.generate_theme_from_vibe(
"Cyberpunk neon city with pink and cyan accents"
)
# Returns a dict with Tailwind class strings, e.g.:
# {
# "nav_bg": "bg-black border-b-2 border-cyan-400",
# "hero_title": "text-6xl font-black text-pink-500 uppercase",
# "card_bg": "bg-gray-900 border border-cyan-500 shadow-2xl",
# ...
# }Generation Pipeline
1. Style description (natural language)
↓
2. LLM generates Tailwind class mappings
↓
3. Schema validation (13 required components)
↓
4. Retry up to 3 times on validation failure
↓
5. Theme saved to config/themes.jsonCLI Usage
Single Theme Generation
trinity theme-gen "Cyberpunk neon city" --name cyberpunkRequirements:
- Running LLM endpoint (Ollama, LM Studio, or cloud)
- Theme name must be lowercase alphanumeric with underscores only
Validation:
# Invalid name
trinity theme-gen "Cool Theme" --name Cool-Theme # ERROR
# Valid name
trinity theme-gen "Cool Theme" --name cool_theme # OK
# Existing theme
trinity theme-gen "New vibe" --name brutalist
# WARNING: Theme 'brutalist' already exists. Overwrite? [y/N]Mass Theme Generation
python scripts/mass_theme_generator.py --count 100# Dry-run preview (no LLM calls, no file writes)
python scripts/mass_theme_generator.py --dry-runTheme Categories
The mass generator uses predefined category vibes to ensure diversity. Example vibes per category:
Historical:
- "Victorian ornate with gold and burgundy"
- "Art Deco geometric with black and gold"
- "1980s Memphis design with bold shapes"
Tech:
- "DOS terminal with green monospace"
- "Material Design with elevation shadows"
- "Cyberpunk neon with dark backgrounds"
Artistic:
- "Cubist fragmented with earth tones"
- "Swiss design with grids and Helvetica"
- "Japanese minimalism with negative space"
Chaotic (intentionally difficult for ML training):
- "Glitch art with corrupted pixels"
- "Rainbow gradient overload"
- "Late 90s GeoCities with animations"
Professional:
- "Legal firm conservative with navy"
- "Medical clean with white and blue"
- "Startup modern with gradients"
Implementation
Theme Generation Function
The generate_theme_from_vibe method in ContentEngine sends the style description to the LLM and validates the response:
def generate_theme_from_vibe(
self,
vibe_description: str,
max_retries: int = 3
) -> Dict[str, str]:
"""
Convert a style description to Tailwind CSS class mappings.
Returns a dict with 13 required keys:
nav_bg, nav_text, nav_link,
hero_bg, hero_title, hero_subtitle,
card_bg, card_title, card_text,
btn_primary, btn_secondary,
footer_bg, footer_text
Raises ContentEngineError after max_retries failures.
"""
prompt = f"""
Generate a TailwindCSS theme configuration for: {vibe_description}
Return ONLY a JSON object with these 13 keys:
nav_bg, nav_text, nav_link, hero_bg, hero_title, hero_subtitle,
card_bg, card_title, card_text, btn_primary, btn_secondary,
footer_bg, footer_text
Values should be complete TailwindCSS class strings.
"""
for attempt in range(1, max_retries + 1):
response = self.llm_client.generate(
prompt=prompt,
temperature=0.9,
max_tokens=1000
)
try:
theme = json.loads(response)
required_keys = [
"nav_bg", "nav_text", "nav_link",
"hero_bg", "hero_title", "hero_subtitle",
"card_bg", "card_title", "card_text",
"btn_primary", "btn_secondary",
"footer_bg", "footer_text"
]
if all(key in theme for key in required_keys):
return theme
except json.JSONDecodeError:
pass
raise ContentEngineError(
f"Failed to generate valid theme after {max_retries} attempts"
)ML Training Benefits
Generating diverse themes is primarily useful for collecting training data for the ML predictor. With only a few themes, the predictor may learn theme-specific patterns rather than general layout rules.
Hypothesis:
Training on many diverse themes may help the model learn general rules about text width relative to container width, rather than memorizing patterns for specific theme configurations.
Current state:
- 14 built-in themes
- ML predictor requires local training data
To collect training data across more themes:
python scripts/mass_theme_generator.py --count 100
trinity mine-generate --count 10000 --themes <all_generated_themes>
trinity trainConfiguration
Key settings for theme generation (not all of these are in the default settings.yaml; set via environment variables if needed):
- LLM endpoint:
TRINITY_LM_STUDIO_URL(default:http://localhost:1234/v1) - Themes output:
config/themes.json(single theme gen) orconfig/themes.yaml(mass gen)
Next Steps
- Self-Healing Layouts - How themes affect layout validation
- Retry Logic with Heuristics - Training pipeline
- LLM Caching - Speed up generation