Covers architecture, setup, database schema, API reference, and image pipeline; link from README. Co-authored-by: Cursor <cursoragent@cursor.com>
77 lines
3.3 KiB
Markdown
77 lines
3.3 KiB
Markdown
# Art Gallery — data and images
|
||
|
||
How catalog content and artwork files enter the system.
|
||
|
||
## Principles
|
||
|
||
1. **No runtime hot-linking** — the UI reads from `/images/…` (local disk). External URLs are used only during ingest.
|
||
2. **No AI-generated art or text** — biographies and descriptions come from Wikipedia; influence notes from curated art-history sources.
|
||
3. **Local copies** — every displayed image should exist under `data/images/` after seeding or fetch.
|
||
|
||
## Directory layout
|
||
|
||
```text
|
||
data/images/
|
||
├── portraits/ # Artist headshots
|
||
│ └── Claude_Monet.jpg
|
||
└── paintings/
|
||
├── Claude_Monet_Water_Lilies.jpg
|
||
└── thumbs/
|
||
└── Claude_Monet_Water_Lilies_thumb.jpg
|
||
```
|
||
|
||
File names are sanitised `{Artist}_{Title}.{ext}`. The image service can rediscover files on disk even when DB paths are empty (`server/image-service.js` → `syncPaintingFromDisk`).
|
||
|
||
## Seeding pipeline
|
||
|
||
`npm run seed` runs `scripts/seed-wikipedia.js`, which:
|
||
|
||
1. Inserts **historical eras** and **art movements** (curated date ranges and colours).
|
||
2. For each curated **artist**:
|
||
- Fetches Wikipedia intro text for `bio_short` / `bio_full`.
|
||
- Downloads a Commons portrait into `portraits/`.
|
||
- Creates **artist periods** and **paintings**.
|
||
- Downloads painting images into `paintings/`.
|
||
3. Writes **painting_influences** edges from curated scholarship references.
|
||
|
||
Artists are grouped by movement and century; the seed list targets at most ~100 artists per century.
|
||
|
||
## On-demand image resolution
|
||
|
||
When a painting has no local file, `GET /api/paintings/:id/image` triggers `ensurePaintingImages()`:
|
||
|
||
1. Check DB paths → verify file on disk.
|
||
2. Scan disk by `{artist}_{title}` pattern.
|
||
3. If still missing and `wikipedia_title` is set, call `scripts/image-fetcher.js`:
|
||
- Wikidata → Wikimedia Commons → Wikipedia page image
|
||
- Fallbacks: Met Museum, Art Institute of Chicago, Rijksmuseum APIs
|
||
4. Save full + thumbnail, update DB, serve file.
|
||
|
||
Requests are deduplicated (`inflight` map) and timeout after 15 seconds. A 2.5 s delay between external requests reduces rate-limit risk.
|
||
|
||
## Preload before 3D gallery
|
||
|
||
`POST /api/artists/:id/preload-images` runs **local-only** linking — no network. Call this when entering an artist’s 3D hall so textures use files already on disk.
|
||
|
||
The 3D scene uses `galleryImageUrl()`, which never hits the on-demand API (remote latency breaks WebGL texture loading).
|
||
|
||
## Placeholders
|
||
|
||
When no image is available:
|
||
|
||
- `/placeholder-portrait.svg` — timeline / movement band portraits
|
||
- `/placeholder-art.svg` — paintings in lists and detail view
|
||
|
||
These live in `client/public/` (and `client/dist/` after build).
|
||
|
||
## Adding new artists manually
|
||
|
||
1. Insert rows into `artists`, `artist_periods`, `paintings` (or extend the `ARTISTS` array in the seed script).
|
||
2. Place image files under `data/images/` using the naming convention.
|
||
3. Run `npm run sync-image-paths` if that script is available, or rely on preload / on-demand sync.
|
||
4. Add influence rows to `painting_influences` with citation fields where possible.
|
||
|
||
## Image fetcher overrides
|
||
|
||
`scripts/image-fetcher.js` includes hand-maintained overrides for ambiguous Wikipedia titles and direct URLs (e.g. works whose Commons name does not match the article title). Extend `PAINTING_WIKI_OVERRIDES` and `DIRECT_IMAGE_OVERRIDES` when automated resolution fails.
|