← back to CelebritySignatures
add 27 themed signature murals (Wikidata P109 sigs + Met PD art) → 30 murals on /murals; catalog-roster drawer
5af58db1fdbe583e8b1895c3931c663318c32869 · 2026-06-19 10:45:22 -0700 · SteveStudio2
Files touched
M .gitignoreA data/mural-themes.jsonM data/murals-catalog.jsonA output/collage-abolitionists-named.pngA output/collage-abolitionists.pngA output/collage-american-authors-named.pngA output/collage-american-authors.pngA output/collage-american-presidents-named.pngA output/collage-american-presidents.pngA output/collage-astronomers-named.pngA output/collage-astronomers.pngA output/collage-aviation-pioneers-named.pngA output/collage-aviation-pioneers.pngA output/collage-composers-named.pngA output/collage-composers.pngA output/collage-economists-named.pngA output/collage-economists.pngA output/collage-european-statesmen-named.pngA output/collage-european-statesmen.pngA output/collage-explorers-navigators-named.pngA output/collage-explorers-navigators.pngA output/collage-founding-fathers-named.pngA output/collage-founding-fathers.pngA output/collage-generals-commanders-named.pngA output/collage-generals-commanders.pngA output/collage-industrialists-named.pngA output/collage-industrialists.pngA output/collage-mathematicians-named.pngA output/collage-mathematicians.pngA output/collage-medicine-named.pngA output/collage-medicine.pngA output/collage-monarchs-named.pngA output/collage-monarchs.pngA output/collage-naturalists-named.pngA output/collage-naturalists.pngA output/collage-nobel-laureates-named.pngA output/collage-nobel-laureates.pngA output/collage-painters-artists-named.pngA output/collage-painters-artists.pngA output/collage-philosophers-named.pngA output/collage-philosophers.pngA output/collage-physicists-named.pngA output/collage-physicists.pngA output/collage-playwrights-named.pngA output/collage-playwrights.pngA output/collage-poets-named.pngA output/collage-poets.pngA output/collage-renaissance-masters-named.pngA output/collage-renaissance-masters.pngA output/collage-revolutionaries-named.pngA output/collage-revolutionaries.pngA output/collage-scientists-inventors-named.pngA output/collage-scientists-inventors.pngA output/collage-suffragists-named.pngA output/collage-suffragists.pngA output/collage-writers-novelists-named.pngA output/collage-writers-novelists.pngM public/murals.htmlA scripts/build-theme-murals.py
Diff
commit 5af58db1fdbe583e8b1895c3931c663318c32869
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Fri Jun 19 10:45:22 2026 -0700
add 27 themed signature murals (Wikidata P109 sigs + Met PD art) → 30 murals on /murals; catalog-roster drawer
---
.gitignore | 1 +
data/mural-themes.json | 29 ++
data/murals-catalog.json | 519 ++++++++++++++++++++++++++
output/collage-abolitionists-named.png | Bin 0 -> 144974 bytes
output/collage-abolitionists.png | Bin 0 -> 134138 bytes
output/collage-american-authors-named.png | Bin 0 -> 208004 bytes
output/collage-american-authors.png | Bin 0 -> 189068 bytes
output/collage-american-presidents-named.png | Bin 0 -> 140171 bytes
output/collage-american-presidents.png | Bin 0 -> 126628 bytes
output/collage-astronomers-named.png | Bin 0 -> 134716 bytes
output/collage-astronomers.png | Bin 0 -> 125376 bytes
output/collage-aviation-pioneers-named.png | Bin 0 -> 153200 bytes
output/collage-aviation-pioneers.png | Bin 0 -> 141931 bytes
output/collage-composers-named.png | Bin 0 -> 215661 bytes
output/collage-composers.png | Bin 0 -> 195107 bytes
output/collage-economists-named.png | Bin 0 -> 123587 bytes
output/collage-economists.png | Bin 0 -> 114283 bytes
output/collage-european-statesmen-named.png | Bin 0 -> 199801 bytes
output/collage-european-statesmen.png | Bin 0 -> 183159 bytes
output/collage-explorers-navigators-named.png | Bin 0 -> 212707 bytes
output/collage-explorers-navigators.png | Bin 0 -> 199160 bytes
output/collage-founding-fathers-named.png | Bin 0 -> 170855 bytes
output/collage-founding-fathers.png | Bin 0 -> 159261 bytes
output/collage-generals-commanders-named.png | Bin 0 -> 183078 bytes
output/collage-generals-commanders.png | Bin 0 -> 166478 bytes
output/collage-industrialists-named.png | Bin 0 -> 130926 bytes
output/collage-industrialists.png | Bin 0 -> 120740 bytes
output/collage-mathematicians-named.png | Bin 0 -> 143455 bytes
output/collage-mathematicians.png | Bin 0 -> 132466 bytes
output/collage-medicine-named.png | Bin 0 -> 168137 bytes
output/collage-medicine.png | Bin 0 -> 155530 bytes
output/collage-monarchs-named.png | Bin 0 -> 200847 bytes
output/collage-monarchs.png | Bin 0 -> 186803 bytes
output/collage-naturalists-named.png | Bin 0 -> 153188 bytes
output/collage-naturalists.png | Bin 0 -> 143412 bytes
output/collage-nobel-laureates-named.png | Bin 0 -> 159137 bytes
output/collage-nobel-laureates.png | Bin 0 -> 144155 bytes
output/collage-painters-artists-named.png | Bin 0 -> 153044 bytes
output/collage-painters-artists.png | Bin 0 -> 138809 bytes
output/collage-philosophers-named.png | Bin 0 -> 185271 bytes
output/collage-philosophers.png | Bin 0 -> 170013 bytes
output/collage-physicists-named.png | Bin 0 -> 169321 bytes
output/collage-physicists.png | Bin 0 -> 154068 bytes
output/collage-playwrights-named.png | Bin 0 -> 158163 bytes
output/collage-playwrights.png | Bin 0 -> 142907 bytes
output/collage-poets-named.png | Bin 0 -> 202655 bytes
output/collage-poets.png | Bin 0 -> 187706 bytes
output/collage-renaissance-masters-named.png | Bin 0 -> 133108 bytes
output/collage-renaissance-masters.png | Bin 0 -> 123698 bytes
output/collage-revolutionaries-named.png | Bin 0 -> 160302 bytes
output/collage-revolutionaries.png | Bin 0 -> 147820 bytes
output/collage-scientists-inventors-named.png | Bin 0 -> 199216 bytes
output/collage-scientists-inventors.png | Bin 0 -> 182198 bytes
output/collage-suffragists-named.png | Bin 0 -> 126243 bytes
output/collage-suffragists.png | Bin 0 -> 117447 bytes
output/collage-writers-novelists-named.png | Bin 0 -> 213034 bytes
output/collage-writers-novelists.png | Bin 0 -> 194794 bytes
public/murals.html | 9 +-
scripts/build-theme-murals.py | 205 ++++++++++
59 files changed, 762 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index 9681475..e966f20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,4 @@ data/sessions.json
.deploy.conf
tmp_oldest_cache/
+tmp_theme_cache/
diff --git a/data/mural-themes.json b/data/mural-themes.json
new file mode 100644
index 0000000..82338d2
--- /dev/null
+++ b/data/mural-themes.json
@@ -0,0 +1,29 @@
+[
+ {"code":"si","slug":"scientists-inventors","title":"Scientists & Inventors","blurb":"The minds who remade the modern world, in their own hand.","met_query":"scientific instrument astrolabe","roster":["Thomas Edison","Nikola Tesla","Albert Einstein","Isaac Newton","Charles Darwin","Louis Pasteur","Marie Curie","Michael Faraday","Benjamin Franklin","Alessandro Volta","Alexander Graham Bell","Samuel Morse","Galileo Galilei","George Washington Carver"]},
+ {"code":"co","slug":"composers","title":"Great Composers","blurb":"The signatures behind the symphonies — Bach to Mahler.","met_query":"musical instrument violin","roster":["Wolfgang Amadeus Mozart","Ludwig van Beethoven","Johann Sebastian Bach","Frederic Chopin","Richard Wagner","Giuseppe Verdi","Johannes Brahms","Franz Liszt","Pyotr Ilyich Tchaikovsky","George Frideric Handel","Joseph Haydn","Franz Schubert","Gustav Mahler","Claude Debussy"]},
+ {"code":"wr","slug":"writers-novelists","title":"Writers & Novelists","blurb":"The hands that wrote the canon — Austen to Tolstoy.","met_query":"illuminated manuscript book","roster":["Charles Dickens","Mark Twain","Leo Tolstoy","Fyodor Dostoevsky","Victor Hugo","Alexandre Dumas","Jane Austen","Edgar Allan Poe","Nathaniel Hawthorne","Herman Melville","Oscar Wilde","Arthur Conan Doyle","Robert Louis Stevenson","Jules Verne"]},
+ {"code":"po","slug":"poets","title":"The Poets","blurb":"Romantics and visionaries — every verse signed.","met_query":"Romantic landscape painting","roster":["William Wordsworth","Lord Byron","John Keats","Percy Bysshe Shelley","Walt Whitman","Alfred Tennyson","Henry Wadsworth Longfellow","Samuel Taylor Coleridge","Johann Wolfgang von Goethe","Robert Burns","William Blake","Elizabeth Barrett Browning","William Butler Yeats"]},
+ {"code":"ph","slug":"philosophers","title":"Philosophers","blurb":"The architects of thought — Descartes to Nietzsche.","met_query":"ancient Greek bust marble","roster":["Immanuel Kant","Voltaire","Jean-Jacques Rousseau","Friedrich Nietzsche","David Hume","John Locke","Rene Descartes","Arthur Schopenhauer","John Stuart Mill","Francis Bacon","Baruch Spinoza","Georg Wilhelm Friedrich Hegel"]},
+ {"code":"pa","slug":"painters-artists","title":"Painters & Masters","blurb":"The signatures of the easel — Rembrandt to Van Gogh.","met_query":"old master oil painting","roster":["Rembrandt van Rijn","Peter Paul Rubens","Vincent van Gogh","Claude Monet","Pierre-Auguste Renoir","Paul Cezanne","Edgar Degas","Francisco Goya","Eugene Delacroix","Edouard Manet","Paul Gauguin","J. M. W. Turner","John Singer Sargent"]},
+ {"code":"ex","slug":"explorers-navigators","title":"Explorers & Navigators","blurb":"The hands that charted the world.","met_query":"antique navigation globe map","roster":["Christopher Columbus","Ferdinand Magellan","James Cook","Francis Drake","Amerigo Vespucci","Samuel de Champlain","Hernan Cortes","Meriwether Lewis","William Clark","Henry Hudson","Vasco da Gama"]},
+ {"code":"ge","slug":"generals-commanders","title":"Generals & Commanders","blurb":"The signatures that moved armies.","met_query":"arms and armor sword","roster":["Napoleon Bonaparte","Duke of Wellington","George Washington","Ulysses S. Grant","Robert E. Lee","Horatio Nelson","Giuseppe Garibaldi","Simon Bolivar","Marquis de Lafayette","William Tecumseh Sherman","John J. Pershing"]},
+ {"code":"mo","slug":"monarchs","title":"Monarchs & Royalty","blurb":"Kings and queens — sovereign hands across the centuries.","met_query":"royal crown jewelry portrait","roster":["Henry VIII of England","Elizabeth I of England","Louis XIV of France","Queen Victoria","Catherine the Great","Frederick the Great","Charles I of England","Marie Antoinette","Philip II of Spain","Napoleon Bonaparte"]},
+ {"code":"py","slug":"physicists","title":"Physicists","blurb":"From classical mechanics to the quantum age.","met_query":"scientific instrument brass","roster":["Albert Einstein","Isaac Newton","Niels Bohr","Max Planck","James Clerk Maxwell","Michael Faraday","Marie Curie","Ernest Rutherford","Erwin Schrodinger","Enrico Fermi","Nikola Tesla"]},
+ {"code":"ma","slug":"mathematicians","title":"Mathematicians","blurb":"The signatures behind the theorems.","met_query":"astrolabe geometry instrument","roster":["Carl Friedrich Gauss","Leonhard Euler","Isaac Newton","Gottfried Wilhelm Leibniz","Blaise Pascal","Pierre-Simon Laplace","Bernhard Riemann","Henri Poincare","David Hilbert","Georg Cantor"]},
+ {"code":"na","slug":"naturalists","title":"Naturalists","blurb":"The observers of the living world.","met_query":"Audubon bird natural history print","roster":["Charles Darwin","John James Audubon","Alexander von Humboldt","Alfred Russel Wallace","Carl Linnaeus","Gregor Mendel","John Muir","Louis Agassiz","Luther Burbank"]},
+ {"code":"as","slug":"astronomers","title":"Astronomers","blurb":"The hands that mapped the heavens.","met_query":"celestial globe astronomy","roster":["Galileo Galilei","Johannes Kepler","Nicolaus Copernicus","Isaac Newton","William Herschel","Edmond Halley","Tycho Brahe","Edwin Hubble","Camille Flammarion"]},
+ {"code":"av","slug":"aviation-pioneers","title":"Aviation Pioneers","blurb":"The first to sign the sky.","met_query":"early aviation flight","roster":["Wilbur Wright","Orville Wright","Charles Lindbergh","Amelia Earhart","Alberto Santos-Dumont","Louis Bleriot","Ferdinand von Zeppelin","Eddie Rickenbacker","Jimmy Doolittle"]},
+ {"code":"ab","slug":"abolitionists","title":"Abolition & Liberty","blurb":"The signatures that helped end slavery.","met_query":"19th century American history","roster":["Frederick Douglass","Abraham Lincoln","Harriet Beecher Stowe","William Lloyd Garrison","John Brown","Sojourner Truth","William Wilberforce","Charles Sumner","Wendell Phillips"]},
+ {"code":"su","slug":"suffragists","title":"Suffragists & Pioneers","blurb":"Women who signed history forward.","met_query":"19th century portrait woman","roster":["Susan B. Anthony","Elizabeth Cady Stanton","Emmeline Pankhurst","Florence Nightingale","Clara Barton","Marie Curie","Helen Keller","Lucretia Mott","Ida B. Wells"]},
+ {"code":"re","slug":"renaissance-masters","title":"Renaissance Masters","blurb":"The hands of the rebirth — Leonardo to Machiavelli.","met_query":"Italian Renaissance drawing","roster":["Leonardo da Vinci","Michelangelo Buonarroti","Galileo Galilei","Albrecht Durer","Niccolo Machiavelli","Desiderius Erasmus","Nicolaus Copernicus","Titian","Raphael"]},
+ {"code":"pl","slug":"playwrights","title":"Playwrights","blurb":"The dramatists, signed and staged.","met_query":"theater mask drama","roster":["William Shakespeare","Moliere","Johann Wolfgang von Goethe","Friedrich Schiller","Henrik Ibsen","Anton Chekhov","Oscar Wilde","George Bernard Shaw","Christopher Marlowe"]},
+ {"code":"ec","slug":"economists","title":"Economists & Thinkers","blurb":"The signatures behind the wealth of nations.","met_query":"18th century engraving portrait","roster":["Adam Smith","Karl Marx","David Ricardo","John Maynard Keynes","Thomas Robert Malthus","John Stuart Mill","Jeremy Bentham","Friedrich Engels"]},
+ {"code":"in","slug":"industrialists","title":"Industrialists & Tycoons","blurb":"The hands that built the Gilded Age.","met_query":"Gilded Age decorative arts","roster":["Andrew Carnegie","John D. Rockefeller","Cornelius Vanderbilt","J. P. Morgan","Henry Ford","Thomas Edison","George Westinghouse","John Jacob Astor"]},
+ {"code":"aa","slug":"american-authors","title":"American Authors","blurb":"The signatures that built American letters — Irving to London.","met_query":"American 19th century painting","roster":["Mark Twain","Edgar Allan Poe","Nathaniel Hawthorne","Herman Melville","Walt Whitman","Ralph Waldo Emerson","Henry David Thoreau","Washington Irving","James Fenimore Cooper","Harriet Beecher Stowe","Jack London","Louisa May Alcott","Henry Wadsworth Longfellow"]},
+ {"code":"ff","slug":"founding-fathers","title":"Founding Fathers","blurb":"The architects of the American republic.","met_query":"American Federal period portrait","roster":["George Washington","Thomas Jefferson","Benjamin Franklin","John Adams","James Madison","Alexander Hamilton","John Jay","James Monroe","Patrick Henry","Thomas Paine"]},
+ {"code":"pr","slug":"american-presidents","title":"American Presidents","blurb":"Executive signatures across two centuries.","met_query":"American presidential portrait","roster":["George Washington","Thomas Jefferson","Abraham Lincoln","Theodore Roosevelt","Andrew Jackson","Ulysses S. Grant","Woodrow Wilson","Franklin D. Roosevelt","Grover Cleveland","William McKinley"]},
+ {"code":"rv","slug":"revolutionaries","title":"Revolutionaries","blurb":"The hands that overturned the old order.","met_query":"French Revolution print","roster":["Maximilien Robespierre","Georges Danton","Jean-Paul Marat","Simon Bolivar","Jose de San Martin","Giuseppe Garibaldi","Vladimir Lenin","Sun Yat-sen","Lajos Kossuth"]},
+ {"code":"nl","slug":"nobel-laureates","title":"Nobel Laureates","blurb":"Early signatures of the prize.","met_query":"medal portrait engraving","roster":["Marie Curie","Albert Einstein","Theodore Roosevelt","Rudyard Kipling","Ernest Rutherford","Max Planck","Rabindranath Tagore","George Bernard Shaw","Guglielmo Marconi","Ivan Pavlov"]},
+ {"code":"md","slug":"medicine","title":"Medicine & Healers","blurb":"The signatures that conquered disease.","met_query":"medical instrument apothecary","roster":["Louis Pasteur","Joseph Lister","Robert Koch","Edward Jenner","Alexander Fleming","Florence Nightingale","William Harvey","William Osler","Sigmund Freud"]},
+ {"code":"es","slug":"european-statesmen","title":"European Statesmen","blurb":"The hands that steered nations — Talleyrand to Churchill.","met_query":"19th century European portrait","roster":["Otto von Bismarck","William Ewart Gladstone","Benjamin Disraeli","Klemens von Metternich","Winston Churchill","Georges Clemenceau","Camillo Benso di Cavour","Charles Maurice de Talleyrand","Robert Peel","Giuseppe Mazzini","Lord Palmerston","Charles de Gaulle"]}
+]
diff --git a/data/murals-catalog.json b/data/murals-catalog.json
index bad0cfb..9e57fb2 100644
--- a/data/murals-catalog.json
+++ b/data/murals-catalog.json
@@ -30,6 +30,525 @@
"title": "Politics & Statecraft",
"blurb": "Presidents, premiers and world leaders across two centuries.",
"sigs": 53
+ },
+ {
+ "code": "si",
+ "slug": "scientists-inventors",
+ "title": "Scientists & Inventors",
+ "blurb": "The minds who remade the modern world, in their own hand.",
+ "sigs": 13,
+ "roster": [
+ "Thomas Edison",
+ "Nikola Tesla",
+ "Albert Einstein",
+ "Isaac Newton",
+ "Charles Darwin",
+ "Louis Pasteur",
+ "Marie Curie",
+ "Michael Faraday",
+ "Benjamin Franklin",
+ "Alexander Graham Bell",
+ "Samuel Morse",
+ "Galileo Galilei",
+ "George Washington Carver"
+ ],
+ "met_accent": "Barometer"
+ },
+ {
+ "code": "co",
+ "slug": "composers",
+ "title": "Great Composers",
+ "blurb": "The signatures behind the symphonies — Bach to Mahler.",
+ "sigs": 14,
+ "roster": [
+ "Wolfgang Amadeus Mozart",
+ "Ludwig van Beethoven",
+ "Johann Sebastian Bach",
+ "Frederic Chopin",
+ "Richard Wagner",
+ "Giuseppe Verdi",
+ "Johannes Brahms",
+ "Franz Liszt",
+ "Pyotr Ilyich Tchaikovsky",
+ "George Frideric Handel",
+ "Joseph Haydn",
+ "Franz Schubert",
+ "Gustav Mahler",
+ "Claude Debussy"
+ ],
+ "met_accent": "Drum"
+ },
+ {
+ "code": "wr",
+ "slug": "writers-novelists",
+ "title": "Writers & Novelists",
+ "blurb": "The hands that wrote the canon — Austen to Tolstoy.",
+ "sigs": 14,
+ "roster": [
+ "Charles Dickens",
+ "Mark Twain",
+ "Leo Tolstoy",
+ "Fyodor Dostoevsky",
+ "Victor Hugo",
+ "Alexandre Dumas",
+ "Jane Austen",
+ "Edgar Allan Poe",
+ "Nathaniel Hawthorne",
+ "Herman Melville",
+ "Oscar Wilde",
+ "Arthur Conan Doyle",
+ "Robert Louis Stevenson",
+ "Jules Verne"
+ ],
+ "met_accent": "Jaharis Byzantine Lectionary"
+ },
+ {
+ "code": "po",
+ "slug": "poets",
+ "title": "The Poets",
+ "blurb": "Romantics and visionaries — every verse signed.",
+ "sigs": 10,
+ "roster": [
+ "Lord Byron",
+ "John Keats",
+ "Percy Bysshe Shelley",
+ "Walt Whitman",
+ "Henry Wadsworth Longfellow",
+ "Samuel Taylor Coleridge",
+ "Johann Wolfgang von Goethe",
+ "Robert Burns",
+ "William Blake",
+ "William Butler Yeats"
+ ],
+ "met_accent": "Evening: Landscape with an Aqueduct"
+ },
+ {
+ "code": "ph",
+ "slug": "philosophers",
+ "title": "Philosophers",
+ "blurb": "The architects of thought — Descartes to Nietzsche.",
+ "sigs": 10,
+ "roster": [
+ "Immanuel Kant",
+ "Voltaire",
+ "Jean-Jacques Rousseau",
+ "Friedrich Nietzsche",
+ "John Locke",
+ "Rene Descartes",
+ "Arthur Schopenhauer",
+ "John Stuart Mill",
+ "Baruch Spinoza",
+ "Georg Wilhelm Friedrich Hegel"
+ ],
+ "met_accent": "Aristotle with a Bust of Homer"
+ },
+ {
+ "code": "pa",
+ "slug": "painters-artists",
+ "title": "Painters & Masters",
+ "blurb": "The signatures of the easel — Rembrandt to Van Gogh.",
+ "sigs": 10,
+ "roster": [
+ "Claude Monet",
+ "Pierre-Auguste Renoir",
+ "Paul Cezanne",
+ "Edgar Degas",
+ "Francisco Goya",
+ "Eugene Delacroix",
+ "Edouard Manet",
+ "Paul Gauguin",
+ "J. M. W. Turner",
+ "John Singer Sargent"
+ ],
+ "met_accent": "Rothschild lamp"
+ },
+ {
+ "code": "ex",
+ "slug": "explorers-navigators",
+ "title": "Explorers & Navigators",
+ "blurb": "The hands that charted the world.",
+ "sigs": 9,
+ "roster": [
+ "Christopher Columbus",
+ "Ferdinand Magellan",
+ "James Cook",
+ "Francis Drake",
+ "Samuel de Champlain",
+ "Hernan Cortes",
+ "Meriwether Lewis",
+ "William Clark",
+ "Vasco da Gama"
+ ],
+ "met_accent": "Lucas van Uffel (died 1637)"
+ },
+ {
+ "code": "ge",
+ "slug": "generals-commanders",
+ "title": "Generals & Commanders",
+ "blurb": "The signatures that moved armies.",
+ "sigs": 10,
+ "roster": [
+ "Napoleon Bonaparte",
+ "Duke of Wellington",
+ "Ulysses S. Grant",
+ "Robert E. Lee",
+ "Horatio Nelson",
+ "Giuseppe Garibaldi",
+ "Simon Bolivar",
+ "Marquis de Lafayette",
+ "William Tecumseh Sherman",
+ "John J. Pershing"
+ ],
+ "met_accent": "Pair of Four-Barreled Turnover Percussion Pistols of Henry Pelham Fiennes Pelham-Clinton, 4th Duke of Newcastle-under-Lyne (1785–1851), with Pair of Box-Lock Turn-Off Pocket Pistols, Case, and Accessories"
+ },
+ {
+ "code": "mo",
+ "slug": "monarchs",
+ "title": "Monarchs & Royalty",
+ "blurb": "Kings and queens — sovereign hands across the centuries.",
+ "sigs": 9,
+ "roster": [
+ "Henry VIII of England",
+ "Elizabeth I of England",
+ "Louis XIV of France",
+ "Queen Victoria",
+ "Catherine the Great",
+ "Frederick the Great",
+ "Charles I of England",
+ "Philip II of Spain",
+ "Napoleon Bonaparte"
+ ],
+ "met_accent": "Standing Figure with Feathered Headdress"
+ },
+ {
+ "code": "py",
+ "slug": "physicists",
+ "title": "Physicists",
+ "blurb": "From classical mechanics to the quantum age.",
+ "sigs": 11,
+ "roster": [
+ "Albert Einstein",
+ "Isaac Newton",
+ "Niels Bohr",
+ "Max Planck",
+ "James Clerk Maxwell",
+ "Michael Faraday",
+ "Marie Curie",
+ "Ernest Rutherford",
+ "Erwin Schrodinger",
+ "Enrico Fermi",
+ "Nikola Tesla"
+ ],
+ "met_accent": "Altar bell with Portuguese heads"
+ },
+ {
+ "code": "ma",
+ "slug": "mathematicians",
+ "title": "Mathematicians",
+ "blurb": "The signatures behind the theorems.",
+ "sigs": 8,
+ "roster": [
+ "Carl Friedrich Gauss",
+ "Leonhard Euler",
+ "Isaac Newton",
+ "Gottfried Wilhelm Leibniz",
+ "Blaise Pascal",
+ "Pierre-Simon Laplace",
+ "Bernhard Riemann",
+ "Henri Poincare"
+ ],
+ "met_accent": "Celestial globe with clockwork"
+ },
+ {
+ "code": "na",
+ "slug": "naturalists",
+ "title": "Naturalists",
+ "blurb": "The observers of the living world.",
+ "sigs": 6,
+ "roster": [
+ "Charles Darwin",
+ "John James Audubon",
+ "Alexander von Humboldt",
+ "Alfred Russel Wallace",
+ "Carl Linnaeus",
+ "Luther Burbank"
+ ],
+ "met_accent": "Flowers in a Grotesque Vase"
+ },
+ {
+ "code": "as",
+ "slug": "astronomers",
+ "title": "Astronomers",
+ "blurb": "The hands that mapped the heavens.",
+ "sigs": 7,
+ "roster": [
+ "Galileo Galilei",
+ "Johannes Kepler",
+ "Nicolaus Copernicus",
+ "Isaac Newton",
+ "William Herschel",
+ "Tycho Brahe",
+ "Edwin Hubble"
+ ],
+ "met_accent": "Celestial globe with clockwork"
+ },
+ {
+ "code": "av",
+ "slug": "aviation-pioneers",
+ "title": "Aviation Pioneers",
+ "blurb": "The first to sign the sky.",
+ "sigs": 8,
+ "roster": [
+ "Wilbur Wright",
+ "Orville Wright",
+ "Charles Lindbergh",
+ "Amelia Earhart",
+ "Alberto Santos-Dumont",
+ "Louis Bleriot",
+ "Ferdinand von Zeppelin",
+ "Eddie Rickenbacker"
+ ],
+ "met_accent": "Portrait of a Noblewoman, Probably Isabella of Portugal (1397–1472)"
+ },
+ {
+ "code": "ab",
+ "slug": "abolitionists",
+ "title": "Abolition & Liberty",
+ "blurb": "The signatures that helped end slavery.",
+ "sigs": 7,
+ "roster": [
+ "Frederick Douglass",
+ "Abraham Lincoln",
+ "Harriet Beecher Stowe",
+ "John Brown",
+ "William Wilberforce",
+ "Charles Sumner",
+ "Wendell Phillips"
+ ],
+ "met_accent": "Madame Georges Charpentier (Marguerite-Louise Lemonnier, 1848–1904) and Her Children, Georgette-Berthe (1872–1945) and Paul-Emile-Charles (1875–1895)"
+ },
+ {
+ "code": "su",
+ "slug": "suffragists",
+ "title": "Suffragists & Pioneers",
+ "blurb": "Women who signed history forward.",
+ "sigs": 6,
+ "roster": [
+ "Susan B. Anthony",
+ "Elizabeth Cady Stanton",
+ "Florence Nightingale",
+ "Clara Barton",
+ "Marie Curie",
+ "Helen Keller"
+ ],
+ "met_accent": "Portrait of Sor Juana de Nuestra Señora de Guadalupe"
+ },
+ {
+ "code": "re",
+ "slug": "renaissance-masters",
+ "title": "Renaissance Masters",
+ "blurb": "The hands of the rebirth — Leonardo to Machiavelli.",
+ "sigs": 7,
+ "roster": [
+ "Leonardo da Vinci",
+ "Michelangelo Buonarroti",
+ "Galileo Galilei",
+ "Albrecht Durer",
+ "Niccolo Machiavelli",
+ "Nicolaus Copernicus",
+ "Titian"
+ ],
+ "met_accent": "Pilgrim flask"
+ },
+ {
+ "code": "pl",
+ "slug": "playwrights",
+ "title": "Playwrights",
+ "blurb": "The dramatists, signed and staged.",
+ "sigs": 9,
+ "roster": [
+ "William Shakespeare",
+ "Moliere",
+ "Johann Wolfgang von Goethe",
+ "Friedrich Schiller",
+ "Henrik Ibsen",
+ "Anton Chekhov",
+ "Oscar Wilde",
+ "George Bernard Shaw",
+ "Christopher Marlowe"
+ ],
+ "met_accent": "Mask"
+ },
+ {
+ "code": "ec",
+ "slug": "economists",
+ "title": "Economists & Thinkers",
+ "blurb": "The signatures behind the wealth of nations.",
+ "sigs": 6,
+ "roster": [
+ "Adam Smith",
+ "Karl Marx",
+ "John Maynard Keynes",
+ "John Stuart Mill",
+ "Jeremy Bentham",
+ "Friedrich Engels"
+ ],
+ "met_accent": "Commode"
+ },
+ {
+ "code": "in",
+ "slug": "industrialists",
+ "title": "Industrialists & Tycoons",
+ "blurb": "The hands that built the Gilded Age.",
+ "sigs": 7,
+ "roster": [
+ "Andrew Carnegie",
+ "Cornelius Vanderbilt",
+ "J. P. Morgan",
+ "Henry Ford",
+ "Thomas Edison",
+ "George Westinghouse",
+ "John Jacob Astor"
+ ],
+ "met_accent": "Enameled and Gilded Bottle"
+ },
+ {
+ "code": "aa",
+ "slug": "american-authors",
+ "title": "American Authors",
+ "blurb": "The signatures that built American letters — Irving to London.",
+ "sigs": 13,
+ "roster": [
+ "Mark Twain",
+ "Edgar Allan Poe",
+ "Nathaniel Hawthorne",
+ "Herman Melville",
+ "Walt Whitman",
+ "Ralph Waldo Emerson",
+ "Henry David Thoreau",
+ "Washington Irving",
+ "James Fenimore Cooper",
+ "Harriet Beecher Stowe",
+ "Jack London",
+ "Louisa May Alcott",
+ "Henry Wadsworth Longfellow"
+ ],
+ "met_accent": "Portrait of Sor Juana de Nuestra Señora de Guadalupe"
+ },
+ {
+ "code": "ff",
+ "slug": "founding-fathers",
+ "title": "Founding Fathers",
+ "blurb": "The architects of the American republic.",
+ "sigs": 9,
+ "roster": [
+ "Thomas Jefferson",
+ "Benjamin Franklin",
+ "John Adams",
+ "James Madison",
+ "Alexander Hamilton",
+ "John Jay",
+ "James Monroe",
+ "Patrick Henry",
+ "Thomas Paine"
+ ],
+ "met_accent": "Desk and Bookcase"
+ },
+ {
+ "code": "pr",
+ "slug": "american-presidents",
+ "title": "American Presidents",
+ "blurb": "Executive signatures across two centuries.",
+ "sigs": 9,
+ "roster": [
+ "Thomas Jefferson",
+ "Abraham Lincoln",
+ "Theodore Roosevelt",
+ "Andrew Jackson",
+ "Ulysses S. Grant",
+ "Woodrow Wilson",
+ "Franklin D. Roosevelt",
+ "Grover Cleveland",
+ "William McKinley"
+ ],
+ "met_accent": "Life Mask of Abraham Lincoln"
+ },
+ {
+ "code": "rv",
+ "slug": "revolutionaries",
+ "title": "Revolutionaries",
+ "blurb": "The hands that overturned the old order.",
+ "sigs": 9,
+ "roster": [
+ "Maximilien Robespierre",
+ "Georges Danton",
+ "Jean-Paul Marat",
+ "Simon Bolivar",
+ "Jose de San Martin",
+ "Giuseppe Garibaldi",
+ "Vladimir Lenin",
+ "Sun Yat-sen",
+ "Lajos Kossuth"
+ ],
+ "met_accent": "Sabine Houdon (1787–1836)"
+ },
+ {
+ "code": "nl",
+ "slug": "nobel-laureates",
+ "title": "Nobel Laureates",
+ "blurb": "Early signatures of the prize.",
+ "sigs": 9,
+ "roster": [
+ "Marie Curie",
+ "Albert Einstein",
+ "Theodore Roosevelt",
+ "Rudyard Kipling",
+ "Ernest Rutherford",
+ "Max Planck",
+ "Rabindranath Tagore",
+ "George Bernard Shaw",
+ "Guglielmo Marconi"
+ ],
+ "met_accent": "Henry IV, King of France (b. 1553, r. 1589–1610)"
+ },
+ {
+ "code": "md",
+ "slug": "medicine",
+ "title": "Medicine & Healers",
+ "blurb": "The signatures that conquered disease.",
+ "sigs": 9,
+ "roster": [
+ "Louis Pasteur",
+ "Joseph Lister",
+ "Robert Koch",
+ "Edward Jenner",
+ "Alexander Fleming",
+ "Florence Nightingale",
+ "William Harvey",
+ "William Osler",
+ "Sigmund Freud"
+ ],
+ "met_accent": "Bronze instrument"
+ },
+ {
+ "code": "es",
+ "slug": "european-statesmen",
+ "title": "European Statesmen",
+ "blurb": "The hands that steered nations — Talleyrand to Churchill.",
+ "sigs": 10,
+ "roster": [
+ "Otto von Bismarck",
+ "William Ewart Gladstone",
+ "Benjamin Disraeli",
+ "Klemens von Metternich",
+ "Georges Clemenceau",
+ "Camillo Benso di Cavour",
+ "Charles Maurice de Talleyrand",
+ "Robert Peel",
+ "Giuseppe Mazzini",
+ "Charles de Gaulle"
+ ],
+ "met_accent": "Madame Georges Charpentier (Marguerite-Louise Lemonnier, 1848–1904) and Her Children, Georgette-Berthe (1872–1945) and Paul-Emile-Charles (1875–1895)"
}
]
}
\ No newline at end of file
diff --git a/output/collage-abolitionists-named.png b/output/collage-abolitionists-named.png
new file mode 100644
index 0000000..0cf87dc
Binary files /dev/null and b/output/collage-abolitionists-named.png differ
diff --git a/output/collage-abolitionists.png b/output/collage-abolitionists.png
new file mode 100644
index 0000000..b3365f0
Binary files /dev/null and b/output/collage-abolitionists.png differ
diff --git a/output/collage-american-authors-named.png b/output/collage-american-authors-named.png
new file mode 100644
index 0000000..68211a1
Binary files /dev/null and b/output/collage-american-authors-named.png differ
diff --git a/output/collage-american-authors.png b/output/collage-american-authors.png
new file mode 100644
index 0000000..bbc48ab
Binary files /dev/null and b/output/collage-american-authors.png differ
diff --git a/output/collage-american-presidents-named.png b/output/collage-american-presidents-named.png
new file mode 100644
index 0000000..4111dc1
Binary files /dev/null and b/output/collage-american-presidents-named.png differ
diff --git a/output/collage-american-presidents.png b/output/collage-american-presidents.png
new file mode 100644
index 0000000..467e04b
Binary files /dev/null and b/output/collage-american-presidents.png differ
diff --git a/output/collage-astronomers-named.png b/output/collage-astronomers-named.png
new file mode 100644
index 0000000..a6e7846
Binary files /dev/null and b/output/collage-astronomers-named.png differ
diff --git a/output/collage-astronomers.png b/output/collage-astronomers.png
new file mode 100644
index 0000000..3e5a203
Binary files /dev/null and b/output/collage-astronomers.png differ
diff --git a/output/collage-aviation-pioneers-named.png b/output/collage-aviation-pioneers-named.png
new file mode 100644
index 0000000..680cd54
Binary files /dev/null and b/output/collage-aviation-pioneers-named.png differ
diff --git a/output/collage-aviation-pioneers.png b/output/collage-aviation-pioneers.png
new file mode 100644
index 0000000..a24ea2e
Binary files /dev/null and b/output/collage-aviation-pioneers.png differ
diff --git a/output/collage-composers-named.png b/output/collage-composers-named.png
new file mode 100644
index 0000000..04f08ed
Binary files /dev/null and b/output/collage-composers-named.png differ
diff --git a/output/collage-composers.png b/output/collage-composers.png
new file mode 100644
index 0000000..b83b91e
Binary files /dev/null and b/output/collage-composers.png differ
diff --git a/output/collage-economists-named.png b/output/collage-economists-named.png
new file mode 100644
index 0000000..3ec156d
Binary files /dev/null and b/output/collage-economists-named.png differ
diff --git a/output/collage-economists.png b/output/collage-economists.png
new file mode 100644
index 0000000..56d5c1a
Binary files /dev/null and b/output/collage-economists.png differ
diff --git a/output/collage-european-statesmen-named.png b/output/collage-european-statesmen-named.png
new file mode 100644
index 0000000..7715992
Binary files /dev/null and b/output/collage-european-statesmen-named.png differ
diff --git a/output/collage-european-statesmen.png b/output/collage-european-statesmen.png
new file mode 100644
index 0000000..abc2ee6
Binary files /dev/null and b/output/collage-european-statesmen.png differ
diff --git a/output/collage-explorers-navigators-named.png b/output/collage-explorers-navigators-named.png
new file mode 100644
index 0000000..730403a
Binary files /dev/null and b/output/collage-explorers-navigators-named.png differ
diff --git a/output/collage-explorers-navigators.png b/output/collage-explorers-navigators.png
new file mode 100644
index 0000000..8a890d2
Binary files /dev/null and b/output/collage-explorers-navigators.png differ
diff --git a/output/collage-founding-fathers-named.png b/output/collage-founding-fathers-named.png
new file mode 100644
index 0000000..7d9c08d
Binary files /dev/null and b/output/collage-founding-fathers-named.png differ
diff --git a/output/collage-founding-fathers.png b/output/collage-founding-fathers.png
new file mode 100644
index 0000000..8870cd0
Binary files /dev/null and b/output/collage-founding-fathers.png differ
diff --git a/output/collage-generals-commanders-named.png b/output/collage-generals-commanders-named.png
new file mode 100644
index 0000000..e643a71
Binary files /dev/null and b/output/collage-generals-commanders-named.png differ
diff --git a/output/collage-generals-commanders.png b/output/collage-generals-commanders.png
new file mode 100644
index 0000000..87932c5
Binary files /dev/null and b/output/collage-generals-commanders.png differ
diff --git a/output/collage-industrialists-named.png b/output/collage-industrialists-named.png
new file mode 100644
index 0000000..eae12f8
Binary files /dev/null and b/output/collage-industrialists-named.png differ
diff --git a/output/collage-industrialists.png b/output/collage-industrialists.png
new file mode 100644
index 0000000..899b4d9
Binary files /dev/null and b/output/collage-industrialists.png differ
diff --git a/output/collage-mathematicians-named.png b/output/collage-mathematicians-named.png
new file mode 100644
index 0000000..e8d9bd8
Binary files /dev/null and b/output/collage-mathematicians-named.png differ
diff --git a/output/collage-mathematicians.png b/output/collage-mathematicians.png
new file mode 100644
index 0000000..fd9cea3
Binary files /dev/null and b/output/collage-mathematicians.png differ
diff --git a/output/collage-medicine-named.png b/output/collage-medicine-named.png
new file mode 100644
index 0000000..1e9280b
Binary files /dev/null and b/output/collage-medicine-named.png differ
diff --git a/output/collage-medicine.png b/output/collage-medicine.png
new file mode 100644
index 0000000..79824b6
Binary files /dev/null and b/output/collage-medicine.png differ
diff --git a/output/collage-monarchs-named.png b/output/collage-monarchs-named.png
new file mode 100644
index 0000000..04f8a03
Binary files /dev/null and b/output/collage-monarchs-named.png differ
diff --git a/output/collage-monarchs.png b/output/collage-monarchs.png
new file mode 100644
index 0000000..2be5dea
Binary files /dev/null and b/output/collage-monarchs.png differ
diff --git a/output/collage-naturalists-named.png b/output/collage-naturalists-named.png
new file mode 100644
index 0000000..759d0ba
Binary files /dev/null and b/output/collage-naturalists-named.png differ
diff --git a/output/collage-naturalists.png b/output/collage-naturalists.png
new file mode 100644
index 0000000..3302d24
Binary files /dev/null and b/output/collage-naturalists.png differ
diff --git a/output/collage-nobel-laureates-named.png b/output/collage-nobel-laureates-named.png
new file mode 100644
index 0000000..1e90301
Binary files /dev/null and b/output/collage-nobel-laureates-named.png differ
diff --git a/output/collage-nobel-laureates.png b/output/collage-nobel-laureates.png
new file mode 100644
index 0000000..0771cea
Binary files /dev/null and b/output/collage-nobel-laureates.png differ
diff --git a/output/collage-painters-artists-named.png b/output/collage-painters-artists-named.png
new file mode 100644
index 0000000..8ae1188
Binary files /dev/null and b/output/collage-painters-artists-named.png differ
diff --git a/output/collage-painters-artists.png b/output/collage-painters-artists.png
new file mode 100644
index 0000000..d51c9a4
Binary files /dev/null and b/output/collage-painters-artists.png differ
diff --git a/output/collage-philosophers-named.png b/output/collage-philosophers-named.png
new file mode 100644
index 0000000..1477998
Binary files /dev/null and b/output/collage-philosophers-named.png differ
diff --git a/output/collage-philosophers.png b/output/collage-philosophers.png
new file mode 100644
index 0000000..9355405
Binary files /dev/null and b/output/collage-philosophers.png differ
diff --git a/output/collage-physicists-named.png b/output/collage-physicists-named.png
new file mode 100644
index 0000000..e1c35fb
Binary files /dev/null and b/output/collage-physicists-named.png differ
diff --git a/output/collage-physicists.png b/output/collage-physicists.png
new file mode 100644
index 0000000..2140d00
Binary files /dev/null and b/output/collage-physicists.png differ
diff --git a/output/collage-playwrights-named.png b/output/collage-playwrights-named.png
new file mode 100644
index 0000000..0be4f46
Binary files /dev/null and b/output/collage-playwrights-named.png differ
diff --git a/output/collage-playwrights.png b/output/collage-playwrights.png
new file mode 100644
index 0000000..19c3ae0
Binary files /dev/null and b/output/collage-playwrights.png differ
diff --git a/output/collage-poets-named.png b/output/collage-poets-named.png
new file mode 100644
index 0000000..8218539
Binary files /dev/null and b/output/collage-poets-named.png differ
diff --git a/output/collage-poets.png b/output/collage-poets.png
new file mode 100644
index 0000000..a8a9e0a
Binary files /dev/null and b/output/collage-poets.png differ
diff --git a/output/collage-renaissance-masters-named.png b/output/collage-renaissance-masters-named.png
new file mode 100644
index 0000000..06005fa
Binary files /dev/null and b/output/collage-renaissance-masters-named.png differ
diff --git a/output/collage-renaissance-masters.png b/output/collage-renaissance-masters.png
new file mode 100644
index 0000000..f080caf
Binary files /dev/null and b/output/collage-renaissance-masters.png differ
diff --git a/output/collage-revolutionaries-named.png b/output/collage-revolutionaries-named.png
new file mode 100644
index 0000000..2fbd6f5
Binary files /dev/null and b/output/collage-revolutionaries-named.png differ
diff --git a/output/collage-revolutionaries.png b/output/collage-revolutionaries.png
new file mode 100644
index 0000000..3a219ad
Binary files /dev/null and b/output/collage-revolutionaries.png differ
diff --git a/output/collage-scientists-inventors-named.png b/output/collage-scientists-inventors-named.png
new file mode 100644
index 0000000..7603967
Binary files /dev/null and b/output/collage-scientists-inventors-named.png differ
diff --git a/output/collage-scientists-inventors.png b/output/collage-scientists-inventors.png
new file mode 100644
index 0000000..fa0ce8d
Binary files /dev/null and b/output/collage-scientists-inventors.png differ
diff --git a/output/collage-suffragists-named.png b/output/collage-suffragists-named.png
new file mode 100644
index 0000000..1959f08
Binary files /dev/null and b/output/collage-suffragists-named.png differ
diff --git a/output/collage-suffragists.png b/output/collage-suffragists.png
new file mode 100644
index 0000000..15a38ce
Binary files /dev/null and b/output/collage-suffragists.png differ
diff --git a/output/collage-writers-novelists-named.png b/output/collage-writers-novelists-named.png
new file mode 100644
index 0000000..c9b2698
Binary files /dev/null and b/output/collage-writers-novelists-named.png differ
diff --git a/output/collage-writers-novelists.png b/output/collage-writers-novelists.png
new file mode 100644
index 0000000..0a0af83
Binary files /dev/null and b/output/collage-writers-novelists.png differ
diff --git a/public/murals.html b/public/murals.html
index 0c9e0c4..b5cf69c 100644
--- a/public/murals.html
+++ b/public/murals.html
@@ -292,7 +292,14 @@ async function boot(){
SIGS = all.filter(r => r.usable_in_commercial_collage === 'yes');
for(const r of SIGS) sigByKey[r.category + '|' + r.rank] = r;
for(const m of CAT.murals){
- byMural[m.code] = SIGS.filter(r => r.category === CATEGORY_OF[m.slug]).sort((a,b)=>a.rank-b.rank);
+ if(CATEGORY_OF[m.slug]){
+ byMural[m.code] = SIGS.filter(r => r.category === CATEGORY_OF[m.slug]).sort((a,b)=>a.rank-b.rank);
+ } else if(Array.isArray(m.roster)){
+ // themed murals carry their resolved roster in the catalog entry
+ byMural[m.code] = m.roster.map((nm,i)=>({full_name:nm, category:m.slug, rank:i+1, signature_image_url:''}));
+ } else {
+ byMural[m.code] = [];
+ }
}
}catch(e){ SIGS = []; }
diff --git a/scripts/build-theme-murals.py b/scripts/build-theme-murals.py
new file mode 100644
index 0000000..e8d4833
--- /dev/null
+++ b/scripts/build-theme-murals.py
@@ -0,0 +1,205 @@
+#!/usr/bin/env python3
+"""
+Themed signature-mural factory.
+
+Reads data/mural-themes.json (list of {slug,title,blurb,met_query,roster:[names]}).
+For each theme:
+ - resolves every roster name's REAL signature via Wikidata P109 (signature image)
+ -> Commons thumbnail. Names without a P109 signature are SKIPPED (never invented).
+ - pulls one PUBLIC-DOMAIN Met artifact (Met Open Access API) as a header accent.
+ - composes output/collage-<slug>.png and collage-<slug>-named.png (the murals
+ page toggles base<->named), matching the existing storefront image convention.
+Then appends/updates each theme in data/murals-catalog.json with its resolved roster.
+
+Free / local + public no-key HTTP (Wikidata + Commons + Met). $0.
+"""
+import json, os, re, time, urllib.parse, urllib.request, sys
+from io import BytesIO
+from concurrent.futures import ThreadPoolExecutor
+from PIL import Image, ImageDraw, ImageFont
+
+ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+THEMES = os.path.join(ROOT, "data", "mural-themes.json")
+CATALOG = os.path.join(ROOT, "data", "murals-catalog.json")
+CACHE = os.path.join(ROOT, "tmp_theme_cache")
+OUT = os.path.join(ROOT, "output")
+UA = "CelebritySignatures-research/1.0 (steve@designerwallcoverings.com)"
+WD = "https://www.wikidata.org/w/api.php"
+COMMONS = "https://commons.wikimedia.org/w/api.php"
+MET = "https://collectionapi.metmuseum.org/public/collection/v1"
+os.makedirs(CACHE, exist_ok=True); os.makedirs(OUT, exist_ok=True)
+
+
+def get(url, tries=5):
+ for i in range(tries):
+ try:
+ req = urllib.request.Request(url, headers={"User-Agent": UA})
+ with urllib.request.urlopen(req, timeout=25) as r:
+ return r.read()
+ except Exception:
+ if i == tries - 1:
+ return None
+ time.sleep(1.0 * (i + 1)) # gentle backoff to avoid Wikidata 429s
+
+
+def getjson(url):
+ b = get(url)
+ try:
+ return json.loads(b) if b else None
+ except Exception:
+ return None
+
+
+def wd_signature(name):
+ """name -> (commons thumb url) via Wikidata P109, or None."""
+ s = getjson(f"{WD}?action=wbsearchentities&search={urllib.parse.quote(name)}"
+ f"&language=en&format=json&type=item&limit=1&maxlag=5")
+ try:
+ qid = s["search"][0]["id"]
+ except Exception:
+ return None
+ c = getjson(f"{WD}?action=wbgetclaims&entity={qid}&property=P109&format=json&maxlag=5")
+ try:
+ fname = c["claims"]["P109"][0]["mainsnak"]["datavalue"]["value"]
+ except Exception:
+ return None
+ title = "File:" + fname
+ q = (f"{COMMONS}?action=query&titles={urllib.parse.quote(title)}"
+ f"&prop=imageinfo&iiprop=url&iiurlwidth=600&format=json")
+ d = getjson(q)
+ try:
+ info = next(iter(d["query"]["pages"].values()))["imageinfo"][0]
+ return info.get("thumburl") or info.get("url")
+ except Exception:
+ return None
+
+
+def met_public_domain(query):
+ s = getjson(f"{MET}/search?q={urllib.parse.quote(query)}&hasImages=true")
+ for oid in (s or {}).get("objectIDs", [])[:10]:
+ o = getjson(f"{MET}/objects/{oid}")
+ if o and o.get("isPublicDomain") and (o.get("primaryImageSmall") or o.get("primaryImage")):
+ return o.get("primaryImageSmall") or o.get("primaryImage"), o.get("title", "")
+ return None, ""
+
+
+def cache_img(url, key):
+ if not url:
+ return None
+ p = os.path.join(CACHE, re.sub(r"[^a-z0-9]+", "-", key.lower()).strip("-") + ".png")
+ if os.path.exists(p) and os.path.getsize(p) > 200:
+ return p
+ b = get(url)
+ if not b:
+ return None
+ try:
+ Image.open(BytesIO(b)).convert("RGBA").save(p)
+ return p
+ except Exception:
+ return None
+
+
+def font(sz, bold=False):
+ for p in (["/System/Library/Fonts/Supplemental/Georgia Bold.ttf" if bold else "/System/Library/Fonts/Supplemental/Georgia.ttf",
+ "/System/Library/Fonts/Supplemental/Arial Bold.ttf" if bold else "/System/Library/Fonts/Supplemental/Arial.ttf"]):
+ try:
+ return ImageFont.truetype(p, sz)
+ except Exception:
+ continue
+ return ImageFont.load_default()
+
+
+def resolve_theme(theme):
+ roster = theme["roster"]
+ workers = int(os.environ.get("WORKERS", "3"))
+ with ThreadPoolExecutor(max_workers=workers) as ex:
+ thumbs = list(ex.map(wd_signature, roster))
+ sigs = []
+ for name, url in zip(roster, thumbs):
+ if url:
+ local = cache_img(url, theme["slug"] + "-" + name)
+ if local:
+ sigs.append({"name": name, "local": local})
+ met_url, met_title = met_public_domain(theme.get("met_query", theme["title"]))
+ met_local = cache_img(met_url, theme["slug"] + "-met") if met_url else None
+ return sigs, met_local, met_title
+
+
+def build(theme, sigs, met_local, named):
+ n = len(sigs)
+ COLS = 5 if n > 12 else 4 if n > 6 else 3
+ rows = max(1, (n + COLS - 1) // COLS)
+ BOX_W, BOX_H = 300, 110
+ LABEL_H = 30 if named else 0
+ PAD = 22
+ CELL_W = BOX_W + PAD
+ CELL_H = BOX_H + LABEL_H + PAD
+ HEADER_H = 180
+ FOOT = 54
+ W = COLS * CELL_W + PAD
+ H = HEADER_H + rows * CELL_H + FOOT
+ INK = (26, 24, 22); MUTED = (122, 118, 112); LINE = (226, 222, 216)
+ img = Image.new("RGB", (W, H), (250, 249, 246))
+ d = ImageDraw.Draw(img)
+ # Met accent top-right
+ if met_local and os.path.exists(met_local):
+ try:
+ im = Image.open(met_local).convert("RGB"); im.thumbnail((150, 150), Image.LANCZOS)
+ img.paste(im, (W - im.width - PAD - 6, 22))
+ except Exception:
+ pass
+ d.text((PAD + 6, 46), theme["title"], font=font(46, True), fill=INK)
+ d.text((PAD + 8, 110), theme.get("blurb", "")[:120], font=font(19), fill=MUTED)
+ d.line([(PAD + 6, HEADER_H - 16), (W - PAD - 6, HEADER_H - 16)], fill=LINE, width=2)
+ for i, s in enumerate(sigs):
+ cx = PAD + (i % COLS) * CELL_W
+ cy = HEADER_H + (i // COLS) * CELL_H
+ try:
+ im = Image.open(s["local"]).convert("RGBA")
+ bg = Image.new("RGBA", im.size, (255, 255, 255, 255))
+ im = Image.alpha_composite(bg, im).convert("RGB")
+ im.thumbnail((BOX_W, BOX_H), Image.LANCZOS)
+ img.paste(im, (cx + (BOX_W - im.width) // 2, cy + (BOX_H - im.height) // 2))
+ except Exception:
+ pass
+ if named:
+ d.text((cx + 4, cy + BOX_H + 6), s["name"][:30], font=font(17, True), fill=INK)
+ d.text((PAD + 6, H - 38),
+ f"{n} signatures · every name traced to a public-domain Wikimedia source · accent artifact: The Met (public domain).",
+ font=font(13), fill=MUTED)
+ suffix = "-named" if named else ""
+ img.save(os.path.join(OUT, f"collage-{theme['slug']}{suffix}.png"))
+
+
+def main():
+ only = sys.argv[1] if len(sys.argv) > 1 else None
+ themes = json.load(open(THEMES))
+ if only:
+ themes = [t for t in themes if t["slug"] == only]
+ catalog = json.load(open(CATALOG))
+ by_slug = {m["slug"]: m for m in catalog["murals"]}
+ built = []
+ for t in themes:
+ sigs, met_local, met_title = resolve_theme(t)
+ if len(sigs) < 4:
+ print(f"[{t['slug']}] only {len(sigs)} signatures resolved — SKIP (need >=4)")
+ continue
+ build(t, sigs, met_local, named=True)
+ build(t, sigs, met_local, named=False)
+ entry = {"code": t.get("code", t["slug"][:2]), "slug": t["slug"], "title": t["title"],
+ "blurb": t["blurb"], "sigs": len(sigs),
+ "roster": [s["name"] for s in sigs], "met_accent": met_title}
+ by_slug[t["slug"]] = entry
+ built.append((t["slug"], len(sigs)))
+ print(f"[{t['slug']}] -> {len(sigs)} sigs · met:{met_title[:30]}")
+ # preserve original first three, then themed by order
+ order = ["oldest-signatures", "declaration-of-independence", "politics"]
+ murals = [by_slug[s] for s in order if s in by_slug]
+ murals += [by_slug[t["slug"]] for t in json.load(open(THEMES)) if t["slug"] in by_slug and t["slug"] not in order]
+ catalog["murals"] = murals
+ json.dump(catalog, open(CATALOG, "w"), indent=2, ensure_ascii=False)
+ print(f"\nBuilt {len(built)} themed murals. Catalog now lists {len(murals)} murals total.")
+
+
+if __name__ == "__main__":
+ main()
← 3a77cd8 wire Oldest Signatures into storefront: grid category + mura
·
back to CelebritySignatures
·
chore: macstudio3 migration — reconcile from mac2 + repoint b3b1355 →