← Files DesignlyARCHIVED FILE
skills/creative-director/scripts/generate_mocs.py
7.63 KB · Oct 2, 2026 · 00:30 UTC
# /// script
# requires-python = ">=3.11"
# dependencies = ["pyyaml"]
# ///
"""Generate 6 MOC files from legendary-campaigns card library."""
import sys
import re
from collections import defaultdict
from pathlib import Path
import yaml
CARDS_DIR = Path(__file__).parent.parent / "references" / "legendary-campaigns" / "cards"
MOCS_DIR = Path(__file__).parent.parent / "references" / "legendary-campaigns"
PATTERN_ORDER = [f"P{i:02d}" for i in range(1, 19)]
CATEGORY_ORDER = ["film", "integrated", "stunt_pr", "social", "ooh_print", "experiential", "digital_product", "long_form"]
BUDGET_ORDER = ["low", "medium", "high"]
def parse_frontmatter(path: Path) -> dict | None:
"""Parse YAML frontmatter from a markdown file, return None on failure."""
text = path.read_text(encoding="utf-8")
match = re.match(r"^---\n(.*?)\n---", text, re.DOTALL)
if not match:
return None
try:
return yaml.safe_load(match.group(1)) or {}
except yaml.YAMLError as exc:
print(f"WARNING: {path.name}: invalid YAML — {exc}", file=sys.stderr)
return None
def get(card: dict, key: str) -> str:
"""Return card field as string, '?' if missing or None."""
val = card.get(key)
if val is None:
return "?"
return str(val)
def format_card_line(card: dict) -> str:
"""Format a single MOC list item with inline context."""
cid = get(card, "id")
title = get(card, "title")
brand = get(card, "brand")
year = get(card, "year")
category = get(card, "category")
budget = get(card, "budget")
emotions = card.get("emotion") or []
primary_emotion = emotions[0] if emotions else "?"
awards = card.get("awards") or []
top_award = awards[0] if awards else "unknown"
return f"- [[cards/{cid}.md|{title}]] — {brand} · {year} · {category} · {primary_emotion} · {budget} · {top_award}"
def moc_header(title: str, total: int) -> list[str]:
"""Return standard MOC file header lines."""
return [
f"# {title}",
"",
"> Auto-generated by `scripts/generate_mocs.py`. Do not edit by hand.",
"",
f"Total: {total} cards",
]
def write_moc(path: Path, lines: list[str]) -> None:
"""Write MOC lines to file, joining with newlines."""
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
def generate_moc_index(cards: list[dict]) -> list[str]:
"""Generate MOC-index: all cards sorted by year DESC, quality_score DESC."""
sorted_cards = sorted(
cards,
key=lambda c: (-int(c.get("year") or 0), -int(c.get("quality_score") or 0)),
)
lines = moc_header("MOC — Index", len(cards))
lines.append("")
for card in sorted_cards:
lines.append(format_card_line(card))
return lines
def generate_moc_pattern(cards: list[dict]) -> list[str]:
"""Generate MOC-pattern: grouped by pattern P01–P18, quality_score DESC."""
by_pattern: dict[str, list[dict]] = defaultdict(list)
for card in cards:
patterns = card.get("pattern") or []
if not patterns:
by_pattern["?"].append(card)
for p in patterns:
by_pattern[p].append(card)
lines = moc_header("MOC — Pattern", len(cards))
order = PATTERN_ORDER + sorted(k for k in by_pattern if k not in PATTERN_ORDER)
for p in order:
group = by_pattern.get(p)
if not group:
continue
group_sorted = sorted(group, key=lambda c: -int(c.get("quality_score") or 0))
lines += ["", f"## {p} ({len(group_sorted)} cases)"]
for card in group_sorted:
lines.append(format_card_line(card))
return lines
def generate_moc_emotion(cards: list[dict]) -> list[str]:
"""Generate MOC-emotion: grouped by emotion_tier 3→2→1, quality_score DESC."""
by_tier: dict[int, list[dict]] = defaultdict(list)
for card in cards:
tier = card.get("emotion_tier")
by_tier[int(tier) if tier is not None else 0].append(card)
lines = moc_header("MOC — Emotion", len(cards))
for tier in [3, 2, 1, 0]:
group = by_tier.get(tier)
if not group:
continue
group_sorted = sorted(group, key=lambda c: -int(c.get("quality_score") or 0))
label = f"Tier {tier}" if tier else "Unknown Tier"
lines += ["", f"## {label} ({len(group_sorted)} cases)"]
for card in group_sorted:
lines.append(format_card_line(card))
return lines
def generate_moc_format(cards: list[dict]) -> list[str]:
"""Generate MOC-format: grouped by category, year DESC."""
by_cat: dict[str, list[dict]] = defaultdict(list)
for card in cards:
cat = card.get("category") or "?"
by_cat[cat].append(card)
lines = moc_header("MOC — Format", len(cards))
order = CATEGORY_ORDER + sorted(k for k in by_cat if k not in CATEGORY_ORDER)
for cat in order:
group = by_cat.get(cat)
if not group:
continue
group_sorted = sorted(group, key=lambda c: -int(c.get("year") or 0))
lines += ["", f"## {cat} ({len(group_sorted)} cases)"]
for card in group_sorted:
lines.append(format_card_line(card))
return lines
def generate_moc_industry(cards: list[dict]) -> list[str]:
"""Generate MOC-industry: grouped by industry alphabetically, quality_score DESC."""
by_industry: dict[str, list[dict]] = defaultdict(list)
for card in cards:
ind = card.get("industry") or "?"
by_industry[ind].append(card)
lines = moc_header("MOC — Industry", len(cards))
for ind in sorted(by_industry.keys()):
group = sorted(by_industry[ind], key=lambda c: -int(c.get("quality_score") or 0))
lines += ["", f"## {ind} ({len(group)} cases)"]
for card in group:
lines.append(format_card_line(card))
return lines
def generate_moc_budget(cards: list[dict]) -> list[str]:
"""Generate MOC-budget: grouped by budget low/medium/high, quality_score DESC."""
by_budget: dict[str, list[dict]] = defaultdict(list)
for card in cards:
bud = card.get("budget") or "?"
by_budget[bud].append(card)
lines = moc_header("MOC — Budget", len(cards))
order = BUDGET_ORDER + sorted(k for k in by_budget if k not in BUDGET_ORDER)
for bud in order:
group = by_budget.get(bud)
if not group:
continue
group_sorted = sorted(group, key=lambda c: -int(c.get("quality_score") or 0))
lines += ["", f"## {bud} ({len(group_sorted)} cases)"]
for card in group_sorted:
lines.append(format_card_line(card))
return lines
def load_cards() -> tuple[list[dict], int]:
"""Load and parse all card files, return (cards, error_count)."""
cards: list[dict] = []
errors = 0
for md_file in sorted(CARDS_DIR.glob("*.md")):
fm = parse_frontmatter(md_file)
if fm is None:
print(f"WARNING: skipping {md_file.name} — no valid frontmatter", file=sys.stderr)
errors += 1
continue
cards.append(fm)
return cards, errors
def main() -> None:
"""Entry point: load cards, write 6 MOC files, print summary."""
cards, errors = load_cards()
mocs = [
("MOC-index.md", generate_moc_index(cards)),
("MOC-pattern.md", generate_moc_pattern(cards)),
("MOC-emotion.md", generate_moc_emotion(cards)),
("MOC-format.md", generate_moc_format(cards)),
("MOC-industry.md", generate_moc_industry(cards)),
("MOC-budget.md", generate_moc_budget(cards)),
]
for filename, lines in mocs:
write_moc(MOCS_DIR / filename, lines)
print(f"Generated {len(mocs)} MOCs from {len(cards)} cards ({errors} errors skipped)")
if __name__ == "__main__":
main()
SHA-256: ebede99cce9b4bbfec4b0e8b6be5105c99400fb973d1e19a67e1a49002286a37