Skip to content

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:

  1. Single theme generation via the trinity theme-gen CLI command
  2. 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:

python
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.json

CLI Usage

Single Theme Generation

bash
trinity theme-gen "Cyberpunk neon city" --name cyberpunk

Requirements:

  • Running LLM endpoint (Ollama, LM Studio, or cloud)
  • Theme name must be lowercase alphanumeric with underscores only

Validation:

bash
# 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

bash
python scripts/mass_theme_generator.py --count 100
bash
# Dry-run preview (no LLM calls, no file writes)
python scripts/mass_theme_generator.py --dry-run

Theme 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:

python
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:

bash
python scripts/mass_theme_generator.py --count 100
trinity mine-generate --count 10000 --themes <all_generated_themes>
trinity train

Configuration

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) or config/themes.yaml (mass gen)

Next Steps

Released under the MIT License.