# 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///` 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` - `.png` — the plate image (used for thumbnails, lightbox, og:image) `content/posts//_index.md` carries `build.render: never` so only `/posts///` pages are emitted — the per-issue landing page is the taxonomy term at `/issues//`. Issue membership is the `issues` taxonomy; each issue also has a branch bundle at `content/issues//_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 2–4 all write `content/posts/NN//.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//` → `/posts/01//`); 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.