← back to Pattern Vault
gap-brief generation: 16 settlement-PASS originals staged + 6 Spoonflower-ready (150 DPI, no upscale) + curator gallery
8d1ba79fb21b677bac8f6218726ed79d30193429 · 2026-07-02 12:06:44 -0700 · Steve
Files touched
A assets/generated/BRIEF-2026-animalprint-01_v1.pngA assets/generated/BRIEF-2026-animalprint-01_v2.pngA assets/generated/BRIEF-2026-animalprint-02_v1.pngA assets/generated/BRIEF-2026-animalprint-02_v2.pngA assets/generated/BRIEF-2026-chinoiserie-sat-01_v1.pngA assets/generated/BRIEF-2026-chinoiserie-sat-01_v2.pngA assets/generated/BRIEF-2026-deco-01_v1.pngA assets/generated/BRIEF-2026-deco-01_v2.pngA assets/generated/BRIEF-2026-ditsy-01_v1.pngA assets/generated/BRIEF-2026-ditsy-01_v2.pngA assets/generated/BRIEF-2026-mural-01_v1.pngA assets/generated/BRIEF-2026-mural-01_v2.pngA assets/generated/BRIEF-2026-texture-01_v1.pngA assets/generated/BRIEF-2026-texture-01_v2.pngA assets/generated/BRIEF-2026-toile-01_v1.pngA assets/generated/BRIEF-2026-toile-01_v2.pngA assets/spoonflower-ready/animalprint-01_150dpi.pngA assets/spoonflower-ready/animalprint-02_150dpi.pngA assets/spoonflower-ready/chinoiserie-sat-01_150dpi.pngA assets/spoonflower-ready/ditsy-01_150dpi.pngA assets/spoonflower-ready/mural-01_150dpi.pngA assets/spoonflower-ready/toile-01_150dpi.pngA scripts/curator-gallery.jsA whimsical-compare/.portA whimsical-compare/data/originals.tsvA whimsical-compare/public/index.htmlA whimsical-compare/public/originals/10021703.jpgA whimsical-compare/public/originals/10125958.jpgA whimsical-compare/public/originals/10473378.jpgA whimsical-compare/public/originals/10719320.jpgA whimsical-compare/public/originals/10749527.jpgA whimsical-compare/public/originals/10828427.jpgA whimsical-compare/public/originals/10862296.jpgA whimsical-compare/public/originals/11237842.jpgA whimsical-compare/public/originals/11388473.jpgA whimsical-compare/public/originals/11464311.jpgA whimsical-compare/public/originals/11478772.jpgA whimsical-compare/public/originals/11483815.jpgA whimsical-compare/public/originals/11495382.jpgA whimsical-compare/public/originals/11757941.jpgA whimsical-compare/public/originals/12049973.jpgA whimsical-compare/public/originals/12135529.jpgA whimsical-compare/public/originals/12441406.jpgA whimsical-compare/public/originals/12448122.jpgA whimsical-compare/public/originals/12479233.jpgA whimsical-compare/public/originals/12611067.jpgA whimsical-compare/public/originals/12788019.jpgA whimsical-compare/public/originals/12788028.jpgA whimsical-compare/public/originals/12804113.jpgA whimsical-compare/public/originals/12869734.jpgA whimsical-compare/public/originals/12878048.jpgA whimsical-compare/public/originals/12894549.jpgA whimsical-compare/public/originals/12904568.jpgA whimsical-compare/public/originals/12906217.jpgA whimsical-compare/public/originals/12929666.jpgA whimsical-compare/public/originals/12929681.jpgA whimsical-compare/public/originals/12929706.jpgA whimsical-compare/public/originals/13214654.jpgA whimsical-compare/public/originals/13584767.jpgA whimsical-compare/public/originals/13629046.jpgA whimsical-compare/public/originals/13728995.jpgA whimsical-compare/public/originals/13918325.jpgA whimsical-compare/public/originals/13918453.jpgA whimsical-compare/public/originals/13920815.jpgA whimsical-compare/public/originals/13949729.jpgA whimsical-compare/public/originals/13957257.jpgA whimsical-compare/public/originals/14150480.jpgA whimsical-compare/public/originals/14163752.jpgA whimsical-compare/public/originals/14178793.jpgA whimsical-compare/public/originals/14281611.jpgA whimsical-compare/public/originals/14288984.jpgA whimsical-compare/public/originals/14289044.jpgA whimsical-compare/public/originals/14309427.jpgA whimsical-compare/public/originals/14372386.jpgA whimsical-compare/public/originals/14438928.jpgA whimsical-compare/public/originals/14576878.jpgA whimsical-compare/public/originals/14634270.jpgA whimsical-compare/public/originals/14800343.jpgA whimsical-compare/public/originals/14999334.jpgA whimsical-compare/public/originals/15006191.jpgA whimsical-compare/public/originals/15062910.jpgA whimsical-compare/public/originals/15094678.jpgA whimsical-compare/public/originals/15095313.jpgA whimsical-compare/public/originals/15235563.jpgA whimsical-compare/public/originals/15252682.jpgA whimsical-compare/public/originals/15300002.jpgA whimsical-compare/public/originals/15558511.jpgA whimsical-compare/public/originals/15606286.jpgA whimsical-compare/public/originals/15622273.jpgA whimsical-compare/public/originals/15910606.jpgA whimsical-compare/public/originals/15914489.jpgA whimsical-compare/public/originals/16014251.jpgA whimsical-compare/public/originals/16019794.jpgA whimsical-compare/public/originals/16267560.jpgA whimsical-compare/public/originals/16483638.jpgA whimsical-compare/public/originals/16520351.jpgA whimsical-compare/public/originals/16594395.jpgA whimsical-compare/public/originals/16701521.jpgA whimsical-compare/public/originals/16859966.jpgA whimsical-compare/public/originals/17081029.jpgA whimsical-compare/public/originals/17256838.jpgA whimsical-compare/public/originals/1743921.jpgA whimsical-compare/public/originals/17530673.jpgA whimsical-compare/public/originals/17610058.jpgA whimsical-compare/public/originals/17617859.jpgA whimsical-compare/public/originals/17742136.jpgA whimsical-compare/public/originals/17742893.jpgA whimsical-compare/public/originals/17761350.jpgA whimsical-compare/public/originals/17809925.jpgA whimsical-compare/public/originals/18035772.jpgA whimsical-compare/public/originals/18166792.jpgA whimsical-compare/public/originals/18381034.jpgA whimsical-compare/public/originals/18506377.jpgA whimsical-compare/public/originals/18719041.jpgA whimsical-compare/public/originals/18891417.jpgA whimsical-compare/public/originals/18891419.jpgA whimsical-compare/public/originals/3564038.jpgA whimsical-compare/public/originals/5151893.jpgA whimsical-compare/public/originals/5608890.jpgA whimsical-compare/public/originals/6401436.jpgA whimsical-compare/public/originals/6402897.jpgA whimsical-compare/public/originals/7354857.jpgA whimsical-compare/public/originals/7988956.jpgA whimsical-compare/public/originals/8223425.jpgA whimsical-compare/public/originals/9709002.jpgA whimsical-compare/public/originals/9987142.jpgA whimsical-compare/public/ours/12448122.pngA whimsical-compare/public/ours/14634270.pngA whimsical-compare/public/ours/16483638.pngA whimsical-compare/public/ours/18891419.pngA whimsical-compare/scripts/gen_ours.pyA whimsical-compare/server.js
Diff
commit 8d1ba79fb21b677bac8f6218726ed79d30193429
Author: Steve <steve@designerwallcoverings.com>
Date: Thu Jul 2 12:06:44 2026 -0700
gap-brief generation: 16 settlement-PASS originals staged + 6 Spoonflower-ready (150 DPI, no upscale) + curator gallery
---
assets/generated/BRIEF-2026-animalprint-01_v1.png | Bin 0 -> 1301549 bytes
assets/generated/BRIEF-2026-animalprint-01_v2.png | Bin 0 -> 1658743 bytes
assets/generated/BRIEF-2026-animalprint-02_v1.png | Bin 0 -> 1096351 bytes
assets/generated/BRIEF-2026-animalprint-02_v2.png | Bin 0 -> 1180126 bytes
.../generated/BRIEF-2026-chinoiserie-sat-01_v1.png | Bin 0 -> 1738769 bytes
.../generated/BRIEF-2026-chinoiserie-sat-01_v2.png | Bin 0 -> 1685309 bytes
assets/generated/BRIEF-2026-deco-01_v1.png | Bin 0 -> 2240015 bytes
assets/generated/BRIEF-2026-deco-01_v2.png | Bin 0 -> 2232401 bytes
assets/generated/BRIEF-2026-ditsy-01_v1.png | Bin 0 -> 1739807 bytes
assets/generated/BRIEF-2026-ditsy-01_v2.png | Bin 0 -> 2017432 bytes
assets/generated/BRIEF-2026-mural-01_v1.png | Bin 0 -> 1678529 bytes
assets/generated/BRIEF-2026-mural-01_v2.png | Bin 0 -> 1522731 bytes
assets/generated/BRIEF-2026-texture-01_v1.png | Bin 0 -> 2142138 bytes
assets/generated/BRIEF-2026-texture-01_v2.png | Bin 0 -> 2037315 bytes
assets/generated/BRIEF-2026-toile-01_v1.png | Bin 0 -> 2281033 bytes
assets/generated/BRIEF-2026-toile-01_v2.png | Bin 0 -> 2276006 bytes
assets/spoonflower-ready/animalprint-01_150dpi.png | Bin 0 -> 1480750 bytes
assets/spoonflower-ready/animalprint-02_150dpi.png | Bin 0 -> 1212829 bytes
.../chinoiserie-sat-01_150dpi.png | Bin 0 -> 1818155 bytes
assets/spoonflower-ready/ditsy-01_150dpi.png | Bin 0 -> 1891923 bytes
assets/spoonflower-ready/mural-01_150dpi.png | Bin 0 -> 1599610 bytes
assets/spoonflower-ready/toile-01_150dpi.png | Bin 0 -> 2051895 bytes
scripts/curator-gallery.js | 28 +++
whimsical-compare/.port | 1 +
whimsical-compare/data/originals.tsv | 100 ++++++++++
whimsical-compare/public/index.html | 202 ++++++++++++++++++++
whimsical-compare/public/originals/10021703.jpg | Bin 0 -> 229747 bytes
whimsical-compare/public/originals/10125958.jpg | Bin 0 -> 198285 bytes
whimsical-compare/public/originals/10473378.jpg | Bin 0 -> 138279 bytes
whimsical-compare/public/originals/10719320.jpg | Bin 0 -> 130202 bytes
whimsical-compare/public/originals/10749527.jpg | Bin 0 -> 241409 bytes
whimsical-compare/public/originals/10828427.jpg | Bin 0 -> 243958 bytes
whimsical-compare/public/originals/10862296.jpg | Bin 0 -> 239658 bytes
whimsical-compare/public/originals/11237842.jpg | Bin 0 -> 266122 bytes
whimsical-compare/public/originals/11388473.jpg | Bin 0 -> 176496 bytes
whimsical-compare/public/originals/11464311.jpg | Bin 0 -> 90450 bytes
whimsical-compare/public/originals/11478772.jpg | Bin 0 -> 220979 bytes
whimsical-compare/public/originals/11483815.jpg | Bin 0 -> 347021 bytes
whimsical-compare/public/originals/11495382.jpg | Bin 0 -> 238418 bytes
whimsical-compare/public/originals/11757941.jpg | Bin 0 -> 230766 bytes
whimsical-compare/public/originals/12049973.jpg | Bin 0 -> 126822 bytes
whimsical-compare/public/originals/12135529.jpg | Bin 0 -> 213942 bytes
whimsical-compare/public/originals/12441406.jpg | Bin 0 -> 136722 bytes
whimsical-compare/public/originals/12448122.jpg | Bin 0 -> 174210 bytes
whimsical-compare/public/originals/12479233.jpg | Bin 0 -> 169718 bytes
whimsical-compare/public/originals/12611067.jpg | Bin 0 -> 142352 bytes
whimsical-compare/public/originals/12788019.jpg | Bin 0 -> 213575 bytes
whimsical-compare/public/originals/12788028.jpg | Bin 0 -> 214417 bytes
whimsical-compare/public/originals/12804113.jpg | Bin 0 -> 207324 bytes
whimsical-compare/public/originals/12869734.jpg | Bin 0 -> 230084 bytes
whimsical-compare/public/originals/12878048.jpg | Bin 0 -> 260423 bytes
whimsical-compare/public/originals/12894549.jpg | Bin 0 -> 154421 bytes
whimsical-compare/public/originals/12904568.jpg | Bin 0 -> 159592 bytes
whimsical-compare/public/originals/12906217.jpg | Bin 0 -> 245456 bytes
whimsical-compare/public/originals/12929666.jpg | Bin 0 -> 190128 bytes
whimsical-compare/public/originals/12929681.jpg | Bin 0 -> 168229 bytes
whimsical-compare/public/originals/12929706.jpg | Bin 0 -> 200969 bytes
whimsical-compare/public/originals/13214654.jpg | Bin 0 -> 133731 bytes
whimsical-compare/public/originals/13584767.jpg | Bin 0 -> 268991 bytes
whimsical-compare/public/originals/13629046.jpg | Bin 0 -> 211539 bytes
whimsical-compare/public/originals/13728995.jpg | Bin 0 -> 242722 bytes
whimsical-compare/public/originals/13918325.jpg | Bin 0 -> 201053 bytes
whimsical-compare/public/originals/13918453.jpg | Bin 0 -> 277556 bytes
whimsical-compare/public/originals/13920815.jpg | Bin 0 -> 235020 bytes
whimsical-compare/public/originals/13949729.jpg | Bin 0 -> 356783 bytes
whimsical-compare/public/originals/13957257.jpg | Bin 0 -> 256099 bytes
whimsical-compare/public/originals/14150480.jpg | Bin 0 -> 124221 bytes
whimsical-compare/public/originals/14163752.jpg | Bin 0 -> 283658 bytes
whimsical-compare/public/originals/14178793.jpg | Bin 0 -> 175809 bytes
whimsical-compare/public/originals/14281611.jpg | Bin 0 -> 80488 bytes
whimsical-compare/public/originals/14288984.jpg | Bin 0 -> 158829 bytes
whimsical-compare/public/originals/14289044.jpg | Bin 0 -> 136300 bytes
whimsical-compare/public/originals/14309427.jpg | Bin 0 -> 200445 bytes
whimsical-compare/public/originals/14372386.jpg | Bin 0 -> 191188 bytes
whimsical-compare/public/originals/14438928.jpg | Bin 0 -> 246878 bytes
whimsical-compare/public/originals/14576878.jpg | Bin 0 -> 285762 bytes
whimsical-compare/public/originals/14634270.jpg | Bin 0 -> 204984 bytes
whimsical-compare/public/originals/14800343.jpg | Bin 0 -> 257927 bytes
whimsical-compare/public/originals/14999334.jpg | Bin 0 -> 154862 bytes
whimsical-compare/public/originals/15006191.jpg | Bin 0 -> 210887 bytes
whimsical-compare/public/originals/15062910.jpg | Bin 0 -> 259148 bytes
whimsical-compare/public/originals/15094678.jpg | Bin 0 -> 123532 bytes
whimsical-compare/public/originals/15095313.jpg | Bin 0 -> 190159 bytes
whimsical-compare/public/originals/15235563.jpg | Bin 0 -> 279786 bytes
whimsical-compare/public/originals/15252682.jpg | Bin 0 -> 161800 bytes
whimsical-compare/public/originals/15300002.jpg | Bin 0 -> 90521 bytes
whimsical-compare/public/originals/15558511.jpg | Bin 0 -> 219717 bytes
whimsical-compare/public/originals/15606286.jpg | Bin 0 -> 185256 bytes
whimsical-compare/public/originals/15622273.jpg | Bin 0 -> 212254 bytes
whimsical-compare/public/originals/15910606.jpg | Bin 0 -> 200801 bytes
whimsical-compare/public/originals/15914489.jpg | Bin 0 -> 220016 bytes
whimsical-compare/public/originals/16014251.jpg | Bin 0 -> 208277 bytes
whimsical-compare/public/originals/16019794.jpg | Bin 0 -> 179556 bytes
whimsical-compare/public/originals/16267560.jpg | Bin 0 -> 204341 bytes
whimsical-compare/public/originals/16483638.jpg | Bin 0 -> 140658 bytes
whimsical-compare/public/originals/16520351.jpg | Bin 0 -> 259585 bytes
whimsical-compare/public/originals/16594395.jpg | Bin 0 -> 136989 bytes
whimsical-compare/public/originals/16701521.jpg | Bin 0 -> 178549 bytes
whimsical-compare/public/originals/16859966.jpg | Bin 0 -> 167926 bytes
whimsical-compare/public/originals/17081029.jpg | Bin 0 -> 140979 bytes
whimsical-compare/public/originals/17256838.jpg | Bin 0 -> 109298 bytes
whimsical-compare/public/originals/1743921.jpg | Bin 0 -> 352424 bytes
whimsical-compare/public/originals/17530673.jpg | Bin 0 -> 192427 bytes
whimsical-compare/public/originals/17610058.jpg | Bin 0 -> 263077 bytes
whimsical-compare/public/originals/17617859.jpg | Bin 0 -> 216106 bytes
whimsical-compare/public/originals/17742136.jpg | Bin 0 -> 210131 bytes
whimsical-compare/public/originals/17742893.jpg | Bin 0 -> 292284 bytes
whimsical-compare/public/originals/17761350.jpg | Bin 0 -> 222853 bytes
whimsical-compare/public/originals/17809925.jpg | Bin 0 -> 161294 bytes
whimsical-compare/public/originals/18035772.jpg | Bin 0 -> 288537 bytes
whimsical-compare/public/originals/18166792.jpg | Bin 0 -> 159503 bytes
whimsical-compare/public/originals/18381034.jpg | Bin 0 -> 248461 bytes
whimsical-compare/public/originals/18506377.jpg | Bin 0 -> 116430 bytes
whimsical-compare/public/originals/18719041.jpg | Bin 0 -> 195178 bytes
whimsical-compare/public/originals/18891417.jpg | Bin 0 -> 176571 bytes
whimsical-compare/public/originals/18891419.jpg | Bin 0 -> 174737 bytes
whimsical-compare/public/originals/3564038.jpg | Bin 0 -> 246088 bytes
whimsical-compare/public/originals/5151893.jpg | Bin 0 -> 330631 bytes
whimsical-compare/public/originals/5608890.jpg | Bin 0 -> 196691 bytes
whimsical-compare/public/originals/6401436.jpg | Bin 0 -> 227866 bytes
whimsical-compare/public/originals/6402897.jpg | Bin 0 -> 228496 bytes
whimsical-compare/public/originals/7354857.jpg | Bin 0 -> 207448 bytes
whimsical-compare/public/originals/7988956.jpg | Bin 0 -> 231881 bytes
whimsical-compare/public/originals/8223425.jpg | Bin 0 -> 162952 bytes
whimsical-compare/public/originals/9709002.jpg | Bin 0 -> 257653 bytes
whimsical-compare/public/originals/9987142.jpg | Bin 0 -> 189533 bytes
whimsical-compare/public/ours/12448122.png | Bin 0 -> 1841686 bytes
whimsical-compare/public/ours/14634270.png | Bin 0 -> 1663201 bytes
whimsical-compare/public/ours/16483638.png | Bin 0 -> 1681284 bytes
whimsical-compare/public/ours/18891419.png | Bin 0 -> 2168082 bytes
whimsical-compare/scripts/gen_ours.py | 173 +++++++++++++++++
whimsical-compare/server.js | 211 +++++++++++++++++++++
132 files changed, 715 insertions(+)
diff --git a/assets/generated/BRIEF-2026-animalprint-01_v1.png b/assets/generated/BRIEF-2026-animalprint-01_v1.png
new file mode 100644
index 0000000..7247e8f
Binary files /dev/null and b/assets/generated/BRIEF-2026-animalprint-01_v1.png differ
diff --git a/assets/generated/BRIEF-2026-animalprint-01_v2.png b/assets/generated/BRIEF-2026-animalprint-01_v2.png
new file mode 100644
index 0000000..8477d97
Binary files /dev/null and b/assets/generated/BRIEF-2026-animalprint-01_v2.png differ
diff --git a/assets/generated/BRIEF-2026-animalprint-02_v1.png b/assets/generated/BRIEF-2026-animalprint-02_v1.png
new file mode 100644
index 0000000..245e4f9
Binary files /dev/null and b/assets/generated/BRIEF-2026-animalprint-02_v1.png differ
diff --git a/assets/generated/BRIEF-2026-animalprint-02_v2.png b/assets/generated/BRIEF-2026-animalprint-02_v2.png
new file mode 100644
index 0000000..af80657
Binary files /dev/null and b/assets/generated/BRIEF-2026-animalprint-02_v2.png differ
diff --git a/assets/generated/BRIEF-2026-chinoiserie-sat-01_v1.png b/assets/generated/BRIEF-2026-chinoiserie-sat-01_v1.png
new file mode 100644
index 0000000..194d8dc
Binary files /dev/null and b/assets/generated/BRIEF-2026-chinoiserie-sat-01_v1.png differ
diff --git a/assets/generated/BRIEF-2026-chinoiserie-sat-01_v2.png b/assets/generated/BRIEF-2026-chinoiserie-sat-01_v2.png
new file mode 100644
index 0000000..3dc0056
Binary files /dev/null and b/assets/generated/BRIEF-2026-chinoiserie-sat-01_v2.png differ
diff --git a/assets/generated/BRIEF-2026-deco-01_v1.png b/assets/generated/BRIEF-2026-deco-01_v1.png
new file mode 100644
index 0000000..4ec9ec9
Binary files /dev/null and b/assets/generated/BRIEF-2026-deco-01_v1.png differ
diff --git a/assets/generated/BRIEF-2026-deco-01_v2.png b/assets/generated/BRIEF-2026-deco-01_v2.png
new file mode 100644
index 0000000..2b44a8a
Binary files /dev/null and b/assets/generated/BRIEF-2026-deco-01_v2.png differ
diff --git a/assets/generated/BRIEF-2026-ditsy-01_v1.png b/assets/generated/BRIEF-2026-ditsy-01_v1.png
new file mode 100644
index 0000000..bc0430c
Binary files /dev/null and b/assets/generated/BRIEF-2026-ditsy-01_v1.png differ
diff --git a/assets/generated/BRIEF-2026-ditsy-01_v2.png b/assets/generated/BRIEF-2026-ditsy-01_v2.png
new file mode 100644
index 0000000..a49ca2b
Binary files /dev/null and b/assets/generated/BRIEF-2026-ditsy-01_v2.png differ
diff --git a/assets/generated/BRIEF-2026-mural-01_v1.png b/assets/generated/BRIEF-2026-mural-01_v1.png
new file mode 100644
index 0000000..17fdbf1
Binary files /dev/null and b/assets/generated/BRIEF-2026-mural-01_v1.png differ
diff --git a/assets/generated/BRIEF-2026-mural-01_v2.png b/assets/generated/BRIEF-2026-mural-01_v2.png
new file mode 100644
index 0000000..d28ae94
Binary files /dev/null and b/assets/generated/BRIEF-2026-mural-01_v2.png differ
diff --git a/assets/generated/BRIEF-2026-texture-01_v1.png b/assets/generated/BRIEF-2026-texture-01_v1.png
new file mode 100644
index 0000000..73d7b46
Binary files /dev/null and b/assets/generated/BRIEF-2026-texture-01_v1.png differ
diff --git a/assets/generated/BRIEF-2026-texture-01_v2.png b/assets/generated/BRIEF-2026-texture-01_v2.png
new file mode 100644
index 0000000..e288cb3
Binary files /dev/null and b/assets/generated/BRIEF-2026-texture-01_v2.png differ
diff --git a/assets/generated/BRIEF-2026-toile-01_v1.png b/assets/generated/BRIEF-2026-toile-01_v1.png
new file mode 100644
index 0000000..6ee9704
Binary files /dev/null and b/assets/generated/BRIEF-2026-toile-01_v1.png differ
diff --git a/assets/generated/BRIEF-2026-toile-01_v2.png b/assets/generated/BRIEF-2026-toile-01_v2.png
new file mode 100644
index 0000000..9e78c9f
Binary files /dev/null and b/assets/generated/BRIEF-2026-toile-01_v2.png differ
diff --git a/assets/spoonflower-ready/animalprint-01_150dpi.png b/assets/spoonflower-ready/animalprint-01_150dpi.png
new file mode 100644
index 0000000..9cc162d
Binary files /dev/null and b/assets/spoonflower-ready/animalprint-01_150dpi.png differ
diff --git a/assets/spoonflower-ready/animalprint-02_150dpi.png b/assets/spoonflower-ready/animalprint-02_150dpi.png
new file mode 100644
index 0000000..d66bd65
Binary files /dev/null and b/assets/spoonflower-ready/animalprint-02_150dpi.png differ
diff --git a/assets/spoonflower-ready/chinoiserie-sat-01_150dpi.png b/assets/spoonflower-ready/chinoiserie-sat-01_150dpi.png
new file mode 100644
index 0000000..ecc94dc
Binary files /dev/null and b/assets/spoonflower-ready/chinoiserie-sat-01_150dpi.png differ
diff --git a/assets/spoonflower-ready/ditsy-01_150dpi.png b/assets/spoonflower-ready/ditsy-01_150dpi.png
new file mode 100644
index 0000000..5357455
Binary files /dev/null and b/assets/spoonflower-ready/ditsy-01_150dpi.png differ
diff --git a/assets/spoonflower-ready/mural-01_150dpi.png b/assets/spoonflower-ready/mural-01_150dpi.png
new file mode 100644
index 0000000..bad1625
Binary files /dev/null and b/assets/spoonflower-ready/mural-01_150dpi.png differ
diff --git a/assets/spoonflower-ready/toile-01_150dpi.png b/assets/spoonflower-ready/toile-01_150dpi.png
new file mode 100644
index 0000000..32f71f1
Binary files /dev/null and b/assets/spoonflower-ready/toile-01_150dpi.png differ
diff --git a/scripts/curator-gallery.js b/scripts/curator-gallery.js
new file mode 100644
index 0000000..64783fb
--- /dev/null
+++ b/scripts/curator-gallery.js
@@ -0,0 +1,28 @@
+const http=require('http'),fs=require('fs'),path=require('path');
+const PORT=process.env.PORT||9955, AUTH='admin:DW2024!';
+const GEN=path.join(__dirname,'..','assets','generated'), RDY=path.join(__dirname,'..','assets','spoonflower-ready');
+const TB=path.join(__dirname,'..','data','trend-board.json');
+function briefs(){ try{ return JSON.parse(fs.readFileSync(TB,'utf8')).briefs||[]; }catch(e){ return []; } }
+function pngs(dir){ try{ return fs.readdirSync(dir).filter(f=>/\.png$/i.test(f)); }catch(e){ return []; } }
+http.createServer((req,res)=>{
+ if(('Basic '+Buffer.from(AUTH).toString('base64'))!==(req.headers.authorization||'')){res.writeHead(401,{'WWW-Authenticate':'Basic realm=curator'});return res.end('auth');}
+ const u=new URL(req.url,'http://x');
+ if(u.pathname.startsWith('/img/')){ const f=path.join(GEN,path.basename(u.pathname)); return fs.readFile(f,(e,b)=>e?(res.writeHead(404),res.end()):(res.writeHead(200,{'Content-Type':'image/png'}),res.end(b))); }
+ if(u.pathname.startsWith('/rdy/')){ const f=path.join(RDY,path.basename(u.pathname)); return fs.readFile(f,(e,b)=>e?(res.writeHead(404),res.end()):(res.writeHead(200,{'Content-Type':'image/png'}),res.end(b))); }
+ const bmap={}; for(const b of briefs()) bmap[b.id]=b;
+ const files=pngs(GEN).sort();
+ const groups={}; for(const f of files){ const id=f.replace(/_v\d+\.png$/i,''); (groups[id]=groups[id]||[]).push(f); }
+ let cards='';
+ for(const id of Object.keys(groups).sort()){
+ const b=bmap[id]||{}; const title=b.title||id;
+ cards+='<section><h2>'+title+' <span class="lane">'+(b.lane||'')+'</span> <span class="ok">✓ settlement PASS</span></h2><div class="row">';
+ for(const f of groups[id]) cards+='<figure><img src="/img/'+f+'" loading="lazy"><figcaption>'+f.replace(id+'_','').replace('.png','')+'</figcaption></figure>';
+ cards+='</div><p class="brief">'+(b.prompt||'')+' <b>· target '+(b.targetTier||'')+'</b></p></section>';
+ }
+ const rdy=pngs(RDY);
+ const html='<!doctype html><meta charset=utf-8><title>Pattern Vault — Curator</title><style>body{font-family:Helvetica,Arial;margin:0;background:#faf8f3;color:#1c1a17}h1{padding:18px 26px;margin:0;border-bottom:1px solid #e4ded2;letter-spacing:.1em;text-transform:uppercase;font-size:15px}h1 small{font-weight:400;color:#8a8272;text-transform:none;letter-spacing:0}section{padding:14px 26px;border-bottom:1px solid #efe9dd}h2{font-size:15px;margin:0 0 10px}.lane{font-size:11px;color:#8a8272;font-weight:400}.ok{font-size:10px;background:#e6ede7;color:#2f5d3a;padding:2px 8px;border-radius:20px;font-weight:700}.row{display:flex;gap:14px;flex-wrap:wrap}figure{margin:0;width:260px}img{width:260px;height:260px;object-fit:cover;border-radius:10px;border:1px solid #e4ded2;background:#fff}figcaption{font-size:11px;color:#8a8272;margin-top:4px}.brief{font-size:12px;color:#6a6456;max-width:900px}.hd{padding:10px 26px;background:#2f5d3a;color:#fff;font-size:13px}</style>'
+ +'<h1>Pattern Vault — Curator <small> original, settlement-PASS, staged (unpublished)</small></h1>'
+ +'<div class=hd>'+files.length+' generated variants · '+rdy.length+' Spoonflower-ready (150 DPI, native res, no upscale)</div>'
+ +cards;
+ res.writeHead(200,{'Content-Type':'text/html'}); res.end(html);
+}).listen(PORT,()=>console.log('curator on http://127.0.0.1:'+PORT+' (admin:DW2024!)'));
diff --git a/whimsical-compare/.port b/whimsical-compare/.port
new file mode 100644
index 0000000..1b98715
--- /dev/null
+++ b/whimsical-compare/.port
@@ -0,0 +1 @@
+60218
\ No newline at end of file
diff --git a/whimsical-compare/data/originals.tsv b/whimsical-compare/data/originals.tsv
new file mode 100644
index 0000000..3b6cb51
--- /dev/null
+++ b/whimsical-compare/data/originals.tsv
@@ -0,0 +1,100 @@
+1 18891419 https://img.spoonflower.com/c/18891419/i/l/gG5Zh0y94tBai5HkKZJDW4R9KsPesoYRppw9eSITXUl-4oJrowoMXw/Heritage%20Charm%20-%20Botanical%20Tapestry%20-%20Midnight%20Forest.jpg
+2 14309427 https://img.spoonflower.com/c/14309427/i/l/Q_Wqmg4B5QdeKsqDhHLmNG1Cdb4YaPPWB3aBvU0kotdXfE2bVjGCeQ/Art%20Nouveau%20Cranes%20with%20vintage%20texture.jpg
+3 16483638 https://img.spoonflower.com/c/16483638/i/l/UApNQtPTSHgGYWkCvrz8FtqypcIqPPQgPi_pV8_oc5DdrKoSWSKyoQ/Abstract%20symmetrical%20floral%20white%20on%20beige.jpg
+4 12448122 https://img.spoonflower.com/c/12448122/i/l/n81iUUuQS8aN47ZiCBavHi5AOuzfWh7RZWHT1K-9Rvv3wwf8gHc9rw/San%20Diego%20(blue).jpg
+5 14634270 https://img.spoonflower.com/c/14634270/i/l/Aig4ElfBrwuUlZc_cPZXkEQPUxlZznQ18GW0oyx3sufZxrklS-40-5Lh/medium%20-%20Chiara%20-%20rustic%20green.jpg
+6 11495382 https://img.spoonflower.com/c/11495382/i/l/BYZ5atz9ET9RoRvkWt03ZLZcFnc1Jwk8LUIqeroQeeqgPHQ5GKMRCA/herons%20in%20marsh%20on%20slate%20medium%20scale.jpg
+7 16267560 https://img.spoonflower.com/c/16267560/i/l/vkrVpWPEPm5GxQt2eTD9y2MihdJCbkz3OBvtKziVdMmGMh3w_1O6fg/Dancing%20Blooms.jpg
+8 12804113 https://img.spoonflower.com/c/12804113/i/l/1xFyBJN9VOd9uReAlpC73FCl9ptOPKBKr97J2wURIAgQbFDB_pAaMw/Queen%20Anne's%20Lace.jpg
+9 12929706 https://img.spoonflower.com/c/12929706/i/l/wdetMpAAop4dccCofodAnh7u1TqCCV81FhKOBDm6nif19vZyOIsopa1D/(large%20scale)%20Ivy%20Stripes%20-%20Vertical%20Dark%20Blue%2FBrown%20on%20Cream%20-%20LAD22.jpg
+10 15094678 https://img.spoonflower.com/c/15094678/i/l/xPwVoLzYuLLS7Es6AN7gDjnSy2_VNVzzkriyYGKJQ6xvfwKzeZnSYc87/L%20French%20Blue%20Provincial%20Grain%20Sack%20-%20Vertical%20Stripe%20-%20Chambray%20Blue.jpg
+11 13728995 https://img.spoonflower.com/c/13728995/i/l/OUx3lyhL-EskuDHPUUwqEz3Tr10GmcZlrkhzNbtXOdSYsVue3NsX2w/Large%20Monticello%20Dusty%20Blue%20Green%20and%20Butterscotch%20on%20CREAM%20copy.jpg
+12 17761350 https://img.spoonflower.com/c/17761350/i/l/G-tfe_moQ2Fxo0vdCZMFAUpyGOf3IXtw_dc-RBJZMxJ8mCRnhYEs_w/Marigold%20-%20extra%20large%20-%20dusty%20blue%20and%20sage%20green.jpg
+13 5151893 https://img.spoonflower.com/c/5151893/i/l/OOpnAf8rdPlwKduf_p9JZ3ceXF1AH3q1wOxaOW4jGW1xp8ujDwoj/William%20Morris%20Honeysuckle%20Medium.jpg
+14 15252682 https://img.spoonflower.com/c/15252682/i/l/zllDIbtnKSxhpAU4BCoGe9oxlcnm4sYONrI2P5S2i4eT5GwazMiA9KOt/scallop%20fans%20-%20creamy%20white%20french%20grey%20blue%20-%20art%20deco%20geometric%20seashells.jpg
+15 15095313 https://img.spoonflower.com/c/15095313/i/l/27eDvAz4oSRRVBxJg7PYbP0g2T4WzCAM4ttKqlLLp5UwSOErZyGHhQ/French%20Country%20Floral-%20Original%20(SM).jpg
+16 9987142 https://img.spoonflower.com/c/9987142/i/l/s7_WKsxLRTYlMGszwItz2uJuc7pTYf-om67s7lUsbJbb_QEKcbJm/Daisy%20Dreams-Jumbo.jpg
+17 7354857 https://img.spoonflower.com/c/7354857/i/l/LFAjhyEOs_8n7yF41IfrkQ93WmSIj2C7yAIYsa45-2mRxtVl2fv7/greenery%20stripe.jpg
+18 14800343 https://img.spoonflower.com/c/14800343/i/l/fQlXFf4kz_fUfirZubcIHJKyv_DwRPlKefy6dglSMo09I4FpFPaZtA/Dark%20Moody%20Floral%20Pattern.jpg
+19 15558511 https://img.spoonflower.com/c/15558511/i/l/LyKBy7o-nnUW76tEvpK6EkZS8pp6EpPbuBL07gAuG2g7FyDIFhRhag/Butterfly%20Chinoiserie%20(cream)%20LRG.jpg
+20 14372386 https://img.spoonflower.com/c/14372386/i/l/bIcYljzakkCM8r4S8rzx5Uh0VVAh7zGWtWCgYpXk8akysnTMVn6uPGOT/Modern%20Moody%20Dark%20Green%20Plaid%20for%20Cabincore%20Accent%20Wall.jpg
+21 12878048 https://img.spoonflower.com/c/12878048/i/l/gKjA4laCdsy1ZENnj4uZucCqwPompngl7t7AGXPOBWR975wf4ktrlg/Blackthorn%20by%20William%20Morris%20-%20antique%20colors%20(24%20inch%20wide%20pattern).jpg
+22 7988956 https://img.spoonflower.com/c/7988956/i/l/4CoghucmbBVsd6cOCt8IhrLLCpM4_49ySFP2Vxgw8iCzkio0jpGk-yY/KALAMI%20LINEN%20SIMPLE.jpg
+23 12479233 https://img.spoonflower.com/c/12479233/i/l/xdh0Nq6CqEvdNE7TG43W_N_CWvtwhESf0kQaGD8a3sea2OpM9FKuJNPw/Large%20%2F%20Sketch%20Peonies%20in%20Latte%20on%20Off-White.jpg
+24 15606286 https://img.spoonflower.com/c/15606286/i/l/MJlATdAD8EcP0qw9eEfR7hV_rsrxRmBO1st5l7855Be8X8fzmmYKig/ACORN%20IN%20DOVE%20AND%20LINEN%20(Arts%20%26%20Crafts%20Neutrals)%20-%20WILLIAM%20MORRIS.jpg
+25 12049973 https://img.spoonflower.com/c/12049973/i/l/pb2_x29wgWHfCb95L73VrasQVSGZlYOxbsnTJsRLayZ4iJ4Dxm1fjISd/Art%20Deco%20Swans%20-%2012%22%20-%20Duck%20Egg%20on%20Soft%20Cream%20-%2012%22.jpg
+26 12894549 https://img.spoonflower.com/c/12894549/i/l/BYnY8VUDcPGxt9fmX_UuleD8jxEyaEUOHd75pgoGsPCAc1-m6RoHXQ/Emma%20Stripe%20Custom%20Gina3.jpg
+27 15914489 https://img.spoonflower.com/c/15914489/i/l/qvd-yVNrW1sJ3WU00bcC6IGD5vDwP2acpgc0v0FbCMRckzHVSuu_9Q/HALI%20VINTAGE%20MAIA.jpg
+28 18719041 https://img.spoonflower.com/c/18719041/i/l/WWNbO_oP-vIGgLXTa5QM92DamAGeHYBAXBCx6E-vEWmzI6rAwC-xZQ/Mughal-flowers-block%20print%20neutral-French%20country%20linen%20texture.jpg
+29 9709002 https://img.spoonflower.com/c/9709002/i/l/OLcU5FpiijqeRRht0vB9Ff7T2yavbvqkylAAR6Vj3rueszlpGZHR/tiger%20and%20peacock%20dark%20green%20(large%20scale).jpg
+30 13920815 https://img.spoonflower.com/c/13920815/i/l/pDQK8lmawvKwbJkOXm3VbBgkeP9UTiR_tTLjj9mhXyjnx8-F08wLlg/Elegant%20Art%20Deco%20bats%20and%20flowers%20-Teal%20gold%20black%20and%20pink%20-jumbo.jpg
+31 10862296 https://img.spoonflower.com/c/10862296/i/l/UiSFL6Urwbrp_EmnPEgKCioe8dcnUbw5f26WZ8gtRpfTVtHSSH9frw/THISTLE.jpg
+32 17617859 https://img.spoonflower.com/c/17617859/i/l/KskSUhvRiF52Was6aabakwQVf8la4NEhUL8PACNvK_w4UXvnQwJ4rw/Cat%20And%20Toilet%20Paper%20Art%20Nouveau%20Bg%20Green%20100Size.jpg
+33 13584767 https://img.spoonflower.com/c/13584767/i/l/Axr3WnIvk7jzzLGNneaoUk_oiE8wAcVbGfbxyHAUeqJ8qAxN8opZhw/OG%20Bubble%20Gum%20FRANKIE%20Floral%20Print%20in%20Charcoal.jpg
+34 13629046 https://img.spoonflower.com/c/13629046/i/l/YeyvofCsV7xHMynFyF6Ju20tZp4xkvNpXiXHYZIlOwuBYcL6FgLxVA/Vincent%20Van%20Gogh%20Almond%20Blossom%20in%20Vintage%20White%20Sage%20Green%20Blush%20Pink.jpg
+35 10828427 https://img.spoonflower.com/c/10828427/i/l/J0pAQKNyHi1lGeJuy85c6FR14CRO6bzEnKiOYDzPSTbxX2EmFNRsmw/Henrietta%20floral%20(light).jpg
+36 13214654 https://img.spoonflower.com/c/13214654/i/l/moXFhSO56fr1f8KjPsBWS8AQNe9F1lFzjE8hm5yNnxftOnQKK5Ps4Q/WILLOW%20BOUGH%20IN%20PALE%20IVORY%20(Arts%20%26%20Crafts%20Neutrals)%20-%20WILLIAM%20MORRIS.jpg
+37 12904568 https://img.spoonflower.com/c/12904568/i/l/ZGghP2iO3iirxDRtx4Qlw1cvsyEI2VrH3O5kdBmlQD3lT8NpIJSCznIe/Petal%20Prism%20L%20-%20dark%20blue%20gray%20gold%20Half%20drop.jpg
+38 17530673 https://img.spoonflower.com/c/17530673/i/l/C341zvfshDbs3A-oQkJCBW65CHU0GrrFrZI3zuoEMQoUEIOFhKWDZA/(L)%20Toilet%20aesthetics%20-%20gold%20and%20grey%20Damask%20toilet%20paper%20and%20toilet%20brush.jpg
+39 10125958 https://img.spoonflower.com/c/10125958/i/l/iTW_0DIRvEeF5hVHknTZ5LzMsNAR87AyvO6qWfTBI8hQ0N_LRTZTuKaU/Vincent%20Van%20Gogh%20Almond%20Blossom%20sage%20green.jpg
+40 14150480 https://img.spoonflower.com/c/14150480/i/l/c-6ZcW4y-ogMmKZw1SxFlV8FNcmlaw2ivzx50pJpov_1bb0VLV4r1w/AEGEAN%20STRIPE%20BLACK.jpg
+41 12135529 https://img.spoonflower.com/c/12135529/i/l/dAXqfaAuUfP5zqPC3moSrwYASsTZSQHv42HisJlW0dZWVivmsRCUf5dQ/neutral%20fall%20plaid%20-%20OG%20-%20LAD21.jpg
+42 17742136 https://img.spoonflower.com/c/17742136/i/l/SB4Giu08jCv6F5HQvs8D3fB9fy1J1sBACH3KwEkmDztZPH4rkcI_4suL/Boho%20Jungle%20Navy%20Blue%20Off%20White%20Clay%20Tan%20Refined%20Bohemian%20Cottagecore%20Large.jpg
+43 13918453 https://img.spoonflower.com/c/13918453/i/l/QmtQByYe0e1-UfY6xilbr9pzMdxaV9qQ8ymDx_fjEKbcVQwCQmRM6w/Mermaid%20in%20Moonlight.jpg
+44 11464311 https://img.spoonflower.com/c/11464311/i/l/XflThBd39cMHhfwMwVJ_FNDLp7Nv7_1BRIiJ_Zhm0P1cS3nW7MHUEw/Art%20Deco%20Swans%20-%2012%22%20Wide%20Repeat%20-%20Off-White%20on%20Off-White.jpg
+45 14288984 https://img.spoonflower.com/c/14288984/i/l/L3d21OZ7wMHtvywM6ncf0zBXkpzV9Nws_y1oCWgQm7G83qIzwEuMdWl_/Grasscloth-Ernesto%20Blue%20Trees-%20Agreeable%20Gray%20Wallpaper.jpg
+46 12788028 https://img.spoonflower.com/c/12788028/i/l/FhU9Mb6HUZlZKdf-GNtrA7H0BQ-VG1SSBC19KOqlVDTYbsisgrUXhYLy/LA%20VILLE%20VINE%20LINEN%20SAP.jpg
+47 10719320 https://img.spoonflower.com/c/10719320/i/l/xYk0X7OTuMNgjRBVnmqpHDa1FvSCQIuy41CfLlwFK34r2KE3m76Hqg/Dark%20Blue%20and%20Brown%20Fine%20Line%20Plaid%20Large%20Scale%20for%20Wallpaper%20and%20Home.jpg
+48 17742893 https://img.spoonflower.com/c/17742893/i/l/rpN7sqXKZgSact4GmlC1aRAWwoL7zlFHEFRWMzO9mj2SlaYykMVO1w/Terracotta%20Blossoms.jpg
+49 18891417 https://img.spoonflower.com/c/18891417/i/l/PZjWyBhLpQAr9-8awZNNDqNNKwB9U0RDQuRWtCFoalN1ypGjAf_rMA/Heritage%20Charm%20-%20Botanical%20Tapestry%20-%20Twilight%20Garden.jpg
+50 16859966 https://img.spoonflower.com/c/16859966/i/l/4EO7vYv7VZGZ3esq6DqnS2EeDJ7a_mZjNh-sx5rx6Ww4kIZr1x9iOQ/palm%20stripes%20-%20dusty%20blue%20and%20brown%20-%20large.jpg
+51 3564038 https://img.spoonflower.com/c/3564038/i/l/8amqPMMSBQugjvjTGisJwMJ9-dfuiRhdcvRFJigpP-xwD6_M7yh3/Grasscloth%20Fabric%20and%20Wallpaper%20in%20Natural.jpg
+52 16014251 https://img.spoonflower.com/c/16014251/i/l/7g7ZvHHvdLWKczQryTk9v6Vdh1ns83UvxCD8vgFAH_k60FheZ_zqOUqs/Eloise%20-grandmillennial%20stripes%20climbing%20watercolour%20vine%20leaves-sage%20blue.jpg
+53 6401436 https://img.spoonflower.com/c/6401436/i/l/HKky6wDgtmKWXdMQ-rBrkfW-9hRhnjLrc7LCYlBIR4uzZTQOTFH-/Martini%20Mermaids.jpg
+54 5608890 https://img.spoonflower.com/c/5608890/i/l/Wb_5DfZgGxPXb0w-oQ3mvJnRSbNgkyPD8bhEnWjTcDo3LQn32tvq/Large%20Scale%20Japanese%20Garden%20Sage%2024%20in%20repeat.jpg
+55 11388473 https://img.spoonflower.com/c/11388473/i/l/vdYEIlpLiO4UOnPXksfCFWS5b8RPYOBmEfbe2BVqr1gzA4xq26xNQw/Soft%20Blue%20and%20greens%20on%20white.jpg
+56 8223425 https://img.spoonflower.com/c/8223425/i/l/aQo1yoOUa_lFsGUvG7pWDebv5zARtW7hAg4obgb3rWoC8XPEUWeMfUY/Grandmillennial%20Peonies%20Gothic%20Dramatic%20Heritage%20timeless%20Elegance%20Blooms.jpg
+57 14289044 https://img.spoonflower.com/c/14289044/i/l/FUSHDoCSgXF6Pw3FIwCJswKrlRjhgMaX4lpjF8wwuKdgn8qrbg1JwOyI/Cowboy%20Toile%20-%20Warm.jpg
+58 12611067 https://img.spoonflower.com/c/12611067/i/l/eeobrJ2oIIzV1i7nz_LUqP6dL51GShV9uJpmnHQsUK13UhtIsRLh_TyJ/Peonies%20-neutral%20botanical%20Art%20Nouveau%20large%20scale%20Victorian%20wallpaper.jpg
+59 1743921 https://img.spoonflower.com/c/1743921/i/l/z2t7jH9rQo5KIcp8OA2Rw1nsk--b69DHFsUX4ayNuuU31gIqwLt9/William%20Morris%20Honeysuckle.jpg
+60 14281611 https://img.spoonflower.com/c/14281611/i/l/Bm-YLtsvQhxCjNaYDpu5QMk4h-Ra1EZfBRgtKi6EimNqaR1TJRHODA/Distressed%20Neutral%20Beige%20Block%20Print%20Plaid%20Extra%20Large%20Scale%20for.jpg
+61 18506377 https://img.spoonflower.com/c/18506377/i/l/xG_z_qcGAKlYlc-vayq3j8MG25uK0disrO8OnGliyWKdH4BebKn_1Q/Linen%20look%20rustic%20farmhouse%20ticking%20stripe%20wide%20%2F%20light%20blue%20and%20cream.jpg
+62 14576878 https://img.spoonflower.com/c/14576878/i/l/TG9ZVJ3ZD4RcOlAfbQ_vVwWy0Cknyj9Ds8lB047ovZyG5joaKV_0jQ/Garden%20Bloom%20Floral%20Jumbo%20Large%20Blue%20Hufton%20Studio.jpg
+63 10021703 https://img.spoonflower.com/c/10021703/i/l/eMMP1maf-T1zWZL7pNkR5caDldAFeu5cl_EnxbbCWs_1C02sDGC5Pw/Sexy%20Mushrooms.jpg
+64 10749527 https://img.spoonflower.com/c/10749527/i/l/Vpzr-cUDBnuasCWsnxoM2hpAFrhPkTtjkUdK1vJBh_NsYcvxxPktWnV3/Forest%20Green%20%26%20Cream%20Alien%20Abduction.jpg
+65 18166792 https://img.spoonflower.com/c/18166792/i/l/v2di-wcai-vlinaOIxseqSk6J6EOh6Mu-il8jMl0-HA1M2yoQQZ_3Q/Antique%20Beige%20Cottage%20Floral%20Vintage%20Inspired%20Bohemian%20Earthy%20Neutral%20(L).jpg
+66 16520351 https://img.spoonflower.com/c/16520351/i/l/csoqg95FQbXn399CyxpBPhLAdsSeiSOmWUOp6Q_ed6OdciPKMhRGWw/Art%20Nouveau%20Frogs%20with%20lily%20of%20the%20valley%20Luna%20moth%20and%20moon%20and%20stars.jpg
+67 17610058 https://img.spoonflower.com/c/17610058/i/l/A0r7LfoGKbIY-Hs5jrKIJcxM37vHdiBwv9iYlLIVXNPXKa2HZGisNw/Spicy%20life%20-%20Large%20scale.jpg
+68 12869734 https://img.spoonflower.com/c/12869734/i/l/2j3ebziLidgwhSRol0K2E2dbzXLGeTzLUnoDz1Jn7qot0siGkizj5A/Sophisticated%20Botanicals%20Black.jpg
+69 17256838 https://img.spoonflower.com/c/17256838/i/l/y7mnVPsOy1M6h4ssFnIYwCjDsmD5bq2lZculs4qQzmWeR0UpmolDxjfN/JUMBO%20%2F%20Hummingbird%20Trellis%20%2F%20Flowers%20Leaves%20on%20Vines%20%2F%20Modern%20Vintage.jpg
+70 11478772 https://img.spoonflower.com/c/11478772/i/l/wJjLv-_nXv1I0pJPjkoy6tWYsFUAECr1voVi4vZJHb1GUgjaIq-Nyg/Queen%20Anne%20color%20variation%20background%20F6F5EC.jpg
+71 12929681 https://img.spoonflower.com/c/12929681/i/l/W6vDHKClZOzgXSqnVzpa81BjFiAUgyJbSsdXa3uNYpE4hdXMie6PFlXP/(large%20scale)%20Ivy%20Stripes%20-%20Vertical%20Coastal%20Blue%20on%20Cream%20-%20LAD22.jpg
+72 12906217 https://img.spoonflower.com/c/12906217/i/l/z3UeyEwyZV-3G-lVMZNucFeru9T39GQmUVI-gGxIeYFGorz9A-0vyVGK/maximalist%20folk%20flowers%2024%22.jpg
+73 15062910 https://img.spoonflower.com/c/15062910/i/l/gD_qHMShXGXN1bLG4R_xhF4a0TW3gBHRE4fA3-rSoHgk3NiXNccSHo6H/Yellow%20Vintage-Inspired%2070s%20Floral%20Cottage%20Garden.jpg
+74 12788019 https://img.spoonflower.com/c/12788019/i/l/593JDOcuzyuZYvwNZwh5pjYSOSdvkcaSiy8ONwtIj9sF-Z5xsQaGfQ/LA%20VILLE%20VINE%20LINEN%20SAND.jpg
+75 14163752 https://img.spoonflower.com/c/14163752/i/l/4TaM2Vupc7zvhpswuKY5obd_Fw32-VZw8JiMooKYZXTMcI5FoHNIr_i2/Wonderful%20poisonous%20lily%20of%20the%20valley%20-%20M.jpg
+76 15235563 https://img.spoonflower.com/c/15235563/i/l/UCeiwmn4o38HBjGVaeMMX0Napw0vjph-kZuzkAypVdJlzRN--LlE_w/French%20Country%20Vintage%20Birds%20and%20Roses%20Blue%20Large.jpg
+77 15910606 https://img.spoonflower.com/c/15910606/i/l/c7Mzl2i0eKWpdgqqxDxDuARRa1XCIpcAb1RyHiW8tiRMsUxZtpBql2cj/UMBRIA%20DUSK%20WOODS.jpg
+78 10473378 https://img.spoonflower.com/c/10473378/i/l/T9SuFTm4jLR6T82x46-HhaeZ0y1hsxLASavx4NZyTGODE31-EilkWw/Custom%20Blues%202%20Anderson%20Ticking%20Stripe.jpg
+79 16701521 https://img.spoonflower.com/c/16701521/i/l/jFxJl-Vb2bgBRPHl5PgU2rE8LAT2JKZM1rHMfai-rsNj73VFGApbFw/Bluebirds%20in%20the%20Brush%20Blue%20%26%20Gold%20-%20Large.jpg
+80 11237842 https://img.spoonflower.com/c/11237842/i/l/Qgw86DEKuu949q-FAcQAf3PQYbdQmTu0Sno_GclwCYV5GNRRboS7nQ/Sonetto%20Floral%20(brown)%20JUMBO.jpg
+81 6402897 https://img.spoonflower.com/c/6402897/i/l/2MLQAk27JREF1Zz08Whrb1iyAv4nEui7bk1xVaArdUHwlJau738z/Martini%20Mermaids%20on%20Coral.jpg
+82 18381034 https://img.spoonflower.com/c/18381034/i/l/QPLJz86dvfO7_orZlBqtfNjAVOV5kit2DFzyHdRY8r4YWraK6Q132g/ACORN%20IN%20SAND%20%26%20LEAF%20(Traditional%20Arts%20%26%20Crafts)%20-%20WILLIAM%20MORRIS.jpg
+83 16019794 https://img.spoonflower.com/c/16019794/i/l/tk3_bg5kMpwxE0-z4KdKY6_UtLLEeuuheYL9pLDLk4Py3X6UizRCYw/Rye%20-%20Watercolor%20Grandmillennial%20climbing%20vine%20leaves%20stripes%20-%20green%20blue.jpg
+84 15622273 https://img.spoonflower.com/c/15622273/i/l/hi570a06Ds7d55u5ff0TR-BBdfpqXRSZ0mZ-tPDH7Nbd04fK9wSLsw/Cat%20Cameos.jpg
+85 11757941 https://img.spoonflower.com/c/11757941/i/l/Yf4M7OAHrOWnGYAYpEYzPAts-MQ4Uia72mMo3rketJfbbOq5CfT3kr05/Japanese%20Garden%20Chantilly%20Green%2024inch%20Repeat.jpg
+86 18035772 https://img.spoonflower.com/c/18035772/i/l/GLZFh6fG5AF8dXKh3O8m1TSOvfTlg7yS9MyhWKX86pnpOb4eFBrDQQ/Trees%20Toile%20de%20jouy%20Green%20on%20off%20white.jpg
+87 17809925 https://img.spoonflower.com/c/17809925/i/l/ZBXJmtpmSdJtZrWWM5fXmuSwX--T_wVHxkopyepi0kf72QvX35GBtkH0/Heritage%20revival%20floral%20poppy%20neutral%20texture%20cool%20grey.jpg
+88 16594395 https://img.spoonflower.com/c/16594395/i/l/5Ynxhp6pv2FTMUGJ2AL8TOKEJu0yM7S3eTQG6Sun0j8c18WWOgdORQ/(L)%20Abstract%20Zen%20Garden%20Concentric%20Arches%20and%20Ovals%20on%20Beige%20Raked.jpg
+89 15300002 https://img.spoonflower.com/c/15300002/i/l/9_fJ4AGBC-0ShKm1k4YvTaT5-HqOEO7fn6kNouPGXYjfjOolecoj7g/Vintage%20Wildflowers.jpg
+90 12441406 https://img.spoonflower.com/c/12441406/i/l/zjpgq1Taf-FRrUY_AGBkPSInk6JGCT2IYyu-okZY1OvKBpJZ2AYvIQ/large%20-%20aara%20palm%20floral%20-%20natural%2Fpink.jpg
+91 11483815 https://img.spoonflower.com/c/11483815/i/l/euxNxbA0erYkUatwaD5jJkb7iKu2lF_KomZS5OWj4_u0k5hSmyRoOA/Updated%20Large%20scale%20Natural%20Habitat%20of%20Bees%20and%20Moths%20wild%20grass%20and.jpg
+92 13949729 https://img.spoonflower.com/c/13949729/i/l/KqHfaCjgewjDvLLDrvFJZqLSXGBrdz36TQzNhUUEpXOqbQOq1CCHGg/Strawberry%20Thief%20William%20Morris%20Vintage%20Bird%20Design%20Smaller%20Scale.jpg
+93 14438928 https://img.spoonflower.com/c/14438928/i/l/zKfX0gAs8vhywSwtEvWiVZXyJ-rE_2vCCwKc8gl9ZtMuEIraQ7UEWWSV/Carrots%20Dance%20in%20green.jpg
+94 13957257 https://img.spoonflower.com/c/13957257/i/l/KcLrmcEaeD5oLbHwMv96HCDz388Y_wUW8hd340LIvPy_O-lfPkH59Q/Pimpernel%20William%20Morris%20Heritage%20Glamour%20%26%20Cottage%20Flowers%20Deco%20Sage%20Green.jpg
+95 14178793 https://img.spoonflower.com/c/14178793/i/l/EMBthR-3MWcElbB8_kOEPl3NpAj1Juu64QsU_WcRo5S4_4L-27XQRUvW/Grasscloth%20Wallpaper%20and%20Fabric%20-%20Natural%20-%20Faux%20Texture.jpg
+96 15006191 https://img.spoonflower.com/c/15006191/i/l/12nqw5P6W035mVw9u_S4pCLasph9L4RGtADTBKv0mEAG7NxsU5NYCxtc/Wonderful%20world%20of%20scandi%20blooms-mid%20century.jpg
+97 17081029 https://img.spoonflower.com/c/17081029/i/l/h0PXQQ3bYvXMQJgXqN3bjq_lKsjd0kVwToPhVVUjFwpE5hK_cubeuw/Weeping%20Branches.jpg
+98 14999334 https://img.spoonflower.com/c/14999334/i/l/5QVdbqGr33wH-cG53iK2Yl_uo3-efpEV1GFsCdrcQaaKRAn9mQCXg7UA/Smaller%20Clarabelle%20Quiet%20blue%20on%20Cream%20copy%202.jpg
+99 12929666 https://img.spoonflower.com/c/12929666/i/l/wdetMpAAop4dccGufodAnh7u1TqCCV81FhKOBDm6nif19vZyOIsF9A/(large%20scale)%20Ivy%20Stripes%20-%20Vertical%20Sage%20on%20Cream%20-%20LAD22.jpg
+100 13918325 https://img.spoonflower.com/c/13918325/i/l/47TcVjqTVlFdsMxj6YKjw1vsnV1UkxPhCy6oC0ok907iazMi5RrhGnM6/Art%20Deco%20Sunset%20And%20Leaves.jpg
diff --git a/whimsical-compare/public/index.html b/whimsical-compare/public/index.html
new file mode 100644
index 0000000..2fc1abc
--- /dev/null
+++ b/whimsical-compare/public/index.html
@@ -0,0 +1,202 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Whimsical Top 100 — Original vs. Ours</title>
+<style>
+ :root { --cols: 1; --gap: 22px; }
+ * { box-sizing: border-box; }
+ body { margin: 0; font-family: -apple-system, "Segoe UI", Roboto, sans-serif; background: #f6f4ef; color: #23201b; }
+ header { position: sticky; top: 0; z-index: 20; background: #fffdf8; border-bottom: 1px solid #e4ddd0;
+ padding: 14px 22px; display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
+ header h1 { font-size: 18px; margin: 0; font-weight: 600; letter-spacing: .3px; }
+ header .sub { color: #8a8172; font-size: 12px; }
+ .controls { margin-left: auto; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
+ .controls label { font-size: 12px; color: #6b6355; display: flex; align-items: center; gap: 6px; }
+ select, input[type=range] { accent-color: #7a6a52; }
+ .wrap { padding: 22px; }
+ .grid { display: grid; grid-template-columns: repeat(var(--cols), 1fr); gap: var(--gap); }
+ .card { background: #fffdf8; border: 1px solid #e4ddd0; border-radius: 12px; overflow: hidden; display: flex; flex-direction: column; }
+ .row { display: grid; grid-template-columns: 1fr 1fr; }
+ .pane { position: relative; }
+ .pane img { width: 100%; aspect-ratio: 1/1; object-fit: cover; display: block; background: #efe9de; }
+ .tag { position: absolute; top: 8px; left: 8px; font-size: 10px; font-weight: 600; letter-spacing: .5px;
+ text-transform: uppercase; padding: 3px 8px; border-radius: 20px; background: rgba(255,253,248,.92); color: #6b6355; }
+ .tag.ours { background: #2e5b3f; color: #fff; }
+ .pending { display: flex; align-items: center; justify-content: center; width: 100%; aspect-ratio: 1/1;
+ background: repeating-linear-gradient(45deg, #efe9de, #efe9de 12px, #e7e0d3 12px, #e7e0d3 24px);
+ color: #8a8172; font-size: 12px; text-align: center; padding: 12px; }
+ .meta { padding: 10px 14px; border-top: 1px solid #efe9de; }
+ .meta .name { font-size: 13px; font-weight: 600; }
+ .meta .small { font-size: 11px; color: #8a8172; margin-top: 2px; }
+ .verdict { font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 10px; }
+ .v-OK { background: #dcefe2; color: #2e5b3f; } .v-BLOCK { background: #f5d9d4; color: #a33; }
+ .v-none { background: #eee6d6; color: #8a8172; }
+ .actions { display: flex; gap: 8px; padding: 0 14px 12px; }
+ button { font: inherit; font-size: 12px; border: 1px solid #cabfa9; background: #fff; color: #4a4335;
+ padding: 6px 12px; border-radius: 8px; cursor: pointer; }
+ button.primary { background: #2e5b3f; color: #fff; border-color: #2e5b3f; }
+ button:disabled { opacity: .5; cursor: default; }
+ .chat { display: none; border-top: 1px solid #efe9de; padding: 12px 14px; background: #faf7f0; }
+ .chat.open { display: block; }
+ .log { max-height: 180px; overflow-y: auto; font-size: 12px; display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
+ .msg { padding: 6px 10px; border-radius: 8px; max-width: 85%; }
+ .msg.u { background: #e7ddc8; align-self: flex-end; }
+ .msg.a { background: #eef1e9; align-self: flex-start; }
+ .chatbar { display: flex; gap: 8px; }
+ .chatbar input { flex: 1; padding: 7px 10px; border: 1px solid #cabfa9; border-radius: 8px; font: inherit; font-size: 12px; }
+ .spin { display: inline-block; width: 12px; height: 12px; border: 2px solid #cabfa9; border-top-color: #2e5b3f;
+ border-radius: 50%; animation: s .7s linear infinite; vertical-align: -2px; }
+ @keyframes s { to { transform: rotate(360deg); } }
+</style>
+</head>
+<body>
+<header>
+ <div>
+ <h1>Whimsical Top 100 — <span style="color:#8a8172">Original vs. Ours</span></h1>
+ <div class="sub">Spoonflower bestsellers (left) · our settlement-safe originals (right) · chat to adjust & regenerate</div>
+ </div>
+ <div class="controls">
+ <label>Sort
+ <select id="sort">
+ <option value="rank">Bestselling</option>
+ <option value="orders">Most orders</option>
+ <option value="favs">Most favorites</option>
+ <option value="pending">Needs ours</option>
+ <option value="name">Title A→Z</option>
+ </select>
+ </label>
+ <label>Density
+ <input type="range" id="density" min="1" max="4" step="1" value="1">
+ </label>
+ <span id="stat" class="sub"></span>
+ </div>
+</header>
+<div class="wrap"><div class="grid" id="grid"></div></div>
+
+<script>
+const $ = s => document.querySelector(s);
+let DATA = [];
+const chats = {}; // id -> {history, prompt}
+
+function verdictBadge(v) {
+ const cls = v === 'OK' ? 'v-OK' : v === 'BLOCK' ? 'v-BLOCK' : 'v-none';
+ return `<span class="verdict ${cls}">${v || 'not yet'}</span>`;
+}
+
+function card(d) {
+ const ours = d.ours
+ ? `<img loading="lazy" src="${d.ours}?t=${Date.now()}" alt="ours">`
+ : `<div class="pending" id="pend-${d.id}">generating our original…<br>(or chat below to make it now)</div>`;
+ return `<div class="card" data-id="${d.id}">
+ <div class="row">
+ <div class="pane"><span class="tag">Original · #${d.rank}</span>
+ <a href="https://www.spoonflower.com/en/wallpaper/${d.id}" target="_blank" rel="noopener noreferrer">
+ <img loading="lazy" src="${d.original}" alt="${d.name}"></a></div>
+ <div class="pane" id="ourpane-${d.id}"><span class="tag ours">Ours</span>${ours}</div>
+ </div>
+ <div class="meta">
+ <div class="name">${d.name || 'Untitled'}</div>
+ <div class="small">by ${d.designer || '—'} · ${d.orders} orders · ${d.favs} favs · ${verdictBadge(d.verdict)}
+ ${d.updated ? '· <span title="last updated">'+d.updated+'</span>' : ''}</div>
+ <div class="small" style="margin-top:4px;color:#a99">Our brief: ${d.brief || '—'}</div>
+ </div>
+ <div class="actions">
+ <button onclick="toggleChat('${d.id}')">💬 Adjust</button>
+ <button class="primary" onclick="regen('${d.id}')" id="rebtn-${d.id}">↻ Regenerate</button>
+ </div>
+ <div class="chat" id="chat-${d.id}">
+ <div class="log" id="log-${d.id}"></div>
+ <div class="chatbar">
+ <input id="in-${d.id}" placeholder="e.g. make it more muted, add tiny stars, softer palette…"
+ onkeydown="if(event.key==='Enter')send('${d.id}')">
+ <button onclick="send('${d.id}')">Send</button>
+ </div>
+ </div>
+ </div>`;
+}
+
+function render() {
+ const s = $('#sort').value;
+ const arr = [...DATA].sort((a, b) => {
+ if (s === 'rank') return a.rank - b.rank;
+ if (s === 'orders') return b.orders - a.orders;
+ if (s === 'favs') return b.favs - a.favs;
+ if (s === 'name') return (a.name || '').localeCompare(b.name || '');
+ if (s === 'pending') return (a.ours ? 1 : 0) - (b.ours ? 1 : 0);
+ });
+ $('#grid').innerHTML = arr.map(card).join('');
+ const done = DATA.filter(d => d.ours).length;
+ $('#stat').textContent = `${done}/${DATA.length} ours ready`;
+}
+
+function toggleChat(id) { $(`#chat-${id}`).classList.toggle('open'); }
+
+async function send(id) {
+ const inp = $(`#in-${id}`); const msg = inp.value.trim(); if (!msg) return;
+ inp.value = '';
+ const log = $(`#log-${id}`);
+ chats[id] = chats[id] || { history: [], prompt: DATA.find(d => d.id === id).prompt };
+ log.insertAdjacentHTML('beforeend', `<div class="msg u">${msg}</div>`);
+ const wait = document.createElement('div'); wait.className = 'msg a'; wait.innerHTML = '<span class="spin"></span>';
+ log.appendChild(wait); log.scrollTop = log.scrollHeight;
+ const d = DATA.find(x => x.id === id);
+ const r = await fetch('/api/chat', { method: 'POST', headers: { 'content-type': 'application/json' },
+ body: JSON.stringify({ id, message: msg, history: chats[id].history, brief: d.brief, prompt: chats[id].prompt }) });
+ const j = await r.json();
+ wait.remove();
+ log.insertAdjacentHTML('beforeend', `<div class="msg a">${j.reply || '…'}</div>`);
+ chats[id].history.push({ role: 'user', content: msg }, { role: 'assistant', content: j.reply || '' });
+ if (j.prompt) { chats[id].prompt = j.prompt;
+ log.insertAdjacentHTML('beforeend', `<div class="msg a" style="font-size:11px;color:#8a8172">↻ Ready — hit Regenerate to apply.</div>`); }
+ log.scrollTop = log.scrollHeight;
+}
+
+async function regen(id) {
+ const btn = $(`#rebtn-${id}`); btn.disabled = true; btn.innerHTML = '<span class="spin"></span> rendering…';
+ const d = DATA.find(x => x.id === id);
+ const prompt = (chats[id] && chats[id].prompt) || d.prompt;
+ const r = await fetch('/api/regenerate', { method: 'POST', headers: { 'content-type': 'application/json' },
+ body: JSON.stringify({ id, prompt }) });
+ const j = await r.json();
+ btn.disabled = false; btn.innerHTML = '↻ Regenerate';
+ if (j.ours) {
+ d.ours = j.ours.split('?')[0]; d.verdict = 'OK';
+ $(`#ourpane-${id}`).innerHTML = `<span class="tag ours">Ours</span><img src="${j.ours}" alt="ours">`;
+ $(`#stat`).textContent = `${DATA.filter(x => x.ours).length}/${DATA.length} ours ready`;
+ } else {
+ alert(j.note || j.error || 'Regenerate failed');
+ }
+ if (j.cost) console.log(`regen ${id}: ${j.cost} (${j.secs}s)`);
+}
+
+$('#sort').onchange = render;
+$('#density').oninput = e => document.documentElement.style.setProperty('--cols', e.target.value);
+// persist controls
+['sort', 'density'].forEach(k => {
+ const el = $('#' + k), v = localStorage.getItem('whim_' + k);
+ if (v !== null) { el.value = v; if (k === 'density') document.documentElement.style.setProperty('--cols', v); }
+ el.addEventListener('change', () => localStorage.setItem('whim_' + k, el.value));
+ el.addEventListener('input', () => localStorage.setItem('whim_' + k, el.value));
+});
+
+// poll for background-generated "ours" until all present
+async function load() {
+ DATA = await (await fetch('/api/designs')).json();
+ render();
+}
+load();
+setInterval(async () => {
+ const fresh = await (await fetch('/api/designs')).json();
+ let changed = false;
+ fresh.forEach(f => { const cur = DATA.find(d => d.id === f.id);
+ if (cur && !cur.ours && f.ours) { cur.ours = f.ours; cur.verdict = f.verdict; cur.brief = f.brief;
+ const pane = document.querySelector(`#ourpane-${f.id}`);
+ if (pane) pane.innerHTML = `<span class="tag ours">Ours</span><img src="${f.ours}?t=${Date.now()}" alt="ours">`;
+ changed = true; } });
+ if (changed) $('#stat').textContent = `${DATA.filter(d => d.ours).length}/${DATA.length} ours ready`;
+}, 15000);
+</script>
+</body>
+</html>
diff --git a/whimsical-compare/public/originals/10021703.jpg b/whimsical-compare/public/originals/10021703.jpg
new file mode 100644
index 0000000..69fe11e
Binary files /dev/null and b/whimsical-compare/public/originals/10021703.jpg differ
diff --git a/whimsical-compare/public/originals/10125958.jpg b/whimsical-compare/public/originals/10125958.jpg
new file mode 100644
index 0000000..0e6020b
Binary files /dev/null and b/whimsical-compare/public/originals/10125958.jpg differ
diff --git a/whimsical-compare/public/originals/10473378.jpg b/whimsical-compare/public/originals/10473378.jpg
new file mode 100644
index 0000000..a62ccd8
Binary files /dev/null and b/whimsical-compare/public/originals/10473378.jpg differ
diff --git a/whimsical-compare/public/originals/10719320.jpg b/whimsical-compare/public/originals/10719320.jpg
new file mode 100644
index 0000000..d7da5b9
Binary files /dev/null and b/whimsical-compare/public/originals/10719320.jpg differ
diff --git a/whimsical-compare/public/originals/10749527.jpg b/whimsical-compare/public/originals/10749527.jpg
new file mode 100644
index 0000000..eeb96c0
Binary files /dev/null and b/whimsical-compare/public/originals/10749527.jpg differ
diff --git a/whimsical-compare/public/originals/10828427.jpg b/whimsical-compare/public/originals/10828427.jpg
new file mode 100644
index 0000000..f90d222
Binary files /dev/null and b/whimsical-compare/public/originals/10828427.jpg differ
diff --git a/whimsical-compare/public/originals/10862296.jpg b/whimsical-compare/public/originals/10862296.jpg
new file mode 100644
index 0000000..4d74975
Binary files /dev/null and b/whimsical-compare/public/originals/10862296.jpg differ
diff --git a/whimsical-compare/public/originals/11237842.jpg b/whimsical-compare/public/originals/11237842.jpg
new file mode 100644
index 0000000..b1c2cfa
Binary files /dev/null and b/whimsical-compare/public/originals/11237842.jpg differ
diff --git a/whimsical-compare/public/originals/11388473.jpg b/whimsical-compare/public/originals/11388473.jpg
new file mode 100644
index 0000000..90213ac
Binary files /dev/null and b/whimsical-compare/public/originals/11388473.jpg differ
diff --git a/whimsical-compare/public/originals/11464311.jpg b/whimsical-compare/public/originals/11464311.jpg
new file mode 100644
index 0000000..aff66e1
Binary files /dev/null and b/whimsical-compare/public/originals/11464311.jpg differ
diff --git a/whimsical-compare/public/originals/11478772.jpg b/whimsical-compare/public/originals/11478772.jpg
new file mode 100644
index 0000000..883c4c5
Binary files /dev/null and b/whimsical-compare/public/originals/11478772.jpg differ
diff --git a/whimsical-compare/public/originals/11483815.jpg b/whimsical-compare/public/originals/11483815.jpg
new file mode 100644
index 0000000..aa6c1c2
Binary files /dev/null and b/whimsical-compare/public/originals/11483815.jpg differ
diff --git a/whimsical-compare/public/originals/11495382.jpg b/whimsical-compare/public/originals/11495382.jpg
new file mode 100644
index 0000000..54197c1
Binary files /dev/null and b/whimsical-compare/public/originals/11495382.jpg differ
diff --git a/whimsical-compare/public/originals/11757941.jpg b/whimsical-compare/public/originals/11757941.jpg
new file mode 100644
index 0000000..7755ea4
Binary files /dev/null and b/whimsical-compare/public/originals/11757941.jpg differ
diff --git a/whimsical-compare/public/originals/12049973.jpg b/whimsical-compare/public/originals/12049973.jpg
new file mode 100644
index 0000000..e5d4981
Binary files /dev/null and b/whimsical-compare/public/originals/12049973.jpg differ
diff --git a/whimsical-compare/public/originals/12135529.jpg b/whimsical-compare/public/originals/12135529.jpg
new file mode 100644
index 0000000..cf1e9d2
Binary files /dev/null and b/whimsical-compare/public/originals/12135529.jpg differ
diff --git a/whimsical-compare/public/originals/12441406.jpg b/whimsical-compare/public/originals/12441406.jpg
new file mode 100644
index 0000000..2f09b65
Binary files /dev/null and b/whimsical-compare/public/originals/12441406.jpg differ
diff --git a/whimsical-compare/public/originals/12448122.jpg b/whimsical-compare/public/originals/12448122.jpg
new file mode 100644
index 0000000..18c324e
Binary files /dev/null and b/whimsical-compare/public/originals/12448122.jpg differ
diff --git a/whimsical-compare/public/originals/12479233.jpg b/whimsical-compare/public/originals/12479233.jpg
new file mode 100644
index 0000000..d033be4
Binary files /dev/null and b/whimsical-compare/public/originals/12479233.jpg differ
diff --git a/whimsical-compare/public/originals/12611067.jpg b/whimsical-compare/public/originals/12611067.jpg
new file mode 100644
index 0000000..2f8be97
Binary files /dev/null and b/whimsical-compare/public/originals/12611067.jpg differ
diff --git a/whimsical-compare/public/originals/12788019.jpg b/whimsical-compare/public/originals/12788019.jpg
new file mode 100644
index 0000000..01278d6
Binary files /dev/null and b/whimsical-compare/public/originals/12788019.jpg differ
diff --git a/whimsical-compare/public/originals/12788028.jpg b/whimsical-compare/public/originals/12788028.jpg
new file mode 100644
index 0000000..efb9e5b
Binary files /dev/null and b/whimsical-compare/public/originals/12788028.jpg differ
diff --git a/whimsical-compare/public/originals/12804113.jpg b/whimsical-compare/public/originals/12804113.jpg
new file mode 100644
index 0000000..e66a704
Binary files /dev/null and b/whimsical-compare/public/originals/12804113.jpg differ
diff --git a/whimsical-compare/public/originals/12869734.jpg b/whimsical-compare/public/originals/12869734.jpg
new file mode 100644
index 0000000..08f0a86
Binary files /dev/null and b/whimsical-compare/public/originals/12869734.jpg differ
diff --git a/whimsical-compare/public/originals/12878048.jpg b/whimsical-compare/public/originals/12878048.jpg
new file mode 100644
index 0000000..1b14fdb
Binary files /dev/null and b/whimsical-compare/public/originals/12878048.jpg differ
diff --git a/whimsical-compare/public/originals/12894549.jpg b/whimsical-compare/public/originals/12894549.jpg
new file mode 100644
index 0000000..dae3ebf
Binary files /dev/null and b/whimsical-compare/public/originals/12894549.jpg differ
diff --git a/whimsical-compare/public/originals/12904568.jpg b/whimsical-compare/public/originals/12904568.jpg
new file mode 100644
index 0000000..84e0fe2
Binary files /dev/null and b/whimsical-compare/public/originals/12904568.jpg differ
diff --git a/whimsical-compare/public/originals/12906217.jpg b/whimsical-compare/public/originals/12906217.jpg
new file mode 100644
index 0000000..659236e
Binary files /dev/null and b/whimsical-compare/public/originals/12906217.jpg differ
diff --git a/whimsical-compare/public/originals/12929666.jpg b/whimsical-compare/public/originals/12929666.jpg
new file mode 100644
index 0000000..89e7cf2
Binary files /dev/null and b/whimsical-compare/public/originals/12929666.jpg differ
diff --git a/whimsical-compare/public/originals/12929681.jpg b/whimsical-compare/public/originals/12929681.jpg
new file mode 100644
index 0000000..f0bcf51
Binary files /dev/null and b/whimsical-compare/public/originals/12929681.jpg differ
diff --git a/whimsical-compare/public/originals/12929706.jpg b/whimsical-compare/public/originals/12929706.jpg
new file mode 100644
index 0000000..b4a7621
Binary files /dev/null and b/whimsical-compare/public/originals/12929706.jpg differ
diff --git a/whimsical-compare/public/originals/13214654.jpg b/whimsical-compare/public/originals/13214654.jpg
new file mode 100644
index 0000000..190b15d
Binary files /dev/null and b/whimsical-compare/public/originals/13214654.jpg differ
diff --git a/whimsical-compare/public/originals/13584767.jpg b/whimsical-compare/public/originals/13584767.jpg
new file mode 100644
index 0000000..5f028a0
Binary files /dev/null and b/whimsical-compare/public/originals/13584767.jpg differ
diff --git a/whimsical-compare/public/originals/13629046.jpg b/whimsical-compare/public/originals/13629046.jpg
new file mode 100644
index 0000000..ff65616
Binary files /dev/null and b/whimsical-compare/public/originals/13629046.jpg differ
diff --git a/whimsical-compare/public/originals/13728995.jpg b/whimsical-compare/public/originals/13728995.jpg
new file mode 100644
index 0000000..ded4c3d
Binary files /dev/null and b/whimsical-compare/public/originals/13728995.jpg differ
diff --git a/whimsical-compare/public/originals/13918325.jpg b/whimsical-compare/public/originals/13918325.jpg
new file mode 100644
index 0000000..80572ae
Binary files /dev/null and b/whimsical-compare/public/originals/13918325.jpg differ
diff --git a/whimsical-compare/public/originals/13918453.jpg b/whimsical-compare/public/originals/13918453.jpg
new file mode 100644
index 0000000..4be317c
Binary files /dev/null and b/whimsical-compare/public/originals/13918453.jpg differ
diff --git a/whimsical-compare/public/originals/13920815.jpg b/whimsical-compare/public/originals/13920815.jpg
new file mode 100644
index 0000000..8b8bd5e
Binary files /dev/null and b/whimsical-compare/public/originals/13920815.jpg differ
diff --git a/whimsical-compare/public/originals/13949729.jpg b/whimsical-compare/public/originals/13949729.jpg
new file mode 100644
index 0000000..82b30b1
Binary files /dev/null and b/whimsical-compare/public/originals/13949729.jpg differ
diff --git a/whimsical-compare/public/originals/13957257.jpg b/whimsical-compare/public/originals/13957257.jpg
new file mode 100644
index 0000000..e8fda66
Binary files /dev/null and b/whimsical-compare/public/originals/13957257.jpg differ
diff --git a/whimsical-compare/public/originals/14150480.jpg b/whimsical-compare/public/originals/14150480.jpg
new file mode 100644
index 0000000..2e4302f
Binary files /dev/null and b/whimsical-compare/public/originals/14150480.jpg differ
diff --git a/whimsical-compare/public/originals/14163752.jpg b/whimsical-compare/public/originals/14163752.jpg
new file mode 100644
index 0000000..6a6f902
Binary files /dev/null and b/whimsical-compare/public/originals/14163752.jpg differ
diff --git a/whimsical-compare/public/originals/14178793.jpg b/whimsical-compare/public/originals/14178793.jpg
new file mode 100644
index 0000000..f72bb2b
Binary files /dev/null and b/whimsical-compare/public/originals/14178793.jpg differ
diff --git a/whimsical-compare/public/originals/14281611.jpg b/whimsical-compare/public/originals/14281611.jpg
new file mode 100644
index 0000000..6c79dd0
Binary files /dev/null and b/whimsical-compare/public/originals/14281611.jpg differ
diff --git a/whimsical-compare/public/originals/14288984.jpg b/whimsical-compare/public/originals/14288984.jpg
new file mode 100644
index 0000000..7aaaded
Binary files /dev/null and b/whimsical-compare/public/originals/14288984.jpg differ
diff --git a/whimsical-compare/public/originals/14289044.jpg b/whimsical-compare/public/originals/14289044.jpg
new file mode 100644
index 0000000..d39ddf0
Binary files /dev/null and b/whimsical-compare/public/originals/14289044.jpg differ
diff --git a/whimsical-compare/public/originals/14309427.jpg b/whimsical-compare/public/originals/14309427.jpg
new file mode 100644
index 0000000..17dfd59
Binary files /dev/null and b/whimsical-compare/public/originals/14309427.jpg differ
diff --git a/whimsical-compare/public/originals/14372386.jpg b/whimsical-compare/public/originals/14372386.jpg
new file mode 100644
index 0000000..92bced0
Binary files /dev/null and b/whimsical-compare/public/originals/14372386.jpg differ
diff --git a/whimsical-compare/public/originals/14438928.jpg b/whimsical-compare/public/originals/14438928.jpg
new file mode 100644
index 0000000..62119eb
Binary files /dev/null and b/whimsical-compare/public/originals/14438928.jpg differ
diff --git a/whimsical-compare/public/originals/14576878.jpg b/whimsical-compare/public/originals/14576878.jpg
new file mode 100644
index 0000000..5cd6a17
Binary files /dev/null and b/whimsical-compare/public/originals/14576878.jpg differ
diff --git a/whimsical-compare/public/originals/14634270.jpg b/whimsical-compare/public/originals/14634270.jpg
new file mode 100644
index 0000000..6aa3ce9
Binary files /dev/null and b/whimsical-compare/public/originals/14634270.jpg differ
diff --git a/whimsical-compare/public/originals/14800343.jpg b/whimsical-compare/public/originals/14800343.jpg
new file mode 100644
index 0000000..5bfb2f3
Binary files /dev/null and b/whimsical-compare/public/originals/14800343.jpg differ
diff --git a/whimsical-compare/public/originals/14999334.jpg b/whimsical-compare/public/originals/14999334.jpg
new file mode 100644
index 0000000..ca6ce69
Binary files /dev/null and b/whimsical-compare/public/originals/14999334.jpg differ
diff --git a/whimsical-compare/public/originals/15006191.jpg b/whimsical-compare/public/originals/15006191.jpg
new file mode 100644
index 0000000..beac60f
Binary files /dev/null and b/whimsical-compare/public/originals/15006191.jpg differ
diff --git a/whimsical-compare/public/originals/15062910.jpg b/whimsical-compare/public/originals/15062910.jpg
new file mode 100644
index 0000000..8182473
Binary files /dev/null and b/whimsical-compare/public/originals/15062910.jpg differ
diff --git a/whimsical-compare/public/originals/15094678.jpg b/whimsical-compare/public/originals/15094678.jpg
new file mode 100644
index 0000000..c8c6234
Binary files /dev/null and b/whimsical-compare/public/originals/15094678.jpg differ
diff --git a/whimsical-compare/public/originals/15095313.jpg b/whimsical-compare/public/originals/15095313.jpg
new file mode 100644
index 0000000..454b8de
Binary files /dev/null and b/whimsical-compare/public/originals/15095313.jpg differ
diff --git a/whimsical-compare/public/originals/15235563.jpg b/whimsical-compare/public/originals/15235563.jpg
new file mode 100644
index 0000000..08e26ee
Binary files /dev/null and b/whimsical-compare/public/originals/15235563.jpg differ
diff --git a/whimsical-compare/public/originals/15252682.jpg b/whimsical-compare/public/originals/15252682.jpg
new file mode 100644
index 0000000..07678bc
Binary files /dev/null and b/whimsical-compare/public/originals/15252682.jpg differ
diff --git a/whimsical-compare/public/originals/15300002.jpg b/whimsical-compare/public/originals/15300002.jpg
new file mode 100644
index 0000000..76c4048
Binary files /dev/null and b/whimsical-compare/public/originals/15300002.jpg differ
diff --git a/whimsical-compare/public/originals/15558511.jpg b/whimsical-compare/public/originals/15558511.jpg
new file mode 100644
index 0000000..cf79e93
Binary files /dev/null and b/whimsical-compare/public/originals/15558511.jpg differ
diff --git a/whimsical-compare/public/originals/15606286.jpg b/whimsical-compare/public/originals/15606286.jpg
new file mode 100644
index 0000000..231df0e
Binary files /dev/null and b/whimsical-compare/public/originals/15606286.jpg differ
diff --git a/whimsical-compare/public/originals/15622273.jpg b/whimsical-compare/public/originals/15622273.jpg
new file mode 100644
index 0000000..82b346d
Binary files /dev/null and b/whimsical-compare/public/originals/15622273.jpg differ
diff --git a/whimsical-compare/public/originals/15910606.jpg b/whimsical-compare/public/originals/15910606.jpg
new file mode 100644
index 0000000..762a011
Binary files /dev/null and b/whimsical-compare/public/originals/15910606.jpg differ
diff --git a/whimsical-compare/public/originals/15914489.jpg b/whimsical-compare/public/originals/15914489.jpg
new file mode 100644
index 0000000..de8b06a
Binary files /dev/null and b/whimsical-compare/public/originals/15914489.jpg differ
diff --git a/whimsical-compare/public/originals/16014251.jpg b/whimsical-compare/public/originals/16014251.jpg
new file mode 100644
index 0000000..e305991
Binary files /dev/null and b/whimsical-compare/public/originals/16014251.jpg differ
diff --git a/whimsical-compare/public/originals/16019794.jpg b/whimsical-compare/public/originals/16019794.jpg
new file mode 100644
index 0000000..21f16eb
Binary files /dev/null and b/whimsical-compare/public/originals/16019794.jpg differ
diff --git a/whimsical-compare/public/originals/16267560.jpg b/whimsical-compare/public/originals/16267560.jpg
new file mode 100644
index 0000000..296f692
Binary files /dev/null and b/whimsical-compare/public/originals/16267560.jpg differ
diff --git a/whimsical-compare/public/originals/16483638.jpg b/whimsical-compare/public/originals/16483638.jpg
new file mode 100644
index 0000000..7efa9e1
Binary files /dev/null and b/whimsical-compare/public/originals/16483638.jpg differ
diff --git a/whimsical-compare/public/originals/16520351.jpg b/whimsical-compare/public/originals/16520351.jpg
new file mode 100644
index 0000000..35e9237
Binary files /dev/null and b/whimsical-compare/public/originals/16520351.jpg differ
diff --git a/whimsical-compare/public/originals/16594395.jpg b/whimsical-compare/public/originals/16594395.jpg
new file mode 100644
index 0000000..3802312
Binary files /dev/null and b/whimsical-compare/public/originals/16594395.jpg differ
diff --git a/whimsical-compare/public/originals/16701521.jpg b/whimsical-compare/public/originals/16701521.jpg
new file mode 100644
index 0000000..7ca1067
Binary files /dev/null and b/whimsical-compare/public/originals/16701521.jpg differ
diff --git a/whimsical-compare/public/originals/16859966.jpg b/whimsical-compare/public/originals/16859966.jpg
new file mode 100644
index 0000000..d8fdefe
Binary files /dev/null and b/whimsical-compare/public/originals/16859966.jpg differ
diff --git a/whimsical-compare/public/originals/17081029.jpg b/whimsical-compare/public/originals/17081029.jpg
new file mode 100644
index 0000000..013357e
Binary files /dev/null and b/whimsical-compare/public/originals/17081029.jpg differ
diff --git a/whimsical-compare/public/originals/17256838.jpg b/whimsical-compare/public/originals/17256838.jpg
new file mode 100644
index 0000000..944aa5a
Binary files /dev/null and b/whimsical-compare/public/originals/17256838.jpg differ
diff --git a/whimsical-compare/public/originals/1743921.jpg b/whimsical-compare/public/originals/1743921.jpg
new file mode 100644
index 0000000..abd5631
Binary files /dev/null and b/whimsical-compare/public/originals/1743921.jpg differ
diff --git a/whimsical-compare/public/originals/17530673.jpg b/whimsical-compare/public/originals/17530673.jpg
new file mode 100644
index 0000000..3e54265
Binary files /dev/null and b/whimsical-compare/public/originals/17530673.jpg differ
diff --git a/whimsical-compare/public/originals/17610058.jpg b/whimsical-compare/public/originals/17610058.jpg
new file mode 100644
index 0000000..aedb55b
Binary files /dev/null and b/whimsical-compare/public/originals/17610058.jpg differ
diff --git a/whimsical-compare/public/originals/17617859.jpg b/whimsical-compare/public/originals/17617859.jpg
new file mode 100644
index 0000000..57c4a45
Binary files /dev/null and b/whimsical-compare/public/originals/17617859.jpg differ
diff --git a/whimsical-compare/public/originals/17742136.jpg b/whimsical-compare/public/originals/17742136.jpg
new file mode 100644
index 0000000..39141e3
Binary files /dev/null and b/whimsical-compare/public/originals/17742136.jpg differ
diff --git a/whimsical-compare/public/originals/17742893.jpg b/whimsical-compare/public/originals/17742893.jpg
new file mode 100644
index 0000000..4c7ec0d
Binary files /dev/null and b/whimsical-compare/public/originals/17742893.jpg differ
diff --git a/whimsical-compare/public/originals/17761350.jpg b/whimsical-compare/public/originals/17761350.jpg
new file mode 100644
index 0000000..da76914
Binary files /dev/null and b/whimsical-compare/public/originals/17761350.jpg differ
diff --git a/whimsical-compare/public/originals/17809925.jpg b/whimsical-compare/public/originals/17809925.jpg
new file mode 100644
index 0000000..c4b500a
Binary files /dev/null and b/whimsical-compare/public/originals/17809925.jpg differ
diff --git a/whimsical-compare/public/originals/18035772.jpg b/whimsical-compare/public/originals/18035772.jpg
new file mode 100644
index 0000000..9d6632e
Binary files /dev/null and b/whimsical-compare/public/originals/18035772.jpg differ
diff --git a/whimsical-compare/public/originals/18166792.jpg b/whimsical-compare/public/originals/18166792.jpg
new file mode 100644
index 0000000..1f7fc54
Binary files /dev/null and b/whimsical-compare/public/originals/18166792.jpg differ
diff --git a/whimsical-compare/public/originals/18381034.jpg b/whimsical-compare/public/originals/18381034.jpg
new file mode 100644
index 0000000..d8ed7c0
Binary files /dev/null and b/whimsical-compare/public/originals/18381034.jpg differ
diff --git a/whimsical-compare/public/originals/18506377.jpg b/whimsical-compare/public/originals/18506377.jpg
new file mode 100644
index 0000000..995ab4c
Binary files /dev/null and b/whimsical-compare/public/originals/18506377.jpg differ
diff --git a/whimsical-compare/public/originals/18719041.jpg b/whimsical-compare/public/originals/18719041.jpg
new file mode 100644
index 0000000..84c7c2d
Binary files /dev/null and b/whimsical-compare/public/originals/18719041.jpg differ
diff --git a/whimsical-compare/public/originals/18891417.jpg b/whimsical-compare/public/originals/18891417.jpg
new file mode 100644
index 0000000..27186ff
Binary files /dev/null and b/whimsical-compare/public/originals/18891417.jpg differ
diff --git a/whimsical-compare/public/originals/18891419.jpg b/whimsical-compare/public/originals/18891419.jpg
new file mode 100644
index 0000000..04952a9
Binary files /dev/null and b/whimsical-compare/public/originals/18891419.jpg differ
diff --git a/whimsical-compare/public/originals/3564038.jpg b/whimsical-compare/public/originals/3564038.jpg
new file mode 100644
index 0000000..d8309f3
Binary files /dev/null and b/whimsical-compare/public/originals/3564038.jpg differ
diff --git a/whimsical-compare/public/originals/5151893.jpg b/whimsical-compare/public/originals/5151893.jpg
new file mode 100644
index 0000000..8c3194f
Binary files /dev/null and b/whimsical-compare/public/originals/5151893.jpg differ
diff --git a/whimsical-compare/public/originals/5608890.jpg b/whimsical-compare/public/originals/5608890.jpg
new file mode 100644
index 0000000..73f4038
Binary files /dev/null and b/whimsical-compare/public/originals/5608890.jpg differ
diff --git a/whimsical-compare/public/originals/6401436.jpg b/whimsical-compare/public/originals/6401436.jpg
new file mode 100644
index 0000000..133803a
Binary files /dev/null and b/whimsical-compare/public/originals/6401436.jpg differ
diff --git a/whimsical-compare/public/originals/6402897.jpg b/whimsical-compare/public/originals/6402897.jpg
new file mode 100644
index 0000000..006723d
Binary files /dev/null and b/whimsical-compare/public/originals/6402897.jpg differ
diff --git a/whimsical-compare/public/originals/7354857.jpg b/whimsical-compare/public/originals/7354857.jpg
new file mode 100644
index 0000000..5d7e2ac
Binary files /dev/null and b/whimsical-compare/public/originals/7354857.jpg differ
diff --git a/whimsical-compare/public/originals/7988956.jpg b/whimsical-compare/public/originals/7988956.jpg
new file mode 100644
index 0000000..cf2b571
Binary files /dev/null and b/whimsical-compare/public/originals/7988956.jpg differ
diff --git a/whimsical-compare/public/originals/8223425.jpg b/whimsical-compare/public/originals/8223425.jpg
new file mode 100644
index 0000000..6366cb2
Binary files /dev/null and b/whimsical-compare/public/originals/8223425.jpg differ
diff --git a/whimsical-compare/public/originals/9709002.jpg b/whimsical-compare/public/originals/9709002.jpg
new file mode 100644
index 0000000..83867ec
Binary files /dev/null and b/whimsical-compare/public/originals/9709002.jpg differ
diff --git a/whimsical-compare/public/originals/9987142.jpg b/whimsical-compare/public/originals/9987142.jpg
new file mode 100644
index 0000000..5092702
Binary files /dev/null and b/whimsical-compare/public/originals/9987142.jpg differ
diff --git a/whimsical-compare/public/ours/12448122.png b/whimsical-compare/public/ours/12448122.png
new file mode 100644
index 0000000..977cb67
Binary files /dev/null and b/whimsical-compare/public/ours/12448122.png differ
diff --git a/whimsical-compare/public/ours/14634270.png b/whimsical-compare/public/ours/14634270.png
new file mode 100644
index 0000000..f4661b4
Binary files /dev/null and b/whimsical-compare/public/ours/14634270.png differ
diff --git a/whimsical-compare/public/ours/16483638.png b/whimsical-compare/public/ours/16483638.png
new file mode 100644
index 0000000..1b67c2b
Binary files /dev/null and b/whimsical-compare/public/ours/16483638.png differ
diff --git a/whimsical-compare/public/ours/18891419.png b/whimsical-compare/public/ours/18891419.png
new file mode 100644
index 0000000..4224bb1
Binary files /dev/null and b/whimsical-compare/public/ours/18891419.png differ
diff --git a/whimsical-compare/scripts/gen_ours.py b/whimsical-compare/scripts/gen_ours.py
new file mode 100644
index 0000000..4c0aa30
--- /dev/null
+++ b/whimsical-compare/scripts/gen_ours.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python3
+"""
+Generate OUR original version of each top-100 whimsical bestseller.
+
+Pipeline per design:
+ 1. qwen2.5vl (local Ollama, $0) looks at the ORIGINAL thumbnail and returns a
+ structured brief: style, motifs, palette, whimsy notes, and whether any
+ settlement-banned element (bird/butterfly/banana/grape) is visible.
+ 2. We compose an ORIGINAL, settlement-SAFE SDXL prompt — inspired-by the lane
+ (whimsical + palette + motif family), never a copy, with banned elements
+ hard-excluded in the prompt AND the negative prompt.
+ 3. Replicate SDXL renders a seamless tile (~1 cent/img).
+ 4. Post-gen: qwen2.5vl vision-checks the OUTPUT for banned elements. Any hit
+ -> settlement_verdict=BLOCK and the file is discarded (no copy in place).
+ 5. Store our_brief / our_prompt / our_design_path / settlement_verdict in PG.
+
+$0 for the vision steps (local). Replicate SDXL is the only paid part.
+Usage: python3 gen_ours.py [--limit N] [--only <sf_design_id>] [--redo]
+"""
+import os, re, json, time, sys, base64, urllib.request, urllib.error, subprocess
+
+ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+OURS = f"{ROOT}/public/ours"
+ORIG = f"{ROOT}/public/originals"
+os.makedirs(OURS, exist_ok=True)
+PG = "postgresql:///dw_unified?host=/tmp"
+OLLAMA = os.environ.get("OLLAMA_URL", "http://127.0.0.1:11434")
+VMODEL = "qwen2.5vl:7b"
+
+args = sys.argv[1:]
+def argv(flag, default=None):
+ return args[args.index(flag)+1] if flag in args else default
+LIMIT = int(argv("--limit", "1000"))
+ONLY = argv("--only")
+REDO = "--redo" in args
+
+# token
+tok = None
+with open(os.path.expanduser("~/Projects/secrets-manager/.env")) as f:
+ m = re.search(r"REPLICATE_API_TOKEN=([A-Za-z0-9_-]+)", f.read())
+ tok = m and m.group(1)
+assert tok, "no replicate token"
+
+UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
+NEG = ("bird, birds, butterfly, butterflies, banana, bananas, banana leaves, banana pods, "
+ "grape, grapes, grape clusters, text, watermark, signature, logo, blurry, low quality, "
+ "jpeg artifacts, seams, mismatched edges, frame, border, vignette")
+
+def http_json(url, payload=None, headers=None, timeout=180):
+ hdr = {"User-Agent": UA, "Content-Type": "application/json"}
+ if headers: hdr.update(headers)
+ data = json.dumps(payload).encode() if payload is not None else None
+ req = urllib.request.Request(url, data=data, headers=hdr, method="POST" if data else "GET")
+ with urllib.request.urlopen(req, timeout=timeout) as r:
+ return json.load(r)
+
+def ollama_vision(img_path, prompt):
+ b64 = base64.b64encode(open(img_path, "rb").read()).decode()
+ out = http_json(f"{OLLAMA}/api/generate", {
+ "model": VMODEL, "prompt": prompt, "images": [b64],
+ "stream": False, "options": {"temperature": 0.4}
+ }, timeout=180)
+ return out.get("response", "")
+
+def describe(img_path):
+ p = ("You are a textile design analyst. Look at this repeating wallpaper/fabric pattern and "
+ "reply ONLY with compact JSON: {\"style\":\"...\",\"motifs\":\"...\",\"palette\":\"...\","
+ "\"whimsy\":\"...\",\"has_bird\":bool,\"has_butterfly\":bool,\"has_banana\":bool,\"has_grape\":bool}. "
+ "style=aesthetic era (e.g. cottagecore, mid-century, art-nouveau, folk, watercolor). "
+ "motifs=the main repeated shapes. palette=3-5 dominant colors in words. "
+ "whimsy=what makes it playful/whimsical. Flags true only if that element is clearly present.")
+ raw = ollama_vision(img_path, p)
+ m = re.search(r"\{.*\}", raw, re.S)
+ try:
+ d = json.loads(m.group(0)) if m else {}
+ except Exception:
+ d = {}
+ # coerce any list/None fields to clean strings
+ def s(v, default):
+ if isinstance(v, list): return ", ".join(str(x) for x in v)
+ return str(v) if v not in (None, "") else default
+ return {
+ "style": s(d.get("style"), "whimsical"),
+ "motifs": s(d.get("motifs"), "scattered playful motifs"),
+ "palette": s(d.get("palette"), "soft multicolor"),
+ "whimsy": s(d.get("whimsy"), "playful"),
+ "has_bird": bool(d.get("has_bird")), "has_butterfly": bool(d.get("has_butterfly")),
+ "has_banana": bool(d.get("has_banana")), "has_grape": bool(d.get("has_grape")),
+ }
+
+def check_output(img_path):
+ p = ("Look at this wallpaper image. Reply ONLY JSON: "
+ "{\"bird\":bool,\"butterfly\":bool,\"banana\":bool,\"grape\":bool}. "
+ "true only if that specific element is clearly depicted.")
+ raw = ollama_vision(img_path, p)
+ m = re.search(r"\{.*\}", raw, re.S)
+ try: return json.loads(m.group(0)) if m else {}
+ except Exception: return {}
+
+def our_prompt(d):
+ style = d.get("style", "whimsical")
+ motifs = d.get("motifs", "playful scattered motifs")
+ palette = d.get("palette", "soft multicolor")
+ # Rewrite motifs to strip any banned element the analyst saw — we go our own way.
+ safe_motifs = re.sub(r"\b(bird|birds|butterfly|butterflies|banana[s]?|grape[s]?)\b", "botanical sprig", motifs, flags=re.I)
+ base = (f"Original hand-illustrated {style} wallpaper: {safe_motifs}, whimsical and charming, "
+ f"gentle hand-drawn linework, our own artistic interpretation, not a copy of any existing design. "
+ f"seamless repeating wallpaper pattern, tileable, flat lay, even lighting, high-end wallcovering. "
+ f"Colorway: {palette}.")
+ return base
+
+def sdxl(prompt, seed):
+ ver = http_json("https://api.replicate.com/v1/models/stability-ai/sdxl",
+ headers={"Authorization": f"Bearer {tok}"})["latest_version"]["id"]
+ pred = http_json("https://api.replicate.com/v1/predictions", {
+ "version": ver, "input": {"prompt": prompt, "negative_prompt": NEG,
+ "width": 1024, "height": 1024, "num_inference_steps": 30,
+ "guidance_scale": 7.5, "seed": seed, "refine": "no_refiner"}},
+ headers={"Authorization": f"Bearer {tok}"})
+ for _ in range(90):
+ if pred.get("status") in ("succeeded","failed","canceled"): break
+ time.sleep(2)
+ pred = http_json(pred["urls"]["get"], headers={"Authorization": f"Bearer {tok}"})
+ return pred
+
+def rows():
+ q = "SELECT rank, sf_design_id FROM whimsical_top100"
+ if ONLY: q += f" WHERE sf_design_id={int(ONLY)}"
+ elif not REDO: q += " WHERE our_design_path IS NULL"
+ q += " ORDER BY rank LIMIT %d" % LIMIT
+ out = subprocess.run(["psql", PG, "-t", "-A", "-F", "\t", "-c", q], capture_output=True, text=True).stdout
+ return [l.split("\t") for l in out.strip().splitlines() if l.strip()]
+
+def sqlset(did, brief, prompt, path, verdict):
+ b = brief.replace("'", "''")
+ p = prompt.replace("'", "''")
+ path_sql = "NULL" if not path else "'" + path.replace("'", "''") + "'"
+ sql = ("UPDATE whimsical_top100 SET our_brief='%s', our_prompt='%s', our_design_path=%s, "
+ "settlement_verdict='%s', updated_at=now() WHERE sf_design_id=%d;"
+ % (b, p, path_sql, verdict, int(did)))
+ subprocess.run(["psql", PG, "-c", sql], capture_output=True, text=True)
+
+total_secs=0.0; made=0; blocked=0
+todo=rows()
+print(f"generating {len(todo)} designs | model=stability-ai/sdxl | vision={VMODEL} ($0 local)", flush=True)
+for rank, did in todo:
+ op = f"{ORIG}/{did}.jpg"
+ if not os.path.exists(op): print(f"[{did}] no original, skip", flush=True); continue
+ d = describe(op)
+ brief = f"{d.get('style','whimsical')} · {d.get('motifs','')[:60]} · {d.get('palette','')[:40]}"
+ prompt = our_prompt(d)
+ pred = sdxl(prompt, seed=int(did) % 100000)
+ secs = (pred.get("metrics") or {}).get("predict_time", 0) or 0
+ total_secs += secs
+ if pred.get("status") != "succeeded":
+ print(f"[{did}] gen {pred.get('status')}: {pred.get('error')}", flush=True)
+ sqlset(did, brief, prompt, None, "GEN_FAIL"); continue
+ out = pred["output"]; imgurl = out[0] if isinstance(out, list) else out
+ dest = f"{OURS}/{did}.png"
+ urllib.request.urlretrieve(imgurl, dest)
+ chk = check_output(dest)
+ if any(chk.get(k) for k in ("bird","butterfly","banana","grape")):
+ os.remove(dest); blocked += 1
+ print(f"[{did}] SETTLEMENT BLOCK (post-gen vision saw {chk}) — discarded", flush=True)
+ sqlset(did, brief, prompt, None, "BLOCK"); continue
+ made += 1
+ sqlset(did, brief, prompt, f"/ours/{did}.png", "OK")
+ print(f"[{did}] rank {rank} OK {secs:.1f}s -> {dest}", flush=True)
+ time.sleep(0.8)
+
+RATE=0.000725
+cost=total_secs*RATE
+print(f"\n=== made={made} blocked={blocked} | predict {total_secs:.1f}s | est ${cost:.4f} (SDXL A40 ${RATE}/s) ===", flush=True)
diff --git a/whimsical-compare/server.js b/whimsical-compare/server.js
new file mode 100644
index 0000000..36dfb37
--- /dev/null
+++ b/whimsical-compare/server.js
@@ -0,0 +1,211 @@
+#!/usr/bin/env node
+/**
+ * Whimsical Top-100 compare tool.
+ * left = Spoonflower's bestselling "whimsical" wallpaper (the original)
+ * right = OUR settlement-safe original interpretation
+ * Inline chat per row (Anthropic, local-qwen fallback) to adjust the brief,
+ * then Regenerate re-renders via Replicate SDXL and serves the new image in place.
+ *
+ * Internal admin tool — Basic Auth admin / DW2024!.
+ */
+const express = require('express');
+const { execFile } = require('child_process');
+const fs = require('fs');
+const path = require('path');
+const https = require('https');
+
+const ROOT = __dirname;
+const PG = 'postgresql:///dw_unified?host=/tmp';
+const PORT = process.env.PORT || 0; // OS-assigned free port
+const OURS = path.join(ROOT, 'public', 'ours');
+
+// ---- secrets ----
+function secret(name) {
+ try {
+ const env = fs.readFileSync(path.join(process.env.HOME, 'Projects/secrets-manager/.env'), 'utf8');
+ const m = env.match(new RegExp('^' + name + '=([^\\n]+)', 'm'));
+ return m ? m[1].trim() : null;
+ } catch { return null; }
+}
+const REPLICATE = secret('REPLICATE_API_TOKEN');
+const ANTHROPIC = secret('ANTHROPIC_API_KEY');
+const NEG = 'bird, birds, butterfly, butterflies, banana, bananas, banana leaves, grape, grapes, ' +
+ 'text, watermark, signature, logo, blurry, low quality, jpeg artifacts, seams, frame, border, vignette';
+
+const app = express();
+app.use(express.json({ limit: '1mb' }));
+
+// ---- basic auth ----
+app.use((req, res, next) => {
+ const h = req.headers.authorization || '';
+ const [, b64] = h.split(' ');
+ const [u, p] = Buffer.from(b64 || '', 'base64').toString().split(':');
+ if (u === 'admin' && p === 'DW2024!') return next();
+ res.set('WWW-Authenticate', 'Basic realm="whimsical"').status(401).end('Auth required');
+});
+
+app.use(express.static(path.join(ROOT, 'public')));
+
+// ---- db helper ----
+function psql(sql) {
+ return new Promise((resolve, reject) => {
+ execFile('psql', [PG, '-t', '-A', '-F', '\t', '-c', sql], { maxBuffer: 32 * 1024 * 1024 },
+ (e, out) => e ? reject(e) : resolve(out));
+ });
+}
+
+app.get('/api/designs', async (req, res) => {
+ try {
+ const out = await psql(
+ `SELECT rank, sf_design_id, coalesce(name,''), coalesce(designer,''), coalesce(orders,0),
+ coalesce(num_favorites,0), coalesce(our_design_path,''), coalesce(our_brief,''),
+ coalesce(settlement_verdict,''), coalesce(our_prompt,''), to_char(updated_at,'Mon DD, YYYY, HH12:MI AM')
+ FROM whimsical_top100 ORDER BY rank`);
+ const rows = out.trim().split('\n').filter(Boolean).map(l => {
+ const [rank, id, name, designer, orders, favs, ourPath, brief, verdict, prompt, updated] = l.split('\t');
+ return {
+ rank: +rank, id, name, designer, orders: +orders, favs: +favs,
+ original: `/originals/${id}.jpg`,
+ ours: ourPath || null, brief, verdict, prompt, updated
+ };
+ });
+ res.json(rows);
+ } catch (e) { res.status(500).json({ error: String(e) }); }
+});
+
+// ---- inline chat: adjust the brief conversationally ----
+app.post('/api/chat', async (req, res) => {
+ const { id, message, history = [], brief = '', prompt = '' } = req.body || {};
+ const sys = `You are a wallpaper design assistant helping refine OUR ORIGINAL version of a whimsical pattern.
+Current brief: "${brief}"
+Current image prompt: "${prompt}"
+The user wants to adjust our version. Reply conversationally in 1-2 sentences, THEN on a new line output an updated image prompt prefixed exactly with "PROMPT: ".
+HARD RULE: never include birds, butterflies, bananas, grapes (legal settlement). Keep it a seamless tileable wallpaper. Always our own original, never a copy.`;
+ const msgs = [...history, { role: 'user', content: message }];
+ try {
+ let reply = await anthropicChat(sys, msgs);
+ if (!reply) reply = await qwenChat(sys, msgs);
+ const pm = reply.match(/PROMPT:\s*([\s\S]+)$/);
+ let newPrompt = pm ? pm[1].trim() : null;
+ if (newPrompt) newPrompt = newPrompt.replace(/\b(bird|birds|butterfly|butterflies|banana[s]?|grape[s]?)\b/gi, 'botanical sprig');
+ const chat = reply.replace(/PROMPT:[\s\S]+$/, '').trim();
+ res.json({ reply: chat || 'Updated.', prompt: newPrompt });
+ } catch (e) { res.status(500).json({ error: String(e) }); }
+});
+
+// ---- regenerate: render new prompt via SDXL, serve in place ----
+app.post('/api/regenerate', async (req, res) => {
+ const { id, prompt } = req.body || {};
+ if (!id || !prompt) return res.status(400).json({ error: 'id + prompt required' });
+ try {
+ const safe = prompt.replace(/\b(bird|birds|butterfly|butterflies|banana[s]?|grape[s]?)\b/gi, 'botanical sprig');
+ const { url, secs } = await sdxl(safe, (parseInt(id, 10) % 100000) + Math.floor(Math.random() * 1000));
+ const dest = path.join(OURS, `${id}.png`);
+ await download(url, dest);
+ // post-gen banned-element vision check (local qwen, $0)
+ const banned = await visionBanned(dest);
+ let verdict = 'OK';
+ if (banned) { fs.unlinkSync(dest); verdict = 'BLOCK'; }
+ const ourPath = verdict === 'OK' ? `/ours/${id}.png` : null;
+ await psql(`UPDATE whimsical_top100 SET our_prompt='${safe.replace(/'/g, "''")}',
+ our_design_path=${ourPath ? `'${ourPath}'` : 'NULL'}, settlement_verdict='${verdict}', updated_at=now()
+ WHERE sf_design_id=${parseInt(id, 10)}`);
+ const cost = (secs * 0.000725);
+ res.json({ ok: verdict === 'OK', verdict, ours: ourPath ? `${ourPath}?t=${Date.now()}` : null,
+ cost: `$${cost.toFixed(4)}`, secs: secs.toFixed(1),
+ note: verdict === 'BLOCK' ? 'Settlement block — output contained a banned element, discarded.' : null });
+ } catch (e) { res.status(500).json({ error: String(e) }); }
+});
+
+// ---- LLM helpers ----
+function anthropicChat(sys, msgs) {
+ if (!ANTHROPIC) return Promise.resolve(null);
+ const body = JSON.stringify({
+ model: 'claude-haiku-4-5-20251001', max_tokens: 400, system: sys,
+ messages: msgs.map(m => ({ role: m.role, content: m.content }))
+ });
+ return new Promise((resolve) => {
+ const r = https.request('https://api.anthropic.com/v1/messages', {
+ method: 'POST', headers: {
+ 'content-type': 'application/json', 'x-api-key': ANTHROPIC, 'anthropic-version': '2023-06-01'
+ }
+ }, resp => {
+ let d = ''; resp.on('data', c => d += c);
+ resp.on('end', () => {
+ try { const j = JSON.parse(d); resolve(j.content?.[0]?.text || null); }
+ catch { resolve(null); }
+ });
+ });
+ r.on('error', () => resolve(null)); r.write(body); r.end();
+ });
+}
+function qwenChat(sys, msgs) {
+ const body = JSON.stringify({
+ model: 'qwen3:14b', stream: false,
+ messages: [{ role: 'system', content: sys }, ...msgs], options: { temperature: 0.6 }
+ });
+ return new Promise((resolve) => {
+ const http = require('http');
+ const r = http.request('http://127.0.0.1:11434/api/chat', { method: 'POST',
+ headers: { 'content-type': 'application/json' } }, resp => {
+ let d = ''; resp.on('data', c => d += c);
+ resp.on('end', () => { try { resolve(JSON.parse(d).message?.content || 'Updated.'); } catch { resolve('Updated.'); } });
+ });
+ r.on('error', () => resolve('Updated.')); r.write(body); r.end();
+ });
+}
+function visionBanned(imgPath) {
+ const b64 = fs.readFileSync(imgPath).toString('base64');
+ const body = JSON.stringify({
+ model: 'qwen2.5vl:7b', stream: false,
+ prompt: 'Reply ONLY JSON {"bird":bool,"butterfly":bool,"banana":bool,"grape":bool} — true only if clearly depicted.',
+ images: [b64], options: { temperature: 0.2 }
+ });
+ return new Promise((resolve) => {
+ const http = require('http');
+ const r = http.request('http://127.0.0.1:11434/api/generate', { method: 'POST',
+ headers: { 'content-type': 'application/json' } }, resp => {
+ let d = ''; resp.on('data', c => d += c);
+ resp.on('end', () => {
+ try { const j = JSON.parse(JSON.parse(d).response.match(/\{.*\}/s)[0]);
+ resolve(!!(j.bird || j.butterfly || j.banana || j.grape)); }
+ catch { resolve(false); }
+ });
+ });
+ r.on('error', () => resolve(false)); r.write(body); r.end();
+ });
+}
+function sdxl(prompt, seed) {
+ const post = (url, payload) => new Promise((resolve, reject) => {
+ const body = payload ? JSON.stringify(payload) : null;
+ const r = https.request(url, { method: payload ? 'POST' : 'GET', headers: {
+ 'Authorization': `Bearer ${REPLICATE}`, 'Content-Type': 'application/json' } }, resp => {
+ let d = ''; resp.on('data', c => d += c); resp.on('end', () => { try { resolve(JSON.parse(d)); } catch (e) { reject(e); } });
+ });
+ r.on('error', reject); if (body) r.write(body); r.end();
+ });
+ return (async () => {
+ const ver = (await post('https://api.replicate.com/v1/models/stability-ai/sdxl')).latest_version.id;
+ let pred = await post('https://api.replicate.com/v1/predictions', { version: ver, input: {
+ prompt, negative_prompt: NEG, width: 1024, height: 1024, num_inference_steps: 30,
+ guidance_scale: 7.5, seed, refine: 'no_refiner' } });
+ for (let i = 0; i < 90 && !['succeeded', 'failed', 'canceled'].includes(pred.status); i++) {
+ await new Promise(r => setTimeout(r, 2000)); pred = await post(pred.urls.get);
+ }
+ if (pred.status !== 'succeeded') throw new Error('gen ' + pred.status);
+ const out = Array.isArray(pred.output) ? pred.output[0] : pred.output;
+ return { url: out, secs: (pred.metrics && pred.metrics.predict_time) || 0 };
+ })();
+}
+function download(url, dest) {
+ return new Promise((resolve, reject) => {
+ https.get(url, r => { const f = fs.createWriteStream(dest); r.pipe(f); f.on('finish', () => f.close(resolve)); })
+ .on('error', reject);
+ });
+}
+
+const server = app.listen(PORT, () => {
+ const p = server.address().port;
+ fs.writeFileSync(path.join(ROOT, '.port'), String(p));
+ console.log(`whimsical compare → http://127.0.0.1:${p} (admin / DW2024!)`);
+});
← 1a98394 pattern-vault: generate + settlement post-gen-vision 8 trend
·
back to Pattern Vault
·
whimsical top-100: compare tool (original vs ours) + inline 7662df1 →