diff --git a/README.md b/README.md new file mode 100644 index 0000000..e87ff16 --- /dev/null +++ b/README.md @@ -0,0 +1,337 @@ +# 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.