Character Conditions System
The Character Conditions system provides structured, rule-based character state generation for procedural content. Unlike simple text file lookups, it uses weighted probability distributions, semantic exclusion rules, and mandatory/optional axis policies to generate coherent character descriptions.
Overview
The system generates character states across multiple axes:
Physique: Body structure (skinny, wiry, stocky, hunched, frail, broad)
Wealth: Economic status (poor, modest, well-kept, wealthy, decadent)
Health: Physical condition (sickly, scarred, weary, hale, limping)
Demeanor: Behavioral presentation (timid, suspicious, resentful, alert, proud)
Age: Life stage (young, middle-aged, old, ancient)
Key Features
Weighted Probability
The system uses realistic population distributions:
WEIGHTS = {
"wealth": {
"poor": 4.0, # Most common
"modest": 3.0,
"well-kept": 2.0,
"wealthy": 1.0,
"decadent": 0.5, # Rare
}
}
This creates a believable population where most characters are poor or modest, and wealthy/decadent characters are rare.
Semantic Exclusions
Rules prevent illogical combinations:
Decadent characters can’t be frail or sickly (wealth enables health care)
Ancient characters aren’t timid (age brings confidence)
Broad, strong physiques don’t pair with sickness
Hale (healthy) characters shouldn’t have frail physiques
Mandatory/Optional Axes
Mandatory: Always include physique and wealth (establish baseline)
Optional: Include 0-2 additional axes (add narrative detail)
Max Optional: Prevents prompt dilution and maintains clarity
Usage
Basic Generation
from pipeworks.core.character_conditions import (
generate_condition,
condition_to_prompt
)
# Generate random condition
condition = generate_condition()
prompt_text = condition_to_prompt(condition)
print(prompt_text)
# Output: "wiry, poor, suspicious, old"
Reproducible Generation
# Use seed for reproducibility
condition1 = generate_condition(seed=42)
condition2 = generate_condition(seed=42)
assert condition1 == condition2 # Same result
Integration with Image Generation
from pipeworks import model_registry, config
from pipeworks.core.character_conditions import (
generate_condition,
condition_to_prompt
)
adapter = model_registry.instantiate("Z-Image-Turbo", config)
# Generate character condition
condition = generate_condition(seed=42)
condition_text = condition_to_prompt(condition)
# Use in prompt
full_prompt = f"{condition_text}, goblin warrior in dark tavern"
image = adapter.generate(prompt=full_prompt, seed=42)
Dynamic Conditions
Generate different conditions for each run:
# Generate 10 different goblins
for i in range(10):
condition = generate_condition() # No seed = random
condition_text = condition_to_prompt(condition)
prompt = f"{condition_text}, goblin character portrait"
image, path = generator.generate_and_save(
prompt=prompt,
seed=1000 + i
)
UI Integration
The Gradio UI provides a “Character Condition Generator” in the Start 1 segment:
Auto-generate condition: Enable to generate conditions
Generated Condition: Shows the current condition (editable)
🎲 Regenerate: Generate a new random condition
Dynamic: Regenerate condition for each run in batch generation
When Dynamic is enabled:
Batch Size: 2, Runs: 20 = 20 different conditions (each used for 2 images)
Each run gets a unique condition, but images within the run share it
Architecture
Data Structures
# Axis definitions (single source of truth)
CONDITION_AXES: dict[str, list[str]]
# Policy (controls complexity)
AXIS_POLICY: dict[str, Any] = {
"mandatory": ["physique", "wealth"],
"optional": ["health", "demeanor", "age"],
"max_optional": 2,
}
# Weights (population distribution)
WEIGHTS: dict[str, dict[str, float]]
# Exclusions (semantic constraints)
EXCLUSIONS: dict[tuple[str, str], dict[str, list[str]]]
Generation Process
Select mandatory axes: Always pick physique + wealth
Select optional axes: Randomly pick 0-2 additional axes
Apply weights: Use weighted random selection for each axis
Apply exclusions: Remove illogical combinations