Art history suffers from a fragmentation problem that has nothing to do with gaps in scholarship. The knowledge exists. The Metropolitan Museum has published its entire collection through an open API. The Rijksmuseum, the Getty, the Tate, and a dozen other major institutions have done the same. Wikipedia covers every significant movement and figure in remarkable depth. Wikidata structures relationships across all of it. The data is out there. What's missing is a layer that pulls it together and makes the connections navigable.
That's what I wanted to build: not a catalog or a reference site, but something closer to a research environment. A place where you can look at all of Impressionism's characteristic colors as a data visualization, follow an influence edge from Courbet to Manet, and understand what was happening in the world when a movement emerged or collapsed. The relationships are what explain art history. The chronology alone doesn't.
Named after Ellsworth Kelly
The project takes its name from Ellsworth Kelly because his work is a useful design constraint. Dark canvas. Color used to carry meaning, never as decoration. Nothing in the frame that doesn't do work. That became the design brief: Wikipedia density, FiveThirtyEight rigor, no visual noise.
The interface runs on a dark background with movement accent colors used sparingly, always pulled from real palette data rather than chosen aesthetically. Typography is neutral and hierarchical. The data is the thing.
The data layer
Ellsworth aggregates from thirteen museum collections and two major knowledge APIs. The museum sources are the Metropolitan Museum of Art, the Art Institute of Chicago, the Rijksmuseum, the J. Paul Getty Museum, the Tate, the National Gallery of Art, the Cleveland Museum of Art, the Library of Congress, the Smithsonian Institution, the Harvard Art Museums, the Victoria and Albert Museum, the Museum of Modern Art, and the Princeton University Art Museum. The knowledge layer runs on Wikipedia and Wikidata. Narrative content is generated by Claude.
Every one of these sources has different data structures, different levels of detail, and different conventions for how they describe the same things. A Rijksmuseum record and a MoMA record for a work from the same period might agree on the title and date while differing on movement attribution, nationality encoding, and how they handle medium description. The normalization work is substantial.
The core database is PostgreSQL. Collections data comes in through ingestion jobs that hit each museum API, parse the response into a normalized schema, and write to a staging table before the data gets validated and merged. Duplicate detection runs on a combination of artist name, birth/death year, and work title. Artworks are associated with movements through a junction table that carries a confidence weight, since some attributions are clean and others are ambiguous.
Redis sits in front of all Claude-generated content. Every narrative profile, every movement summary, every style analysis is cached and keyed to a combination of the subject ID and the prompt version. Updating the voice or tone of a profile means bumping the prompt version number, which invalidates only the content generated with the old prompt. You don't have to regenerate everything from scratch every time you want to refine the writing.
PostgreSQL for the primary data store, Redis for AI-generated content caching keyed to prompt version, Next.js 15 for the frontend, D3 for the network and timeline visualizations. Museum data ingests through per-institution API clients that normalize to a shared schema. Claude handles all editorial content through a versioned prompt system.
The intelligence layer
Claude's role in Ellsworth is editorial, not retrieval. The museum APIs and Wikidata provide the facts: dates, locations, artists, attributions, relationships. Claude turns those facts into prose that explains what a movement was reacting against, what it made possible, how it felt from the inside.
The prompts are carefully structured to avoid the kind of neutral, encyclopedic tone that you'd get from a summary of Wikipedia. Each movement profile includes a brief on the historical context, the key figures and their specific contributions, the movement's internal tensions and factions, and its downstream influence. The output reads more like a good piece of arts journalism than a dictionary entry.
Prompt versioning is how this stays maintainable at scale. Every output is stored with a prompt_version field alongside the content. When I refine the voice, add new instructions, or adjust the structure, I bump the version. Cache lookups check the version before returning cached content, so only changed-prompt content gets regenerated. For a database of this size, that distinction matters.








