Improve timeline UX and add catalog restore scripts for paintings and portraits.

Load the home-page catalog once with a lightweight artists API, batch pan/zoom updates per frame, use dynamic year labels, and speed up movement-flow zoom. Add sync-image-paths and fetch-artist-images plus docs for the post-seed pipeline.
This commit is contained in:
Danila Khodjaef
2026-07-03 18:33:16 +03:00
parent 7f26696328
commit 02d238b043
26 changed files with 865 additions and 195 deletions
+21 -8
View File
@@ -55,7 +55,7 @@ Or step by step:
```bash
npm run migrate # db/schema.sql + db/migrate-*.sql via server/migrate.js
npm run seed # eras, movements, artists, paintings, influences
npm run seed # eras, movements, artists, flagship paintings (one per artist)
```
`npm run migrate` is safe to re-run on existing databases (uses `IF NOT EXISTS` / `ADD COLUMN IF NOT EXISTS`).
@@ -67,6 +67,8 @@ If migration fails with permission errors, grant schema rights to the app user f
After a fresh seed, run these to match a fully populated local install:
```bash
npm run sync-image-paths # import paintings from data/images/paintings/ (clone with image files)
npm run fetch-artist-images # link local portraits or download from Wikipedia
npm run fetch-artist-bios # bio_short / bio_full from Wikipedia
npm run expand-catalog # famous works for artists below MIN_PAINTINGS
npm run update-influences # painting influence graph for detail view + hall exits
@@ -79,6 +81,8 @@ npm run fetch-images -- --limit=50 --max-wait=120 # same batch size, longer look
cd client && npm run build && cd ..
```
**Order matters:** `sync-image-paths` should run when the repo already contains painting files under `data/images/paintings/` but the database only has one flagship work per artist (typical after `npm run setup` on a clone). `update-influences` is required for *Influenced By* / *Influenced* panels and golden lamps in the 3D hall — seed does not insert influence edges.
Image fetch can take hours if you run it for the entire catalog. The first line of each run reports **`Missing local files: N`**. Use **`npm run fetch-images -- --limit=N`** for random batches (10s per painting by default), **`--artist="…"`** for one artist in catalog order, or on-demand resolution when viewing a painting in the detail view.
## Run
@@ -139,9 +143,9 @@ Or use the systemd unit in [`deploy/gallery.service`](../deploy/gallery.service)
Point `gallery.mysuperlab.netcraze.pro` at the host running the app. Example nginx config: [`deploy/nginx-gallery.conf`](../deploy/nginx-gallery.conf).
**Development (default in repo):** nginx forwards to **Vite on `127.0.0.1:5173`**. Run both `npm run dev:server` (API on `3520`) and `npm run dev:client` (`5173`). Vite proxies `/api` and `/images` to the API.
**Development (default in repo):** nginx forwards to **Vite on `127.0.0.1:5173`**. Run both `npm run dev:server` (API on `3520`) and `npm run dev:client` (`5173`). Vite proxies `/api` and `/images` to the API. If either process stops, the public hostname may return **503** (reverse proxy cannot reach upstream).
**Production (built SPA):** change nginx `proxy_pass` to `http://127.0.0.1:3520` after `npm run build` and `npm run start` — Node serves `client/dist` and the API on one port.
**Production (built SPA):** change nginx `proxy_pass` to `http://127.0.0.1:3520` after `npm run build` and `npm run start` — Node serves `client/dist` and the API on one port. Prefer the systemd unit in [`deploy/gallery.service`](../deploy/gallery.service) so the process restarts automatically.
Keep `TRUST_PROXY=true` in `.env` so Express sees the correct client IP and scheme.
@@ -168,8 +172,10 @@ Allow inbound **TCP 3520** on the gallery host if clients reach it directly on t
| `npm run regenerate-thumbnails` | `scripts/regenerate-thumbnails.js` | Rebuild all thumbs from full local files |
| `npm run audit-painting-images` | `scripts/audit-painting-images.js` | List thumb/full aspect-ratio mismatches |
| `npm run migrate:thumbnails` | `db/migrate-thumbnails.sql` | Add thumbnail columns |
| `npm run fetch-artist-images` | `scripts/fetch-artist-images.js` | Backfill portrait files *(if present)* |
| `npm run sync-image-paths` | `scripts/sync-image-paths.js` | Align DB paths with disk *(if present)* |
| `npm run fetch-artist-images` | `scripts/fetch-artist-images.js` | Download portraits or link existing files under `data/images/portraits/` |
| `npm run fetch-artist-images -- --force` | ↑ | Re-fetch even when `portrait_path` is set |
| `npm run sync-image-paths` | `scripts/sync-image-paths.js` | Link `image_path` / `thumbnail_path` and import missing painting rows from disk |
| `npm run sync-image-paths -- --dry-run` | ↑ | Report only, no DB writes |
| `npm run migrate:influence-sources` | `scripts/migrate-influence-sources.js` | Create `painting_influence_sources` + backfill legacy edges |
| `npm run migrate:checkup-flags` | `scripts/migrate-checkup-flags.js` | Add `checkup_checked` / `checkup_fixed` on `paintings` |
| `npm run migrate:artist-checkup-flags` | `scripts/migrate-artist-checkup-flags.js` | Add `checkup_checked` / `checkup_fixed` on `artists` (bio debug) |
@@ -192,7 +198,10 @@ Allow inbound **TCP 3520** on the gallery host if clients reach it directly on t
These are checked in and maintained:
- `seed-wikipedia.js`, `seed-catalog-data.js` — initial catalog (`npm run seed`)
- `image-fetcher.js` — Wikimedia / museum image resolution
- `fetch-artist-images.js` — artist portrait download / disk linking
- `sync-image-paths.js` — import paintings and align paths from `data/images/paintings/`
- `fetch-artist-bios.js` — artist biographies
- `expand-paintings.js` + `famous-paintings-data.js` — catalog expansion
- `update-influences.js` + `art-influences-data.js` — influence graph (paintings, artists, movements)
@@ -207,8 +216,6 @@ These are checked in and maintained:
- `migrate-painting-annotations.js`, `update-painting-annotations.js`, `painting-annotations-data.js` — art-history notes on painting detail
- `regenerate-thumbnails.js`, `audit-painting-images.js`
These are referenced in `package.json` but may need to be restored from git history if missing locally: `fetch-artist-images.js`, `sync-image-paths.js`.
See [data-and-images.md](data-and-images.md) for pipeline details and override maps.
## Remote repository
@@ -226,9 +233,15 @@ After clone: copy `.env.example` → `.env`, install dependencies, run `npm run
| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| Empty timeline | DB not seeded | `npm run seed` |
| 503 on public URL | Vite or API not running behind nginx | Start `npm run dev:server` + `npm run dev:client`, or switch nginx to production `:3520` |
| 500 on all `/api/*` | Wrong `.env` or Postgres down | Check connection, logs |
| “Biographical information not yet available” | Bios not fetched | `npm run fetch-artist-bios` |
| Artist hall has only 12 paintings | Catalog not expanded | `npm run expand-catalog`; extend `famous-paintings-data.js` |
| Placeholder portraits on timeline | `portrait_path` not set | `npm run fetch-artist-images` |
| Artist hall has only 12 paintings | DB not expanded / disk not imported | `npm run sync-image-paths` then `npm run expand-catalog`; extend `famous-paintings-data.js` |
| Movement flow shows “Loading art history…” repeatedly | Stale client refetching on every pan/zoom | Pull latest client; timeline loads catalog once — hard-refresh |
| Movement flow slow on first load | Large artist payload | Client uses `GET /api/artists?timeline=1` (no full bios); rebuild client |
| Movement flow zoom sluggish / dead over portraits | Stale client build | Rebuild client — wheel uses capture listener + interaction-mode rendering; hard-refresh |
| Timeline year labels overlap when zoomed out | Stale client | Rebuild client — `chooseTimelineTickInterval()` adapts step to span and bar width |
| Black frames / canvas covers in 3D gallery | No local image for painting | `npm run fetch-images -- --limit=50` or `--artist="…"`; then `POST …/preload-images` |
| Many `⏱ timeout` lines in fetch batch | Default 10s cap too short for hard works | `--max-wait=120` or raise `FETCH_MAX_WAIT_SEC` |
| White/grey flicker on frames | Texture loading or z-fighting with wall | Rebuild client (`cd client && npm run build`); ensure latest `VirtualGallery.tsx` |