feat: portfolio-led redesign with Shootings umbrella, original logo and motion layer

This commit is contained in:
desfoto automation
2026-09-19 17:11:25 +02:00
parent 2ccb39a69b
commit 447b909d05
177 changed files with 1853 additions and 773 deletions

View File

@@ -7,7 +7,17 @@ no runtime dependencies. `src/` holds Python builders and the editorial content,
`scripts/build-site.py` renders everything into the committed `site/` directory,
and nginx serves `site/` from a container behind the shared VPS Traefik instance.
`dennyschulz.de` is a **separate** site and must never be modified or linked from here.
`dennyschulz.de` is a **separate** site: nothing here may modify it, proxy it or
hotlink its assets. Linking out to it from the footer is an explicit operator
request and is the only permitted reference (see "Editing rules").
## Structure
- `/` — hero, two pillars (**Shootings** = photo, **Videoprojekte** = video), portfolio
gallery, music video, mobiles Studio, process, facts.
- `/shootings/` — the umbrella for all photographic work: Businessfotografie,
Portrait & Model, Familien & Paare, Minishootings, plus the mobiles Studio.
`/fotografie` and `/fotografie/` are 301-redirected here by `nginx.conf`.
- `/video/`, `/social-media/`, `/projekte/` (music + free work + pro bono), `/ueber/`.
## Commands
- `python3 scripts/fetch-assets.py` — download pool images, Google Fonts subsets and
@@ -27,10 +37,35 @@ and nginx serves `site/` from a container behind the shared VPS Traefik instance
- Never invent facts. Prices, testimonials, client names, awards and biography dates
are intentionally absent; do not add them without verified information. Legal data
in `src/content.py:LEGAL` mirrors the operator's own Impressum (`§ 5 DDG`).
The portfolio must reflect the operator's real work (musicians, live shows, free
and artistic series, business shoots) — never invent trips, locations or jobs
(an earlier build captioned an image as a "Japanreise"; that was invented and must
not return).
- Keep the design language: paper/ink/rust/teal tokens from `src/theme.py`, rounded
cards, hairline dividers, Fraunces for display and Manrope for text.
- Images come from the operator's own pool through `src/images.json`. Only add an
entry if the operator holds the rights; always give a meaningful German `alt`.
`"source": "legacy"` marks images fetched from the operator's own site
(`dennyschulz.de/legacy/<file>`) — they are written into `assets-src/images/` and
never hotlinked at runtime. `alt` texts must come from the operator's own captions.
- The operator's original logo lives in `assets-src/brand/logo.png`; the build derives
`logo-160.png`, the favicons, the apple-touch icon and `favicon.svg` from it. Never
redraw or guess a replacement mark.
- The footer's "Netzwerk" column links to `https://www.dennyschulz.de/` and
`https://dennyapp.de/` because the operator asked for it; these are the only
external links allowed and they must keep `target="_blank" rel="noopener"`.
Nothing else may reference `dennyschulz.de` (no assets, no fetches, no rewriting).
- Animations are progressive enhancement: they live in CSS plus the guarded
`site.js` block, every page carries the `<noscript>` reveal fallback, and the
`prefers-reduced-motion` block must stay the **last** rule in `src/theme.py` so it
wins over the motion definitions.
- Never hide the element you observe: Chromium folds a target's own `clip-path` into
the `IntersectionObserver` geometry, so a closed mask never reports as visible and
the content stays hidden forever. `.reveal--mask` therefore clips its children.
- Never nest `<a>` inside `<a>` (or any other invalid nesting). The parser closes the
outer anchor and the surrounding grid falls apart — that is what happened to the
two homepage pillars. Cards with their own links use the stretched-link pattern
(`.pillar__go::after`); `tests/test_site.py` guards this for every page.
- Two-space indentation, `from __future__ import annotations`, type hints on public
functions, no new third-party Python packages (Pillow is the only dependency).