Files
roux/README.md
T
valknarandClaude Sonnet 5 2dc7a0063f Add issue No. 02 "Obsession" + reusable image pipeline
Content
- 100 new plates under content/posts/02/ — one recurring red-haired model
  across 10 editorial registers (Haute Couture, Film Noir, Boudoir,
  Avant-Garde, Minimalism, Baroque, Street Style, Surrealism, Monochrome,
  Nocturne), generated with flux-1.1-pro, face-swapped to a consistent
  identity (FaceFusion), and upscaled (Upscayl + Remacri, 3328x4992).
- content/issues/02/_index.md; issue 01 -> status archived; hugo.toml params
  (issueIds newest-first, issueNumber/Name/Season/Blurb).

Structure
- Plate bundles grouped by issue: content/posts/<issue>/<slug>/, with
  build.render:never stubs so /posts/<issue>/ isn't emitted. nginx 301s the
  legacy flat /posts/<slug>/ URLs to /posts/01/<slug>/. The /posts/ archive
  uses .RegularPagesRecursive.

Image pipeline (scripts/, data/ gitignored)
- generate-images.py  — Replicate flux-1.1-pro, 960x1440, idempotent.
- faceswap-images.py  — FaceFusion batch-run, one consistent face.
- upscale-images.py   — Upscayl + remacri-4x, long edge clamped to 4992.
- build-issue.py      — prompts JSON -> content/posts/<issue>/*/index.md.

Build
- CSS now compiled by Hugo's css.TailwindCSS (partials/css.html +
  templates.Defer); dropped the standalone Tailwind CLI step, concurrently,
  and the gitignored static/css/main.css. Requires Hugo >= 0.161; Dockerfile
  collapsed to a single hugomods/hugo:debian-node build stage.
  pnpm-workspace.yaml: preferSymlinkedExecutables + allowBuilds.

Front end
- Pagination 8 per page.
- Lightbox: brand mark and category link out; robust SPA back/forward
  (fetch before startViewTransition, single-flight guard, swallow the
  transition abort rejection, popstate re-renders / reopens the viewer).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZPmxGywFnAhmYJB1eh9fm
2026-08-29 21:11:24 +02:00

109 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Roux
A slow-publishing fashion journal — one hundred photographs at a time.
Editorial, couture, beauty and backstage plates.
**Live:** [roux.pivoine.art](https://roux.pivoine.art)
---
## Stack
| Layer | Tool |
|---|---|
| Static site generator | Hugo Extended (≥ 0.161) |
| CSS | Tailwind CSS v4, compiled by Hugo's `css.TailwindCSS` |
| JavaScript | Vanilla (no framework) |
| Package manager | pnpm |
| Server | nginx (Docker) |
## Development
```bash
pnpm install # installs @tailwindcss/cli (Hugo shells out to it)
pnpm dev # hugo server -D → http://localhost:1313
```
Hugo builds the CSS itself via `css.TailwindCSS` (see `layouts/partials/css.html`),
watches `assets/`, and hot-reloads. There is no separate CSS build step or watcher.
Requires `node` on `PATH` — Hugo execs `node_modules/.bin/tailwindcss`.
## Build
```bash
pnpm build # hugo --minify → public/
```
CSS is emitted as a fingerprinted, integrity-hashed resource under `public/css/`;
`hugo_stats.json` (the class list Tailwind scans) is generated on every build and
gitignored.
`pnpm-workspace.yaml` sets `preferSymlinkedExecutables: true` so pnpm links
`node_modules/.bin/tailwindcss` as a symlink — Hugo rejects pnpm's default shell
shim (`binary "tailwindcss" is not a Node.js script`).
## Content
Posts live in `content/posts/<issue>/<slug>/` as Hugo page bundles (e.g.
`content/posts/01/…`, `content/posts/02/…`). Each bundle contains:
- `index.md` — frontmatter with `plate`, `title`, `description`, `categories`, `tags`, `issues`, optional `featured: true`
- `<slug>.png` — the plate image (used for thumbnails, lightbox, og:image)
`content/posts/<issue>/_index.md` carries `build.render: never` so only `/posts/<issue>/<slug>/`
pages are emitted — the per-issue landing page is the taxonomy term at `/issues/<issue>/`.
Issue membership is the `issues` taxonomy; each issue also has a branch bundle at
`content/issues/<id>/_index.md` (`title`, `description`, `issueNumber`, `season`, `status`).
### Adding a new issue
1. Write `data/prompts/issue-NN.json` — an array of `{slug, title, category, tags, description, prompt, featured?}`.
2. Generate images: `python3 scripts/generate-images.py --prompts data/prompts/issue-NN.json --issue NN`
(Replicate `flux-1.1-pro` by default; token from `$REPLICATE_API_TOKEN` or `~/.env`).
3. Face-swap one consistent model into every plate:
`python3 scripts/faceswap-images.py --issue NN --source ~/Bilder/palina.webp`
(FaceFusion at `~/Projekte/facefusion`; add `--enhance` for a sharper face pass).
4. Upscale: `python3 scripts/upscale-images.py --issue NN`
(Upscayl + the `remacri-4x` model, then clamped to a 4992 px long edge; `--scale 2` or
`--max-edge 2880` keeps the committed PNGs lean).
5. Build the bundles: `python3 scripts/build-issue.py --issue NN --prompts data/prompts/issue-NN.json`
6. Add `content/issues/NN/_index.md`, add `content/posts/NN/_index.md` (`build.render: never`),
flip the previous issue's `status` away from `current`, and update `hugo.toml` `[params]`
(`issueIds`, `issueNumber`, `issueName`, `issueSeason`, `issueBlurb`).
Steps 24 all write `content/posts/NN/<slug>/<slug>.png` in place and are each idempotent
(re-run to finish a failed batch; `--force` to redo). Pass `--out DIR` to stage instead.
### Importing issue 01
Issue 01 is sourced from `~/projects/ginger/posts.csv` and matching images in
`~/projects/ginger/images/final/selected/`:
```bash
python3 scripts/import-posts.py # writes content/posts/01/
```
This creates or updates page bundles, assigns plate numbers (sorted alphabetically by filename for stability), normalises descriptions, and copies images.
## Design tokens
All colours, fonts, and spacing are defined in `assets/css/main.css` inside `@theme {}` and mirrored as CSS custom properties in `:root`. Edit there — not in a Tailwind config file (v4 has none).
Key tokens: `--color-paper` `--color-ink` `--color-roux` `--font-display` `--font-serif` `--font-sans` `--pad` `--gap`
## Deployment
`Dockerfile` is a two-stage build: `hugomods/hugo:debian-node-*` runs
`pnpm install` then `hugo --minify --environment production` (Hugo compiles
Tailwind in-process — no pre-build CSS step), and `nginx:alpine` serves the
result with `nginx.conf`. Analytics (Umami) are injected only in the production
environment.
`nginx.conf` also 301-redirects the legacy flat issue-01 plate URLs
(`/posts/<slug>/``/posts/01/<slug>/`); widen its negative-lookahead when
adding issue 03+.
## License
All editorial content, photographs, and design © Roux MMXXVI. All rights reserved.
Contents are explicitly excluded from AI/ML training use without written consent.