← back to Paul Conrad Cartoons Shadowman
Replace text-only research-records section with public-domain cartoon gallery (DPLA libraries/universities + Met, Art Institute of Chicago, Cleveland open access)
5891a0795cc4c02a46f4a81fc01bb876ab69d0cb · 2026-09-25 10:11:17 -0700 · Steve Abrams
Items are kept only when the holding institution's own rights field says public domain / CC0 /
NoC-US. scripts/fetch-pd-cartoons.mjs builds data/pd-cartoons.json + local images; /api/cartoons
(research records) is no longer served; verify-inkwell.cjs 28/28 incl. PD gallery checks.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SW5KHgwrh2Rr9TKHM6ndqM
Files touched
A data/pd-cartoons.jsonM public/app.jsM public/index.htmlA public/pd/aic-113092.jpgA public/pd/aic-113093.jpgA public/pd/aic-113319.jpgA public/pd/aic-113329.jpgA public/pd/aic-113331.jpgA public/pd/aic-113333.jpgA public/pd/aic-113392.jpgA public/pd/aic-122398.jpgA public/pd/aic-129180.jpgA public/pd/aic-15800.jpgA public/pd/aic-15803.jpgA public/pd/aic-15809.jpgA public/pd/aic-15812.jpgA public/pd/aic-15814.jpgA public/pd/aic-15818.jpgA public/pd/aic-15826.jpgA public/pd/aic-260711.jpgA public/pd/aic-266997.jpgA public/pd/aic-37163.jpgA public/pd/aic-61076.jpgA public/pd/aic-6469.jpgA public/pd/aic-66094.jpgA public/pd/aic-79864.jpgA public/pd/aic-82876.jpgA public/pd/aic-86054.jpgA public/pd/cma-104977.jpgA public/pd/cma-106785.jpgA public/pd/cma-106900.jpgA public/pd/cma-107016.jpgA public/pd/cma-109042.jpgA public/pd/cma-110905.jpgA public/pd/cma-110910.jpgA public/pd/cma-111369.jpgA public/pd/cma-115100.jpgA public/pd/cma-115833.jpgA public/pd/cma-115925.jpgA public/pd/cma-121136.jpgA public/pd/cma-122753.jpgA public/pd/cma-122818.jpgA public/pd/cma-123223.jpgA public/pd/cma-124699.jpgA public/pd/cma-135782.jpgA public/pd/cma-136334.jpgA public/pd/cma-142680.jpgA public/pd/cma-143203.jpgA public/pd/cma-159238.jpgA public/pd/cma-166522.jpgA public/pd/cma-167916.jpgA public/pd/cma-167919.jpgA public/pd/cma-167946.jpgA public/pd/cma-169587.jpgA public/pd/cma-311853.jpgA public/pd/cma-679091.jpgA public/pd/dpla-011db0d6402b87d831becb51e511531e.jpgA public/pd/dpla-0dc692932207db1bca33b3a117b13da5.jpgA public/pd/dpla-13cc17544ee2b24ada29234443164cb7.jpgA public/pd/dpla-16dd3836398e1ef087c87a02787eaf86.jpgA public/pd/dpla-19ee8d0c65cc66876f1e3a538551dc73.jpgA public/pd/dpla-1f9def937f520d341f505c5aa58e4701.jpgA public/pd/dpla-324c1487694efb27c2129fc716733a03.jpgA public/pd/dpla-3d6cc1343d435d52d106a5b81db8ec02.jpgA public/pd/dpla-59c2c7f9b9b972cfe6ef06295633a31e.jpgA public/pd/dpla-685e7a51d73780ff04c22ed56189287a.jpgA public/pd/dpla-6b52edab1b7446f237535b24b007a321.jpgA public/pd/dpla-71f79303fad059e00b6be4dbfe404c4f.jpgA public/pd/dpla-85115befac6f4fc67ea0173909cb4ad2.jpgA public/pd/dpla-852d92ecc93967ec12222fe7931603d3.jpgA public/pd/dpla-90e3ffd4a24de5719990bde3b8d314c6.jpgA public/pd/dpla-a1b7033d8a652629a71210770151b2e4.jpgA public/pd/dpla-a6b018396a4424de8c3a630f516adb83.jpgA public/pd/dpla-f039f35275b4973903264aa5d98a1146.jpgA public/pd/dpla-f123156ba4fc6d8663d073e324d04c61.jpgA public/pd/met-15662.jpgA public/pd/met-335913.jpgA public/pd/met-335916.jpgA public/pd/met-339826.jpgA public/pd/met-340110.jpgA public/pd/met-341322.jpgA public/pd/met-343561.jpgA public/pd/met-351971.jpgA public/pd/met-362270.jpgA public/pd/met-362271.jpgA public/pd/met-388974.jpgA public/pd/met-389056.jpgA public/pd/met-389085.jpgA public/pd/met-389090.jpgA public/pd/met-389091.jpgA public/pd/met-389104.jpgA public/pd/met-392320.jpgA public/pd/met-392759.jpgA public/pd/met-395366.jpgA public/pd/met-418567.jpgA public/pd/met-418570.jpgA public/pd/met-459504.jpgA public/pd/met-744206.jpgA public/pd/met-744243.jpgA public/pd/met-745548.jpgA public/pd/met-819943.jpgA public/pd/met-850627.jpgA public/pd/met-850632.jpgA public/pd/met-850635.jpgA public/pd/met-850636.jpgA public/pd/met-850639.jpgA public/pd/met-850659.jpgA public/pd/met-850668.jpgA public/pd/met-850669.jpgA public/pd/met-850670.jpgA public/pd/met-850671.jpgA public/pd/met-850673.jpgA public/pd/met-850674.jpgA public/pd/met-850676.jpgA public/pd/met-850679.jpgM public/style.cssA scripts/fetch-pd-cartoons.mjsM scripts/verify-inkwell.cjsM server.js
Diff
commit 5891a0795cc4c02a46f4a81fc01bb876ab69d0cb
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Fri Sep 25 10:11:17 2026 -0700
Replace text-only research-records section with public-domain cartoon gallery (DPLA libraries/universities + Met, Art Institute of Chicago, Cleveland open access)
Items are kept only when the holding institution's own rights field says public domain / CC0 /
NoC-US. scripts/fetch-pd-cartoons.mjs builds data/pd-cartoons.json + local images; /api/cartoons
(research records) is no longer served; verify-inkwell.cjs 28/28 incl. PD gallery checks.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SW5KHgwrh2Rr9TKHM6ndqM
---
data/pd-cartoons.json | 1723 ++++++++++++++++++++
public/app.js | 369 ++---
public/index.html | 41 +-
public/pd/aic-113092.jpg | Bin 0 -> 506805 bytes
public/pd/aic-113093.jpg | Bin 0 -> 883152 bytes
public/pd/aic-113319.jpg | Bin 0 -> 128593 bytes
public/pd/aic-113329.jpg | Bin 0 -> 148179 bytes
public/pd/aic-113331.jpg | Bin 0 -> 139452 bytes
public/pd/aic-113333.jpg | Bin 0 -> 181031 bytes
public/pd/aic-113392.jpg | Bin 0 -> 130762 bytes
public/pd/aic-122398.jpg | Bin 0 -> 303347 bytes
public/pd/aic-129180.jpg | Bin 0 -> 332985 bytes
public/pd/aic-15800.jpg | Bin 0 -> 621514 bytes
public/pd/aic-15803.jpg | Bin 0 -> 648428 bytes
public/pd/aic-15809.jpg | Bin 0 -> 743477 bytes
public/pd/aic-15812.jpg | Bin 0 -> 340407 bytes
public/pd/aic-15814.jpg | Bin 0 -> 219449 bytes
public/pd/aic-15818.jpg | Bin 0 -> 519919 bytes
public/pd/aic-15826.jpg | Bin 0 -> 574596 bytes
public/pd/aic-260711.jpg | Bin 0 -> 305756 bytes
public/pd/aic-266997.jpg | Bin 0 -> 204662 bytes
public/pd/aic-37163.jpg | Bin 0 -> 183541 bytes
public/pd/aic-61076.jpg | Bin 0 -> 255387 bytes
public/pd/aic-6469.jpg | Bin 0 -> 648027 bytes
public/pd/aic-66094.jpg | Bin 0 -> 492650 bytes
public/pd/aic-79864.jpg | Bin 0 -> 176220 bytes
public/pd/aic-82876.jpg | Bin 0 -> 231041 bytes
public/pd/aic-86054.jpg | Bin 0 -> 215082 bytes
public/pd/cma-104977.jpg | Bin 0 -> 226662 bytes
public/pd/cma-106785.jpg | Bin 0 -> 845547 bytes
public/pd/cma-106900.jpg | Bin 0 -> 644588 bytes
public/pd/cma-107016.jpg | Bin 0 -> 71852 bytes
public/pd/cma-109042.jpg | Bin 0 -> 296926 bytes
public/pd/cma-110905.jpg | Bin 0 -> 178863 bytes
public/pd/cma-110910.jpg | Bin 0 -> 184478 bytes
public/pd/cma-111369.jpg | Bin 0 -> 686269 bytes
public/pd/cma-115100.jpg | Bin 0 -> 853802 bytes
public/pd/cma-115833.jpg | Bin 0 -> 537043 bytes
public/pd/cma-115925.jpg | Bin 0 -> 390489 bytes
public/pd/cma-121136.jpg | Bin 0 -> 793110 bytes
public/pd/cma-122753.jpg | Bin 0 -> 447195 bytes
public/pd/cma-122818.jpg | Bin 0 -> 816210 bytes
public/pd/cma-123223.jpg | Bin 0 -> 458998 bytes
public/pd/cma-124699.jpg | Bin 0 -> 66807 bytes
public/pd/cma-135782.jpg | Bin 0 -> 306895 bytes
public/pd/cma-136334.jpg | Bin 0 -> 793051 bytes
public/pd/cma-142680.jpg | Bin 0 -> 555567 bytes
public/pd/cma-143203.jpg | Bin 0 -> 475748 bytes
public/pd/cma-159238.jpg | Bin 0 -> 255486 bytes
public/pd/cma-166522.jpg | Bin 0 -> 515550 bytes
public/pd/cma-167916.jpg | Bin 0 -> 183632 bytes
public/pd/cma-167919.jpg | Bin 0 -> 94745 bytes
public/pd/cma-167946.jpg | Bin 0 -> 172627 bytes
public/pd/cma-169587.jpg | Bin 0 -> 283432 bytes
public/pd/cma-311853.jpg | Bin 0 -> 193070 bytes
public/pd/cma-679091.jpg | Bin 0 -> 290874 bytes
.../pd/dpla-011db0d6402b87d831becb51e511531e.jpg | Bin 0 -> 16246 bytes
.../pd/dpla-0dc692932207db1bca33b3a117b13da5.jpg | Bin 0 -> 71583 bytes
.../pd/dpla-13cc17544ee2b24ada29234443164cb7.jpg | Bin 0 -> 61113 bytes
.../pd/dpla-16dd3836398e1ef087c87a02787eaf86.jpg | Bin 0 -> 3825 bytes
.../pd/dpla-19ee8d0c65cc66876f1e3a538551dc73.jpg | Bin 0 -> 4496 bytes
.../pd/dpla-1f9def937f520d341f505c5aa58e4701.jpg | Bin 0 -> 16261 bytes
.../pd/dpla-324c1487694efb27c2129fc716733a03.jpg | Bin 0 -> 32135 bytes
.../pd/dpla-3d6cc1343d435d52d106a5b81db8ec02.jpg | Bin 0 -> 6817 bytes
.../pd/dpla-59c2c7f9b9b972cfe6ef06295633a31e.jpg | Bin 0 -> 15410 bytes
.../pd/dpla-685e7a51d73780ff04c22ed56189287a.jpg | Bin 0 -> 2856 bytes
.../pd/dpla-6b52edab1b7446f237535b24b007a321.jpg | Bin 0 -> 2941 bytes
.../pd/dpla-71f79303fad059e00b6be4dbfe404c4f.jpg | Bin 0 -> 42885 bytes
.../pd/dpla-85115befac6f4fc67ea0173909cb4ad2.jpg | Bin 0 -> 30276 bytes
.../pd/dpla-852d92ecc93967ec12222fe7931603d3.jpg | Bin 0 -> 79306 bytes
.../pd/dpla-90e3ffd4a24de5719990bde3b8d314c6.jpg | Bin 0 -> 828254 bytes
.../pd/dpla-a1b7033d8a652629a71210770151b2e4.jpg | Bin 0 -> 5257 bytes
.../pd/dpla-a6b018396a4424de8c3a630f516adb83.jpg | Bin 0 -> 3704 bytes
.../pd/dpla-f039f35275b4973903264aa5d98a1146.jpg | Bin 0 -> 5642 bytes
.../pd/dpla-f123156ba4fc6d8663d073e324d04c61.jpg | Bin 0 -> 8544 bytes
public/pd/met-15662.jpg | Bin 0 -> 52293 bytes
public/pd/met-335913.jpg | Bin 0 -> 65632 bytes
public/pd/met-335916.jpg | Bin 0 -> 86288 bytes
public/pd/met-339826.jpg | Bin 0 -> 57196 bytes
public/pd/met-340110.jpg | Bin 0 -> 72143 bytes
public/pd/met-341322.jpg | Bin 0 -> 73756 bytes
public/pd/met-343561.jpg | Bin 0 -> 68704 bytes
public/pd/met-351971.jpg | Bin 0 -> 64956 bytes
public/pd/met-362270.jpg | Bin 0 -> 70466 bytes
public/pd/met-362271.jpg | Bin 0 -> 71447 bytes
public/pd/met-388974.jpg | Bin 0 -> 106158 bytes
public/pd/met-389056.jpg | Bin 0 -> 119306 bytes
public/pd/met-389085.jpg | Bin 0 -> 138527 bytes
public/pd/met-389090.jpg | Bin 0 -> 120822 bytes
public/pd/met-389091.jpg | Bin 0 -> 143965 bytes
public/pd/met-389104.jpg | Bin 0 -> 125045 bytes
public/pd/met-392320.jpg | Bin 0 -> 73816 bytes
public/pd/met-392759.jpg | Bin 0 -> 141172 bytes
public/pd/met-395366.jpg | Bin 0 -> 77064 bytes
public/pd/met-418567.jpg | Bin 0 -> 55131 bytes
public/pd/met-418570.jpg | Bin 0 -> 51943 bytes
public/pd/met-459504.jpg | Bin 0 -> 161348 bytes
public/pd/met-744206.jpg | Bin 0 -> 160811 bytes
public/pd/met-744243.jpg | Bin 0 -> 134023 bytes
public/pd/met-745548.jpg | Bin 0 -> 184170 bytes
public/pd/met-819943.jpg | Bin 0 -> 92818 bytes
public/pd/met-850627.jpg | Bin 0 -> 82492 bytes
public/pd/met-850632.jpg | Bin 0 -> 95823 bytes
public/pd/met-850635.jpg | Bin 0 -> 84494 bytes
public/pd/met-850636.jpg | Bin 0 -> 93500 bytes
public/pd/met-850639.jpg | Bin 0 -> 122619 bytes
public/pd/met-850659.jpg | Bin 0 -> 117265 bytes
public/pd/met-850668.jpg | Bin 0 -> 108478 bytes
public/pd/met-850669.jpg | Bin 0 -> 114568 bytes
public/pd/met-850670.jpg | Bin 0 -> 101677 bytes
public/pd/met-850671.jpg | Bin 0 -> 86861 bytes
public/pd/met-850673.jpg | Bin 0 -> 115641 bytes
public/pd/met-850674.jpg | Bin 0 -> 90685 bytes
public/pd/met-850676.jpg | Bin 0 -> 104708 bytes
public/pd/met-850679.jpg | Bin 0 -> 102799 bytes
public/style.css | 4 +
scripts/fetch-pd-cartoons.mjs | 242 +++
scripts/verify-inkwell.cjs | 35 +-
server.js | 44 +-
119 files changed, 2136 insertions(+), 322 deletions(-)
diff --git a/data/pd-cartoons.json b/data/pd-cartoons.json
new file mode 100644
index 0000000..6634909
--- /dev/null
+++ b/data/pd-cartoons.json
@@ -0,0 +1,1723 @@
+{
+ "generated_at": "2026-09-25T17:10:50.424Z",
+ "sources": {
+ "dpla": {
+ "candidates": 40,
+ "kept": 19
+ },
+ "aic": {
+ "candidates": 25,
+ "kept": 25
+ },
+ "met": {
+ "candidates": 40,
+ "kept": 40
+ },
+ "cma": {
+ "candidates": 28,
+ "kept": 28
+ }
+ },
+ "count": 112,
+ "items": [
+ {
+ "id": "dpla-85115befac6f4fc67ea0173909cb4ad2",
+ "source": "Atlanta History Center",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Political Cartoon",
+ "artist": "Brewerton, Alfred West, 1881-1960, Cartoonist",
+ "date": "1924-01-06",
+ "year": 1924,
+ "medium": null,
+ "image_remote": "https://dlg.galileo.usg.edu/do-th:geh_athpc_2328",
+ "source_url": "http://album.atlantahistorycenter.com/cdm/ref/collection/athpc/id/2328",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Atlanta History Center",
+ "image": "/pd/dpla-85115befac6f4fc67ea0173909cb4ad2.jpg"
+ },
+ {
+ "id": "dpla-0dc692932207db1bca33b3a117b13da5",
+ "source": "Missouri Historical Society",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "\"China Tableaux\" political cartoon",
+ "artist": "Unknown artist",
+ "date": "ca. 1850",
+ "year": 1850,
+ "medium": "Lithograph",
+ "image_remote": "https://images.mohistory.org/images/p0289-00009_0001/medium.jpg",
+ "source_url": "https://mohistory.org/collections/item/P0289-00009",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Missouri Historical Society",
+ "image": "/pd/dpla-0dc692932207db1bca33b3a117b13da5.jpg"
+ },
+ {
+ "id": "dpla-324c1487694efb27c2129fc716733a03",
+ "source": "Duke University Libraries",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "North Carolina Democracy political cartoon",
+ "artist": "Unknown artist",
+ "date": "1850 to 1900",
+ "year": 1850,
+ "medium": "Broadsides",
+ "image_remote": "https://repository.duke.edu/iiif/ark:/87924/r41j99h4p/full/!350,350/0/default.jpg",
+ "source_url": "https://idn.duke.edu/ark:/87924/r4dv1fx3q",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Duke University Libraries",
+ "image": "/pd/dpla-324c1487694efb27c2129fc716733a03.jpg"
+ },
+ {
+ "id": "dpla-1f9def937f520d341f505c5aa58e4701",
+ "source": "Schomburg Center for Research in Black Culture, Manuscripts, Archives and Rare Books Division. The New York Public Library",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Political cartoon depicting Marcus Garvey",
+ "artist": "Smalls, F",
+ "date": null,
+ "year": null,
+ "medium": "Political cartoons",
+ "image_remote": "https://images.nypl.org/index.php?t=t&id=1230977",
+ "source_url": "https://digitalcollections.nypl.org/items/1b292ba0-c637-012f-698a-58d385a7bc34",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Schomburg Center for Research in Black Culture, Manuscripts, Archives and Rare Books Division. The New York Public Library",
+ "image": "/pd/dpla-1f9def937f520d341f505c5aa58e4701.jpg"
+ },
+ {
+ "id": "dpla-16dd3836398e1ef087c87a02787eaf86",
+ "source": "Dudley Observatory",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Political Cartoon, All-Cut Come-It",
+ "artist": "Unknown artist",
+ "date": "1858",
+ "year": 1858,
+ "medium": "Photograph 5 x 7 1/4 inches ( 12.7 x 18.42 centimeters)",
+ "image_remote": "http://cdm16694.contentdm.oclc.org/utils/getthumbnail/collection/dudleyo/id/1728",
+ "source_url": "http://cdm16694.contentdm.oclc.org/cdm/ref/collection/dudleyo/id/1728",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Dudley Observatory",
+ "image": "/pd/dpla-16dd3836398e1ef087c87a02787eaf86.jpg"
+ },
+ {
+ "id": "dpla-13cc17544ee2b24ada29234443164cb7",
+ "source": "Boston Public Library",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "The political cartoon, for the year 1775",
+ "artist": "Unknown artist",
+ "date": "1775",
+ "year": 1775,
+ "medium": "Prints",
+ "image_remote": "https://ark.digitalcommonwealth.org/ark:/50959/9880w778h/thumbnail",
+ "source_url": "https://ark.digitalcommonwealth.org/ark:/50959/9880w778h",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Boston Public Library",
+ "image": "/pd/dpla-13cc17544ee2b24ada29234443164cb7.jpg"
+ },
+ {
+ "id": "dpla-685e7a51d73780ff04c22ed56189287a",
+ "source": "Benjamin Harrison Presidential Site",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Harper's Weekly political cartoon, June 30, 1888",
+ "artist": "Unknown artist",
+ "date": "1888-06-30",
+ "year": 1888,
+ "medium": "Political cartoons",
+ "image_remote": "http://iuidigital.contentdm.oclc.org/utils/getthumbnail/collection/BHPS/id/6667",
+ "source_url": "http://iuidigital.contentdm.oclc.org/cdm/ref/collection/BHPS/id/6667",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Benjamin Harrison Presidential Site",
+ "image": "/pd/dpla-685e7a51d73780ff04c22ed56189287a.jpg"
+ },
+ {
+ "id": "dpla-3d6cc1343d435d52d106a5b81db8ec02",
+ "source": "Tennessee State Library and Archives",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Political cartoon depicting the election of 1844",
+ "artist": "Unknown artist",
+ "date": "1844",
+ "year": 1844,
+ "medium": "Political cartoons",
+ "image_remote": "http://cdm15138.contentdm.oclc.org/utils/getthumbnail/collection/p15138coll43/id/6",
+ "source_url": "http://cdm15138.contentdm.oclc.org/cdm/ref/collection/p15138coll43/id/6",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Tennessee State Library and Archives",
+ "image": "/pd/dpla-3d6cc1343d435d52d106a5b81db8ec02.jpg"
+ },
+ {
+ "id": "dpla-f123156ba4fc6d8663d073e324d04c61",
+ "source": "Indiana Album",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "The Confederacy In Petticoats Political Cartoon, Indiana, circa 1865",
+ "artist": "Dryer & Brisben, Columbus, Ind",
+ "date": "1865, circa",
+ "year": 1865,
+ "medium": "Still Image",
+ "image_remote": "https://s3.amazonaws.com/pastperfectonline/images/museum_383/076/thumbs/ia05550113.jpg",
+ "source_url": "http://indianaalbum.pastperfectonline.com/photo/26E5B327-EEDF-4398-AD13-963076440084",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Indiana Album",
+ "image": "/pd/dpla-f123156ba4fc6d8663d073e324d04c61.jpg"
+ },
+ {
+ "id": "dpla-90e3ffd4a24de5719990bde3b8d314c6",
+ "source": "Center for Legislative Archives",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Gridiron Club Banquet - Clever Burlesque by Famous Entertainers",
+ "artist": "U.S. Senate. Office of Senate Curator.?",
+ "date": "1907-01-27",
+ "year": 1907,
+ "medium": "Paper",
+ "image_remote": "https://nara-media-001.s3.amazonaws.com/arcmedia/legislative/clifford-berryman/1-27-1907_H-085_46_Berryman.jpg",
+ "source_url": "http://catalog.archives.gov/id/6010691",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Center for Legislative Archives",
+ "image": "/pd/dpla-90e3ffd4a24de5719990bde3b8d314c6.jpg"
+ },
+ {
+ "id": "dpla-6b52edab1b7446f237535b24b007a321",
+ "source": "Manuscripts and Archives Division. The New York Public Library",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Cartoon Strip",
+ "artist": "New York World's Fair (1939-1940 : New York, N.Y.)",
+ "date": "1935",
+ "year": 1935,
+ "medium": "Index cards",
+ "image_remote": "https://images.nypl.org/index.php?t=t&id=wf39_025044",
+ "source_url": "https://digitalcollections.nypl.org/items/78ad6df0-c539-012f-8295-58d385a7bc34",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Manuscripts and Archives Division. The New York Public Library",
+ "image": "/pd/dpla-6b52edab1b7446f237535b24b007a321.jpg"
+ },
+ {
+ "id": "dpla-19ee8d0c65cc66876f1e3a538551dc73",
+ "source": "Cincinnati and Hamilton County Public Library",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Crows cartoon",
+ "artist": "Hannaford, Samuel, 1835-1911",
+ "date": "1882",
+ "year": 1882,
+ "medium": "Illustrations",
+ "image_remote": "http://digital.cincinnatilibrary.org/utils/getthumbnail/collection/p16998coll56/id/0",
+ "source_url": "http://digital.cincinnatilibrary.org/cdm/ref/collection/p16998coll56/id/0",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Cincinnati and Hamilton County Public Library",
+ "image": "/pd/dpla-19ee8d0c65cc66876f1e3a538551dc73.jpg"
+ },
+ {
+ "id": "dpla-59c2c7f9b9b972cfe6ef06295633a31e",
+ "source": "University of Wisconsin Digital Collections",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Darwin Cartoon",
+ "artist": "Unknown artist",
+ "date": null,
+ "year": null,
+ "medium": "Black and white illustration",
+ "image_remote": "https://asset.library.wisc.edu/1711.dl/BD6PWHLTOYYJ28X/M/s240-d41f4.jpg",
+ "source_url": "https://digital.library.wisc.edu/1711.dl/6NKIRWB4SRPI28R",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "University of Wisconsin Digital Collections",
+ "image": "/pd/dpla-59c2c7f9b9b972cfe6ef06295633a31e.jpg"
+ },
+ {
+ "id": "dpla-852d92ecc93967ec12222fe7931603d3",
+ "source": "University of Colorado Boulder University Libraries",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Newspaper cartoon",
+ "artist": "Unknown artist",
+ "date": "1913-11-05",
+ "year": 1913,
+ "medium": null,
+ "image_remote": "https://cudl.colorado.edu/MediaManager/srvr?mediafile=/Size2/UCBOULDERCB1~76~76/4730/DPL51.jpg",
+ "source_url": "https://cudl.colorado.edu/luna/servlet/detail/UCBOULDERCB1~76~76~1106942~260776",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "University of Colorado Boulder University Libraries",
+ "image": "/pd/dpla-852d92ecc93967ec12222fe7931603d3.jpg"
+ },
+ {
+ "id": "dpla-71f79303fad059e00b6be4dbfe404c4f",
+ "source": "University of Tennessee, Knoxville. Special Collections",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Feminism, a cartoon",
+ "artist": "Unknown artist",
+ "date": "1915/1920",
+ "year": 1915,
+ "medium": null,
+ "image_remote": "https://dlg.galileo.usg.edu/do-th:utkn_volvoices_volvoices-3693",
+ "source_url": "https://digital.lib.utk.edu/collections/islandora/object/volvoices%3A3693",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "University of Tennessee, Knoxville. Special Collections",
+ "image": "/pd/dpla-71f79303fad059e00b6be4dbfe404c4f.jpg"
+ },
+ {
+ "id": "dpla-011db0d6402b87d831becb51e511531e",
+ "source": "Dorot Jewish Division. The New York Public Library",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Cartoon Gimel Haresha",
+ "artist": "Unknown artist",
+ "date": null,
+ "year": null,
+ "medium": "Illustrations",
+ "image_remote": "https://images.nypl.org/index.php?t=t&id=58321093",
+ "source_url": "https://digitalcollections.nypl.org/items/e2178430-e806-0139-9182-0242ac110002",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Dorot Jewish Division. The New York Public Library",
+ "image": "/pd/dpla-011db0d6402b87d831becb51e511531e.jpg"
+ },
+ {
+ "id": "dpla-f039f35275b4973903264aa5d98a1146",
+ "source": "Columbus Metropolitan Library",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "McCorkles' Confectionary Cartoon",
+ "artist": "Columbus Dispatch",
+ "date": "1940",
+ "year": 1940,
+ "medium": null,
+ "image_remote": "http://digital-collections.columbuslibrary.org/utils/getthumbnail/collection/memory/id/107072",
+ "source_url": "http://digital-collections.columbuslibrary.org/cdm/ref/collection/memory/id/107072",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Columbus Metropolitan Library",
+ "image": "/pd/dpla-f039f35275b4973903264aa5d98a1146.jpg"
+ },
+ {
+ "id": "dpla-a1b7033d8a652629a71210770151b2e4",
+ "source": "Lincoln Financial Foundation Collection, Allen County Public Library, Fort Wayne, Indiana",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Anti-Emancipation Proclamation cartoon",
+ "artist": "Unknown artist",
+ "date": "ca. 1863",
+ "year": 1863,
+ "medium": "Photograph",
+ "image_remote": "http://cdm15155.contentdm.oclc.org/utils/getthumbnail/collection/p15155coll1/id/3323",
+ "source_url": "http://cdm15155.contentdm.oclc.org/cdm/ref/collection/p15155coll1/id/3323",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Lincoln Financial Foundation Collection, Allen County Public Library, Fort Wayne, Indiana",
+ "image": "/pd/dpla-a1b7033d8a652629a71210770151b2e4.jpg"
+ },
+ {
+ "id": "dpla-a6b018396a4424de8c3a630f516adb83",
+ "source": "Ohio History Connection",
+ "source_key": "dpla",
+ "via": "Digital Public Library of America",
+ "title": "Outhwaite Homes - Mural Cartoon",
+ "artist": "Ohio Federal Writers' Project",
+ "date": "1930s",
+ "year": 1930,
+ "medium": "Picture",
+ "image_remote": "http://www.ohiomemory.org/utils/getthumbnail/collection/p267401coll34/id/5582",
+ "source_url": "http://www.ohiomemory.org/cdm/ref/collection/p267401coll34/id/5582",
+ "rights": "No Copyright – United States (rightsstatements.org NoC-US)",
+ "credit": "Ohio History Connection",
+ "image": "/pd/dpla-a6b018396a4424de8c3a630f516adb83.jpg"
+ },
+ {
+ "id": "aic-86054",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Political Cartoon",
+ "artist": "Unknown artist",
+ "date": "n.d.",
+ "year": 1800,
+ "medium": "Pen and black ink, on off-white board, laid down on tan board",
+ "image_remote": "https://www.artic.edu/iiif/2/8462c18e-c81c-423f-98da-032a6da1e8fc/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/86054",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "The Leonora Hall Gurley Memorial Collection",
+ "image": "/pd/aic-86054.jpg"
+ },
+ {
+ "id": "aic-129180",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "The Political Handicap, from Puck",
+ "artist": "Joseph Keppler",
+ "date": "n.d.",
+ "year": 1858,
+ "medium": "Color lithograph on newsprint",
+ "image_remote": "https://www.artic.edu/iiif/2/f04e074b-7e4f-1fc9-8aa7-59fc66cb1591/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/129180",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Gift of Miss Nathalie Gookin",
+ "image": "/pd/aic-129180.jpg"
+ },
+ {
+ "id": "aic-260711",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "The Coalition (La Coalition)",
+ "artist": "Esprit-Antoine Gibelin",
+ "date": "1795",
+ "year": 1795,
+ "medium": "Etching and engraving in black on tan laid paper",
+ "image_remote": "https://www.artic.edu/iiif/2/f540f7f2-a024-2b28-8832-5dea32dc4c02/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/260711",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "The Amanda S. Johnson and Marion J. Livingston Endowment Fund",
+ "image": "/pd/aic-260711.jpg"
+ },
+ {
+ "id": "aic-15826",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricature of Auguste Vacquerie",
+ "artist": "Claude Monet",
+ "date": "c. 1859",
+ "year": 1855,
+ "medium": "Graphite on tan wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/91138ade-e305-636d-bb7a-ffd9d3d10b96/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/15826",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Mr. and Mrs. Carter H. Harrison Collection",
+ "image": "/pd/aic-15826.jpg"
+ },
+ {
+ "id": "aic-15800",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricature of Léon Manchon",
+ "artist": "Claude Monet",
+ "date": "1858",
+ "year": 1858,
+ "medium": "Black and white chalks on blue laid paper",
+ "image_remote": "https://www.artic.edu/iiif/2/f7ef6ed1-b05f-5ef9-faf2-72e41cdfa1c3/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/15800",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Mr. and Mrs. Carter H. Harrison Collection",
+ "image": "/pd/aic-15800.jpg"
+ },
+ {
+ "id": "aic-15818",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricature of Henri Cassinelli (“Rufus Croutinelli”)",
+ "artist": "Claude Monet",
+ "date": "c. 1858",
+ "year": 1857,
+ "medium": "Graphite on tan wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/0f57d4e1-b0f3-b06c-ed89-2c6b1a0372ff/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/15818",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Mr. and Mrs. Carter H. Harrison Collection",
+ "image": "/pd/aic-15818.jpg"
+ },
+ {
+ "id": "aic-113092",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricature of a Man with a Large Nose",
+ "artist": "Claude Monet",
+ "date": "1855/56",
+ "year": 1855,
+ "medium": "Graphite on tan wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/8c47d8be-2149-719d-555b-af20897ca294/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/113092",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Mr. and Mrs. Carter H. Harrison Collection",
+ "image": "/pd/aic-113092.jpg"
+ },
+ {
+ "id": "aic-15812",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricature of Mario Uchard",
+ "artist": "Claude Monet",
+ "date": "c. 1858",
+ "year": 1857,
+ "medium": "Graphite on tan wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/1745a1b7-f530-caf3-3435-cc15970e0a88/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/15812",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Mr. and Mrs. Carter H. Harrison Collection",
+ "image": "/pd/aic-15812.jpg"
+ },
+ {
+ "id": "aic-15809",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricature of a Man with a Big Cigar",
+ "artist": "Claude Monet",
+ "date": "1855/56",
+ "year": 1855,
+ "medium": "Black, white, and colored chalks on blue wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/fcbe6e18-8b6f-8519-81a5-a416e6bdf3c1/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/15809",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Mr. and Mrs. Carter H. Harrison Collection",
+ "image": "/pd/aic-15809.jpg"
+ },
+ {
+ "id": "aic-15803",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricature of Jules Didier (“Butterfly Man”)",
+ "artist": "Claude Monet",
+ "date": "c. 1858",
+ "year": 1857,
+ "medium": "Black and white chalks on blue laid paper",
+ "image_remote": "https://www.artic.edu/iiif/2/ffceac7e-98d9-eb34-daeb-6587c998ad73/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/15803",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Mr. and Mrs. Carter H. Harrison Collection",
+ "image": "/pd/aic-15803.jpg"
+ },
+ {
+ "id": "aic-113093",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricature of Eugène Marcel",
+ "artist": "Claude Monet",
+ "date": "1855/56",
+ "year": 1855,
+ "medium": "Graphite with white chalk on gray wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/fe62fbcf-2c09-3fb2-a0e5-f61f4dfd9aad/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/113093",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Mr. and Mrs. Carter H. Harrison Collection",
+ "image": "/pd/aic-113093.jpg"
+ },
+ {
+ "id": "aic-15814",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricature of a Man in the Small Hat",
+ "artist": "Claude Monet",
+ "date": "1855/56",
+ "year": 1855,
+ "medium": "Graphite on cream wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/510c084b-d8d3-62c2-d71d-270c2f286a51/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/15814",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Mr. and Mrs. Carter H. Harrison Collection",
+ "image": "/pd/aic-15814.jpg"
+ },
+ {
+ "id": "aic-113329",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Sheet of Caricatures",
+ "artist": "Jean Louis André Théodore Géricault",
+ "date": "1818/19",
+ "year": 1818,
+ "medium": "Graphite on cream wove paper, perimeter mounted on cream wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/b7945e9f-24bd-da22-9fd2-f1e9d54fcae3/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/113329",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Margaret Day Blake Collection",
+ "image": "/pd/aic-113329.jpg"
+ },
+ {
+ "id": "aic-113333",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Seven Caricatures of Heads",
+ "artist": "Jean Louis André Théodore Géricault",
+ "date": "1818/19",
+ "year": 1818,
+ "medium": "Graphite on cream wove paper, perimeter mounted on cream wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/61d79898-20ed-493a-6f3b-e08fc13ac705/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/113333",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Margaret Day Blake Collection",
+ "image": "/pd/aic-113333.jpg"
+ },
+ {
+ "id": "aic-113331",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Three Caricatures of Heads",
+ "artist": "Jean Louis André Théodore Géricault",
+ "date": "1818/19",
+ "year": 1818,
+ "medium": "Graphite on cream wove paper, perimeter mounted on cream wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/1e49db28-5780-af06-c15d-3234f81ca6bc/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/113331",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Margaret Day Blake Collection",
+ "image": "/pd/aic-113331.jpg"
+ },
+ {
+ "id": "aic-79864",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Masks of 1831, plate 143 from La Caricature",
+ "artist": "Honoré-Victorin Daumier",
+ "date": "1832",
+ "year": 1832,
+ "medium": "Lithograph in black on white wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/dbb3c0d6-28e9-9f59-5583-a2277de0dbb4/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/79864",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Gift of Mr. and Mrs. Carl O. Schniewind",
+ "image": "/pd/aic-79864.jpg"
+ },
+ {
+ "id": "aic-66094",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricatures of Gauguin and Governor Gallet, with headpiece from Le sourire",
+ "artist": "Paul Gauguin",
+ "date": "1900",
+ "year": 1900,
+ "medium": "Watercolor, with black colored pencil, and touches of pen and black ink, over a transfer drawing in black, and wood-block print in black ink with blue watercolor on cream wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/89d02f05-0bac-c5de-2b90-6f53051487bb/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/66094",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Gift of Walter S. Brewster",
+ "image": "/pd/aic-66094.jpg"
+ },
+ {
+ "id": "aic-61076",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Mr. Prune, plate 288 from Célébrités de la Caricature",
+ "artist": "Honoré-Victorin Daumier",
+ "date": "1833",
+ "year": 1833,
+ "medium": "Lithograph in black on cream wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/d6de897a-0d4e-e72e-de7d-600983c02e55/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/61076",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Print Sales Miscellaneous Fund",
+ "image": "/pd/aic-61076.jpg"
+ },
+ {
+ "id": "aic-113319",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Sketch of a Horse Facing Right and a Caricature in Profile",
+ "artist": "Jean Louis André Théodore Géricault",
+ "date": "1818/19",
+ "year": 1818,
+ "medium": "Graphite, on cream laid paper, perimeter mounted on cream wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/a0542a4d-a9c4-cc26-1f6c-83816c18dc60/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/113319",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Margaret Day Blake Collection",
+ "image": "/pd/aic-113319.jpg"
+ },
+ {
+ "id": "aic-113392",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricature of a Man Wearing a Broad-Brimmed Hat",
+ "artist": "Jean Louis André Théodore Géricault",
+ "date": "1818/19",
+ "year": 1818,
+ "medium": "Graphite on cream laid paper, perimeter mounted on cream wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/127ff26f-568e-742f-d307-81d1244d7f77/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/113392",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Margaret Day Blake Collection",
+ "image": "/pd/aic-113392.jpg"
+ },
+ {
+ "id": "aic-37163",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "The Caricature Magazine, or Hudibrastic Mirror, Vol. I and II",
+ "artist": "George Woodward",
+ "date": "1819",
+ "year": 1819,
+ "medium": "Book with hand-colored etchings in black on cream wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/ac50b3bb-08ee-819e-34ed-967499d5704c/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/37163",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Gift of Mrs. James Ward Thorne",
+ "image": "/pd/aic-37163.jpg"
+ },
+ {
+ "id": "aic-122398",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Mr. Pot De Naz.., plate 270 from Célébrités de la Caricature",
+ "artist": "Honoré-Victorin Daumier",
+ "date": "1833",
+ "year": 1833,
+ "medium": "Lithograph in black on white wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/7e2dbff0-cb54-fc58-32ee-8b1dea4cc50b/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/122398",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Print Sales Miscellaneous Fund",
+ "image": "/pd/aic-122398.jpg"
+ },
+ {
+ "id": "aic-82876",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Caricature of Man, Woman and Dog",
+ "artist": "Alfred Henry Forrester",
+ "date": "1869",
+ "year": 1869,
+ "medium": "Pen and brown ink on gray wove paper",
+ "image_remote": "https://www.artic.edu/iiif/2/a814cda1-6b1e-22bc-3c14-f4222d129039/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/82876",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "The Leonora Hall Gurley Memorial Collection",
+ "image": "/pd/aic-82876.jpg"
+ },
+ {
+ "id": "aic-6469",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Sojo Henjo, from the series \"One Hundred Satirical Poems (Kyoka neboke hyakushu)\"",
+ "artist": "Utagawa Hiroshige",
+ "date": "19th century",
+ "year": 1800,
+ "medium": "Color woodblock print; chutanzaku",
+ "image_remote": "https://www.artic.edu/iiif/2/5335f89d-ce14-273b-8363-3ea7d1acd97c/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/6469",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Clarence Buckingham Collection",
+ "image": "/pd/aic-6469.jpg"
+ },
+ {
+ "id": "aic-266997",
+ "source": "Art Institute of Chicago",
+ "source_key": "aic",
+ "title": "Satires about the Situation in the Low Countries: The Sleeping Lion (Plate 2)",
+ "artist": "Jan Wierix",
+ "date": "1578",
+ "year": 1578,
+ "medium": "Engraving in black on cream laid paper",
+ "image_remote": "https://www.artic.edu/iiif/2/4a5be7d0-4825-f92f-8b44-a682301b5796/full/843,/0/default.jpg",
+ "source_url": "https://www.artic.edu/artworks/266997",
+ "rights": "Public domain (Art Institute of Chicago open access, CC0)",
+ "credit": "Charles Hack and the Hearn Family Trust Collection, purchased with funds provided by the Harry B. and Bessie K. Braude Memorial, Amanda S. Johnson and Marion J. Livingston, anonymous, and Suzanne Searle Dixon endowment funds",
+ "image": "/pd/aic-266997.jpg"
+ },
+ {
+ "id": "met-389085",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "The Political Cartoon, for the Year 1775",
+ "artist": "Anonymous, British, 18th century",
+ "date": "May 1, 1775",
+ "year": 1775,
+ "medium": "Engraving",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP876949.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/389085",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Bequest of Charles Allen Munn, 1924",
+ "image": "/pd/met-389085.jpg"
+ },
+ {
+ "id": "met-850669",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "\"Taking the Stump\" or Stephen in Search of his Mother",
+ "artist": "Louis Maurer",
+ "date": "1860",
+ "year": 1860,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21532-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850669",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850669.jpg"
+ },
+ {
+ "id": "met-850668",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Storming the Castle – \"Old \"Abe\" on Guard",
+ "artist": "Currier & Ives",
+ "date": "1860",
+ "year": 1860,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21531-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850668",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850668.jpg"
+ },
+ {
+ "id": "met-389090",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "The Colonies Reduced; Its Companion, designed and engraved for The Political Register",
+ "artist": "Benjamin Franklin",
+ "date": "December 1768",
+ "year": 1768,
+ "medium": "Etching and engraving",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP876943.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/389090",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Bequest of Charles Allen Munn, 1924",
+ "image": "/pd/met-389090.jpg"
+ },
+ {
+ "id": "met-389056",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "The American Rattlesnake Presenting Monsieur his Ally a Dish of Frogs",
+ "artist": "Anonymous, British, 18th century",
+ "date": "November 8, 1782",
+ "year": 1782,
+ "medium": "Etching with watercolor",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-45412-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/389056",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Bequest of Charles Allen Munn, 1924",
+ "image": "/pd/met-389056.jpg"
+ },
+ {
+ "id": "met-850627",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "An Heir to the Throne, Or the Next Republican Candidate",
+ "artist": "Louis Maurer",
+ "date": "1860",
+ "year": 1860,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21406-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850627",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850627.jpg"
+ },
+ {
+ "id": "met-819943",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "The True Peace Commissioners",
+ "artist": "Currier & Ives",
+ "date": "1865",
+ "year": 1865,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP883819.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/819943",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-819943.jpg"
+ },
+ {
+ "id": "met-850676",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "\"The Nigger\" in the Woodpile",
+ "artist": "Louis Maurer",
+ "date": "1860",
+ "year": 1860,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21517-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850676",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850676.jpg"
+ },
+ {
+ "id": "met-850659",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "The True Issue or \"Thats Whats the Matter\"",
+ "artist": "Currier & Ives",
+ "date": "1864",
+ "year": 1864,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21533-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850659",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850659.jpg"
+ },
+ {
+ "id": "met-850670",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "The National Game. Three \"Outs\" and One \"Run\" – Abraham Winning the Ball",
+ "artist": "Louis Maurer",
+ "date": "1860",
+ "year": 1860,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21516-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850670",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850670.jpg"
+ },
+ {
+ "id": "met-389091",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Magna Britannia: Her Colonies Reduced",
+ "artist": "Benjamin Franklin",
+ "date": "1833 [based on 1766 print]",
+ "year": 1766,
+ "medium": "Etching and engraving",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP876942.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/389091",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of William H. Huntington, 1883",
+ "image": "/pd/met-389091.jpg"
+ },
+ {
+ "id": "met-389104",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "All on Hobbies, Gee Up, Gee Ho!",
+ "artist": "Edward Williams Clay",
+ "date": "1838",
+ "year": 1838,
+ "medium": "Lithograph, hand-colored",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP876995.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/389104",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "The Elisha Whittelsey Collection, The Elisha Whittelsey Fund and Harris Brisbane Dick Fund, by Exchange, 1970",
+ "image": "/pd/met-389104.jpg"
+ },
+ {
+ "id": "met-388974",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Chicago Nominee: \"I knew him, Horatio; a fellow of infinite jest...Where be your gibes now?–Hamlet, Act IV [sic], Scene 1\"",
+ "artist": "Justin H. Howard",
+ "date": "1864",
+ "year": 1864,
+ "medium": "Wood engraving",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP808901.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/388974",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of Georgiana W. Sargent, in memory of John Osborne Sargent, 1924",
+ "image": "/pd/met-388974.jpg"
+ },
+ {
+ "id": "met-850632",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "The Great Exhibition of 1860",
+ "artist": "Louis Maurer",
+ "date": "1860",
+ "year": 1860,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21403-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850632",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850632.jpg"
+ },
+ {
+ "id": "met-850673",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "\"Uncle Sam\" Making New Arrangements",
+ "artist": "Louis Maurer",
+ "date": "1860",
+ "year": 1860,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21534-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850673",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850673.jpg"
+ },
+ {
+ "id": "met-850671",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "The Rail Candidate",
+ "artist": "Louis Maurer",
+ "date": "1860",
+ "year": 1860,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21522-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850671",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850671.jpg"
+ },
+ {
+ "id": "met-850635",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Abraham's Dream! – \"Coming Events Cast Their Shadows Before\"",
+ "artist": "Louis Maurer",
+ "date": "1864",
+ "year": 1864,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21390-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850635",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850635.jpg"
+ },
+ {
+ "id": "met-850639",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "\"The Irrepressible Conflict,\" or the Republican Barque in Danger",
+ "artist": "Louis Maurer",
+ "date": "1860",
+ "year": 1860,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21409-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850639",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850639.jpg"
+ },
+ {
+ "id": "met-850674",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "The Old Bull Dog on the Right Track",
+ "artist": "Currier & Ives",
+ "date": "1864",
+ "year": 1864,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21518-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850674",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850674.jpg"
+ },
+ {
+ "id": "met-850636",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Breaking that \"Backbone\"",
+ "artist": "Benjamin Henry Day Jr.",
+ "date": "1862–63",
+ "year": 1862,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21393-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850636",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850636.jpg"
+ },
+ {
+ "id": "met-850679",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "The Smelling Committee",
+ "artist": "John Cameron",
+ "date": "1868",
+ "year": 1868,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP-21528-001.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/850679",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of A. S. Colgate, 1952",
+ "image": "/pd/met-850679.jpg"
+ },
+ {
+ "id": "met-341322",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature",
+ "artist": "Caran d'Ache [Emmanuel Poiré]",
+ "date": "1858–1909",
+ "year": 1858,
+ "medium": "Pen and brown ink, brush and brown wash",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP808308.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/341322",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Harris Brisbane Dick Fund, 1933",
+ "image": "/pd/met-341322.jpg"
+ },
+ {
+ "id": "met-362271",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature",
+ "artist": "Anonymous, French, 19th century",
+ "date": "19th century",
+ "year": 1800,
+ "medium": "Graphite and watercolor",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP809157.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/362271",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "The Elisha Whittelsey Collection, The Elisha Whittelsey Fund, 1960",
+ "image": "/pd/met-362271.jpg"
+ },
+ {
+ "id": "met-343561",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature",
+ "artist": "Anonymous, French, 18th century",
+ "date": "ca. 1776–86",
+ "year": 1766,
+ "medium": "Graphite, brush and wash",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP808735.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/343561",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of Eugene L. Garbaty, 1953",
+ "image": "/pd/met-343561.jpg"
+ },
+ {
+ "id": "met-459504",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Male Caricature",
+ "artist": "Follower of Guercino",
+ "date": "mid–late 17th century",
+ "year": 1635,
+ "medium": "Pen and brown ink",
+ "image_remote": "https://images.metmuseum.org/CRDImages/rl/web-large/DP-17358-048.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/459504",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Robert Lehman Collection, 1975",
+ "image": "/pd/met-459504.jpg"
+ },
+ {
+ "id": "met-392320",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature of Berlioz, from \"La Caricature Provisoire, no. 1\"",
+ "artist": "Benjamin Roubaud (called \"Benjamin\")",
+ "date": "1838",
+ "year": 1838,
+ "medium": "Lithograph",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP818604.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/392320",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of Bella C. Landauer, 1926",
+ "image": "/pd/met-392320.jpg"
+ },
+ {
+ "id": "met-351971",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature of Henri Mürger",
+ "artist": "Nadar",
+ "date": "1849–61",
+ "year": 1849,
+ "medium": "Pen and watercolor",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP808866.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/351971",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of Lincoln Kirstein, 1965",
+ "image": "/pd/met-351971.jpg"
+ },
+ {
+ "id": "met-362270",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature (Jean Baptiste Chollet?)",
+ "artist": "Anonymous, French, 19th century",
+ "date": "19th century",
+ "year": 1800,
+ "medium": "Black, red, and white chalk",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP809161.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/362270",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "The Elisha Whittelsey Collection, The Elisha Whittelsey Fund, 1960",
+ "image": "/pd/met-362270.jpg"
+ },
+ {
+ "id": "met-418570",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature of Paul Meurice",
+ "artist": "Hippolyte Mailly",
+ "date": "1859",
+ "year": 1859,
+ "medium": "Black chalk on brown paper",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP830238.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/418570",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of Dr. Stephen K. and Janie Woo Scher, 2012",
+ "image": "/pd/met-418570.jpg"
+ },
+ {
+ "id": "met-418567",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature of Charles Philipon",
+ "artist": "Hippolyte Mailly",
+ "date": "1859",
+ "year": 1859,
+ "medium": "Black chalk on brown paper",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP830227.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/418567",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of Dr. Stephen K. and Janie Woo Scher, 2012",
+ "image": "/pd/met-418567.jpg"
+ },
+ {
+ "id": "met-744243",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Title Page, Rowlandson's Caricature Magazine",
+ "artist": "Thomas Rowlandson",
+ "date": "1808",
+ "year": 1808,
+ "medium": "Hand-colored etching; proof before letters",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP873954.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/744243",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "The Elisha Whittelsey Collection, The Elisha Whittelsey Fund, 1956",
+ "image": "/pd/met-744243.jpg"
+ },
+ {
+ "id": "met-335913",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature of a Printer",
+ "artist": "Jean Charles Delafosse",
+ "date": "",
+ "year": 1734,
+ "medium": "Pen and black ink, brush and gray and colored wash, over traces of black chalk",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP808302.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/335913",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "The Elisha Whittelsey Collection, The Elisha Whittelsey Fund, 1960",
+ "image": "/pd/met-335913.jpg"
+ },
+ {
+ "id": "met-339826",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature of Joseph-Benoît Suvée",
+ "artist": "François André Vincent",
+ "date": "mid-18th–early 19th century",
+ "year": 1764,
+ "medium": "Black chalk; counterproof",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP808433.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/339826",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of Jean-Pierre Selz, 1986",
+ "image": "/pd/met-339826.jpg"
+ },
+ {
+ "id": "met-15662",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature of a Man",
+ "artist": "John Singer Sargent",
+ "date": "1880–82",
+ "year": 1880,
+ "medium": "Graphite on off-white wove paper",
+ "image_remote": "https://images.metmuseum.org/CRDImages/ad/web-large/50.130.95 verso.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/15662",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of Mrs. Francis Ormond, 1950",
+ "image": "/pd/met-15662.jpg"
+ },
+ {
+ "id": "met-340110",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature of a Grandee",
+ "artist": "Ercole Procaccini The Younger",
+ "date": "17th century",
+ "year": 1600,
+ "medium": "Pen and brown ink, brush and brown wash over black chalk on light tan paper",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP802420.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/340110",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "Gift of Cornelius Vanderbilt, 1880",
+ "image": "/pd/met-340110.jpg"
+ },
+ {
+ "id": "met-335916",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature of a Sculptor",
+ "artist": "Jean Charles Delafosse",
+ "date": "",
+ "year": 1734,
+ "medium": "Pen and black ink with gray, ochre, blue, pink and green washes over black chalk underdrawing",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP102705.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/335916",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "The Elisha Whittelsey Collection, The Elisha Whittelsey Fund, 1960",
+ "image": "/pd/met-335916.jpg"
+ },
+ {
+ "id": "met-392759",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Title Page, The Caricature Magazine, or Mirror of Mirth",
+ "artist": "Thomas Rowlandson",
+ "date": "November 19, 1808",
+ "year": 1808,
+ "medium": "Hand-colored etching",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP818499.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/392759",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "The Elisha Whittelsey Collection, The Elisha Whittelsey Fund, 1959",
+ "image": "/pd/met-392759.jpg"
+ },
+ {
+ "id": "met-395366",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Caricature of Charles-Henri Plantade (?)",
+ "artist": "Horace Vernet",
+ "date": "19th century",
+ "year": 1800,
+ "medium": "Pen and brown ink, brush and brown wash and black chalk",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP812850.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/395366",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "The Elisha Whittelsey Collection, The Elisha Whittelsey Fund, 2010",
+ "image": "/pd/met-395366.jpg"
+ },
+ {
+ "id": "met-745548",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Title Page, The Caricature Magazine by G. M. Woodward, vol. 4",
+ "artist": "Thomas Rowlandson",
+ "date": "[1809] 1821",
+ "year": 1809,
+ "medium": "Hand-colored etching",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP880584.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/745548",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "The Elisha Whittelsey Collection, The Elisha Whittelsey Fund, 1959",
+ "image": "/pd/met-745548.jpg"
+ },
+ {
+ "id": "met-744206",
+ "source": "The Metropolitan Museum of Art",
+ "source_key": "met",
+ "title": "Title Page, Rowlandson's Caricature Magazine, Vol. 5",
+ "artist": "Thomas Rowlandson",
+ "date": "1808",
+ "year": 1808,
+ "medium": "Hand-colored etching",
+ "image_remote": "https://images.metmuseum.org/CRDImages/dp/web-large/DP873952.jpg",
+ "source_url": "https://www.metmuseum.org/art/collection/search/744206",
+ "rights": "Public domain (The Met Open Access, CC0)",
+ "credit": "The Elisha Whittelsey Collection, The Elisha Whittelsey Fund, 1959",
+ "image": "/pd/met-744206.jpg"
+ },
+ {
+ "id": "cma-311853",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Caricature of Paul Gauguin",
+ "artist": "Émile Bernard (French, 1868–1941)",
+ "date": "1889",
+ "year": 1889,
+ "medium": "watercolor and black ink on paper",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/2018.75/2018.75_web.jpg",
+ "source_url": "https://clevelandart.org/art/2018.75",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Bequest of William Kelly Simpson in memory of his wife Marilyn M. Simpson and her grandfather, John D. Rockefeller Jr.",
+ "image": "/pd/cma-311853.jpg"
+ },
+ {
+ "id": "cma-111369",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "The Nightmare",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1832",
+ "year": 1832,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1929.874/1929.874_web.jpg",
+ "source_url": "https://clevelandart.org/art/1929.874",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of Frank S. Lahm",
+ "image": "/pd/cma-111369.jpg"
+ },
+ {
+ "id": "cma-106900",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "The Repose of France",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1834",
+ "year": 1834,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1924.910/1924.910_web.jpg",
+ "source_url": "https://clevelandart.org/art/1924.910",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of Philip Hofer",
+ "image": "/pd/cma-106900.jpg"
+ },
+ {
+ "id": "cma-124699",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "We are all honest men, so let us embrace and be done with it",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1834",
+ "year": 1834,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1946.184/1946.184_web.jpg",
+ "source_url": "https://clevelandart.org/art/1946.184",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of Mrs. Malcolm L. McBride",
+ "image": "/pd/cma-124699.jpg"
+ },
+ {
+ "id": "cma-167919",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Mr. Keratr.",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1833",
+ "year": 1833,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/2009.506/2009.506_web.jpg",
+ "source_url": "https://clevelandart.org/art/2009.506",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of John Bonebrake",
+ "image": "/pd/cma-167919.jpg"
+ },
+ {
+ "id": "cma-142680",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "A Pleasure Trip to Paris",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1843",
+ "year": 1843,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1966.400/1966.400_web.jpg",
+ "source_url": "https://clevelandart.org/art/1966.400",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Mr. and Mrs. Charles G. Prasse Collection",
+ "image": "/pd/cma-142680.jpg"
+ },
+ {
+ "id": "cma-167916",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Athenians Beware of Phillip! (Demosthenes to the Athenians)",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1835",
+ "year": 1835,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/2009.503/2009.503_web.jpg",
+ "source_url": "https://clevelandart.org/art/2009.503",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of John Bonebrake",
+ "image": "/pd/cma-167916.jpg"
+ },
+ {
+ "id": "cma-110905",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "History of a Picture No. 1: Before the Jury",
+ "artist": "Frank Wilcox (American, 1887–1964)",
+ "date": "c. 1929",
+ "year": 1924,
+ "medium": "pencil and wash heightened with white",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1929.422/1929.422_web.jpg",
+ "source_url": "https://clevelandart.org/art/1929.422",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of Mrs. Howard M. Hanna",
+ "image": "/pd/cma-110905.jpg"
+ },
+ {
+ "id": "cma-109042",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Art Lovers",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "c. 1863",
+ "year": 1858,
+ "medium": "Gray and black wash, charcoal, and graphite, with watercolor, on cream laid paper",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1927.208/1927.208_web.jpg",
+ "source_url": "https://clevelandart.org/art/1927.208",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Dudley P. Allen Fund",
+ "image": "/pd/cma-109042.jpg"
+ },
+ {
+ "id": "cma-104977",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "The Legislative Belly",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1834",
+ "year": 1834,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1923.206/1923.206_web.jpg",
+ "source_url": "https://clevelandart.org/art/1923.206",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Charles W. Harkness Endowment Fund",
+ "image": "/pd/cma-104977.jpg"
+ },
+ {
+ "id": "cma-121136",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Don't Meddle With It!",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1834",
+ "year": 1834,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1942.1018/1942.1018_web.jpg",
+ "source_url": "https://clevelandart.org/art/1942.1018",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Mr. and Mrs. Lewis B. Williams Collection",
+ "image": "/pd/cma-121136.jpg"
+ },
+ {
+ "id": "cma-136334",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Failed Lafayette! It Serves You Right, My Old Friend!",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1834",
+ "year": 1834,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1960.21/1960.21_web.jpg",
+ "source_url": "https://clevelandart.org/art/1960.21",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Fortieth Anniversary Gift of The Print Club of Cleveland in honor of William Mathewson Milliken",
+ "image": "/pd/cma-136334.jpg"
+ },
+ {
+ "id": "cma-107016",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Memories",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1840",
+ "year": 1840,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1925.1013/1925.1013_web.jpg",
+ "source_url": "https://clevelandart.org/art/1925.1013",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Dudley P. Allen Fund",
+ "image": "/pd/cma-107016.jpg"
+ },
+ {
+ "id": "cma-169587",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Lesson in Understanding in 1843",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1843",
+ "year": 1843,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/2011.407/2011.407_web.jpg",
+ "source_url": "https://clevelandart.org/art/2011.407",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of Susan Schulman and Carolyn Bullard in honor of Jane Glaubinger",
+ "image": "/pd/cma-169587.jpg"
+ },
+ {
+ "id": "cma-122753",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "If you knew how pretty you are!",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1841",
+ "year": 1841,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1942.928/1942.928_web.jpg",
+ "source_url": "https://clevelandart.org/art/1942.928",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of George W. Bierce",
+ "image": "/pd/cma-122753.jpg"
+ },
+ {
+ "id": "cma-106785",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Rue Transnonain, April 15, 1834",
+ "artist": "Honoré Daumier (French, 1808–1879)",
+ "date": "1834",
+ "year": 1834,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1924.809/1924.809_web.jpg",
+ "source_url": "https://clevelandart.org/art/1924.809",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of Ralph King",
+ "image": "/pd/cma-106785.jpg"
+ },
+ {
+ "id": "cma-115833",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "The Holdup, first state",
+ "artist": "George Bellows (American, 1882–1925)",
+ "date": "1921",
+ "year": 1921,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1936.548/1936.548_web.jpg",
+ "source_url": "https://clevelandart.org/art/1936.548",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of Leonard C. Hanna Jr.",
+ "image": "/pd/cma-115833.jpg"
+ },
+ {
+ "id": "cma-167946",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Satan",
+ "artist": "Paul Gavarni (French, 1804–1866)",
+ "date": "c.1848–62",
+ "year": 1843,
+ "medium": "lithograph on chine collé",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/2009.530/2009.530_web.jpg",
+ "source_url": "https://clevelandart.org/art/2009.530",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of John Bonebrake",
+ "image": "/pd/cma-167946.jpg"
+ },
+ {
+ "id": "cma-123223",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Caricatures du jour: La Lecture des mystères de Paris",
+ "artist": "Charles Joseph Traviès de Villers (French, 1804–1859)",
+ "date": "c. 1830–45",
+ "year": 1830,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1943.478/1943.478_web.jpg",
+ "source_url": "https://clevelandart.org/art/1943.478",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of George W. Bierce",
+ "image": "/pd/cma-123223.jpg"
+ },
+ {
+ "id": "cma-115100",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Speicher, Kroll and Bellows",
+ "artist": "George Bellows (American, 1882–1925)",
+ "date": "1921",
+ "year": 1921,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1935.256/1935.256_web.jpg",
+ "source_url": "https://clevelandart.org/art/1935.256",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of Leonard C. Hanna Jr.",
+ "image": "/pd/cma-115100.jpg"
+ },
+ {
+ "id": "cma-122818",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "An Intensely Contested Young Woman",
+ "artist": "Charles-Émile Jacque (French, 1813–1894)",
+ "date": "1843",
+ "year": 1843,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1942.987/1942.987_web.jpg",
+ "source_url": "https://clevelandart.org/art/1942.987",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of George W. Bierce",
+ "image": "/pd/cma-122818.jpg"
+ },
+ {
+ "id": "cma-110910",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "History of a Picture No. 2: The Public",
+ "artist": "Frank Wilcox (American, 1887–1964)",
+ "date": "c. 1929",
+ "year": 1924,
+ "medium": "pencil and wash heightened with white",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1929.427/1929.427_web.jpg",
+ "source_url": "https://clevelandart.org/art/1929.427",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of The Print Club of Cleveland",
+ "image": "/pd/cma-110910.jpg"
+ },
+ {
+ "id": "cma-166522",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "The Clothes are Italian",
+ "artist": "Jean-Antoine Watteau (French, 1684–1721)",
+ "date": "1715–16",
+ "year": 1715,
+ "medium": "etching",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/2008.3/2008.3_web.jpg",
+ "source_url": "https://clevelandart.org/art/2008.3",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Severance and Greta Millikin Purchase Fund",
+ "image": "/pd/cma-166522.jpg"
+ },
+ {
+ "id": "cma-135782",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Strolling Actresses Dressing in a Barn",
+ "artist": "William Hogarth (British, 1697–1764)",
+ "date": "1738",
+ "year": 1738,
+ "medium": "engraving",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1959.310/1959.310_web.jpg",
+ "source_url": "https://clevelandart.org/art/1959.310",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of Mr. and Mrs. Milton Curtiss Rose",
+ "image": "/pd/cma-135782.jpg"
+ },
+ {
+ "id": "cma-679091",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Satirical Prints of Suzhou Customs",
+ "artist": "Unknown artist",
+ "date": "1760",
+ "year": 1760,
+ "medium": "Woodblock print; ink on paper",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/2025.64/2025.64_web.jpg",
+ "source_url": "https://clevelandart.org/art/2025.64",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Purchase from the J. H. Wade Fund",
+ "image": "/pd/cma-679091.jpg"
+ },
+ {
+ "id": "cma-143203",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Conversation: Ludovic Halévy and Madame Cardinal (The Conversation) for \"La Famille Cardinal\" by Ludovic Halévy",
+ "artist": "Edgar Degas (French, 1834–1917)",
+ "date": "c. 1880–83",
+ "year": 1880,
+ "medium": "monotype",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1967.167/1967.167_web.jpg",
+ "source_url": "https://clevelandart.org/art/1967.167",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of The Print Club of Cleveland in honor of Henry Sayles Francis",
+ "image": "/pd/cma-143203.jpg"
+ },
+ {
+ "id": "cma-115925",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Business Men's Class",
+ "artist": "George Bellows (American, 1882–1925)",
+ "date": "1916",
+ "year": 1916,
+ "medium": "lithograph",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1936.630/1936.630_web.jpg",
+ "source_url": "https://clevelandart.org/art/1936.630",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "Gift of Leonard C. Hanna Jr.",
+ "image": "/pd/cma-115925.jpg"
+ },
+ {
+ "id": "cma-159238",
+ "source": "Cleveland Museum of Art",
+ "source_key": "cma",
+ "title": "Oh Heigh Oh or A View of the Back Settlements",
+ "artist": "Matthew Darly (British, active 1741–1780)",
+ "date": "1776",
+ "year": 1776,
+ "medium": "engraving",
+ "image_remote": "https://openaccess-cdn.clevelandart.org/1995.53/1995.53_web.jpg",
+ "source_url": "https://clevelandart.org/art/1995.53",
+ "rights": "Public domain (Cleveland Museum of Art Open Access, CC0)",
+ "credit": "John L. Severance Fund",
+ "image": "/pd/cma-159238.jpg"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/public/app.js b/public/app.js
index df3344e..160bcc8 100644
--- a/public/app.js
+++ b/public/app.js
@@ -1,18 +1,16 @@
-// Inkwell — Editorial Cartoon Archive: private catalog viewer.
-// Loads /api/cartoons, renders a filterable/sortable grid with a density slider,
-// a topic-chip + section + decade nav, and a detail modal. Choices persist to localStorage.
-// No server-side state beyond the static dataset.
+// Inkwell — Public-domain cartoons gallery.
+// Loads /api/pd-cartoons (built by scripts/fetch-pd-cartoons.mjs from museum, library and university
+// open-access APIs) and renders a filterable/sortable image grid with a density slider, a
+// museums vs libraries nav, and a detail modal carrying the holding institution's rights + credit.
+// Also owns the shared nav (hamburger) and modal close wiring that p24.js relies on.
+// Choices persist to localStorage.
-const LS_SORT = 'pcc:sort';
-const LS_DENSITY = 'pcc:density';
-const LS_FILTERS = 'pcc:filters';
+const LS_SORT = 'inkwell:pd:sort';
+const LS_DENSITY = 'inkwell:pd:density';
+const LS_FILTERS = 'inkwell:pd:filters';
let ALL = [];
-let BIO = null;
-let filters = {
- year: null, publication: null, award: null, subject: null, recordType: null,
- topic: null, section: 'all', decade: null,
-};
+let filters = { source: null, century: null, kind: 'all' };
function safeGetLS(key, fallback) {
try {
@@ -24,262 +22,140 @@ function safeSetLS(key, val) {
try { localStorage.setItem(key, JSON.stringify(val)); } catch (e) { /* ignore */ }
}
-function yearOf(rec) {
- const d = rec.date || rec.date_range || '';
- const m = String(d).match(/\d{4}/);
- return m ? m[0] : 'Unknown';
-}
-
-function decadeOf(rec) {
- const y = parseInt(rec.year, 10);
- if (!y) return null;
- return String(Math.floor(y / 10) * 10);
+function escapeHtml(s) {
+ return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
}
-function normalizeRecords(raw) {
- return raw.map((r, i) => {
- const year = yearOf(r);
- return {
- id: r.id || `pc-${i}`,
- title: r.title || 'Untitled',
- date: r.date || r.date_range || null,
- year,
- decade: (() => { const y = parseInt(year, 10); return y ? String(Math.floor(y / 10) * 10) : null; })(),
- publication: r.publication || null,
- subject: r.subject || null,
- award: r.award || null,
- record_type: r.record_type || 'documented',
- extent: r.extent || null,
- topics: Array.isArray(r.topics) ? r.topics : [],
- image: r.image || null, // local downloaded path, preferred for display
- image_url: r.image_url || null, // external legitimate source, fallback
- image_source: r.image_source || null,
- image_status: r.image_status || null, // 'not_found' when no image exists anywhere
- representative: !!r.representative,
- rights_note: r.rights_note || null,
- citation_url: r.citation_url || null,
- };
- });
+// Only http(s) links from the dataset become hrefs.
+function safeUrl(u) {
+ return /^https?:\/\//i.test(String(u || '')) ? u : null;
}
-function sectionOf(rec) {
- if (rec.id.startsWith('pulitzer-')) return 'pulitzers';
- if (rec.id.startsWith('loc-')) return 'loc';
- if (rec.id.startsWith('coll-')) return 'archives';
- return 'cartoons';
+function yearOf(it) {
+ if (Number.isFinite(it.year) && it.year > 0) return it.year;
+ const m = String(it.date || '').match(/\b(1[0-9]{3})\b/);
+ return m ? Number(m[1]) : null;
}
-function buildFacet(records, field) {
- const counts = new Map();
- for (const r of records) {
- const v = r[field];
- if (!v) continue;
- counts.set(v, (counts.get(v) || 0) + 1);
- }
- return [...counts.entries()].sort((a, b) => b[1] - a[1] || String(a[0]).localeCompare(String(b[0])));
+function centuryLabel(y) {
+ if (!y) return 'Undated';
+ const c = Math.floor((y - 1) / 100) + 1;
+ const sfx = (c % 10 === 1 && c !== 11) ? 'st' : (c % 10 === 2 && c !== 12) ? 'nd' : (c % 10 === 3 && c !== 13) ? 'rd' : 'th';
+ return `${c}${sfx} century`;
}
-function buildTopicCounts(records) {
- const counts = new Map();
- for (const r of records) {
- for (const t of r.topics) counts.set(t, (counts.get(t) || 0) + 1);
- }
- return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
+function normalize(items) {
+ return items.map((it, i) => {
+ const year = yearOf(it);
+ return {
+ ...it,
+ order: i,
+ year,
+ century: centuryLabel(year),
+ kind: it.source_key === 'dpla' ? 'library' : 'museum',
+ };
+ });
}
-function applyFilters(records) {
+function applyFilters(list) {
const q = document.getElementById('search').value.trim().toLowerCase();
- return records.filter(r => {
- if (filters.year && r.year !== filters.year) return false;
- if (filters.publication && r.publication !== filters.publication) return false;
- if (filters.award && r.award !== filters.award) return false;
- if (filters.subject && r.subject !== filters.subject) return false;
- if (filters.recordType && r.record_type !== filters.recordType) return false;
- if (filters.topic && !r.topics.includes(filters.topic)) return false;
- if (filters.decade && r.decade !== filters.decade) return false;
- if (filters.section && filters.section !== 'all' && filters.section !== 'bio' && sectionOf(r) !== filters.section) return false;
+ return list.filter(it => {
+ if (filters.kind !== 'all' && it.kind !== filters.kind) return false;
+ if (filters.source && it.source !== filters.source) return false;
+ if (filters.century && it.century !== filters.century) return false;
if (q) {
- const hay = [r.title, r.subject, r.publication, r.award, r.date, ...(r.topics || [])].filter(Boolean).join(' ').toLowerCase();
+ const hay = [it.title, it.artist, it.date, it.source, it.medium].join(' ').toLowerCase();
if (!hay.includes(q)) return false;
}
return true;
});
}
-function sortRecords(records, mode) {
- const arr = [...records];
+function sortItems(list, mode) {
+ const a = [...list];
+ const y = (x) => x.year || 99999;
switch (mode) {
- case 'year-asc': return arr.sort((a, b) => (a.year > b.year ? 1 : -1));
- case 'year-desc': return arr.sort((a, b) => (a.year < b.year ? 1 : -1));
- case 'title-az': return arr.sort((a, b) => a.title.localeCompare(b.title));
- case 'topic-az': return arr.sort((a, b) => (a.topics[0] || 'zzz').localeCompare(b.topics[0] || 'zzz') || a.title.localeCompare(b.title));
- case 'award-first': return arr.sort((a, b) => (b.award ? 1 : 0) - (a.award ? 1 : 0));
- case 'newest':
- default: return arr; // natural/dataset order = "Newest"-equivalent default
+ case 'year-desc': return a.sort((p, q) => (q.year || 0) - (p.year || 0));
+ case 'title-az': return a.sort((p, q) => String(p.title).localeCompare(String(q.title)));
+ case 'artist-az': return a.sort((p, q) => String(p.artist).localeCompare(String(q.artist)));
+ case 'source-az': return a.sort((p, q) => String(p.source).localeCompare(String(q.source)) || y(p) - y(q));
+ case 'dataset': return a.sort((p, q) => p.order - q.order);
+ case 'year-asc':
+ default: return a.sort((p, q) => y(p) - y(q));
}
}
+// Facet counts respect the other active filters, so a count never promises rows that won't show.
function renderFacetGroup(containerId, field, label) {
const el = document.getElementById(containerId);
- const facet = buildFacet(ALL, field);
- const rowsHtml = facet.map(([val, count]) => {
- const activeKey = field === 'record_type' ? 'recordType' : field;
- const isActive = filters[activeKey] === val;
- return `<div class="filter-row${isActive ? ' active' : ''}" data-field="${field}" data-value="${encodeURIComponent(val)}">
- <span>${val === 'documented' ? 'Documented cartoon' : val === 'collection-summary' ? 'Archive collection' : escapeHtml(val)}</span>
- <span class="count">${count}</span>
- </div>`;
- }).join('');
- el.innerHTML = `<summary>${label}</summary><div class="rows">${rowsHtml || '<div class="filter-row">— none —</div>'}</div>`;
+ // Count against every active filter except this facet's own, so its other values stay selectable.
+ const own = filters[field];
+ filters[field] = null;
+ const base = applyFilters(ALL);
+ filters[field] = own;
+ const counts = new Map();
+ for (const it of base) counts.set(it[field], (counts.get(it[field]) || 0) + 1);
+ if (filters[field] && !counts.has(filters[field])) counts.set(filters[field], 0);
+ const rows = [...counts.entries()].sort((a, b) => b[1] - a[1] || String(a[0]).localeCompare(String(b[0])));
+ el.innerHTML = `<summary>${label}</summary><div class="rows">${rows.map(([val, n]) => `
+ <div class="filter-row${filters[field] === val ? ' active' : ''}" data-field="${field}" data-value="${encodeURIComponent(val)}">
+ <span>${escapeHtml(val)}</span><span class="count">${n}</span>
+ </div>`).join('') || '<div class="filter-row">— none —</div>'}</div>`;
el.querySelectorAll('.filter-row[data-field]').forEach(row => {
row.addEventListener('click', () => {
- const f = row.dataset.field;
const v = decodeURIComponent(row.dataset.value);
- const key = f === 'record_type' ? 'recordType' : f;
- filters[key] = filters[key] === v ? null : v;
- safeSetLS(LS_FILTERS, filters);
- renderAll();
- });
- });
-}
-
-function renderFilters() {
- renderFacetGroup('facet-year', 'year', 'Year');
- renderFacetGroup('facet-publication', 'publication', 'Publication');
- renderFacetGroup('facet-award', 'award', 'Award');
- renderFacetGroup('facet-subject', 'subject', 'Subject');
- renderFacetGroup('facet-recordtype', 'record_type', 'Record Type');
-}
-
-function renderTopicRow() {
- const el = document.getElementById('topic-row');
- const counts = buildTopicCounts(ALL);
- const totalCount = ALL.length;
- const allChip = `<button type="button" class="topic-chip${!filters.topic ? ' active' : ''}" data-topic="">All <span class="chip-count">${totalCount}</span></button>`;
- const chips = counts.map(([topic, count]) => {
- const isActive = filters.topic === topic;
- return `<button type="button" class="topic-chip${isActive ? ' active' : ''}" data-topic="${encodeURIComponent(topic)}">${escapeHtml(topic)} <span class="chip-count">${count}</span></button>`;
- }).join('');
- el.innerHTML = allChip + chips;
- el.querySelectorAll('.topic-chip').forEach(chip => {
- chip.addEventListener('click', () => {
- const t = chip.dataset.topic ? decodeURIComponent(chip.dataset.topic) : null;
- filters.topic = (filters.topic === t) ? null : t;
+ filters[field] = filters[field] === v ? null : v;
safeSetLS(LS_FILTERS, filters);
renderAll();
});
});
}
-function renderSectionLinks() {
- document.querySelectorAll('#section-links button[data-section]').forEach(btn => {
- btn.classList.toggle('active', filters.section === btn.dataset.section);
- });
-}
-
-function renderDecadeJump() {
- document.querySelectorAll('#decade-jump button[data-decade]').forEach(btn => {
- btn.classList.toggle('active', filters.decade === btn.dataset.decade);
- });
-}
-
-// TK-12179 (Steve, 2026-09-24): the documented research cartoons are research-only and are NEVER displayed —
-// not even locally. Records render as text; the original lives at its archive (citation link).
-function cardHtml(r) {
- let thumb;
- if (r.image || r.image_url) {
- thumb = `<div class="no-img">Research record —<br>image not displayed</div>`;
- } else if (r.image_status === 'not_found') {
- thumb = `<div class="no-img no-img-notfound">No verified image found —<br>view at source</div>`;
- } else {
- thumb = `<div class="no-img">Not digitized —<br>see archive citation</div>`;
- }
- const badges = [
- `<span class="badge ${r.record_type}">${r.record_type === 'documented' ? 'Documented' : 'Archive'}</span>`,
- r.award ? `<span class="badge award">Pulitzer</span>` : '',
- r.representative ? `<span class="badge representative">Representative image</span>` : '',
- ].join('');
- const topicChips = r.topics.slice(0, 3).map(t => `<span class="topic-tag">${escapeHtml(t)}</span>`).join('');
- return `<div class="card" data-id="${r.id}">
- <div class="thumb">${thumb}</div>
+function cardHtml(it) {
+ return `<div class="card" data-id="${escapeHtml(it.id)}" tabindex="0">
+ <div class="thumb"><img src="${escapeHtml(it.image)}" alt="${escapeHtml(it.title)}" loading="lazy"></div>
<div class="body">
- <div class="title">${escapeHtml(r.title)}</div>
- <div class="meta">${escapeHtml(r.date || r.year || '')}${r.publication ? ' · ' + escapeHtml(r.publication) : ''}</div>
- <div class="topics">${topicChips}</div>
- <div class="badges">${badges}</div>
+ <div class="title">${escapeHtml(it.title)}</div>
+ <div class="meta">${escapeHtml(it.artist)}${it.date ? ' · ' + escapeHtml(it.date) : ''}</div>
+ <div class="badges"><span class="topic-tag">${escapeHtml(it.source)}</span><span class="badge pd">Public domain</span></div>
</div>
</div>`;
}
-function escapeHtml(s) {
- return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
-}
-
function renderGrid() {
- const sortMode = document.getElementById('sort').value;
- const filtered = sortRecords(applyFilters(ALL), sortMode);
- document.getElementById('result-count').textContent = `${filtered.length} of ${ALL.length}`;
- const gridEl = document.getElementById('grid');
- gridEl.innerHTML = filtered.length
- ? filtered.map(cardHtml).join('')
- : `<div class="empty-note">No cartoons match these filters.</div>`;
- gridEl.querySelectorAll('.card').forEach(card => {
- card.addEventListener('click', () => openModal(card.dataset.id));
+ const list = sortItems(applyFilters(ALL), document.getElementById('sort').value);
+ document.getElementById('result-count').textContent = `${list.length} of ${ALL.length}`;
+ const grid = document.getElementById('grid');
+ grid.innerHTML = list.length ? list.map(cardHtml).join('') : '<div class="empty-note">No cartoons match these filters.</div>';
+ grid.querySelectorAll('.card').forEach(c => {
+ c.addEventListener('click', () => openModal(c.dataset.id));
+ c.addEventListener('keydown', (e) => { if (e.key === 'Enter') openModal(c.dataset.id); });
});
}
function renderAll() {
- renderFilters();
- renderTopicRow();
- renderSectionLinks();
- renderDecadeJump();
+ document.querySelectorAll('#section-links button[data-kind]').forEach(b => b.classList.toggle('active', b.dataset.kind === filters.kind));
+ renderFacetGroup('facet-source', 'source', 'Collection');
+ renderFacetGroup('facet-century', 'century', 'Century');
renderGrid();
}
function openModal(id) {
- const r = ALL.find(x => x.id === id);
- if (!r) return;
- const topicChips = r.topics.map(t => `<span class="topic-tag modal-topic-tag">${escapeHtml(t)}</span>`).join('');
- let imgBlock = '';
- if (r.image || r.image_url) {
- imgBlock = `<div class="modal-no-img">Research record — image not displayed.${r.citation_url ? ` <a href="${r.citation_url}" target="_blank" rel="noopener noreferrer">Original at source →</a>` : ''}</div>`;
- } else if (r.image_status === 'not_found') {
- imgBlock = `<div class="modal-no-img">No verified image found for this cartoon.${r.citation_url ? ` <a href="${r.citation_url}" target="_blank" rel="noopener noreferrer">View at source →</a>` : ''}</div>`;
- }
- document.getElementById('modal-body').innerHTML = `
- <button class="close-x" id="modal-close">×</button>
- <h2>${escapeHtml(r.title)}</h2>
- <div class="modal-meta">${escapeHtml(r.date || r.year || '')}${r.publication ? ' · ' + escapeHtml(r.publication) : ''}</div>
- <div class="topics modal-topics">${topicChips}</div>
- ${imgBlock}
- <dl>
- <dt>Subject</dt><dd>${escapeHtml(r.subject || '—')}</dd>
- <dt>Award</dt><dd>${escapeHtml(r.award || '—')}</dd>
- <dt>Record type</dt><dd>${r.record_type === 'documented' ? 'Documented cartoon' : 'Archive collection summary'}</dd>
- ${r.extent ? `<dt>Extent</dt><dd>${escapeHtml(r.extent)}</dd>` : ''}
- ${r.image_source ? `<dt>Image source</dt><dd>${escapeHtml(r.image_source)}</dd>` : ''}
- <dt>Citation</dt><dd>${r.citation_url ? `<a href="${r.citation_url}" target="_blank" rel="noopener noreferrer">${escapeHtml(r.citation_url)}</a>` : '—'}</dd>
- </dl>
- ${r.rights_note ? `<div class="rights-note">${escapeHtml(r.rights_note)}</div>` : ''}
- `;
- document.getElementById('modal-backdrop').classList.add('open');
- document.getElementById('modal-close').addEventListener('click', closeModal);
-}
-
-function openBioModal() {
- if (!BIO) return;
+ const it = ALL.find(x => x.id === id);
+ if (!it) return;
+ const src = safeUrl(it.source_url);
document.getElementById('modal-body').innerHTML = `
<button class="close-x" id="modal-close">×</button>
- <h2>${escapeHtml(BIO.name || 'The artist')}</h2>
- <div class="modal-meta">${escapeHtml(BIO.born || '')} — ${escapeHtml(BIO.died || '')}</div>
+ <h2>${escapeHtml(it.title)}</h2>
+ <div class="modal-meta">${escapeHtml(it.artist)}${it.date ? ' · ' + escapeHtml(it.date) : ''}</div>
+ <img class="modal-img" src="${escapeHtml(it.image)}" alt="${escapeHtml(it.title)}">
<dl>
- <dt>Education</dt><dd>${escapeHtml(BIO.education || '—')}</dd>
- <dt>Career</dt><dd>${escapeHtml(BIO.career || '—')}</dd>
- <dt>Honors</dt><dd>${escapeHtml(BIO.honors || '—')}</dd>
- <dt>Family</dt><dd>${escapeHtml(BIO.family || '—')}</dd>
- <dt>Citation</dt><dd>${BIO.citation_url ? `<a href="${BIO.citation_url}" target="_blank" rel="noopener noreferrer">${escapeHtml(BIO.citation_url)}</a>` : '—'}</dd>
- </dl>
- `;
+ <dt>Collection</dt><dd>${escapeHtml(it.source)}${it.via ? ' (via ' + escapeHtml(it.via) + ')' : ''}</dd>
+ ${it.medium ? `<dt>Medium</dt><dd>${escapeHtml(it.medium)}</dd>` : ''}
+ <dt>Rights</dt><dd>${escapeHtml(it.rights)}</dd>
+ ${it.credit && it.credit !== it.source ? `<dt>Credit</dt><dd>${escapeHtml(it.credit)}</dd>` : ''}
+ <dt>Source record</dt><dd>${src ? `<a href="${escapeHtml(src)}" target="_blank" rel="noopener noreferrer">${escapeHtml(src)}</a>` : '—'}</dd>
+ </dl>`;
document.getElementById('modal-backdrop').classList.add('open');
document.getElementById('modal-close').addEventListener('click', closeModal);
}
@@ -297,39 +173,25 @@ function initNav() {
const isOpen = nav.classList.toggle('nav-open');
document.getElementById('hamburger').setAttribute('aria-expanded', String(isOpen));
});
-
document.getElementById('wordmark').addEventListener('click', (e) => {
e.preventDefault();
- filters.section = 'all';
+ filters = { source: null, century: null, kind: 'all' };
safeSetLS(LS_FILTERS, filters);
renderAll();
closeMobileNav();
+ window.scrollTo({ top: 0, behavior: 'smooth' });
});
-
- document.querySelectorAll('#section-links button[data-section]').forEach(btn => {
- btn.addEventListener('click', () => {
- const section = btn.dataset.section;
- if (section === 'bio') {
- openBioModal();
- closeMobileNav();
- return;
- }
- filters.section = section;
- safeSetLS(LS_FILTERS, filters);
- renderAll();
- closeMobileNav();
- });
- });
-
- document.querySelectorAll('#decade-jump button[data-decade]').forEach(btn => {
+ document.querySelectorAll('#section-links button[data-kind]').forEach(btn => {
btn.addEventListener('click', () => {
- const d = btn.dataset.decade;
- filters.decade = (filters.decade === d) ? null : d;
+ filters.kind = btn.dataset.kind;
+ filters.source = null;
safeSetLS(LS_FILTERS, filters);
renderAll();
closeMobileNav();
+ document.getElementById('pd').scrollIntoView({ behavior: 'smooth' });
});
});
+ document.querySelectorAll('#section-links .nav-anchor').forEach(a => a.addEventListener('click', closeMobileNav));
}
function initControls() {
@@ -338,17 +200,17 @@ function initControls() {
sortEl.addEventListener('change', () => { safeSetLS(LS_SORT, sortEl.value); renderGrid(); });
const densityEl = document.getElementById('density');
- const savedDensity = safeGetLS(LS_DENSITY, 220);
- densityEl.value = savedDensity;
- document.documentElement.style.setProperty('--card-min', savedDensity + 'px');
+ const saved = safeGetLS(LS_DENSITY, 240);
+ densityEl.value = saved;
+ document.documentElement.style.setProperty('--card-min', saved + 'px');
densityEl.addEventListener('input', () => {
document.documentElement.style.setProperty('--card-min', densityEl.value + 'px');
- safeSetLS(LS_DENSITY, densityEl.value);
+ safeSetLS(LS_DENSITY, Number(densityEl.value));
});
- document.getElementById('search').addEventListener('input', renderGrid);
+ document.getElementById('search').addEventListener('input', renderAll);
document.getElementById('clear-filters').addEventListener('click', () => {
- filters = { year: null, publication: null, award: null, subject: null, recordType: null, topic: null, section: 'all', decade: null };
+ filters = { source: null, century: null, kind: 'all' };
safeSetLS(LS_FILTERS, filters);
document.getElementById('search').value = '';
renderAll();
@@ -358,22 +220,19 @@ function initControls() {
if (e.target.id === 'modal-backdrop') closeModal();
});
document.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeModal(); });
-
- initNav();
}
async function boot() {
- const savedFilters = safeGetLS(LS_FILTERS, filters);
- filters = { ...filters, ...savedFilters };
- if (!filters.section) filters.section = 'all';
- const res = await fetch('/api/cartoons');
- const raw = await res.json();
- ALL = normalizeRecords(raw.records || raw);
- BIO = raw.bio || null;
+ initNav();
initControls();
+ filters = { ...filters, ...safeGetLS(LS_FILTERS, {}) };
+ const res = await fetch('/api/pd-cartoons');
+ if (!res.ok) throw new Error('HTTP ' + res.status);
+ const doc = await res.json();
+ ALL = normalize(doc.items || []);
renderAll();
}
boot().catch(err => {
- document.getElementById('grid').innerHTML = `<div class="empty-note">Could not load the research records — ${escapeHtml(err.message)}</div>`;
+ document.getElementById('grid').innerHTML = `<div class="empty-note">Could not load the public-domain cartoons — ${escapeHtml(err.message)}</div>`;
});
diff --git a/public/index.html b/public/index.html
index 14afed9..49b402f 100644
--- a/public/index.html
+++ b/public/index.html
@@ -14,32 +14,20 @@
Inkwell <span>Editorial Cartoon Archive</span>
</a>
<div class="topnav-search">
- <input id="search" type="search" placeholder="Search title, subject, date…">
+ <input id="search" type="search" placeholder="Search title, artist, date, collection…">
</div>
</div>
<div class="topnav-row2" id="topnav-row2">
<div class="section-links" id="section-links">
<a class="nav-anchor" href="#p24">P24 Art</a>
- <button type="button" data-section="all" class="active">Research records</button>
- <button type="button" data-section="pulitzers">Pulitzers</button>
- <button type="button" data-section="loc">Library of Congress</button>
- <button type="button" data-section="archives">Archives</button>
- <button type="button" data-section="bio">Bio</button>
- </div>
- <div class="decade-jump" id="decade-jump">
- <span class="decade-label">Jump to decade:</span>
- <button type="button" data-decade="1950">50s</button>
- <button type="button" data-decade="1960">60s</button>
- <button type="button" data-decade="1970">70s</button>
- <button type="button" data-decade="1980">80s</button>
- <button type="button" data-decade="1990">90s</button>
- <button type="button" data-decade="2000">00s</button>
+ <button type="button" data-kind="all" class="active">Public-domain cartoons</button>
+ <button type="button" data-kind="museum">Museums</button>
+ <button type="button" data-kind="library">Libraries & universities</button>
</div>
</div>
- <div class="topic-row" id="topic-row"></div>
</nav>
- <div class="masthead-sub">Private archive · editorial-cartoon research records · local reference tool, not published</div>
+ <div class="masthead-sub">Private archive · public-domain cartoons from museums, libraries & universities · local reference tool, not published</div>
<section class="p24" id="p24" aria-labelledby="p24-heading">
<div class="p24-head">
@@ -71,15 +59,13 @@
</div>
</section>
- <h2 class="section-heading">Research records <span>text-only; images never displayed</span></h2>
+ <section class="pd" id="pd" aria-labelledby="pd-heading">
+ <h2 class="section-heading" id="pd-heading">Public-domain cartoons <span>from museums, libraries & universities — each item marked public domain / CC0 by its holding institution</span></h2>
<div class="layout">
<aside class="filters">
- <details class="filter-group" id="facet-award" open></details>
- <details class="filter-group" id="facet-recordtype" open></details>
- <details class="filter-group" id="facet-publication"></details>
- <details class="filter-group" id="facet-year"></details>
- <details class="filter-group" id="facet-subject"></details>
+ <details class="filter-group" id="facet-source" open></details>
+ <details class="filter-group" id="facet-century" open></details>
<button class="clear-filters" id="clear-filters">Clear all filters</button>
</aside>
@@ -91,14 +77,14 @@
<option value="year-asc">Year ↑ (oldest first)</option>
<option value="year-desc">Year ↓ (newest first)</option>
<option value="title-az">Title A→Z</option>
- <option value="topic-az">Topic A→Z</option>
- <option value="award-first">Award winners first</option>
- <option value="newest">Dataset order</option>
+ <option value="artist-az">Artist A→Z</option>
+ <option value="source-az">Collection A→Z</option>
+ <option value="dataset">Dataset order</option>
</select>
</div>
<div class="density-wrap">
<label for="density">Density</label>
- <input type="range" id="density" min="150" max="340" step="10">
+ <input type="range" id="density" min="150" max="420" step="10">
</div>
<div class="result-count" id="result-count"></div>
</div>
@@ -107,6 +93,7 @@
</div>
</main>
</div>
+ </section>
<div class="modal-backdrop" id="modal-backdrop">
<div class="modal" id="modal-body"></div>
diff --git a/public/pd/aic-113092.jpg b/public/pd/aic-113092.jpg
new file mode 100644
index 0000000..c50a9d4
Binary files /dev/null and b/public/pd/aic-113092.jpg differ
diff --git a/public/pd/aic-113093.jpg b/public/pd/aic-113093.jpg
new file mode 100644
index 0000000..4a2d84c
Binary files /dev/null and b/public/pd/aic-113093.jpg differ
diff --git a/public/pd/aic-113319.jpg b/public/pd/aic-113319.jpg
new file mode 100644
index 0000000..ce9cf8a
Binary files /dev/null and b/public/pd/aic-113319.jpg differ
diff --git a/public/pd/aic-113329.jpg b/public/pd/aic-113329.jpg
new file mode 100644
index 0000000..62e1ea2
Binary files /dev/null and b/public/pd/aic-113329.jpg differ
diff --git a/public/pd/aic-113331.jpg b/public/pd/aic-113331.jpg
new file mode 100644
index 0000000..efe6ba6
Binary files /dev/null and b/public/pd/aic-113331.jpg differ
diff --git a/public/pd/aic-113333.jpg b/public/pd/aic-113333.jpg
new file mode 100644
index 0000000..ca64cd7
Binary files /dev/null and b/public/pd/aic-113333.jpg differ
diff --git a/public/pd/aic-113392.jpg b/public/pd/aic-113392.jpg
new file mode 100644
index 0000000..cb1c283
Binary files /dev/null and b/public/pd/aic-113392.jpg differ
diff --git a/public/pd/aic-122398.jpg b/public/pd/aic-122398.jpg
new file mode 100644
index 0000000..404917c
Binary files /dev/null and b/public/pd/aic-122398.jpg differ
diff --git a/public/pd/aic-129180.jpg b/public/pd/aic-129180.jpg
new file mode 100644
index 0000000..727b79a
Binary files /dev/null and b/public/pd/aic-129180.jpg differ
diff --git a/public/pd/aic-15800.jpg b/public/pd/aic-15800.jpg
new file mode 100644
index 0000000..b2e5d34
Binary files /dev/null and b/public/pd/aic-15800.jpg differ
diff --git a/public/pd/aic-15803.jpg b/public/pd/aic-15803.jpg
new file mode 100644
index 0000000..11007d0
Binary files /dev/null and b/public/pd/aic-15803.jpg differ
diff --git a/public/pd/aic-15809.jpg b/public/pd/aic-15809.jpg
new file mode 100644
index 0000000..e0fca1c
Binary files /dev/null and b/public/pd/aic-15809.jpg differ
diff --git a/public/pd/aic-15812.jpg b/public/pd/aic-15812.jpg
new file mode 100644
index 0000000..8dc6c6b
Binary files /dev/null and b/public/pd/aic-15812.jpg differ
diff --git a/public/pd/aic-15814.jpg b/public/pd/aic-15814.jpg
new file mode 100644
index 0000000..92cd5e9
Binary files /dev/null and b/public/pd/aic-15814.jpg differ
diff --git a/public/pd/aic-15818.jpg b/public/pd/aic-15818.jpg
new file mode 100644
index 0000000..79f4e29
Binary files /dev/null and b/public/pd/aic-15818.jpg differ
diff --git a/public/pd/aic-15826.jpg b/public/pd/aic-15826.jpg
new file mode 100644
index 0000000..9f8eb03
Binary files /dev/null and b/public/pd/aic-15826.jpg differ
diff --git a/public/pd/aic-260711.jpg b/public/pd/aic-260711.jpg
new file mode 100644
index 0000000..e22b4d8
Binary files /dev/null and b/public/pd/aic-260711.jpg differ
diff --git a/public/pd/aic-266997.jpg b/public/pd/aic-266997.jpg
new file mode 100644
index 0000000..03d88e2
Binary files /dev/null and b/public/pd/aic-266997.jpg differ
diff --git a/public/pd/aic-37163.jpg b/public/pd/aic-37163.jpg
new file mode 100644
index 0000000..bacdfe6
Binary files /dev/null and b/public/pd/aic-37163.jpg differ
diff --git a/public/pd/aic-61076.jpg b/public/pd/aic-61076.jpg
new file mode 100644
index 0000000..0f00dd6
Binary files /dev/null and b/public/pd/aic-61076.jpg differ
diff --git a/public/pd/aic-6469.jpg b/public/pd/aic-6469.jpg
new file mode 100644
index 0000000..b7c6350
Binary files /dev/null and b/public/pd/aic-6469.jpg differ
diff --git a/public/pd/aic-66094.jpg b/public/pd/aic-66094.jpg
new file mode 100644
index 0000000..848dca6
Binary files /dev/null and b/public/pd/aic-66094.jpg differ
diff --git a/public/pd/aic-79864.jpg b/public/pd/aic-79864.jpg
new file mode 100644
index 0000000..a5247c2
Binary files /dev/null and b/public/pd/aic-79864.jpg differ
diff --git a/public/pd/aic-82876.jpg b/public/pd/aic-82876.jpg
new file mode 100644
index 0000000..d354ecb
Binary files /dev/null and b/public/pd/aic-82876.jpg differ
diff --git a/public/pd/aic-86054.jpg b/public/pd/aic-86054.jpg
new file mode 100644
index 0000000..df2ed1e
Binary files /dev/null and b/public/pd/aic-86054.jpg differ
diff --git a/public/pd/cma-104977.jpg b/public/pd/cma-104977.jpg
new file mode 100644
index 0000000..97c30fe
Binary files /dev/null and b/public/pd/cma-104977.jpg differ
diff --git a/public/pd/cma-106785.jpg b/public/pd/cma-106785.jpg
new file mode 100644
index 0000000..8b4eebc
Binary files /dev/null and b/public/pd/cma-106785.jpg differ
diff --git a/public/pd/cma-106900.jpg b/public/pd/cma-106900.jpg
new file mode 100644
index 0000000..b98b332
Binary files /dev/null and b/public/pd/cma-106900.jpg differ
diff --git a/public/pd/cma-107016.jpg b/public/pd/cma-107016.jpg
new file mode 100644
index 0000000..3a1e97f
Binary files /dev/null and b/public/pd/cma-107016.jpg differ
diff --git a/public/pd/cma-109042.jpg b/public/pd/cma-109042.jpg
new file mode 100644
index 0000000..9d8fe48
Binary files /dev/null and b/public/pd/cma-109042.jpg differ
diff --git a/public/pd/cma-110905.jpg b/public/pd/cma-110905.jpg
new file mode 100644
index 0000000..a9cefc3
Binary files /dev/null and b/public/pd/cma-110905.jpg differ
diff --git a/public/pd/cma-110910.jpg b/public/pd/cma-110910.jpg
new file mode 100644
index 0000000..deb660f
Binary files /dev/null and b/public/pd/cma-110910.jpg differ
diff --git a/public/pd/cma-111369.jpg b/public/pd/cma-111369.jpg
new file mode 100644
index 0000000..ffd36e5
Binary files /dev/null and b/public/pd/cma-111369.jpg differ
diff --git a/public/pd/cma-115100.jpg b/public/pd/cma-115100.jpg
new file mode 100644
index 0000000..140dbda
Binary files /dev/null and b/public/pd/cma-115100.jpg differ
diff --git a/public/pd/cma-115833.jpg b/public/pd/cma-115833.jpg
new file mode 100644
index 0000000..2cd2a63
Binary files /dev/null and b/public/pd/cma-115833.jpg differ
diff --git a/public/pd/cma-115925.jpg b/public/pd/cma-115925.jpg
new file mode 100644
index 0000000..4430902
Binary files /dev/null and b/public/pd/cma-115925.jpg differ
diff --git a/public/pd/cma-121136.jpg b/public/pd/cma-121136.jpg
new file mode 100644
index 0000000..48a7a7b
Binary files /dev/null and b/public/pd/cma-121136.jpg differ
diff --git a/public/pd/cma-122753.jpg b/public/pd/cma-122753.jpg
new file mode 100644
index 0000000..9e4dae5
Binary files /dev/null and b/public/pd/cma-122753.jpg differ
diff --git a/public/pd/cma-122818.jpg b/public/pd/cma-122818.jpg
new file mode 100644
index 0000000..dc5cd6b
Binary files /dev/null and b/public/pd/cma-122818.jpg differ
diff --git a/public/pd/cma-123223.jpg b/public/pd/cma-123223.jpg
new file mode 100644
index 0000000..4c7c1cf
Binary files /dev/null and b/public/pd/cma-123223.jpg differ
diff --git a/public/pd/cma-124699.jpg b/public/pd/cma-124699.jpg
new file mode 100644
index 0000000..5588699
Binary files /dev/null and b/public/pd/cma-124699.jpg differ
diff --git a/public/pd/cma-135782.jpg b/public/pd/cma-135782.jpg
new file mode 100644
index 0000000..938c389
Binary files /dev/null and b/public/pd/cma-135782.jpg differ
diff --git a/public/pd/cma-136334.jpg b/public/pd/cma-136334.jpg
new file mode 100644
index 0000000..3efba48
Binary files /dev/null and b/public/pd/cma-136334.jpg differ
diff --git a/public/pd/cma-142680.jpg b/public/pd/cma-142680.jpg
new file mode 100644
index 0000000..1f7e5d2
Binary files /dev/null and b/public/pd/cma-142680.jpg differ
diff --git a/public/pd/cma-143203.jpg b/public/pd/cma-143203.jpg
new file mode 100644
index 0000000..243da0f
Binary files /dev/null and b/public/pd/cma-143203.jpg differ
diff --git a/public/pd/cma-159238.jpg b/public/pd/cma-159238.jpg
new file mode 100644
index 0000000..cc86fc2
Binary files /dev/null and b/public/pd/cma-159238.jpg differ
diff --git a/public/pd/cma-166522.jpg b/public/pd/cma-166522.jpg
new file mode 100644
index 0000000..c83bf51
Binary files /dev/null and b/public/pd/cma-166522.jpg differ
diff --git a/public/pd/cma-167916.jpg b/public/pd/cma-167916.jpg
new file mode 100644
index 0000000..e0e7597
Binary files /dev/null and b/public/pd/cma-167916.jpg differ
diff --git a/public/pd/cma-167919.jpg b/public/pd/cma-167919.jpg
new file mode 100644
index 0000000..599fc49
Binary files /dev/null and b/public/pd/cma-167919.jpg differ
diff --git a/public/pd/cma-167946.jpg b/public/pd/cma-167946.jpg
new file mode 100644
index 0000000..a8fa854
Binary files /dev/null and b/public/pd/cma-167946.jpg differ
diff --git a/public/pd/cma-169587.jpg b/public/pd/cma-169587.jpg
new file mode 100644
index 0000000..8c5f02f
Binary files /dev/null and b/public/pd/cma-169587.jpg differ
diff --git a/public/pd/cma-311853.jpg b/public/pd/cma-311853.jpg
new file mode 100644
index 0000000..36a35e8
Binary files /dev/null and b/public/pd/cma-311853.jpg differ
diff --git a/public/pd/cma-679091.jpg b/public/pd/cma-679091.jpg
new file mode 100644
index 0000000..df9c1ab
Binary files /dev/null and b/public/pd/cma-679091.jpg differ
diff --git a/public/pd/dpla-011db0d6402b87d831becb51e511531e.jpg b/public/pd/dpla-011db0d6402b87d831becb51e511531e.jpg
new file mode 100644
index 0000000..bd1110a
Binary files /dev/null and b/public/pd/dpla-011db0d6402b87d831becb51e511531e.jpg differ
diff --git a/public/pd/dpla-0dc692932207db1bca33b3a117b13da5.jpg b/public/pd/dpla-0dc692932207db1bca33b3a117b13da5.jpg
new file mode 100644
index 0000000..d36cb8d
Binary files /dev/null and b/public/pd/dpla-0dc692932207db1bca33b3a117b13da5.jpg differ
diff --git a/public/pd/dpla-13cc17544ee2b24ada29234443164cb7.jpg b/public/pd/dpla-13cc17544ee2b24ada29234443164cb7.jpg
new file mode 100644
index 0000000..9f8ec9e
Binary files /dev/null and b/public/pd/dpla-13cc17544ee2b24ada29234443164cb7.jpg differ
diff --git a/public/pd/dpla-16dd3836398e1ef087c87a02787eaf86.jpg b/public/pd/dpla-16dd3836398e1ef087c87a02787eaf86.jpg
new file mode 100644
index 0000000..1c8b394
Binary files /dev/null and b/public/pd/dpla-16dd3836398e1ef087c87a02787eaf86.jpg differ
diff --git a/public/pd/dpla-19ee8d0c65cc66876f1e3a538551dc73.jpg b/public/pd/dpla-19ee8d0c65cc66876f1e3a538551dc73.jpg
new file mode 100644
index 0000000..91b461c
Binary files /dev/null and b/public/pd/dpla-19ee8d0c65cc66876f1e3a538551dc73.jpg differ
diff --git a/public/pd/dpla-1f9def937f520d341f505c5aa58e4701.jpg b/public/pd/dpla-1f9def937f520d341f505c5aa58e4701.jpg
new file mode 100644
index 0000000..cf64512
Binary files /dev/null and b/public/pd/dpla-1f9def937f520d341f505c5aa58e4701.jpg differ
diff --git a/public/pd/dpla-324c1487694efb27c2129fc716733a03.jpg b/public/pd/dpla-324c1487694efb27c2129fc716733a03.jpg
new file mode 100644
index 0000000..28fed9f
Binary files /dev/null and b/public/pd/dpla-324c1487694efb27c2129fc716733a03.jpg differ
diff --git a/public/pd/dpla-3d6cc1343d435d52d106a5b81db8ec02.jpg b/public/pd/dpla-3d6cc1343d435d52d106a5b81db8ec02.jpg
new file mode 100644
index 0000000..75927fc
Binary files /dev/null and b/public/pd/dpla-3d6cc1343d435d52d106a5b81db8ec02.jpg differ
diff --git a/public/pd/dpla-59c2c7f9b9b972cfe6ef06295633a31e.jpg b/public/pd/dpla-59c2c7f9b9b972cfe6ef06295633a31e.jpg
new file mode 100644
index 0000000..a8a997c
Binary files /dev/null and b/public/pd/dpla-59c2c7f9b9b972cfe6ef06295633a31e.jpg differ
diff --git a/public/pd/dpla-685e7a51d73780ff04c22ed56189287a.jpg b/public/pd/dpla-685e7a51d73780ff04c22ed56189287a.jpg
new file mode 100644
index 0000000..23c6b93
Binary files /dev/null and b/public/pd/dpla-685e7a51d73780ff04c22ed56189287a.jpg differ
diff --git a/public/pd/dpla-6b52edab1b7446f237535b24b007a321.jpg b/public/pd/dpla-6b52edab1b7446f237535b24b007a321.jpg
new file mode 100644
index 0000000..10e39b9
Binary files /dev/null and b/public/pd/dpla-6b52edab1b7446f237535b24b007a321.jpg differ
diff --git a/public/pd/dpla-71f79303fad059e00b6be4dbfe404c4f.jpg b/public/pd/dpla-71f79303fad059e00b6be4dbfe404c4f.jpg
new file mode 100644
index 0000000..28bf60f
Binary files /dev/null and b/public/pd/dpla-71f79303fad059e00b6be4dbfe404c4f.jpg differ
diff --git a/public/pd/dpla-85115befac6f4fc67ea0173909cb4ad2.jpg b/public/pd/dpla-85115befac6f4fc67ea0173909cb4ad2.jpg
new file mode 100644
index 0000000..70a98db
Binary files /dev/null and b/public/pd/dpla-85115befac6f4fc67ea0173909cb4ad2.jpg differ
diff --git a/public/pd/dpla-852d92ecc93967ec12222fe7931603d3.jpg b/public/pd/dpla-852d92ecc93967ec12222fe7931603d3.jpg
new file mode 100644
index 0000000..6e7ab76
Binary files /dev/null and b/public/pd/dpla-852d92ecc93967ec12222fe7931603d3.jpg differ
diff --git a/public/pd/dpla-90e3ffd4a24de5719990bde3b8d314c6.jpg b/public/pd/dpla-90e3ffd4a24de5719990bde3b8d314c6.jpg
new file mode 100644
index 0000000..c51fe22
Binary files /dev/null and b/public/pd/dpla-90e3ffd4a24de5719990bde3b8d314c6.jpg differ
diff --git a/public/pd/dpla-a1b7033d8a652629a71210770151b2e4.jpg b/public/pd/dpla-a1b7033d8a652629a71210770151b2e4.jpg
new file mode 100644
index 0000000..03e4bf2
Binary files /dev/null and b/public/pd/dpla-a1b7033d8a652629a71210770151b2e4.jpg differ
diff --git a/public/pd/dpla-a6b018396a4424de8c3a630f516adb83.jpg b/public/pd/dpla-a6b018396a4424de8c3a630f516adb83.jpg
new file mode 100644
index 0000000..67bc78b
Binary files /dev/null and b/public/pd/dpla-a6b018396a4424de8c3a630f516adb83.jpg differ
diff --git a/public/pd/dpla-f039f35275b4973903264aa5d98a1146.jpg b/public/pd/dpla-f039f35275b4973903264aa5d98a1146.jpg
new file mode 100644
index 0000000..91414e3
Binary files /dev/null and b/public/pd/dpla-f039f35275b4973903264aa5d98a1146.jpg differ
diff --git a/public/pd/dpla-f123156ba4fc6d8663d073e324d04c61.jpg b/public/pd/dpla-f123156ba4fc6d8663d073e324d04c61.jpg
new file mode 100644
index 0000000..bb27f9f
Binary files /dev/null and b/public/pd/dpla-f123156ba4fc6d8663d073e324d04c61.jpg differ
diff --git a/public/pd/met-15662.jpg b/public/pd/met-15662.jpg
new file mode 100644
index 0000000..5c7a12e
Binary files /dev/null and b/public/pd/met-15662.jpg differ
diff --git a/public/pd/met-335913.jpg b/public/pd/met-335913.jpg
new file mode 100644
index 0000000..941d5a5
Binary files /dev/null and b/public/pd/met-335913.jpg differ
diff --git a/public/pd/met-335916.jpg b/public/pd/met-335916.jpg
new file mode 100644
index 0000000..dfb0b23
Binary files /dev/null and b/public/pd/met-335916.jpg differ
diff --git a/public/pd/met-339826.jpg b/public/pd/met-339826.jpg
new file mode 100644
index 0000000..a16e579
Binary files /dev/null and b/public/pd/met-339826.jpg differ
diff --git a/public/pd/met-340110.jpg b/public/pd/met-340110.jpg
new file mode 100644
index 0000000..1cc4f15
Binary files /dev/null and b/public/pd/met-340110.jpg differ
diff --git a/public/pd/met-341322.jpg b/public/pd/met-341322.jpg
new file mode 100644
index 0000000..a50e9d5
Binary files /dev/null and b/public/pd/met-341322.jpg differ
diff --git a/public/pd/met-343561.jpg b/public/pd/met-343561.jpg
new file mode 100644
index 0000000..2e3602a
Binary files /dev/null and b/public/pd/met-343561.jpg differ
diff --git a/public/pd/met-351971.jpg b/public/pd/met-351971.jpg
new file mode 100644
index 0000000..48ac0f4
Binary files /dev/null and b/public/pd/met-351971.jpg differ
diff --git a/public/pd/met-362270.jpg b/public/pd/met-362270.jpg
new file mode 100644
index 0000000..afbe921
Binary files /dev/null and b/public/pd/met-362270.jpg differ
diff --git a/public/pd/met-362271.jpg b/public/pd/met-362271.jpg
new file mode 100644
index 0000000..ee5663f
Binary files /dev/null and b/public/pd/met-362271.jpg differ
diff --git a/public/pd/met-388974.jpg b/public/pd/met-388974.jpg
new file mode 100644
index 0000000..c81b9fa
Binary files /dev/null and b/public/pd/met-388974.jpg differ
diff --git a/public/pd/met-389056.jpg b/public/pd/met-389056.jpg
new file mode 100644
index 0000000..222cc63
Binary files /dev/null and b/public/pd/met-389056.jpg differ
diff --git a/public/pd/met-389085.jpg b/public/pd/met-389085.jpg
new file mode 100644
index 0000000..d1f0b34
Binary files /dev/null and b/public/pd/met-389085.jpg differ
diff --git a/public/pd/met-389090.jpg b/public/pd/met-389090.jpg
new file mode 100644
index 0000000..9b88a90
Binary files /dev/null and b/public/pd/met-389090.jpg differ
diff --git a/public/pd/met-389091.jpg b/public/pd/met-389091.jpg
new file mode 100644
index 0000000..41a5e71
Binary files /dev/null and b/public/pd/met-389091.jpg differ
diff --git a/public/pd/met-389104.jpg b/public/pd/met-389104.jpg
new file mode 100644
index 0000000..8c06672
Binary files /dev/null and b/public/pd/met-389104.jpg differ
diff --git a/public/pd/met-392320.jpg b/public/pd/met-392320.jpg
new file mode 100644
index 0000000..e720ffe
Binary files /dev/null and b/public/pd/met-392320.jpg differ
diff --git a/public/pd/met-392759.jpg b/public/pd/met-392759.jpg
new file mode 100644
index 0000000..67747b3
Binary files /dev/null and b/public/pd/met-392759.jpg differ
diff --git a/public/pd/met-395366.jpg b/public/pd/met-395366.jpg
new file mode 100644
index 0000000..cd1bc39
Binary files /dev/null and b/public/pd/met-395366.jpg differ
diff --git a/public/pd/met-418567.jpg b/public/pd/met-418567.jpg
new file mode 100644
index 0000000..5fdd5a4
Binary files /dev/null and b/public/pd/met-418567.jpg differ
diff --git a/public/pd/met-418570.jpg b/public/pd/met-418570.jpg
new file mode 100644
index 0000000..a7d58ed
Binary files /dev/null and b/public/pd/met-418570.jpg differ
diff --git a/public/pd/met-459504.jpg b/public/pd/met-459504.jpg
new file mode 100644
index 0000000..1d319d4
Binary files /dev/null and b/public/pd/met-459504.jpg differ
diff --git a/public/pd/met-744206.jpg b/public/pd/met-744206.jpg
new file mode 100644
index 0000000..7460730
Binary files /dev/null and b/public/pd/met-744206.jpg differ
diff --git a/public/pd/met-744243.jpg b/public/pd/met-744243.jpg
new file mode 100644
index 0000000..a58d435
Binary files /dev/null and b/public/pd/met-744243.jpg differ
diff --git a/public/pd/met-745548.jpg b/public/pd/met-745548.jpg
new file mode 100644
index 0000000..7cd5a7f
Binary files /dev/null and b/public/pd/met-745548.jpg differ
diff --git a/public/pd/met-819943.jpg b/public/pd/met-819943.jpg
new file mode 100644
index 0000000..01b5334
Binary files /dev/null and b/public/pd/met-819943.jpg differ
diff --git a/public/pd/met-850627.jpg b/public/pd/met-850627.jpg
new file mode 100644
index 0000000..33b4c34
Binary files /dev/null and b/public/pd/met-850627.jpg differ
diff --git a/public/pd/met-850632.jpg b/public/pd/met-850632.jpg
new file mode 100644
index 0000000..968eab3
Binary files /dev/null and b/public/pd/met-850632.jpg differ
diff --git a/public/pd/met-850635.jpg b/public/pd/met-850635.jpg
new file mode 100644
index 0000000..1b6bfe3
Binary files /dev/null and b/public/pd/met-850635.jpg differ
diff --git a/public/pd/met-850636.jpg b/public/pd/met-850636.jpg
new file mode 100644
index 0000000..b3ea20e
Binary files /dev/null and b/public/pd/met-850636.jpg differ
diff --git a/public/pd/met-850639.jpg b/public/pd/met-850639.jpg
new file mode 100644
index 0000000..6c131f0
Binary files /dev/null and b/public/pd/met-850639.jpg differ
diff --git a/public/pd/met-850659.jpg b/public/pd/met-850659.jpg
new file mode 100644
index 0000000..ba1beeb
Binary files /dev/null and b/public/pd/met-850659.jpg differ
diff --git a/public/pd/met-850668.jpg b/public/pd/met-850668.jpg
new file mode 100644
index 0000000..6bdf1f3
Binary files /dev/null and b/public/pd/met-850668.jpg differ
diff --git a/public/pd/met-850669.jpg b/public/pd/met-850669.jpg
new file mode 100644
index 0000000..0609d34
Binary files /dev/null and b/public/pd/met-850669.jpg differ
diff --git a/public/pd/met-850670.jpg b/public/pd/met-850670.jpg
new file mode 100644
index 0000000..15fb1ac
Binary files /dev/null and b/public/pd/met-850670.jpg differ
diff --git a/public/pd/met-850671.jpg b/public/pd/met-850671.jpg
new file mode 100644
index 0000000..5c45a87
Binary files /dev/null and b/public/pd/met-850671.jpg differ
diff --git a/public/pd/met-850673.jpg b/public/pd/met-850673.jpg
new file mode 100644
index 0000000..6d8e503
Binary files /dev/null and b/public/pd/met-850673.jpg differ
diff --git a/public/pd/met-850674.jpg b/public/pd/met-850674.jpg
new file mode 100644
index 0000000..6cb708a
Binary files /dev/null and b/public/pd/met-850674.jpg differ
diff --git a/public/pd/met-850676.jpg b/public/pd/met-850676.jpg
new file mode 100644
index 0000000..1658359
Binary files /dev/null and b/public/pd/met-850676.jpg differ
diff --git a/public/pd/met-850679.jpg b/public/pd/met-850679.jpg
new file mode 100644
index 0000000..4692119
Binary files /dev/null and b/public/pd/met-850679.jpg differ
diff --git a/public/style.css b/public/style.css
index 6f252e1..a2c36aa 100644
--- a/public/style.css
+++ b/public/style.css
@@ -478,3 +478,7 @@ body {
.modal .p24-full { width: 100%; height: auto; display: block; margin: 12px 0; border: 1px solid var(--line); background: #111; }
.modal .p24-panels { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 8px; margin-bottom: 12px; }
.modal .p24-panels img { width: 100%; height: auto; border: 1px solid var(--line); background: #111; }
+
+/* ---- public-domain cartoons gallery ---- */
+.badge.pd { background: var(--badge-doc); }
+.pd .card .thumb img { background: #fff; }
diff --git a/scripts/fetch-pd-cartoons.mjs b/scripts/fetch-pd-cartoons.mjs
new file mode 100644
index 0000000..1808f2e
--- /dev/null
+++ b/scripts/fetch-pd-cartoons.mjs
@@ -0,0 +1,242 @@
+#!/usr/bin/env node
+// Inkwell — public-domain cartoon gallery builder.
+// Replaces the text-only research-records section: pulls cartoons / caricatures / satirical prints that
+// the holding institution itself marks public domain or CC0, downloads a local display copy, and writes
+// data/pd-cartoons.json for /api/pd-cartoons.
+//
+// Sources ($0):
+// - DPLA (libraries, universities, archives) api.dp.la rights === rightsstatements.org NoC-US
+// (key: DPLA_API_KEY from env or ~/Projects/secrets-manager/.env — same resolution as paul-conrad-archive)
+// - Art Institute of Chicago api.artic.edu rights: is_public_domain === true
+// - The Metropolitan Museum collectionapi.metmuseum.org rights: isPublicDomain === true
+// - Cleveland Museum of Art openaccess-api.clevelandart.org rights: share_license_status === 'CC0'
+// An item is kept ONLY when its source's own rights field says public domain / CC0 — never inferred from date.
+//
+// Usage: node scripts/fetch-pd-cartoons.mjs [--per-source 30]
+
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
+const OUT_JSON = path.join(ROOT, 'data/pd-cartoons.json');
+const IMG_DIR = path.join(ROOT, 'public/pd');
+const argIdx = process.argv.indexOf('--per-source');
+const PER_SOURCE = argIdx > -1 ? Number(process.argv[argIdx + 1]) : 30;
+const UA = 'Inkwell/1.0 (private research tool; steve@designerwallcoverings.com)';
+// Museum queries deliberately omit bare "cartoon": in museum catalogs it mostly means a full-scale
+// preparatory design drawing (tapestry/fresco/textile cartoons), not a satirical cartoon.
+const QUERIES = ['political cartoon', 'caricature', 'satire', 'satirical print'];
+// Keep works on paper; drop ceramics, sculpture, textiles, etc. that match "caricature" by subject.
+const PAPER = /print|drawing|lithograph|etching|engraving|woodcut|wood engraving|graphite|ink|charcoal|watercolor|photomechanical|periodical|book/i;
+// Relevance guard: "cartoon" also means a full-scale design drawing (Raphael Cartoons), and "caricature"
+// matches textiles, paintings on ivory, album leaves, etc. Drop those.
+const NOT_CARTOON = /raphael cartoons|cartoon for|\bcotton\b|\bsilk\b|weave|tempera|ivory|ceramic|porcelain|landscape|recto|verso|mezzotint|drypoint|\bpapers:|films, ltd/i;
+// Topical guard for sources whose keyword search is loose (AIC, DPLA): the title or the record's own
+// subject/term tags must say cartoon / caricature / satire.
+const RELEVANT = /cartoon|caricat|satir|puck\b|punch\b|charivari|lampoon|burlesque|parody|humor|comic/i;
+// The naming rule (TK-12230) applies to this gallery too.
+const BANNED = /conrad/i;
+
+const sleep = (ms) => new Promise(r => setTimeout(r, ms));
+
+async function getJson(url) {
+ for (let attempt = 1; attempt <= 3; attempt++) {
+ const res = await fetch(url, { headers: { 'User-Agent': UA, Accept: 'application/json' } });
+ if (res.ok) return res.json();
+ if (attempt === 3 || (res.status < 500 && res.status !== 429)) throw new Error(`HTTP ${res.status} ${url}`);
+ await sleep(1000 * 2 ** attempt);
+ }
+}
+
+async function fromAIC() {
+ const out = [];
+ const fields = 'id,title,artist_title,date_display,date_start,image_id,is_public_domain,classification_title,medium_display,credit_line,subject_titles,term_titles,category_titles';
+ for (const q of QUERIES) {
+ const u = new URL('https://api.artic.edu/api/v1/artworks/search');
+ u.searchParams.set('q', q);
+ u.searchParams.set('query[term][is_public_domain]', 'true');
+ u.searchParams.set('limit', '40');
+ u.searchParams.set('fields', fields);
+ const d = await getJson(u);
+ for (const r of d.data || []) {
+ if (r.is_public_domain !== true || !r.image_id) continue;
+ if (!PAPER.test(`${r.classification_title} ${r.medium_display}`)) continue;
+ if (NOT_CARTOON.test(`${r.title} ${r.medium_display}`)) continue;
+ if (!RELEVANT.test([r.title, ...(r.subject_titles || []), ...(r.term_titles || []), ...(r.category_titles || [])].join(' '))) continue;
+ out.push({
+ id: `aic-${r.id}`, source: 'Art Institute of Chicago', source_key: 'aic',
+ title: r.title, artist: r.artist_title || 'Unknown artist', date: r.date_display, year: r.date_start || null,
+ medium: r.medium_display || r.classification_title || null,
+ image_remote: `https://www.artic.edu/iiif/2/${r.image_id}/full/843,/0/default.jpg`,
+ source_url: `https://www.artic.edu/artworks/${r.id}`,
+ rights: 'Public domain (Art Institute of Chicago open access, CC0)', credit: r.credit_line || null,
+ });
+ }
+ await sleep(300);
+ }
+ return out;
+}
+
+async function fromMet() {
+ const out = [];
+ const seen = new Set();
+ for (const q of QUERIES) {
+ const u = `https://collectionapi.metmuseum.org/public/collection/v1/search?hasImages=true&q=${encodeURIComponent(q)}`;
+ let d;
+ // The Met's edge intermittently 403s bursts; one blocked query must not drop the whole source.
+ try { d = await getJson(u); } catch (e) { console.warn('met query skipped:', q, e.message); await sleep(2000); continue; }
+ for (const id of (d.objectIDs || []).slice(0, 40)) {
+ if (seen.has(id)) continue;
+ seen.add(id);
+ let r;
+ try { r = await getJson(`https://collectionapi.metmuseum.org/public/collection/v1/objects/${id}`); } catch { continue; }
+ await sleep(120); // Met asks for <= 80 req/s; stay far under it
+ if (r.isPublicDomain !== true || !r.primaryImageSmall) continue;
+ if (!PAPER.test(`${r.classification} ${r.medium}`)) continue;
+ if (NOT_CARTOON.test(`${r.title} ${r.medium}`)) continue;
+ out.push({
+ id: `met-${r.objectID}`, source: 'The Metropolitan Museum of Art', source_key: 'met',
+ title: r.title, artist: r.artistDisplayName || 'Unknown artist', date: r.objectDate, year: r.objectBeginDate || null,
+ medium: r.medium || r.classification || null,
+ image_remote: r.primaryImageSmall,
+ source_url: r.objectURL,
+ rights: 'Public domain (The Met Open Access, CC0)', credit: r.creditLine || null,
+ });
+ }
+ }
+ return out;
+}
+
+async function fromCleveland() {
+ const out = [];
+ for (const q of QUERIES) {
+ const u = `https://openaccess-api.clevelandart.org/api/artworks/?q=${encodeURIComponent(q)}&cc0=1&has_image=1&limit=40`;
+ const d = await getJson(u);
+ for (const r of d.data || []) {
+ const img = r.images && (r.images.web || r.images.print);
+ if (r.share_license_status !== 'CC0' || !img) continue;
+ if (!/^(Print|Drawing)$/.test(r.type) || NOT_CARTOON.test(`${r.title} ${r.technique}`)) continue;
+ out.push({
+ id: `cma-${r.id}`, source: 'Cleveland Museum of Art', source_key: 'cma',
+ title: r.title, artist: (r.creators && r.creators[0] && r.creators[0].description) || 'Unknown artist',
+ date: r.creation_date, year: r.creation_date_earliest || null, medium: r.technique || r.type || null,
+ image_remote: img.url,
+ source_url: r.url,
+ rights: 'Public domain (Cleveland Museum of Art Open Access, CC0)', credit: r.creditline || null,
+ });
+ }
+ await sleep(300);
+ }
+ return out;
+}
+
+function dplaKey() {
+ if (process.env.DPLA_API_KEY) return process.env.DPLA_API_KEY;
+ try {
+ const env = fs.readFileSync(path.join(process.env.HOME, 'Projects/secrets-manager/.env'), 'utf8');
+ const m = env.match(/^DPLA_API_KEY=["']?([^"'\n]+)/m);
+ return m ? m[1].trim() : null;
+ } catch { return null; }
+}
+
+const NOC_US = 'http://rightsstatements.org/vocab/NoC-US/1.0/';
+const PER_PROVIDER = 8; // keep the gallery from being one archive's run of near-identical scans
+
+async function fromDPLA() {
+ const key = dplaKey();
+ if (!key) throw new Error('DPLA_API_KEY not set — skipped');
+ const out = [];
+ const perProvider = new Map();
+ for (const q of ['political cartoon', 'editorial cartoon', 'cartoon']) {
+ for (let page = 1; page <= 2; page++) {
+ const u = new URL('https://api.dp.la/v2/items');
+ u.searchParams.set('api_key', key);
+ u.searchParams.set('q', q);
+ u.searchParams.set('rights', `"${NOC_US}"`);
+ u.searchParams.set('page_size', '100');
+ u.searchParams.set('page', String(page));
+ const d = await getJson(u);
+ for (const r of d.docs || []) {
+ const sr = r.sourceResource || {};
+ if (r.rights !== NOC_US || !r.object) continue; // rights re-checked on the record, not just the query
+ const provider = (r.dataProvider && r.dataProvider.name) || String(r.dataProvider || 'Unknown');
+ const n = perProvider.get(provider) || 0;
+ if (n >= PER_PROVIDER) continue;
+ const title = [].concat(sr.title || 'Untitled')[0];
+ if (NOT_CARTOON.test(title)) continue;
+ const subjects = [].concat(sr.subject || []).map(x => (x && x.name) || '').join(' ');
+ if (!RELEVANT.test(`${title} ${subjects}`)) continue;
+ const date = [].concat(sr.date || [])[0];
+ const display = date && (date.displayDate || date.begin) || null;
+ const creator = [].concat(sr.creator || [])[0];
+ perProvider.set(provider, n + 1);
+ out.push({
+ id: `dpla-${r.id}`, source: provider, source_key: 'dpla', via: 'Digital Public Library of America',
+ title, artist: creator || 'Unknown artist', date: display,
+ year: display && /\d{4}/.test(display) ? Number(display.match(/\d{4}/)[0]) : null,
+ medium: [].concat(sr.format || [])[0] || null,
+ image_remote: r.object,
+ source_url: r.isShownAt || `https://dp.la/item/${r.id}`,
+ rights: 'No Copyright – United States (rightsstatements.org NoC-US)', credit: provider,
+ });
+ }
+ await sleep(300);
+ }
+ }
+ return out;
+}
+
+async function download(item) {
+ const file = `${item.id}.jpg`;
+ const dest = path.join(IMG_DIR, file);
+ if (!fs.existsSync(dest)) {
+ const res = await fetch(item.image_remote, { headers: { 'User-Agent': UA } });
+ if (!res.ok) throw new Error(`image HTTP ${res.status}`);
+ const buf = Buffer.from(await res.arrayBuffer());
+ if (buf.length < 2000) throw new Error('image too small');
+ fs.writeFileSync(dest, buf);
+ }
+ return `/pd/${file}`;
+}
+
+// Same work digitized by several libraries (DPLA) arrives under different ids — dedupe on title+date too.
+function dedupe(list) {
+ const seen = new Set();
+ return list.filter(i => {
+ const k1 = i.id;
+ const k2 = `${String(i.title).toLowerCase().replace(/\W+/g, ' ').trim()}|${i.year || i.date || ''}`;
+ if (seen.has(k1) || seen.has(k2)) return false;
+ seen.add(k1); seen.add(k2);
+ return true;
+ });
+}
+
+async function main() {
+ fs.mkdirSync(IMG_DIR, { recursive: true });
+ const sources = { dpla: fromDPLA, aic: fromAIC, met: fromMet, cma: fromCleveland };
+ const items = [];
+ const report = {};
+ for (const [key, fn] of Object.entries(sources)) {
+ try {
+ const got = dedupe(await fn()).filter(i => !BANNED.test(JSON.stringify(i))).slice(0, PER_SOURCE);
+ let ok = 0;
+ for (const it of got) {
+ try { it.image = await download(it); items.push(it); ok++; } catch (e) { /* skip unreachable image */ }
+ }
+ report[key] = { candidates: got.length, kept: ok };
+ } catch (e) {
+ report[key] = { error: e.message };
+ }
+ console.log(key, JSON.stringify(report[key]));
+ }
+ if (!items.length) {
+ console.error('No public-domain items fetched from any source; leaving existing data untouched.');
+ process.exit(1);
+ }
+ const doc = { generated_at: new Date().toISOString(), sources: report, count: items.length, items };
+ fs.writeFileSync(OUT_JSON, JSON.stringify(doc, null, 2));
+ console.log(`wrote ${items.length} items -> ${path.relative(ROOT, OUT_JSON)}`);
+}
+
+main().catch(e => { console.error(e); process.exit(1); });
diff --git a/scripts/verify-inkwell.cjs b/scripts/verify-inkwell.cjs
index baa3c5b..213a2af 100644
--- a/scripts/verify-inkwell.cjs
+++ b/scripts/verify-inkwell.cjs
@@ -22,12 +22,17 @@ const check = (name, ok, detail = '') => { results.push({ name, ok: !!ok, detail
const expected = p24.items.length;
const expectedImgs = p24.items.reduce((n, i) => n + 1 + (i.panels || []).length, 0);
check('/api/p24 has items', expected > 0, `${p24.counts.photo} photos + ${p24.counts.cartoon} cartoons = ${expected}; ${expectedImgs} images incl. panels`);
- for (const ep of ['/api/p24', '/api/cartoons', '/health', '/', '/app.js', '/p24.js', '/style.css']) {
+ for (const ep of ['/api/p24', '/api/pd-cartoons', '/health', '/', '/app.js', '/p24.js', '/style.css']) {
const r = await fetch(BASE + ep);
const body = await r.text();
check(`${ep} 200 and name-free`, r.status === 200 && !NAME.test(body), `status ${r.status}`);
}
+ const gone = await fetch(BASE + '/api/cartoons');
+ check('research-records endpoint removed (/api/cartoons 404)', gone.status === 404, `status ${gone.status}`);
+ const pd = await (await fetch(BASE + '/api/pd-cartoons')).json();
+ check('/api/pd-cartoons has items, each with rights + local image + http source', pd.items.length > 0 && pd.items.every(i => i.rights && /^\/pd\//.test(i.image) && /^https?:/.test(i.source_url)), `${pd.items.length} items`);
+
const browser = await chromium.launch();
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1000 } });
const page = await ctx.newPage();
@@ -96,12 +101,32 @@ const check = (name, ok, detail = '') => { results.push({ name, ok: !!ok, detail
await page.screenshot({ path: path.join(SHOTS, 'inkwell-modal.png') });
await page.keyboard.press('Escape');
- // Name-free page text (whole document, incl. research section + bio modal)
+ // Name-free page text (whole document)
const text = await page.evaluate(() => document.documentElement.innerText + ' ' + document.title);
check('page text contains no name', !NAME.test(text));
- await page.click('#section-links button[data-section="bio"]');
- const bioText = await page.$eval('#modal-body', el => el.innerText);
- check('bio modal contains no name', !NAME.test(bioText), bioText.split('\n')[1]);
+ // Public-domain gallery (replaced the research-records section)
+ check('research-records section gone', !/Research records|image not displayed/i.test(text));
+ await page.waitForSelector('#grid .card');
+ await page.evaluate(() => document.querySelectorAll('#grid img').forEach(i => { i.loading = 'eager'; }));
+ await page.waitForFunction(() => [...document.querySelectorAll('#grid img')].every(i => i.complete), null, { timeout: 60000 });
+ const pdImgs = await page.evaluate(() => [...document.querySelectorAll('#grid img')].map(i => i.naturalWidth));
+ check('every public-domain image rendered', pdImgs.length === pd.items.length && pdImgs.every(w => w > 0), `${pdImgs.filter(w => w > 0).length}/${pd.items.length}`);
+ const nMuseum = pd.items.filter(i => i.source_key !== 'dpla').length;
+ await page.click('#section-links button[data-kind="museum"]');
+ check('Museums nav filter', await page.locator('#grid .card').count() === nMuseum, `${nMuseum}`);
+ await page.click('#section-links button[data-kind="library"]');
+ check('Libraries & universities nav filter', await page.locator('#grid .card').count() === pd.items.length - nMuseum, `${pd.items.length - nMuseum}`);
+ await page.locator('#pd').screenshot({ path: path.join(SHOTS, 'inkwell-pd-libraries.png') });
+ await page.click('#section-links button[data-kind="all"]');
+ await page.locator('#grid .card').first().click();
+ await page.waitForSelector('.modal .modal-img');
+ const modalText = await page.$eval('#modal-body', el => el.innerText);
+ check('PD modal shows rights + source record', /Rights/.test(modalText) && /(Public domain|No Copyright)/.test(modalText) && /Source record/.test(modalText));
+ await page.waitForTimeout(400);
+ await page.screenshot({ path: path.join(SHOTS, 'inkwell-pd-modal.png') });
+ await page.keyboard.press('Escape');
+ await page.locator('#pd').scrollIntoViewIfNeeded();
+ await page.screenshot({ path: path.join(SHOTS, 'inkwell-pd.png') });
check('0 console errors', errors.length === 0, errors.slice(0, 3).join(' | '));
// Reset persisted prefs so the running app opens on defaults
diff --git a/server.js b/server.js
index dda6037..ab25a8a 100644
--- a/server.js
+++ b/server.js
@@ -1,11 +1,10 @@
// Inkwell — Editorial Cartoon Archive. Private local reference tool (no auth, not deployed).
-// Serves public/, the research records (data/cartoons.json) and the imported P24 art (data/p24.json).
+// Serves public/, the public-domain cartoon gallery (data/pd-cartoons.json) and the imported P24 art (data/p24.json).
+// data/cartoons.json (research records) is kept on disk as source material but is no longer served.
//
// TK-12230 naming rule: the served UI and every API response must never contain the name of the
-// real cartoonist the research records document. data/cartoons.json is kept verbatim as the
-// research source of truth; neutralizeRecords() scrubs it on the way OUT (text -> "the artist",
-// URLs/paths that embed the name are withheld), and sendClean() refuses to send any response
-// that still contains the name.
+// real cartoonist the (no longer served) research records document; sendClean() refuses to send
+// any response that still contains the name.
const express = require('express');
const path = require('path');
@@ -25,33 +24,6 @@ function neutralText(s) {
.replace(/conrad/gi, 'artist');
}
-function neutralize(value, key = '') {
- if (typeof value === 'string') {
- if (!BANNED.test(value)) return value;
- // A URL or file path that embeds the name cannot be reworded without breaking it: withhold it.
- if (/(url|image|href|src)$/i.test(key) || /^(https?:|\/|images\/|research\/)/i.test(value)) return null;
- return neutralText(value);
- }
- if (Array.isArray(value)) return value.map(v => neutralize(v, key));
- if (value && typeof value === 'object') {
- const out = {};
- for (const [k, v] of Object.entries(value)) out[k] = neutralize(v, k);
- return out;
- }
- return value;
-}
-
-function neutralizeRecords(raw) {
- const data = neutralize(raw);
- if (data.bio) data.bio.name = 'The artist';
- // Records whose image path was withheld still need the UI's "image not displayed" state.
- for (const [i, r] of (data.records || []).entries()) {
- const src = raw.records[i];
- if ((src.image || src.image_url) && !r.image && !r.image_url) r.image = 'withheld';
- }
- return data;
-}
-
function sendClean(res, obj) {
const body = JSON.stringify(obj);
if (BANNED.test(body)) return res.status(500).json({ error: 'response blocked: naming rule (TK-12230)' });
@@ -64,11 +36,13 @@ function readJson(rel) {
app.use(express.static(path.join(__dirname, 'public')));
-app.get('/api/cartoons', (req, res) => {
+// Public-domain cartoons from museum / library / university open-access APIs
+// (built by scripts/fetch-pd-cartoons.mjs). Replaces the text-only research-records section.
+app.get('/api/pd-cartoons', (req, res) => {
try {
- sendClean(res, neutralizeRecords(readJson('data/cartoons.json')));
+ sendClean(res, readJson('data/pd-cartoons.json'));
} catch (err) {
- res.status(500).json({ error: 'could not read research records', detail: neutralText(err.message) });
+ res.status(500).json({ error: 'could not read data/pd-cartoons.json', detail: neutralText(err.message) });
}
});
← 17318de TK-12230: P24 Art gallery — all 68 photos + cartoons inline
·
back to Paul Conrad Cartoons Shadowman
·
TK-12241: Shadow Man gallery + Arena Ideas curation in Inkwe d329174 →