# PIVOINE > *Where the machine dreams.* An editorial magazine for AI-generated art and generative aesthetics — built on Hugo, styled with Tailwind v4, animated with Alpine.js and HTMX. --- ## Stack | Layer | Technology | |-------|-----------| | Static site generator | Hugo (extended) | | CSS | Tailwind CSS v4 via PostCSS | | Reactivity | Alpine.js v3 | | Navigation | HTMX v2 (boosted links + View Transitions) | | Fonts | Bebas Neue · Barlow · Share Tech Mono (Google Fonts) | | Analytics | Umami (cookie-free) | | Server | nginx (Docker) → Traefik → Coolify | --- ## Getting Started **Prerequisites:** Node.js 22+, pnpm, Hugo extended ```bash pnpm install pnpm dev # Hugo dev server with drafts, http://localhost:1313 pnpm build # Production build → public/ ``` --- ## Project Structure ``` pivoine.art/ ├── assets/ │ ├── css/main.css # Design tokens + all component styles │ └── js/main.js # HTMX progress bar, lazy-load videos ├── content/ │ ├── _index.md # Homepage front matter │ ├── about/index.md │ ├── imprint/index.md │ ├── authors/ │ │ └── {slug}/ │ │ ├── index.md # Author profile │ │ └── avatar.png # Page resource (auto-processed to WebP) │ └── posts/ │ └── {slug}/ │ ├── index.md # Post front matter │ ├── banner.png # Hero image (or 01.png as fallback) │ ├── 01.png # Gallery image │ ├── 01.mp4 # Optional companion video │ └── 02.png … ├── layouts/ │ ├── _default/ # baseof, list, single, terms │ ├── partials/ # head, nav, footer, cards, img, schema … │ ├── posts/single.html # Article template │ ├── authors/ # Author list + profile │ ├── categories/ tags/ # Taxonomy pages │ ├── index.html # Homepage │ └── 404.html ├── static/ │ ├── images/og-default.jpg │ └── favicon.* / site.webmanifest ├── Dockerfile ├── nginx.conf ├── hugo.toml └── postcss.config.js ``` --- ## Content Model ### Posts ```yaml title: "Hyperloop" description: "Short editorial summary shown in cards and meta tags." date: 2025-08-17 author: "valknar" # must match content/authors/{slug}/ featured: true # appears in homepage hero / secondary strip categories: [Surreal] tags: [futuristic, vibrant, urban] # Optional — only needed when not using page-bundle images banner: type: image # or "video" src: "/images/posts/…" alt: "Alt text" background: # full-bleed blurred backdrop on article page type: image src: "/images/posts/…" alt: "Alt text" ``` **Page-bundle images (preferred):** Drop numbered images and optional companion videos alongside `index.md`: ``` posts/hyperloop/ ├── index.md ├── banner.png ← hero (detected automatically) ├── 01.png ← gallery item 1 ├── 01.mp4 ← plays instead of 01.png if present ├── 02.png └── 03.png … ``` Hugo automatically resizes all bundle images to WebP at multiple widths — no manual optimisation needed. ### Authors ```yaml title: "Valknar" name: "Valknar" bio: "Short biography shown in bylines and author profile." social: instagram: "handle" x: "handle" ``` Place `avatar.png` (or `.jpg`) in the same directory — it is converted to 96 × 96 px WebP automatically. --- ## Image Processing All page-resource images are handled by `layouts/partials/img.html`, which converts to WebP and emits responsive `srcset`: | Context | Widths generated | `sizes` hint | |---------|-----------------|-------------| | Post banner | 1200w · 1800w | `100vw` | | Gallery image | 800w · 1200w | `33vw` on desktop | | Featured card | 800w · 1200w | `50vw` on desktop | | Grid card thumbnail | 600w · 1000w | `25vw` on desktop | | Author avatar | 96px | — | **Before / after example (hyperloop/banner.png):** | Original PNG | WebP 1800w | WebP 600w | |-------------|-----------|----------| | 7.9 MB | 496 KB | 56 KB | Processed images are cached in `resources/_gen/` (gitignored). --- ## Design System ### Colour Palette ```css /* Base — deep navy-black */ --color-void: #050510 --color-ink: #09091A --color-concrete: #0F0F22 --color-zinc: #1C1C38 /* Neutrals */ --color-fog: #6868A0 --color-chalk: #B8B8E0 --color-paper: #EEEEFF /* Accent triad */ --color-heat: #FF1A8C /* hot pink — primary */ --color-pulse: #9B00FF /* electric purple — mid */ --color-frost: #00C8FF /* ice blue — cool */ ``` ### Typography | Role | Font | Usage | |------|------|-------| | Display | Bebas Neue | Headlines, oversized decorative text | | Body | Barlow 300–600 | Editorial prose, UI copy | | Label | Share Tech Mono | Metadata, badges, specs | ### Component Classes ``` .btn CTA button — clip-path skew, shimmer sweep on hover .btn-outline Transparent variant .btn-frost Ice blue variant .badge Parallelogram sticker (multiple colour variants) .badge-outline Bordered, transparent .card-comic Card with 1.5px border + lift + glow on hover .card-media Media container — zoom on hover .gradient-line 1 px heat → pulse → frost divider .graffiti-tag Oversized hollow decorative text (text-stroke) .speed-lines Isometric triangle grid background .halftone Diamond crosshatch background .spray-bg Radial dot pattern .text-gradient Static pink → purple → ice gradient text .text-gradient-animated Looping gradient (5 s) .label Monospace spec-sheet micro-text .prose-editorial Long-form article body styles .gutter-x Responsive horizontal padding (clamp 1 – 3 rem) ``` --- ## Templates | Template | Route | Description | |----------|-------|-------------| | `index.html` | `/` | Hero (featured post) · secondary cards (3) · latest grid (8) · about strip | | `posts/single.html` | `/posts/{slug}/` | Article header · author byline · banner · prose · gallery · tags · related | | `_default/list.html` | `/posts/` | Paginated post grid (12/page) | | `authors/single.html` | `/authors/{slug}/` | Author profile · all posts by author | | `authors/list.html` | `/authors/` | Author grid | | `categories/single.html` | `/categories/{slug}/` | Posts by category | | `_default/terms.html` | `/categories/` `/tags/` | Badge cloud of all terms + counts | | `404.html` | `*` | Styled error page | --- ## Navigation & Interactivity **HTMX** — `hx-boost` on `` intercepts all internal links, swaps only `#main-content`, and pushes URL history. Combined with the CSS View Transitions API for smooth page animations. **Alpine.js** — `$store.nav.path` drives active link highlighting. `$store.nav.open` toggles the mobile fullscreen overlay (teleported to `` to escape header stacking context). **Mobile menu** — animated hamburger → ✕, staggered link slide-in with `mob-link-in` keyframe. --- ## SEO & Meta - Open Graph + Twitter Card on every page - JSON-LD structured data (`WebSite` on home, `BlogPosting` on articles) - `robots.txt` generated by Hugo (`enableRobotsTXT = true`) - `X-Robots-Tag: index, follow` set in nginx - Canonical URLs, `article:modified_time` from git history - Sitemap at `/sitemap.xml` --- ## Deployment ### Docker ```dockerfile # Stage 1 — build FROM node:22-alpine AS builder # installs Hugo + pnpm, runs pnpm build # Stage 2 — serve FROM nginx:alpine COPY --from=builder /app/public /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf ``` ```bash docker build -t pivoine-art . docker run -p 8080:80 pivoine-art ``` ### nginx - Gzip enabled for text, CSS, JS, SVG, JSON - Static assets: `Cache-Control: public, immutable` · 1 year - HTML: `Cache-Control: no-store, no-cache` (always fresh) - Clean URLs via `try_files $uri $uri/ $uri.html` ### Traefik / Coolify The container sits behind Traefik (managed by Coolify). A global `security-headers` middleware in `stacks/traefik/dynamic/security.yaml` applies HSTS, CSP, and other headers to all services. A separate `no-index` middleware in the same file can be applied to internal services that should not be indexed. --- ## Adding Content ### New post ```bash # Create a leaf bundle mkdir -p content/posts/my-new-drop touch content/posts/my-new-drop/index.md # Drop images alongside index.md cp ~/renders/banner.png content/posts/my-new-drop/ cp ~/renders/01.png content/posts/my-new-drop/ ``` Fill in `index.md` front matter, run `pnpm dev`, and the post appears immediately. Hugo handles WebP conversion, srcset generation, and gallery detection automatically. ### New author ```bash mkdir -p content/authors/my-handle touch content/authors/my-handle/index.md cp ~/avatar.png content/authors/my-handle/ ``` Reference the author slug in any post's `author:` field. --- ## Configuration Key settings in `hugo.toml`: ```toml [params] description = "An editorial magazine for AI-generated art …" tagline = "Where the machine dreams." author = "Pivoine Editorial" logoText = "PIVOINE" twitterHandle = "pivoineArt" ogImage = "/images/og-default.jpg" copyrightYear = "2026" umamiSrc = "https://umami.pivoine.art/script.js" umamiId = "…" [params.social] instagram = "https://instagram.com/…" x = "https://x.com/…" ``` Menus are defined as `[[menus.main]]` and `[[menus.footer]]` arrays in the same file. --- ## License © 2026 Pivoine Editorial. All rights reserved.