← back to CelebritySignatures
wear: auto-detect campaign-<slug>.jpg for the 'worn' shot instead of a hardcoded map
d8381ce41a569442ba5f99a52b16cac8586bfd33 · 2026-09-09 16:50:29 -0700 · Steve
Per peer coordination (celebritysignatures-e9 owns generation + naming): derive
slug candidates from the signer's name (surname / joined last-two / full / first,
+ overrides for vangogh & frida) and probe which campaign-<slug>.jpg exists, so
every shot the pipeline generates (Shakespeare, da Vinci, Goethe, … the top 50)
surfaces on its product page automatically with no code change. Fixes Lincoln to
use campaign-lincoln.jpg (was pointing at -seated). Verified Darwin/Lincoln worn,
Shakespeare no-shot, 0 errors. Local only, not deployed. Reverse: git revert HEAD.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
Diff
commit d8381ce41a569442ba5f99a52b16cac8586bfd33
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Sep 9 16:50:29 2026 -0700
wear: auto-detect campaign-<slug>.jpg for the 'worn' shot instead of a hardcoded map
Per peer coordination (celebritysignatures-e9 owns generation + naming): derive
slug candidates from the signer's name (surname / joined last-two / full / first,
+ overrides for vangogh & frida) and probe which campaign-<slug>.jpg exists, so
every shot the pipeline generates (Shakespeare, da Vinci, Goethe, … the top 50)
surfaces on its product page automatically with no code change. Fixes Lincoln to
use campaign-lincoln.jpg (was pointing at -seated). Verified Darwin/Lincoln worn,
Shakespeare no-shot, 0 errors. Local only, not deployed. Reverse: git revert HEAD.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
public/wear.html | 55 +++++++++++++++++++++++++++++++++++++------------------
1 file changed, 37 insertions(+), 18 deletions(-)
diff --git a/public/wear.html b/public/wear.html
index 8ee1810..848d8b2 100644
--- a/public/wear.html
+++ b/public/wear.html
@@ -223,17 +223,27 @@ const INK_PRESETS = [
{ id:'white', label:'White', hex:'#ffffff' },
];
// Editorial "worn" shots — the celebrity seated in the full Signature Edit
-// (AI-generated). Only some signers have one; matched by name. Non-wear-eligible
-// names (Einstein etc.) never reach /wear, so listing them is harmless.
-const LIFESTYLE = [
- ['charles darwin','darwin'], ['benjamin franklin','franklin'], ['abraham lincoln','lincoln-seated'],
- ['napoleon','napoleon'], ['michelangelo','michelangelo'], ['van gogh','vangogh'],
- ['albert einstein','einstein'], ['frida','frida'], ['pablo picasso','picasso'], ['mark twain','twain'],
-];
-function lifestyleFor(sig){
- const n = (sig && sig.full_name || '').toLowerCase();
- const hit = LIFESTYLE.find(([m]) => n.includes(m));
- return hit ? `/assets/campaign-${hit[1]}.jpg` : null;
+// (AI-generated, named /assets/campaign-<slug>.jpg by the campaign pipeline).
+// Rather than hardcode a name→file map (which wouldn't pick up newly generated
+// shots), AUTO-DETECT: derive candidate slugs from the person's name and probe
+// which campaign-<slug>.jpg actually exists. Handles the naming quirks — some
+// files are keyed on the surname (darwin, napoleon), some on a joined full
+// surname (vangogh), some on a first name (frida). A few explicit overrides
+// pin the non-obvious existing files.
+const LIFESTYLE_OVERRIDE = { 'vincent van gogh':'vangogh', 'frida kahlo':'frida' };
+function lifestyleCandidates(name){
+ const n = (name || '').toLowerCase().replace(/[^a-z ]/g,'').trim();
+ if (!n) return [];
+ const cands = [];
+ if (LIFESTYLE_OVERRIDE[n]) cands.push(LIFESTYLE_OVERRIDE[n]);
+ const parts = n.split(/\s+/).filter(Boolean);
+ if (parts.length){
+ cands.push(parts[parts.length-1]); // surname (darwin, lincoln, shakespeare)
+ if (parts.length >= 2) cands.push(parts.slice(-2).join('')); // joined last two (vangogh)
+ cands.push(parts.join('')); // full name joined (leonardodavinci)
+ cands.push(parts[0]); // first name (frida)
+ }
+ return [...new Set(cands)].filter(Boolean);
}
// Toggle the modal's left visual between the editorial "worn" shot and the
// interactive garment mockup.
@@ -247,14 +257,23 @@ function setLifeView(mode){
document.getElementById('lifestyleToggle').textContent = worn ? 'See on garment' : 'See it worn';
}
function applyLifestyle(){
- const url = lifestyleFor(state.sig);
const shot = document.getElementById('lifestyleShot'), tog = document.getElementById('lifestyleToggle');
- if (url){
- shot.src = url; shot.alt = `${state.sig.full_name} in the Signature Edit`;
- tog.hidden = false; setLifeView('worn'); // lead with the editorial shot
- } else {
- tog.hidden = true; shot.hidden = true; shot.removeAttribute('src'); setLifeView('garment');
- }
+ // Default to the garment mockup; probe for a worn shot and switch in if found.
+ tog.hidden = true; shot.hidden = true; shot.removeAttribute('src'); setLifeView('garment');
+ const sig = state.sig;
+ const cands = lifestyleCandidates(sig && sig.full_name);
+ (function tryNext(i){
+ if (i >= cands.length || state.sig !== sig) return;
+ const url = `/assets/campaign-${cands[i]}.jpg`;
+ const probe = new Image();
+ probe.onload = () => {
+ if (state.sig !== sig) return; // signer changed while probing
+ shot.src = url; shot.alt = `${sig.full_name} in the Signature Edit`;
+ tog.hidden = false; setLifeView('worn'); // lead with the editorial shot
+ };
+ probe.onerror = () => tryNext(i + 1);
+ probe.src = url;
+ })(0);
}
// Top-level HTML-attribute escape (the autocomplete's own `esc` is scoped to
// that block, so the grid renderer needs its own).
← 523cb04 wear: 'See it worn' — feature each celebrity's seated editor
·
back to CelebritySignatures
·
wear: accent-fold worn-shot slug candidates (Velázquez→velaz 22b0eba →