Files
Art-gallery/Documentation/basics.md
T
Danila KhodjaefandCursor df29848d89 Add movement gallery wings with period interiors and expand timeline features.
Movement galleries split large catalogs into chronological wings (~55 works), use era-themed 3D interiors with side-wall windows, wing navigator on the back exit, and front archways between wings. Also adds painting annotations, timeline event guides, portrait hover highlights, and documentation/API updates.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:54:19 +03:00

22 KiB
Raw Blame History

Art Gallery — architecture basics

Interactive virtual museum spanning art history: zoomable timeline with event guides, branching movement flow, 3D gallery halls, painting influence graphs, and art-history annotations on detail pages. See README.md for quick start.

Concept

The app is organised as a drill-down hierarchy:

  1. Timeline — historical eras (Ancient → Contemporary) with definite or fuzzy date boundaries.
  2. Movement flow — art movements as curved SVG streams on the same year axis; documented predecessor→successor branches; portrait thumbnails placed along each stream.
  3. 3D gallery — one personal hall per artist or a movement gallery (click a movement name on the flow diagram): period-themed interiors, chronological wings of up to ~55 works, side-wall hang only.
  4. Painting detail — full work in the centre, Influenced By on the left, Influenced on the right (paintings, artists, or movements), optional art-history notes with image markers, prev/next catalog browsing, optional fullscreen, link to artist biography.
  5. Artist biography — portrait, lifespan, movement, and Wikipedia-sourced intro text (bio_short / bio_full). With debug mode on, the same image-audit panel as painting detail (portrait search, Checked / Fix it / More / Clear / Upload).

All artwork images are stored locally under data/images/ — the UI never hot-links to Wikipedia or Commons at runtime (except optional on-demand fetch when a file is missing).

Stack

Layer Choice Role
API Node.js + Express 5 REST API, static image serving, optional SPA hosting from client/dist
Database PostgreSQL Eras, movements, artists, paintings, influence edges
Frontend React 19 + Vite 8 SPA routing and UI
3D Three.js via @react-three/fiber, @react-three/drei Virtual gallery navigation
Data ingestion Node scripts Wikipedia summaries, Commons images, curated influence data

Repository layout

Gallery/
├── server/              # Express API, DB pool, image service
├── client/              # React/Vite frontend
│   ├── src/             # Source (components, pages, 3D scene)
│   │   ├── components/VirtualGallery.tsx  # 3D hall (artist + movement modes)
│   │   ├── components/GalleryWindows.tsx  # Side-wall daylight windows (movement)
│   │   ├── components/HallPassage.tsx     # Open archway between movement wings
│   │   ├── components/MovementHallDetails.tsx  # Period architectural details
│   │   ├── data/movement-interior-styles.ts    # Per-movement interior themes
│   │   ├── utils/movementHallLayout.ts         # Wing split + window gap placement
│   │   ├── utils/galleryProceduralTextures.ts  # Hi-res wall/floor textures
│   │   ├── components/PaintingDetail.tsx    # Detail view + debug panel
│   │   ├── components/ArtistBio.tsx         # Biography + portrait debug panel
│   │   ├── components/DebugSearchResultsModal.tsx  # “More” search picker (20 results)
│   │   ├── components/Timeline.tsx          # Era bar, year ticks, event markers
│   │   ├── components/TimelineEventGuides.tsx  # Event vertical guides into movement flow
│   │   ├── components/MovementBands.tsx   # Movement flow (SVG streams + branches)
│   │   ├── components/PaintingAnnotations.tsx  # Art-history notes on painting detail
│   │   ├── pages/CheckupPage.tsx            # Image audit table
│   │   ├── data/historical-events.ts     # Timeline event markers (UI)
│   │   ├── data/movement-lineage.ts       # Curated movement predecessor links (UI)
│   │   ├── utils/parquetFloorTexture.ts     # Procedural parquet floor
│   │   ├── utils/debugMode.ts               # Debug mode localStorage toggle
│   │   └── utils/timelineView.ts          # Shared zoom/pan math for timeline + movements
│   └── dist/            # Production build (served by API when present)
├── scripts/             # Seed, bios, catalog expansion, image fetch, checkup tools
│   ├── fetch-artist-bios.js
│   ├── expand-paintings.js
│   ├── famous-paintings-data.js
│   ├── fetch-missing-images.js
│   ├── find-duplicate-paintings.js
│   └── image-fetcher.js
├── data/images/         # Local portraits and paintings (+ thumbs/)
├── db/                  # SQL schema and migrations (when present)
├── Documentation/       # This folder
└── .env                 # DB and port config (not committed)

Runtime modes

Production-style (single process)

npm run server    # http://localhost:3001

Serves /api/*, /images/*, and the built SPA from client/dist if it exists.

Development (two processes)

npm run dev:server   # API on :3001
npm run dev:client   # Vite on :5173, proxies /api and /images

Use the Vite URL during frontend work for HMR.

User navigation flow

flowchart TD
  A[Home — timeline + movement flow] -->|scroll / drag / zoom| A
  A -->|click movement name| G[Movement gallery — 3D wings]
  G -->|click painting| D
  D -->|Back| G
  G -->|back door / Wings / Exit| H[Wing navigator]
  H -->|pick wing| G
  H -->|Exit to Timeline| A
  G -->|front arch / E| G
  G -->|Back to Timeline| A
  A -->|click portrait| B[Artist bio — Wikipedia text]
  B -->|Enter Gallery| C[Artist hall — 3D]
  C -->|click painting| D[Painting detail + influences]
  D -->|prev / next| D
  D -->|click centre image| F[Fullscreen lightbox]
  F -->|close| D
  D -->|Back| C
  C -->|exit doorway / E key| E[Path picker]
  E -->|predecessors| C
  E -->|successors| C
  D -->|influence thumbnail| D
  D -->|artist link| B
  B -->|Back| A
  C -->|Back| A

Timeline and movement flow

The home page shows two linked views over the same year window (viewStart / viewEnd in HomePage.tsx):

View Component Purpose
Era bar Timeline.tsx Historical eras, major event markers, click-to-zoom
Movement flow MovementBands.tsx Curved streams per movement, lineage branches, artist portraits

Both views share zoom/pan behaviour via client/src/utils/timelineView.ts. The home page uses a fixed viewport (100vh): timeline + movement flow sit in a shared home-timeline-stack so event guide lines can extend from the era bar down through the movement canvas. The movement flow compresses vertically so all movements in the visible year range fit without page scrolling.

Timeline year labels

Year ticks along the bottom of the era bar use large, high-contrast labels (bold cream text with shadow). The active range in the control row (e.g. 1400 CE — 1900 CE) uses the same stronger styling.

Timeline controls

Input Action
Click an era band Zoom to that historical period
Click an event marker Zoom to that event (or war span)
Scroll wheel Zoom toward cursor
Drag centre Pan the year range
Drag left / right handle Trim view start / end
+ / / buttons Zoom in, zoom out, reset to full range

Historical event markers

Major world events appear on the era bar as pin markers (single years) or shaded spans (e.g. World War I, World War II). Data lives in client/src/data/historical-events.ts — not in PostgreSQL. Labels appear when zoomed in enough; tooltips always show name and dates. Edit HISTORICAL_EVENTS and rebuild the client to add or change markers.

Vertical guides: TimelineEventGuides.tsx draws faint gold lines (point events) or shaded bands (spans) from the marker row down through the movement flow, aligned to the same year scale. Guides are visual only (pointer-events: none); click-to-zoom stays on the markers in Timeline.tsx.

Movement flow

Each visible movement is drawn as a portrait-width curved stream (~54 px stroke, compressed when many rows are visible) from its start year to its end year.

Feature Implementation
Lineage layout client/src/data/movement-lineage.ts — curated predecessor→successor pairs (Met / ArtStory / museum essays); multiple parents allowed
Vertical depth Successor movements sit on rows below their deepest parent; sibling movements at the same depth are spread into lanes to limit overlap
Branch connectors Smooth curves from the centre of a parent stream to the centre of each child stream (siblings fan out along the parents length)
Visual blending Path-aligned SVG gradients with transparent fades at stream ends and branch junctions; streams draw on top of branches so overlap brightness stays uniform
Filtering Same rule as the API: only movements with at least one artist active in the visible year range
Viewport layout Row height and stream width scale from measured canvas size so every visible movement row fits in the remaining screen space

Artists on movement streams

Each artist appears as a portrait circle on their movements stream row:

Feature Behaviour
Placement Portrait at the midpoint of birthdeath years
Lifespan line Hidden by default; hover the portrait to show a horizontal line from birth year to death year
Timeline span The lifespan line follows the full timeline axis (clamped to the current zoom), even when it extends beyond the movement band
Stacking Artists in the same movement who would overlap are placed on separate lanes within the stream band
Colour Each lane gets a slightly shifted tint derived from the movement colour; portrait border matches its line

Movement flow controls

Input Action
Scroll wheel on flow canvas Zoom (same range as timeline)
Drag on flow canvas Pan
Click portrait Open artist biography
Click movement name (label on stream) Open movement gallery for that movement

Artist portraits stop wheel/drag propagation so zooming over a face does not fight portrait clicks. Hovering a portrait highlights the artists lifespan on the era bar and brightens their segment on the movement stream.

Note: Movement lineage is frontend curation for layout and labels — it is not stored in PostgreSQL. Painting influence links (painting_influence_sources, plus legacy painting_influences for hall navigation) are separate and drive the 3D exit picker and detail panels.

The 3D scene supports two modes in VirtualGallery.tsx: artist halls (personal catalog) and movement galleries (full movement collection, chronological).

Artist halls

Each artist has exactly one hall. The hall is a rectangular room sized to fit their catalog:

Rule Implementation
One hall per artist VirtualGallery.tsx builds a single room from that artists paintings
Catalog depth Most artists target ≥ 6 notable works via npm run expand-catalog and famous-paintings-data.js; some masters have larger museum dumps
Paintings on walls Works hang on the back, left, and right walls in one row per wall; room depth grows when the catalog is large
Corridor layout 15+ paintings: short back wall (up to 8 works), remaining works on extended left/right side walls — a long gallery corridor
Wall order On each wall, left → right: later works on the left, earlier works on the right; undated works sort toward the left
Floor Herringbone parquet procedural texture (parquetFloorTexture.ts)
Wall tint Gallery walls blend the artists movement colour into cream plaster tones
Frame finish Unchecked works: black moulding; Reviewed (checkup_checked): bright gold moulding at double width
Influence lamps A golden picture light appears above frames whose work has any influence-graph edge (has_influence_links from the API)
Eye-level viewing Frame centres sit at eye height (~1.65 m); the camera stays level with the floor (no pitch up/down)
Open centre Floor and ceiling only — no columns, pedestals, or other centre objects
Museum exit Front-wall double doors with transom, brass hardware, sconces, marble threshold, and warm vestibule glow
Hall-to-hall travel Exit opens a panel: Predecessors (left) and Successors (right), each grouped by art movement
Missing images Works without a local file show a draped canvas cover in the frame (not a blank white rectangle)
Detail view return Opening a painting close-up keeps the 3D hall mounted in the background so position and view direction are preserved when you go back
After image fix Debug Fix it updates the gallery session, busts texture cache (?v=N), and returns to the hall with the new image and gold frame

Controls (artist hall):

Input Action
W / Walk forward
S / Walk back
A / / Q Turn left
D / Turn right
Mouse drag Look left / right (same direction as keyboard turns)
Click painting Open detail view
Exit doorway / E / Exit → header button Open path picker

Predecessors and successors come from the painting influence graph (painting_influences → other artists). Empty lists mean no influence edges are recorded yet for that artist — run npm run update-influences or extend seed data.

Movement galleries

Enter from the home page by clicking a movement name on the movement flow (MovementBands.tsxGET /api/movements/:id/gallery).

Rule Implementation
One gallery per movement All paintings by artists in that movement, sorted chronologically
Wings Catalog split into wings of up to 55 works (movementHallLayout.ts); large movements (e.g. Baroque) use multiple wings
Paintings on walls Left and right walls only — back wall reserved for exit, front for passage to the next wing
Wall order Along each side wall: later works on the left, earlier on the right (same convention as artist halls)
Frame captions Year · artist label below each frame
Period interior Each of the 26 seeded movements maps to a unique style in movement-interior-styles.ts (Italian palazzo, Baroque palace, NYC loft, white cube, etc.)
Textures Hi-res procedural wall/floor/ceiling maps with normal maps (galleryProceduralTextures.ts)
Windows Side walls only — placed in gaps between frames (high on the wall, no overlap with paintings); style matches the movement era
Lighting Daylight from windows + ceiling track lights + ambient/sun fill
Back wall Exit double doorsWing navigator (jump to any wing) or Exit to Timeline
Front wall Open “Next wing →” archway when a later wing exists; walk through or press E when near
Influence lamps Same golden lamps as artist halls when has_influence_links is true
Missing images Draped canvas cover in frame
Detail return Hall stays mounted; camera preserved on Back to Timeline / Back to Gallery

Controls (movement gallery):

Input Action
Walk / turn / drag Same as artist hall
Click painting Open detail view (returns to the same wing)
Back wall / E / Wings / Exit → Open wing navigator
Front archway / E (when near) Advance to the next chronological wing

Movement galleries do not use the predecessor/successor influence picker — that remains artist-hall only.

Shared 3D behaviour

3D images use locally cached files only (galleryImageUrl in client/src/api/client.ts). Remote fetches are too slow for realtime WebGL textures; call POST /api/artists/:id/preload-images before entering an artist hall to link disk files. Movement galleries load painting lists from the API without a separate preload step. While a texture is loading, the frame shows the canvas cover instead of a white placeholder.

Painting detail view

Opened from the 3D hall (artist or movement wing — click a frame) or from influence thumbnails on another works detail page.

Layer What you see
Detail Centre image, Influenced By (left) and Influenced (right) — painting thumbnails, artist portraits, or movement swatches — position in catalog (e.g. 3 of 12)
Art history notes Numbered markers on the image (when positioned) plus a note list below — short citations from Gombrich, museum catalogs, Wikipedia, etc. (painting_annotations table)
Fullscreen Click the centre image; Escape or click anywhere to return to detail only

Controls:

Input Action
/ beside image Previous / next work by the same artist (chronological order)
/ Same as prev / next (disabled while fullscreen is open)
Click centre image Open fullscreen lightbox
Click influence thumbnail Open that works detail (different artist allowed)
Click influence artist portrait Open that artists 3D gallery hall
← Back to Gallery / ← Back to Timeline Return to the hall or movement wing you entered from — 3D camera position is preserved
About {artist} Open artist biography

Navigation rules:

  • Catalog browsing ( / arrow keys) walks the current artists works earliest → latest. It does not change the back target: after browsing several works, Back to Gallery still returns directly to the hall.
  • Influence links push a new detail layer; Back from an influenced work returns to the painting you came from (and from there back to the gallery if applicable).
  • The 3D hall stays mounted in the background while detail is open so nothing is lost on return.

Debug mode (developer)

When Debug mode is enabled from the home header, painting detail and artist biography show a bottom-left panel with image search preview and five action buttons. See Developer tools (image audit).

Key design decisions

  • Timeline bounds derive from the earliest art movement start year, not ancient-era metadata alone, so the default view opens where catalogued content begins.
  • Movement filtering on zoom only shows movements that have at least one artist active in the visible year range.
  • Movement lineage (movement-lineage.ts) documents art-historical predecessor→successor links for the flow diagram; extend that file to add or correct branches.
  • One hall per artist keeps navigation predictable: enter from the timeline or bio, leave via the single exit or back button.
  • Movement galleries complement artist halls: full movement corpus in period-themed wings, entered from the flow diagram.
  • Influence-based hall links connect artists through documented painting relationships, grouped by movement at the exit.
  • 3D gallery images use locally cached files only; slow remote fetches would break realtime rendering.
  • Influence data is stored as directed links from paintings to sources (another painting, an artist, or a movement), with optional period fields and citation metadata (source author, quote, URL).

Developer tools (image audit)

Optional workflow for curating local image files — not part of the public visitor experience.

Feature Where Purpose
Debug mode Home header toggle (client/src/utils/debugMode.ts) Persists in localStorage; enables debug panel on painting detail and artist bio
Checkup page Home header → Checkup (CheckupPage.tsx) Full-catalog table: gallery vs detail thumbnails, search, fix, review flags
Debug panel Painting detail or artist bio (bottom-left, when debug mode on) Search preview + five action buttons

Debug panel (painting detail and artist bio)

When debug mode is on, a panel at the bottom-left shows the image search query, a preview when a result is found, and five buttons in two rows:

Button Action
Checked Sets checkup_checked via PATCH …/checkup-flags (disabled once already reviewed)
Fix it Replaces the local image from the top search result (POST …/fix-image or …/fix-portrait); sets Fixed and Reviewed
More Opens a modal with up to 20 search results (each shows image resolution when available); click one to apply the same replace as Fix it
Clear Deletes the local file(s), clears DB paths, leaves an empty frame (no placeholder); sets Fixed and Reviewed so on-demand fetch does not refill the slot
Upload File picker for a local image; saves to disk like Fix it (thumbnail generated for paintings; portrait resized for artists)

After Fix it, More, Upload, or Clear, the main view, gallery textures (paintings), and timeline portrait (artists) update without a full page reload. Reviewed portraits show a gold border on the bio page; reviewed paintings use gold frames in the 3D hall. Back to Gallery returns to the live hall session, not a stale snapshot.

Checkup page

Columns: Gallery and Detail thumbnails, Search (reference image), Fix (replace local file), Reviewed (checkup_checked), Fixed (checkup_fixed).

Search visible runs image search only for rows currently shown after text/filter — not automatically on page load. Fixing an image sets Fixed and Reviewed.

Run npm run migrate:checkup-flags, npm run migrate:artist-checkup-flags, and npm run migrate:painting-annotations once on existing databases. Load notes with npm run update-painting-annotations (add --wikipedia for overview lines from Wikipedia intro text). After server code changes, restart npm run dev so new routes (e.g. clear, upload, portrait debug, annotations) are registered. JSON body limit for uploads is 20 MB (express.json in server/index.js); individual files are capped at 15 MB after decode.

See API.md and data-and-images.md.

Document Contents
setup.md Install, database, npm scripts
DB_structure.md Tables and relationships
API.md REST endpoints
data-and-images.md Image pipeline and seeding