A static single-page art gallery site — plain HTML/CSS/JS, no build step, no
framework, no package.json. Site text is in Czech; code and comments are in
English.
Live at: https://coronav.github.io/Gallery/ (GitHub Pages; changes propagate
shortly after pushing to main).
Browsers block fetch() of local files under file://, and gallery.js
fetches pictures/manifest.json, so the site must be served over HTTP:
python3 -m http.server
then open http://localhost:8000/.
-
Take/collect the raw phone photo(s) and drop them in
picture_processing/raw_photos/(gitignored — never committed). -
Run the pipeline:
python3 update_gallery.pyBy default this first auto-deskews any new raw photos (detecting the canvas edges and perspective-warping them to a flat rectangle into
picture_processing/cropped/), then builds the derivatives, captions stubs, and manifest from everything incropped/. -
If a photo couldn't be auto-deskewed, the run prints
NO QUAD FOUND/ a failure summary for it. Either:- open
picture_processing/manual_corner_crop.htmldirectly in a browser (no server needed), drag the 4 corners by hand, and move the downloaded<name>_corrected.pngintopicture_processing/cropped/; or - add the filename to
picture_processing/raw_ignore.txt(one per line,#comments allowed) to stop the pipeline from retrying it.
Then run
python3 update_gallery.pyagain. - open
-
Fill in captions: open
pictures/captions.txtand add/edit thetitle:/meta:/date:/description:fields for any painting listed as missing a title.date:accepts2023,2023-05,5/2023or05/2023,5.2023,12.5.2023(day.month.year), or2023-05-12— as much precision as you have. The file's header documents the full format. -
Run
python3 update_gallery.pyagain somanifest.jsonpicks up the new captions. -
Commit and push.
pictures/web/,pictures/thumbs/,pictures/hires/,pictures/manifest.json, andpictures/captions.txtare all checked in — GitHub Pages serves them directly.
The order paintings appear on the site is the order their [section]
blocks appear in pictures/captions.txt. To rearrange the gallery, move a
whole section (its [header] plus its title:/meta:/date:/
description: lines) up or down in that file, then run
python3 update_gallery.py and commit. Newly added images are appended at
the bottom, so they show last until you move them.
index.html+gallery.js—index.htmlis a static shell with an empty#gallerydiv. On load,gallery.js'sloadGallery()fetchespictures/manifest.json(an array of{file, thumb, hires, width, height, title, meta, date, description}) and builds the painting cards- lightbox from it entirely client-side. There is no server logic.
update_gallery.py— the single pipeline script. It has two stages: (1) an on-by-default deskew stage that auto-corrects new raw photos frompicture_processing/raw_photos/intopicture_processing/cropped/(skip with--skip-deskew); (2) the derivatives stage, which turns everything incropped/into whatpictures/needs: three resized JPEG tiers —web/(max 1600px),thumbs/(max 480px), andhires/(max 2560px, for zooming in) —captions.txtstubs for new paintings, andmanifest.json. Because the paintings are photos of woven canvas, each downscale is followed by a small Gaussian blur to suppress the moiré that canvas texture otherwise produces against the resample and the display's pixel grid. Run it after adding, removing, or re-cropping any image. Seepython3 update_gallery.py --helpfor the--source,--out,--raw,--force, and--skip-deskewflags.pictures/captions.txt— the single source of truth for every painting's title/meta/date/description, keyed by the source filename inpicture_processing/cropped/(e.g.[IMG_1202_corrected.jpg]). See the header comment in the file itself for the exact format.picture_processing/— the image-correction pipeline:raw_photos/(gitignored originals) →deskew.py(automatic perspective correction, invoked byupdate_gallery.pyitself) ormanual_corner_crop.html(manual fallback) →cropped/(flat, full-resolution corrected images, the input toupdate_gallery.py's derivatives stage).raw_ignore.txt(optional) lists raw filenames to never auto-deskew.
python3 -m unittest discover -s tests
update_gallery.py and its tests are linted with ruff
and covered by stdlib unittest. A versioned pre-commit hook in hooks/
runs both before every commit. Enable it once per clone:
python3 -m pip install ruff # one-time; the hook skips lint if it's absent
git config core.hooksPath hooks
After that, git commit runs ruff check . and the test suite, and aborts
the commit if either fails. Lint rules live in pyproject.toml. To bypass
the hook for a single commit, use git commit --no-verify.