[object Object]

← back to Wallco Ai

Interior-designer naming: motif-aware pattern names (parse hero animal from Motif: clause) + curated colorway palette (Verdigris/Bottle Green/Oxblood/Prussian...). 'Peacocks Bacchanal in Bottle Green' replaces 'Marine Vignette No.NNNN'

a7c3834e4c0e69889d9740eb1f648445deee780d · 2026-05-31 16:37:49 -0700 · Steve

Files touched

Diff

commit a7c3834e4c0e69889d9740eb1f648445deee780d
Author: Steve <steve@designerwallcoverings.com>
Date:   Sun May 31 16:37:49 2026 -0700

    Interior-designer naming: motif-aware pattern names (parse hero animal from Motif: clause) + curated colorway palette (Verdigris/Bottle Green/Oxblood/Prussian...). 'Peacocks Bacchanal in Bottle Green' replaces 'Marine Vignette No.NNNN'
---
 scripts/refresh_designs_snapshot.py | 98 +++++++++++++++++++++++++++++++++++--
 1 file changed, 93 insertions(+), 5 deletions(-)

diff --git a/scripts/refresh_designs_snapshot.py b/scripts/refresh_designs_snapshot.py
index 576e70e..422ce05 100644
--- a/scripts/refresh_designs_snapshot.py
+++ b/scripts/refresh_designs_snapshot.py
@@ -10,7 +10,7 @@ Generates semantic titles by category palette:
   damask    → Baroque / Damask / Heirloom + hue-name + No.{id}
   mixed     → Atelier / Studio / Origin + hue-name + No.{id}
 """
-import json, subprocess, colorsys, os
+import json, subprocess, colorsys, os, re
 from pathlib import Path
 
 # Resolve relative to this script so it works in both
@@ -50,6 +50,86 @@ def hue_name(hex_):
     if deg < 330: return 'Plum'
     return 'Rose'
 
+# ── Interior-designer colorway names ────────────────────────────────────────
+# Curated heritage paint/textile palette (Farrow & Ball / de Gournay sensibility)
+# keyed by hue band → [dark, mid, light] so lightness picks the right shade name.
+# Steve 2026-05-31: "int des skill color and pattern names" — replace the flat
+# 11-word hue map with named colorways.
+COLORWAYS = {
+    'neutral': {  # s < 0.10, chosen by lightness
+        'vlight': 'Alabaster', 'light': 'Oyster', 'mid': 'Greige',
+        'dark': 'Pewter', 'vdark': 'Charcoal',
+    },
+    # hue bands: (max_deg, {dark, mid, light})
+    'bands': [
+        (15,  {'dark': 'Oxblood',   'mid': 'Claret',     'light': 'Blush'}),       # red
+        (35,  {'dark': 'Terracotta','mid': 'Amber',      'light': 'Apricot'}),      # orange
+        (55,  {'dark': 'Ochre',     'mid': 'Honey',      'light': 'Chamois'}),      # yellow
+        (80,  {'dark': 'Loden',     'mid': 'Olive',      'light': 'Chartreuse'}),   # yellow-green
+        (155, {'dark': 'Bottle Green','mid': 'Sage',     'light': 'Celadon'}),      # green
+        (200, {'dark': 'Verdigris', 'mid': 'Teal',       'light': 'Eau de Nil'}),   # teal/marine
+        (250, {'dark': 'Prussian',  'mid': 'Sapphire',   'light': 'Delft'}),        # blue
+        (290, {'dark': 'Aubergine', 'mid': 'Amethyst',   'light': 'Wisteria'}),     # purple
+        (330, {'dark': 'Damson',    'mid': 'Plum',        'light': 'Mauve'}),        # magenta
+        (361, {'dark': 'Garnet',    'mid': 'Rosewood',    'light': 'Rose'}),         # pink-red
+    ],
+}
+def colorway_name(hex_):
+    h, l, s = hex_to_hls(hex_)
+    if s < 0.10:
+        n = COLORWAYS['neutral']
+        if l > 0.85: return n['vlight']
+        if l > 0.65: return n['light']
+        if l > 0.42: return n['mid']
+        if l > 0.22: return n['dark']
+        return n['vdark']
+    deg = h * 360
+    for maxd, shades in COLORWAYS['bands']:
+        if deg < maxd:
+            tier = 'light' if l > 0.62 else 'dark' if l < 0.34 else 'mid'
+            return shades[tier]
+    return 'Rose'
+
+# ── Motif-aware pattern names for the animal categories ─────────────────────
+# Parse the actual creature out of the prompt so the name describes the design
+# ("Peacock Carouse in Verdigris") instead of a generic "Marine Vignette".
+ANIMALS = ['peacock','giraffe','elephant','orangutan','bullfrog','treefrog',
+           'sloth','parrot','macaw','lemur','panda','flamingo','toucan','owl',
+           'fox','raccoon','koala','otter','badger','hare','rabbit','tiger',
+           'lion','bear','stag','deer','hedgehog','squirrel','swan','crane',
+           'heron','pheasant','cockatoo','gecko','chameleon','turtle',
+           'hummingbird','monkey','frog']
+# display plural override; default is Capitalize + 's'
+ANIMAL_PLURAL = {'fox':'Foxes','hare':'Hares','stag':'Stags','deer':'Deer',
+                 'goose':'Geese','monkey':'Monkeys',
+                 'bullfrog':'Frogs','treefrog':'Frogs'}
+def animal_in(prompt):
+    # The luxe-regen prompt is structured "...Ground: <SKU may name an animal>.
+    # Motif: <hero animal> ...". Search the Motif clause ONLY so a ground SKU like
+    # "Blue Dart Frog" can't out-rank the actual peacock. Fall back to the whole
+    # prompt if there's no Motif: clause. Word-boundary match so 'foxglove'≠fox.
+    p = (prompt or '').lower()
+    m = re.search(r'motif:\s*(.+?)(?:palette:|ground:|$)', p, re.S)
+    hay = m.group(1) if m else p
+    best = None; best_pos = len(hay) + 1
+    for a in ANIMALS:
+        mm = re.search(r'\b' + a + r'(?:s|es)?\b', hay)
+        if mm and mm.start() < best_pos:
+            best, best_pos = a, mm.start()
+    if best:
+        return ANIMAL_PLURAL.get(best, best.capitalize() + 's')
+    return None
+
+# Witty bacchanal nouns for drunk-animals; serene for stoned; grand for murals.
+ANIMAL_NOUNS = {
+    'drunk-animals':  ['Carouse', 'Tipple', 'Soirée', 'Revel', 'Nightcap',
+                       'Bacchanal', 'Spree', 'Toast', 'Saunter', 'Folly'],
+    'stoned-animals': ['Reverie', 'Daydream', 'Halcyon', 'Vespers', 'Lullaby',
+                       'Drift', 'Idyll', 'Repose', 'Slumber', 'Haze'],
+    'mural-animals':  ['Menagerie', 'Pavillon', 'Tableau', 'Procession',
+                       'Chinoiserie', 'Allée', 'Aviary', 'Court', 'Salon', 'Frieze'],
+}
+
 NOUNS = {
     'floral':    ['Botanical', 'Bouquet', 'Blossom', 'Garden', 'Floret'],
     'geometric': ['Lattice', 'Tessellation', 'Geometry', 'Meridian', 'Fan'],
@@ -64,11 +144,19 @@ NOUNS = {
     'mural-scenic':   ['Scenic', 'Panorama', 'Vista', 'Frieze', 'Tapestry',
                        'Folly', 'Allée', 'Belvedere', 'Promenade', 'Pavillon']
 }
-def title_for(cat, hex_, id_):
+def title_for(cat, hex_, id_, prompt=None):
+    color = colorway_name(hex_)
+    # Animal categories: name from the actual creature → "Peacock Carouse in Verdigris"
+    if cat in ANIMAL_NOUNS:
+        animal = animal_in(prompt)
+        noun = ANIMAL_NOUNS[cat][id_ % len(ANIMAL_NOUNS[cat])]
+        if animal:
+            return f"{animal} {noun} in {color}"
+        return f"{color} {noun} No.{id_}"
+    # Everything else: keep the colorway + category noun + No.{id}
     pool = NOUNS.get(cat, NOUNS['mixed'])
-    hue = hue_name(hex_)
     noun = pool[id_ % len(pool)]
-    return f"{hue} {noun} No.{id_}"
+    return f"{color} {noun} No.{id_}"
 
 rows = psql_json(
     "SELECT COALESCE(json_agg(t),'[]'::json) FROM ("
@@ -139,7 +227,7 @@ for r in rows:
         "category": r['category'],
         "dominant_hex": r['dominant_hex'],
         "saturation": round(s, 3),
-        "title": title_for(r['category'], r['dominant_hex'] or '', r['id']),
+        "title": title_for(r['category'], r['dominant_hex'] or '', r['id'], r.get('prompt')),
         "handle": f"wallco-{r['id']:04d}",
         "image_url": f"/designs/img/{filename}",
         "filename": filename,

← 71b98af generator: user-chosen batch size renders server-side in bac  ·  back to Wallco Ai  ·  Publish luxe-v2 batch L2 image-reviewed (41576,41844,41868,4 c8fc9a6 →