[object Object]

← back to CelebritySignatures

snapshot before removing alive celebrities

3c6f4922a957426a12b7734dd837a0a20a9d18d3 · 2026-06-19 09:35:00 -0700 · SteveStudio2

Files touched

Diff

commit 3c6f4922a957426a12b7734dd837a0a20a9d18d3
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Fri Jun 19 09:35:00 2026 -0700

    snapshot before removing alive celebrities
---
 scripts/build-collages.py        | 19 +++++++++++++++++--
 scripts/build-portrait-murals.py | 26 +++++++++++++++++++++++---
 2 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/scripts/build-collages.py b/scripts/build-collages.py
index 19c8616..2ac15a1 100644
--- a/scripts/build-collages.py
+++ b/scripts/build-collages.py
@@ -260,12 +260,27 @@ def build(category, rows):
     return made
 
 
+def _death_year(r):
+    m = re.search(r"\b(1[0-9]\d\d|20\d\d)\b", str(r.get("death_date") or ""))
+    return int(m.group(1)) if m else None
+
+
 def main():
+    # SAFE_ONLY: keep only people who died ≤1956 — clear of California's 70-year
+    # postmortem right of publicity (§3344.1) for commercial sale.
+    safe_only = bool(os.environ.get("SAFE_ONLY"))
     data = json.load(open(DATA))
     by = {}
     for r in data:
-        if r["usable_in_commercial_collage"] == "yes":
-            by.setdefault(r["category"], []).append(r)
+        if r["usable_in_commercial_collage"] != "yes":
+            continue
+        if safe_only:
+            y = _death_year(r)
+            if y is None or y > 1956:
+                continue
+        by.setdefault(r["category"], []).append(r)
+    if safe_only:
+        print("⚖️  PUBLICITY-SAFE mode: only people who died ≤1956\n")
     order = ["Declaration of Independence", "Politics", "Sports", "Hollywood", "Movies (Classic)", "Movies", "TV"]
     made = []
     print(f"QR target host: {BASE_URL}\n")
diff --git a/scripts/build-portrait-murals.py b/scripts/build-portrait-murals.py
index f942105..9a3fdad 100644
--- a/scripts/build-portrait-murals.py
+++ b/scripts/build-portrait-murals.py
@@ -214,7 +214,8 @@ def render(category, cells, named, slug, with_portrait, total):
            "Portraits used only where public-domain / openly licensed; others shown by signature alone. Living-celebrity rows excluded.",
            font=font(13), fill=MUTED)
     suffix = "-named" if named else ""
-    path = os.path.join(OUT, f"portrait-{slug}{suffix}.png")
+    prefix = "portrait-safe-" if os.environ.get("SAFE_ONLY") else "portrait-"
+    path = os.path.join(OUT, f"{prefix}{slug}{suffix}.png")
     canvas.save(path, "PNG")
     print(f"[{category}] -> {os.path.basename(path)} ({n} cells, {with_portrait} portraits, {cols}×{rows_ct}, {W}×{H})")
     return path
@@ -249,12 +250,31 @@ def build(category, rows, slug):
             render(category, cells, False, slug, with_portrait, len(cells))]
 
 
+def death_year(r):
+    m = re.search(r"\b(1[0-9]\d\d|20\d\d)\b", str(r.get("death_date") or ""))
+    return int(m.group(1)) if m else None
+
+
+# Publicity-rights gate: California §3344.1 protects a deceased personality's
+# name/likeness/signature for 70 YEARS after death. So only people who died on or
+# before this cutoff are clear of right-of-publicity exposure for commercial sale.
+PUBLICITY_SAFE_CUTOFF = 1956   # 2026 − 70
+
+
 def main():
     which = (sys.argv[1] if len(sys.argv) > 1 else "all").lower()
+    safe_only = bool(os.environ.get("SAFE_ONLY"))
     data = json.load(open(DATA)); by = {}
     for r in data:
-        if r["usable_in_commercial_collage"] == "yes":
-            by.setdefault(r["category"], []).append(r)
+        if r["usable_in_commercial_collage"] != "yes":
+            continue
+        if safe_only:
+            y = death_year(r)
+            if y is None or y > PUBLICITY_SAFE_CUTOFF:   # unknown/too-recent → exclude
+                continue
+        by.setdefault(r["category"], []).append(r)
+    if safe_only:
+        print("⚖️  PUBLICITY-SAFE mode: only people who died ≤", PUBLICITY_SAFE_CUTOFF, "\n")
     order = ["Declaration of Independence", "Politics", "Sports", "Hollywood", "Movies (Classic)", "TV"]
     print(f"Portrait murals · QR host {BASE_URL}\n")
     made = []

← 11d1aad Accounts + save-your-placement: zero-dep email/password auth  ·  back to CelebritySignatures  ·  remove all living celebrities; keep only deceased (publicity 8def5d9 →